From 670a4f78b69a4f3a11840828b84a9a626ac340fe Mon Sep 17 00:00:00 2001 From: Apotheosis <97164662+0xApotheosis@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:39:55 +1100 Subject: [PATCH] perf: optimize seed creation --- .../crypto/isolation/engines/default/bip39.ts | 42 ++++++------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/packages/hdwallet-native/src/crypto/isolation/engines/default/bip39.ts b/packages/hdwallet-native/src/crypto/isolation/engines/default/bip39.ts index a7c1cafa0..beeb2438f 100644 --- a/packages/hdwallet-native/src/crypto/isolation/engines/default/bip39.ts +++ b/packages/hdwallet-native/src/crypto/isolation/engines/default/bip39.ts @@ -2,6 +2,7 @@ import * as core from "@shapeshiftoss/hdwallet-core"; import * as bip32crypto from "bip32/src/crypto"; +import { createSHA512, pbkdf2 } from "hash-wasm"; import { TextEncoder } from "web-encoding"; import * as BIP32 from "../../core/bip32"; @@ -12,34 +13,6 @@ import { Revocable, revocable } from "./revocable"; export * from "../../core/bip39"; -// Poor man's single-block PBKDF2 implementation -//TODO: get something better -function pbkdf2_sha512_singleblock( - password: string, - salt: Uint8Array, - iterations: number -): Uint8Array & { length: 64 } { - function be32Buf(index: number): Buffer { - const indexBE = Buffer.alloc(4); - indexBE.writeUInt32BE(index); - return indexBE; - } - - const pwBuffer = safeBufferFrom(new TextEncoder().encode(password)); - - const out = bip32crypto.hmacSHA512(pwBuffer, core.compatibleBufferConcat([salt, be32Buf(1)])) as Buffer & { - length: 64; - }; - let lastU = out; - for (let i = 2; i <= iterations; i++) { - const newU = bip32crypto.hmacSHA512(pwBuffer, lastU) as Buffer & { length: 64 }; - for (let j = 0; j < out.length; j++) out[j] ^= newU[j]; - lastU = newU; - } - - return out; -} - export class Mnemonic extends Revocable(class {}) implements BIP39.Mnemonic { readonly #mnemonic: string; @@ -59,7 +32,18 @@ export class Mnemonic extends Revocable(class {}) implements BIP39.Mnemonic { const mnemonic = this.#mnemonic; const salt = new TextEncoder().encode(`mnemonic${passphrase ?? ""}`.normalize("NFKD")); - const out = await BIP32Engine.Seed.create(pbkdf2_sha512_singleblock(mnemonic, salt, 2048)); + const out = await BIP32Engine.Seed.create( + Buffer.from( + await pbkdf2({ + password: mnemonic, + salt, + iterations: 2048, + hashLength: 64, + hashFunction: createSHA512(), + outputType: "binary", + }) + ) + ); this.addRevoker(() => out.revoke?.()); return out; }