index.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.mnemonicToSeedSync = exports.mnemonicToSeed = exports.validateMnemonic = exports.entropyToMnemonic = exports.mnemonicToEntropy = exports.generateMnemonic = void 0;
  4. /*! scure-bip39 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) */
  5. const _assert_1 = require("@noble/hashes/_assert");
  6. const pbkdf2_1 = require("@noble/hashes/pbkdf2");
  7. const sha256_1 = require("@noble/hashes/sha256");
  8. const sha512_1 = require("@noble/hashes/sha512");
  9. const utils_1 = require("@noble/hashes/utils");
  10. const base_1 = require("@scure/base");
  11. // Japanese wordlist
  12. const isJapanese = (wordlist) => wordlist[0] === '\u3042\u3044\u3053\u304f\u3057\u3093';
  13. // Normalization replaces equivalent sequences of characters
  14. // so that any two texts that are equivalent will be reduced
  15. // to the same sequence of code points, called the normal form of the original text.
  16. // https://tonsky.me/blog/unicode/#why-is-a----
  17. function nfkd(str) {
  18. if (typeof str !== 'string')
  19. throw new TypeError(`Invalid mnemonic type: ${typeof str}`);
  20. return str.normalize('NFKD');
  21. }
  22. function normalize(str) {
  23. const norm = nfkd(str);
  24. const words = norm.split(' ');
  25. if (![12, 15, 18, 21, 24].includes(words.length))
  26. throw new Error('Invalid mnemonic');
  27. return { nfkd: norm, words };
  28. }
  29. function assertEntropy(entropy) {
  30. (0, _assert_1.bytes)(entropy, 16, 20, 24, 28, 32);
  31. }
  32. /**
  33. * Generate x random words. Uses Cryptographically-Secure Random Number Generator.
  34. * @param wordlist imported wordlist for specific language
  35. * @param strength mnemonic strength 128-256 bits
  36. * @example
  37. * generateMnemonic(wordlist, 128)
  38. * // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
  39. */
  40. function generateMnemonic(wordlist, strength = 128) {
  41. (0, _assert_1.number)(strength);
  42. if (strength % 32 !== 0 || strength > 256)
  43. throw new TypeError('Invalid entropy');
  44. return entropyToMnemonic((0, utils_1.randomBytes)(strength / 8), wordlist);
  45. }
  46. exports.generateMnemonic = generateMnemonic;
  47. const calcChecksum = (entropy) => {
  48. // Checksum is ent.length/4 bits long
  49. const bitsLeft = 8 - entropy.length / 4;
  50. // Zero rightmost "bitsLeft" bits in byte
  51. // For example: bitsLeft=4 val=10111101 -> 10110000
  52. return new Uint8Array([((0, sha256_1.sha256)(entropy)[0] >> bitsLeft) << bitsLeft]);
  53. };
  54. function getCoder(wordlist) {
  55. if (!Array.isArray(wordlist) || wordlist.length !== 2048 || typeof wordlist[0] !== 'string')
  56. throw new Error('Wordlist: expected array of 2048 strings');
  57. wordlist.forEach((i) => {
  58. if (typeof i !== 'string')
  59. throw new Error(`Wordlist: non-string element: ${i}`);
  60. });
  61. return base_1.utils.chain(base_1.utils.checksum(1, calcChecksum), base_1.utils.radix2(11, true), base_1.utils.alphabet(wordlist));
  62. }
  63. /**
  64. * Reversible: Converts mnemonic string to raw entropy in form of byte array.
  65. * @param mnemonic 12-24 words
  66. * @param wordlist imported wordlist for specific language
  67. * @example
  68. * const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
  69. * mnemonicToEntropy(mnem, wordlist)
  70. * // Produces
  71. * new Uint8Array([
  72. * 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
  73. * 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
  74. * ])
  75. */
  76. function mnemonicToEntropy(mnemonic, wordlist) {
  77. const { words } = normalize(mnemonic);
  78. const entropy = getCoder(wordlist).decode(words);
  79. assertEntropy(entropy);
  80. return entropy;
  81. }
  82. exports.mnemonicToEntropy = mnemonicToEntropy;
  83. /**
  84. * Reversible: Converts raw entropy in form of byte array to mnemonic string.
  85. * @param entropy byte array
  86. * @param wordlist imported wordlist for specific language
  87. * @returns 12-24 words
  88. * @example
  89. * const ent = new Uint8Array([
  90. * 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
  91. * 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
  92. * ]);
  93. * entropyToMnemonic(ent, wordlist);
  94. * // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
  95. */
  96. function entropyToMnemonic(entropy, wordlist) {
  97. assertEntropy(entropy);
  98. const words = getCoder(wordlist).encode(entropy);
  99. return words.join(isJapanese(wordlist) ? '\u3000' : ' ');
  100. }
  101. exports.entropyToMnemonic = entropyToMnemonic;
  102. /**
  103. * Validates mnemonic for being 12-24 words contained in `wordlist`.
  104. */
  105. function validateMnemonic(mnemonic, wordlist) {
  106. try {
  107. mnemonicToEntropy(mnemonic, wordlist);
  108. }
  109. catch (e) {
  110. return false;
  111. }
  112. return true;
  113. }
  114. exports.validateMnemonic = validateMnemonic;
  115. const salt = (passphrase) => nfkd(`mnemonic${passphrase}`);
  116. /**
  117. * Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
  118. * @param mnemonic 12-24 words
  119. * @param passphrase string that will additionally protect the key
  120. * @returns 64 bytes of key data
  121. * @example
  122. * const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
  123. * await mnemonicToSeed(mnem, 'password');
  124. * // new Uint8Array([...64 bytes])
  125. */
  126. function mnemonicToSeed(mnemonic, passphrase = '') {
  127. return (0, pbkdf2_1.pbkdf2Async)(sha512_1.sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
  128. }
  129. exports.mnemonicToSeed = mnemonicToSeed;
  130. /**
  131. * Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
  132. * @param mnemonic 12-24 words
  133. * @param passphrase string that will additionally protect the key
  134. * @returns 64 bytes of key data
  135. * @example
  136. * const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
  137. * mnemonicToSeedSync(mnem, 'password');
  138. * // new Uint8Array([...64 bytes])
  139. */
  140. function mnemonicToSeedSync(mnemonic, passphrase = '') {
  141. return (0, pbkdf2_1.pbkdf2)(sha512_1.sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
  142. }
  143. exports.mnemonicToSeedSync = mnemonicToSeedSync;