-
Notifications
You must be signed in to change notification settings - Fork 11
If it helps it helps. Thanks #3
Description
Input:
threshold: minimum number of shares needed to reconstruct.
total: total number of shares to generate.
secret: the secret split byte-by-byte.
indexBits: how many bits to use for the x-coordinate (defaults to 8).
It generates total number of shares with unique non-zero x-coordinates.
For each byte of the secret:
Constructs a random polynomial of degree threshold - 1, with secret byte as the constant term.
Evaluates this polynomial at all chosen x-values to produce shares.
- Invalid index selection due to indexBits logic
let index_mask = 2**indexBits - 1;
if (total > index_mask) throw new Error("index bits is to low");
Should be:
if (total > index_mask + 1) throw new Error("index bits too low");
Reason: index_mask is the maximum value, and you skip index 0, so the number of usable indexes is only index_mask.
Fix suggestion:
if (total > index_mask) throw new Error("index bits too low (max usable: " + index_mask + ")");
- index !== 0 check: Why is index 0 skipped?
if ((shares[index] === undefined)&&(index !== 0)) {
Skipping index === 0 may break polynomial interpolation if 0 is a valid input (which it usually is). In classic Shamir's Secret Sharing, x = 0 is often used as the secret.
If you're avoiding x=0 deliberately (e.g., to avoid exposing the secret directly), document this explicitly.
However, this introduces bias and reduces the available index pool.
✅ Skipping x=0 is valid if and only if your Shamir reconstruction algorithm accounts for that and expects only x > 0.
- q.includes(w) check reduces entropy
do {
...
} while (q.includes(w));
This ensures coefficients are unique, but in standard SSS, polynomial coefficients do not need to be unique.
You're reducing entropy unnecessarily by rejecting duplicates.
Fix suggestion: Remove the q.includes(w) check for more entropy and better randomness.
- Ambiguous / unclear functions:
You use:
BF([])
BC([...])
S.__shamirFn(i, q)
These are likely:
BF = byte field / finite field byte conversion
BC = byte concatenation?
S.__shamirFn(x, coeffs) = evaluate polynomial
If these are not secure finite field arithmetic functions over GF(256), then your SSS implementation may break or become insecure.
Ensure: All arithmetic is done in the correct finite field (GF(256)), not modulo 256 unless using proper irreducible polynomial.
- Re-using entropy multiple times
You're generating entropy once and consuming it gradually:
e = S.generateEntropy({hex:false});
...
if (ePointer >= e.length) {
e = S.generateEntropy({hex:false});
ePointer = 0;
}
This is fine if S.generateEntropy gives truly random, cryptographically secure bytes. Just be aware of overusing small entropy pools.
✅ Use a cryptographically secure RNG and re-seed adequately.
- Returned structure is unclear
You return:
return shares;
But shares is an object where each key is the x-coordinate, and value is... a buffer?
This makes sense, but you may want to return it as:
return sharesIndexes.map(i => ({ x: i, y: shares[i] }));
For better serialization and reconstruction clarity.
🧠 Suggested Improvements
Add type validation for inputs.
Consider not skipping index 0 (or explicitly document why you are).
Don't enforce uniqueness of polynomial coefficients.
Clarify or rename BF and BC functions.
Return shares as { x, y } tuples, not an object map.
Add test vectors (e.g., compare with known SSS implementations).
✅ Example of improvement
if (threshold > 255 || total > 255)
throw new Error("threshold and total must be <= 255");
if (threshold > total)
throw new Error("threshold cannot exceed total");
const index_mask = 2 ** indexBits - 1;
if (total > index_mask)
throw new Error("indexBits too low to generate unique indices");
const shares = {};
const shareIndices = [];
let entropy = S.generateEntropy({ hex: false });
let ePointer = 0;
while (shareIndices.length < total) {
if (ePointer >= entropy.length) {
entropy = S.generateEntropy({ hex: false });
ePointer = 0;
}
const index = entropy[ePointer++] & index_mask;
if (index !== 0 && !(index in shares)) {
shares[index] = BF([]);
shareIndices.push(index);
}
}
entropy = S.generateEntropy({ hex: false });
ePointer = 0;
for (let b = 0; b < secret.length; b++) {
const coeffs = [secret[b]];
for (let j = 1; j < threshold; j++) {
if (ePointer >= entropy.length) {
entropy = S.generateEntropy({ hex: false });
ePointer = 0;
}
coeffs.push(entropy[ePointer++]); // allow duplicates
}
for (const i of shareIndices) {
const y = S.__shamirFn(i, coeffs);
shares[i] = BC([shares[i], BF([y])]);
}
}
return shareIndices.map(i => ({ x: i, y: shares[i] }));
Btc address is bc1qtvxzxt2pq20xd27pyarjhwv2ve8pl93e06qjy4