]> git.codecow.com Git - libnemo.git/commitdiff
Use bitwise ops instead of arithmetic where possible. Build mnemonic phrase string...
authorChris Duncan <chris@codecow.com>
Fri, 3 Jul 2026 06:58:59 +0000 (23:58 -0700)
committerChris Duncan <chris@codecow.com>
Fri, 3 Jul 2026 06:58:59 +0000 (23:58 -0700)
src/lib/crypto/bip39.ts

index a00c755d1e497f5514369f49ca918218472841a6..37a5f265ea70566a29421586e8c90a95f19c79d8 100644 (file)
@@ -17,7 +17,7 @@ export class Bip39 {
         * @returns {Promise<bigint>} First N/32 bits of the hash as a bigint\r
         */\r
        static checksum (entropy: ArrayBuffer | Bytes): Promise<bigint> {\r
-               const checksumBitLength = (entropy.byteLength / 4) | 0\r
+               const checksumBitLength = entropy.byteLength >> 2\r
                return crypto.subtle.digest('SHA-256', entropy)\r
                        .then(hash => {\r
                                const sha256sum = new Uint8Array(hash)[0]\r
@@ -46,25 +46,22 @@ export class Bip39 {
                if (entropy.byteLength < 16 || entropy.byteLength > 32) {\r
                        throw new RangeError(`Entropy must be 16-32 bytes`)\r
                }\r
-               if (entropy.byteLength % 4 !== 0) {\r
+               if (entropy.byteLength & 3) {\r
                        throw new RangeError(`Entropy must be a multiple of 4 bytes`)\r
                }\r
 \r
-               const phraseLength = 0.75 * entropy.byteLength\r
+               const phraseLength = (entropy.byteLength >> 2) * 3\r
                return this.checksum(entropy)\r
                        .then(checksum => {\r
-                               const bigEntropy = bytes.toInt(entropy)\r
-\r
-                               let concatenation: bigint = (bigEntropy << BigInt(entropy.byteLength) / 4n) | checksum\r
-                               const words: string[] = []\r
+                               let concatenation: bigint = (bytes.toInt(entropy) << BigInt(entropy.byteLength >> 2)) | checksum\r
+                               let phrase = ''\r
                                for (let i = 0; i < phraseLength; i++) {\r
                                        const wordBits = concatenation & 2047n\r
                                        const wordIndex = Number(wordBits)\r
-                                       words.unshift(wordlist[wordIndex])\r
+                                       phrase = wordlist[wordIndex] + (i ? ' ' : '') + phrase\r
                                        concatenation >>= 11n\r
                                }\r
-                               const sentence = words.join(' ')\r
-                               return this.fromPhrase(sentence)\r
+                               return this.fromPhrase(phrase)\r
                        })\r
        }\r
 \r
@@ -129,13 +126,13 @@ export class Bip39 {
                        || entropyBits > (1n << 256n) - 1n\r
                        || entropyLength < 128n\r
                        || entropyLength > 256n\r
-                       || Number(entropyLength) % 32 !== 0\r
+                       || Number(entropyLength & 31n) !== 0\r
                ) {\r
                        return Promise.resolve(false)\r
                }\r
-               const bytes = new Uint8Array(Number(entropyLength) / 8)\r
+               const bytes = new Uint8Array(Number(entropyLength >> 3n))\r
                for (let i = 0; i < bytes.length; i++) {\r
-                       const shift = entropyLength - (8n * BigInt(i + 1))\r
+                       const shift = entropyLength - (BigInt(i + 1) << 3n)\r
                        const byte = (entropyBits >> shift) & 255n\r
                        bytes[i] = Number(byte)\r
                }\r