summaryrefslogtreecommitdiff
path: root/app/lib/bip/b173.hoon
blob: e554597047c17762d9c9ba49fd86e43b96df8d17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
::  BIP173: Bech32 Addresses
::  https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
::
::  Heavily copies:
::  https://github.com/bitcoinjs/bech32/blob/master/index.js
::
:: TODO not really working at generating npub/nsec keys from hex
/-  sur=bitcoin
/+  bcu=bitcoin-utils
=,  sur
=,  bcu
|%
++  prefixes
  ^-  (map network tape)
  (my [[%main "bc"] [%testnet "tb"] [%regtest "bcrt"] ~])
++  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 @)
  |^  ^-  @
  =/  gen=(list @ux)
    ~[0x3b6a.57b2 0x2650.8e6d 0x1ea1.19fa 0x3d42.33dd 0x2a14.62b3]
  =/  chk=@  1
  |-  ?~  values  chk
  =/  top  (rsh [0 25] chk)
  =.  chk
    (mix i.values (lsh [0 5] (dis chk 0x1ff.ffff)))
  $(values t.values, chk (update-chk chk top gen))
::
  ++  update-chk
    |=  [chk=@ top=@ gen=(list @ux)]
    =/  is  (gulf 0 4)
    |-  ?~  is  chk
    ?:  =(1 (dis 1 (rsh [0 i.is] top)))
      $(is t.is, chk (mix chk (snag i.is gen)))
    $(is t.is)
  --
::
++  expand-hrp
  |=  hrp=tape
  ^-  (list @)
  =/  front  (turn hrp |=(p=@tD (rsh [0 5] p)))
  =/  back   (turn hrp |=(p=@tD (dis 31 p)))
  (zing ~[front ~[0] back])
::
++  verify-checksum
  |=  [hrp=tape data-and-checksum=(list @)]
  ^-  ?
  %-  |=(a=@ =(1 a))
  %-  polymod
  (weld (expand-hrp hrp) data-and-checksum)
::
++  checksum
  |=  [hrp=tape data=(list @)]
  ^-  (list @)
  ::  xor 1 with the polymod
  ::
  =/  pmod=@
    %+  mix  1
    %-  polymod
    (zing ~[(expand-hrp hrp) data (reap 6 0)])
  %+  turn  (gulf 0 5)
  |=(i=@ (dis 31 (rsh [0 (mul 5 (sub 5 i))] pmod)))
::
++  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 @)]
  ^-  cord
  =/  combined=(list @)
    (weld data (checksum hrp data))
  %-  crip
  (zing ~[hrp "1" (tape (murn combined value-to-charset))])
++  decode-raw
  |=  body=cord
  ^-  (unit raw-decoded)
  =/  bech  (cass (trip body))              ::  to lowercase
  =/  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)]
::  +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)
::
++  from-address
  |=  body=cord
  ^-  hexb
  ~|  "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 cord)
  ?.  =(33 wid.pubkey)
    ~|('pubkey must be a 33 byte ECC compressed public key' !!)
  =/  prefix  (~(get by prefixes) network)
  ?~  prefix  ~
  :-  ~
  %+  encode-raw  u.prefix
  [0v0 (to-atoms:bit 5 [160 `@ub`dat:(hash-160 pubkey)])]
--