]> git.codecow.com Git - libnemo.git/commitdiff
Refactor mnemonic validation to compare bitwise using bigints.
authorChris Duncan <chris@zoso.dev>
Wed, 30 Jul 2025 14:29:37 +0000 (07:29 -0700)
committerChris Duncan <chris@zoso.dev>
Wed, 30 Jul 2025 14:29:37 +0000 (07:29 -0700)
src/lib/bip39-mnemonic.ts

index 47fe7cc3c63c9720c96c221b3adfccfc26482181..3d05afda04fcf74b4a5aa1507f8988c7bd12a1f2 100644 (file)
@@ -117,31 +117,38 @@ export class Bip39Mnemonic {
                        return false\r
                }\r
 \r
-               const wordBits = words.map(word => {\r
+               let bits = 0n, bitLength = 0n\r
+               for (const word of words) {\r
                        const wordIndex = Bip39Words.indexOf(word)\r
                        if (wordIndex === -1) {\r
                                return false\r
                        }\r
-                       return dec.toBin(wordIndex, 11)\r
-               }).join('')\r
-               const checksumLength = wordBits.length / 33\r
-               const entropyLength = wordBits.length - checksumLength\r
-               const entropyBits = wordBits.substring(0, entropyLength)\r
-               const checksumBits = wordBits.substring(entropyLength)\r
-\r
-               if (\r
-                       entropyBits == null\r
-                       || entropyBits.length < 128\r
-                       || entropyBits.length > 256\r
-                       || entropyBits.length % 32 !== 0\r
+                       bits = (bits << 11n) | BigInt(Bip39Words.indexOf(word))\r
+                       bitLength += 11n\r
+               }\r
+               if (Number(bitLength) % 33 !== 0) {\r
+                       return false\r
+               }\r
+\r
+               const checksumLength = bitLength / 33n\r
+               const entropyLength = Number(bitLength - checksumLength)\r
+               const entropyBits = bits >> checksumLength\r
+               const checksumBits = bits & ((1n << checksumLength) - 1n)\r
+\r
+               if (entropyBits == null\r
+                       || entropyBits < 0n\r
+                       || entropyBits > (1n << 256n) - 1n\r
+                       || entropyLength < 128\r
+                       || entropyLength > 256\r
+                       || entropyLength % 32 !== 0\r
                ) {\r
                        return false\r
                }\r
 \r
-               const entropy = await Entropy.import(bin.toBytes(entropyBits))\r
+               const entropyHex = entropyBits.toString(16).padStart(entropyLength / 4, '0')\r
+               const entropy = await Entropy.import(entropyHex)\r
                const expectedChecksum = await this.checksum(entropy.bytes)\r
-\r
-               if (Number(expectedChecksum) !== parseInt(checksumBits, 2)) {\r
+               if (expectedChecksum !== checksumBits) {\r
                        return false\r
                }\r
 \r