bech32.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import { assertU8, E_STRING } from './fallback/_utils.js'
  2. import { nativeEncoder } from './fallback/platform.js'
  3. import { decodeAscii, encodeAscii, encodeLatin1 } from './fallback/latin1.js'
  4. const alphabet = [...'qpzry9x8gf2tvdw0s3jn54khce6mua7l']
  5. const BECH32 = 1
  6. const BECH32M = 0x2b_c8_30_a3
  7. const E_SIZE = 'Input length is out of range'
  8. const E_PREFIX = 'Missing or invalid prefix'
  9. const E_MIXED = 'Mixed-case string'
  10. const E_PADDING = 'Padding is invalid'
  11. const E_CHECKSUM = 'Invalid checksum'
  12. const E_CHARACTER = 'Non-bech32 character'
  13. // nativeEncoder path uses encodeAscii which asserts ascii, otherwise we have 0-255 bytes from encodeLatin1
  14. const c2x = new Int8Array(nativeEncoder ? 128 : 256).fill(-1)
  15. const x2c = new Uint8Array(32)
  16. for (let i = 0; i < alphabet.length; i++) {
  17. const c = alphabet[i].charCodeAt(0)
  18. c2x[c] = i
  19. x2c[i] = c
  20. }
  21. // checksum size is 30 bits, 0x3f_ff_ff_ff
  22. // The good thing about the checksum is that it's linear over every bit
  23. const poly0 = new Uint32Array(32) // just precache all possible ones, it's only 1 KiB
  24. const p = (x) => ((x & 0x1_ff_ff_ff) << 5) ^ poly0[x >> 25]
  25. for (let i = 0; i < 32; i++) {
  26. poly0[i] =
  27. (i & 0b0_0001 ? 0x3b_6a_57_b2 : 0) ^
  28. (i & 0b0_0010 ? 0x26_50_8e_6d : 0) ^
  29. (i & 0b0_0100 ? 0x1e_a1_19_fa : 0) ^
  30. (i & 0b0_1000 ? 0x3d_42_33_dd : 0) ^
  31. (i & 0b1_0000 ? 0x2a_14_62_b3 : 0)
  32. }
  33. // 7 KiB more for faster p6/p8
  34. const poly1 = new Uint32Array(32)
  35. const poly2 = new Uint32Array(32)
  36. const poly3 = new Uint32Array(32)
  37. const poly4 = new Uint32Array(32)
  38. const poly5 = new Uint32Array(32)
  39. const poly6 = new Uint32Array(32)
  40. const poly7 = new Uint32Array(32)
  41. for (let i = 0; i < 32; i++) {
  42. // poly0[i] === p(p(p(p(p(p(i))))))
  43. poly1[i] = p(poly0[i]) // aka p(p(p(p(p(p(i << 5))))))
  44. poly2[i] = p(poly1[i]) // aka p(p(p(p(p(p(i << 10))))))
  45. poly3[i] = p(poly2[i]) // aka p(p(p(p(p(p(i << 15))))))
  46. poly4[i] = p(poly3[i]) // aka p(p(p(p(p(p(i << 20))))))
  47. poly5[i] = p(poly4[i]) // aka p(p(p(p(p(p(i << 25))))))
  48. poly6[i] = p(poly5[i])
  49. poly7[i] = p(poly6[i])
  50. }
  51. function p6(x) {
  52. // Same as: return p(p(p(p(p(p(x))))))
  53. const x0 = x & 0x1f
  54. const x1 = (x >> 5) & 0x1f
  55. const x2 = (x >> 10) & 0x1f
  56. const x3 = (x >> 15) & 0x1f
  57. const x4 = (x >> 20) & 0x1f
  58. const x5 = (x >> 25) & 0x1f
  59. return poly0[x0] ^ poly1[x1] ^ poly2[x2] ^ poly3[x3] ^ poly4[x4] ^ poly5[x5]
  60. }
  61. function p8(x) {
  62. // Same as: return p(p(p(p(p(p(p(p(x))))))))
  63. const x0 = x & 0x1f
  64. const x1 = (x >> 5) & 0x1f
  65. const x2 = (x >> 10) & 0x1f
  66. const x3 = (x >> 15) & 0x1f
  67. const x4 = (x >> 20) & 0x1f
  68. const x5 = (x >> 25) & 0x1f
  69. return poly2[x0] ^ poly3[x1] ^ poly4[x2] ^ poly5[x3] ^ poly6[x4] ^ poly7[x5]
  70. }
  71. // p(p(p(p(p(p(chk) ^ x0) ^ x1) ^ x2) ^ x3) ^ x4) ^ x5 === p6(chk) ^ merge(x0, x1, x2, x3, x4, x5)
  72. const merge = (a, b, c, d, e, f) => f ^ (e << 5) ^ (d << 10) ^ (c << 15) ^ (b << 20) ^ (a << 25)
  73. const prefixCache = new Map() // Cache 10 of them
  74. function pPrefix(prefix) {
  75. if (prefix === 'bc') return 0x2_31_80_43 // perf
  76. const cached = prefixCache.get(prefix)
  77. if (cached !== undefined) return cached
  78. // bech32_hrp_expand(s): [ord(x) >> 5 for x in s] + [0] + [ord(x) & 31 for x in s]
  79. // We can do this in a single scan due to linearity, but it's not very beneficial
  80. let chk = 1 // it starts with one (see def bech32_polymod in BIP_0173)
  81. const length = prefix.length
  82. for (let i = 0; i < length; i++) {
  83. const c = prefix.charCodeAt(i)
  84. if (c < 33 || c > 126) throw new Error(E_PREFIX) // each character having a value in the range [33-126]
  85. chk = p(chk) ^ (c >> 5)
  86. }
  87. chk = p(chk) // <= for + [0]
  88. for (let i = 0; i < length; i++) {
  89. const c = prefix.charCodeAt(i)
  90. chk = p(chk) ^ (c & 0x1f)
  91. }
  92. if (prefixCache.size < 10) prefixCache.set(prefix, chk)
  93. return chk
  94. }
  95. function toBech32enc(prefix, bytes, limit, encoding) {
  96. if (typeof prefix !== 'string' || !prefix) throw new TypeError(E_PREFIX)
  97. if (typeof limit !== 'number') throw new TypeError(E_SIZE)
  98. assertU8(bytes)
  99. const bytesLength = bytes.length
  100. const wordsLength = Math.ceil((bytesLength * 8) / 5)
  101. if (!(prefix.length + 7 + wordsLength <= limit)) throw new TypeError(E_SIZE)
  102. prefix = prefix.toLowerCase()
  103. const out = new Uint8Array(wordsLength + 6)
  104. let chk = pPrefix(prefix)
  105. let i = 0, j = 0 // prettier-ignore
  106. // This loop is just an optimization of the next one
  107. for (const length4 = bytesLength - 4; i < length4; i += 5, j += 8) {
  108. const b0 = bytes[i], b1 = bytes[i + 1], b2 = bytes[i + 2], b3 = bytes[i + 3], b4 = bytes[i + 4] // prettier-ignore
  109. const x0 = b0 >> 3
  110. const x1 = ((b0 << 2) & 0x1f) | (b1 >> 6)
  111. const x2 = (b1 >> 1) & 0x1f
  112. const x3 = ((b1 << 4) & 0x1f) | (b2 >> 4)
  113. const x4 = ((b2 << 1) & 0x1f) | (b3 >> 7)
  114. const x5 = (b3 >> 2) & 0x1f
  115. const x6 = ((b3 << 3) & 0x1f) | (b4 >> 5)
  116. const x7 = b4 & 0x1f
  117. chk = merge(x2, x3, x4, x5, x6, x7) ^ poly0[x1] ^ poly1[x0] ^ p8(chk)
  118. out[j] = x2c[x0]
  119. out[j + 1] = x2c[x1]
  120. out[j + 2] = x2c[x2]
  121. out[j + 3] = x2c[x3]
  122. out[j + 4] = x2c[x4]
  123. out[j + 5] = x2c[x5]
  124. out[j + 6] = x2c[x6]
  125. out[j + 7] = x2c[x7]
  126. }
  127. let value = 0, bits = 0 // prettier-ignore
  128. for (; i < bytesLength; i++) {
  129. value = ((value & 0xf) << 8) | bytes[i]
  130. bits += 3
  131. const x = (value >> bits) & 0x1f
  132. chk = p(chk) ^ x
  133. out[j++] = x2c[x]
  134. if (bits >= 5) {
  135. bits -= 5
  136. const x = (value >> bits) & 0x1f
  137. chk = p(chk) ^ x
  138. out[j++] = x2c[x]
  139. }
  140. }
  141. if (bits > 0) {
  142. const x = (value << (5 - bits)) & 0x1f
  143. chk = p(chk) ^ x
  144. out[j++] = x2c[x]
  145. }
  146. chk = encoding ^ p6(chk)
  147. out[j++] = x2c[(chk >> 25) & 0x1f]
  148. out[j++] = x2c[(chk >> 20) & 0x1f]
  149. out[j++] = x2c[(chk >> 15) & 0x1f]
  150. out[j++] = x2c[(chk >> 10) & 0x1f]
  151. out[j++] = x2c[(chk >> 5) & 0x1f]
  152. out[j++] = x2c[(chk >> 0) & 0x1f]
  153. return prefix + '1' + decodeAscii(out) // suboptimal in barebones, but actually ok in Hermes for not to care atm
  154. }
  155. function assertDecodeArgs(str, limit) {
  156. if (typeof str !== 'string') throw new TypeError(E_STRING)
  157. if (typeof limit !== 'number' || str.length < 8 || !(str.length <= limit)) throw new Error(E_SIZE)
  158. }
  159. // this is instant on 8-bit strings
  160. const NON_LATIN = /[^\x00-\xFF]/ // eslint-disable-line no-control-regex
  161. function fromBech32enc(str, limit, encoding) {
  162. assertDecodeArgs(str, limit)
  163. const lower = str.toLowerCase()
  164. if (str !== lower) {
  165. if (str !== str.toUpperCase()) throw new Error(E_MIXED)
  166. str = lower
  167. }
  168. const split = str.lastIndexOf('1')
  169. if (split <= 0) throw new Error(E_PREFIX)
  170. const prefix = str.slice(0, split)
  171. const charsLength = str.length - split - 1
  172. const wordsLength = charsLength - 6
  173. if (wordsLength < 0) throw new Error(E_SIZE)
  174. const bytesLength = (wordsLength * 5) >> 3
  175. const slice = str.slice(split + 1)
  176. if (!nativeEncoder && NON_LATIN.test(slice)) throw new SyntaxError(E_CHARACTER) // otherwise can't use encodeLatin1
  177. const c = nativeEncoder ? encodeAscii(slice, E_CHARACTER) : encodeLatin1(slice) // suboptimal, but only affects non-Hermes barebones
  178. const bytes = new Uint8Array(bytesLength)
  179. let chk = pPrefix(prefix)
  180. let i = 0, j = 0 // prettier-ignore
  181. // This loop is just an optimization of the next one
  182. for (const length7 = wordsLength - 7; i < length7; i += 8, j += 5) {
  183. const c0 = c[i], c1 = c[i + 1], c2 = c[i + 2], c3 = c[i + 3], c4 = c[i + 4], c5 = c[i + 5], c6 = c[i + 6], c7 = c[i + 7] // prettier-ignore
  184. const x0 = c2x[c0], x1 = c2x[c1], x2 = c2x[c2], x3 = c2x[c3], x4 = c2x[c4], x5 = c2x[c5], x6 = c2x[c6], x7 = c2x[c7] // prettier-ignore
  185. if (x0 < 0 || x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || x5 < 0 || x6 < 0 || x7 < 0) throw new SyntaxError(E_CHARACTER) // prettier-ignore
  186. chk = merge(x2, x3, x4, x5, x6, x7) ^ poly0[x1] ^ poly1[x0] ^ p8(chk)
  187. bytes[j] = (x0 << 3) | (x1 >> 2)
  188. bytes[j + 1] = (((x1 << 6) | (x2 << 1)) & 0xff) | (x3 >> 4)
  189. bytes[j + 2] = ((x3 << 4) & 0xff) | (x4 >> 1)
  190. bytes[j + 3] = ((((x4 << 5) | x5) << 2) & 0xff) | (x6 >> 3)
  191. bytes[j + 4] = ((x6 << 5) & 0xff) | x7
  192. }
  193. let value = 0, bits = 0 // prettier-ignore
  194. for (; i < wordsLength; i++) {
  195. const x = c2x[c[i]]
  196. if (x < 0) throw new SyntaxError(E_CHARACTER)
  197. chk = p(chk) ^ x
  198. value = (value << 5) | x
  199. bits += 5
  200. if (bits >= 8) {
  201. bits -= 8
  202. bytes[j++] = (value >> bits) & 0xff
  203. }
  204. }
  205. if (bits >= 5 || (value << (8 - bits)) & 0xff) throw new Error(E_PADDING)
  206. // Checksum
  207. {
  208. const c0 = c[i], c1 = c[i + 1], c2 = c[i + 2], c3 = c[i + 3], c4 = c[i + 4], c5 = c[i + 5] // prettier-ignore
  209. const x0 = c2x[c0], x1 = c2x[c1], x2 = c2x[c2], x3 = c2x[c3], x4 = c2x[c4], x5 = c2x[c5] // prettier-ignore
  210. if (x0 < 0 || x1 < 0 || x2 < 0 || x3 < 0 || x4 < 0 || x5 < 0) throw new SyntaxError(E_CHARACTER)
  211. if ((merge(x0, x1, x2, x3, x4, x5) ^ p6(chk)) !== encoding) throw new Error(E_CHECKSUM)
  212. }
  213. return { prefix, bytes }
  214. }
  215. // This is designed to be a very quick check, skipping all other validation
  216. export function getPrefix(str, limit = 90) {
  217. assertDecodeArgs(str, limit)
  218. const split = str.lastIndexOf('1')
  219. if (split <= 0) throw new Error(E_PREFIX)
  220. return str.slice(0, split).toLowerCase()
  221. }
  222. export const toBech32 = (prefix, bytes, limit = 90) => toBech32enc(prefix, bytes, limit, BECH32)
  223. export const fromBech32 = (str, limit = 90) => fromBech32enc(str, limit, BECH32)
  224. export const toBech32m = (prefix, bytes, limit = 90) => toBech32enc(prefix, bytes, limit, BECH32M)
  225. export const fromBech32m = (str, limit = 90) => fromBech32enc(str, limit, BECH32M)