mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-12 15:01:38 +03:00
tests passing for addresses
This commit is contained in:
parent
b485955df0
commit
5322c66d43
@ -2,3 +2,4 @@
|
||||
*.sh
|
||||
*.md
|
||||
*.txt
|
||||
*.js
|
||||
|
209
lib/btc.hoon
209
lib/btc.hoon
@ -45,56 +45,71 @@
|
||||
%- ripemd-160
|
||||
(sha256 val)
|
||||
::
|
||||
++ base58check
|
||||
|%
|
||||
++ checksum dsha256
|
||||
++ encode
|
||||
|= body=hexb
|
||||
^- tape
|
||||
=> :- .
|
||||
%- cat:byt
|
||||
:~ body
|
||||
(take:byt 4 (checksum body))
|
||||
++ pubkey-to-address
|
||||
|= [=bipt =network pubkey=hexb]
|
||||
^- address
|
||||
?- bipt
|
||||
%44
|
||||
:- %base58
|
||||
=< ^-(@uc dat)
|
||||
%- cat:byt
|
||||
:- ?- network
|
||||
%main 1^0x0
|
||||
%testnet 1^0x6f
|
||||
==
|
||||
(en-base58:mimes:html dat)
|
||||
::
|
||||
++ decode
|
||||
|= b=tape
|
||||
^- hexb
|
||||
~| "Invalid base58check input: {<b>}"
|
||||
=/ h=@ux
|
||||
(de-base58:mimes:html b)
|
||||
:: handle leading 0 ('1' in base68)
|
||||
=/ len=@
|
||||
?: =('1' (snag 0 b))
|
||||
(add 1 (met 3 h))
|
||||
(met 3 h)
|
||||
=/ body=hexb (take (sub len 4) len^h)
|
||||
=/ check=hexb (drop:byt (sub len 4) len^h)
|
||||
?> =(check (take:byt 4 (checksum body)))
|
||||
body
|
||||
--
|
||||
~[(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))
|
||||
==
|
||||
::
|
||||
++ script-pubkey
|
||||
|= =address
|
||||
^- hexb
|
||||
?- -.address
|
||||
:: TODO: make work for P2WSH (32 byte bech32)
|
||||
%bech32
|
||||
=+ h=(to-hex:bech32 address)
|
||||
=+ h=(from-address:bech32 +.address)
|
||||
%- cat:byt
|
||||
:~ 1^0x0
|
||||
1^wid.h
|
||||
h
|
||||
==
|
||||
:: TODO switch on 1/3 below
|
||||
:: https://bitcoinops.org/en/tools/calc-size/
|
||||
:: above link shows how to make P2PKH and P2SH, which I'd need here
|
||||
::
|
||||
%base58
|
||||
~|("base58 not supported" !!)
|
||||
:: (decode:base58check (trip +.address))
|
||||
=/ 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]
|
||||
?: =(0x6f lead-byt) [%49 %testnet]
|
||||
~|("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
|
||||
==
|
||||
==
|
||||
:: +txu: tx utility functions
|
||||
::
|
||||
++ txu
|
||||
|%
|
||||
++ en
|
||||
@ -451,6 +466,7 @@
|
||||
::
|
||||
++ take
|
||||
|= [n=@ b=byts]
|
||||
^- byts
|
||||
?: (gth n wid.b)
|
||||
[n dat.b]
|
||||
[n (rsh [3 (sub wid.b n)] dat.b)]
|
||||
@ -464,50 +480,52 @@
|
||||
0^0x0
|
||||
=+ n-take=(sub wid.b n)
|
||||
[n-take (end [3 n-take] dat.b)]
|
||||
:: Converts a list of bits to a list of n-bit numbers
|
||||
:: input-bits should be big-endian
|
||||
::
|
||||
++ bit
|
||||
|%
|
||||
:: rip atom a with num-bits. Preserve leading 0s, big endian
|
||||
:: returns a list of bits
|
||||
++ cat
|
||||
|= bs=(list bits)
|
||||
^- bits
|
||||
:- (roll (turn bs |=(b=bits wid.b)) add)
|
||||
(can 0 (flop bs))
|
||||
::
|
||||
++ zeros-brip
|
||||
|= [num-bits=@ a=@]
|
||||
^- (list @)
|
||||
=/ bits=(list @) (flop (rip 0 a))
|
||||
=/ pad=@ (sub num-bits (lent bits))
|
||||
(weld (reap pad 0) bits)
|
||||
:: +convert: list of bits to a list of atoms each with bitwidth d(est)
|
||||
++ take
|
||||
|= [n=@ b=bits]
|
||||
^- bits
|
||||
?: (gth n wid.b)
|
||||
[n dat.b]
|
||||
[n (rsh [0 (sub wid.b n)] dat.b)]
|
||||
::
|
||||
++ convert
|
||||
|= [d=@ bits=(list @)]
|
||||
^- (list @)
|
||||
=| ret=(list @)
|
||||
|- ?~ bits ret
|
||||
=/ dest-bits (scag d ((list @) bits))
|
||||
:: left-shift the "missing" number of bits
|
||||
=/ num=@
|
||||
%+ lsh [0 (sub d (lent dest-bits))]
|
||||
(rep 0 (flop dest-bits))
|
||||
$(ret (snoc ret num), bits (slag d ((list @) bits)))
|
||||
:: Converts e.g. ~[0 0 31 31 31 31 0 0] in base32 (5 bitwidth)
|
||||
:: to ~[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0]
|
||||
++ 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-digits
|
||||
++ from-atoms
|
||||
|= [bitwidth=@ digits=(list @)]
|
||||
^- (list @)
|
||||
%- zing
|
||||
^- bits
|
||||
%- cat:bit
|
||||
%+ turn digits
|
||||
|= d=@ (zeros-brip bitwidth d)
|
||||
:: converts 40 bits: ~[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0]
|
||||
:: to 0x3fff.fc00 when cast to hex
|
||||
|= a=@
|
||||
?> (lte (met 0 a) bitwidth)
|
||||
[bitwidth `@ub`a]
|
||||
:: +to-atoms: convert bits to atoms of bitwidth
|
||||
::
|
||||
++ to-atom
|
||||
|= bits=(list @)
|
||||
^- @
|
||||
%+ rep 0
|
||||
%- flop bits
|
||||
++ 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)
|
||||
==
|
||||
--
|
||||
::
|
||||
++ bech32
|
||||
@ -550,8 +568,7 @@
|
||||
++ verify-checksum
|
||||
|= [hrp=tape data-and-checksum=(list @)]
|
||||
^- ?
|
||||
%+ |=([a=@ b=@] =(a b))
|
||||
1
|
||||
%- |=(a=@ =(1 a))
|
||||
%- polymod
|
||||
(weld (expand-hrp hrp) data-and-checksum)
|
||||
::
|
||||
@ -559,6 +576,7 @@
|
||||
|= [hrp=tape data=(list @)]
|
||||
^- (list @)
|
||||
:: xor 1 with the polymod
|
||||
::
|
||||
=/ pmod=@
|
||||
%+ mix 1
|
||||
%- polymod
|
||||
@ -589,16 +607,15 @@
|
||||
::
|
||||
++ encode-raw
|
||||
|= [hrp=tape data=(list @)]
|
||||
^- bech32-a
|
||||
^- cord
|
||||
=/ combined=(list @)
|
||||
(weld data (checksum hrp data))
|
||||
:- %bech32
|
||||
%- crip
|
||||
(zing ~[hrp "1" (tape (murn combined value-to-charset))])
|
||||
++ decode-raw
|
||||
|= b=bech32-a
|
||||
|= body=cord
|
||||
^- (unit raw-decoded)
|
||||
=/ bech (cass (trip +.b)) :: to lowercase
|
||||
=/ bech (cass (trip body)) :: to lowercase
|
||||
=/ pos (flop (fand "1" bech))
|
||||
?~ pos ~
|
||||
=/ last-1=@ i.pos
|
||||
@ -616,41 +633,35 @@
|
||||
~
|
||||
=/ checksum-pos (sub (lent data-and-checksum) 6)
|
||||
`[hrp (scag checksum-pos data-and-checksum) (slag checksum-pos data-and-checksum)]
|
||||
:: goes from a bech32 address to hex. Returns byts to preserve leading 0s
|
||||
:: +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)
|
||||
::
|
||||
++ to-hex
|
||||
|= b=bech32-a
|
||||
++ from-address
|
||||
|= body=cord
|
||||
^- hexb
|
||||
=/ d=(unit raw-decoded) (decode-raw b)
|
||||
?~ d ~|("Invalid bech32 address" !!)
|
||||
=/ bs=(list @)
|
||||
(from-digits:bit 5 (slag 1 data.u.d))
|
||||
=/ byt-len=@ (div (lent bs) 8)
|
||||
?. =(0 (mod (lent bs) 8))
|
||||
~|("Invalid bech32 address: not 8bit" !!)
|
||||
?. ?|(?=(%20 byt-len) ?=(%32 byt-len))
|
||||
~|("Invalid bech32 address: must be 20 (P2WPKH) or 32 (P2WSH) bytes" !!)
|
||||
[byt-len (to-atom:bit bs)]
|
||||
~| "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))]
|
||||
:: pubkey is the 33 byte ECC compressed public key
|
||||
::
|
||||
++ encode-pubkey
|
||||
|= [=network pubkey=byts]
|
||||
^- (unit bech32-a)
|
||||
^- (unit cord)
|
||||
?. =(33 wid.pubkey)
|
||||
~|('pubkey must be a 33 byte ECC compressed public key' !!)
|
||||
=/ prefix (~(get by prefixes) network)
|
||||
?~ prefix ~
|
||||
:- ~
|
||||
%+ encode-raw u.prefix
|
||||
[0 (convert:bit 5 (zeros-brip:bit 160 dat:(hash-160 pubkey)))]
|
||||
++ encode-hash-160
|
||||
|= [=network h160=byts]
|
||||
^- (unit bech32-a)
|
||||
=/ prefix (~(get by prefixes) network)
|
||||
?~ prefix ~
|
||||
:- ~
|
||||
%+ encode-raw u.prefix
|
||||
[0 (convert:bit 5 (zeros-brip:bit 160 dat.h160))]
|
||||
[0v0 (to-atoms:bit 5 [160 `@ub`dat:(hash-160 pubkey)])]
|
||||
--
|
||||
::
|
||||
--
|
||||
|
10
sur/btc.hoon
10
sur/btc.hoon
@ -3,10 +3,12 @@
|
||||
|%
|
||||
+$ network ?(%main %testnet)
|
||||
+$ hexb [wid=@ dat=@ux] :: hex byts
|
||||
+$ bits [wid=@ dat=@ub]
|
||||
+$ xpub @ta
|
||||
+$ address ?(base58-a bech32-a)
|
||||
+$ base58-a $%([%base58 cord])
|
||||
+$ bech32-a $%([%bech32 cord])
|
||||
+$ address
|
||||
$% [%base58 @uc]
|
||||
[%bech32 cord]
|
||||
==
|
||||
+$ fprint hexb
|
||||
+$ bipt $?(%44 %49 %84)
|
||||
+$ chyg $?(%0 %1)
|
||||
@ -26,7 +28,7 @@
|
||||
|%
|
||||
+$ data
|
||||
$: is=(list input)
|
||||
os=(list output)
|
||||
os=(list output)
|
||||
locktime=@ud
|
||||
nversion=@ud
|
||||
segwit=(unit @ud)
|
||||
|
106
tests/btc.hoon
106
tests/btc.hoon
@ -1,40 +1,88 @@
|
||||
/+ *test, *btc
|
||||
|%
|
||||
+$ key-address [pubkey=hexb =address]
|
||||
+$ pubkey-vec [=bipt =network pubkey=hexb =address]
|
||||
+$ script-pubkey-vec [=address spk=hexb]
|
||||
++ vectors
|
||||
|%
|
||||
++ p2wsh1
|
||||
:: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
||||
^- key-address
|
||||
:* 33^0x3.9b3b.694b.8fc5.b5e0.7fb0.69c7.83ca.c754.f5d3.8c3e.08be.d196.0e31.fdb1.dda3.5c24
|
||||
[%base58 '37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf']
|
||||
++ base32
|
||||
:* atoms=~[0 31 31 0 31 0]
|
||||
bs=[30 0b1.1111.1111.1000.0011.1110.0000]
|
||||
==
|
||||
:: below use mnemonic:
|
||||
:: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
|
||||
::
|
||||
++ pubkeys
|
||||
^- (list pubkey-vec)
|
||||
:~ :* %84
|
||||
%main
|
||||
33^0x3.30d5.4fd0.dd42.0a6e.5f8d.3624.f5f3.482c.ae35.0f79.d5f0.753b.f5be.ef9c.2d91.af3c
|
||||
[%bech32 'bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu']
|
||||
==
|
||||
::
|
||||
:* %44
|
||||
%main
|
||||
33^0x3.aaeb.52dd.7494.c361.049d.e67c.c680.e83e.bcbb.bdbe.b136.37d9.2cd8.45f7.0308.af5e
|
||||
[%base58 0c1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA]
|
||||
==
|
||||
::
|
||||
:* %49
|
||||
%main
|
||||
33^0x3.9b3b.694b.8fc5.b5e0.7fb0.69c7.83ca.c754.f5d3.8c3e.08be.d196.0e31.fdb1.dda3.5c24
|
||||
[%base58 0c37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf]
|
||||
==
|
||||
::
|
||||
:* %84
|
||||
%testnet
|
||||
33^0x2.e7ab.2537.b5d4.9e97.0309.aae0.6e9e.49f3.6ce1.c9fe.bbd4.4ec8.e0d1.cca0.b4f9.c319
|
||||
[%bech32 'tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl']
|
||||
==
|
||||
::
|
||||
:* %44
|
||||
%testnet
|
||||
33^0x2.a745.1395.7353.69f2.ecdf.c829.c0f7.74e8.8ef1.303d.fe5b.2f04.dbaa.b30a.535d.fdd6
|
||||
[%base58 0cmkpZhYtJu2r87Js3pDiWJDmPte2NRZ8bJV]
|
||||
==
|
||||
::
|
||||
:* %49
|
||||
%testnet
|
||||
33^0x3.a1af.804a.c108.a8a5.1782.198c.2d03.4b28.bf90.c880.3f5a.53f7.6276.fa69.a4ea.e77f
|
||||
[%base58 0c2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2]
|
||||
==
|
||||
==
|
||||
::
|
||||
++ script-pubkeys
|
||||
^- (list script-pubkey-vec)
|
||||
:~ :* [%bech32 'bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu']
|
||||
[wid=22 dat=0x14.c0ce.bcd6.c3d3.ca8c.75dc.5ec6.2ebe.5533.0ef9.10e2]
|
||||
==
|
||||
::
|
||||
:* [%bech32 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3']
|
||||
[wid=34 dat=0x20.1863.143c.14c5.1668.04bd.1920.3356.da13.6c98.5678.cd4d.27a1.b8c6.3296.0490.3262]
|
||||
==
|
||||
::
|
||||
==
|
||||
++ psbt1
|
||||
^- base64:psbt
|
||||
'cHNidP8BAHEBAAAAAeECXCgB7Co1v8MkjfseiHiAmD6f5IGHggCodBxdcE6DAQAAAAD/////AtAHAAAAAAAAFgAUmEQgSFlZ0Noj5/6QK/MVgUzHtksw/AAAAAAAABYAFCj6E0N2r50pGUjGeWDtDrP3JxeQAAAAAAABAR+EJQEAAAAAABYAFDi7rsJdW0ystnpbESNGOx1ypK7lIgYDXS/0FkRiWJny6+uNNGt7tpCWk96YQDJnUKqZLWGx9JYYvu/erVQAAIAAAACAAAAAgAEAAAADAAAAAAAiAgOQCPy++fOAW9XIFBqcaec8QU0qPeSDFLD1PR/QrWTSrBi+796tVAAAgAAAAIAAAACAAQAAAAQAAAAA'
|
||||
--
|
||||
++ pk-to-p2wsh
|
||||
|= pubkey=hexb
|
||||
^- hexb
|
||||
%- hash-160
|
||||
%- cat:byt
|
||||
:~ 1^0x0
|
||||
1^0x14
|
||||
(hash-160 pubkey)
|
||||
==
|
||||
::
|
||||
++ run
|
||||
:: base58check encode/decode
|
||||
:: bit manipulation
|
||||
::
|
||||
=/ p2wsh1=key-address
|
||||
p2wsh1:vectors
|
||||
=/ with-version=hexb
|
||||
(cat:byt ~[1^0x5 (pk-to-p2wsh pubkey.p2wsh1)])
|
||||
=/ encoding=tape
|
||||
(encode:base58check with-version)
|
||||
?. =(address.p2wsh1 [%base58 (crip encoding)])
|
||||
~|("pubkey doesn't encode to base58" !!)
|
||||
?. =(with-version (decode:base58check encoding))
|
||||
~|("'can't decode base58 encoding" !!)
|
||||
=/ atoms=(list @) -:base32:vectors
|
||||
=/ =bits +:base32:vectors
|
||||
?. ?& =((from-atoms:bit 5 atoms) bits)
|
||||
=((to-atoms:bit 5 bits) atoms)
|
||||
==
|
||||
~|("base32 bit manipulation failed" !!)
|
||||
:: pubkey to address
|
||||
?. %+ levy pubkeys:vectors
|
||||
|= [=bipt =network pubkey=hexb =address]
|
||||
=(address (pubkey-to-address bipt network pubkey))
|
||||
~|("pubkey doesn't encode to address" !!)
|
||||
::
|
||||
:: script-pubkey from address
|
||||
::
|
||||
?. %+ levy script-pubkeys:vectors
|
||||
|= [a=address spk=hexb]
|
||||
=(spk (script-pubkey a))
|
||||
~|("script-pubkey doesn't encode from address" !!)
|
||||
"All tests passed."
|
||||
--
|
||||
|
Loading…
Reference in New Issue
Block a user