Path: blob/master/Public Key/RSA/coppersmith_short_pad.sage
336 views
import random1import binascii23def coppersmith_short_pad(C1, C2, N, e = 3, eps = 1/25):4P.<x, y> = PolynomialRing(Zmod(N))5P2.<y> = PolynomialRing(Zmod(N))67g1 = (x^e - C1).change_ring(P2)8g2 = ((x + y)^e - C2).change_ring(P2)910# Changes the base ring to Z_N[y] and finds resultant of g1 and g2 in x11res = g1.resultant(g2, variable=x)1213# coppersmith's small_roots only works over univariate polynomial rings, so we14# convert the resulting polynomial to its univariate form and take the coefficients modulo N15# Then we can call the sage's small_roots function and obtain the delta between m_1 and m_2.16# Play around with these parameters: (epsilon, beta, X)17roots = res.univariate_polynomial().change_ring(Zmod(N))\18.small_roots(epsilon=eps)1920return roots[0]2122def franklin_reiter(C1, C2, N, r, e=3):23P.<x> = PolynomialRing(Zmod(N))24equations = [x ^ e - C1, (x + r) ^ e - C2]25g1, g2 = equations26return -composite_gcd(g1,g2).coefficients()[0]272829# I should implement something to divide the resulting message by some power of 2^i30def recover_message(C1, C2, N, e = 3):31delta = coppersmith_short_pad(C1, C2, N)32recovered = franklin_reiter(C1, C2, N, delta)33return recovered3435def composite_gcd(g1,g2):36return g1.monic() if g2 == 0 else composite_gcd(g2, g1 % g2)3738# Takes a long time for larger values and smaller epsilon39def test():40N = random_prime(2^512, proof=False) * random_prime(2^512, proof=False)41e = 34243m = Integer(math.log(N, 2) // e^2)4445r1 = random.randint(1, pow(2, m))46r2 = random.randint(1, pow(2, m))4748M = int(binascii.hexlify(b"hello"), 16)49C1 = pow(pow(2, m) * M + r1, e, N)50C2 = pow(pow(2, m) * M + r2, e, N)5152# Using eps = 1/125 is slooooowww53print(coppersmith_short_pad(C1, C2, N, eps=1/200))54print(recover_message(C1, C2, N))5556if __name__ == "__main__":57test()585960