index.js 19 KB

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