- Category: Crypto
- Score: 421/500
- Solves: 3
LCG is fun, ECDSA is fun too, so why not combine them together?
It signs 16 messages with ECDSA using secp256k1, with nonces
Warning: I do not fully understand why my solver works, so the explanation here is most likely wrong.
This writeup will roughly explain how solve2.py work, which is modified from my first working solver solve.py. But what they actually do is the same, just with different implementation.
First, take any two message and signature pairs
where
So from the given
$$ \begin{aligned} (v_1)i &= s_i^{-1} z_i - s{i+1}^{-1} z_{i+1} \ (v_2)i &= s_i^{-1} r_i - s{i+1}^{-1} r_{i+1} \ (\Delta k)i &= k_i - k{i+1} \end{aligned} $$
It follows that:
Then apply orthogonal lattice to
$O$ is theortho2.T
in the solver.
From the properties of LCG, we can see that:
$$ a \cdot ((\Delta k)1, \cdots, (\Delta k){n-1}) - ((\Delta k)2, \cdots, (\Delta k){n}) \equiv 0 \pmod{p} $$
which is
$$ a \cdot \mathop{\text{Slice}}(\Delta k, 0, n-1) - \mathop{\text{Slice}}(\Delta k, 1, n) \equiv a \cdot \mathop{\text{Slice}(O \mu, 0, n-1)} - \mathop{\text{Slice}(O \mu, 1, n)} \equiv 0 \pmod{p}
$$
where
And it can be further simplified to:
Since
Here we assume that
While this explaination sounds reasonable (to me), I find that replacing the
@genni first blooded this challenge, and he said his solution is based on Stern's algorithm, which only require one LLL to solve the challenge. I have no idea how it works, but I think it is worth mentioning and I might try to understand it later.
His idea is to recover a and p using a variant of Stern's attack, then it becomes a similar problem to my old challenge Easy DSA:LCG (or "Pseudo-Random" Number Generation within Cryptographic Algorithms: the DSS Case).
Lance Roy: Stern's attack is usually done when you are given the high bits of the LCG output, but it works equally well with the low bits of the LCG output, or more generally reducing the LCG output modulo a second, smaller modulus.
Lance Roy: Because I didn't get the LCG output exactly, only that the output is
$k = s^{-1} * z + s^{-1} * r * d \pmod{q}$ , I made it search for short vectors orthogonal$\pmod{q}$ to both$s^{-1} * z$ and$s^{-1} * r * d$ , so that I'd be sure that it was orthogonal to k. When these vectors are short enough, a bound similar to the one for Stern's attack shows that the vector has to be orthogonal to the original PRG output. Interpreting the orthogonal vector as a polynomial, this means that the polynomial is a multiple of$(x - a)$ modulo$p$ , so I can take a gcd of resultants of a few of these orthogonal vectors to get$p$ , and then take the gcd of the polynomials$\pmod{p}$ to get$x - a$ .
Solver: solve_lance_roy.sage
Actually, the idea of adapting Stern's attack is one of the few things I tried when I tried to develop this challenge, but it doesn't work for me at that time. However, after I read and understand his solution, I understand that culpit is that the short vectors ortho
matrix in my solver are only orthogonal in
It turns out a simple find_ortho_fp(q, v1, v2)
it not sufficient, but find_ortho_fp(q, v1[:-1], v2[:-1], v1[1:], v2[1:])
could result in vectors that zeros
The solution from genni and ConnorM are also fairly similar at the start, so I think we can conclude that the most crucial step is to find orthogonal vectors.