From 66dd4944190b9c4c0ee7b7bb5b24213df600924d Mon Sep 17 00:00:00 2001 From: moe Date: Tue, 12 May 2026 18:53:31 -0400 Subject: [PATCH] fix: reject single-share shamir splits Threshold-1 splits generate shares that expose the raw secret but cannot be restored through the existing recovery path, which rejects fewer than two points. Reject the split up front so callers do not create unusable mnemonic share sets. Co-authored-by: Codex --- src/functions/shamir_secret_sharing.js | 3 ++- test/jsbtc.test.js | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/functions/shamir_secret_sharing.js b/src/functions/shamir_secret_sharing.js index def4f16..ffcfc86 100644 --- a/src/functions/shamir_secret_sharing.js +++ b/src/functions/shamir_secret_sharing.js @@ -86,6 +86,7 @@ module.exports = function (S) { S.__split_secret = (threshold, total, secret, indexBits=8) => { + if (threshold < 2) throw new Error("Minimum 2 shares required"); if (threshold > 255) throw new Error("threshold limit 255"); if (total > 255) throw new Error("total limit 255"); let index_mask = 2**indexBits - 1; @@ -167,4 +168,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..45bcd3f 100644 --- a/test/jsbtc.test.js +++ b/test/jsbtc.test.js @@ -266,8 +266,8 @@ describe(`${(browser) ? 'Browser' : 'Node'} test jsbtc library`, function () { s = splitMnemonic(2, 255, m, {embeddedIndex: true}); equal(m, combineMnemonic(s)); - s = splitMnemonic(1, 255, m, {embeddedIndex: true}); - equal(m, combineMnemonic(s)); + expect(() => splitMnemonic(1, 255, m, {embeddedIndex: true})) + .to.throw("Minimum 2 shares required"); m = "stage amused wasp estate tomorrow outer satoshi version verb pudding ghost slender"; s = splitMnemonic(3, 8, m, {embeddedIndex: true}); @@ -529,6 +529,9 @@ describe(`${(browser) ? 'Browser' : 'Node'} test jsbtc library`, function () { }); it('Secret splitting', () => { + expect(() => __split_secret(1, 3, Buffer.from("w", 'utf8'))) + .to.throw("Minimum 2 shares required"); + let secret = Buffer.from("w", 'utf8'); for (let i = 0 ; i < 1000; i++) { let shares = __split_secret(5, 5, secret);