Example #1
0
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
Example #2
0
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 BI(self, a, j):
     verbose('BI')
     K = self.parent().coefficient_module().base_ring()
     p = K.prime()
     G = self.parent().S_arithgroup()
     N = G.Gpn.level
     scale = 1 / self.Tq_eigenvalue(p)
     N = p * self.parent().S_arithgroup().level
     x = ZZ['x'].gen()
     prec = K.precision_cap()
     ans = 0
     for q,_ in ZZ(N).factor():
         if q == p:
             continue
         lambda_q = self.Tq_eigenvalue(q)
         order = Zmod(p)(q).multiplicative_order()
         scale /= (lambda_q - lambda_q**(1-order) * ZZ(q)**(order * j))
         print 'scale = %s'%scale
         for m in range(order):
             new_ans = 0
             for b in range(N):
                 if (q**m * b - a) % p != 0:
                     continue
                 g, alpha0, beta = xgcd(b, -N)
                 if g != 1:
                     continue
                 symb = self.evaluate(matrix(ZZ,2,2,[b, N, beta, alpha0]))
                 new_ans += sum(ZZ(j).binomial(r) * b**(j-r) * N**r * symb.moment(r) for r in range(j+1))
             ans += lambda_q**(-m) * q**(m*j) * new_ans
     return scale * ans
Example #4
0
    def atkin_lehner_matrix(self, Q):
        r"""
        Return the matrix of the Atkin--Lehner--Li operator `W_Q` associated to
        an exact divisor `Q` of `N`, where `N` is the level of this group; that
        is, `gcd(Q, N/Q) = 1`.

        .. note::

            We follow the conventions of [AL1978]_ here, so `W_Q` is given by
            the action of any matrix of the form `\begin{pmatrix} Qx & y \\ Nz
            & Qw \end{pmatrix}` where `x,y,z,w` are integers such that `y = 1
            \bmod Q`, `x = 1 \bmod N/Q`, and `det(W_Q) = Q`. For convenience,
            we actually always choose `x = y = 1`.

        INPUT:

        - ``Q`` (integer): an integer dividing `N`, where `N` is the level of
          this group. If this divisor does not satisfy `gcd(Q, N/Q) = 1`, it
          will be replaced by the unique integer with this property having
          the same prime factors as `Q`.

        EXAMPLES::

            sage: Gamma1(994).atkin_lehner_matrix(71)
            [  71    1]
            [4970   71]
            sage: Gamma1(996).atkin_lehner_matrix(2)
            [   4    1]
            [-996 -248]
            sage: Gamma1(15).atkin_lehner_matrix(7)
            Traceback (most recent call last):
            ...
            ValueError: Q must divide the level
        """
        # normalise Q
        Q = ZZ(Q)
        N = self.level()
        if not Q.divides(N):
            raise ValueError("Q must divide the level")
        Q = N // N.prime_to_m_part(Q)

        _, z, w = xgcd(-N // Q, Q)
        # so w * Q - z*(N/Q) = 1
        return matrix(ZZ, 2, 2, [Q, 1, N * z, Q * w])
 def BI_old(self, a, j):
     G = self.parent().S_arithgroup()
     N = G.Gpn.level
     p = G.prime()
     scale = 1
     x = ZZ['x'].gen()
     for q,_ in ZZ(N).factor():
         if q != p:
             lambda_q = self.get_liftee().Tq_eigenvalue(q)
             scale /= (1 - ZZ(q)**j / lambda_q)
     ans = 0
     for alpha in range(N):
         if (alpha - a) % p != 0:
             continue
         g, alpha0, beta = xgcd(alpha, -N)
         if g != 1:
             continue
         symb = self.evaluate(matrix(ZZ,2,2,[alpha, beta, N, alpha0]))
         ans += -symb.evaluate_at_poly((alpha + N*(-x))**j)
     return scale * ans
Example #6
0
    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 [MvOV1996]_. 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))
Example #7
0
    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: [is_blum_prime(_) for _ in 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.")
Example #8
0
    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))
Example #9
0
    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: [is_blum_prime(_) for _ in 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.")