Bivariate Copper
Bivariate Copper - Writeup
Challenge Overview
The "Bivariate Copper" challenge involves recovering a flag hidden within a set of modular relations. We are provided with:
- An RSA-encrypted message with a 1049-bit modulus .
- A 64-bit value .
- Two 512-bit values .
- The upper bits of two values , where: and is a large prime factor of .
The task is to factor , decrypt the RSA message, and use the leaked bits of to recover the flag via a bivariate Coppersmith-style attack.
Solving Steps
1. Factoring the RSA Modulus
The RSA modulus is 1049 bits long. Testing for small factors reveals a small prime factor :
- (a 25-bit prime)
- (a 1024-bit prime)
This factorization provides the modulus used in the relations.
2. RSA Decryption
With and , we calculate and the private exponent . Decrypting the ciphertext :
- Decoded hint:
b'Hurry up and go smelt copper!'
The hint points towards a Coppersmith attack.
3. Deriving the Bivariate Equation
The relations modulo are:
Eliminating :
Let and , where are the known upper bits and are the small unknowns (). Substituting these into the equation yields a bivariate polynomial: where are constants derived from .
4. Lattice Construction and Solving (SageMath)
Using SageMath, we can find the small roots efficiently. We define the bounds and construct a lattice based on the polynomial .
The basis matrix :
Running LLL on this matrix yields short vectors corresponding to polynomials that have as a root over the integers. We can then find the intersection of two such polynomials using resultants:
P.<x, y> = PolynomialRing(ZZ)
g1 = polys[0]
g2 = polys[1]
res = g1.resultant(g2, y)
roots_x = res.univariate_polynomial().roots()
5. Flag Recovery
After finding the root , we compute and recover :
Converting to bytes reveals the flag: flag{H4hAHhhHh4_c0pP3r_N07_v1OI3n7_3n0uGh}.