def solve_congruence_equations(congruences): """ Return a quotient class that simultaneously solves the list of @p congruences; this is the Chinese Remainder Theorem. All representatives of the returned congruence have the remainders of @p congruences when taken modulo the respective moduli. The result is a congruence modulo the product of all moduli. Thus the function returns a number @f$ z \mod \prod_{i} m_i @f$ such that @f{align*}{ z &\equiv a_1 \mod m_1 \\ \vdots \\ z &\equiv a_k \mod m_k @f} @note The moduli @f$ m_i @f$ of all congruences must be relatively prime. @exception ValueError if @p congruences is empty. @param congruences An iterable of objects of QuotientClass over the Integers. Every pair of two different moduli must have a greatest common divisor (gcd()) of 1. @return An instance of rings.quotients.naive.QuotientRing over the rings.integers.naive.Integers solving the @p congruences. @see Robinson, D. J. S., "An Introduction to Abstract Algebra", p. 27 """ # The Chinese remainder theorem if not congruences: raise ValueError("cannot solve empty equation system") if __debug__: # This test is expensive; remove it in optimized execution pairs = [(c1, c2) for c1 in congruences for c2 in congruences if c1 != c2] pairwise_gcds = [gcd(c1.modulus(), c2.modulus()) for c1, c2 in pairs] assert set(pairwise_gcds) == set([1]), \ "the Chinese Remainder Theorem requires relatively prime moduli" common_modulus = reduce(mul, [c.modulus() for c in congruences]) common_representative = 0 for c in congruences: neutralizer = common_modulus // c.modulus() common_representative += c.remainder() * neutralizer \ * inverse_modulo(neutralizer, c.modulus()) quotient_ring = QuotientRing(Integers, common_modulus) return quotient_ring(common_representative)
def solve_congruence_equations( congruences ): """ Return a quotient class that simultaneously solves the list of @p congruences; this is the Chinese Remainder Theorem. All representatives of the returned congruence have the remainders of @p congruences when taken modulo the respective moduli. The result is a congruence modulo the product of all moduli. Thus the function returns a number @f$ z \mod \prod_{i} m_i @f$ such that @f{align*}{ z &\equiv a_1 \mod m_1 \\ \vdots \\ z &\equiv a_k \mod m_k @f} @note The moduli @f$ m_i @f$ of all congruences must be relatively prime. @exception ValueError if @p congruences is empty. @param congruences An iterable of objects of QuotientClass over the Integers. Every pair of two different moduli must have a greatest common divisor (gcd()) of 1. @return An instance of rings.quotients.naive.QuotientRing over the rings.integers.naive.Integers solving the @p congruences. @see Robinson, D. J. S., "An Introduction to Abstract Algebra", p. 27 """ # The Chinese remainder theorem if not congruences: raise ValueError( "cannot solve empty equation system" ) if __debug__: # This test is expensive; remove it in optimized execution pairs = [ (c1, c2) for c1 in congruences for c2 in congruences if c1 != c2 ] pairwise_gcds = [ gcd( c1.modulus(), c2.modulus() ) for c1, c2 in pairs ] assert set( pairwise_gcds ) == set([ 1 ]), \ "the Chinese Remainder Theorem requires relatively prime moduli" common_modulus = reduce( mul, [ c.modulus() for c in congruences ] ) common_representative = 0 for c in congruences: neutralizer = common_modulus // c.modulus() common_representative += c.remainder() * neutralizer \ * inverse_modulo( neutralizer, c.modulus() ) quotient_ring = QuotientRing( Integers, common_modulus ) return quotient_ring( common_representative )
def frobenius_trace_mod_2(curve): """ Compute the trace of the Frobenius endomorphism modulo 2. We cannot use the implicit torsion group representation of frobenius_trace_mod_l() in the case @f$ l=2 @f$ because the second division polynomial is @f$ y @f$, and multivariate polynomial arithmetic is unavailable. Implementing it for this single case would be overkill. Instead, we test whether there are any rational 2-torsion points. If so, then @f$ E[2] @f$ is a subgroup of the @p curve and its order divides the order of the curve (which is the number of rational points). Now, the number of rational points in @f$ E[2] @f$ can only be 2 or 4 in this case, so we know that the number of rational points is even. Hence, the Frobenius trace must then be 0 modulo 2. @return 0 if the number of points on the curve is even, 1 otherwise. The result is a congruence class modulo 2, that is, an element of @c QuotientRing( Integers, 2 ). """ R = Polynomials(curve.field()) x = R(0, 1) A, B = curve.parameters() defining_polynomial = x**3 + A * x + B rational_characteristic = x**curve.field().size() - x # gcd() has an arbitrary unit as leading coefficient; # relatively prime polynomials have a constant gcd. d = gcd(rational_characteristic, defining_polynomial) if d.degree() == 0: # The rational characteristic and the defining polynomial # are relatively prime: no rational point of order 2 exists # and the Frobenius trace must be odd. return QuotientRing(Integers, 2)(1) else: return QuotientRing(Integers, 2)(0)
def frobenius_trace_mod_2(curve): """ Compute the trace of the Frobenius endomorphism modulo 2. We cannot use the implicit torsion group representation of frobenius_trace_mod_l() in the case @f$ l=2 @f$ because the second division polynomial is @f$ y @f$, and multivariate polynomial arithmetic is unavailable. Implementing it for this single case would be overkill. Instead, we test whether there are any rational 2-torsion points. If so, then @f$ E[2] @f$ is a subgroup of the @p curve and its order divides the order of the curve (which is the number of rational points). Now, the number of rational points in @f$ E[2] @f$ can only be 2 or 4 in this case, so we know that the number of rational points is even. Hence, the Frobenius trace must then be 0 modulo 2. @return 0 if the number of points on the curve is even, 1 otherwise. The result is a congruence class modulo 2, that is, an element of @c QuotientRing( Integers, 2 ). """ R = Polynomials( curve.field() ) x = R(0, 1) A, B = curve.parameters() defining_polynomial = x**3 + A*x + B rational_characteristic = x**curve.field().size() - x # gcd() has an arbitrary unit as leading coefficient; # relatively prime polynomials have a constant gcd. d = gcd( rational_characteristic, defining_polynomial ) if d.degree() == 0: # The rational characteristic and the defining polynomial # are relatively prime: no rational point of order 2 exists # and the Frobenius trace must be odd. return QuotientRing( Integers, 2 )(1) else: return QuotientRing( Integers, 2 )(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)
def test_integer_gcd(self): """Integer GCD""" self.assert_(gcd(17, 25) == 1) self.assert_(gcd(24, 27) == 3)
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 )
def test_integer_gcd(self): """Integer GCD""" self.assert_( gcd( 17, 25 ) == 1 ) self.assert_( gcd( 24, 27 ) == 3 )