80 lines
1.8 KiB
Python
80 lines
1.8 KiB
Python
def int_to_bytes(raw, length):
|
|
data = []
|
|
for _ in range(length):
|
|
data.append(raw % 256)
|
|
raw //= 256
|
|
return bytes(data[::-1])
|
|
|
|
|
|
def bytes_to_int(data):
|
|
raw = 0
|
|
for byte in data:
|
|
raw = raw * 256 + byte
|
|
return raw
|
|
|
|
|
|
def legendre(a, p):
|
|
res = pow(a, (p - 1) // 2, p)
|
|
if res == p - 1:
|
|
return -1
|
|
else:
|
|
return res
|
|
|
|
|
|
def inverse(a, n):
|
|
if a == 0:
|
|
return 0
|
|
lm, hm = 1, 0
|
|
low, high = a % n, n
|
|
while low > 1:
|
|
r = high // low
|
|
nm, new = hm - lm * r, high - low * r
|
|
lm, low, hm, high = nm, new, lm, low
|
|
return lm % n
|
|
|
|
|
|
def square_root_mod_prime(n, p):
|
|
if n == 0:
|
|
return 0
|
|
if p == 2:
|
|
return n # We should never get here but it might be useful
|
|
if legendre(n, p) != 1:
|
|
raise ValueError("No square root")
|
|
# Optimizations
|
|
if p % 4 == 3:
|
|
return pow(n, (p + 1) // 4, p)
|
|
# 1. By factoring out powers of 2, find Q and S such that p - 1 =
|
|
# Q * 2 ** S with Q odd
|
|
q = p - 1
|
|
s = 0
|
|
while q % 2 == 0:
|
|
q //= 2
|
|
s += 1
|
|
# 2. Search for z in Z/pZ which is a quadratic non-residue
|
|
z = 1
|
|
while legendre(z, p) != -1:
|
|
z += 1
|
|
m, c, t, r = s, pow(z, q, p), pow(n, q, p), pow(n, (q + 1) // 2, p)
|
|
while True:
|
|
if t == 0:
|
|
return 0
|
|
elif t == 1:
|
|
return r
|
|
# Use repeated squaring to find the least i, 0 < i < M, such
|
|
# that t ** (2 ** i) = 1
|
|
t_sq = t
|
|
i = 0
|
|
for i in range(1, m):
|
|
t_sq = t_sq * t_sq % p
|
|
if t_sq == 1:
|
|
break
|
|
else:
|
|
raise ValueError("Should never get here")
|
|
# Let b = c ** (2 ** (m - i - 1))
|
|
b = pow(c, 2 ** (m - i - 1), p)
|
|
m = i
|
|
c = b * b % p
|
|
t = t * b * b % p
|
|
r = r * b % p
|
|
return r
|