Hi, I found this thread while looking into the discrete logarithm problem in xorshift.
In
short, it *is* possible, but it's difficult. I have successfully found
the index for a few 128-bit xorshift seeds in a few hours of time per
seed. This is sufficiently weak to be useless for cryptography, but
still too slow for my use-case.
The weakness
originates from the fact that the order of xorshift128, 2^128-1 is
highly factorizable into relatively small primes:
$ factor $(python -c "print(2**128-1)")
340282366920938463463374607431768211455: 3 5 17 257 641 65537 274177 6700417 67280421310721
This
means that in the group of, say 'apply xorshift (2^128-1)/3 times',
each element has order 3. You can relatively easily force any element
from the full xorshift group onto a small cycle that contains the
identity element by exponentiating it by that factor.
You can
then easily get the residues of the index modulo the smaller primes,
even by brute force, the issue starts with the 6.7 million prime, and
then the 67 trillion prime. By using Pollard's rho algorithm (I mostly
stole the implementation from Sage), you can relatively quickly find the
residue modulo the smaller prime, but the algorithm takes hours for the
largest prime.
The reason I'm still searching
for something better is that I see a lot of mentions of algorithms that
can solve discrete logarithm in some fields in some faster way, and
xorshift does in fact form a certain (weird) field of characteristic 2
with some interesting linearity properties. There are papers like "A
heuristic quasi-polynomial algorithm for discrete logarithm in finite
fields of small characteristic", which seems like exactly what I want,
but the paper is unreadable, and assumes knowledge I don't have, and it
doesn't seem like any implementations of it actually exists. Even if it
does, how would I know if it applies to xorshift? It seems to need some
sort of subfield with a squared prime order, but each prime in
xorshift's order is unique, and those subgroups don't seem to form
sub-fields anyway if I understand the term correctly.
That
paper also mentions a Function Field Sieve, which is apparently
exponential time in some weird L() notation I haven't come across
before, but I don't know if it applies here either.
Back
on topic, your proposed shared key scheme is trivially breakable, as
you don't need to know the index of the seed values to be able to
compute how to transform any seed into any other seed by some amount of
xorshift applications. This is because of the odd linearity properties
of the field that xorshift forms. You can consider each bit
individually, making a matrix of which bit of input affects which bit of
output. These matrices can be xored with each other to obtain another
valid matrix that also represents applying xorshift some amount of
times. You can then solve for such a matrix that changes a specific seed
to another specific seed. I used a rather braindead algorithm for this
and just solved 128 rows of the matrix separately by Gaussian
elimination for each row, obtaining more relations between bits of data
by applying xorshift to both the input seed and output seed to keep them
at the same distance. (It should be possible to solve it faster, and
without doing this with a smarter algorithm that exploits the linearity
more directly.)
Having this matrix allows you
to effectively know everything you need to know about Alice's private
key, without actually knowing it. You can either do the same with the
seed and Bob's response to 'obtain' his private key, or just apply the
matrix to his response to obtain the shared key immediately.
If
Bob is an attacker, he can also force any specific value for the
derived key by doing this solving procedure to see how to transform
Alice's result into that value, and using the matrix in place of his own
private key, then sending the seed transformed by that matrix as his
response.