def test_import_openssh(self): for key, passphrase in [ TEST_OPENSSH0, TEST_OPENSSH1, TEST_OPENSSH2, TEST_OPENSSH3 ]: if passphrase: with self.assertRaises(ValueError): DSA.import_key(key) dsa = DSA.import_key(key, passphrase=passphrase) self.assertEqual(dsa.y, pow(dsa.g, dsa.x, dsa.p)) self.assertLess(dsa.x, dsa.q) self.assertTrue(is_prime(dsa.p)) self.assertTrue(is_prime(dsa.q))
def test_import_openssh(self): for key, passphrase in [ TEST_OPENSSH0, TEST_OPENSSH1, TEST_OPENSSH2, TEST_OPENSSH3 ]: if passphrase: with self.assertRaises(ValueError): RSA.import_key(key) rsa = RSA.import_key(key, passphrase=passphrase) self.assertEqual(rsa.p * rsa.q, rsa.n) self.assertEqual(rsa.alt_d, mod_inv(rsa.e, (rsa.p - 1) * (rsa.q - 1))) self.assertTrue(is_prime(rsa.p)) self.assertTrue(is_prime(rsa.q))
def __init__(self, p: int, n: int = 1, reducing_poly: Polynomial = None): """ Parameters: p (int): Prime. n (int): Exponent. reducing_poly (Polynomial): Polynomial to reduce the `PolynomialRing`. """ from samson.math.algebra.rings.integer_ring import ZZ assert is_prime(p) self.p = p self.n = n self.internal_ring = ZZ / ZZ(p) if not reducing_poly: if n == 1: reducing_poly = Polynomial([0, 1], self.internal_ring) else: for c in itertools.product(range(p), repeat=n): poly = Polynomial((1, *c)[::-1], self.internal_ring) if poly.is_irreducible(): reducing_poly = poly break self.reducing_poly = reducing_poly poly_ring = self.reducing_poly.ring self.internal_field = poly_ring / poly_ring(reducing_poly)
def analyze(n: int) -> 'IntegerAnalysis': n_is_prime = is_prime(n) byte_aligned = not n % 8 is_safe_prime = is_sophie_germain_prime(n) prime_name = WELL_KNOWN_GROUPS.get(n) # Determine bit distribution bits = bin(n)[2:] bit_distribution = count_items(bits) percent_one = bit_distribution['1'] / len(bits) uniform_dist = abs(0.50 - percent_one) < 0.05 factor_mod = n - (1 if n_is_prime else 0) small_factors = factor(factor_mod, use_rho=False, use_siqs=False, use_smooth_p=False) smoothness_ratio = smoothness(factor_mod, factors=small_factors) return IntegerAnalysis(n=n, is_prime=n_is_prime, smoothness_ratio=smoothness_ratio, byte_aligned=byte_aligned, is_safe_prime=is_safe_prime, prime_name=prime_name, percent_one=percent_one, is_uniform=uniform_dist, small_factors=small_factors)
def check_full_period(self) -> bool: """ Checks whether the LCG will achieve a full period with its current parameters. Returns: bool: Whether or not it will acheive a full period. References: https://en.wikipedia.org/wiki/Linear_congruential_generator#Period_length """ # Technically, this achieves m-1 if is_prime(self.m) and self.c == 0 and is_primitive_root( self.a, self.m): return True # Maximially m/4 elif is_power_of_two(self.m) and self.c == 0: return False else: # 1. m and c are relatively prime relatively_prime = gcd(self.m, self.c) == 1 # 2. a-1 is divisible by all prime factors of m factors = [factor for factor in factorint(self.m)] divisible_by_all_factors = all([((self.a - 1) % factor) == 0 for factor in factors]) # 3. a-1 is divisible by 4 if m is divisible by 4 divisible_by_four = True if self.m % 4 == 0: divisible_by_four = (self.a - 1) % 4 == 0 return relatively_prime and divisible_by_all_factors and divisible_by_four
def generate_ntt_params(v1, v2): vec_len = len(v1) max_value = max(chain(v1, v2)) min_mod = max_value**2 * vec_len + 1 # Find a modulus for offset in count(max(1, min_mod + vec_len - 2)): modulus = offset * vec_len + 1 if is_prime(modulus): break totient = modulus - 1 # Find a generator factors = [f for f, _ in factor(totient).items()] for possible_gen in range(1, modulus): if pow(possible_gen, totient, modulus) == 1 and all( [pow(possible_gen, totient // f, modulus) != 1 for f in factors]): gen = possible_gen break # Find a primitive root root = pow(gen, totient // vec_len, modulus) return root, modulus
def __init__(self, hash_obj: object=SHA256(), p: int=None, q: int=None, g: int=None, x: int=None, L: int=2048, N: int=256): """ Parameters: hash_obj (object): Instantiated object with compatible hash interface. p (int): (Optional) Prime modulus. q (int): (Optional) Prime modulus. g (int): (Optional) Generator. x (int): (Optional) Private key. L (int): (Optional) Bit length of `p`. N (int): (Optional) Bit length of `q`. """ Primitive.__init__(self) # Parameter generation # https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf if not q: q = find_prime(N) # Start somewhere in 2**(L-1); ensure it's even i = Bytes.random((L-1) // 8).int() // 2 * 2 # Construct the base as an even multiple of `q` base = 2**(L-1) // (2*q) * 2 while not is_prime((base + i) * q + 1): i += 2 p = (base + i) * q + 1 assert (p-1) % q == 0 # Construct `g` while True: h = Bytes.random(N // 8).int() % (p-1) g = pow(h, (p-1) // q, p) if h > 1 and h < (p-1) and g > 1: break self.p = p self.q = q self.g = g self.x = x or random_int_between(1, self.q) self.y = pow(self.g, self.x, self.p) self.hash_obj = hash_obj
def invert_poly(f_poly: Polynomial, R_poly: Polynomial, p: int) -> Polynomial: """ Inverts a polynomial `f_poly` over `R_poly` in GF(p). Parameters: f_poly (Polynomial): Polynomial to be inverted. R_poly (Polynomial): Polynomial to be inverted _over_. p (int): Integer modulus. Returns: Polynomial: Inverted polynomial. """ power_of_two = is_power_of_two(p) if is_prime(p) or power_of_two: if power_of_two: Z_p = ZZ / ZZ(2) else: Z_p = ZZ / ZZ(p) f_poly_p = Polynomial([(idx, Z_p[coeff]) for idx, coeff in f_poly.coeffs], Z_p) R_poly_p = Polynomial([(idx, Z_p[coeff]) for idx, coeff in R_poly.coeffs], Z_p) inv_poly = mod_inv(f_poly_p, R_poly_p) inv_poly = Polynomial([(idx, ZZ[int(coeff)]) for idx, coeff in inv_poly.coeffs], ZZ) if power_of_two: for _ in range(int(math.log(p, 2))): inv_poly = (2 * inv_poly) - (f_poly * (inv_poly**2)) inv_poly = (inv_poly % R_poly).trunc(p) else: raise Exception( f"Polynomial not invertible in Z_{p}. NTRU: p and q must be prime or power of two." ) return inv_poly
def is_prime(self) -> list: return is_prime(self.val)