index.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. /*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
  2. // Utilities
  3. /**
  4. * @__NO_SIDE_EFFECTS__
  5. */
  6. export function assertNumber(n: number) {
  7. if (!Number.isSafeInteger(n)) throw new Error(`Wrong integer: ${n}`);
  8. }
  9. export interface Coder<F, T> {
  10. encode(from: F): T;
  11. decode(to: T): F;
  12. }
  13. export interface BytesCoder extends Coder<Uint8Array, string> {
  14. encode: (data: Uint8Array) => string;
  15. decode: (str: string) => Uint8Array;
  16. }
  17. function isBytes(a: unknown): a is Uint8Array {
  18. return (
  19. a instanceof Uint8Array ||
  20. (a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array')
  21. );
  22. }
  23. // TODO: some recusive type inference so it would check correct order of input/output inside rest?
  24. // like <string, number>, <number, bytes>, <bytes, float>
  25. type Chain = [Coder<any, any>, ...Coder<any, any>[]];
  26. // Extract info from Coder type
  27. type Input<F> = F extends Coder<infer T, any> ? T : never;
  28. type Output<F> = F extends Coder<any, infer T> ? T : never;
  29. // Generic function for arrays
  30. type First<T> = T extends [infer U, ...any[]] ? U : never;
  31. type Last<T> = T extends [...any[], infer U] ? U : never;
  32. type Tail<T> = T extends [any, ...infer U] ? U : never;
  33. type AsChain<C extends Chain, Rest = Tail<C>> = {
  34. // C[K] = Coder<Input<C[K]>, Input<Rest[k]>>
  35. [K in keyof C]: Coder<Input<C[K]>, Input<K extends keyof Rest ? Rest[K] : any>>;
  36. };
  37. /**
  38. * @__NO_SIDE_EFFECTS__
  39. */
  40. function chain<T extends Chain & AsChain<T>>(...args: T): Coder<Input<First<T>>, Output<Last<T>>> {
  41. const id = (a: any) => a;
  42. // Wrap call in closure so JIT can inline calls
  43. const wrap = (a: any, b: any) => (c: any) => a(b(c));
  44. // Construct chain of args[-1].encode(args[-2].encode([...]))
  45. const encode = args.map((x) => x.encode).reduceRight(wrap, id);
  46. // Construct chain of args[0].decode(args[1].decode(...))
  47. const decode = args.map((x) => x.decode).reduce(wrap, id);
  48. return { encode, decode };
  49. }
  50. type Alphabet = string[] | string;
  51. /**
  52. * Encodes integer radix representation to array of strings using alphabet and back
  53. * @__NO_SIDE_EFFECTS__
  54. */
  55. function alphabet(alphabet: Alphabet): Coder<number[], string[]> {
  56. return {
  57. encode: (digits: number[]) => {
  58. if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
  59. throw new Error('alphabet.encode input should be an array of numbers');
  60. return digits.map((i) => {
  61. assertNumber(i);
  62. if (i < 0 || i >= alphabet.length)
  63. throw new Error(`Digit index outside alphabet: ${i} (alphabet: ${alphabet.length})`);
  64. return alphabet[i]!;
  65. });
  66. },
  67. decode: (input: string[]) => {
  68. if (!Array.isArray(input) || (input.length && typeof input[0] !== 'string'))
  69. throw new Error('alphabet.decode input should be array of strings');
  70. return input.map((letter) => {
  71. if (typeof letter !== 'string')
  72. throw new Error(`alphabet.decode: not string element=${letter}`);
  73. const index = alphabet.indexOf(letter);
  74. if (index === -1) throw new Error(`Unknown letter: "${letter}". Allowed: ${alphabet}`);
  75. return index;
  76. });
  77. },
  78. };
  79. }
  80. /**
  81. * @__NO_SIDE_EFFECTS__
  82. */
  83. function join(separator = ''): Coder<string[], string> {
  84. if (typeof separator !== 'string') throw new Error('join separator should be string');
  85. return {
  86. encode: (from) => {
  87. if (!Array.isArray(from) || (from.length && typeof from[0] !== 'string'))
  88. throw new Error('join.encode input should be array of strings');
  89. for (let i of from)
  90. if (typeof i !== 'string') throw new Error(`join.encode: non-string input=${i}`);
  91. return from.join(separator);
  92. },
  93. decode: (to) => {
  94. if (typeof to !== 'string') throw new Error('join.decode input should be string');
  95. return to.split(separator);
  96. },
  97. };
  98. }
  99. /**
  100. * Pad strings array so it has integer number of bits
  101. * @__NO_SIDE_EFFECTS__
  102. */
  103. function padding(bits: number, chr = '='): Coder<string[], string[]> {
  104. assertNumber(bits);
  105. if (typeof chr !== 'string') throw new Error('padding chr should be string');
  106. return {
  107. encode(data: string[]): string[] {
  108. if (!Array.isArray(data) || (data.length && typeof data[0] !== 'string'))
  109. throw new Error('padding.encode input should be array of strings');
  110. for (let i of data)
  111. if (typeof i !== 'string') throw new Error(`padding.encode: non-string input=${i}`);
  112. while ((data.length * bits) % 8) data.push(chr);
  113. return data;
  114. },
  115. decode(input: string[]): string[] {
  116. if (!Array.isArray(input) || (input.length && typeof input[0] !== 'string'))
  117. throw new Error('padding.encode input should be array of strings');
  118. for (let i of input)
  119. if (typeof i !== 'string') throw new Error(`padding.decode: non-string input=${i}`);
  120. let end = input.length;
  121. if ((end * bits) % 8)
  122. throw new Error('Invalid padding: string should have whole number of bytes');
  123. for (; end > 0 && input[end - 1] === chr; end--) {
  124. if (!(((end - 1) * bits) % 8))
  125. throw new Error('Invalid padding: string has too much padding');
  126. }
  127. return input.slice(0, end);
  128. },
  129. };
  130. }
  131. /**
  132. * @__NO_SIDE_EFFECTS__
  133. */
  134. function normalize<T>(fn: (val: T) => T): Coder<T, T> {
  135. if (typeof fn !== 'function') throw new Error('normalize fn should be function');
  136. return { encode: (from: T) => from, decode: (to: T) => fn(to) };
  137. }
  138. /**
  139. * Slow: O(n^2) time complexity
  140. * @__NO_SIDE_EFFECTS__
  141. */
  142. function convertRadix(data: number[], from: number, to: number): number[] {
  143. // base 1 is impossible
  144. if (from < 2) throw new Error(`convertRadix: wrong from=${from}, base cannot be less than 2`);
  145. if (to < 2) throw new Error(`convertRadix: wrong to=${to}, base cannot be less than 2`);
  146. if (!Array.isArray(data)) throw new Error('convertRadix: data should be array');
  147. if (!data.length) return [];
  148. let pos = 0;
  149. const res = [];
  150. const digits = Array.from(data);
  151. digits.forEach((d) => {
  152. assertNumber(d);
  153. if (d < 0 || d >= from) throw new Error(`Wrong integer: ${d}`);
  154. });
  155. while (true) {
  156. let carry = 0;
  157. let done = true;
  158. for (let i = pos; i < digits.length; i++) {
  159. const digit = digits[i]!;
  160. const digitBase = from * carry + digit;
  161. if (
  162. !Number.isSafeInteger(digitBase) ||
  163. (from * carry) / from !== carry ||
  164. digitBase - digit !== from * carry
  165. ) {
  166. throw new Error('convertRadix: carry overflow');
  167. }
  168. carry = digitBase % to;
  169. const rounded = Math.floor(digitBase / to);
  170. digits[i] = rounded;
  171. if (!Number.isSafeInteger(rounded) || rounded * to + carry !== digitBase)
  172. throw new Error('convertRadix: carry overflow');
  173. if (!done) continue;
  174. else if (!rounded) pos = i;
  175. else done = false;
  176. }
  177. res.push(carry);
  178. if (done) break;
  179. }
  180. for (let i = 0; i < data.length - 1 && data[i] === 0; i++) res.push(0);
  181. return res.reverse();
  182. }
  183. const gcd = /* @__NO_SIDE_EFFECTS__ */ (a: number, b: number): number => (!b ? a : gcd(b, a % b));
  184. const radix2carry = /*@__NO_SIDE_EFFECTS__ */ (from: number, to: number) =>
  185. from + (to - gcd(from, to));
  186. /**
  187. * Implemented with numbers, because BigInt is 5x slower
  188. * @__NO_SIDE_EFFECTS__
  189. */
  190. function convertRadix2(data: number[], from: number, to: number, padding: boolean): number[] {
  191. if (!Array.isArray(data)) throw new Error('convertRadix2: data should be array');
  192. if (from <= 0 || from > 32) throw new Error(`convertRadix2: wrong from=${from}`);
  193. if (to <= 0 || to > 32) throw new Error(`convertRadix2: wrong to=${to}`);
  194. if (radix2carry(from, to) > 32) {
  195. throw new Error(
  196. `convertRadix2: carry overflow from=${from} to=${to} carryBits=${radix2carry(from, to)}`
  197. );
  198. }
  199. let carry = 0;
  200. let pos = 0; // bitwise position in current element
  201. const mask = 2 ** to - 1;
  202. const res: number[] = [];
  203. for (const n of data) {
  204. assertNumber(n);
  205. if (n >= 2 ** from) throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
  206. carry = (carry << from) | n;
  207. if (pos + from > 32) throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
  208. pos += from;
  209. for (; pos >= to; pos -= to) res.push(((carry >> (pos - to)) & mask) >>> 0);
  210. carry &= 2 ** pos - 1; // clean carry, otherwise it will cause overflow
  211. }
  212. carry = (carry << (to - pos)) & mask;
  213. if (!padding && pos >= from) throw new Error('Excess padding');
  214. if (!padding && carry) throw new Error(`Non-zero padding: ${carry}`);
  215. if (padding && pos > 0) res.push(carry >>> 0);
  216. return res;
  217. }
  218. /**
  219. * @__NO_SIDE_EFFECTS__
  220. */
  221. function radix(num: number): Coder<Uint8Array, number[]> {
  222. assertNumber(num);
  223. return {
  224. encode: (bytes: Uint8Array) => {
  225. if (!isBytes(bytes)) throw new Error('radix.encode input should be Uint8Array');
  226. return convertRadix(Array.from(bytes), 2 ** 8, num);
  227. },
  228. decode: (digits: number[]) => {
  229. if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
  230. throw new Error('radix.decode input should be array of numbers');
  231. return Uint8Array.from(convertRadix(digits, num, 2 ** 8));
  232. },
  233. };
  234. }
  235. /**
  236. * If both bases are power of same number (like `2**8 <-> 2**64`),
  237. * there is a linear algorithm. For now we have implementation for power-of-two bases only.
  238. * @__NO_SIDE_EFFECTS__
  239. */
  240. function radix2(bits: number, revPadding = false): Coder<Uint8Array, number[]> {
  241. assertNumber(bits);
  242. if (bits <= 0 || bits > 32) throw new Error('radix2: bits should be in (0..32]');
  243. if (radix2carry(8, bits) > 32 || radix2carry(bits, 8) > 32)
  244. throw new Error('radix2: carry overflow');
  245. return {
  246. encode: (bytes: Uint8Array) => {
  247. if (!isBytes(bytes)) throw new Error('radix2.encode input should be Uint8Array');
  248. return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
  249. },
  250. decode: (digits: number[]) => {
  251. if (!Array.isArray(digits) || (digits.length && typeof digits[0] !== 'number'))
  252. throw new Error('radix2.decode input should be array of numbers');
  253. return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
  254. },
  255. };
  256. }
  257. type ArgumentTypes<F extends Function> = F extends (...args: infer A) => any ? A : never;
  258. /**
  259. * @__NO_SIDE_EFFECTS__
  260. */
  261. function unsafeWrapper<T extends (...args: any) => any>(fn: T) {
  262. if (typeof fn !== 'function') throw new Error('unsafeWrapper fn should be function');
  263. return function (...args: ArgumentTypes<T>): ReturnType<T> | void {
  264. try {
  265. return fn.apply(null, args);
  266. } catch (e) {}
  267. };
  268. }
  269. /**
  270. * @__NO_SIDE_EFFECTS__
  271. */
  272. function checksum(
  273. len: number,
  274. fn: (data: Uint8Array) => Uint8Array
  275. ): Coder<Uint8Array, Uint8Array> {
  276. assertNumber(len);
  277. if (typeof fn !== 'function') throw new Error('checksum fn should be function');
  278. return {
  279. encode(data: Uint8Array) {
  280. if (!isBytes(data)) throw new Error('checksum.encode: input should be Uint8Array');
  281. const checksum = fn(data).slice(0, len);
  282. const res = new Uint8Array(data.length + len);
  283. res.set(data);
  284. res.set(checksum, data.length);
  285. return res;
  286. },
  287. decode(data: Uint8Array) {
  288. if (!isBytes(data)) throw new Error('checksum.decode: input should be Uint8Array');
  289. const payload = data.slice(0, -len);
  290. const newChecksum = fn(payload).slice(0, len);
  291. const oldChecksum = data.slice(-len);
  292. for (let i = 0; i < len; i++)
  293. if (newChecksum[i] !== oldChecksum[i]) throw new Error('Invalid checksum');
  294. return payload;
  295. },
  296. };
  297. }
  298. // prettier-ignore
  299. export const utils = {
  300. alphabet, chain, checksum, convertRadix, convertRadix2, radix, radix2, join, padding,
  301. };
  302. // RFC 4648 aka RFC 3548
  303. // ---------------------
  304. export const base16: BytesCoder = /* @__PURE__ */ chain(
  305. radix2(4),
  306. alphabet('0123456789ABCDEF'),
  307. join('')
  308. );
  309. export const base32: BytesCoder = /* @__PURE__ */ chain(
  310. radix2(5),
  311. alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'),
  312. padding(5),
  313. join('')
  314. );
  315. export const base32nopad: BytesCoder = /* @__PURE__ */ chain(
  316. radix2(5),
  317. alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'),
  318. join('')
  319. );
  320. export const base32hex: BytesCoder = /* @__PURE__ */ chain(
  321. radix2(5),
  322. alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'),
  323. padding(5),
  324. join('')
  325. );
  326. export const base32hexnopad: BytesCoder = /* @__PURE__ */ chain(
  327. radix2(5),
  328. alphabet('0123456789ABCDEFGHIJKLMNOPQRSTUV'),
  329. join('')
  330. );
  331. export const base32crockford: BytesCoder = /* @__PURE__ */ chain(
  332. radix2(5),
  333. alphabet('0123456789ABCDEFGHJKMNPQRSTVWXYZ'),
  334. join(''),
  335. normalize((s: string) => s.toUpperCase().replace(/O/g, '0').replace(/[IL]/g, '1'))
  336. );
  337. export const base64: BytesCoder = /* @__PURE__ */ chain(
  338. radix2(6),
  339. alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'),
  340. padding(6),
  341. join('')
  342. );
  343. export const base64nopad: BytesCoder = /* @__PURE__ */ chain(
  344. radix2(6),
  345. alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'),
  346. join('')
  347. );
  348. export const base64url: BytesCoder = /* @__PURE__ */ chain(
  349. radix2(6),
  350. alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'),
  351. padding(6),
  352. join('')
  353. );
  354. export const base64urlnopad: BytesCoder = /* @__PURE__ */ chain(
  355. radix2(6),
  356. alphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'),
  357. join('')
  358. );
  359. // base58 code
  360. // -----------
  361. const genBase58 = (abc: string) => chain(radix(58), alphabet(abc), join(''));
  362. export const base58: BytesCoder = /* @__PURE__ */ genBase58(
  363. '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
  364. );
  365. export const base58flickr: BytesCoder = /* @__PURE__ */ genBase58(
  366. '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
  367. );
  368. export const base58xrp: BytesCoder = /* @__PURE__ */ genBase58(
  369. 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz'
  370. );
  371. // xmr ver is done in 8-byte blocks (which equals 11 chars in decoding). Last (non-full) block padded with '1' to size in XMR_BLOCK_LEN.
  372. // Block encoding significantly reduces quadratic complexity of base58.
  373. // Data len (index) -> encoded block len
  374. const XMR_BLOCK_LEN = [0, 2, 3, 5, 6, 7, 9, 10, 11];
  375. export const base58xmr: BytesCoder = {
  376. encode(data: Uint8Array) {
  377. let res = '';
  378. for (let i = 0; i < data.length; i += 8) {
  379. const block = data.subarray(i, i + 8);
  380. res += base58.encode(block).padStart(XMR_BLOCK_LEN[block.length]!, '1');
  381. }
  382. return res;
  383. },
  384. decode(str: string) {
  385. let res: number[] = [];
  386. for (let i = 0; i < str.length; i += 11) {
  387. const slice = str.slice(i, i + 11);
  388. const blockLen = XMR_BLOCK_LEN.indexOf(slice.length);
  389. const block = base58.decode(slice);
  390. for (let j = 0; j < block.length - blockLen; j++) {
  391. if (block[j] !== 0) throw new Error('base58xmr: wrong padding');
  392. }
  393. res = res.concat(Array.from(block.slice(block.length - blockLen)));
  394. }
  395. return Uint8Array.from(res);
  396. },
  397. };
  398. export const createBase58check = (sha256: (data: Uint8Array) => Uint8Array): BytesCoder =>
  399. chain(
  400. checksum(4, (data) => sha256(sha256(data))),
  401. base58
  402. );
  403. // legacy export, bad name
  404. export const base58check = createBase58check;
  405. // Bech32 code
  406. // -----------
  407. export interface Bech32Decoded<Prefix extends string = string> {
  408. prefix: Prefix;
  409. words: number[];
  410. }
  411. export interface Bech32DecodedWithArray<Prefix extends string = string> {
  412. prefix: Prefix;
  413. words: number[];
  414. bytes: Uint8Array;
  415. }
  416. const BECH_ALPHABET: Coder<number[], string> = /* @__PURE__ */ chain(
  417. alphabet('qpzry9x8gf2tvdw0s3jn54khce6mua7l'),
  418. join('')
  419. );
  420. const POLYMOD_GENERATORS = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
  421. /**
  422. * @__NO_SIDE_EFFECTS__
  423. */
  424. function bech32Polymod(pre: number): number {
  425. const b = pre >> 25;
  426. let chk = (pre & 0x1ffffff) << 5;
  427. for (let i = 0; i < POLYMOD_GENERATORS.length; i++) {
  428. if (((b >> i) & 1) === 1) chk ^= POLYMOD_GENERATORS[i]!;
  429. }
  430. return chk;
  431. }
  432. /**
  433. * @__NO_SIDE_EFFECTS__
  434. */
  435. function bechChecksum(prefix: string, words: number[], encodingConst = 1): string {
  436. const len = prefix.length;
  437. let chk = 1;
  438. for (let i = 0; i < len; i++) {
  439. const c = prefix.charCodeAt(i);
  440. if (c < 33 || c > 126) throw new Error(`Invalid prefix (${prefix})`);
  441. chk = bech32Polymod(chk) ^ (c >> 5);
  442. }
  443. chk = bech32Polymod(chk);
  444. for (let i = 0; i < len; i++) chk = bech32Polymod(chk) ^ (prefix.charCodeAt(i) & 0x1f);
  445. for (let v of words) chk = bech32Polymod(chk) ^ v;
  446. for (let i = 0; i < 6; i++) chk = bech32Polymod(chk);
  447. chk ^= encodingConst;
  448. return BECH_ALPHABET.encode(convertRadix2([chk % 2 ** 30], 30, 5, false));
  449. }
  450. export interface Bech32 {
  451. encode<Prefix extends string>(
  452. prefix: Prefix,
  453. words: number[] | Uint8Array,
  454. limit?: number | false
  455. ): `${Lowercase<Prefix>}1${string}`;
  456. decode<Prefix extends string>(
  457. str: `${Prefix}1${string}`,
  458. limit?: number | false
  459. ): Bech32Decoded<Prefix>;
  460. encodeFromBytes(prefix: string, bytes: Uint8Array): string;
  461. decodeToBytes(str: string): Bech32DecodedWithArray;
  462. decodeUnsafe(str: string, limit?: number | false): void | Bech32Decoded<string>;
  463. fromWords(to: number[]): Uint8Array;
  464. fromWordsUnsafe(to: number[]): void | Uint8Array;
  465. toWords(from: Uint8Array): number[];
  466. }
  467. /**
  468. * @__NO_SIDE_EFFECTS__
  469. */
  470. function genBech32(encoding: 'bech32' | 'bech32m'): Bech32 {
  471. const ENCODING_CONST = encoding === 'bech32' ? 1 : 0x2bc830a3;
  472. const _words = radix2(5);
  473. const fromWords = _words.decode;
  474. const toWords = _words.encode;
  475. const fromWordsUnsafe = unsafeWrapper(fromWords);
  476. function encode<Prefix extends string>(
  477. prefix: Prefix,
  478. words: number[] | Uint8Array,
  479. limit: number | false = 90
  480. ): `${Lowercase<Prefix>}1${string}` {
  481. if (typeof prefix !== 'string')
  482. throw new Error(`bech32.encode prefix should be string, not ${typeof prefix}`);
  483. if (words instanceof Uint8Array) words = Array.from(words);
  484. if (!Array.isArray(words) || (words.length && typeof words[0] !== 'number'))
  485. throw new Error(`bech32.encode words should be array of numbers, not ${typeof words}`);
  486. if (prefix.length === 0) throw new TypeError(`Invalid prefix length ${prefix.length}`);
  487. const actualLength = prefix.length + 7 + words.length;
  488. if (limit !== false && actualLength > limit)
  489. throw new TypeError(`Length ${actualLength} exceeds limit ${limit}`);
  490. const lowered = prefix.toLowerCase();
  491. const sum = bechChecksum(lowered, words, ENCODING_CONST);
  492. return `${lowered}1${BECH_ALPHABET.encode(words)}${sum}` as `${Lowercase<Prefix>}1${string}`;
  493. }
  494. function decode<Prefix extends string>(
  495. str: `${Prefix}1${string}`,
  496. limit?: number | false
  497. ): Bech32Decoded<Prefix>;
  498. function decode(str: string, limit?: number | false): Bech32Decoded;
  499. function decode(str: string, limit: number | false = 90): Bech32Decoded {
  500. if (typeof str !== 'string')
  501. throw new Error(`bech32.decode input should be string, not ${typeof str}`);
  502. if (str.length < 8 || (limit !== false && str.length > limit))
  503. throw new TypeError(`Wrong string length: ${str.length} (${str}). Expected (8..${limit})`);
  504. // don't allow mixed case
  505. const lowered = str.toLowerCase();
  506. if (str !== lowered && str !== str.toUpperCase())
  507. throw new Error(`String must be lowercase or uppercase`);
  508. const sepIndex = lowered.lastIndexOf('1');
  509. if (sepIndex === 0 || sepIndex === -1)
  510. throw new Error(`Letter "1" must be present between prefix and data only`);
  511. const prefix = lowered.slice(0, sepIndex);
  512. const data = lowered.slice(sepIndex + 1);
  513. if (data.length < 6) throw new Error('Data must be at least 6 characters long');
  514. const words = BECH_ALPHABET.decode(data).slice(0, -6);
  515. const sum = bechChecksum(prefix, words, ENCODING_CONST);
  516. if (!data.endsWith(sum)) throw new Error(`Invalid checksum in ${str}: expected "${sum}"`);
  517. return { prefix, words };
  518. }
  519. const decodeUnsafe = unsafeWrapper(decode);
  520. function decodeToBytes(str: string): Bech32DecodedWithArray {
  521. const { prefix, words } = decode(str, false);
  522. return { prefix, words, bytes: fromWords(words) };
  523. }
  524. function encodeFromBytes(prefix: string, bytes: Uint8Array) {
  525. return encode(prefix, toWords(bytes));
  526. }
  527. return {
  528. encode,
  529. decode,
  530. encodeFromBytes,
  531. decodeToBytes,
  532. decodeUnsafe,
  533. fromWords,
  534. fromWordsUnsafe,
  535. toWords,
  536. };
  537. }
  538. export const bech32: Bech32 = /* @__PURE__ */ genBech32('bech32');
  539. export const bech32m: Bech32 = /* @__PURE__ */ genBech32('bech32m');
  540. declare const TextEncoder: any;
  541. declare const TextDecoder: any;
  542. export const utf8: BytesCoder = {
  543. encode: (data) => new TextDecoder().decode(data),
  544. decode: (str) => new TextEncoder().encode(str),
  545. };
  546. export const hex: BytesCoder = /* @__PURE__ */ chain(
  547. radix2(4),
  548. alphabet('0123456789abcdef'),
  549. join(''),
  550. normalize((s: string) => {
  551. if (typeof s !== 'string' || s.length % 2)
  552. throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`);
  553. return s.toLowerCase();
  554. })
  555. );
  556. // prettier-ignore
  557. const CODERS = {
  558. utf8, hex, base16, base32, base64, base64url, base58, base58xmr
  559. };
  560. type CoderType = keyof typeof CODERS;
  561. const coderTypeError =
  562. 'Invalid encoding type. Available types: utf8, hex, base16, base32, base64, base64url, base58, base58xmr';
  563. export const bytesToString = (type: CoderType, bytes: Uint8Array): string => {
  564. if (typeof type !== 'string' || !CODERS.hasOwnProperty(type)) throw new TypeError(coderTypeError);
  565. if (!isBytes(bytes)) throw new TypeError('bytesToString() expects Uint8Array');
  566. return CODERS[type].encode(bytes);
  567. };
  568. export const str = bytesToString; // as in python, but for bytes only
  569. export const stringToBytes = (type: CoderType, str: string): Uint8Array => {
  570. if (!CODERS.hasOwnProperty(type)) throw new TypeError(coderTypeError);
  571. if (typeof str !== 'string') throw new TypeError('stringToBytes() expects string');
  572. return CODERS[type].decode(str);
  573. };
  574. export const bytes = stringToBytes;