def test_curve(q,t,r,k,D,E): """ Description: Tests that E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: bool - true iff E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ bool = True bool = bool and (power_mod(q, k, r) == 1) #q^k -1 ==0 mod r bool = bool and (E.trace_of_frobenius() == t) bool = bool and (kronecker((t*t-4*q) * Integer(D).inverse_mod(q),q) == 1) bool = bool and (E.cardinality() == q+1-t) bool = bool and (E.cardinality() % r ==0) return bool
def find_element_of_order(k, r): """ Description: Finds a random element of order k in Z_r^* Input: k - integer such that r % k == 1 r - prime Output: h - element of order k in Z_r^* """ assert r % k == 1 h = 0 def order(h, k, p): bool = True g = h for i in range(1, k): bool = bool and g != 1 g = Mod(g * h, p) bool = bool and g == 1 return bool while not order(h, k, r): # expected number of iterations is k/euler_phi(k) h = power_mod(randint(2, r - 1), (r - 1) // k, r) return h
def galoisorbit(self): order = self.order mod, num = self.modulus, self.number prim = self.isprimitive #beware this **must** be a generator orbit = ( power_mod(num, k, mod) for k in xsrange(1, order) if gcd(k, order) == 1) # use xsrange not xrange return ( self._char_desc(num, prim=prim) for num in orbit )
def small_A_twist(E): """ Description: Finds a curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B Input: E - elliptic curve Output: E' - elliptic curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B """ a = E.ainvs()[3] q = E.base_field().order() a = power_mod(Integer(a), -1, q) if kronecker(a,q) == -1: b = 2 while kronecker(b,q) == 1: b += 1 a = a*b assert kronecker(a,q) == 1 d = Mod(a,q).sqrt() ainvs = [i for i in E.ainvs()] ainvs[3]*= d**2 ainvs[4] *= d**3 return EllipticCurve(E.base_field(), ainvs)
def find_element_of_order(k,r): """ Description: Finds a random element of order k in Z_r^* Input: k - integer such that r % k == 1 r - prime Output: h - element of order k in Z_r^* """ assert r % k == 1 h = 0 def order(h,k,p): bool = True g = h for i in range(1,k): bool = bool and g != 1 g = Mod(g * h, p) bool = bool and g == 1 return bool while not order(h,k,r): # expected number of iterations is k/euler_phi(k) h = power_mod(randint(2, r-1), (r-1)//k, r) return h
def small_B_twist(E): """ Description: Finds a curve isogenous to E that has small B in the curve equation y^2 = x^3 + A*x + B Input: E - elliptic curve Output: E' - elliptic curve isogenous to E that has small B in the curve equation y^2 = x^3 + A*x + B """ b = E.ainvs()[4] q = E.base_field().order() b = power_mod(Integer(b), -1, q) d = 0 s = Mod(1,q) bool = True while bool: try: d = (s*b) d = d.nth_root(3) d = Integer(d) bool = False except ValueError as e: s+=1 pass ainvs = [i for i in E.ainvs()] ainvs[3] *= d**2 ainvs[4] *= d**3 return EllipticCurve(E.base_field(), ainvs)
def test_curve(q, t, r, k, D, E): """ Description: Tests that E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: bool - true iff E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ bool = True bool = bool and (power_mod(q, k, r) == 1) #q^k -1 ==0 mod r bool = bool and (E.trace_of_frobenius() == t) bool = bool and (kronecker( (t * t - 4 * q) * Integer(D).inverse_mod(q), q) == 1) bool = bool and (E.cardinality() == q + 1 - t) bool = bool and (E.cardinality() % r == 0) return bool
def small_A_twist(E): """ Description: Finds a curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B Input: E - elliptic curve Output: E' - elliptic curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B """ a = E.ainvs()[3] q = E.base_field().order() a = power_mod(Integer(a), -1, q) if kronecker(a, q) == -1: b = 2 while kronecker(b, q) == 1: b += 1 a = a * b assert kronecker(a, q) == 1 d = Mod(a, q).sqrt() ainvs = [i for i in E.ainvs()] ainvs[3] *= d**2 ainvs[4] *= d**3 return EllipticCurve(E.base_field(), ainvs)
def small_B_twist(E): """ Description: Finds a curve isogenous to E that has small B in the curve equation y^2 = x^3 + A*x + B Input: E - elliptic curve Output: E' - elliptic curve isogenous to E that has small B in the curve equation y^2 = x^3 + A*x + B """ b = E.ainvs()[4] q = E.base_field().order() b = power_mod(Integer(b), -1, q) d = 0 s = Mod(1, q) bool = True while bool: try: d = (s * b) d = d.nth_root(3) d = Integer(d) bool = False except ValueError as e: s += 1 pass ainvs = [i for i in E.ainvs()] ainvs[3] *= d**2 ainvs[4] *= d**3 return EllipticCurve(E.base_field(), ainvs)
def encrypt_message(message, public_key): if isinstance(public_key, str): public_key = json_key(public_key) if not public_key: return None public_exponent, modulus = public_key cipher_text = " ".join([ str(sage_all.power_mod(ord(char), public_exponent, modulus)) for char in message ]) return cipher_text
def method(r, k, D, max_trials=10000, g=0): """ Description: Run the Cocks-Pinch method to find an elliptic curve Input: r - prime k - embedding degree, r % k == 1 D - (negative) fundamental discriminant where D is a square mod r max_trials - the number of integers q to test for primality in the CP method g - an element of order k in Z_r^* Output: (q,t) - tuple where q is a prime and t is chosen such that there exists an elliptic curve E over F_q with trace t, and r | q+1-t; if the algorithm fails to find (q,t), it will return (0,0) """ assert test_promise(r, k, D), 'Invalid inputs' if g != 0: assert power_mod(g, k, r) == 1, 'Invalid inputs' else: g = find_element_of_order(k, r) D = Integer(D) t = Integer(g) + 1 root_d = Integer(Mod(D, r).sqrt()) u = Integer(Mod((t - 2) * root_d.inverse_mod(r), r)) q = 1 j = Integer(0) i = Integer(0) count = 0 while (count < max_trials): q = Integer((t + i * r)**2 - D * (u + j * r)**2) if q % 4 == 0: q = q // 4 if utils.is_suitable_q(q): return (q, t + i * r) q = 1 if random() < 0.5: j += 1 else: i += 1 count += 1 return (0, 0) # no prime found, so end
def method(r,k,D,max_trials=10000, g=0): """ Description: Run the Cocks-Pinch method to find an elliptic curve Input: r - prime k - embedding degree, r % k == 1 D - (negative) fundamental discriminant where D is a square mod r max_trials - the number of integers q to test for primality in the CP method g - an element of order k in Z_r^* Output: (q,t) - tuple where q is a prime and t is chosen such that there exists an elliptic curve E over F_q with trace t, and r | q+1-t; if the algorithm fails to find (q,t), it will return (0,0) """ assert test_promise(r,k,D), 'Invalid inputs' if g != 0: assert power_mod(g,k,r) == 1, 'Invalid inputs' else: g = find_element_of_order(k,r) D = Integer(D) t = Integer(g) + 1 root_d = Integer(Mod(D, r).sqrt()) u = Integer(Mod((t-2)*root_d.inverse_mod(r) ,r)) q = 1 j = Integer(0) i = Integer(0) count = 0 while (count < max_trials): q = Integer( (t+i*r)**2 - D*(u + j*r)**2) if q % 4 ==0: q = q//4 if utils.is_suitable_q(q): return (q, t+i*r) q = 1 if random() < 0.5: j+=1 else: i+=1 count+=1 return (0, 0) # no prime found, so end
def decrypt_message(cipher_text, private_key): if isinstance(private_key, str): private_key = json_key(private_key) if not private_key: return None private_exponent, modulus = private_key block_num = [(int(block)) for block in cipher_text.split()] decrypted_num = "" for block in block_num: message = sage_all.power_mod(block, private_exponent, modulus) decrypted_num += " " + str(message) message = "".join([chr(int(num)) for num in decrypted_num.split()]) return message
def is_valid_curve(q, t, r, k, D): """ Description: Tests that (q,t,r,k,D) is a valid elliptic curve Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: bool - true iff there exists an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ if q == 0 or t == 0 or r == 0 or k == 0 or D == 0: return False if not is_prime(q): return False if not is_prime(r): return False if not fundamental_discriminant(D) == D: return False if D % 4 == 0: #check CM equation if not is_square(4 * (t * t - 4 * q) // D): return False if D % 4 == 1: if not is_square((t * t - 4 * q) // D): return False if not (q + 1 - t) % r == 0: #check r | #E(F_q) return False if not power_mod(q, k, r) == 1: #check embedding degree is k return False return True
def is_valid_curve(q,t,r,k,D): """ Description: Tests that (q,t,r,k,D) is a valid elliptic curve Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: bool - true iff there exists an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ if q == 0 or t == 0 or r == 0 or k == 0 or D == 0: return False if not is_prime(q): return False if not is_prime(r): return False if not fundamental_discriminant(D) == D: return False if D % 4 == 0: #check CM equation if not is_square(4*(t*t - 4*q)//D): return False if D % 4 == 1: if not is_square((t*t - 4*q)//D): return False if not (q+1-t) % r == 0: #check r | #E(F_q) return False if not power_mod(q,k,r) == 1: #check embedding degree is k return False return True
def make_curve(q,t,r,k,D,debug=False): """ Description: Finds the curve equation for the elliptic curve (q,t,r,k,D) using the Complex Multiplication method Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: E - elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ assert is_valid_curve(q,t,r,k,D), 'Invalid input. No curve exists.' # check inputs if debug: print('Tested input') poly = hilbert_class_polynomial(D) # compute hilbert class polynomial if debug: print('Computed Hilbert class polynomial') check = False j_inv = poly.any_root(GF(q)) # find j-invariant orig_curve = EllipticCurve(GF(q), j=j_inv) # make a curve E = orig_curve check = test_curve(q,t,r,k,D,E) # see if this is the right curve twist = False if not check: # not the right curve, use quadratic twist E = E.quadratic_twist() check = test_curve(q,t,r,k,D,E) if check: twist = True else: # twist didnt work => j = 0 or 1728 if j_inv == 0: # for j = 0, use sextic twists prim = primitive_root(q) i = 1 while t != E.trace_of_frobenius() and i < 6: E = orig_curve.sextic_twist(power_mod(prim,i,q)) i+=1 elif j_inv == 1728: # for j = 1728, use quartic twists prim = primitive_root(q) i = 1 while t != E.trace_of_frobenius() and i < 4: E = orig_curve.quartic_twist(power_mod(prim,i,q)) i+=1 else: # twist didnt work and j != 0, 1728. this should never happen, so write input to a file for debugging print('Error. Quadratic twist failed to find the correct curve with j != 0, 1728. Logging output to debug.txt') # this line should never be reached' f = open('debug.txt', 'w') f.write('Twist: ' + str(twist) + '\n') f.write('q: ' + str(q) + '\n') f.write('t: ' + str(t) + '\n') f.write('r: ' + str(r) + '\n') f.write('k: ' + str(k) + '\n') f.write('D: ' + str(D) + '\n') f.write('E: ' + str(E) + '\n') f.write('orig_curve: ' + str(orig_curve)) f.close() return False check = test_curve(q,t,r,k,D,E) twist = True if not check: # didnt find a curve. this should never happen, so write input to a file for debugging print('Error. Failed to find curve. Logging output to debug.txt') f = open('debug.txt', 'w') f.write('Twist: ' + str(twist) + '\n') f.write('q: ' + str(q) + '\n') f.write('t: ' + str(t) + '\n') f.write('r: ' + str(r) + '\n') f.write('k: ' + str(k) + '\n') f.write('D: ' + str(D) + '\n') f.write('E: ' + str(E) + '\n') f.write('orig_curve: ' + str(orig_curve)) f.close() return False return E
def gen_inv_n(self): temp = [] for n in self.n: temp.append(power_mod(n, -1, self.p - 1)) self.n = temp
def gen_inv_k(self): temp = [] for n in self.k: temp.append(power_mod(n, -1, self.p)) self.k = temp
def make_curve(q, t, r, k, D, debug=False): """ Description: Finds the curve equation for the elliptic curve (q,t,r,k,D) using the Complex Multiplication method Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: E - elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ assert is_valid_curve(q, t, r, k, D), 'Invalid input. No curve exists.' # check inputs if debug: print('Tested input') poly = hilbert_class_polynomial(D) # compute hilbert class polynomial if debug: print('Computed Hilbert class polynomial') check = False j_inv = poly.any_root(GF(q)) # find j-invariant orig_curve = EllipticCurve(GF(q), j=j_inv) # make a curve E = orig_curve check = test_curve(q, t, r, k, D, E) # see if this is the right curve twist = False if not check: # not the right curve, use quadratic twist E = E.quadratic_twist() check = test_curve(q, t, r, k, D, E) if check: twist = True else: # twist didnt work => j = 0 or 1728 if j_inv == 0: # for j = 0, use sextic twists prim = primitive_root(q) i = 1 while t != E.trace_of_frobenius() and i < 6: E = orig_curve.sextic_twist(power_mod(prim, i, q)) i += 1 elif j_inv == 1728: # for j = 1728, use quartic twists prim = primitive_root(q) i = 1 while t != E.trace_of_frobenius() and i < 4: E = orig_curve.quartic_twist(power_mod(prim, i, q)) i += 1 else: # twist didnt work and j != 0, 1728. this should never happen, so write input to a file for debugging print( 'Error. Quadratic twist failed to find the correct curve with j != 0, 1728. Logging output to debug.txt' ) # this line should never be reached' f = open('debug.txt', 'w') f.write('Twist: ' + str(twist) + '\n') f.write('q: ' + str(q) + '\n') f.write('t: ' + str(t) + '\n') f.write('r: ' + str(r) + '\n') f.write('k: ' + str(k) + '\n') f.write('D: ' + str(D) + '\n') f.write('E: ' + str(E) + '\n') f.write('orig_curve: ' + str(orig_curve)) f.close() return False check = test_curve(q, t, r, k, D, E) twist = True if not check: # didnt find a curve. this should never happen, so write input to a file for debugging print('Error. Failed to find curve. Logging output to debug.txt') f = open('debug.txt', 'w') f.write('Twist: ' + str(twist) + '\n') f.write('q: ' + str(q) + '\n') f.write('t: ' + str(t) + '\n') f.write('r: ' + str(r) + '\n') f.write('k: ' + str(k) + '\n') f.write('D: ' + str(D) + '\n') f.write('E: ' + str(E) + '\n') f.write('orig_curve: ' + str(orig_curve)) f.close() return False return E
def gen_inv_e(self): temp = [] for n in self.e: temp.append(power_mod(n, -1, self.p)) self.e = temp