From 84cca6d26fa46304f7c958ef99e39406dbd69d44 Mon Sep 17 00:00:00 2001 From: timlucmiptev Date: Fri, 30 Oct 2020 13:45:38 +0200 Subject: [PATCH] address derivation for BIP84 works --- bippy-scratch.md => BTC.scratch.md | 21 ++++----- WALLET.scratch.md | 70 ++++++++++++++++++++++++++++++ app/btc-wallet-store.hoon | 54 +++-------------------- lib/btc-wallet-store.hoon | 42 ++++++++++++++++++ lib/btc.hoon | 6 ++- sur/btc-wallet-store.hoon | 34 +++++---------- sur/btc.hoon | 2 +- 7 files changed, 142 insertions(+), 87 deletions(-) rename bippy-scratch.md => BTC.scratch.md (86%) create mode 100644 WALLET.scratch.md create mode 100644 lib/btc-wallet-store.hoon diff --git a/bippy-scratch.md b/BTC.scratch.md similarity index 86% rename from bippy-scratch.md rename to BTC.scratch.md index 2ceaa1c02..dc482f49f 100644 --- a/bippy-scratch.md +++ b/BTC.scratch.md @@ -23,10 +23,6 @@ abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon ``` =b -build-file %/lib/btc-scratch/hoon =xpub "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs" -``` - -### Getting BIP84 Address from `xpub` -``` (~(address bip84:b %main xpub)) ``` @@ -188,13 +184,12 @@ Using [BIP 143](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#P Native P2WPKH ``` =btc -build-file %/lib/btc/hoon -=btcs -build-file %/sur/btc/hoon -=input0 (input:tx:btcs [[32 0xfff7.f788.1a80.99af.a694.0d42.d1e7.f636.2bec.3817.1ea3.edf4.3354.1db4.e4ad.969f] 0 0 [4 0xeeff.ffff] [35 0x21.03c9.f483.6b9a.4f77.fc0d.81f7.bcb0.1b7f.1b35.9168.64b9.476c.241c.e9fc.198b.d254.32ac] ~ ~ 625.000.000]) -=input1 (input:tx:btcs [[32 0xef51.e1b8.04cc.89d1.82d2.7965.5c3a.a89e.815b.1b30.9fe2.87d9.b2b5.5d57.b90e.c68a] 0 1 [4 0xffff.ffff] [22 0x14.1d0f.172a.0ecb.48ae.e1be.1f26.87d2.963a.e33f.71a1] ~ `[33 0x2.5476.c2e8.3188.368d.a1ff.3e29.2e7a.cafc.db35.66bb.0ad2.53f6.2fc7.0f07.aeee.6357] 600.000.000]) +=input0 (input:tx:btc [[32 0xfff7.f788.1a80.99af.a694.0d42.d1e7.f636.2bec.3817.1ea3.edf4.3354.1db4.e4ad.969f] 0 0 [4 0xeeff.ffff] [35 0x21.03c9.f483.6b9a.4f77.fc0d.81f7.bcb0.1b7f.1b35.9168.64b9.476c.241c.e9fc.198b.d254.32ac] ~ ~ 625.000.000]) +=input1 (input:tx:btc[[32 0xef51.e1b8.04cc.89d1.82d2.7965.5c3a.a89e.815b.1b30.9fe2.87d9.b2b5.5d57.b90e.c68a] 0 1 [4 0xffff.ffff] [22 0x14.1d0f.172a.0ecb.48ae.e1be.1f26.87d2.963a.e33f.71a1] ~ `[33 0x2.5476.c2e8.3188.368d.a1ff.3e29.2e7a.cafc.db35.66bb.0ad2.53f6.2fc7.0f07.aeee.6357] 600.000.000]) -=output0 (output:tx:btcs [[%bech32 'bc1qs2qtxl0n0rdenan0shy457p6w6k85m2e36f7ze'] 112.340.000]) -=output1 (output:tx:btcs [[%bech32 'bc1q800y9klw0exmu63pkt2sechszel64q2enddkt4'] 223.450.000]) -=utx (unsigned:tx:btcs [1 0x11 ~[input0 input1] ~[output0 output1]]) +=output0 (output:tx:btc [[%bech32 'bc1qs2qtxl0n0rdenan0shy457p6w6k85m2e36f7ze'] 112.340.000]) +=output1 (output:tx:btc [[%bech32 'bc1q800y9klw0exmu63pkt2sechszel64q2enddkt4'] 223.450.000]) +=utx (unsigned:tx:btc [1 0x11 ~[input0 input1] ~[output0 output1]]) (~(sighash unsigned-tx:btc utx) 1) :: gives [wid=32 dat=0xc37a.f311.16d1.b27c.af68.aae9.e3ac.82f1.4779.2901.4d5b.9176.57d0.eb49.478c.b670] @@ -230,9 +225,9 @@ Signing input index 0 (non-witness) ### A sample legacy address-only transaction ``` -=linput0 (input:tx:btcs [[32 0xeccf.7e30.3418.9b85.1985.d871.f913.84b8.ee35.7cd4.7c30.2473.6e56.76eb.2deb.b3f2] 1 0 [4 0xffff.ffff] [25 0x76.a914.0109.6677.6006.953d.5567.439e.5e39.f86a.0d27.3bee.88ac] ~ ~ 100.000.000]) -=loutput0 (output:tx:btcs [[%legacy 0c1runeksijzfVxyrpiyCY2LCBvYsSiFsCm] 99.900.000]) -=lutx (unsigned:tx:btcs [1 0x0 ~[linput0] ~[loutput0]]) +=linput0 (input:tx:btc [[32 0xeccf.7e30.3418.9b85.1985.d871.f913.84b8.ee35.7cd4.7c30.2473.6e56.76eb.2deb.b3f2] 1 0 [4 0xffff.ffff] [25 0x76.a914.0109.6677.6006.953d.5567.439e.5e39.f86a.0d27.3bee.88ac] ~ ~ 100.000.000]) +=loutput0 (output:tx:btc [[%legacy 0c1runeksijzfVxyrpiyCY2LCBvYsSiFsCm] 99.900.000]) +=lutx (unsigned:tx:btc [1 0x0 ~[linput0] ~[loutput0]]) =lh dat:(~(sighash unsigned-tx:btc lutx) 0) =lprivkey 0x18e1.4a7b.6a30.7f42.6a94.f811.4701.e7c8.e774.e7f9.a47e.2c20.35db.29a2.0632.1725 diff --git a/WALLET.scratch.md b/WALLET.scratch.md new file mode 100644 index 000000000..8da4277c2 --- /dev/null +++ b/WALLET.scratch.md @@ -0,0 +1,70 @@ +# btc-wallet-* Scratch Code + +## xpub +``` +=xpub1 "zpub6r8dKyWJ31XF6n69KKeEwLjVC5ruqAbiJ4QCqLsrV36Mvx9WEjUaiPNPGFLHNCCqgCdy6iZC8ZgHsm6a1AUTVBMVbKGemNcWFcwBGSjJKbD" +=xpub2 "xpub6D7yaZieZEeG617UcKXDhbsDeso6bmxSAiGWkvkASoiwcjaRtrH5HeNRnDT25s7zmxYzj6MtFe32dVqcf9YcBKKgn9THHjwn2uSjkvobK4e" +=bl -build-file %/lib/btc-wallet-store/hoon +``` + +### add +``` +:btc-wallet-store|action [%add-wallet xpub ~ ~] +``` + +### get address at indices +``` +=walt1 (from-xpub:walt:bl xpub1 ~ ~) +=walt2 (from-xpub:walt:bl xpub2 ~ ~) +(get-address:walt1 %0 0) +(get-address:walt2 %0 0) +``` + + +## scratch code, refactor +++ update-address + |= [a=address:btc us=(set utxo)] + ^- (quip card _state) + =/ xpubs=(list tape) + %~ tap in + ~(key by walts.state) + |- ?~ xpubs `state + =/ w=walt (~(got by walts.state) i.xpubs) + ?: (~(has by wach.w) a) + %: send-address-update + i.xpubs + (update-wallet w a us) + a + us + == + $(xpubs t.xpubs) +:: +++ update-wallet + |= [w=walt a=address:btc us=(set utxo)] + ^- walt + =/ curr-addi=addi + (~(got by wach.w) a) + w(wach (~(put by wach.w) a curr-addi(used %.y, utxos us))) +:: +++ send-address-update + |= [xpub=tape =walt a=address:btc us=(set utxo)] + ^- (quip card _state) + :_ state(walts (~(put by walts.state) xpub walt)) + ~[[%give %fact ~[/wallets] %btc-wallet-store-update !>([%address a us])]] +:: +++ add-wallet + |= [xpub=tape scan-to=(unit scon) max-gap=(unit @)] + ^- (quip card _state) + ?: (~(has by walts.state) xpub) + ~& >>> "xpub already imported" + `state + =/ wallet=walt + :* (from-extended:bip32 xpub) + (xpub-type:btc xpub) + *wach + [0 0] + %.n + (fall scan-to *scon) + (fall max-gap max-gap.state) + == + `state(walts (~(put by walts.state) xpub wallet)) diff --git a/app/btc-wallet-store.hoon b/app/btc-wallet-store.hoon index ac0f30ddf..59df8b384 100644 --- a/app/btc-wallet-store.hoon +++ b/app/btc-wallet-store.hoon @@ -6,7 +6,7 @@ :: watched address updates :: /- *btc-wallet-store -/+ dbug, default-agent, bip32, btc +/+ dbug, default-agent, *btc-wallet-store, btc, bip32 |% +$ versioned-state $% state-0 @@ -73,55 +73,11 @@ ^- (quip card _state) ?- -.act %add-wallet - (add-wallet +.act) + `state +:: (add-wallet +.act) :: %update-address - (update-address +.act) - == -++ update-address - |= [a=address us=(set utxo)] - ^- (quip card _state) - =/ xpubs=(list tape) - %~ tap in - ~(key by walts.state) - |- ?~ xpubs `state - =/ w=walt (~(got by walts.state) i.xpubs) - ?: (~(has by wach.w) a) - %: send-address-update - i.xpubs - (update-wallet w a us) - a - us - == - $(xpubs t.xpubs) -:: -++ update-wallet - |= [w=walt a=address us=(set utxo)] - ^- walt - =/ curr-addi=addi - (~(got by wach.w) a) - w(wach (~(put by wach.w) a curr-addi(used %.y, utxos us))) -:: -++ send-address-update - |= [xpub=tape =walt a=address us=(set utxo)] - ^- (quip card _state) - :_ state(walts (~(put by walts.state) xpub walt)) - ~[[%give %fact ~[/wallets] %btc-wallet-store-update !>([%address a us])]] -:: -++ add-wallet - |= [xpub=tape scan-to=(unit scon) max-gap=(unit @)] - ^- (quip card _state) - ?: (~(has by walts.state) xpub) - ~& >>> "xpub already imported" `state - =/ wallet=walt - :* (from-extended:bip32 xpub) - (xpub-type:btc xpub) - *wach - [0 0] - %.n - (fall scan-to *scon) - (fall max-gap max-gap.state) - == - `state(walts (~(put by walts.state) xpub wallet)) + :: (update-address +.act) + == -- diff --git a/lib/btc-wallet-store.hoon b/lib/btc-wallet-store.hoon new file mode 100644 index 000000000..19c3a8c9f --- /dev/null +++ b/lib/btc-wallet-store.hoon @@ -0,0 +1,42 @@ +/- *btc-wallet-store +/+ bip32, btc +=, secp:crypto +=+ ecc=secp256k1 +|% +++ default-max-gap 20 +:: xpub +:: wilt +:: bipt: BIP44/49/84 +:: wach +:: next: next index to generate address for in non-change/change accounts respectively +:: scanned: whether the wallet's addresses have been checked for prior activity +:: if unscanned, 'next' values won't be valid +:: scan-to +:: max-gap +:: +++ walt + |_ [=wilt =bipt =wach next=idxs scanned=? scan-to=scon max-gap=@u] + ++ from-xpub + |= [xpub=tape scan-to=(unit scon) max-gap=(unit @u)] + %= +> + wilt (from-extended:bip32 xpub) + bipt (xpub-type:btc xpub) + wach *^wach + next [0 0] + scanned %.n + scan-to (fall scan-to *scon) + max-gap (fall max-gap default-max-gap) + == + ++ get-address + |= [=chyg idx=@] + ^- address:btc + =/ pubkey=@ux + %- compress-point:ecc + pub:(derive-public:(derive-public:wilt (@u chyg)) idx) + ~& > pubkey + ?: ?=(%bip84 bipt) + (need (encode-pubkey:bech32:btc %main pubkey)) +:: [%legacy (@uc pubkey)] + ~|("legacy addresses not supported yet" !!) + -- +-- diff --git a/lib/btc.hoon b/lib/btc.hoon index ee41ff4ab..4a7f0206a 100644 --- a/lib/btc.hoon +++ b/lib/btc.hoon @@ -1,4 +1,7 @@ -/- *btc +/- sur=btc +^? +=< [sur .] +=, sur |% ++ xpub-type |= xpub=tape @@ -264,6 +267,7 @@ (my [[%main "bc"] [%testnet "tb"] ~]) ++ charset "qpzry9x8gf2tvdw0s3jn54khce6mua7l" +$ raw-decoded [hrp=tape data=(list @) checksum=(list @)] + :: below is a port of: https://github.com/bitcoinjs/bech32/blob/master/index.js :: ++ polymod |= values=(list @) diff --git a/sur/btc-wallet-store.hoon b/sur/btc-wallet-store.hoon index 52acd9e9e..ba5d95a81 100644 --- a/sur/btc-wallet-store.hoon +++ b/sur/btc-wallet-store.hoon @@ -5,39 +5,27 @@ /- *btc /+ bip32 |% -:: chyg: stores the state of a change/non-change path +++ max-index (dec (pow 2 32)) +:: chyg: whether account is non-change/change +:: idxs: pair of indices (non-change/change) :: addi: address with metadata inside a change path :: wach: map for watched addresses :: scon: indices to initially scan to in non-change/change accounts respectively -:: defaults to 2^32-1 (i.e. all the addresses) +:: defaults to 2^32-1 (i.e. all the addresses, ~4B) :: wilt: stores xpub; copulates with thousands of indices to form addresses :: walt: wallet metadata :: +$ chyg $?(%0 %1) -+$ addi [=chyg idx=@ used=? utxos=(set utxo)] ++$ idxs (pair @u @u) ++$ addi [=chyg idx=@u used=? utxos=(set utxo)] +$ wach (map address addi) -++ max-index (dec (pow 2 32)) -+$ scon $~([max-index max-index] (pair @ @)) ++$ scon $~([max-index max-index] idxs) +$ wilt _bip32 -+$ walt - $: :: bipt: BIP44/49/84 - :: next: next index to generate address for in non-change/change accounts respectively - :: scanned: whether the wallet's addresses have been checked for prior activity - :: if unscanned, 'next' values won't be valid - :: - =wilt - =bipt - =wach - next=(pair @ @) - scanned=? - scan-to=scon - max-gap=@ - == -+$ action - $% [%add-wallet xpub=tape scan-to=(unit scon) max-gap=(unit @)] - [%update-address =address utxos=(set utxo)] ++$ action + $% [%add-wallet xpub=tape scan-to=(unit scon) max-gap=(unit @u)] + [%update-address a=address utxos=(set utxo)] == +$ update - $% [%address =address utxos=(set utxo)] + $% [%address a=address utxos=(set utxo)] == -- diff --git a/sur/btc.hoon b/sur/btc.hoon index 4c2bbaf3b..28e188309 100644 --- a/sur/btc.hoon +++ b/sur/btc.hoon @@ -4,7 +4,7 @@ +$ bech32-address $%([%bech32 cord]) +$ address ?(legacy-address bech32-address) +$ bipt $?(%bip44 %bip49 %bip84) -+$ sats @ud :: ++$ sats @ud +$ hash256 [wid=%32 dat=@ux] +$ hash160 [wid=%20 dat=@ux] +$ hash ?(hash256 hash160)