secrets.js icon indicating copy to clipboard operation
secrets.js copied to clipboard

Unnecessary ruling out of zero in (CS)PRNG

Open scrovy opened this issue 2 years ago • 6 comments

Thanks for your implementation. Since this is audited, I'm using it as a basis for a (simplified) Python implementation of my own. Nevertheless I don't understand one thing: why do you restrict the cryptographically secure pseudo-random number generator to spit out non-zero coefficients for the polynomials? This reduces the search space slightly by 1/2^bits for each coefficient (for large bits this is not an issue but it is for small bits (for bits=1 the algorithm would break down completely since the coefficients would always be equal to 1, but fortunately you only allow bits>=3)).

https://github.com/grempe/secrets.js/blob/14a4b682a28242b1dbe5506674b5d5f476b78dbf/secrets.js#L228-L231

Here, the construct function returns null on all-zeros (i.e., the zero vector) https://github.com/grempe/secrets.js/blob/14a4b682a28242b1dbe5506674b5d5f476b78dbf/secrets.js#L252-L255 https://github.com/grempe/secrets.js/blob/14a4b682a28242b1dbe5506674b5d5f476b78dbf/secrets.js#L273-L280

In these two, you keep generating new PRNG numbers until they are not the zero vector. For bits=3 this means that the only coefficients allowed are $1, 2, 3, \ldots, 7 \in GF(8)$, but not 0.

scrovy avatar Dec 22 '22 16:12 scrovy

@scrovy Did you ever get this solved? Do you have a working version in Python? Is available? Cross-compatibility is important!

jeffkitson-music avatar Jan 06 '24 03:01 jeffkitson-music

As far as I know it's a non crucial issue, especially for a large number of bits. Typically bits=8 is used. But in principle yes, you should allow $0 \in GF(2^{bits})$ as well.

scrovy avatar Jan 06 '24 12:01 scrovy

Do you have a working version in Python? Is available? Cross-compatibility is important!

@jeffkitson-music I just finished working on my own cross-compatible port of secrets.js to Python. You can find it here.

poing avatar Mar 25 '24 04:03 poing

To answer the non-zero question... I am sure it was a conscious decision.

If random provided $0$ for both coefficients $a_1$ and $a_2$, it could potentially reveal the secret.

$q(x) = a_0 + a_1x + \dotsi + a_{k-1}x^{k-1}$

$1234 + (0\times 1) + (0\times 1^2) = 1234$ $1234 + (0\times 2) + (0\times 2^2) = 1234$ $1234 + (0\times 3) + (0\times 3^2) = 1234$ $1234 + (0\times x) + (0\times x^2) = 1234$

poing avatar Mar 25 '24 05:03 poing

What you're saying is that if all the coefficients $a_1, a_2, \ldots, a_k$ are identically zero, then your polynomial is constant hence the share is equal to the secret for any abscissa. Shouldn't then the check be $(a_1, a_2, \ldots, a_k) = 0$, I.e. all the coefficients equal to zero, instead of any coefficient equal to zero? Or is there an additional weakness I'm not seeing where a polynomial of the form $a_0 + a_1 x + a_2 x^2 + \ldots + a_{k-1} x^{k-1}$ with some of the $a_i, i\geq 1$ but not all of them zero, discloses any information on $a_0$?

scrovy avatar Mar 25 '24 09:03 scrovy

@scrovy

Dividing a secret into pieces, with the simplified method, without the galileo field $GF(p)$, every $0$ on the right would reduce $k$, reducing the number of shares needed to reconstruct a secret.

$q(x) = a_0 + a_1x + a_2x^2 + a_3x^3 + a_4x^4\implies k=5$ $q(x) = a_0 + a_1x + a_2x^2 + a_3x^3 + 0x^4\implies k=4$ $q(x) = a_0 + a_1x + a_2x^2 + 0x^3 + 0x^4\implies k=3$ $q(x) = a_0 + a_1x + 0x^2 + 0x^3 + 0x^4\implies k=2$ $q(x) = a_0 + 0_1x + 0x^2 + 0x^3 + 0x^4\implies a_0\implies secret$

Interpolation doesn't use $k$, it just derives the values from the shares. It's a reason why for $k=3$, you can combine $3$ or $30$ shares and get the same result. The $0$'s on the right would be canceled out.

With a galileo field $GF(p)$, having a $0$ might not be an issue.
Since the polynomials involved in $k=3$ reconstruction [47, 123, 67] might become a 0, but $GF(p)$ maintain $k=3$, since reconstruction can't determine the value is $0$ without the correct number of shares.

Technically, according to the original paper... the polynomials used for $a_1 + \dotsi + a_{k-1}$ are supposed to be randomly chosen from a uniform distribution over the integers in $[0,p)$. Which implies $0$ would be valid.

$f(x_0)\implies (x_0, y_0)\implies D_0\implies a_0\implies secret$

Because $0$ implies the $secret$, using $(1,p)$ for random integers seems to be a safer path.

poing avatar Mar 25 '24 12:03 poing