Skip to content

If it helps it helps. Thanks #3

@coryscotthodson-png

Description

@coryscotthodson-png

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.


⚠️ Critical / Possible Bugs or Concerns

  1. 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 + ")");


  1. 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.


  1. 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.


  1. 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.


  1. 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.


  1. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions