diff --git a/app/test.hoon b/app/test.hoon index 4a5849bd5d..355e60312d 100644 --- a/app/test.hoon +++ b/app/test.hoon @@ -155,6 +155,7 @@ :- /lib/sole "ford can't handle surs from libs" :- /lib/hall "ford can't handle surs from libs" :- /lib/twitter "ford can't handle surs from libs" + :- /lib/keygen "ford can't handle surs from libs" :- /sys/arvo "BROKEN" :- /sys/vane/jael "expects our" :- /sys/vane/xmas "expects our" diff --git a/lib/bip32.hoon b/lib/bip32.hoon new file mode 100644 index 0000000000..90f822f3e0 --- /dev/null +++ b/lib/bip32.hoon @@ -0,0 +1,216 @@ +:: bip32 implementation in hoon +:: +:: to use, call one of the core initialization arms. +:: using the produced core, derive as needed and take out the data you want. +:: +::NOTE tested to be correct against +:: https://en.bitcoin.it/wiki/BIP_0032_TestVectors +:: +=, hmac:crypto +=, secp:crypto +=+ ecc=secp256k1 +:: +:: prv: private key +:: pub: public key +:: cad: chain code +:: dep: depth in chain +:: ind: index at depth +:: pif: parent fingerprint (4 bytes) +|_ [prv=@ pub=pont cad=@ dep=@ud ind=@ud pif=@] +:: ++= keyc [key=@ cai=@] :: prv/pub key + chain code +:: +:: elliptic curve operations and values +:: +++ point priv-to-pub.ecc +:: +++ ser-p compress-point.ecc +:: +++ n ^n:ecc +:: +:: core initialization +:: +++ from-seed + |= byts + ^+ +> + =+ der=(hmac-sha512l [12 'dees nioctiB'] [wid dat]) + =+ pri=(cut 3 [32 32] der) + +>.$(prv pri, pub (point pri), cad (cut 3 [0 32] der)) +:: +++ from-private + |= keyc + +>(prv key, pub (point key), cad cai) +:: +++ from-public + |= keyc + +>(pub (decompress-point.ecc key), cad cai) +:: +++ from-public-point + |= [pon=pont cai=@] + +>(pub pon, cad cai) +:: +++ from-extended + |= t=tape + =+ x=(de-base58check 4 t) + => |% + ++ take + |= b=@ud + ^- [v=@ x=@] + :- (end 3 b x) + (rsh 3 b x) + -- + =^ k x (take 33) + =^ c x (take 32) + =^ i x (take 4) + =^ p x (take 4) + =^ d x (take 1) + ?> =(0 x) :: sanity check + %. [d i p] + =< set-metadata + =+ v=(scag 4 t) + ?: =("xprv" v) (from-private k c) + ?: =("xpub" v) (from-public k c) + !! +:: +++ set-metadata + |= [d=@ud i=@ud p=@] + +>(dep d, ind i, pif p) +:: +:: derivation +:: +++ derivation-path + ;~ pfix + ;~(pose (jest 'm/') (easy ~)) + %+ most fas ::TODO net + ;~ pose + %+ cook + |=(i=@ (add i (bex 31))) + ;~(sfix dem soq) ::TODO say + :: + dem + == == +:: +++ derive-path + |= t=tape + %- derive-sequence + (scan t derivation-path) +:: +++ derive-sequence + |= j=(list @u) + ?~ j +> + =. +> (derive i.j) + $(j t.j) +:: +++ derive + ?: =(0 prv) + derive-public + derive-private +:: +++ derive-private + |= i=@u + ^+ +> + :: we must have a private key to derive the next one + ?: =(0 prv) + ~| %know-no-private-key + !! + :: derive child at i + =+ ^- [left=@ right=@] ::TODO =/ w/o face + =- [(cut 3 [32 32] -) (cut 3 [0 32] -)] + %+ hmac-sha512l [32 cad] + :- 37 + ?: (gte i (bex 31)) + :: hardened child + (can 3 ~[4^i 32^prv 1^0]) + :: normal child + (can 3 ~[4^i 33^(ser-p (point prv))]) + =+ key=(mod (add left prv) n) + :: rare exception, invalid key, go to the next one + ?: |(=(0 key) (gte left n)) $(i +(i)) + %_ +>.$ + prv key + pub (point key) + cad right + dep +(dep) + ind i + pif fingerprint + == +:: +++ derive-public + |= i=@u + ^+ +> + :: public keys can't be hardened + ?: (gte i (bex 31)) + ~| %cant-derive-hardened-public-key + !! + :: derive child at i + =+ ^- [left=@ right=@] ::TODO =/ w/o face + =- [(cut 3 [32 32] -) (cut 3 [0 32] -)] + %+ hmac-sha512l [32 cad] + 37^(can 3 ~[4^i 33^(ser-p pub)]) + :: rare exception, invalid key, go to the next one + ?: (gte left n) $(i +(i)) ::TODO or child key is "point at infinity" + %_ +>.$ + pub (jc-add.ecc (point left) pub) + cad right + dep +(dep) + ind i + pif fingerprint + == +:: +:: rendering +:: +++ private-key ?.(=(0 prv) prv ~|(%know-no-private-key !!)) +++ public-key (ser-p pub) +++ chain-code cad +++ private-chain [private-key cad] +++ public-chain [public-key cad] +:: +++ identity (hash160 public-key) +++ fingerprint (cut 3 [16 4] identity) +:: +++ prv-extended + %+ en-b58c-bip32 0x488.ade4 + (build-extended private-key) +:: +++ pub-extended + %+ en-b58c-bip32 0x488.b21e + (build-extended public-key) +:: +++ build-extended + |= key=@ + %+ can 3 + :~ 33^key + 32^cad + 4^ind + 4^pif + 1^dep + == +:: +++ en-b58c-bip32 + |= [v=@ k=@] + (en-base58check [4 v] [74 k]) +:: +:: base58check +:: +++ en-base58check + :: v: version bytes + :: d: data + |= [v=byts d=byts] + %- en-base58:mimes:html + =+ p=[(add wid.v wid.d) (can 3 ~[d v])] + =- (can 3 ~[4^- p]) + %^ rsh 3 28 + (sha-256l:sha 32 (sha-256l:sha p)) +:: +++ de-base58check + :: vw: amount of version bytes + |= [vw=@u t=tape] + =+ x=(de-base58:mimes:html t) + =+ hash=(sha-256l:sha 32 (sha-256:sha (rsh 3 4 x))) + ?> =((end 3 4 x) (rsh 3 28 hash)) + (cut 3 [vw (sub (met 3 x) (add 4 vw))] x) +:: +++ hash160 + |= d=@ + (ripemd-160:ripemd:crypto 256 (sha-256:sha d)) +-- diff --git a/lib/keygen.hoon b/lib/keygen.hoon new file mode 100644 index 0000000000..a793d05726 --- /dev/null +++ b/lib/keygen.hoon @@ -0,0 +1,115 @@ +:: urbit-style key generation and derivation functions +:: +/- keygen +:: +/+ bip32 +:: +:: +=, sha +=, ^keygen +:: +|% +++ to-byts + |= a=@t + =+ (met 3 a) + [- (rev 3 - a)] +:: +++ argon2u + |= [inp=byts out=@ud] + ^- @ + %- (argon2-urbit:argon2:crypto out) + [inp (to-byts 'urbitkeygen')] +:: +++ child-node-from-seed + |= [seed=byts met=meta pass=(unit @t)] + ^- node + =+ dr=~(. sd pass) + =+ child-seed=(seed:dr seed met) + :+ met dat.child-seed + (wallet:dr child-seed) +:: +++ full-wallet-from-ticket + |= [ticket=byts seed-size=@ud sis=(set ship) pass=(unit @t) revs=revisions] + =+ owner-seed=seed-size^(argon2u ticket seed-size) + (full-wallet-from-seed owner-seed sis pass revs) +:: +++ full-wallet-from-seed + |= [owner-seed=byts sis=(set ship) pass=(unit @t) revs=revisions] + =+ dr=~(. sd pass) + =+ cn=|=([s=byts m=meta] (child-node-from-seed s m pass)) + :: + :- ^= owner ^- node + :+ *meta dat.owner-seed + (wallet:dr owner-seed) + :: + :- ^= delegate + (cn owner-seed "delegate" delegate.revs ~) + :: + =/ manage=node + (cn owner-seed "manage" manage.revs ~) + :- manage=manage + :: + :- ^= transfer + %- ~(rep in sis) + |= [s=ship n=nodes] + %+ ~(put by n) s + (cn owner-seed "transfer" transfer.revs `s) + :: + :- ^= spawn + %- ~(rep in sis) + |= [s=ship n=nodes] + %+ ~(put by n) s + (cn owner-seed "spawn" spawn.revs `s) + :: + ^= network + %- ~(rep in sis) + |= [s=ship u=uodes] + %+ ~(put by u) s + =+ m=["network" network.revs `s] + =+ s=(seed:dr [wid.owner-seed seed.manage] m) + [m dat.s (urbit:dr s)] +:: +++ sd :: seed derivation + |_ pass=(unit @t) + ++ append-pass + |= b=byts + ^- byts + =+ (fall pass '') + :- (add wid.b (met 3 -)) + (cat 3 (swp 3 -) dat.b) + :: + ++ wallet + %+ cork append-pass + |= seed=byts + ^- ^wallet + => (from-seed:bip32 64^(sha-512l seed)) + [public-key private-key chain-code] + :: + ++ urbit + %+ cork append-pass + |= seed=byts + ^- edkeys + =+ =< [pub=pub:ex sec=sec:ex] + (pit:nu:crub:crypto (mul 8 wid.seed) dat.seed) + :- ^= auth + :- (rsh 3 1 (end 3 33 pub)) + (rsh 3 1 (end 3 33 sec)) + ^= crypt + :- (rsh 3 33 pub) + (rsh 3 33 sec) + :: + ++ seed + |= [seed=byts meta] + ^- byts + :- wid.seed + %^ rsh 3 (sub 64 wid.seed) + %- sha-512l + %- append-pass + =+ ;: weld + typ "-" (a-co:co rev) + ?~(who ~ ['-' (a-co:co u.who)]) + == + :- (add wid.seed (lent -)) + (cat 3 (crip (flop -)) dat.seed) + -- +-- diff --git a/sur/keygen.hoon b/sur/keygen.hoon new file mode 100644 index 0000000000..655d4cd910 --- /dev/null +++ b/sur/keygen.hoon @@ -0,0 +1,17 @@ +|% ++= nodes (map ship node) ++= uodes (map ship uode) +:: ++= node [meta=meta seed=@ux keys=wallet] ++= uode [meta=meta seed=@ux keys=edkeys] +:: ++= meta [typ=tape rev=@ud who=(unit ship)] +:: ++= wallet [public=@ux private=@ux chain=@ux] +:: ++= edkeys [auth=keypair crypt=keypair] +:: ++= keypair [public=@ux secret=@ux] +:: ++= revisions [transfer=@ud spawn=@ud delegate=@ud manage=@ud network=@ud] +-- diff --git a/sys/zuse.hoon b/sys/zuse.hoon index 6293917624..ebd6b6c691 100644 --- a/sys/zuse.hoon +++ b/sys/zuse.hoon @@ -3693,12 +3693,9 @@ :: :: shorthands :: - ++ argon2-minimal - (argon2 32 %id 0x13 1 8 1 *byts *byts) - :: - ::TODO discuss and standardize? ++ argon2-urbit - (argon2 64 %u 0x13 4 1.024 10 *byts *byts) + |= out=@ud + (argon2 out %u 0x13 4 512.000 1 *byts *byts) :: :: argon2 proper :: @@ -5032,6 +5029,28 @@ (cold 62 (just '+')) (cold 63 (just '/')) == + :: + ++ en-base58 + |= dat=@ + =/ cha + '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + %- flop + |- ^- tape + ?: =(0 dat) ~ + :- (cut 3 [(mod dat 58) 1] cha) + $(dat (div dat 58)) + :: + ++ de-base58 + |= t=tape + =- (scan t (bass 58 (plus -))) + ;~ pose + (cook |=(a=@ (sub a 56)) (shim 'A' 'H')) + (cook |=(a=@ (sub a 57)) (shim 'J' 'N')) + (cook |=(a=@ (sub a 58)) (shim 'P' 'Z')) + (cook |=(a=@ (sub a 64)) (shim 'a' 'k')) + (cook |=(a=@ (sub a 65)) (shim 'm' 'z')) + (cook |=(a=@ (sub a 49)) (shim '1' '9')) + == -- ::mimes :: :: ++en-json:html ++ en-json :: print json