Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/shared/__init__.py
2587 views
1
import logging
2
from math import gcd
3
from math import isqrt
4
5
6
def int_to_bits_le(i, count):
7
"""
8
Converts an integer to bits, little endian.
9
:param i: the integer
10
:param count: the number of bits
11
:return: the bits
12
"""
13
bits = []
14
for _ in range(count):
15
bits.append(i & 1)
16
i >>= 1
17
18
return bits
19
20
21
def bits_to_int_le(bits, count):
22
"""
23
Converts bits to an integer, little endian
24
:param bits: the bits
25
:param count: the number of bits
26
:return: the integer
27
"""
28
i = 0
29
for k in range(count):
30
i |= (bits[k] & 1) << k
31
32
return i
33
34
35
def floor_div(a, b):
36
"""
37
Returns floor(a / b), works with large integers.
38
:param a: a
39
:param b: b
40
:return: floor(a / b)
41
"""
42
return a // b
43
44
45
def ceil_div(a, b):
46
"""
47
Returns ceil(a / b), works with large integers.
48
:param a: a
49
:param b: b
50
:return: ceil(a / b)
51
"""
52
return a // b + (a % b > 0)
53
54
55
def is_square(x):
56
"""
57
Returns the square root of x if x is a perfect square, or None otherwise.
58
:param x: x
59
:return: the square root of x or None
60
"""
61
y = isqrt(x)
62
return y if y ** 2 == x else None
63
64
65
def symmetric_mod(x, m):
66
"""
67
Computes the symmetric modular reduction.
68
:param x: the number to reduce
69
:param m: the modulus
70
:return: x reduced in the interval [-m/2, m/2]
71
"""
72
return int((x + m + m // 2) % m) - int(m // 2)
73
74
75
def solve_congruence(a, b, m):
76
"""
77
Solves a congruence of the form ax = b mod m.
78
:param a: the parameter a
79
:param b: the parameter b
80
:param m: the modulus m
81
:return: a generator generating solutions for x
82
"""
83
g = gcd(a, m)
84
a //= g
85
b //= g
86
n = m // g
87
for i in range(g):
88
yield (pow(a, -1, n) * b + i * n) % m
89
90
91
def divisors(factors):
92
"""
93
Computes all divisors from a list of factors
94
:param factors: the factors (tuples of primes and exponents)
95
:return: a generator generating divisors
96
"""
97
divisors = [1]
98
yield 1
99
for p, e in factors:
100
new = []
101
for d in divisors:
102
for k in range(1, e + 1):
103
d_ = p ** k * d
104
new.append(d_)
105
yield int(d_)
106
107
divisors += new
108
109
110
def make_square_free(x, factors):
111
"""
112
For any integer x, removes all square factors.
113
:param x: the value x
114
:param factors: the factors of x
115
:return: a square-free integer y, corresponding to x with all square factors removed
116
"""
117
for p, e in factors:
118
while e > 0 and e % 2 == 0:
119
e -= 2
120
x //= p
121
x //= p
122
return int(x)
123
124
125
def roots_of_unity(ring, l, r):
126
"""
127
Generates r-th roots of unity in a ring, with r | l.
128
:param ring: the ring, with order n
129
:param l: the Carmichael lambda of n
130
:param r: r
131
:return: a generator generating the roots of unity
132
"""
133
assert l % r == 0, "r should divide l"
134
135
x = ring(2)
136
while (g := x ** (l // r)) == 1:
137
x += 1
138
139
for i in range(r):
140
yield int(g ** i)
141
142
143
def rth_roots(Fq, delta, r):
144
"""
145
Uses the Adleman-Manders-Miller algorithm to extract r-th roots in Fq, with r | q - 1.
146
More information: Cao Z. et al., "Adleman-Manders-Miller Root Extraction Method Revisited" (Table 4)
147
:param Fq: the field Fq
148
:param delta: the r-th residue delta
149
:param r: the r
150
:return: a generator generating the rth roots
151
"""
152
delta = Fq(delta)
153
q = Fq.order()
154
assert (q - 1) % r == 0, "r should divide q - 1"
155
156
p = Fq(1)
157
while p ** ((q - 1) // r) == 1:
158
p = Fq.random_element()
159
160
t = 0
161
s = q - 1
162
while s % r == 0:
163
t += 1
164
s //= r
165
166
k = 1
167
while (k * s + 1) % r != 0:
168
k += 1
169
alpha = (k * s + 1) // r
170
171
a = p ** (pow(r, t - 1, q - 1) * s)
172
b = delta ** (r * alpha - 1)
173
c = p ** s
174
h = 1
175
for i in range(1, t):
176
d = b ** pow(r, t - 1 - i, q - 1)
177
logging.debug(f"Computing the discrete logarithm for {i = }, this may take a long time...")
178
j = 0 if d == 1 else -d.log(a)
179
b *= (c ** r) ** j
180
h *= c ** j
181
c **= r
182
183
root = int(delta ** alpha * h)
184
for primitive_root in roots_of_unity(Fq, q - 1, r):
185
yield root * primitive_root % q
186
187
188
def modinv_range(n, p):
189
"""
190
Computes the modular inverses of the numbers in the range (1, n] (exclusive), mod p.
191
More information: grhkm, "[Tutorial] Calculate modulo inverses efficiently!" (Codeforces)
192
:param n: the n
193
:param p: the modulus
194
:return: a generator generating the modular inverses of 1, 2... n - 1 mod p
195
"""
196
inv = [0] * n
197
inv[1] = 1
198
yield inv[1]
199
for i in range(2, n):
200
inv[i] = (p - p // i) * inv[p % i] % p
201
yield inv[i]
202
203
204
def modinv(a, p):
205
"""
206
Computes the modular inverses a list of numbers mod p.
207
More information: grhkm, "[Tutorial] Calculate modulo inverses efficiently!" (Codeforces)
208
:param a: the list of numbers
209
:param p: the modulus
210
:return: a generator generating the modular inverses of a1, a2... mod p
211
"""
212
n = len(a)
213
pre = [0] * n
214
pre[0] = 1
215
suf = [0] * n
216
suf[n - 1] = 1
217
prod = 1
218
for i in range(n - 1):
219
pre[i + 1] = pre[i] * a[i] % p
220
suf[n - i - 2] = suf[n - i - 1] * a[n - i - 1] % p
221
prod = prod * a[i] % p
222
223
prod = prod * a[n - 1] % p
224
prod = pow(prod, -1, p)
225
for i in range(n):
226
yield (pre[i] * suf[i] % p) * prod % p
227
228