def encode(cls, m): """Encode message m in the first coefficient of a form.""" D = cls.discriminant gap = cls.gap assert (m + 1) * gap <= isqrt(-D) / 2 # ensure M (and Z) will be reduced assert gap % 4 == 0 for i in range(0, gap, 4): a_0 = i + 3 b_0 = int(powmod(D, (a_0 + 1) // 4, a_0)) if (b_0**2 - D) % a_0 == 0: # NB: gcd(a_0,b_0)=1 because -D is prime a_m = m * gap + i + 3 b_m = int(powmod(D, (a_m + 1) // 4, a_m)) if (b_m**2 - D) % a_m == 0: # NB: gcd(a_m,b_m)=1 because -D is prime b_m = a_m - b_m if D % 2 != b_m % 2 else b_m c_m = (b_m**2 - D) // (4 * a_m) M = cls((a_m, b_m, c_m), check=False) b_0 = a_0 - b_0 if D % 2 != b_0 % 2 else b_0 c_0 = (b_0**2 - D) // (4 * a_0) Z = cls((a_0, b_0, c_0), check=False) return M, Z # NB: M and Z are reduced raise ValueError('message encoding failed, try larger gap')
def find_prime_root(l, blum=True, n=1): """Find smallest prime of bit length at least l satisfying given constraints. Default is to return Blum primes (primes p with p % 4 == 3). Also, a primitive root w is returned of prime order at least n (0 < w < p). """ if l <= 2: if not blum: p = 2 assert n == 1 w = 1 else: p = 3 n, w = 2, p - 1 elif n <= 2: p = gmpy2.next_prime(1 << l - 1) if blum: while p % 4 != 3: p = gmpy2.next_prime(p) p = int(p) w = p - 1 if n == 2 else 1 else: assert blum if not gmpy2.is_prime(n): n = gmpy2.next_prime(n) p = 1 + 2 * n * (3 + 2 * ((1 << l - 3) // n)) while not gmpy2.is_prime(p): p += 4 * n a = 2 while (w := gmpy2.powmod(a, (p - 1) // n, p)) == 1: a += 1 p, w = int(p), int(w)
def SchnorrGroup(p=None, q=None, g=None, l=None, n=None): """Create type for Schnorr group of odd prime order q. If q is not given, q will be the smallest n-bit prime, n>=2. If p is not given, p will be the least l-bit prime, l>n, such that q divides p-1. If l and/or n are not given, default bit lengths will be set (2<=n<l). """ n_l = ((160, 1024), (192, 1536), (224, 2048), (256, 3072), (384, 7680)) if p is None: if q is None: if n is None: if l is None: l = 2048 n = next((n for n, _ in n_l if _ >= l), 512) q = next_prime(1 << n-1) else: if n is None: n = q.bit_length() assert q%2 and is_prime(q) if l is None: l = next((l for _, l in n_l if _ >= n), 15360) # n-bit prime q w = (1 << l-2) // q + 1 # w*q >= 2^(l-2), so p = 2*w*q + 1 > 2^(l-1) p = 2*w*q + 1 while not is_prime(p): p += 2*q # 2^(l-1) < p < 2^l else: assert q is not None # if p is given, q must be given as well assert (p - 1) % q == 0 assert q%2 and is_prime(q) assert is_prime(p) if l is None: l = p.bit_length() if n is None: n = q.bit_length() assert l == p.bit_length() assert n == q.bit_length() p = int(p) q = int(q) if g is None: w = (p-1) // q i = 2 while True: g = powmod(i, w, p) if g != 1 and powmod(g, q, p) == 1: break i += 1 g = int(g) return _SchnorrGroup(p, q, g)
def sqrt(self, INV=False): a = self.value p = self.modulus if p == 2: return type(self)(a) if p & 3 == 3: if INV: p4 = (p * 3 - 5) >> 2 # a**p4 == a**(-1/2) == 1/sqrt(a) mod p else: p4 = (p + 1) >> 2 return type(self)(int(gmpy2.powmod(a, p4, p))) # 1 (mod 4) primes are covered using Cipolla-Lehmer's algorithm. # find b s.t. b^2 - 4*a is not a square b = 1 while gmpy2.legendre(b * b - 4 * a, p) != -1: b += 1 # compute u*X + v = X^{(p+1)/2} mod f, for f = X^2 - b*X + a u, v = 0, 1 e = (p + 1) >> 1 for i in range(e.bit_length() - 1, -1, -1): u2 = (u * u) % p u = ((u << 1) * v + b * u2) % p v = (v * v - a * u2) % p if (e >> i) & 1: u, v = (v + b * u) % p, (-a * u) % p if INV: return type(self)(v).reciprocal() return type(self)(v)
def test_basic(self): self.assertFalse(gmpy.is_prime(1)) self.assertTrue(gmpy.is_prime(2)) self.assertTrue(gmpy.is_prime(101)) self.assertFalse(gmpy.is_prime(561)) self.assertTrue(gmpy.is_prime(2**16 + 1)) self.assertFalse(gmpy.is_prime(41041)) self.assertEqual(gmpy.next_prime(1), 2) self.assertEqual(gmpy.next_prime(2), 3) self.assertEqual(gmpy.next_prime(256), 257) self.assertEqual(gmpy.powmod(3, 256, 257), 1) self.assertEqual(gmpy.invert(3, 257), 86) self.assertRaises(ZeroDivisionError, gmpy.invert, 2, 4) self.assertEqual(gmpy.legendre(0, 101), 0) self.assertEqual(gmpy.legendre(42, 101), -1) self.assertEqual(gmpy.legendre(54, 101), 1) self.assertTrue(gmpy.is_square(625)) self.assertFalse(gmpy.is_square(652)) self.assertEqual(gmpy.isqrt(0), 0) self.assertEqual(gmpy.isqrt(1225), 35) self.assertTrue(gmpy.iroot(0, 10)[1]) self.assertFalse(gmpy.iroot(1226, 2)[1]) self.assertEqual(gmpy.iroot(1226, 2)[0], 35) self.assertEqual(gmpy.iroot(3**10 + 42, 10)[0], 3)
def sqrt(self, INV=False): """Modular (inverse) square roots.""" a = self.value p = type(self).modulus if p == 2: return type(self)(a) if p & 3 == 3: if INV: q = (3 * p - 5) // 4 # a**q == a**(-1/2) == 1/sqrt(a) mod p else: q = (p + 1) // 4 return type(self)(int(gmpy2.powmod(a, q, p))) # 1 (mod 4) primes are covered using Cipolla-Lehmer's algorithm. # find b s.t. b^2 - 4*a is not a square (maybe cache this for p) b = 1 while gmpy2.legendre(b * b - 4 * a, p) != -1: b += 1 # compute u*X + v = X^{(p+1)/2} mod f, for f = X^2 - b*X + a u, v = 0, 1 e = (p + 1) // 2 for i in range(e.bit_length() - 1, -1, -1): u2 = (u * u) % p u = ((u << 1) * v + b * u2) % p v = (v * v - a * u2) % p if (e >> i) & 1: u, v = (v + b * u) % p, (-a * u) % p if INV: return type(self)(v)._reciprocal() else: return type(self)(v)
def find_prime_root(l, blum=True, n=1): """Find smallest prime of bit length l satisfying given constraints. Default is to return Blum primes (primes p with p % 4 == 3). Also, a primitive root w is returned of prime order at least n. """ if l == 1: assert not blum assert n == 1 p = 2 w = 1 elif n <= 2: n = 2 w = -1 p = gmpy2.next_prime(2**(l - 1)) if blum: while p % 4 != 3: p = gmpy2.next_prime(p) p = int(p) else: assert blum if not gmpy2.is_prime(n): n = int(gmpy2.next_prime(n)) p = 1 + n * (1 + (n**2) % 4 + 4 * ((2**(l - 2)) // n)) while not gmpy2.is_prime(p): p += 4 * n a = 1 w = 1 while w == 1: a += 1 w = gmpy2.powmod(a, (p - 1) // n, p) p, w = int(p), int(w) return p, n, w
def _sqrt(cls, a, INV=False): p = cls.modulus if a == 0: if INV: raise ZeroDivisionError('no inverse sqrt of 0') return a if p == 2: return a if p & 3 == 3: if INV: p4 = (p * 3 - 5) >> 2 # a**p4 == a**(-1/2) == 1/sqrt(a) mod p else: p4 = (p + 1) >> 2 return int(gmpy2.powmod(a, p4, p)) # 1 (mod 4) primes are covered using Cipolla-Lehmer's algorithm. # find b s.t. b^2 - 4*a is not a square b = 1 while gmpy2.legendre(b * b - 4 * a, p) != -1: b += 1 # compute u*X + v = X^{(p+1)/2} mod f, for f = X^2 - b*X + a u, v = 0, 1 e = (p + 1) >> 1 for i in range(e.bit_length() - 1, -1, -1): u2 = (u * u) % p u = ((u << 1) * v + b * u2) % p v = (v * v - a * u2) % p if (e >> i) & 1: u, v = (v + b * u) % p, (-a * u) % p if INV: v = cls._reciprocal(v) return v
def __pow__(self, other): """Exponentiation.""" if not isinstance(other, int): return NotImplemented return type(self)(int(gmpy2.powmod(self.value, other, self.modulus)))
def test_basic(self): self.assertFalse(gmpy.is_prime(1)) self.assertTrue(gmpy.is_prime(2)) self.assertTrue(gmpy.is_prime(101)) self.assertFalse(gmpy.is_prime(561)) self.assertTrue(gmpy.is_prime(2**16 + 1)) self.assertFalse(gmpy.is_prime(41041)) self.assertEqual(gmpy.next_prime(1), 2) self.assertEqual(gmpy.next_prime(2), 3) self.assertEqual(gmpy.next_prime(256), 257) self.assertEqual(gmpy.powmod(3, 256, 257), 1) self.assertEqual(gmpy.gcdext(3, 257), (1, 86, -1)) self.assertEqual(gmpy.gcdext(1234, 257), (1, -126, 605)) self.assertEqual(gmpy.gcdext(-1234 * 3, -257 * 3), (3, 126, -605)) def te_s_t(a, b): g, s, t = gmpy.gcdext(a, b) if abs(a) == abs(b): test_s = s == 0 elif b == 0 or abs(b) == 2 * g: test_s = s == bool(a > 0) - bool(a < 0) # sign of a else: test_s = abs(s) < abs(b) / (2 * g) if abs(a) == abs(b) or a == 0 or abs(a) == 2 * g: test_t = t == bool(b > 0) - bool(b < 0) # sign of b else: test_t = abs(t) < abs(a) / (2 * g) return g == a * s + b * t and test_s and test_t self.assertTrue( all((te_s_t(0, 0), te_s_t(0, -1), te_s_t(1, 0), te_s_t(-1, 1)))) self.assertTrue(te_s_t(-1234, 257)) self.assertTrue(te_s_t(-12537, -257)) self.assertTrue(te_s_t(-11 * 1234, -11 * 2567)) self.assertTrue(te_s_t(1234, -2 * 1234)) self.assertTrue(te_s_t(-2 * 12364, 12364)) # self.assertEqual(gmpy.invert(3, -1), 0) # pending gmpy2 issue if modulus is 1 or -1 self.assertEqual(gmpy.invert(3, 257), 86) self.assertRaises(ZeroDivisionError, gmpy.invert, 2, 0) self.assertRaises(ZeroDivisionError, gmpy.invert, 2, 4) self.assertEqual(gmpy.legendre(0, 101), 0) self.assertEqual(gmpy.legendre(42, 101), -1) self.assertEqual(gmpy.legendre(54, 101), 1) self.assertRaises(ValueError, gmpy.legendre, 1, 2) self.assertEqual(gmpy.jacobi(9, 99), 0) self.assertEqual(gmpy.jacobi(43, 99), -1) self.assertEqual(gmpy.jacobi(53, 99), 1) self.assertRaises(ValueError, gmpy.jacobi, 1, 20) self.assertEqual(gmpy.kronecker(0, 0), 0) self.assertEqual(gmpy.kronecker(-1, 0), 1) self.assertEqual(gmpy.kronecker(43, -98), -1) self.assertEqual(gmpy.kronecker(-53, -98), 1) self.assertEqual(gmpy.kronecker(-54, -98), 0) self.assertTrue(gmpy.is_square(625)) self.assertFalse(gmpy.is_square(652)) self.assertEqual(gmpy.isqrt(0), 0) self.assertEqual(gmpy.isqrt(1225), 35) self.assertTrue(gmpy.iroot(0, 10)[1]) self.assertFalse(gmpy.iroot(1226, 2)[1]) self.assertEqual(gmpy.iroot(1226, 2)[0], 35) self.assertEqual(gmpy.iroot(3**10 + 42, 10)[0], 3)
def __pow__(self, exponent): """Exponentiation.""" return type(self)(int( gmpy2.powmod(self.value, exponent, type(self).modulus)))