From 771b665321b7f993a1659b2cf81204ff5f90e97c Mon Sep 17 00:00:00 2001 From: Micheal KENECHUKWU Date: Mon, 11 May 2026 10:05:28 +0100 Subject: [PATCH] Fix embedded mnemonic share indexes --- src/functions/bip39_mnemonic.js | 4 ++-- src/functions/shamir_secret_sharing.js | 19 ++++++++++++++++--- test/jsbtc.test.js | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/functions/bip39_mnemonic.js b/src/functions/bip39_mnemonic.js index 462579a..592fa61 100644 --- a/src/functions/bip39_mnemonic.js +++ b/src/functions/bip39_mnemonic.js @@ -301,7 +301,7 @@ module.exports = function (S) { checkSum: A.checkSumVerify, hex: false}); let bits; if (A.embeddedIndex) - bits = Math.ceil(Math.log2(total))+1; + bits = S.__secret_index_bits(e); else bits = 8; @@ -366,4 +366,4 @@ module.exports = function (S) { return S.entropyToMnemonic(S.__restore_secret(s), A); } -}; \ No newline at end of file +}; diff --git a/src/functions/shamir_secret_sharing.js b/src/functions/shamir_secret_sharing.js index def4f16..a4af6cf 100644 --- a/src/functions/shamir_secret_sharing.js +++ b/src/functions/shamir_secret_sharing.js @@ -85,11 +85,24 @@ module.exports = function (S) { }; - S.__split_secret = (threshold, total, secret, indexBits=8) => { + S.__secret_index_bits = (secret) => { + const checksumBitsByEntropyLength = { + 16: 4, + 20: 5, + 24: 6, + 28: 7, + 32: 8, + }; + + return checksumBitsByEntropyLength[secret.length] || 8; + }; + + S.__split_secret = (threshold, total, secret, indexBits=null) => { if (threshold > 255) throw new Error("threshold limit 255"); if (total > 255) throw new Error("total limit 255"); + if (indexBits === null) indexBits = S.__secret_index_bits(secret); let index_mask = 2**indexBits - 1; - if (total > index_mask) throw new Error("index bits is to low"); + if (total > index_mask) throw new Error("index bits is too low"); if (threshold > total) throw new Error("invalid threshold"); let shares = {}; let sharesIndexes = []; @@ -167,4 +180,4 @@ module.exports = function (S) { }; S.__precompute_GF256_expLog(S); -}; \ No newline at end of file +}; diff --git a/test/jsbtc.test.js b/test/jsbtc.test.js index 99a4ce8..af06fbc 100644 --- a/test/jsbtc.test.js +++ b/test/jsbtc.test.js @@ -256,6 +256,21 @@ describe(`${(browser) ? 'Browser' : 'Node'} test jsbtc library`, function () { equal(combineMnemonic(shares), m); }); + it('split mnemonic with embedded indexes uses checksum-sized share indexes', () => { + let m = 'gift unfold street machine glue spring spin energy assist stereo liar ramp'; + let shares = splitMnemonic(3, 15, m, {embeddedIndex: true}); + + equal(shares.length, 15); + + for (let share of shares) { + let index = getMnemonicCheckSumData(share); + equal(index > 0, true); + equal(index <= 15, true); + } + + equal(combineMnemonic(shares.slice(0, 3)), m); + expect(() => splitMnemonic(3, 16, m, {embeddedIndex: true})).to.throw('index bits is too low'); + }); it('split mnemonic with embedded indexes extensive test', () => { let m = entropyToMnemonic(generateEntropy());