Path: blob/master/Public Key/RSA/hastad.sage
336 views
"""1Sage implementation of Hastad's broadcast attack for small public exponent and multiple message/ciphertext pairs2"""34import binascii5import random67def hastad(ciphertexts, moduli, e=3):8"""9Performs a Hastad's attack on non-padded ciphertexts10M = Message11ciphertexts = ciphertext array12moduli = moduli array13"""1415if not (len(moduli) == len(ciphertexts) == e):16raise RuntimeError("Moduli and ciphertext arrays have to be equal in length, and contain at least as many elements as e")1718M = crt(ciphertexts, moduli).nth_root(e)19return M2021def linear_padding(ciphertexts, moduli, pad_array, const_array=(), e=3, eps=1/8):22if not(len(ciphertexts) == len(moduli) == len(pad_array) == len(const_array) == e):23raise RuntimeError("Moduli and ciphertext arrays have to be equal in length, and contain at least as many elements as e")2425'''26Initialization with placeholders27ciphertexts: ciphertext array28T_array: Chinese Remainder Theorem coefficients29moduli: Modulus array30pad_array: Linear coefficient of padding applied to the message during encryption31const_array: constant pad added to message during encryption (optional)32'''33T_array = [Integer(0)]*e34crt_array = [Integer(0)]*e35polynomial_array = []3637for i in range(e):38crt_array = [0]*e39crt_array[i] = 140T_array[i] = Integer(crt(crt_array,moduli))4142G.<x> = PolynomialRing(Zmod(prod(moduli)))43for i in range(e):44polynomial_array += [T_array[i]*((pad_array[i]*x+const_array[i])^e - Integer(ciphertexts[i]))] #Representation of polynomial f(x) = (A*x + b) ^ e - C where (A*x + b) is the padding polynomial4546g = sum(polynomial_array).monic() #Creates a monic polynomial from the sum of the individual polynomials47roots = g.small_roots(epsilon=eps)48return roots[0] if len(roots) >= 1 else -1495051def convert_to_int(message):52return int(message.encode("hex"),16)5354def decode(message):55return message.decode("hex")5657""" Test / Proof of Correctness """5859def test_no_padding():60m = convert_to_int("hello")61e = 362bound = 2^102463ciphertexts = []64moduli = []6566for i in range(e):67p = random_prime(bound,proof=false)68q = random_prime(bound,proof=false)69n = p*q70c = Integer(pow(m, e, n))71moduli += [Integer(n)]72ciphertexts += [c]7374assert hastad(ciphertexts,moduli,e) == m75print("Success! The recovered message is equal to: " + hex(m)[2:].decode("hex"))7677return 07879def test_linear_padding():80moduli = []81ciphertexts = []82pad_array = []83const_array = []84e = 385pad_bound = 2^51286prime_bound = 2^102487m = convert_to_int("p00rth0_th3_p00r")8889for i in range(e):90pad = random.randint(0,pad_bound)91constant = random.randint(0,pad_bound)92pad_array += [pad]93const_array += [constant]94p = random_prime(prime_bound,proof=false)95q = random_prime(prime_bound,proof=false)96n = p*q97moduli += [n]98ciphertexts.append(pow(pad * m + constant,e,n))99100assert linear_padding(ciphertexts, moduli, pad_array, const_array) == m101print("Success!")102return 0103104105