from Crypto.Random import random
from fastecdsa.curve import P256
from fastecdsa.point import Point
from fastecdsa.util import mod_sqrt
from tqdm.notebook import tqdm
PRNG refresher
$ \boxed{s_0} \\ \big \downarrow \ f\\ \boxed{s_1} \overset{g}{\longrightarrow} r_1 \\ \big\downarrow \ f\\ \boxed{s_2} \overset{g}{\longrightarrow} r_2 \\ \big\downarrow \ f\\ \boxed{s_3} \overset{g}{\longrightarrow} r_3 \\ $
where $f$ and $g$ are functions (problems) that are unfeasable to reverse
Let
ECDLP
If you know $P$ and $Q$ it's unfeasable to find $k$
DRBG = Dual Elliptic Curve Deterministic Random Bit Generator
Forward secrecy
If an internal state is compromised(known), the previous states cannot be compromised
Backward secrecy
If an internal state is compromised(known), the future states cannot be compromised
$ \boxed{s_0} \\ \Bigg \downarrow (s_0\cdot P).x\\ \boxed{s_1} \overset{(s_1\cdot Q).x}{\longrightarrow} r_1 \longrightarrow r_1[:240]\\ \Bigg\downarrow (s_1\cdot P).x\\ \boxed{s_2} \overset{(s_2\cdot Q).x}{\longrightarrow} r_2 \longrightarrow r_2[:240]\\ \Bigg\downarrow (s_2\cdot P).x\\ \boxed{s_3} \overset{(s_3\cdot Q).x}{\longrightarrow} r_3 \longrightarrow r_3[:240]\\ $
The strength of this PRNG is based on the ECDLP
But if $e$ is not random ($e$ is the backdoor) then
If we can choose $P$ and $Q$ let's us choose $Q$ such that $Q = P$
$ \boxed{s_0} \\ \Bigg \downarrow (s_0\cdot P).x\\ r_0 \overset{(r_0\cdot Q).x}{\longrightarrow} t_0 \longrightarrow t_0[:240]\\\\ \Bigg \downarrow (r_0\cdot P).x \\ \boxed{s_1} \\ \Bigg \downarrow (s_1\cdot P).x\\ r_1 \overset{(r_1\cdot Q).x}{\longrightarrow} t_1 \longrightarrow t_1[:240]\\\\ \Bigg \downarrow (r_1\cdot P).x \\ \boxed{s_2} \\ \Bigg \downarrow (s_2\cdot P).x\\ r_2 \overset{(r_2\cdot Q).x}{\longrightarrow} t_2 \longrightarrow t_2[:240]\\\\ \Bigg \downarrow (r_2\cdot P).x \\ \boxed{s_3} $
class Dual_EC_DRBG1:
def __init__(self, seed, P, Q):
self.seed = seed
self.P = P
self.Q = Q
def next_num(self):
s0 = self.seed
s1 = (s0 * self.P).x
r1 = (s1 * self.Q).x
self.seed = s1
return r1 & (2 ** (240) - 1)
P = P256.G
Q = random.getrandbits(256) * P
seed = random.getrandbits(60)
rng = Dual_EC_DRBG1(seed, P, Q)
print([rng.next_num() for i in range(3)])
[1231552060546413391318023453567188090058266792110274047592427562515379405, 1216758479565553634918843678377486776810471339166733586950286515033720989, 737040477072736357580008044487283109729120428264536331387468969326099282]
P = P256.G
seed = random.getrandbits(60)
rng = Dual_EC_DRBG1(seed, P, P)
rng.next_num()
654943182701178462091613576910994236387368131806757211391255622607623880
n1 = rng.next_num() # r1[:240]
n2 = rng.next_num() # r2[:240]
n1, n2
(1120705333011838021085717443044728103621641585710624670403295934388955926, 874745977888782828975052128375260260196665258740514531363400575549275986)
nr_r = 0
for i in tqdm(range(2**16)):
r1 = (i << 240) + n1
r1y = P256.evaluate(r1) # get y^2
r1y = mod_sqrt(r1y, P256.p)[0] # get y
if P256.is_point_on_curve((r1, r1y)): # test if the point is on curve
nr_r += 1
n2_pred = (r1 * P).x & (2 ** (240) - 1)
if n2 == n2_pred: # r2 = n2
print(r1, n2_pred)
break
HBox(children=(HTML(value=''), FloatProgress(value=0.0, max=65536.0), HTML(value='')))
102356338015009594435111093232981057268505591271487192487613172143017145199382 874745977888782828975052128375260260196665258740514531363400575549275986
rng_break = Dual_EC_DRBG1(r1, P, P) # s2
print([rng_break.next_num() == rng.next_num() for _ in range(10)])
[True, True, True, True, True, True, True, True, True, True]
class Dual_EC_DRBG2:
def __init__(self, seed, P, Q):
self.seed = seed
self.P = P
self.Q = Q
def next_num(self):
s0 = self.seed
r0 = (s0 * self.P).x
t0 = (r0 * self.Q).x
s1 = (r0 * self.P).x
self.seed = s1
return t0 & (2 ** (240) - 1)
P = P256.G
Q = random.getrandbits(256) * P
seed = random.getrandbits(60)
rng = Dual_EC_DRBG2(seed, P, Q)
print([rng.next_num() for i in range(3)])
[1069532959224303786163799834010794437350263072425150773821397613645823802, 603462681539745415502546334573068308938505608392255087400055874004112681, 157969509482800121589969694767104179251406862511669414471499855861721492]