mnemonic.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.Mnemonic = void 0;
  4. const index_js_1 = require("../crypto/index.js");
  5. const index_js_2 = require("../utils/index.js");
  6. const lang_en_js_1 = require("../wordlists/lang-en.js");
  7. // Returns a byte with the MSB bits set
  8. function getUpperMask(bits) {
  9. return ((1 << bits) - 1) << (8 - bits) & 0xff;
  10. }
  11. // Returns a byte with the LSB bits set
  12. function getLowerMask(bits) {
  13. return ((1 << bits) - 1) & 0xff;
  14. }
  15. function mnemonicToEntropy(mnemonic, wordlist) {
  16. (0, index_js_2.assertNormalize)("NFKD");
  17. if (wordlist == null) {
  18. wordlist = lang_en_js_1.LangEn.wordlist();
  19. }
  20. const words = wordlist.split(mnemonic);
  21. (0, index_js_2.assertArgument)((words.length % 3) === 0 && words.length >= 12 && words.length <= 24, "invalid mnemonic length", "mnemonic", "[ REDACTED ]");
  22. const entropy = new Uint8Array(Math.ceil(11 * words.length / 8));
  23. let offset = 0;
  24. for (let i = 0; i < words.length; i++) {
  25. let index = wordlist.getWordIndex(words[i].normalize("NFKD"));
  26. (0, index_js_2.assertArgument)(index >= 0, `invalid mnemonic word at index ${i}`, "mnemonic", "[ REDACTED ]");
  27. for (let bit = 0; bit < 11; bit++) {
  28. if (index & (1 << (10 - bit))) {
  29. entropy[offset >> 3] |= (1 << (7 - (offset % 8)));
  30. }
  31. offset++;
  32. }
  33. }
  34. const entropyBits = 32 * words.length / 3;
  35. const checksumBits = words.length / 3;
  36. const checksumMask = getUpperMask(checksumBits);
  37. const checksum = (0, index_js_2.getBytes)((0, index_js_1.sha256)(entropy.slice(0, entropyBits / 8)))[0] & checksumMask;
  38. (0, index_js_2.assertArgument)(checksum === (entropy[entropy.length - 1] & checksumMask), "invalid mnemonic checksum", "mnemonic", "[ REDACTED ]");
  39. return (0, index_js_2.hexlify)(entropy.slice(0, entropyBits / 8));
  40. }
  41. function entropyToMnemonic(entropy, wordlist) {
  42. (0, index_js_2.assertArgument)((entropy.length % 4) === 0 && entropy.length >= 16 && entropy.length <= 32, "invalid entropy size", "entropy", "[ REDACTED ]");
  43. if (wordlist == null) {
  44. wordlist = lang_en_js_1.LangEn.wordlist();
  45. }
  46. const indices = [0];
  47. let remainingBits = 11;
  48. for (let i = 0; i < entropy.length; i++) {
  49. // Consume the whole byte (with still more to go)
  50. if (remainingBits > 8) {
  51. indices[indices.length - 1] <<= 8;
  52. indices[indices.length - 1] |= entropy[i];
  53. remainingBits -= 8;
  54. // This byte will complete an 11-bit index
  55. }
  56. else {
  57. indices[indices.length - 1] <<= remainingBits;
  58. indices[indices.length - 1] |= entropy[i] >> (8 - remainingBits);
  59. // Start the next word
  60. indices.push(entropy[i] & getLowerMask(8 - remainingBits));
  61. remainingBits += 3;
  62. }
  63. }
  64. // Compute the checksum bits
  65. const checksumBits = entropy.length / 4;
  66. const checksum = parseInt((0, index_js_1.sha256)(entropy).substring(2, 4), 16) & getUpperMask(checksumBits);
  67. // Shift the checksum into the word indices
  68. indices[indices.length - 1] <<= checksumBits;
  69. indices[indices.length - 1] |= (checksum >> (8 - checksumBits));
  70. return wordlist.join(indices.map((index) => wordlist.getWord(index)));
  71. }
  72. const _guard = {};
  73. /**
  74. * A **Mnemonic** wraps all properties required to compute [[link-bip-39]]
  75. * seeds and convert between phrases and entropy.
  76. */
  77. class Mnemonic {
  78. /**
  79. * The mnemonic phrase of 12, 15, 18, 21 or 24 words.
  80. *
  81. * Use the [[wordlist]] ``split`` method to get the individual words.
  82. */
  83. phrase;
  84. /**
  85. * The password used for this mnemonic. If no password is used this
  86. * is the empty string (i.e. ``""``) as per the specification.
  87. */
  88. password;
  89. /**
  90. * The wordlist for this mnemonic.
  91. */
  92. wordlist;
  93. /**
  94. * The underlying entropy which the mnemonic encodes.
  95. */
  96. entropy;
  97. /**
  98. * @private
  99. */
  100. constructor(guard, entropy, phrase, password, wordlist) {
  101. if (password == null) {
  102. password = "";
  103. }
  104. if (wordlist == null) {
  105. wordlist = lang_en_js_1.LangEn.wordlist();
  106. }
  107. (0, index_js_2.assertPrivate)(guard, _guard, "Mnemonic");
  108. (0, index_js_2.defineProperties)(this, { phrase, password, wordlist, entropy });
  109. }
  110. /**
  111. * Returns the seed for the mnemonic.
  112. */
  113. computeSeed() {
  114. const salt = (0, index_js_2.toUtf8Bytes)("mnemonic" + this.password, "NFKD");
  115. return (0, index_js_1.pbkdf2)((0, index_js_2.toUtf8Bytes)(this.phrase, "NFKD"), salt, 2048, 64, "sha512");
  116. }
  117. /**
  118. * Creates a new Mnemonic for the %%phrase%%.
  119. *
  120. * The default %%password%% is the empty string and the default
  121. * wordlist is the [English wordlists](LangEn).
  122. */
  123. static fromPhrase(phrase, password, wordlist) {
  124. // Normalize the case and space; throws if invalid
  125. const entropy = mnemonicToEntropy(phrase, wordlist);
  126. phrase = entropyToMnemonic((0, index_js_2.getBytes)(entropy), wordlist);
  127. return new Mnemonic(_guard, entropy, phrase, password, wordlist);
  128. }
  129. /**
  130. * Create a new **Mnemonic** from the %%entropy%%.
  131. *
  132. * The default %%password%% is the empty string and the default
  133. * wordlist is the [English wordlists](LangEn).
  134. */
  135. static fromEntropy(_entropy, password, wordlist) {
  136. const entropy = (0, index_js_2.getBytes)(_entropy, "entropy");
  137. const phrase = entropyToMnemonic(entropy, wordlist);
  138. return new Mnemonic(_guard, (0, index_js_2.hexlify)(entropy), phrase, password, wordlist);
  139. }
  140. /**
  141. * Returns the phrase for %%mnemonic%%.
  142. */
  143. static entropyToPhrase(_entropy, wordlist) {
  144. const entropy = (0, index_js_2.getBytes)(_entropy, "entropy");
  145. return entropyToMnemonic(entropy, wordlist);
  146. }
  147. /**
  148. * Returns the entropy for %%phrase%%.
  149. */
  150. static phraseToEntropy(phrase, wordlist) {
  151. return mnemonicToEntropy(phrase, wordlist);
  152. }
  153. /**
  154. * Returns true if %%phrase%% is a valid [[link-bip-39]] phrase.
  155. *
  156. * This checks all the provided words belong to the %%wordlist%%,
  157. * that the length is valid and the checksum is correct.
  158. */
  159. static isValidMnemonic(phrase, wordlist) {
  160. try {
  161. mnemonicToEntropy(phrase, wordlist);
  162. return true;
  163. }
  164. catch (error) { }
  165. return false;
  166. }
  167. }
  168. exports.Mnemonic = Mnemonic;
  169. //# sourceMappingURL=mnemonic.js.map