def compare(x, y_enc, l, pk): x_b = get_bits(x, l) x_enc = [] for b in x_b: x_enc.append(dgk.encrypt(b, pub)) x_enc = np.array(x_enc) one_enc = dgk.encrypt(1, pub) xxory = [] for i in range(l): if x_b[i] == 0: xxory.append(y_enc[i]) else: xxory.append( ((one_enc % pub['n']) * (mod_inverse(y_enc[i], pub['n']) % pub['n'])) % pub['n']) xxory = np.array(xxory) dela = np.random.randint(0, 2) s = 1 - 2 * dela s_enc = dgk.encrypt(s, pub) # precompute xor cubes xor3precomp = [1] * l i = l - 2 while (i >= 0): xor3precomp[i] = ((pow(xxory[i + 1], 3, pub['n']) % pub['n']) * (xor3precomp[i + 1] % pub['n'])) % pub['n'] i -= 1 # compute [c] c = [] for i in range(l): temp = ((s_enc % pub['n']) * (x_enc[i] % pub['n']) * (mod_inverse(y_enc[i], pub['n'])) % pub['n'] * (xor3precomp[i] % pub['n'])) % pub['n'] r = np.random.randint(1, pub['u']) r_dash = random.getrandbits(int(2.5 * pub['t'])) temp = (pow(temp, r, pub['n']) * pow(pub['h'], r_dash, pub['n'])) % pub['n'] c.append(temp) c = np.array(c) # shuffle c np.random.shuffle(c) N, _ = pk c1 = gm.encrypt(dela, pk) one = gm.encrypt(1, pk) c1_bit = list(c1)[0] one_bit = list(one)[0] ############################################################################################################## c2_bit = step2_B(c, pk) ############################################################################################################## return (((c1_bit % N * c2_bit % N) % N) * one_bit % N) % N
def __eq__(self, other): """Two points are equal if X/Z of both points are equal """ if self.a_24 != other.a_24 or self.mod != other.mod: return False return self.x_cord * mod_inverse(self.z_cord, self.mod) % self.mod ==\ other.x_cord * mod_inverse(other.z_cord, self.mod) % self.mod
def parameters(): # Initialize variables to 0 q = 0 p = 0 e = 0 # Generate 512 bit prime q q = safeprime() # Generate 512 bit prime p p = safeprime() # Calculate N and eulers number N = p * q euler = (p - 1) * (q - 1) # Calculate e while (gcd(e, euler) != 1): e = random.randrange(1, euler) # Solve linear congruence d = mod_inverse(e, euler) #d = modInv(e, euler) # Gen public key pair public_key = (N, e) # Gen private key pair private_key = (d, p, q) return (public_key, private_key)
def _help(m, prime_modulo_method, diff_method, expr_val): """ Helper function for _nthroot_mod_composite and polynomial_congruence. Parameters ========== m : positive integer prime_modulo_method : function to calculate the root of the congruence equation for the prime divisors of m diff_method : function to calculate derivative of expression at any given point expr_val : function to calculate value of the expression at any given point """ from sympy.ntheory.modular import crt f = factorint(m) dd = {} for p, e in f.items(): tot_roots = set() if e == 1: tot_roots.update(prime_modulo_method(p)) else: for root in prime_modulo_method(p): diff = diff_method(root, p) if diff != 0: ppow = p m_inv = mod_inverse(diff, p) for j in range(1, e): ppow *= p root = (root - expr_val(root, ppow) * m_inv) % ppow tot_roots.add(root) else: new_base = p roots_in_base = {root} while new_base < pow(p, e): new_base *= p new_roots = set() for k in roots_in_base: if expr_val(k, new_base) != 0: continue while k not in new_roots: new_roots.add(k) k = (k + (new_base // p)) % new_base roots_in_base = new_roots tot_roots = tot_roots | roots_in_base if tot_roots == set(): return [] dd[pow(p, e)] = tot_roots a = [] m = [] for x, y in dd.items(): m.append(x) a.append(list(y)) return sorted(set(crt(m, list(i))[0] for i in cartes(*a)))
def encrypt(m, pub): neg = False if(m < 0): m = -m neg = True r = random.getrandbits(int(2.5*pub['t'])) c = (pow(pub['g'], m, pub['n']) * pow(pub['h'], r, pub['n'])) % pub['n'] if(neg): c = mod_inverse(c, pub['n']) return c
def get_inverse(self, element): # Gets the inverse of an element in the ring using Geometric progression summands = self.get_summands(element) zero_deg_comp = self.get_zero_degree_component(summands) zero_deg_comp_inv = mod_inverse(zero_deg_comp, self.p) positive_deg_comp = sum(summands) - zero_deg_comp if not positive_deg_comp: return zero_deg_comp_inv inverse = zero_deg_comp_inv*sum((-zero_deg_comp_inv*positive_deg_comp)**i for i in range(self.p*len(summands[:-1]))) return self.coefs_mod_p(self.eliminate_exp_over_p(inverse))
def intt(self): """ Compute IFFT in finite feild. The algorithm is the same as NTT, but it need to change w to w^(-1) and multiply N^(-1) for each coefficient of polynomial. input: FFT(poly), primitive nth root of unity output: polynomial complexity: (N/2 log N) """ inv_w = mod_inverse(self.w, self.mod) inv_N = mod_inverse(self.N, self.mod) poly = self.ntt(self.fft_poly, inv_w) for i in range(0, self.N): poly[i] = poly[i] * inv_N % self.mod # if it is computed over Z[x]/<x^n+1>, it should multiply phi^(-1) if self.ideal: inv_phi = mod_inverse(self.phi, self.mod) poly = self.mulPhi(poly, inv_phi) return poly
def _discrete_log_pohlig_hellman(n, a, b, order=None): """ Pohlig-Hellman algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. In order to compute the discrete logarithm, the algorithm takes advantage of the factorization of the group order. It is more efficient when the group order factors into many small primes. Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_pohlig_hellman >>> _discrete_log_pohlig_hellman(251, 210, 71) 197 See Also ======== discrete_log References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ from .modular import crt a %= n b %= n if order is None: order = n_order(b, n) f = factorint(order) l = [0] * len(f) for i, (pi, ri) in enumerate(f.items()): for j in range(ri): gj = pow(b, l[i], n) aj = pow(a * mod_inverse(gj, n), order // pi ** (j + 1), n) bj = pow(b, order // pi, n) cj = discrete_log(n, aj, bj, pi, True) l[i] += cj * pi ** j d, _ = crt([pi ** ri for pi, ri in f.items()], l) return d
def _discrete_log_pohlig_hellman(n, a, b, order=None): """ Pohlig-Hellman algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. In order to compute the discrete logarithm, the algorithm takes advantage of the factorization of the group order. It is more efficient when the group order factors into many small primes. References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_pohlig_hellman >>> _discrete_log_pohlig_hellman(251, 210, 71) 197 See also ======== discrete_log """ from .modular import crt a %= n b %= n if order is None: order = n_order(b, n) f = factorint(order) l = [0] * len(f) for i, (pi, ri) in enumerate(f.items()): for j in range(ri): gj = pow(b, l[i], n) aj = pow(a * mod_inverse(gj, n), order // pi**(j + 1), n) bj = pow(b, order // pi, n) cj = discrete_log(n, aj, bj, pi, True) l[i] += cj * pi**j d, _ = crt([pi**ri for pi, ri in f.items()], l) return d
def quadratic_congruence(a, b, c, p): """ Find the solutions to ``a x**2 + b x + c = 0 mod p a : integer b : integer c : integer p : positive integer """ from sympy.polys.galoistools import linear_congruence a = as_int(a) b = as_int(b) c = as_int(c) p = as_int(p) a = a % p b = b % p c = c % p if a == 0: return linear_congruence(b, -c, p) if p == 2: roots = [] if c % 2 == 0: roots.append(0) if (a + b + c) % 2 == 0: roots.append(1) return roots if isprime(p): inv_a = mod_inverse(a, p) b *= inv_a c *= inv_a if b % 2 == 1: b = b + p d = ((b * b) // 4 - c) % p y = sqrt_mod(d, p, all_roots=True) res = set() for i in y: res.add((i - b // 2) % p) return sorted(res) y = sqrt_mod(b * b - 4 * a * c, 4 * a * p, all_roots=True) res = set() for i in y: root = linear_congruence(2 * a, i - b, 4 * a * p) for j in root: res.add(j % p) return sorted(res)
def test_Point(): from sympy.core.numbers import mod_inverse #The curve is of the form y**2 = x**3 + a*x**2 + x mod = 101 a = 10 a_24 = (a + 2)*mod_inverse(4, mod) p1 = Point(10, 17, a_24, mod) p2 = p1.double() assert p2 == Point(68, 56, a_24, mod) p4 = p2.double() assert p4 == Point(22, 64, a_24, mod) p8 = p4.double() assert p8 == Point(71, 95, a_24, mod) p16 = p8.double() assert p16 == Point(5, 16, a_24, mod) p32 = p16.double() assert p32 == Point(33, 96, a_24, mod) # p3 = p2 + p1 p3 = p2.add(p1, p1) assert p3 == Point(1, 61, a_24, mod) # p5 = p3 + p2 or p4 + p1 p5 = p3.add(p2, p1) assert p5 == Point(49, 90, a_24, mod) assert p5 == p4.add(p1, p3) # p6 = 2*p3 p6 = p3.double() assert p6 == Point(87, 43, a_24, mod) assert p6 == p4.add(p2, p2) # p7 = p5 + p2 p7 = p5.add(p2, p3) assert p7 == Point(69, 23, a_24, mod) assert p7 == p4.add(p3, p1) assert p7 == p6.add(p1, p5) # p9 = p5 + p4 p9 = p5.add(p4, p1) assert p9 == Point(56, 99, a_24, mod) assert p9 == p6.add(p3, p3) assert p9 == p7.add(p2, p5) assert p9 == p8.add(p1, p7) assert p5 == p1.mont_ladder(5) assert p9 == p1.mont_ladder(9) assert p16 == p1.mont_ladder(16) assert p9 == p3.mont_ladder(3)
def _inv_mod(M, m): r""" Returns the inverse of the matrix `K` (mod `m`), if it exists. Method to find the matrix inverse of `K` (mod `m`) implemented in this function: * Compute `\mathrm{adj}(K) = \mathrm{cof}(K)^t`, the adjoint matrix of `K`. * Compute `r = 1/\mathrm{det}(K) \pmod m`. * `K^{-1} = r\cdot \mathrm{adj}(K) \pmod m`. Examples ======== >>> from sympy import Matrix >>> A = Matrix(2, 2, [1, 2, 3, 4]) >>> A.inv_mod(5) Matrix([ [3, 1], [4, 2]]) >>> A.inv_mod(3) Matrix([ [1, 1], [0, 1]]) """ if not M.is_square: raise NonSquareMatrixError() N = M.cols det_K = M.det() det_inv = None try: det_inv = mod_inverse(det_K, m) except ValueError: raise NonInvertibleMatrixError('Matrix is not invertible (mod %d)' % m) K_adj = M.adjugate() K_inv = M.__class__( N, N, [det_inv * K_adj[i, j] % m for i in range(N) for j in range(N)]) return K_inv
def _discrete_log_shanks_steps(n, a, b, order=None): """ Baby-step giant-step algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. The algorithm is a time-memory trade-off of the method of exhaustive search. It uses `O(sqrt(m))` memory, where `m` is the group order. Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_shanks_steps >>> _discrete_log_shanks_steps(41, 15, 7) 3 See Also ======== discrete_log References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ a %= n b %= n if order is None: order = n_order(b, n) m = isqrt(order) + 1 T = dict() x = 1 for i in range(m): T[x] = i x = x * b % n z = mod_inverse(b, n) z = pow(z, m, n) x = a for i in range(m): if x in T: return i * m + T[x] x = x * z % n raise ValueError("Log does not exist")
def _discrete_log_shanks_steps(n, a, b, order=None): """ Baby-step giant-step algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. The algorithm is a time-memory trade-off of the method of exhaustive search. It uses `O(sqrt(m))` memory, where `m` is the group order. References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_shanks_steps >>> _discrete_log_shanks_steps(41, 15, 7) 3 See also ======== discrete_log """ a %= n b %= n if order is None: order = n_order(b, n) m = isqrt(order) + 1 T = dict() x = 1 for i in range(m): T[x] = i x = x * b % n z = mod_inverse(b, n) z = pow(z, m, n) x = a for i in range(m): if x in T: return i * m + T[x] x = x * z % n raise ValueError("Log does not exist")
def _nthroot_mod_composite(a, n, m): """ Find the solutions to ``x**n = a mod m`` when m is not prime. """ from sympy.ntheory.modular import crt f = factorint(m) dd = {} for p, e in f.items(): tot_roots = set() if e == 1: tot_roots.update(nthroot_mod(a, n, p, True) or []) else: for root in nthroot_mod(a, n, p, True) or []: rootn = pow(root, n) diff = (rootn // (root or 1) * n) % p if diff != 0: ppow = p for j in range(1, e): ppow *= p root = (root - (rootn - a) * mod_inverse(diff, p)) % ppow tot_roots.add(root) else: new_base = p roots_in_base = {root} while new_base < pow(p, e): new_base *= p new_roots = set() for k in roots_in_base: if (pow(k, n) - a) % (new_base) != 0: continue while k not in new_roots: new_roots.add(k) k = (k + (new_base // p)) % new_base roots_in_base = new_roots tot_roots = tot_roots | roots_in_base dd[pow(p, e)] = tot_roots a = [] m = [] for x, y in dd.items(): m.append(x) a.append(list(y)) return sorted(set(crt(m, list(i))[0] for i in cartes(*a)))
if pubkey.has_private(): print("The passed key is a private key") sys.exit(1) # Factorize the modulus (the most ridiculous part!) modulus = pubkey.n print("Factorizing (It takes years :( ) ") l = primefactors(modulus) print("Done :)") # Generate private key from the factors print("Generating the private key") prime1 = l[1] # prime1 > prime2 prime2 = l[0] public_exp = pubkey.e private_exp = mod_inverse(public_exp, (prime1-1)*(prime2-1)) # coef = Integer(prime2).invert(prime1) # print(f"modulus: {prime1 * prime2}") # print(f"publicExponent: {public_exp}"); # print(f"privateExponent: {private_exp}"); # print(f"prime1: {prime1}"); # print(f"prime2: {prime2}"); # print(f"coefficient: {coef}"); key_components = (pubkey.n, public_exp, private_exp, prime1, prime2) # , coef) prikey = RSA.construct(key_components) # Write the generated private key outfilename = f"{sys.argv[1]}.out.pem" print(f"Writing the private key to {outfilename}") with open(outfilename, 'wb') as f: f.write(prikey.export_key('PEM'))
def _initialize_first_polynomial(N, M, factor_base, idx_1000, idx_5000): """This step is the initialization of the 1st sieve polynomial. Here `a` is selected as a product of several primes of the factor_base such that `a` is about to ``sqrt(2*N) / M``. Other initial values of factor_base elem are also intialized which includes a_inv, b_ainv, soln1, soln2 which are used when the sieve polynomial is changed. The b_ainv is required for fast polynomial change as we don't have to calculate `2*b*mod_inverse(a, prime)` every time. We also ensure that the `factor_base` primes which make `a` are between 1000 and 5000. Parameters: =========== N : Number to be factored M : sieve interval factor_base : factor_base primes idx_1000 : index of prime numbe in the factor_base near 1000 idx_5000 : index of primenumber in the factor_base near to 5000 """ approx_val = sqrt(2 * N) / M # `a` is a parameter of the sieve polynomial and `q` is the prime factors of `a` # randomly search for a combination of primes whose multiplication is close to approx_val # This multiplication of primes will be `a` and the primes will be `q` # `best_a` denotes that `a` is close to approx_val in the random search of combination best_a, best_q, best_ratio = None, None, None start = 0 if idx_1000 is None else idx_1000 end = len(factor_base) - 1 if idx_5000 is None else idx_5000 for _ in range(50): a = 1 q = [] while (a < approx_val): rand_p = 0 while (rand_p == 0 or rand_p in q): rand_p = random.randint(start, end) p = factor_base[rand_p].prime a *= p q.append(rand_p) ratio = a / approx_val if best_ratio is None or abs(ratio - 1) < abs(best_ratio - 1): best_q = q best_a = a best_ratio = ratio a = best_a q = best_q B = [] for idx, val in enumerate(q): q_l = factor_base[val].prime gamma = factor_base[val].tmem_p * mod_inverse(a // q_l, q_l) % q_l if gamma > q_l / 2: gamma = q_l - gamma B.append(a // q_l * gamma) b = sum(B) g = SievePolynomial([a * a, 2 * a * b, b * b - N], a, b) for fb in factor_base: if a % fb.prime == 0: continue fb.a_inv = mod_inverse(a, fb.prime) fb.b_ainv = [2 * b_elem * fb.a_inv % fb.prime for b_elem in B] fb.soln1 = (fb.a_inv * (fb.tmem_p - b)) % fb.prime fb.soln2 = (fb.a_inv * (-fb.tmem_p - b)) % fb.prime return g, B
def _trial_division_stage(N, M, factor_base, sieve_array, sieve_poly, partial_relations, ERROR_TERM): """Trial division stage. Here we trial divide the values generetated by sieve_poly in the sieve interval and if it is a smooth number then it is stored in `smooth_relations`. Moreover, if we find two partial relations with same large prime then they are combined to form a smooth relation. First we iterate over sieve array and look for values which are greater than accumulated_val, as these values have a high chance of being smooth number. Then using these values we find smooth relations. In general, let ``t**2 = u*p modN`` and ``r**2 = v*p modN`` be two partial relations with the same large prime p. Then they can be combined ``(t*r/p)**2 = u*v modN`` to form a smooth relation. Parameters: =========== N : Number to be factored M : sieve interval factor_base : factor_base primes sieve_array : stores log_p values sieve_poly : polynomial from which we find smooth relations partial_relations : stores partial relations with one large prime ERROR_TERM : error term for accumulated_val """ sqrt_n = sqrt(float(N)) accumulated_val = log(M * sqrt_n) * 2**10 - ERROR_TERM smooth_relations = [] proper_factor = set() partial_relation_upper_bound = 128 * factor_base[-1].prime for idx, val in enumerate(sieve_array): if val < accumulated_val: continue x = idx - M v = sieve_poly.eval(x) vec, is_smooth = _check_smoothness(v, factor_base) if is_smooth is None: #Neither smooth nor partial continue u = sieve_poly.a * x + sieve_poly.b # Update the partial relation # If 2 partial relation with same large prime is found then generate smooth relation if is_smooth is False: #partial relation found large_prime = vec #Consider the large_primes under 128*F if large_prime > partial_relation_upper_bound: continue if large_prime not in partial_relations: partial_relations[large_prime] = (u, v) continue else: u_prev, v_prev = partial_relations[large_prime] partial_relations.pop(large_prime) try: large_prime_inv = mod_inverse(large_prime, N) except ValueError: #if large_prine divides N proper_factor.add(large_prime) continue u = u * u_prev * large_prime_inv v = v * v_prev // (large_prime * large_prime) vec, is_smooth = _check_smoothness(v, factor_base) #assert u*u % N == v % N smooth_relations.append((u, v, vec)) return smooth_relations, proper_factor
def dgk_compare_no_priv(): global config, data if not config['dgk_pub'] or config['dgk_priv']: print("Key inconsistency for DGK.") return Response("", status=404) if not data['compare_operand']: print("Comparison operand not set.") return Response("", status=404) pub = config['dgk_pub'] y_enc = request.json['y_enc'] l = len(y_enc) # get bits x_b = get_bits(data['compare_operand'], config['dgk_l']) # get encrypted bits x_enc = [] for b in x_b: x_enc.append(dgk.encrypt(b, pub)) x_enc = np.array(x_enc) # get encryption of 1 one_enc = dgk.encrypt(1, pub) # get [x xor y] xxory = [] for i in range(l): if x_b[i] == 0: xxory.append(y_enc[i]) else: xxory.append( ((one_enc % pub['n']) * (mod_inverse(y_enc[i], pub['n']) % pub['n'])) % pub['n']) xxory = np.array(xxory) dela = np.random.randint(0, 2) s = 1 - 2 * dela s_enc = dgk.encrypt(s, pub) # precompute xor cubes xor3precomp = [1] * l i = l - 2 while (i >= 0): xor3precomp[i] = ((pow(xxory[i + 1], 3, pub['n']) % pub['n']) * (xor3precomp[i + 1] % pub['n'])) % pub['n'] i -= 1 # compute [c] c = [] for i in range(l): temp = ((s_enc % pub['n']) * (x_enc[i] % pub['n']) * (mod_inverse(y_enc[i], pub['n'])) % pub['n'] * (xor3precomp[i] % pub['n'])) % pub['n'] r = np.random.randint(1, pub['u']) r_dash = random.getrandbits(int(2.5 * pub['t'])) temp = (pow(temp, r, pub['n']) * pow(pub['h'], r_dash, pub['n'])) % pub['n'] c.append(temp) # shuffle c random.shuffle(c) return jsonify(c, dela)
def private_key(p, q, e): return (p * q, mod_inverse(e, (p - 1) * (q - 1)))
def _discrete_log_pollard_rho(n, a, b, order=None, retries=10, rseed=None): """ Pollard's Rho algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. It is a randomized algorithm with the same expected running time as ``_discrete_log_shanks_steps``, but requires a negligible amount of memory. References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_pollard_rho >>> _discrete_log_pollard_rho(227, 3**7, 3) 7 See also ======== discrete_log """ a %= n b %= n if order is None: order = n_order(b, n) prng = Random() if rseed is not None: prng.seed(rseed) for i in range(retries): aa = prng.randint(1, order - 1) ba = prng.randint(1, order - 1) xa = pow(b, aa, n) * pow(a, ba, n) % n c = xa % 3 if c == 0: xb = a * xa % n ab = aa bb = (ba + 1) % order elif c == 1: xb = xa * xa % n ab = (aa + aa) % order bb = (ba + ba) % order else: xb = b * xa % n ab = (aa + 1) % order bb = ba for j in range(order): c = xa % 3 if c == 0: xa = a * xa % n ba = (ba + 1) % order elif c == 1: xa = xa * xa % n aa = (aa + aa) % order ba = (ba + ba) % order else: xa = b * xa % n aa = (aa + 1) % order c = xb % 3 if c == 0: xb = a * xb % n bb = (bb + 1) % order elif c == 1: xb = xb * xb % n ab = (ab + ab) % order bb = (bb + bb) % order else: xb = b * xb % n ab = (ab + 1) % order c = xb % 3 if c == 0: xb = a * xb % n bb = (bb + 1) % order elif c == 1: xb = xb * xb % n ab = (ab + ab) % order bb = (bb + bb) % order else: xb = b * xb % n ab = (ab + 1) % order if xa == xb: r = (ba - bb) % order if r != 0: return mod_inverse(r, order) * (ab - aa) % order break raise ValueError("Pollard's Rho failed to find logarithm")
def _ecm_one_factor(n, B1=10000, B2=100000, max_curve=200): """Returns one factor of n using Lenstra's 2 Stage Elliptic curve Factorization with Suyama's Parameterization. Here Montgomery arithmetic is used for fast computation of addition and doubling of points in elliptic curve. This ECM method considers elliptic curves in Montgomery form (E : b*y**2*z = x**3 + a*x**2*z + x*z**2) and involves elliptic curve operations (mod N), where the elements in Z are reduced (mod N). Since N is not a prime, E over FF(N) is not really an elliptic curve but we can still do point additions and doubling as if FF(N) was a field. Stage 1 : The basic algorithm involves taking a random point (P) on an elliptic curve in FF(N). The compute k*P using Montgomery ladder algorithm. Let q be an unknown factor of N. Then the order of the curve E, |E(FF(q))|, might be a smooth number that divides k. Then we have k = l * |E(FF(q))| for some l. For any point belonging to the curve E, |E(FF(q))|*P = O, hence k*P = l*|E(FF(q))|*P. Thus kP.z_cord = 0 (mod q), and the unknownn factor of N (q) can be recovered by taking gcd(kP.z_cord, N). Stage 2 : This is a continuation of Stage 1 if k*P != O. The idea utilize the fact that even if kP != 0, the value of k might miss just one large prime divisor of |E(FF(q))|. In this case we only need to compute the scalar multiplication by p to get p*k*P = O. Here a second bound B2 restrict the size of possible values of p. Parameters ========== n : Number to be Factored B1 : Stage 1 Bound B2 : Stage 2 Bound max_curve : Maximum number of curves generated References ========== .. [1] Carl Pomerance and Richard Crandall "Prime Numbers: A Computational Perspective" (2nd Ed.), page 344 """ n = as_int(n) if B1 % 2 != 0 or B2 % 2 != 0: raise ValueError("The Bounds should be an even integer") sieve.extend(B2) if isprime(n): return n from sympy.functions.elementary.miscellaneous import sqrt from sympy.polys.polytools import gcd curve = 0 D = int(sqrt(B2)) beta = [0] * (D + 1) S = [0] * (D + 1) k = 1 for p in sieve.primerange(1, B1 + 1): k *= pow(p, integer_log(B1, p)[0]) while (curve <= max_curve): curve += 1 #Suyama's Paramatrization sigma = rgen.randint(6, n - 1) u = (sigma * sigma - 5) % n v = (4 * sigma) % n diff = v - u u_3 = pow(u, 3, n) try: C = (pow(diff, 3, n) * (3 * u + v) * mod_inverse(4 * u_3 * v, n) - 2) % n except ValueError: #If the mod_inverse(4*u_3*v, n) doesn't exist return gcd(4 * u_3 * v, n) a24 = (C + 2) * mod_inverse(4, n) % n Q = Point(u_3, pow(v, 3, n), a24, n) Q = Q.mont_ladder(k) g = gcd(Q.z_cord, n) #Stage 1 factor if g != 1 and g != n: return g #Stage 1 failure. Q.z = 0, Try another curve elif g == n: continue #Stage 2 - Improved Standard Continuation S[1] = Q.double() S[2] = S[1].double() beta[1] = (S[1].x_cord * S[1].z_cord) % n beta[2] = (S[2].x_cord * S[2].z_cord) % n for d in range(3, D + 1): S[d] = S[d - 1].add(S[1], S[d - 2]) beta[d] = (S[d].x_cord * S[d].z_cord) % n g = 1 B = B1 - 1 T = Q.mont_ladder(B - 2 * D) R = Q.mont_ladder(B) for r in range(B, B2, 2 * D): alpha = (R.x_cord * R.z_cord) % n for q in sieve.primerange(r + 2, r + 2 * D + 1): delta = (q - r) // 2 f = (R.x_cord - S[d].x_cord)*(R.z_cord + S[d].z_cord) -\ alpha + beta[delta] g = (g * f) % n #Swap T, R = R, R.add(S[D], T) g = gcd(n, g) #Stage 2 Factor found if g != 1 and g != n: return g #ECM failed, Increase the bounds raise ValueError("Increase the bounds")
def keygen(k, t, l, save_dir, save_in_file=True, gen_dlut=False): # generate distinct primes vp and vq vp = gensafeprime.generate(t) while (1): vq = gensafeprime.generate(t) if vp != vq: break # generate u to be the prime just greater than 2^l+2 u = nextprime(pow(2, l + 2)) # generate prime p s.t. vp | p-1 and u | p-1 print("Generating p....") while (1): temp1 = 2 * u * vp sz = k // 2 - temp1.bit_length() prand = gensafeprime.generate(sz) p = temp1 * prand + 1 if isprime(p): break print("Generating q....") # generate prime q s.t. vq | q-1 and u | q-1 while (1): temp1 = 2 * u * vq sz = k // 2 - temp1.bit_length() qrand = gensafeprime.generate(sz) q = temp1 * qrand + 1 if isprime(q): break # calc n n = p * q # finding h partials_p = [2 * u * vp, 2 * u * prand, 2 * vp * prand, prand * vp * u] while (1): hrandp = random.randint(0, p - 1) if (hrandp == 1 or math.gcd(hrandp, p) != 1): continue f = False for prod in partials_p: f = f | (pow(hrandp, prod, p) == 1) if (f): break if (not f): break partials_q = [2 * u * vq, 2 * u * qrand, 2 * vq * qrand, qrand * vq * u] while (1): hrandq = random.randint(0, q - 1) if (hrandq == 1 or math.gcd(hrandq, q) != 1): continue f = False for prod in partials_q: f = f | (pow(hrandq, prod, q) == 1) if (f): break if (not f): break hrand = (hrandp * q * mod_inverse(q, p) + hrandq * p * mod_inverse(p, q)) % n h = pow(hrand, 2 * u * prand * qrand, n) #finding g partials_p = [2 * u * vp, 2 * u * prand, 2 * vp * prand, prand * vp * u] while (1): grandp = random.randint(0, p - 1) if (grandp == 1 or math.gcd(grandp, p) != 1): continue f = False for prod in partials_p: f = f | (pow(grandp, prod, p) == 1) # modp or modp-1 if (f): break if (not f): break partials_q = [2 * u * vq, 2 * u * qrand, 2 * vq * qrand, qrand * vq * u] while (1): grandq = random.randint(0, q - 1) if (grandq == 1 or math.gcd(grandq, q) != 1): continue f = False for prod in partials_q: f = f | (pow(grandq, prod, q) == 1) # modp or modp-1 if (f): break if (not f): break grand = (hrandp * q * mod_inverse(q, p) + hrandq * p * mod_inverse(p, q)) % n g = pow(grand, 2 * prand * qrand, n) priv, pub = {}, {} priv['p'], priv['q'], priv['vp'], priv['vq'] = p, q, \ vp, vq pub['n'], pub['g'], pub['h'], pub['u'], pub['t'] = n, g, \ h, u, t if (gen_dlut): print("Generating dlut....") priv['dlut'] = [] for i in range(pub['u']): if (i % 10000 == 0): print(i) priv['dlut'].append(pow(pub['g'], priv['vp'] * i, priv['p'])) priv['dlut'] = np.array(priv['dlut']) if (save_in_file): np.save(os.path.join(save_dir, "priv.npy"), priv) np.save(os.path.join(save_dir, "pub.npy"), pub) return priv, pub
def _discrete_log_pollard_rho(n, a, b, order=None, retries=10, rseed=None): """ Pollard's Rho algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. It is a randomized algorithm with the same expected running time as ``_discrete_log_shanks_steps``, but requires a negligible amount of memory. Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_pollard_rho >>> _discrete_log_pollard_rho(227, 3**7, 3) 7 See Also ======== discrete_log References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ a %= n b %= n if order is None: order = n_order(b, n) prng = Random() if rseed is not None: prng.seed(rseed) for i in range(retries): aa = prng.randint(1, order - 1) ba = prng.randint(1, order - 1) xa = pow(b, aa, n) * pow(a, ba, n) % n c = xa % 3 if c == 0: xb = a * xa % n ab = aa bb = (ba + 1) % order elif c == 1: xb = xa * xa % n ab = (aa + aa) % order bb = (ba + ba) % order else: xb = b * xa % n ab = (aa + 1) % order bb = ba for j in range(order): c = xa % 3 if c == 0: xa = a * xa % n ba = (ba + 1) % order elif c == 1: xa = xa * xa % n aa = (aa + aa) % order ba = (ba + ba) % order else: xa = b * xa % n aa = (aa + 1) % order c = xb % 3 if c == 0: xb = a * xb % n bb = (bb + 1) % order elif c == 1: xb = xb * xb % n ab = (ab + ab) % order bb = (bb + bb) % order else: xb = b * xb % n ab = (ab + 1) % order c = xb % 3 if c == 0: xb = a * xb % n bb = (bb + 1) % order elif c == 1: xb = xb * xb % n ab = (ab + ab) % order bb = (bb + bb) % order else: xb = b * xb % n ab = (ab + 1) % order if xa == xb: r = (ba - bb) % order try: e = mod_inverse(r, order) * (ab - aa) % order if (pow(b, e, n) - a) % n == 0: return e except ValueError: pass break raise ValueError("Pollard's Rho failed to find logarithm")
def deal_with_increment(self, i: int, inverse: bool = False): if not inverse: self.pos = (self.pos * i) % self.cards else: self.pos = (mod_inverse(i, self.cards) * self.pos) % self.cards
def test_mod_inverse(): assert mod_inverse(3, 11) == 4 assert mod_inverse(5, 11) == 9 assert mod_inverse(21124921, 521512) == 7713 assert mod_inverse(124215421, 5125) == 2981 assert mod_inverse(214, 12515) == 1579 assert mod_inverse(5823991, 3299) == 1442 assert mod_inverse(123, 44) == 39 assert mod_inverse(2, 5) == 3 assert mod_inverse(-2, 5) == -3 x = Symbol('x') assert S(2).invert(x) == S.Half raises(TypeError, lambda: mod_inverse(2, x)) raises(ValueError, lambda: mod_inverse(2, S.Half)) raises(ValueError, lambda: mod_inverse(2, cos(1)**2 + sin(1)**2))
def mod_inverse(n, k): return numbers.mod_inverse(k, n)
def compare(x, y, l): # get bits y_b = get_bits(y, l) # get encrypted bits y_enc = [] for b in y_b: y_enc.append(dgk.encrypt(b, pub)) y_enc = np.array(y_enc) # get bits x_b = get_bits(x, l) # get encrypted bits x_enc = [] for b in x_b: x_enc.append(dgk.encrypt(b, pub)) x_enc = np.array(x_enc) # get encryption of 1 one_enc = dgk.encrypt(1, pub) # get [x xor y] xxory = [] for i in range(l): if x_b[i] == 0: xxory.append(y_enc[i]) else: xxory.append( ((one_enc % pub['n']) * (mod_inverse(y_enc[i], pub['n']) % pub['n'])) % pub['n']) xxory = np.array(xxory) dela = np.random.randint(0, 2) s = 1 - 2 * dela s_enc = dgk.encrypt(s, pub) # precompute xor cubes xor3precomp = [1] * l i = l - 2 while (i >= 0): xor3precomp[i] = ((pow(xxory[i + 1], 3, pub['n']) % pub['n']) * (xor3precomp[i + 1] % pub['n'])) % pub['n'] i -= 1 # compute [c] c = [] for i in range(l): temp = ((s_enc % pub['n']) * (x_enc[i] % pub['n']) * (mod_inverse(y_enc[i], pub['n'])) % pub['n'] * (xor3precomp[i] % pub['n'])) % pub['n'] r = np.random.randint(1, pub['u']) r_dash = random.getrandbits(int(2.5 * pub['t'])) temp = (pow(temp, r, pub['n']) * pow(pub['h'], r_dash, pub['n'])) % pub['n'] c.append(temp) c = np.array(c) # shuffle c np.random.shuffle(c) #-----------------B------------------- delb = 0 for ci in c: ci_iszero = dgk.decrypt_iszero(ci, priv) if (ci_iszero): delb = 1 break #-----------------AB------------------- # how to use the values dela delb in an actual algo?? print("IS x <= y ? ", bool(dela ^ delb))
assert isprime(q) assert p.bit_length() == num_bits assert q.bit_length() == num_bits n = p * q z = (p - 1) * (q - 1) e = 65537 # specified encryption exponent import math assert math.gcd(e, z) == 1 # # RSA decryption/private factor # from sympy.core.numbers import mod_inverse d = mod_inverse(e, z) assert (e * d - 1) % z == 0 # # Extracting the integer underlying an arbitrary string # import sys # Using p, q, n, z as before m_str = 'Tøp Secrèt!' m_bytes = m_str.encode() m = int.from_bytes(m_bytes, byteorder=sys.byteorder, signed=False) assert m < n, 'Modulus is too small for message' # # RSA encryption and decryption #
nsquare_byte = private_key.p.to_bytes(256, 'little') privatekey_file.write(nsquare_byte) print('\nprivate key q') print(private_key.q) print(hex(private_key.q)) printhex(private_key.q) nsquare_byte = private_key.q.to_bytes(256, 'little') privatekey_file.write(nsquare_byte) print('\nprivate key lamda') lamda = lcm(private_key.p - 1, private_key.q - 1) lamda = int(lamda) print(lamda) print(hex(lamda)) printhex(lamda) nsquare_byte = lamda.to_bytes(256, 'little') privatekey_file.write(nsquare_byte) print('\nprivate key g_lamda_inv') g_lamda = (fastExpMod(public_key.g, lamda, public_key.nsquare) - 1) // public_key.n g_lamda_inv = mod_inverse(g_lamda, public_key.n) print(g_lamda_inv) print(hex(g_lamda_inv)) printhex(g_lamda_inv) nsquare_byte = g_lamda_inv.to_bytes(256, 'little') privatekey_file.write(nsquare_byte) #print(public_key.encrypt(value=3, r_value=3).ciphertext(False))
print("CT = ", CT) print("PT = ", PT) elif choice == 2: p, q = [int(x) for x in input("Enter values of p,q: ").split(' ')] if (sympy.isprime(p) and sympy.isprime(q)): print("p: ", p, "q : ", q) n = p * q phi_n = (p - 1) * (q - 1) e = int(input("\nEnter Value of e: ")) if (e > phi_n or e < 1): print("Value must be 1<e<", phi_n) elif (math.gcd(e, phi_n) != 1): print("GCD({},{})!=1".format(e, phi_n)) print("e and (p-1)(q-1) must be coprime") else: d = mod_inverse(e, phi_n) print("Public Key:({},{})".format(e, n)) print("Private Key:({},{})".format(d, n)) M = int(input("\nEnter Plaintext: ")) Y = (M**d) % n print("Signed Message (M,Y): ({},{}) ".format(M, Y)) Z = (Y**e) % n print("M:{} Z:{}".format(M, Z)) if (M == Z): print("Signature Valid") else: print("Signature Invalid") else: break """ OUTPUT