From: Chris Duncan Date: Sat, 30 Aug 2025 04:17:38 +0000 (-0700) Subject: Replace async-await with Promise chains. X-Git-Tag: v0.10.5~38^2~13 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=d9365180c7058c03edd524843da96e5a8b144c09;p=libnemo.git Replace async-await with Promise chains. --- diff --git a/src/lib/crypto/bip39.ts b/src/lib/crypto/bip39.ts index 7baf54a..1fae699 100644 --- a/src/lib/crypto/bip39.ts +++ b/src/lib/crypto/bip39.ts @@ -17,11 +17,14 @@ export class Bip39 { * @param {Uint8Array} entropy - Cryptographically strong pseudorandom data of length N bits * @returns {Promise} First N/32 bits of the hash as a bigint */ - static async #checksum (entropy: Uint8Array): Promise { - const sha256sum = new Uint8Array(await crypto.subtle.digest('SHA-256', entropy))[0] - const checksumBitLength = BigInt(entropy.byteLength) / 4n - const checksum = BigInt(sha256sum) >> (8n - checksumBitLength) - return checksum + static #checksum (entropy: Uint8Array): Promise { + const checksumBitLength = (entropy.byteLength / 4) | 0 + return crypto.subtle.digest('SHA-256', entropy) + .then(hash => { + const sha256sum = new Uint8Array(hash)[0] + const checksum = sha256sum >> (8 - checksumBitLength) + return BigInt(checksum) + }) } /** @@ -39,7 +42,7 @@ export class Bip39 { * @param {(ArrayBuffer|Uint8Array)} entropy - Cryptographically secure random value * @returns {string} Mnemonic phrase created using the BIP-39 wordlist */ - static async fromEntropy (entropy: ArrayBuffer | Uint8Array): Promise { + static fromEntropy (entropy: ArrayBuffer | Uint8Array): Promise { if (entropy instanceof ArrayBuffer) { entropy = new Uint8Array(entropy) } @@ -54,19 +57,21 @@ export class Bip39 { } const phraseLength = 0.75 * entropy.byteLength - const checksum = await this.#checksum(entropy) - const bigEntropy = entropy.reduce((a, b) => a = (a << 8n) | BigInt(b), 0n) + return this.#checksum(entropy) + .then(checksum => { + const bigEntropy = entropy.reduce((a, b) => a = (a << 8n) | BigInt(b), 0n) - let concatenation: bigint = (bigEntropy << BigInt(entropy.byteLength) / 4n) | checksum - const words: string[] = [] - for (let i = 0; i < phraseLength; i++) { - const wordBits = concatenation & 2047n - const wordIndex = Number(wordBits) - words.unshift(this.wordlist[wordIndex]) - concatenation >>= 11n - } - const sentence = words.join(' ') - return this.fromPhrase(sentence) + let concatenation: bigint = (bigEntropy << BigInt(entropy.byteLength) / 4n) | checksum + const words: string[] = [] + for (let i = 0; i < phraseLength; i++) { + const wordBits = concatenation & 2047n + const wordIndex = Number(wordBits) + words.unshift(this.wordlist[wordIndex]) + concatenation >>= 11n + } + const sentence = words.join(' ') + return this.fromPhrase(sentence) + }) } /** @@ -78,16 +83,18 @@ export class Bip39 { * @param {string} phrase - String of 12, 15, 18, 21, or 24 words * @returns {string} Mnemonic phrase validated using the BIP-39 wordlist */ - static async fromPhrase (phrase: string): Promise { + static fromPhrase (phrase: string): Promise { this.#isInternal = true const self = new this() - const isValid = await this.validate(phrase) - if (isValid) { - self.#phrase = phrase.normalize('NFKD').toLowerCase().split(' ') - return self - } else { - throw new Error('Invalid mnemonic phrase.') - } + return this.validate(phrase) + .then(isValid => { + if (isValid) { + self.#phrase = phrase.normalize('NFKD').toLowerCase().split(' ') + return self + } else { + throw new Error('Invalid mnemonic phrase.') + } + }) } /** @@ -96,29 +103,29 @@ export class Bip39 { * @param {string} mnemonic - Mnemonic phrase to validate * @returns {boolean} True if the mnemonic phrase is valid */ - static async validate (mnemonic: string): Promise - static async validate (mnemonic: unknown): Promise { + static validate (mnemonic: string): Promise + static validate (mnemonic: unknown): Promise { if (typeof mnemonic !== 'string') { - return false + return Promise.resolve(false) } if (!/^(?:[a-z]{3,8} ){11,23}[a-z]{3,8}$/i.test(mnemonic)) { - return false + return Promise.resolve(false) } const words = mnemonic.normalize('NFKD').split(' ') if (words.length % 3 !== 0) { - return false + return Promise.resolve(false) } let bits = 0n, bitLength = 0n for (const word of words) { const wordIndex = this.wordlist.indexOf(word) if (wordIndex === -1) { - return false + return Promise.resolve(false) } bits = (bits << 11n) | BigInt(this.wordlist.indexOf(word)) bitLength += 11n } if (Number(bitLength) % 33 !== 0) { - return false + return Promise.resolve(false) } const checksumLength = bitLength / 33n const entropyLength = bitLength - checksumLength @@ -131,7 +138,7 @@ export class Bip39 { || entropyLength > 256n || Number(entropyLength) % 32 !== 0 ) { - return false + return Promise.resolve(false) } const bytes = new Uint8Array(Number(entropyLength) / 8) for (let i = 0; i < bytes.length; i++) { @@ -139,11 +146,8 @@ export class Bip39 { const byte = (entropyBits >> shift) & 255n bytes[i] = Number(byte) } - const expectedChecksum = await this.#checksum(bytes) - if (expectedChecksum !== checksumBits) { - return false - } - return true + return this.#checksum(bytes) + .then(expectedChecksum => expectedChecksum === checksumBits) } #bip39Seed?: Uint8Array @@ -153,7 +157,7 @@ export class Bip39 { private constructor () { if (!Bip39.#isInternal) { - throw new Error(`Bip39 must be created with async methods 'fromPhrase()' or 'fromEntropy().`) + throw new Error(`Bip39 must be created with factory methods 'fromPhrase()' or 'fromEntropy().`) } Bip39.#isInternal = false } @@ -178,7 +182,7 @@ export class Bip39 { * @param {string} [passphrase=''] - Used as the PBKDF2 salt. Default: "" * @returns {Promise>} Promise for seed as bytes */ - async toBip39Seed (passphrase: string): Promise> + toBip39Seed (passphrase: string): Promise> /** * Converts the mnemonic phrase to a BIP-39 seed. * @@ -188,45 +192,47 @@ export class Bip39 { * @param {string} [passphrase=''] - Used as the PBKDF2 salt. Default: "" * @returns {Promise} Promise for seed as hexadecimal string */ - async toBip39Seed (passphrase: string, format: 'hex'): Promise - async toBip39Seed (passphrase: unknown, format?: 'hex'): Promise> { + toBip39Seed (passphrase: string, format?: 'hex'): Promise + toBip39Seed (passphrase: unknown, format?: 'hex'): Promise> { if (this.phrase == null) { throw new Error('BIP-39 mnemonic phrase not found') } - if (this.#bip39Seed == null) { - const salt = (passphrase == null || typeof passphrase !== 'string') - ? '' - : passphrase + if (this.#bip39Seed != null) { + return Promise.resolve(format === 'hex' ? bytes.toHex(this.#bip39Seed) : this.#bip39Seed) + } else { + const salt = (typeof passphrase === 'string') ? passphrase : '' const keyData = utf8.toBytes(this.phrase) - const phraseKey = await crypto.subtle.importKey('raw', keyData, 'PBKDF2', false, ['deriveBits', 'deriveKey']) - const algorithm: Pbkdf2Params = { - name: 'PBKDF2', - hash: 'SHA-512', - salt: utf8.toBytes(`mnemonic${salt.normalize('NFKD')}`), - iterations: Bip39.#ITERATIONS - } - const seed = await crypto.subtle.deriveBits(algorithm, phraseKey, 512) - this.#bip39Seed = new Uint8Array(seed) + return crypto.subtle.importKey('raw', keyData, 'PBKDF2', false, ['deriveBits', 'deriveKey']) + .then(phraseKey => { + const algorithm: Pbkdf2Params = { + name: 'PBKDF2', + hash: 'SHA-512', + salt: utf8.toBytes(`mnemonic${salt.normalize('NFKD')}`), + iterations: Bip39.#ITERATIONS + } + return crypto.subtle.deriveBits(algorithm, phraseKey, 512) + .then(seed => { + this.#bip39Seed = new Uint8Array(seed) + return this.toBip39Seed(salt, format) + }) + }) } - return format === 'hex' - ? bytes.toHex(this.#bip39Seed) - : this.#bip39Seed } /** * Converts the mnemonic phrase to a BLAKE2b seed. * - * @returns {Promise>} Promise for seed as bytes + * @returns {Uint8Array} Seed as bytes */ - async toBlake2bSeed (): Promise> + toBlake2bSeed (): Uint8Array /** * Converts the mnemonic phrase to a BLAKE2b seed. * * @param {string} format - * @returns {Promise} Promise for seed as hexadecimal string + * @returns {string} Seed as hexadecimal string */ - async toBlake2bSeed (format: 'hex'): Promise - async toBlake2bSeed (format?: 'hex'): Promise> { + toBlake2bSeed (format: 'hex'): string + toBlake2bSeed (format?: 'hex'): string | Uint8Array { if (this.#phrase?.length !== 24) { throw new Error('BIP-39 mnemonic phrase must be 24 words to convert to BLAKE2b seed') }