base58.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. /**
  2. * The [Base58 Encoding](link-base58) scheme allows a **numeric** value
  3. * to be encoded as a compact string using a radix of 58 using only
  4. * alpha-numeric characters. Confusingly similar characters are omitted
  5. * (i.e. ``"l0O"``).
  6. *
  7. * Note that Base58 encodes a **numeric** value, not arbitrary bytes,
  8. * since any zero-bytes on the left would get removed. To mitigate this
  9. * issue most schemes that use Base58 choose specific high-order values
  10. * to ensure non-zero prefixes.
  11. *
  12. * @_subsection: api/utils:Base58 Encoding [about-base58]
  13. */
  14. import { getBytes } from "./data.js";
  15. import { assertArgument } from "./errors.js";
  16. import { toBigInt } from "./maths.js";
  17. import type { BytesLike } from "./index.js";
  18. const Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
  19. let Lookup: null | Record<string, bigint> = null;
  20. function getAlpha(letter: string): bigint {
  21. if (Lookup == null) {
  22. Lookup = { };
  23. for (let i = 0; i < Alphabet.length; i++) {
  24. Lookup[Alphabet[i]] = BigInt(i);
  25. }
  26. }
  27. const result = Lookup[letter];
  28. assertArgument(result != null, `invalid base58 value`, "letter", letter);
  29. return result;
  30. }
  31. const BN_0 = BigInt(0);
  32. const BN_58 = BigInt(58);
  33. /**
  34. * Encode %%value%% as a Base58-encoded string.
  35. */
  36. export function encodeBase58(_value: BytesLike): string {
  37. const bytes = getBytes(_value);
  38. let value = toBigInt(bytes);
  39. let result = "";
  40. while (value) {
  41. result = Alphabet[Number(value % BN_58)] + result;
  42. value /= BN_58;
  43. }
  44. // Account for leading padding zeros
  45. for (let i = 0; i < bytes.length; i++) {
  46. if (bytes[i]) { break; }
  47. result = Alphabet[0] + result;
  48. }
  49. return result;
  50. }
  51. /**
  52. * Decode the Base58-encoded %%value%%.
  53. */
  54. export function decodeBase58(value: string): bigint {
  55. let result = BN_0;
  56. for (let i = 0; i < value.length; i++) {
  57. result *= BN_58;
  58. result += getAlpha(value[i]);
  59. }
  60. return result;
  61. }