def gpol(g1, g2): """ Return G-Polynomial of ``g_1`` and ``g_2``. Let `a_i t_i` be `LT(g_i)`, `a = a_i*c_i + a_j*c_j` with `a = GCD(a_i,a_j)`, and `s_i = t/t_i` with `t = LCM(t_i,t_j)`. Then the G-Polynomial is defined as: `c_1s_1g_1 - c_2s_2g_2`. INPUT: - ``g1`` - polynomial - ``g2`` - polynomial EXAMPLE:: sage: from sage.rings.polynomial.toy_d_basis import gpol sage: P.<x, y, z> = PolynomialRing(IntegerRing(), 3, order='lex') sage: f = x^2 - 1 sage: g = 2*x*y - z sage: gpol(f,g) x^2*y - y """ a1, a2 = g1.lc(), g2.lc() a, c1, c2 = xgcd(a1, a2) t1, t2 = g1.lm(), g2.lm() t = t1.parent().monomial_lcm(t1, t2) s1, s2 = t // t1, t // t2 return c1 * s1 * g1 + c2 * s2 * g2
def gpol(g1,g2): """ Return G-Polynomial of ``g_1`` and ``g_2``. Let `a_i t_i` be `LT(g_i)`, `a = a_i*c_i + a_j*c_j` with `a = GCD(a_i,a_j)`, and `s_i = t/t_i` with `t = LCM(t_i,t_j)`. Then the G-Polynomial is defined as: `c_1s_1g_1 - c_2s_2g_2`. INPUT: - ``g1`` - polynomial - ``g2`` - polynomial EXAMPLE:: sage: from sage.rings.polynomial.toy_d_basis import gpol sage: P.<x, y, z> = PolynomialRing(IntegerRing(), 3, order='lex') sage: f = x^2 - 1 sage: g = 2*x*y - z sage: gpol(f,g) x^2*y - y """ a1,a2 = g1.lc(),g2.lc() a, c1, c2 = xgcd(a1,a2) t1,t2 = g1.lm(), g2.lm() t = t1.parent().monomial_lcm(t1,t2) s1,s2 = t//t1, t//t2 return c1*s1*g1 + c2*s2*g2
def bezout(q,m): r"""Returns :math:`u,v` such that :math:`uq+mv=1`. Parameters ---------- q,m : integer Two coprime integers with :math:`q > 0`. Returns ------- tuple of integers """ if q == 1: return (1,0) g,u,v = xgcd(q,-m) return (u,v)
def bezout(q, m): r"""Returns :math:`u,v` such that :math:`uq+mv=1`. Parameters ---------- q,m : integer Two coprime integers with :math:`q > 0`. Returns ------- tuple of integers """ if q == 1: return (1, 0) g, u, v = xgcd(q, -m) return (u, v)
def random_key(self, lbound, ubound, ntries=100): r""" Return a pair of random public and private keys. INPUT: - ``lbound`` -- positive integer; the lower bound on how small each random Blum prime `p` and `q` can be. So we have ``0 < lower_bound <= p, q <= upper_bound``. The lower bound must be distinct from the upper bound. - ``ubound`` -- positive integer; the upper bound on how large each random Blum prime `p` and `q` can be. So we have ``0 < lower_bound <= p, q <= upper_bound``. The lower bound must be distinct from the upper bound. - ``ntries`` -- (default: ``100``) the number of attempts to generate a random public/private key pair. If ``ntries`` is a positive integer, then perform that many attempts at generating a random public/private key pair. OUTPUT: - A random public key and its corresponding private key. Each randomly chosen `p` and `q` are guaranteed to be Blum primes. The public key is `n = pq`, and the private key is `(p, q, a, b)` where `\gcd(p, q) = ap + bq = 1`. ALGORITHM: The key generation algorithm is described in Algorithm 8.55, page 308 of [MenezesEtAl1996]_. The algorithm works as follows: #. Let `p` and `q` be distinct large random primes, each congruent to 3 modulo 4. That is, `p` and `q` are Blum primes. #. Let `n = pq` be the product of `p` and `q`. #. Use the extended Euclidean algorithm to compute integers `a` and `b` such that `\gcd(p, q) = ap + bq = 1`. #. The public key is `n` and the corresponding private key is `(p, q, a, b)`. .. NOTE:: Beware that there might not be any primes between the lower and upper bounds. So make sure that these two bounds are "sufficiently" far apart from each other for there to be primes congruent to 3 modulo 4. In particular, there should be at least two distinct primes within these bounds, each prime being congruent to 3 modulo 4. EXAMPLES: Choosing a random pair of public and private keys. We then test to see if they satisfy the requirements of the Blum-Goldwasser scheme:: sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import is_blum_prime sage: bg = BlumGoldwasser() sage: pubkey, prikey = bg.random_key(10**4, 10**5) sage: p, q, a, b = prikey sage: is_blum_prime(p); is_blum_prime(q) True True sage: p == q False sage: pubkey == p*q True sage: gcd(p, q) == a*p + b*q == 1 True TESTS: Make sure that there is at least one Blum prime between the lower and upper bounds. In the following example, we have ``lbound=24`` and ``ubound=30`` with 29 being the only prime within those bounds. But 29 is not a Blum prime. :: sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: bg = BlumGoldwasser() sage: pubkey, privkey = bg.random_key(24, 30) Traceback (most recent call last): ... ValueError: No Blum primes within the specified closed interval. """ # choosing distinct random Blum primes p = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries) q = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries) while p == q: q = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries) # compute the public key n = p * q # compute the private key; here gcd(p, q) = 1 = a*p + b*q bezout = xgcd(p, q) a = bezout[1] b = bezout[2] return (n, (p, q, a, b))
def private_key(self, p, q): r""" Return the Blum-Goldwasser private key corresponding to the distinct Blum primes ``p`` and ``q``. INPUT: - ``p`` -- a Blum prime. - ``q`` -- a Blum prime. OUTPUT: - The Blum-Goldwasser private key `(p, q, a, b)` where `\gcd(p, q) = ap + bq = 1`. Both ``p`` and ``q`` must be distinct Blum primes. Let `p` be a positive prime. Then `p` is a Blum prime if `p` is congruent to 3 modulo 4, i.e. `p \equiv 3 \pmod{4}`. EXAMPLES: Obtain two distinct Blum primes and compute the Blum-Goldwasser private key corresponding to those two Blum primes:: sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: from sage.crypto.util import is_blum_prime sage: bg = BlumGoldwasser() sage: P = primes_first_n(10); P [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] sage: map(is_blum_prime, P) [False, True, False, True, True, False, False, True, True, False] sage: bg.private_key(19, 23) (19, 23, -6, 5) Choose two distinct random Blum primes, compute the Blum-Goldwasser private key corresponding to those two primes, and test that the resulting private key `(p, q, a, b)` satisfies `\gcd(p, q) = ap + bq = 1`:: sage: from sage.crypto.util import random_blum_prime sage: p = random_blum_prime(10**4, 10**5) sage: q = random_blum_prime(10**4, 10**5) sage: while q == p: ... q = random_blum_prime(10**4, 10**5) ... sage: p, q, a, b = bg.private_key(p, q) sage: gcd(p, q) == a*p + b*q == 1 True TESTS: Both of the input ``p`` and ``q`` must be distinct Blum primes. :: sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser sage: bg = BlumGoldwasser() sage: bg.private_key(78307, 78307) Traceback (most recent call last): ... ValueError: p and q must be distinct Blum primes. sage: bg.private_key(7, 4) Traceback (most recent call last): ... ValueError: p and q must be distinct Blum primes. """ if p == q: raise ValueError("p and q must be distinct Blum primes.") if is_blum_prime(p) and is_blum_prime(q): # here gcd(p, q) = ap + bq = 1 bezout = xgcd(p, q) a = bezout[1] b = bezout[2] return (p, q, a, b) else: raise ValueError("p and q must be distinct Blum primes.")