Ejemplo n.º 1
0
def naive_schoof_algorithm(p, A, B, output=sys.stdout):
    p, A, B = int(p), int(A), int(B)

    message = "Counting points on y^2 = x^3 + {A}x + {B} over GF<{p}>: "
    print(message.format(p=p, A=A, B=B), end="", file=output)
    output.flush()

    order = p + 1 - frobenius_trace(EllipticCurve(FiniteField(p), A, B))
    print(order, file=output)
    return order
Ejemplo n.º 2
0
def generate_test_suites(polynomialring_implementation, name_prefix):
    """
    Generate TestCase classes for the given ring of polynomials implementation
    and combine them to a TestSuite. This groups the tests by implementation
    and category (instead of category alone) and allows flexible addition
    and removal of implementations.
    """

    Z = Integers
    F = FiniteField(17)
    # Strictly speaking, we assume the coefficients to come from a field.
    # Most things, however, should work equally well over the ring of integers.
    R = polynomialring_implementation(Z)
    S = polynomialring_implementation(F)

    class ElementsTest(unittest.TestCase):
        """
        Test cases concerning the creation and comparison of polynomials
        """

        #- Creation ---------------------------------------------------------------

        def test_create(self):
            """Element creation"""
            self.assertIsNotNone(R(Z(0)))
            self.assertIsNotNone(S(F(0)))
            self.assertIsNotNone(R(Z(1), Z(2), Z(3), Z(4)))
            self.assertIsNotNone(S(F(1), F(2), F(3), F(4)))

        def test_create_casting(self):
            """Element creation casts integers into field elements"""
            self.assert_(R(Z(1)) == R(1))
            self.assert_(S(F(1)) == S(1))
            self.assert_(R(Z(7), Z(13)) == R(7, 13))
            self.assert_(S(F(7), F(13)) == S(7, 13))

        def test_create_uncastable(self):
            """Element creation raises TypeError if uncastable"""
            def f():
                return R(S(1))

            self.assertRaises(TypeError, f)

        def test_create_idempotent(self):
            """Element creation accepts elements of the same ring"""
            self.assert_(R(R(1)) == R(1))
            self.assert_(S(S(1)) == S(1))
            self.assert_(R(R(7, 13)) == R(7, 13))
            self.assert_(S(S(7, 13)) == S(7, 13))

        #- Equality ---------------------------------------------------------------
        def test_eq_true(self):
            """Equality: true statement"""
            self.assert_(R(0, 3) == R(0, 3))
            self.assert_(S(0, 3) == S(0, 3))

        def test_eq_false(self):
            """Equality: false statement"""
            self.failIf(R(0, 3) == R(2, 5))
            self.failIf(S(0, 3) == S(2, 5))

        def test_eq_ignore_leading_zeros(self):
            self.assert_(R(0) == R(0, 0, 0))
            self.assert_(S(0) == S(0, 0, 0))
            self.assert_(R(1, -1, 3) == R(1, -1, 3, 0, 0))
            self.assert_(S(1, -1, 3) == S(1, -1, 3, 17, 34, 0))

        def test_eq_casting_field_elements(self):
            """Equality: automatic casting of field elements on the right hand side"""
            self.assert_(R(3) == Z(3))
            self.assert_(S(3) == F(3))

        def test_eq_casting_integers(self):
            """Equality: automatic casting of integers on the right hand side"""
            self.assert_(R(1) == 1)
            self.assert_(S(1) == 1)

        def test_eq_casting_field_elements_reversed(self):
            """Equality: automatic casting of field elements on the left hand side"""
            self.assert_(Z(3) == R(3))
            self.assert_(F(3) == S(3))

        def test_eq_casting_integers_reversed(self):
            """Equality: automatic casting of integers on the left hand side"""
            self.assert_(1 == R(1))
            self.assert_(1 == S(1))

        def test_eq_uncastable(self):
            """Equality: uncastable resolves to false"""
            self.failIf(R(1) == S(1))

        #- Inequality -------------------------------------------------------------
        def test_ne_true(self):
            """Inequality: true statement"""
            self.failIf(R(0, 3) != R(0, 3))
            self.failIf(S(0, 3) != S(0, 3))

        def test_ne_false(self):
            """Inequality: false statement"""
            self.assert_(R(0, 3) != R(2, 5))
            self.assert_(S(0, 3) != S(2, 5))

        def test_ne_casting_field_elements(self):
            """Inequality: automatic casting of field elements on the right hand side"""
            self.assert_(R(1) != Z(2))
            self.assert_(S(1) != F(2))

        def test_ne_casting_integers(self):
            """Inequality: automatic casting of integers on the right hand side"""
            self.assert_(R(1) != 2)
            self.assert_(S(1) != 2)

        def test_ne_casting_field_elements_reversed(self):
            """Inequality: automatic casting of field elements on the left hand side"""
            self.assert_(Z(2) != R(1))
            self.assert_(F(2) != S(1))

        def test_ne_casting_integers_reversed(self):
            """Inequality: automatic casting of integers on the left hand side"""
            self.assert_(2 != R(1))
            self.assert_(2 != S(1))

        def test_ne_uncastable(self):
            """Inequality: uncastable resolves to false"""
            self.assert_(R(1) != S(1))

        #- Test for zero ----------------------------------------------------------
        def test_zero_true(self):
            """Test for zero: true"""
            self.failIf(R(0))
            self.failIf(S(0))

        def test_zero_false(self):
            """Test for zero: false"""
            self.assert_(R(42))
            self.assert_(S(42))
            self.assert_(R(0, 0, 7))
            self.assert_(S(0, 0, 7))

        #- Degree -----------------------------------------------------------------
        def test_degree_base(self):
            """Degree base case"""
            self.assert_(R(0, 3).degree() == 1)
            self.assert_(S(0, 3).degree() == 1)
            self.assert_(R(1, 2, 3, 4).degree() == 3)
            self.assert_(S(1, 2, 3, 4).degree() == 3)

        def test_degree_constant(self):
            """Degree of constant polynomials"""
            self.assert_(R(2).degree() == 0)
            self.assert_(S(2).degree() == 0)
            self.assert_(R(-1).degree() == 0)
            self.assert_(S(-1).degree() == 0)

        def test_degree_zero(self):
            """Degree of zero polynomial"""
            # TODO: Test for minus infinity
            pass

    class ArithmeticTest(unittest.TestCase):
        """Test cases for arithmetic operations on polynomials"""

        # These tests rely on working equality comparison and
        # not all elements being zero.

        #- Addition ---------------------------------------------------------------
        def test_add_base(self):
            """Addition base case"""
            self.assert_(R(1, 2, 3) + R(3, 2, 1) == R(4, 4, 4))
            self.assert_(S(1, 2, 3) + S(3, 2, 1) == S(4, 4, 4))

        def test_add_different_length(self):
            """Addition with different lengths"""
            self.assert_(R(1) + R(0, 2, 3) == R(1, 2, 3))
            self.assert_(S(1) + S(0, 2, 3) == S(1, 2, 3))

        def test_add_casting_field_elements(self):
            """Addition: automatic casting of field elements as right summand"""
            self.assert_(R(1, 2) + Z(2) == R(3, 2))
            self.assert_(S(1, 2) + F(2) == S(3, 2))

        def test_add_casting_integers(self):
            """Addition: automatic casting of integers as right summand"""
            self.assert_(R(1, 2) + 2 == R(3, 2))
            self.assert_(S(1, 2) + 2 == S(3, 2))

        def test_add_casting_field_elements_reversed(self):
            """Addition: automatic casting of field elements as left summand"""
            self.assert_(Z(2) + R(1, 2) == R(3, 2))
            self.assert_(F(2) + S(1, 2) == S(3, 2))

        def test_add_casting_integers_reversed(self):
            """Addition: automatic casting of integers as left summand"""
            self.assert_(2 + R(1, 2) == R(3, 2))
            self.assert_(2 + S(1, 2) == S(3, 2))

        def test_add_uncastable(self):
            """Addition: raise TypeError if uncastable"""
            def f():
                return R(1) + S(2)

            self.assertRaises(TypeError, f)

        #- Negation (unary minus) -------------------------------------------------
        def test_neg_base(self):
            """Negation (additive inverse) base case"""
            self.assert_(-R(-2, 3, 8) == R(2, -3, -8))
            self.assert_(-S(-2, 3, 8) == S(2, -3, -8))
            self.assert_(R(1, 3) + (-R(1, 3)) == R(0))
            self.assert_(S(1, 3) + (-S(1, 3)) == S(0))

        def test_neg_double(self):
            """Double negation"""
            self.assert_(-(-(R(17, 3, 9))) == R(17, 3, 9))
            self.assert_(-(-(S(17, 3, 9))) == S(17, 3, 9))

        #- Subtraction ------------------------------------------------------------
        def test_sub_base(self):
            """Subtraction base case"""
            self.assert_(R(8, 5, 3) - R(2, 17, 1) == R(6, -12, 2))
            self.assert_(S(8, 5, 3) - S(2, 17, 1) == S(6, -12, 2))

        def test_sub_wrap(self):
            """Subtraction with different lengths"""
            self.assert_(R(8) - R(2, 17, 1) == R(6, -17, -1))
            self.assert_(S(8) - S(2, 17, 1) == S(6, -17, -1))

        def test_sub_as_add(self):
            """Subtraction as addition of negative"""
            self.assert_(R(5, 4) + (-R(2)) == R(5, 4) - R(2))
            self.assert_(S(5, 4) + (-S(2)) == S(5, 4) - S(2))

        def test_sub_casting_field_elements(self):
            """Subtraction: automatic casting of field elements as subtrahend"""
            self.assert_(R(5, 2) - Z(2) == R(3, 2))
            self.assert_(S(5, 2) - F(2) == S(3, 2))

        def test_sub_casting_integers(self):
            """Subtraction: automatic casting of integers as subtrahend"""
            self.assert_(R(5, 2) - 2 == R(3, 2))
            self.assert_(S(5, 2) - 2 == S(3, 2))

        def test_sub_casting_field_elements_reversed(self):
            """Subtraction: automatic casting of field elements as minuend"""
            self.assert_(Z(2) - R(1, 2) == R(1, -2))
            self.assert_(F(2) - S(1, 2) == S(1, -2))

        def test_sub_casting_integers_reversed(self):
            """Subtraction: automatic casting of integers as minuend"""
            self.assert_(2 - R(1, 2) == R(1, -2))
            self.assert_(2 - S(1, 2) == S(1, -2))

        def test_sub_uncastable(self):
            """Subtraction: raise TypeError if uncastable"""
            def f():
                return R(1) - S(2)

            self.assertRaises(TypeError, f)

        #- Multiplication ---------------------------------------------------------
        def test_mul_base(self):
            """Multiplication base case"""
            self.assert_(R(3) * R(4, 0, 1) == R(12, 0, 3))
            self.assert_(S(3) * S(4, 0, 1) == S(12, 0, 3))
            self.assert_(R(0, 1) * R(4, 0, 1) == R(0, 4, 0, 1))
            self.assert_(S(0, 1) * S(4, 0, 1) == S(0, 4, 0, 1))

        def test_mul_zero(self):
            """Multiplication with zero"""
            self.assert_(R(0) * R(7, 3, 2) == R(0))
            self.assert_(S(0) * S(7, 3, 2) == S(0))

        def test_mul_casting_field_elements(self):
            """Multiplication: automatic casting of field elements as right factor"""
            self.assert_(R(1, 2) * Z(3) == R(3, 6))
            self.assert_(S(1, 2) * F(3) == S(3, 6))

        def test_mul_casting_integers(self):
            """Multiplication: automatic casting of integers as right factor"""
            self.assert_(R(1, 2) * 3 == R(3, 6))
            self.assert_(S(1, 2) * 3 == S(3, 6))

        def test_mul_casting_field_elements_reversed(self):
            """Multiplication: automatic casting of field elements as left factor"""
            self.assert_(Z(3) * R(1, 2) == R(3, 6))
            self.assert_(F(3) * S(1, 2) == S(3, 6))

        def test_mul_casting_integers_reversed(self):
            """Multiplication: automatic casting of integers as left factor"""
            self.assert_(3 * R(1, 2) == R(3, 6))
            self.assert_(3 * S(1, 2) == S(3, 6))

        def test_mul_uncastable(self):
            """Multiplication: raise TypeError if uncastable"""
            def f():
                return R(1) * S(2)

            self.assertRaises(TypeError, f)

        #- Division ---------------------------------------------------------------
        def test_divmod_base(self):
            """Division base case"""
            q, r = divmod(S(-1, 0, 1, 2, -1, 4), S(1, 0, 1))
            self.assert_(q == S(2, -2, -1, 4))
            self.assert_(r == S(-3, 2))

        def test_divmod_casting_field_elements(self):
            """Division: automatic casting of field elements as divisor"""
            q, r = divmod(S(3, 4), F(2))
            # Coefficients in S come from a field; division by units is always OK.
            self.assert_(q == S(10, 2))
            self.assert_(r == S(0))

        def test_divmod_casting_integers(self):
            """Division: automatic casting of integers as divisor"""
            q, r = divmod(S(3, 4), 2)
            # Coefficients in S come from a field; division by units is always OK.
            self.assert_(q == S(10, 2))
            self.assert_(r == S(0))

        def test_divmod_casting_field_elements_reversed(self):
            """Division: automatic casting of field elements as dividend"""
            q, r = divmod(F(3), S(1, 1))
            self.assert_(q == S(0))
            self.assert_(r == S(3))

        def test_divmod_casting_integers_reversed(self):
            """Division: automatic casting of integers as dividend"""
            q, r = divmod(3, S(1, 1))
            self.assert_(q == S(0))
            self.assert_(r == S(3))

        def test_floordiv_base(self):
            """Division rounded to floor"""
            q = S(-1, 0, 1, 2, -1, 4) // S(1, 0, 1)
            self.assert_(q == S(2, -2, -1, 4))

        def test_floordiv_casting_field_elements(self):
            """Division rounded to floor: automatic casting of field elements as divisor"""
            self.assert_(S(3, 4) // F(2) == S(10, 2))

        def test_floordiv_casting_integers(self):
            """Division rounded to floor: automatic casting of integers as divisor"""
            self.assert_(S(3, 4) // 2 == S(10, 2))

        def test_floordiv_casting_field_elements_reversed(self):
            """Division rounded to floor: automatic casting of field elements as dividend"""
            self.assert_(F(3) // S(1, 1) == S(0))

        def test_floordiv_casting_integers_reversed(self):
            """Division rounded to floor: automatic casting of integers as dividend"""
            self.assert_(3 // S(1, 1) == S(0))

        def test_mod_base(self):
            """Modulo operation: base case"""
            r = S(-1, 0, 1, 2, -1, 4) % S(1, 0, 1)
            self.assert_(r == S(-3, 2))

        def test_mod_casting_field_elements(self):
            """Modulo operation: automatic casting of field elements as divisor"""
            self.assert_(S(3, 4) % F(2) == S(0))

        def test_mod_casting_integers(self):
            """Modulo operation: automatic casting of integers as divisor"""
            self.assert_(S(3, 4) % 2 == S(0))

        def test_mod_casting_field_elements_reversed(self):
            """Modulo operation: automatic casting of field elements as modulus"""
            self.assert_(F(5) % S(1, 1) == S(5))

        def test_mod_casting_integers_reversed(self):
            """Modulo operation: automatic casting of integers as modulus"""
            self.assert_(5 % S(1, 1) == S(5))

        def test_mod_uncastable(self):
            """Divsion: raise TypeError if uncastable"""
            def f():
                return divmod(R(1), S(2))

            self.assertRaises(TypeError, f)

        #- Exponentiation ---------------------------------------------------------
        def test_pow_base(self):
            """Integer power base case"""
            self.assert_(R(1, 1)**2 == R(1, 2, 1))
            self.assert_(S(1, 1)**2 == S(1, 2, 1))

        def test_pow_non_casting(self):
            """Integer power: only integer exponents"""
            def f():
                return S(1, 1)**F(3)

            self.assertRaises(TypeError, f)

    suites = []
    for test_class in [ElementsTest, ArithmeticTest]:
        test_class.__name__ = "{0}_{1}".format(name_prefix,
                                               test_class.__name__)
        suites.append(unittest.TestLoader().loadTestsFromTestCase(test_class))
    return suites
Ejemplo n.º 3
0
 def _count_points(self, p, A, B):
     curve = EllipticCurve(FiniteField(p), A, B)
     trace = frobenius_trace_implementation(curve)
     return p + 1 - trace
Ejemplo n.º 4
0
def generate_test_suites(curve_implementation, infinity_implementation,
                         name_prefix):
    """
    Generate TestCase classes for the given implementations of elliptic curves
    and the point at infinity; combine them to TestSuites. This groups the tests
    by implementation and category (instead of category alone) and allows
    flexible addition and removal of implementations.
    """

    # Test the implementation for one small and one large field. Large
    # means that operands require more than 64 bit; the tenth Mersenne
    # prime will do as field size.
    F = FiniteField(23)
    G = FiniteField(2**89 - 1)

    # TODO: Add more test cases, especially larger ones
    E1 = curve_implementation(F, 1, 0)
    O = infinity_implementation()

    # TODO: Add test cases for point creation (on the curve or not)

    class PointsTest(unittest.TestCase):
        """
        Test cases for creating and comparing points on elliptic curves 
        """

        #- Equality ---------------------------------------------------------------

        def test_eq_true(self):
            """Equality: true statement"""
            self.assert_(E1(9, 5) == E1(9, 5))

        def test_eq_false(self):
            """Equality: false statement"""
            self.failIf(E1(9, 5) == E1(13, 5))

        #- Inequality -------------------------------------------------------------
        def test_neq_true(self):
            """Inequality: true statement"""
            self.failIf(E1(9, 5) != E1(9, 5))

        def test_neq_false(self):
            """Inequality: false statement"""
            self.assert_(E1(9, 5) != E1(13, 5))

        #- Finiteness -------------------------------------------------------------
        def test_infinite(self):
            """Test for infinity"""
            self.failIf(E1(9, 5).is_infinite())

    class GroupOperationTest(unittest.TestCase):
        """
        Test cases for the group operation on elliptic curves
        """

        #- Addition ---------------------------------------------------------------

        def test_add_base(self):
            """Addition base case"""
            self.assert_(E1(9, 5) + E1(13, 5) == E1(1, 18))

        def test_add_infinity(self):
            """Addition of neutral element (point at infinity)"""
            self.assert_(E1(11, 10) + O == E1(11, 10))

        def test_add_double(self):
            """Point duplication"""
            self.assert_(E1(11, 10) + E1(11, 10) == E1(13, 18))

        #- Additive inverse (unary minus) -----------------------------------------
        def test_neg_base(self):
            """Negation (additive inverse) base case"""
            self.assert_(-E1(9, 5) == E1(9, -5))
            self.assert_(E1(9, 5) + (-E1(9, 5)) == O)

        def test_neg_double(self):
            """Double negation"""
            self.assert_(-(-E1(9, 5)) == E1(9, 5))

        #- Subtraction ------------------------------------------------------------
        def test_sub_base(self):
            """Subtraction base case"""
            self.assert_(E1(9, 5) - E1(13, -5) == E1(1, 18))

        #- Multiplication with integers (repeated addition) -----------------------
        def test_mul_base(self):
            """Multiplication with integers (point as left factor) base case"""
            P = E1(11, 10)
            self.assert_(P * 2 == P + P)
            self.assert_(P * 5 == P + P + P + P + P)
            self.assert_(P * 6 == P + P + P + P + P + P)

        def test_mul_zero(self):
            """Multiplication with zero (point as left factor)"""
            self.assert_(E1(11, 10) * 0 == O)

        def test_rmul_base(self):
            """Multiplication with integers (point as right factor)"""
            P = E1(11, 10)
            self.assert_(2 * P == P + P)
            self.assert_(5 * P == P + P + P + P + P)
            self.assert_(6 * P == P + P + P + P + P + P)

        def test_rmul_zero(self):
            """Multiplication with zero (point as right factor)"""
            self.assert_(0 * E1(11, 10) == O)

    class PointAtInfinityTest(unittest.TestCase):
        """
        Test cases for the point at infinity
        """
        def test_eq(self):
            """Equality"""
            self.assert_(O == O)
            self.failIf(O == E1(9, 5))

        def test_neq(self):
            """Inequality"""
            self.failIf(O != O)
            self.assert_(O != E1(9, 5))

        def test_infinite(self):
            """Test for infinity"""
            self.assert_(O.is_infinite())

        def test_add(self):
            """Addition"""
            self.assert_(O + E1(11, 10) == E1(11, 10))
            self.assert_(O + O == O)

        def test_neg(self):
            """Negation (additive inverse)"""
            self.assert_(O == (-O))

        def test_mul(self):
            """Multiplication with integers"""
            self.assert_(O * 7 == O)
            self.assert_(7 * O == O)

    suites = []
    for test_class in [PointsTest, GroupOperationTest, PointAtInfinityTest]:
        test_class.__name__ = "{0}_{1}".format(name_prefix,
                                               test_class.__name__)
        suites.append(unittest.TestLoader().loadTestsFromTestCase(test_class))
    return suites
Ejemplo n.º 5
0
 def test_polynomial_gcd_relatively_prime(self):
     """GCD of relatively prime elements"""
     R = Polynomials(FiniteField(7))
     self.assert_(gcd(R(-1, 0, 1), R(0, 1)).degree() == 0)
Ejemplo n.º 6
0
 def test_polynomial_linear_combination(self):
     """Polynomial GCD as linear combination"""
     R = Polynomials(FiniteField(7))
     p, q = R(1, 3, 1, 2, 4), R(1, 0, 1, 1)
     x, y, d = eeuc(p, q)
     self.assert_(x * p + y * q == d)
Ejemplo n.º 7
0
 def test_polynomial_gcd(self):
     """Polynomial GCD"""
     # gcd( (x+1)^2, (x+1)(x-1) ) == (x+1)
     R = Polynomials(FiniteField(7))
     gcd = eeuc(R(1, 2, 1), R(-1, 0, 1))[2]  # Make monic
     self.assert_(gcd // gcd.leading_coefficient() == R(1, 1))