slip10.hoon 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. :: slip-10 implementation in hoon using the cheetah curve
  2. ::
  3. :: to use, call one of the core initialization arms.
  4. :: using the produced core, derive as needed and take out the data you want.
  5. ::
  6. :: NOTE: tested to be correct against the SLIP-10 spec
  7. :: https://github.com/satoshilabs/slips/blob/master/slip-0010.md
  8. ::
  9. /= * /common/zose
  10. /= * /common/zeke
  11. =, hmac:crypto
  12. =, cheetah:zeke
  13. =+ ecc=cheetah
  14. ::
  15. :: prv: private key
  16. :: pub: public key
  17. :: cad: chain code
  18. :: dep: depth in chain
  19. :: ind: index at depth
  20. :: pif: parent fingerprint (4 bytes)
  21. => |%
  22. +$ base [prv=@ pub=a-pt:curve cad=@ dep=@ud ind=@ud pif=@]
  23. --
  24. |_ base
  25. +$ base ^base
  26. ::
  27. +$ keyc [key=@ cai=@] :: prv/pub key + chain code
  28. ::
  29. :: elliptic curve operations and values
  30. ::
  31. ++ point ch-scal:affine:curve
  32. ::
  33. ++ ser-p ser-a-pt
  34. ::
  35. ++ n g-order:curve
  36. ::
  37. ++ domain-separator [14 'dees niahckcoN']
  38. ::
  39. ::
  40. :: rendering
  41. ::
  42. ++ private-key ?.(=(0 prv) prv ~|(%know-no-private-key !!))
  43. ++ public-key (ser-p pub)
  44. ++ chain-code cad
  45. ::
  46. ++ identity (hash160 public-key)
  47. ++ fingerprint (cut 3 [16 4] identity)
  48. ::
  49. ++ hash160
  50. |= d=@
  51. (ripemd-160:ripemd:crypto 32 (sha-256:sha d))
  52. ::
  53. :: core initialization
  54. ::
  55. ++ from-seed
  56. |= byts
  57. ^+ +>
  58. =+ der=(hmac-sha512l domain-separator [wid dat])
  59. =/ [left=@ right=@]
  60. [(cut 3 [32 32] der) (cut 3 [0 32] der)]
  61. ::
  62. :: In the case where the left is greater than or equal to the curve order,
  63. :: We have an invalid key and will use the right digest to rehash until we
  64. :: obtain a valid key. This prevents the distribution from being biased.
  65. |-
  66. ?: (lth left n)
  67. +>.^$(prv left, pub (point left a-gen:curve), cad right)
  68. =/ der (hmac-sha512l domain-separator 64^der)
  69. %= $
  70. der der
  71. left (cut 3 [32 32] der)
  72. right (cut 3 [0 32] der)
  73. ==
  74. ::
  75. ++ from-private
  76. |= keyc
  77. +>(prv key, pub (point key a-gen:curve), cad cai)
  78. ::
  79. :: TODO: why is the input base58 encoded? will it be?
  80. :: TODO: assert that key is in G
  81. :: pt is not inf (id), if you raise it by G-order it should give you inf
  82. ++ from-public
  83. |= keyc
  84. +>(pub (de-a-pt key), cad cai)
  85. ::
  86. :: derivation arms: Only used for testing.
  87. ::
  88. :: +derive-path
  89. ::
  90. :: Given a bip32-style path, i.e "m/0'/25", derive the key associated
  91. :: with that path.
  92. ::
  93. ++ derive-path
  94. |= t=tape
  95. %- derive-sequence
  96. (scan t derivation-path)
  97. ::
  98. :: +derivation-path
  99. ::
  100. :: Parses the bip32-style derivation path and return a list of indices
  101. ::
  102. ++ derivation-path
  103. ;~ pfix
  104. ;~(pose (jest 'm/') (easy ~))
  105. %+ most fas
  106. ;~ pose
  107. %+ cook
  108. |=(i=@ (add i (bex 31)))
  109. ;~(sfix dem soq)
  110. ::
  111. dem
  112. == ==
  113. ::
  114. :: +derive-sequence
  115. ::
  116. :: Derives a key from a list of indices associated with a bip32-style path.
  117. ::
  118. ++ derive-sequence
  119. |= j=(list @u)
  120. ?~ j +>
  121. =. +> (derive i.j)
  122. $(j t.j)
  123. ::
  124. :: +derive
  125. ::
  126. :: Checks if prv has been set to 0, denoting a wallet which only
  127. :: contains public keys. If prv=0, call derive-public otherwise
  128. :: call derive-private.
  129. ::
  130. ++ derive
  131. ?: =(0 prv)
  132. derive-public
  133. derive-private
  134. ::
  135. :: +derive-private
  136. ::
  137. :: derives the i-th child key from `prv`
  138. ::
  139. ++ derive-private
  140. |= i=@u
  141. ^+ +>
  142. :: we must have a private key to derive the next one
  143. ?: =(0 prv)
  144. ~| %know-no-private-key
  145. !!
  146. :: derive child at i
  147. =/ [left=@ right=@]
  148. =- [(cut 3 [32 32] -) (cut 3 [0 32] -)]
  149. %+ hmac-sha512l [32 cad]
  150. ?: (gte i (bex 31))
  151. :: hardened child
  152. [37 (can 3 ~[4^i 32^prv 1^0])]
  153. :: normal child
  154. [101 (can 3 ~[4^i 97^(ser-p (point prv a-gen:curve))])]
  155. =+ key=(mod (add left prv) n)
  156. ::
  157. :: In the case where `left` is greater than or equal to the curve order,
  158. :: or the key is the identity point, we have an invalid key and will
  159. :: rehash `0x1 || right || i` to obtain a valid key. This prevents the
  160. :: distribution from being biased.
  161. |-
  162. ?: &(!=(0 key) (lth left n))
  163. %_ +>.^$
  164. prv key
  165. pub (point key a-gen:curve)
  166. cad right
  167. dep +(dep)
  168. ind i
  169. pif fingerprint
  170. ==
  171. =/ [left=@ right=@]
  172. =- [(cut 3 [32 32] -) (cut 3 [0 32] -)]
  173. %+ hmac-sha512l [32 cad]
  174. [37 (can 3 ~[4^i 32^right 1^0x1])]
  175. %= $
  176. left left
  177. right right
  178. key (mod (add left prv) n)
  179. ==
  180. ::
  181. :: +derive-public
  182. ::
  183. :: derives the i-th child key from `pub`
  184. ++ derive-public
  185. |= i=@u
  186. ^+ +>
  187. :: public keys can't be hardened
  188. ?: (gte i (bex 31))
  189. ~| %cant-derive-hardened-public-key
  190. !!
  191. :: derive child at i
  192. =/ [left=@ right=@]
  193. =- [(cut 3 [32 32] -) (cut 3 [0 32] -)]
  194. %+ hmac-sha512l [32 cad]
  195. 101^(can 3 ~[4^i 97^(ser-p pub)])
  196. =+ key=(ch-add:affine:curve (point left a-gen:curve) pub)
  197. ::
  198. :: In the case where `left` is greater than or equal to the curve order,
  199. :: or the key is the identity point, we have an invalid key and will
  200. :: rehash `0x1 || right || i` to obtain a valid key. This prevents the
  201. :: distribution from being biased.
  202. |-
  203. ?: &((lth left n) !=(a-id:curve key))
  204. %_ +>.^$
  205. pub key
  206. cad right
  207. dep +(dep)
  208. ind i
  209. pif fingerprint
  210. ==
  211. =/ [left=@ right=@]
  212. =- [(cut 3 [32 32] -) (cut 3 [0 32] -)]
  213. %+ hmac-sha512l [32 cad]
  214. [37 (can 3 ~[4^i 32^right 1^0x1])]
  215. %= $
  216. left left
  217. right right
  218. key (ch-add:affine:curve (point left a-gen:curve) pub)
  219. ==
  220. --