UNPKG

@hdwallet/core

Version:

A complete Hierarchical Deterministic (HD) Wallet generator for 200+ cryptocurrencies, built with TypeScript.

158 lines 7.2 kB
"use strict"; // SPDX-License-Identifier: MIT Object.defineProperty(exports, "__esModule", { value: true }); exports.BIP39Mnemonic = exports.BIP39_MNEMONIC_LANGUAGES = exports.BIP39_MNEMONIC_WORDS = void 0; const mnemonic_1 = require("../mnemonic"); const entropies_1 = require("../../entropies"); const crypto_1 = require("../../crypto"); const utils_1 = require("../../utils"); const exceptions_1 = require("../../exceptions"); const wordlists_1 = require("./wordlists"); exports.BIP39_MNEMONIC_WORDS = { TWELVE: 12, FIFTEEN: 15, EIGHTEEN: 18, TWENTY_ONE: 21, TWENTY_FOUR: 24 }; exports.BIP39_MNEMONIC_LANGUAGES = { CHINESE_SIMPLIFIED: 'chinese-simplified', CHINESE_TRADITIONAL: 'chinese-traditional', CZECH: 'czech', ENGLISH: 'english', FRENCH: 'french', ITALIAN: 'italian', JAPANESE: 'japanese', KOREAN: 'korean', PORTUGUESE: 'portuguese', RUSSIAN: 'russian', SPANISH: 'spanish', TURKISH: 'turkish' }; class BIP39Mnemonic extends mnemonic_1.Mnemonic { static wordBitLength = 11; static wordsListNumber = 2048; static wordsList = [ exports.BIP39_MNEMONIC_WORDS.TWELVE, exports.BIP39_MNEMONIC_WORDS.FIFTEEN, exports.BIP39_MNEMONIC_WORDS.EIGHTEEN, exports.BIP39_MNEMONIC_WORDS.TWENTY_ONE, exports.BIP39_MNEMONIC_WORDS.TWENTY_FOUR ]; static wordsToEntropyStrength = { 12: entropies_1.BIP39_ENTROPY_STRENGTHS.ONE_HUNDRED_TWENTY_EIGHT, 15: entropies_1.BIP39_ENTROPY_STRENGTHS.ONE_HUNDRED_SIXTY, 18: entropies_1.BIP39_ENTROPY_STRENGTHS.ONE_HUNDRED_NINETY_TWO, 21: entropies_1.BIP39_ENTROPY_STRENGTHS.TWO_HUNDRED_TWENTY_FOUR, 24: entropies_1.BIP39_ENTROPY_STRENGTHS.TWO_HUNDRED_FIFTY_SIX }; static languages = Object.values(exports.BIP39_MNEMONIC_LANGUAGES); static wordLists = { [exports.BIP39_MNEMONIC_LANGUAGES.CHINESE_SIMPLIFIED]: wordlists_1.BIP39_CHINESE_SIMPLIFIED_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.CHINESE_TRADITIONAL]: wordlists_1.BIP39_CHINESE_TRADITIONAL_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.CZECH]: wordlists_1.BIP39_CZECH_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.ENGLISH]: wordlists_1.BIP39_ENGLISH_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.FRENCH]: wordlists_1.BIP39_FRENCH_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.ITALIAN]: wordlists_1.BIP39_ITALIAN_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.JAPANESE]: wordlists_1.BIP39_JAPANESE_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.KOREAN]: wordlists_1.BIP39_KOREAN_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.PORTUGUESE]: wordlists_1.BIP39_PORTUGUESE_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.RUSSIAN]: wordlists_1.BIP39_RUSSIAN_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.SPANISH]: wordlists_1.BIP39_SPANISH_WORDLIST, [exports.BIP39_MNEMONIC_LANGUAGES.TURKISH]: wordlists_1.BIP39_TURKISH_WORDLIST }; static getName() { return 'BIP39'; } static fromWords(words, language, options = {}) { if (!this.wordsList.includes(words)) { throw new exceptions_1.MnemonicError(`Invalid words`, { expected: this.wordsList, got: words }); } const strength = this.wordsToEntropyStrength[words]; const entropyHex = entropies_1.BIP39Entropy.generate(strength); return this.encode(entropyHex, language, options); } static fromEntropy(entropy, language, options = {}) { let hex; if (typeof entropy === 'string') { hex = entropy; } else if (entropy instanceof Uint8Array) { hex = (0, utils_1.bytesToHex)(entropy); } else { hex = entropy.getEntropy(); } return this.encode(hex, language, options); } static encode(entropyInput, language, options = {}) { const entropyBytes = typeof entropyInput === 'string' ? (0, utils_1.hexToBytes)(entropyInput) : entropyInput; const bitLen = entropyBytes.length * 8; if (!Object.values(this.wordsToEntropyStrength).includes(bitLen)) { throw new exceptions_1.EntropyError(`Unsupported entropy length ${bitLen}`); } const hash = (0, crypto_1.sha256)(entropyBytes); const csLen = bitLen / 32; const entBits = (0, utils_1.bytesToBinaryString)(entropyBytes, bitLen); const hashBits = (0, utils_1.bytesToBinaryString)(hash, 256).slice(0, csLen); const bits = entBits + hashBits; const wordList = this.getWordsListByLanguage(language, this.wordLists); if (wordList.length !== this.wordsListNumber) { throw new Error(`Loaded wordlist length ${wordList.length} !== ${this.wordsListNumber}`); } const words = []; for (let i = 0; i < bits.length / this.wordBitLength; i++) { const idx = parseInt(bits.slice(i * this.wordBitLength, (i + 1) * this.wordBitLength), 2); words.push(wordList[idx]); } return words.join(' '); } static decode(mnemonic, options = { checksum: false }) { const words = this.normalize(mnemonic); if (!this.wordsList.includes(words.length)) { throw new exceptions_1.MnemonicError(`Invalid words ${words.length}`, { expected: this.wordsList, got: words.length }); } let wordList; let idxMap = {}; if (options.wordsList && options.wordsListWithIndex) { idxMap = options.wordsListWithIndex; } else { [wordList] = this.findLanguage(words, this.wordLists); wordList.forEach((w, i) => idxMap[w] = i); } const bits = words .map(w => { const idx = idxMap[w]; if (idx === undefined) { throw new exceptions_1.MnemonicError(`Unknown word: ${w}`); } return (0, utils_1.integerToBinaryString)(idx, this.wordBitLength); }) .join(''); const checksumLen = bits.length / 33; const entropyBits = bits.slice(0, -checksumLen); const givenChecksum = bits.slice(-checksumLen); const entropyBytes = (0, utils_1.binaryStringToBytes)(entropyBits); const hash = (0, crypto_1.sha256)(entropyBytes); const hashBits = (0, utils_1.bytesToBinaryString)(hash, 256).slice(0, checksumLen); if (givenChecksum !== hashBits) { throw new exceptions_1.ChecksumError('Checksum mismatch', { expected: givenChecksum, got: hashBits }); } if (options.checksum) { const totalBits = bits.length; const padBits = totalBits % 8 === 0 ? totalBits : totalBits + (8 - (totalBits % 8)); return (0, utils_1.bytesToHex)((0, utils_1.binaryStringToBytes)(bits, padBits / 8)); } return (0, utils_1.bytesToHex)(entropyBytes); } static normalize(input) { const arr = typeof input === 'string' ? input.trim().split(/\s+/) : input; return arr.map(w => w.normalize('NFKD').toLowerCase()); } } exports.BIP39Mnemonic = BIP39Mnemonic; //# sourceMappingURL=mnemonic.js.map