ECC 2 - 200 (Cryptography)
Writeup by pwang00 (Sanguinius)
More elliptic curve cryptography fun for everyone! handout.txt (Yes, the flag will just be the number n.)
Using SageMath (or something similar which supports working with elliptic curves) will be very helpful.
Use the Pohlig-Hellman algorithm to calculate Elliptic Curve Discrete Logarithm and recover scalar used to arrive at point (n*P)
We are given the following handout:
Elliptic Curve: y^2 = x^3 + A*x + B mod M M = 93556643250795678718734474880013829509320385402690660619699653921022012489089 A = 66001598144012865876674115570268990806314506711104521036747533612798434904785 B = *You can figure this out with the point below :)* P = (56027910981442853390816693056740903416379421186644480759538594137486160388926, 65533262933617146434438829354623658858649726233622196512439589744498050226926) n = *SECRET* n*P = (61124499720410964164289905006830679547191538609778446060514645905829507254103, 2595146854028317060979753545310334521407008629091560515441729386088057610440) n < 400000000000000000000000000000 Find n.
Our first step will be to solve for via rearranging the elliptic curve equation:
In Sage, this is done via substituting the and values as shown:
sage: x, y = P, P sage: b = (y^2 - x^3 - a*x) % N #The ^ operator is exponentiation instead of XOR in Sage. sage: print(b) 25255205054024371783896605039267101837972419055969636393425590261926131199030
Solving for , we obtain 25255205054024371783896605039267101837972419055969636393425590261926131199030.
We now have all the necessary parameters for the elliptic curve. Thus, our next step is to define the curve over a finite field of integers modulo , and define the points and to be on the curve:
F = FiniteField(M) E = EllipticCurve(F,[A,B]) P = E.point(P) Q = E.point(Q)
Essentially, this challenge requires us to solve the Elliptic Curve Discrete Logarithm Problem (ECDLP): compute the scalar given the base point and the product point where . There are a few known attacks against ECDLP, including the:
- MOV attack (involves finding linearly independent points and calculating Weil pairing to reduce ECDLP to over finite field instead of group of points on elliptic curve)
- Pohlig-Hellman (reduces discrete logarithm calculations to prime subgroups of the order of P and uses Chinese Remainder Theorem to solve system of congruences for discrete logarithm of the whole order )
We can rule out the MOV attack, since it is infeasible given the size of the elliptic curve order. However, factoring the order of our elliptic curve reveals many small prime factors, indicating that Pohlig-Hellman could be feasible:
sage: factor(E.order()) 2^2 * 3 * 5 * 7 * 137 * 593 * 24337 * 25589 * 3637793 * 5733569 * 106831998530025000830453 * 1975901744727669147699767
The goal of Pohlig-Hellman and the mathematics leading to it is as follows:
We are attempting to recreate a system of congruences to solve for the value of (referred to as in this problem):
where denotes the discrete logarithm for the order of , denotes discrete logarithm calculations for each of the smaller prime orders (factors) of , and denotes the exponent of .
First, define an integer such that (in other words, is equivalent to the order of ).
can be written in the form:
We then define the points , and .
Since we know that the order of is , we can rewrite the equation as , we can now solve for every by finding a value for such that .
This is comparable to brute force in that if the value of is small enough, it is feasible to try all the values of in range of until a value which satisfies the equation above is found.
In Sage, this can be done as follows:
sage: primes = [4, 3, 5, 7, 137, 593, 24337, 25589, 3637793, 5733569, 106831998530025000830453, 1975901744727669147699767] sage: dlogs =  sage: for fac in primes: t = int(P.order()) / int(fac) dlog = discrete_log(t*Q,t*P,operation="+") dlogs += [dlog] print("factor: "+str(fac)+", Discrete Log: "+str(dlog)) #calculates discrete logarithm for each prime order factor: 4, dlog: 2 factor: 3, dlog: 1 factor: 5, dlog: 4 factor: 7, dlog: 1 factor: 137, dlog: 129 factor: 593, dlog: 224 factor: 24337, dlog: 5729 factor: 25589, dlog: 13993 factor: 3637793, dlog: 1730599 factor: 5733569, dlog: 4590572
You will notice that Sage hangs while computing the discrete logarithms for last 2 prime factors. However, we don't need to know them, since in the problem statement, was defined to be less than 400000000000000000000000000000. Multiplying every prime order save for the last 2 returns a boundary of 443208349730265573969192476820, meaning that fits within the bound!
Our final step is just to solve for via CRT:
sage: l = crt(dlogs.primes[:-2]) 152977126447386808276536247114
which returns the value for !
Just to check the validity of , we perform a quick boolean comparison;
sage: l * P == Q True
Thus, our value of is indeed correct!
Note: due to random problem generation, your value may be different.
M = 93556643250795678718734474880013829509320385402690660619699653921022012489089 A = 66001598144012865876674115570268990806314506711104521036747533612798434904785 B = 25255205054024371783896605039267101837972419055969636393425590261926131199030 P = (56027910981442853390816693056740903416379421186644480759538594137486160388926, 65533262933617146434438829354623658858649726233622196512439589744498050226926) Q = (61124499720410964164289905006830679547191538609778446060514645905829507254103, 2595146854028317060979753545310334521407008629091560515441729386088057610440) F = FiniteField(M) E = EllipticCurve(F,[A,B]) P = E.point(P) Q = E.point(Q) factors, exponents = zip(*factor(E.order())) primes = [factors[i] ^ exponents[i] for i in range(len(factors))][:-2] dlogs =  for fac in primes: t = int(P.order()) / int(fac) dlog = discrete_log(t*Q,t*P,operation="+") dlogs += [dlog] print("factor: "+str(fac)+", Discrete Log: "+str(dlog)) #calculates discrete logarithm for each prime order l = crt(dlogs,primes) print(l)