-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathrejected.py
77 lines (61 loc) · 1.98 KB
/
rejected.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/usr/local/bin/python
import secrets
class LFSR:
def __init__(self, key, taps):
self._s = key
self._t = taps
def _sum(self, L):
s = 0
for x in L:
s ^= x
return s
def _clock(self):
b = self._s[0]
self._s = self._s[1:] + [self._sum(self._s[p] for p in self._t)]
return b
def bit(self):
return self._clock()
class RNG:
def __init__(self, lfsr, N, nbits):
self.lfsr = lfsr
self.N = N
self.nbits = nbits
if not (pow(2, 27) < N < pow(2, 31)):
raise ValueError("modulus is too big or small")
K = pow(2, nbits) // N
self.cutoff = K * N
def get_random_nbit_integer(self):
res = 0
for i in range(self.nbits):
res += self.lfsr.bit() << i
return res
def get_random_integer_modulo_N(self):
count = 1
while True:
x = self.get_random_nbit_integer()
if x < self.cutoff:
return x % self.N, count
count += 1
taps = [60, 58, 54, 52, 48, 47, 45, 43, 38, 36, 32, 28, 22, 21, 13, 9, 8, 5, 2, 0]
n = 64
with open("flag.txt", "r") as f:
flag = f.read()
if __name__ == "__main__":
print("Welcome to the unbiased random number factory!")
N = int(input("What modulus would you like to use? Choose between 2^27 and 2^31: "))
key = secrets.randbits(n)
key_bits = [(key >> i)&1 for i in range(n)]
lfsr = LFSR(key_bits, taps)
rng = RNG(lfsr, N, 32)
for _ in range(1024):
c = input("Enter your command (R,F): ")
if c.startswith("R"):
x,t = rng.get_random_integer_modulo_N()
print("creating this random number took {} attempts".format(t))
elif c.startswith("F"):
seed = int(input("what was my seed?"))
if seed == key:
print(flag)
exit(0)
else:
print("unsupported command")