2020-10-30 14:45:38 +03:00
|
|
|
/- sur=btc
|
|
|
|
^?
|
|
|
|
=< [sur .]
|
|
|
|
=, sur
|
2020-10-04 11:56:38 +03:00
|
|
|
|%
|
2021-01-26 21:36:21 +03:00
|
|
|
++ to-hexb
|
2021-01-24 13:09:49 +03:00
|
|
|
|= h=@t
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
|
|
|
?: =('' h) 1^0x0
|
2021-01-24 13:09:49 +03:00
|
|
|
:: Add leading 00
|
|
|
|
::
|
|
|
|
=+ (lsh [3 2] h)
|
|
|
|
:: Group by 4-size block
|
|
|
|
::
|
|
|
|
=+ (rsh [3 2] -)
|
|
|
|
:: Parse hex to atom
|
|
|
|
::
|
2021-01-26 21:36:21 +03:00
|
|
|
:- (div (lent (trip h)) 2)
|
2021-01-24 13:09:49 +03:00
|
|
|
`@ux`(rash - hex)
|
2020-10-29 15:10:54 +03:00
|
|
|
++ xpub-type
|
2020-10-31 12:41:00 +03:00
|
|
|
|= =xpub
|
2021-01-27 16:40:21 +03:00
|
|
|
^- [=bipt =network]
|
2020-10-31 12:41:00 +03:00
|
|
|
=/ prefix=tape (scag 4 (trip xpub))
|
2021-01-27 16:40:21 +03:00
|
|
|
?: =("tpub" prefix) [%44 %testnet]
|
|
|
|
?: =("upub" prefix) [%49 %testnet]
|
|
|
|
?: =("vpub" prefix) [%84 %testnet]
|
|
|
|
?: =("xpub" prefix) [%44 %main]
|
|
|
|
?: =("ypub" prefix) [%49 %main]
|
|
|
|
?: =("zpub" prefix) [%84 %main]
|
2020-10-29 15:10:54 +03:00
|
|
|
~|("invalid xpub: {<xpub>}" !!)
|
2020-10-14 10:08:35 +03:00
|
|
|
:: big endian sha256: input and output are both MSB first (big endian)
|
2020-10-15 13:55:41 +03:00
|
|
|
::
|
2020-10-14 10:08:35 +03:00
|
|
|
++ sha256
|
2020-12-10 11:22:23 +03:00
|
|
|
|= =byts
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
2020-12-10 11:22:23 +03:00
|
|
|
%- flip:byt
|
|
|
|
[32 (shay (flip:byt byts))]
|
2020-10-16 12:28:51 +03:00
|
|
|
::
|
|
|
|
++ dsha256
|
|
|
|
|= =byts
|
|
|
|
(sha256 (sha256 byts))
|
|
|
|
::
|
2020-10-04 17:16:35 +03:00
|
|
|
++ hash-160
|
2021-01-25 16:01:36 +03:00
|
|
|
|= val=byts
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
2020-10-04 19:03:22 +03:00
|
|
|
=, ripemd:crypto
|
2020-10-16 12:28:51 +03:00
|
|
|
:- 20
|
2020-10-15 13:55:41 +03:00
|
|
|
%- ripemd-160
|
2021-01-25 16:01:36 +03:00
|
|
|
(sha256 val)
|
|
|
|
::
|
2021-01-27 16:09:25 +03:00
|
|
|
++ pubkey-to-address
|
|
|
|
|= [=bipt =network pubkey=hexb]
|
|
|
|
^- address
|
|
|
|
?- bipt
|
|
|
|
%44
|
|
|
|
:- %base58
|
|
|
|
=< ^-(@uc dat)
|
|
|
|
%- cat:byt
|
|
|
|
:- ?- network
|
|
|
|
%main 1^0x0
|
|
|
|
%testnet 1^0x6f
|
2021-01-25 16:01:36 +03:00
|
|
|
==
|
2021-01-27 16:09:25 +03:00
|
|
|
~[(hash-160 pubkey)]
|
|
|
|
::
|
|
|
|
%49
|
|
|
|
:- %base58
|
|
|
|
=< ^-(@uc dat)
|
|
|
|
%- cat:byt
|
|
|
|
:~ ?- network
|
|
|
|
%main 1^0x5
|
|
|
|
%testnet 1^0xc4
|
|
|
|
==
|
|
|
|
%- hash-160
|
|
|
|
(cat:byt ~[2^0x14 (hash-160 pubkey)])
|
|
|
|
==
|
|
|
|
::
|
|
|
|
%84
|
|
|
|
:- %bech32
|
|
|
|
(need (encode-pubkey:bech32 network pubkey))
|
|
|
|
==
|
2020-10-15 13:55:41 +03:00
|
|
|
::
|
2020-12-14 13:35:42 +03:00
|
|
|
++ script-pubkey
|
|
|
|
|= =address
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
|
|
|
?- -.address
|
|
|
|
%bech32
|
2021-01-27 16:09:25 +03:00
|
|
|
=+ h=(from-address:bech32 +.address)
|
2021-01-26 21:36:21 +03:00
|
|
|
%- cat:byt
|
|
|
|
:~ 1^0x0
|
|
|
|
1^wid.h
|
|
|
|
h
|
2020-10-19 11:36:57 +03:00
|
|
|
==
|
2021-01-27 16:09:25 +03:00
|
|
|
::
|
2021-01-26 21:36:21 +03:00
|
|
|
%base58
|
2021-01-27 16:09:25 +03:00
|
|
|
=/ h=hexb [21 `@ux`+.address]
|
|
|
|
=+ lead-byt=dat:(take:byt 1 h)
|
|
|
|
=/ version-network=[bipt network]
|
|
|
|
?: =(0x0 lead-byt) [%44 %main]
|
|
|
|
?: =(0x6f lead-byt) [%44 %testnet]
|
|
|
|
?: =(0x5 lead-byt) [%49 %main]
|
2021-01-27 16:25:31 +03:00
|
|
|
?: =(0xc4 lead-byt) [%49 %testnet]
|
2021-01-27 16:09:25 +03:00
|
|
|
~|("Invalid base58 address: {<+.address>}" !!)
|
|
|
|
%- cat:byt
|
|
|
|
?: ?=(%44 -.version-network)
|
|
|
|
:~ 3^0x76.a914
|
|
|
|
(drop:byt 1 h)
|
|
|
|
2^0x88ac
|
|
|
|
==
|
|
|
|
:~ 2^0xa914
|
|
|
|
(drop:byt 1 h)
|
|
|
|
1^0x87
|
|
|
|
==
|
2020-12-14 13:35:42 +03:00
|
|
|
==
|
2020-12-13 23:33:08 +03:00
|
|
|
:: +txu: tx utility functions
|
2021-01-27 16:09:25 +03:00
|
|
|
::
|
2020-12-13 23:33:08 +03:00
|
|
|
++ txu
|
|
|
|
|%
|
|
|
|
++ en
|
2020-12-14 13:35:42 +03:00
|
|
|
|%
|
|
|
|
++ input
|
|
|
|
|= i=input:tx
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
2020-12-14 13:35:42 +03:00
|
|
|
%- cat:byt
|
|
|
|
:~ (flip:byt txid.i)
|
|
|
|
(flip:byt 4^pos.i)
|
|
|
|
1^0x0
|
|
|
|
(flip:byt sequence.i)
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ output
|
|
|
|
|= o=output:tx
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
2020-12-14 13:35:42 +03:00
|
|
|
%- cat:byt
|
2021-01-24 16:42:55 +03:00
|
|
|
:~ (flip:byt 8^value.o)
|
|
|
|
1^wid.script-pubkey.o
|
|
|
|
script-pubkey.o
|
|
|
|
==
|
2020-12-14 15:13:24 +03:00
|
|
|
--
|
|
|
|
::
|
|
|
|
++ de
|
|
|
|
|%
|
|
|
|
++ nversion
|
|
|
|
|= b=buffer
|
|
|
|
^- [nversion=@ud rest=buffer]
|
|
|
|
:_ (slag 4 b)
|
|
|
|
=< dat
|
|
|
|
%- flip:byt
|
|
|
|
(to-byts:buf (scag 4 b))
|
|
|
|
::
|
|
|
|
++ segwit
|
|
|
|
|= b=buffer
|
2020-12-14 17:40:31 +03:00
|
|
|
^- [segwit=(unit @ud) rest=buffer]
|
|
|
|
?. =(0x0 (snag 0 b))
|
|
|
|
[~ b]
|
2020-12-14 15:13:24 +03:00
|
|
|
:_ (slag 2 b)
|
2020-12-14 17:40:31 +03:00
|
|
|
=< [~ dat]
|
2020-12-14 15:13:24 +03:00
|
|
|
(to-byts:buf (scag 2 b))
|
2020-12-14 17:40:31 +03:00
|
|
|
:: returns value as 0 since we don't know it when we decode
|
2020-12-14 15:13:24 +03:00
|
|
|
::
|
|
|
|
++ input
|
|
|
|
|= b=buffer
|
|
|
|
^- input:tx
|
2021-01-26 21:36:21 +03:00
|
|
|
:* (flip:byt (to-byts:buf (scag 32 b)))
|
|
|
|
|
2020-12-14 15:13:24 +03:00
|
|
|
=<(dat (flip:byt (to-byts:buf (swag [32 4] b))))
|
|
|
|
(flip:byt (to-byts:buf (swag [37 4] b)))
|
|
|
|
~
|
|
|
|
~
|
|
|
|
0
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ output
|
|
|
|
|= b=buffer
|
|
|
|
^- output:tx
|
2021-01-24 16:42:55 +03:00
|
|
|
:: slag 9 instead of 8 to skip the length byte
|
|
|
|
:- (to-byts:buf (slag 9 b))
|
2020-12-14 15:13:24 +03:00
|
|
|
=< dat
|
|
|
|
(flip:byt (to-byts:buf (scag 8 b)))
|
|
|
|
::
|
|
|
|
++ inputs
|
|
|
|
|= b=buffer
|
|
|
|
^- [is=(list input:tx) rest=buffer]
|
|
|
|
=| acc=(list input:tx)
|
|
|
|
=^ count b
|
|
|
|
[(snag 0 b) (slag 1 b)]
|
|
|
|
|-
|
|
|
|
?: =(0 count) [acc b]
|
|
|
|
%= $
|
|
|
|
acc %+ snoc acc
|
|
|
|
(input (scag 41 b))
|
|
|
|
b (slag 41 b)
|
|
|
|
count (dec count)
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ outputs
|
|
|
|
|= b=buffer
|
|
|
|
^- [os=(list output:tx) rest=buffer]
|
|
|
|
=| acc=(list output:tx)
|
|
|
|
=^ count b
|
|
|
|
[(snag 0 b) (slag 1 b)]
|
|
|
|
|-
|
|
|
|
?: =(0 count) [acc b]
|
|
|
|
%= $
|
|
|
|
acc %+ snoc acc
|
|
|
|
(output (scag 31 b))
|
|
|
|
b (slag 31 b)
|
|
|
|
count (dec count)
|
2020-12-14 13:35:42 +03:00
|
|
|
==
|
|
|
|
--
|
2020-12-14 15:13:24 +03:00
|
|
|
::
|
2020-12-14 13:35:42 +03:00
|
|
|
++ encode
|
|
|
|
|= =data:tx
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
2020-12-14 13:35:42 +03:00
|
|
|
%- cat:byt
|
|
|
|
%- zing
|
|
|
|
:~ :~ (flip:byt 4^nversion.data)
|
|
|
|
1^(lent is.data)
|
|
|
|
==
|
|
|
|
(turn is.data input:en)
|
|
|
|
~[1^(lent os.data)]
|
|
|
|
(turn os.data output:en)
|
|
|
|
~[(flip:byt 4^locktime.data)]
|
|
|
|
==
|
2020-12-13 23:33:08 +03:00
|
|
|
++ get-id
|
2020-12-14 19:18:23 +03:00
|
|
|
|= =data:tx
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
2020-12-14 13:35:42 +03:00
|
|
|
%- flip:byt
|
2020-12-14 19:18:23 +03:00
|
|
|
%- dsha256
|
|
|
|
(encode data)
|
2020-12-14 15:13:24 +03:00
|
|
|
::
|
2020-12-14 17:40:31 +03:00
|
|
|
++ decode
|
2021-01-26 21:36:21 +03:00
|
|
|
|= b=hexb
|
2020-12-14 13:35:42 +03:00
|
|
|
^- data:tx
|
2020-12-14 15:13:24 +03:00
|
|
|
=/ bu=buffer (from-byts:buf b)
|
|
|
|
=^ nversion bu
|
|
|
|
(nversion:de bu)
|
|
|
|
=^ segwit bu
|
|
|
|
(segwit:de bu)
|
|
|
|
=^ inputs bu
|
|
|
|
(inputs:de bu)
|
|
|
|
=^ outputs bu
|
|
|
|
(outputs:de bu)
|
2020-12-15 10:36:46 +03:00
|
|
|
=/ locktime=@ud
|
|
|
|
dat:(to-byts:buf (scag 4 (flop bu)))
|
|
|
|
[inputs outputs locktime nversion segwit]
|
2020-12-13 23:33:08 +03:00
|
|
|
--
|
|
|
|
:: core to handle BIP174 PSBTs
|
2020-12-07 14:56:50 +03:00
|
|
|
::
|
2020-12-10 11:22:23 +03:00
|
|
|
++ pbt
|
2020-12-07 14:56:50 +03:00
|
|
|
|%
|
2020-12-09 20:33:50 +03:00
|
|
|
++ en
|
|
|
|
|%
|
|
|
|
++ globals
|
2021-01-26 21:36:21 +03:00
|
|
|
|= rawtx=hexb
|
2020-12-10 11:22:23 +03:00
|
|
|
^- map:psbt
|
2020-12-10 16:22:48 +03:00
|
|
|
:~ [[1 0x0] rawtx]
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ input
|
2020-12-15 12:35:33 +03:00
|
|
|
|= [only-witness=? i=in:psbt]
|
2020-12-10 11:22:23 +03:00
|
|
|
^- map:psbt
|
2020-12-15 12:35:33 +03:00
|
|
|
%+ weld
|
|
|
|
?: only-witness ~
|
|
|
|
~[[1^0x0 rawtx.i]]
|
|
|
|
:~ (witness-tx i)
|
2020-12-10 16:22:48 +03:00
|
|
|
(hdkey %input hdkey.i)
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ output
|
|
|
|
|= =out:psbt
|
2020-12-10 11:22:23 +03:00
|
|
|
^- map:psbt
|
2020-12-10 16:22:48 +03:00
|
|
|
?~ hk.out ~
|
|
|
|
:~ (hdkey %output u.hk.out)
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ witness-tx
|
|
|
|
|= i=in:psbt
|
|
|
|
^- keyval:psbt
|
|
|
|
:- [1 0x1]
|
|
|
|
%- cat:byt
|
2020-12-11 13:10:40 +03:00
|
|
|
:~ (flip:byt 8^value.utxo.i)
|
2020-12-10 16:22:48 +03:00
|
|
|
1^0x16
|
|
|
|
2^0x14
|
2021-01-25 16:01:36 +03:00
|
|
|
(hash-160 pubkey.hdkey.i)
|
2020-12-10 16:22:48 +03:00
|
|
|
==
|
|
|
|
::
|
2020-12-10 11:22:23 +03:00
|
|
|
++ hdkey
|
2020-12-10 16:22:48 +03:00
|
|
|
|= [=target:psbt h=^hdkey]
|
2020-12-10 11:22:23 +03:00
|
|
|
^- keyval:psbt
|
|
|
|
=/ typ=@ux
|
|
|
|
?- target
|
|
|
|
%input 0x6
|
|
|
|
%output 0x2
|
|
|
|
==
|
2020-12-10 16:22:48 +03:00
|
|
|
:- (cat:byt ~[1^typ pubkey.h])
|
2020-12-10 11:22:23 +03:00
|
|
|
%- cat:byt
|
2020-12-10 12:14:03 +03:00
|
|
|
:~ fprint.h
|
2020-12-10 11:22:23 +03:00
|
|
|
%- to-byts:buf
|
2020-12-10 12:14:03 +03:00
|
|
|
:~ `@ux`bipt.h 0x0 0x0 0x80
|
2020-12-10 11:22:23 +03:00
|
|
|
0x0 0x0 0x0 0x80
|
|
|
|
0x0 0x0 0x0 0x80
|
2020-12-10 12:14:03 +03:00
|
|
|
`@ux`chyg.h 0x0 0x0 0x0
|
2020-12-10 11:22:23 +03:00
|
|
|
==
|
2020-12-11 13:10:40 +03:00
|
|
|
(flip:byt 4^idx.h)
|
2020-12-10 11:22:23 +03:00
|
|
|
==
|
2020-12-10 18:54:39 +03:00
|
|
|
::
|
|
|
|
++ keyval-byts
|
|
|
|
|= kv=keyval:psbt
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
2020-12-10 18:54:39 +03:00
|
|
|
%- cat:byt
|
|
|
|
:~ 1^wid.key.kv
|
|
|
|
key.kv
|
|
|
|
1^wid.val.kv
|
|
|
|
val.kv
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ map-byts
|
|
|
|
|= m=map:psbt
|
2021-01-26 21:36:21 +03:00
|
|
|
^- (unit hexb)
|
2020-12-10 18:54:39 +03:00
|
|
|
?~ m ~
|
|
|
|
:- ~
|
|
|
|
%- cat:byt
|
|
|
|
(turn m keyval-byts)
|
2020-12-10 16:22:48 +03:00
|
|
|
--
|
2020-12-11 13:10:40 +03:00
|
|
|
++ base64
|
2021-01-26 21:36:21 +03:00
|
|
|
|= b=hexb
|
2020-12-11 13:10:40 +03:00
|
|
|
^- base64:psbt
|
|
|
|
%- en:base64:mimes:html
|
|
|
|
(flip:byt b)
|
2020-12-09 20:33:50 +03:00
|
|
|
:: +encode: make base64 cord of PSBT
|
2020-12-15 12:35:33 +03:00
|
|
|
:: - only-witness: don't include non-witness UTXO
|
2020-12-09 20:33:50 +03:00
|
|
|
::
|
|
|
|
++ encode
|
2020-12-15 12:35:33 +03:00
|
|
|
|= $: only-witness=?
|
2021-01-26 21:36:21 +03:00
|
|
|
rawtx=hexb
|
|
|
|
txid=hexb
|
2020-12-15 12:35:33 +03:00
|
|
|
inputs=(list in:psbt)
|
|
|
|
outputs=(list out:psbt)
|
|
|
|
==
|
2020-12-10 19:15:25 +03:00
|
|
|
^- base64:psbt
|
2021-01-26 21:36:21 +03:00
|
|
|
=/ sep=(unit hexb) `1^0x0
|
|
|
|
=/ final=(list (unit hexb))
|
2020-12-11 14:12:53 +03:00
|
|
|
%+ join sep
|
2020-12-10 18:54:39 +03:00
|
|
|
%+ turn
|
|
|
|
%- zing
|
|
|
|
:~ ~[(globals:en rawtx)]
|
2020-12-15 12:35:33 +03:00
|
|
|
(turn inputs (cury input:en only-witness))
|
2020-12-10 18:54:39 +03:00
|
|
|
(turn outputs output:en)
|
|
|
|
==
|
|
|
|
map-byts:en
|
2020-12-11 13:10:40 +03:00
|
|
|
%- base64:en
|
2020-12-10 19:15:25 +03:00
|
|
|
%- cat:byt
|
|
|
|
%+ weld ~[[5 0x70.7362.74ff]]
|
2020-12-11 14:12:53 +03:00
|
|
|
(murn (snoc final sep) same)
|
2020-12-08 20:31:21 +03:00
|
|
|
::
|
2020-12-08 15:47:51 +03:00
|
|
|
++ parse
|
|
|
|
|= psbt-base64=cord
|
2020-12-10 11:22:23 +03:00
|
|
|
^- (list map:psbt)
|
2020-12-09 22:59:13 +03:00
|
|
|
=/ todo=buffer
|
2020-12-08 17:48:40 +03:00
|
|
|
%+ slag 5 (to-buffer psbt-base64)
|
2020-12-10 11:22:23 +03:00
|
|
|
=| acc=(list map:psbt)
|
|
|
|
=| m=map:psbt
|
2020-12-08 17:48:40 +03:00
|
|
|
|-
|
|
|
|
?~ todo (snoc acc m)
|
|
|
|
:: 0x0: map separator
|
|
|
|
?: =(0x0 i.todo)
|
2020-12-10 11:22:23 +03:00
|
|
|
$(acc (snoc acc m), m *map:psbt, todo t.todo)
|
2020-12-08 17:48:40 +03:00
|
|
|
=+ [kv rest]=(next-keyval todo)
|
|
|
|
$(m (snoc m kv), todo rest)
|
|
|
|
:: +get-txid: extract txid from a valid PSBT
|
|
|
|
::
|
2020-12-08 15:32:23 +03:00
|
|
|
++ get-txid
|
2020-12-08 15:47:51 +03:00
|
|
|
|= psbt-base64=cord
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
|
|
|
=/ tx=hexb
|
2020-12-07 14:56:50 +03:00
|
|
|
%- raw-tx
|
|
|
|
%+ slag 5
|
2020-12-08 15:47:51 +03:00
|
|
|
(to-buffer psbt-base64)
|
2020-12-10 11:22:23 +03:00
|
|
|
%- flip:byt
|
|
|
|
%- sha256
|
|
|
|
(sha256 tx)
|
2020-12-07 14:56:50 +03:00
|
|
|
:: +raw-tx: extract hex transaction
|
|
|
|
:: looks for key 0x0 in global map
|
|
|
|
:: crashes if tx not in buffer
|
|
|
|
::
|
|
|
|
++ raw-tx
|
2020-12-09 22:59:13 +03:00
|
|
|
|= b=buffer
|
2021-01-26 21:36:21 +03:00
|
|
|
|- ^- hexb
|
2020-12-07 14:56:50 +03:00
|
|
|
?~ b !!
|
|
|
|
?: =(0x0 i.b) !!
|
2020-12-08 17:48:40 +03:00
|
|
|
=+ nk=(next-keyval b)
|
|
|
|
?: =(0x0 dat.key.kv.nk)
|
|
|
|
val.kv.nk
|
|
|
|
$(b rest.nk)
|
|
|
|
:: +next-keyval: returns next key-val in a PSBT map
|
2020-12-07 14:56:50 +03:00
|
|
|
:: input buffer head must be a map key length
|
|
|
|
::
|
2020-12-08 17:48:40 +03:00
|
|
|
++ next-keyval
|
2020-12-09 22:59:13 +03:00
|
|
|
|= b=buffer
|
2020-12-10 11:22:23 +03:00
|
|
|
^- [kv=keyval:psbt rest=buffer]
|
2020-12-07 14:56:50 +03:00
|
|
|
=+ klen=(snag 0 b)
|
|
|
|
=+ k=(swag [1 klen] b)
|
|
|
|
=+ vlen=(snag (add 1 klen) b)
|
|
|
|
=+ v=(swag [(add 2 klen) vlen] b)
|
|
|
|
=+ len=(add 2 (add klen vlen))
|
|
|
|
?> ?=([^ ^] [k v])
|
2020-12-08 15:42:39 +03:00
|
|
|
:_ (slag len b)
|
2020-12-09 22:59:13 +03:00
|
|
|
:- (to-byts:buf k)
|
|
|
|
(to-byts:buf v)
|
2020-12-08 15:42:39 +03:00
|
|
|
::
|
2020-12-08 15:36:51 +03:00
|
|
|
++ to-buffer
|
2020-12-08 15:47:51 +03:00
|
|
|
|= psbt-base64=cord
|
2020-12-09 22:59:13 +03:00
|
|
|
^- buffer
|
2020-12-08 15:36:51 +03:00
|
|
|
~| "Invalid PSBT"
|
2020-12-09 12:10:11 +03:00
|
|
|
=+ p=(de:base64:mimes:html psbt-base64)
|
2020-12-08 15:36:51 +03:00
|
|
|
?~ p !!
|
2020-12-11 13:10:40 +03:00
|
|
|
(from-byts:buf (flip:byt u.p))
|
2020-12-07 14:56:50 +03:00
|
|
|
--
|
2020-12-08 19:16:16 +03:00
|
|
|
:: buffer: byte buffer utilities
|
2020-10-16 10:33:10 +03:00
|
|
|
:: list of @ux that is big endian for hashing purposes
|
|
|
|
:: used to preserve 0s when concatenating byte sequences
|
|
|
|
::
|
2020-12-09 22:59:13 +03:00
|
|
|
++ buf
|
2020-10-15 13:55:41 +03:00
|
|
|
|%
|
2020-10-16 10:33:10 +03:00
|
|
|
++ from-byts
|
2020-12-09 22:59:13 +03:00
|
|
|
|= =byts ^- buffer
|
2020-10-16 10:33:10 +03:00
|
|
|
=/ b=(list @ux)
|
|
|
|
(flop (rip 3 dat.byts))
|
|
|
|
=/ pad=@ (sub wid.byts (lent b))
|
|
|
|
(weld (reap pad 0x0) b)
|
2020-12-10 11:22:23 +03:00
|
|
|
:: converts byts to a little endian buffer with wid length (trailing 0s)
|
2020-10-16 12:28:51 +03:00
|
|
|
:: atom 1 with wid=4 becomes ~[0x1 0x0 0x0 0x0]
|
|
|
|
:: 0xff11 with wid=8 becomes ~[0x11 0xff 0x0 0x0 0x0 0x0 0x0 0x0]
|
|
|
|
::
|
2020-12-10 11:22:23 +03:00
|
|
|
++ from-byts-le
|
2021-01-26 21:36:21 +03:00
|
|
|
|= =byts
|
|
|
|
^- buffer
|
2020-12-10 11:22:23 +03:00
|
|
|
=/ b=(list @ux) (rip 3 dat.byts)
|
|
|
|
=/ pad=@ (sub wid.byts (lent b))
|
2020-10-16 12:28:51 +03:00
|
|
|
(weld b (reap pad 0x0))
|
2020-10-16 10:33:10 +03:00
|
|
|
::
|
|
|
|
++ to-byts
|
2020-12-09 22:59:13 +03:00
|
|
|
|= b=buffer ^- byts
|
2020-10-16 10:33:10 +03:00
|
|
|
[(lent b) (rep 3 (flop b))]
|
2020-11-20 14:58:27 +03:00
|
|
|
::
|
2020-10-16 12:28:51 +03:00
|
|
|
++ concat-as-byts
|
2020-12-09 22:59:13 +03:00
|
|
|
|= bs=(list buffer) ^- byts
|
2020-10-16 12:28:51 +03:00
|
|
|
%- to-byts (zing bs)
|
2020-10-15 13:55:41 +03:00
|
|
|
--
|
2020-12-09 22:59:13 +03:00
|
|
|
++ byt
|
|
|
|
|%
|
2020-12-10 11:22:23 +03:00
|
|
|
:: +cat: concat byts, preserving MSB order
|
|
|
|
:: (cat:byt ~[4^0xaa00 4^0xbb00]) => [8 0xaa00.00bb.0000]
|
|
|
|
::
|
2020-12-09 22:59:13 +03:00
|
|
|
++ cat
|
|
|
|
|= bs=(list byts)
|
|
|
|
^- byts
|
|
|
|
:- (roll (turn bs |=(b=byts -.b)) add)
|
|
|
|
(can 3 (flop bs))
|
|
|
|
--
|
2020-12-10 11:22:23 +03:00
|
|
|
:: +flip:byt: flip endianness while preserving lead/trail zeroes
|
|
|
|
::
|
|
|
|
++ flip
|
|
|
|
|= b=byts
|
|
|
|
^- byts
|
2020-12-10 13:37:36 +03:00
|
|
|
[wid.b (rev 3 b)]
|
2021-01-24 13:09:49 +03:00
|
|
|
:: +take: take n bytes from front of byts
|
|
|
|
:: pads front with extra zeroes if n is longer than byts
|
|
|
|
::
|
|
|
|
++ take
|
|
|
|
|= [n=@ b=byts]
|
2021-01-27 16:09:25 +03:00
|
|
|
^- byts
|
2021-01-24 13:09:49 +03:00
|
|
|
?: (gth n wid.b)
|
|
|
|
[n dat.b]
|
|
|
|
[n (rsh [3 (sub wid.b n)] dat.b)]
|
2021-01-25 16:01:36 +03:00
|
|
|
:: +drop: drop n bytes from the front of byts
|
|
|
|
:: returns 0^0x0 if n >= wid.byts
|
|
|
|
::
|
|
|
|
++ drop
|
|
|
|
|= [n=@ b=byts]
|
|
|
|
^- byts
|
|
|
|
?: (gte n wid.b)
|
|
|
|
0^0x0
|
|
|
|
=+ n-take=(sub wid.b n)
|
|
|
|
[n-take (end [3 n-take] dat.b)]
|
2020-10-04 11:56:38 +03:00
|
|
|
::
|
2020-12-09 22:59:13 +03:00
|
|
|
++ bit
|
2020-10-05 10:49:09 +03:00
|
|
|
|%
|
2021-01-27 16:09:25 +03:00
|
|
|
++ cat
|
|
|
|
|= bs=(list bits)
|
|
|
|
^- bits
|
|
|
|
:- (roll (turn bs |=(b=bits wid.b)) add)
|
|
|
|
(can 0 (flop bs))
|
2020-10-05 10:49:09 +03:00
|
|
|
::
|
2021-01-27 16:09:25 +03:00
|
|
|
++ take
|
|
|
|
|= [n=@ b=bits]
|
|
|
|
^- bits
|
|
|
|
?: (gth n wid.b)
|
|
|
|
[n dat.b]
|
|
|
|
[n (rsh [0 (sub wid.b n)] dat.b)]
|
2020-10-05 10:49:09 +03:00
|
|
|
::
|
2021-01-27 16:09:25 +03:00
|
|
|
++ drop
|
|
|
|
|= [n=@ b=byts]
|
|
|
|
^- bits
|
|
|
|
?: (gte n wid.b)
|
|
|
|
0^0b0
|
|
|
|
=+ n-take=(sub wid.b n)
|
|
|
|
[n-take (end [0 n-take] dat.b)]
|
|
|
|
:: +from-atoms: convert atoms of bitwidth to bits
|
|
|
|
::
|
|
|
|
++ from-atoms
|
2020-10-15 13:55:41 +03:00
|
|
|
|= [bitwidth=@ digits=(list @)]
|
2021-01-27 16:09:25 +03:00
|
|
|
^- bits
|
|
|
|
%- cat:bit
|
2020-10-15 13:55:41 +03:00
|
|
|
%+ turn digits
|
2021-01-27 16:09:25 +03:00
|
|
|
|= a=@
|
|
|
|
?> (lte (met 0 a) bitwidth)
|
|
|
|
[bitwidth `@ub`a]
|
|
|
|
:: +to-atoms: convert bits to atoms of bitwidth
|
|
|
|
::
|
|
|
|
++ to-atoms
|
|
|
|
|= [bitwidth=@ bs=bits]
|
|
|
|
^- (list @)
|
|
|
|
=| res=(list @)
|
|
|
|
?> =(0 (mod wid.bs bitwidth))
|
|
|
|
|-
|
|
|
|
?: =(0 wid.bs) res
|
|
|
|
%= $
|
|
|
|
res (snoc res dat:(take bitwidth bs))
|
|
|
|
bs (drop bitwidth bs)
|
|
|
|
==
|
2020-10-05 10:49:09 +03:00
|
|
|
--
|
2020-10-04 11:56:38 +03:00
|
|
|
::
|
2020-10-05 10:49:09 +03:00
|
|
|
++ bech32
|
|
|
|
|%
|
|
|
|
++ prefixes
|
|
|
|
^- (map network tape)
|
|
|
|
(my [[%main "bc"] [%testnet "tb"] ~])
|
|
|
|
++ charset "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
|
|
|
+$ raw-decoded [hrp=tape data=(list @) checksum=(list @)]
|
2020-10-30 14:45:38 +03:00
|
|
|
:: below is a port of: https://github.com/bitcoinjs/bech32/blob/master/index.js
|
2020-10-05 10:49:09 +03:00
|
|
|
::
|
|
|
|
++ polymod
|
|
|
|
|= values=(list @)
|
|
|
|
|^ ^- @
|
|
|
|
=/ gen=(list @ux)
|
|
|
|
~[0x3b6a.57b2 0x2650.8e6d 0x1ea1.19fa 0x3d42.33dd 0x2a14.62b3]
|
|
|
|
=/ chk=@ 1
|
|
|
|
|- ?~ values chk
|
2020-12-09 12:10:11 +03:00
|
|
|
=/ top (rsh [0 25] chk)
|
2020-10-05 10:49:09 +03:00
|
|
|
=. chk
|
2020-12-09 12:10:11 +03:00
|
|
|
(mix i.values (lsh [0 5] (dis chk 0x1ff.ffff)))
|
2020-10-05 10:49:09 +03:00
|
|
|
$(values t.values, chk (update-chk chk top gen))
|
|
|
|
::
|
|
|
|
++ update-chk
|
|
|
|
|= [chk=@ top=@ gen=(list @ux)]
|
|
|
|
=/ is (gulf 0 4)
|
|
|
|
|- ?~ is chk
|
2020-12-09 12:10:11 +03:00
|
|
|
?: =(1 (dis 1 (rsh [0 i.is] top)))
|
2020-10-05 10:49:09 +03:00
|
|
|
$(is t.is, chk (mix chk (snag i.is gen)))
|
|
|
|
$(is t.is)
|
|
|
|
--
|
|
|
|
::
|
|
|
|
++ expand-hrp
|
|
|
|
|= hrp=tape
|
|
|
|
^- (list @)
|
2020-12-09 12:10:11 +03:00
|
|
|
=/ front (turn hrp |=(p=@tD (rsh [0 5] p)))
|
2020-10-05 10:49:09 +03:00
|
|
|
=/ back (turn hrp |=(p=@tD (dis 31 p)))
|
|
|
|
(zing ~[front ~[0] back])
|
|
|
|
::
|
|
|
|
++ verify-checksum
|
|
|
|
|= [hrp=tape data-and-checksum=(list @)]
|
|
|
|
^- ?
|
2021-01-27 16:09:25 +03:00
|
|
|
%- |=(a=@ =(1 a))
|
2020-10-05 10:49:09 +03:00
|
|
|
%- polymod
|
|
|
|
(weld (expand-hrp hrp) data-and-checksum)
|
|
|
|
::
|
|
|
|
++ checksum
|
|
|
|
|= [hrp=tape data=(list @)]
|
|
|
|
^- (list @)
|
|
|
|
:: xor 1 with the polymod
|
2021-01-27 16:09:25 +03:00
|
|
|
::
|
2020-10-05 10:49:09 +03:00
|
|
|
=/ pmod=@
|
|
|
|
%+ mix 1
|
|
|
|
%- polymod
|
|
|
|
(zing ~[(expand-hrp hrp) data (reap 6 0)])
|
|
|
|
%+ turn (gulf 0 5)
|
2020-12-09 12:10:11 +03:00
|
|
|
|=(i=@ (dis 31 (rsh [0 (mul 5 (sub 5 i))] pmod)))
|
2020-10-05 10:49:09 +03:00
|
|
|
::
|
|
|
|
++ charset-to-value
|
|
|
|
|= c=@tD
|
|
|
|
^- (unit @)
|
|
|
|
(find ~[c] charset)
|
|
|
|
++ value-to-charset
|
|
|
|
|= value=@
|
|
|
|
^- (unit @tD)
|
|
|
|
?: (gth value 31) ~
|
|
|
|
`(snag value charset)
|
|
|
|
::
|
|
|
|
++ is-valid
|
|
|
|
|= [bech=tape last-1-pos=@] ^- ?
|
|
|
|
?& ?|(=((cass bech) bech) =((cuss bech) bech)) :: to upper or to lower is same as bech
|
|
|
|
(gte last-1-pos 1)
|
|
|
|
(lte (add last-1-pos 7) (lent bech))
|
|
|
|
(lte (lent bech) 90)
|
|
|
|
(levy bech |=(c=@tD (gte c 33)))
|
|
|
|
(levy bech |=(c=@tD (lte c 126)))
|
|
|
|
==
|
|
|
|
:: data should be 5bit words
|
|
|
|
::
|
|
|
|
++ encode-raw
|
|
|
|
|= [hrp=tape data=(list @)]
|
2021-01-27 16:09:25 +03:00
|
|
|
^- cord
|
2020-10-05 10:49:09 +03:00
|
|
|
=/ combined=(list @)
|
2020-10-16 14:02:55 +03:00
|
|
|
(weld data (checksum hrp data))
|
|
|
|
%- crip
|
2020-10-05 10:49:09 +03:00
|
|
|
(zing ~[hrp "1" (tape (murn combined value-to-charset))])
|
|
|
|
++ decode-raw
|
2021-01-27 16:09:25 +03:00
|
|
|
|= body=cord
|
2020-10-05 10:49:09 +03:00
|
|
|
^- (unit raw-decoded)
|
2021-01-27 16:09:25 +03:00
|
|
|
=/ bech (cass (trip body)) :: to lowercase
|
2020-10-05 10:49:09 +03:00
|
|
|
=/ pos (flop (fand "1" bech))
|
|
|
|
?~ pos ~
|
|
|
|
=/ last-1=@ i.pos
|
|
|
|
?. (is-valid bech last-1) :: check bech32 validity (not segwit validity or checksum)
|
|
|
|
~
|
|
|
|
=/ hrp (scag last-1 bech)
|
|
|
|
=/ encoded-data-and-checksum=(list @)
|
|
|
|
(slag +(last-1) bech)
|
|
|
|
=/ data-and-checksum=(list @)
|
|
|
|
%+ murn encoded-data-and-checksum
|
|
|
|
charset-to-value
|
|
|
|
?. =((lent encoded-data-and-checksum) (lent data-and-checksum)) :: ensure all were in CHARSET
|
|
|
|
~
|
|
|
|
?. (verify-checksum hrp data-and-checksum)
|
|
|
|
~
|
|
|
|
=/ checksum-pos (sub (lent data-and-checksum) 6)
|
|
|
|
`[hrp (scag checksum-pos data-and-checksum) (slag checksum-pos data-and-checksum)]
|
2021-01-27 16:09:25 +03:00
|
|
|
:: +from-address: BIP173 bech32 address encoding to hex
|
|
|
|
:: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
|
|
|
|
:: expects to drop a leading 5-bit 0 (the witness version)
|
2020-10-15 13:55:41 +03:00
|
|
|
::
|
2021-01-27 16:09:25 +03:00
|
|
|
++ from-address
|
|
|
|
|= body=cord
|
2021-01-26 21:36:21 +03:00
|
|
|
^- hexb
|
2021-01-27 16:09:25 +03:00
|
|
|
~| "Invalid bech32 address"
|
|
|
|
=/ d=(unit raw-decoded) (decode-raw body)
|
|
|
|
?> ?=(^ d)
|
|
|
|
=/ bs=bits (from-atoms:bit 5 data.u.d)
|
|
|
|
=/ byt-len=@ (div (sub wid.bs 5) 8)
|
|
|
|
?> =(5^0b0 (take:bit 5 bs))
|
|
|
|
?> ?| =(20 byt-len)
|
|
|
|
=(32 byt-len)
|
|
|
|
==
|
|
|
|
[byt-len `@ux`dat:(take:bit (mul 8 byt-len) (drop:bit 5 bs))]
|
2020-10-05 10:55:10 +03:00
|
|
|
:: pubkey is the 33 byte ECC compressed public key
|
2020-10-15 13:55:41 +03:00
|
|
|
::
|
2020-10-05 10:49:09 +03:00
|
|
|
++ encode-pubkey
|
2021-01-25 16:01:36 +03:00
|
|
|
|= [=network pubkey=byts]
|
2021-01-27 16:09:25 +03:00
|
|
|
^- (unit cord)
|
2021-01-25 16:01:36 +03:00
|
|
|
?. =(33 wid.pubkey)
|
2020-10-05 10:55:10 +03:00
|
|
|
~|('pubkey must be a 33 byte ECC compressed public key' !!)
|
2020-10-05 10:49:09 +03:00
|
|
|
=/ prefix (~(get by prefixes) network)
|
|
|
|
?~ prefix ~
|
|
|
|
:- ~
|
|
|
|
%+ encode-raw u.prefix
|
2021-01-27 16:09:25 +03:00
|
|
|
[0v0 (to-atoms:bit 5 [160 `@ub`dat:(hash-160 pubkey)])]
|
2020-10-05 10:49:09 +03:00
|
|
|
--
|
2020-10-04 11:56:38 +03:00
|
|
|
::
|
|
|
|
--
|