Dense univariate polynomials over , implemented using NTL#
This implementation is generally slower than the FLINT implementation in
polynomial_zmod_flint
, so we use FLINT by
default when the modulus is small enough; but NTL does not require that int
-sized, so we use it as default when
Note that the classes Polynomial_dense_modn_ntl_zz
and
Polynomial_dense_modn_ntl_ZZ
are different; the former is limited to
moduli less than a certain bound, while the latter supports arbitrarily large
moduli.
AUTHORS:
Robert Bradshaw: Split off from polynomial_element_generic.py (2007-09)
Robert Bradshaw: Major rewrite to use NTL directly (2007-09)
- class sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_mod_n#
Bases:
Polynomial
A dense polynomial over the integers modulo n, where n is composite, with the underlying arithmetic done using NTL.
EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(16), implementation='NTL') sage: f = x^3 - x + 17 sage: f^2 x^6 + 14*x^4 + 2*x^3 + x^2 + 14*x + 1 sage: loads(f.dumps()) == f True sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') sage: p = 3*x sage: q = 7*x sage: p + q 10*x sage: R.<x> = PolynomialRing(Integers(8), implementation='NTL') sage: parent(p) Univariate Polynomial Ring in x over Ring of integers modulo 100 (using NTL) sage: p + q 10*x sage: R({10:-1}) 7*x^10
R.<x> = PolynomialRing(Integers(16), implementation='NTL') f = x^3 - x + 17 f^2 loads(f.dumps()) == f R.<x> = PolynomialRing(Integers(100), implementation='NTL') p = 3*x q = 7*x p + q R.<x> = PolynomialRing(Integers(8), implementation='NTL') parent(p) p + q R({10:-1})
- degree(gen=None)#
Return the degree of this polynomial.
The zero polynomial has degree -1.
EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') sage: (x^3 + 3*x - 17).degree() 3 sage: R.zero().degree() -1
R.<x> = PolynomialRing(Integers(100), implementation='NTL') (x^3 + 3*x - 17).degree() R.zero().degree()
- int_list()#
- list(copy=True)#
Return a new copy of the list of the underlying elements of
self
.EXAMPLES:
sage: _.<x> = PolynomialRing(Integers(100), implementation='NTL') sage: f = x^3 + 3*x - 17 sage: f.list() [83, 3, 0, 1]
_.<x> = PolynomialRing(Integers(100), implementation='NTL') f = x^3 + 3*x - 17 f.list()
- minpoly_mod(other)#
Compute the minimal polynomial of this polynomial modulo another polynomial in the same ring.
ALGORITHM:
NTL’s
MinPolyMod()
, which uses Shoup’s algorithm [Sho1999].EXAMPLES:
sage: R.<x> = PolynomialRing(GF(101), implementation='NTL') sage: f = x^17 + x^2 - 1 sage: (x^2).minpoly_mod(f) x^17 + 100*x^2 + 2*x + 100
R.<x> = PolynomialRing(GF(101), implementation='NTL') f = x^17 + x^2 - 1 (x^2).minpoly_mod(f)
- ntl_ZZ_pX()#
Return underlying NTL representation of this polynomial. Additional ‘’bonus’’ functionality is available through this function.
Warning
You must call
ntl.set_modulus(ntl.ZZ(n))
before doing arithmetic with this object!
- ntl_set_directly(v)#
Set the value of this polynomial directly from a vector or string.
Polynomials over the integers modulo n are stored internally using NTL’s
ZZ_pX
class. Use this function to set the value of this polynomial using the NTL constructor, which is potentially very fast. The input v is either a vector of ints or a string of the form[ n1 n2 n3 ... ]
where the ni are integers and there are no commas between them. The optimal input format is the string format, since that’s what NTL uses by default.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') sage: from sage.rings.polynomial.polynomial_modn_dense_ntl import Polynomial_dense_mod_n as poly_modn_dense sage: poly_modn_dense(R, ([1,-2,3])) 3*x^2 + 98*x + 1 sage: f = poly_modn_dense(R, 0) sage: f.ntl_set_directly([1,-2,3]) sage: f 3*x^2 + 98*x + 1 sage: f.ntl_set_directly('[1 -2 3 4]') sage: f 4*x^3 + 3*x^2 + 98*x + 1
R.<x> = PolynomialRing(Integers(100), implementation='NTL') from sage.rings.polynomial.polynomial_modn_dense_ntl import Polynomial_dense_mod_n as poly_modn_dense poly_modn_dense(R, ([1,-2,3])) f = poly_modn_dense(R, 0) f.ntl_set_directly([1,-2,3]) f f.ntl_set_directly('[1 -2 3 4]') f
- quo_rem(right)#
Return a tuple
(quotient, remainder)
whereself = quotient*other + remainder
.
- shift(n)#
Return this polynomial multiplied by the power
. If is negative, terms below will be discarded. Does not change this polynomial.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(12345678901234567890), implementation='NTL') sage: p = x^2 + 2*x + 4 sage: p.shift(0) x^2 + 2*x + 4 sage: p.shift(-1) x + 2 sage: p.shift(-5) 0 sage: p.shift(2) x^4 + 2*x^3 + 4*x^2
R.<x> = PolynomialRing(Integers(12345678901234567890), implementation='NTL') p = x^2 + 2*x + 4 p.shift(0) p.shift(-1) p.shift(-5) p.shift(2)
AUTHOR:
David Harvey (2006-08-06)
- small_roots(*args, **kwds)#
See
sage.rings.polynomial.polynomial_modn_dense_ntl.small_roots()
for the documentation of this function.EXAMPLES:
sage: N = 10001 sage: K = Zmod(10001) sage: P.<x> = PolynomialRing(K, implementation='NTL') sage: f = x^3 + 10*x^2 + 5000*x - 222 sage: f.small_roots() [4]
N = 10001 K = Zmod(10001) P.<x> = PolynomialRing(K, implementation='NTL') f = x^3 + 10*x^2 + 5000*x - 222 f.small_roots()
- class sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_mod_p#
Bases:
Polynomial_dense_mod_n
A dense polynomial over the integers modulo
, where is prime.- discriminant()#
EXAMPLES:
sage: _.<x> = PolynomialRing(GF(19), implementation='NTL') sage: f = x^3 + 3*x - 17 sage: f.discriminant() 12
_.<x> = PolynomialRing(GF(19), implementation='NTL') f = x^3 + 3*x - 17 f.discriminant()
- gcd(right)#
Return the greatest common divisor of this polynomial and
other
, as a monic polynomial.INPUT:
other
– a polynomial defined over the same ring asself
EXAMPLES:
sage: R.<x> = PolynomialRing(GF(3), implementation="NTL") sage: f, g = x + 2, x^2 - 1 sage: f.gcd(g) x + 2
R.<x> = PolynomialRing(GF(3), implementation="NTL") f, g = x + 2, x^2 - 1 f.gcd(g)
- resultant(other)#
Return the resultant of
self
andother
, which must lie in the same polynomial ring.INPUT:
other
– a polynomial
OUTPUT: an element of the base ring of the polynomial ring
EXAMPLES:
sage: R.<x> = PolynomialRing(GF(19), implementation='NTL') sage: f = x^3 + x + 1; g = x^3 - x - 1 sage: r = f.resultant(g); r 11 sage: r.parent() is GF(19) True
R.<x> = PolynomialRing(GF(19), implementation='NTL') f = x^3 + x + 1; g = x^3 - x - 1 r = f.resultant(g); r r.parent() is GF(19)
- xgcd(other)#
Compute the extended gcd of this element and
other
.INPUT:
other
– an element in the same polynomial ring
OUTPUT:
A tuple
(r,s,t)
of elements in the polynomial ring such thatr = s*self + t*other
.EXAMPLES:
sage: R.<x> = PolynomialRing(GF(3), implementation='NTL') sage: x.xgcd(x) (x, 0, 1) sage: (x^2 - 1).xgcd(x - 1) (x + 2, 0, 1) sage: R.zero().xgcd(R.one()) (1, 0, 1) sage: (x^3 - 1).xgcd((x - 1)^2) (x^2 + x + 1, 0, 1) sage: ((x - 1)*(x + 1)).xgcd(x*(x - 1)) (x + 2, 1, 2)
R.<x> = PolynomialRing(GF(3), implementation='NTL') x.xgcd(x) (x^2 - 1).xgcd(x - 1) R.zero().xgcd(R.one()) (x^3 - 1).xgcd((x - 1)^2) ((x - 1)*(x + 1)).xgcd(x*(x - 1))
- class sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_modn_ntl_ZZ#
Bases:
Polynomial_dense_mod_n
- degree()#
EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(14^34), implementation='NTL') sage: f = x^4 - x - 1 sage: f.degree() 4 sage: f = 14^43*x + 1 sage: f.degree() 0
R.<x> = PolynomialRing(Integers(14^34), implementation='NTL') f = x^4 - x - 1 f.degree() f = 14^43*x + 1 f.degree()
- is_gen()#
- list(copy=True)#
- quo_rem(right)#
Return
and , with the degree of less than the degree ofright
, such thatright
self
.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(10^30), implementation='NTL') sage: f = x^5+1; g = (x+1)^2 sage: q, r = f.quo_rem(g) sage: q x^3 + 999999999999999999999999999998*x^2 + 3*x + 999999999999999999999999999996 sage: r 5*x + 5 sage: q*g + r x^5 + 1
R.<x> = PolynomialRing(Integers(10^30), implementation='NTL') f = x^5+1; g = (x+1)^2 q, r = f.quo_rem(g) q r q*g + r
- reverse(degree=None)#
Return the reverse of the input polynomial thought as a polynomial of degree
degree
.If
is a degree- polynomial, its reverse is .INPUT:
degree
(None
or an integer) - if specified, truncate or zero pad the list of coefficients to this degree before reversing it.
EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(12^29), implementation='NTL') sage: f = x^4 + 2*x + 5 sage: f.reverse() 5*x^4 + 2*x^3 + 1 sage: f = x^3 + x sage: f.reverse() x^2 + 1 sage: f.reverse(1) 1 sage: f.reverse(5) x^4 + x^2
R.<x> = PolynomialRing(Integers(12^29), implementation='NTL') f = x^4 + 2*x + 5 f.reverse() f = x^3 + x f.reverse() f.reverse(1) f.reverse(5)
- shift(n)#
Shift self to left by
, which is multiplication by , truncating if is negative.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(12^30), implementation='NTL') sage: f = x^7 + x + 1 sage: f.shift(1) x^8 + x^2 + x sage: f.shift(-1) x^6 + 1 sage: f.shift(10).shift(-10) == f True
R.<x> = PolynomialRing(Integers(12^30), implementation='NTL') f = x^7 + x + 1 f.shift(1) f.shift(-1) f.shift(10).shift(-10) == f
- truncate(n)#
Return this polynomial mod
.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(15^30), implementation='NTL') sage: f = sum(x^n for n in range(10)); f x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1 sage: f.truncate(6) x^5 + x^4 + x^3 + x^2 + x + 1
R.<x> = PolynomialRing(Integers(15^30), implementation='NTL') f = sum(x^n for n in range(10)); f f.truncate(6)
- valuation()#
Return the valuation of
self
, that is, the power of the lowest non-zero monomial ofself
.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(10^50), implementation='NTL') sage: x.valuation() 1 sage: f = x - 3; f.valuation() 0 sage: f = x^99; f.valuation() 99 sage: f = x - x; f.valuation() +Infinity
R.<x> = PolynomialRing(Integers(10^50), implementation='NTL') x.valuation() f = x - 3; f.valuation() f = x^99; f.valuation() f = x - x; f.valuation()
- class sage.rings.polynomial.polynomial_modn_dense_ntl.Polynomial_dense_modn_ntl_zz#
Bases:
Polynomial_dense_mod_n
Polynomial on
implemented via NTL.- _add_(_right)#
- _sub_(_right)#
- _lmul_(c)#
- _rmul_(c)#
- _mul_(_right)#
- _mul_trunc_(right, n)#
Return the product of
self
andright
truncated to the given lengthEXAMPLES:
sage: R.<x> = PolynomialRing(Integers(100), implementation="NTL") sage: f = x - 2 sage: g = x^2 - 8*x + 16 sage: f*g x^3 + 90*x^2 + 32*x + 68 sage: f._mul_trunc_(g, 42) x^3 + 90*x^2 + 32*x + 68 sage: f._mul_trunc_(g, 3) 90*x^2 + 32*x + 68 sage: f._mul_trunc_(g, 2) 32*x + 68 sage: f._mul_trunc_(g, 1) 68 sage: f._mul_trunc_(g, 0) 0 sage: f = x^2 - 8*x + 16 sage: f._mul_trunc_(f, 2) 44*x + 56
R.<x> = PolynomialRing(Integers(100), implementation="NTL") f = x - 2 g = x^2 - 8*x + 16 f*g f._mul_trunc_(g, 42) f._mul_trunc_(g, 3) f._mul_trunc_(g, 2) f._mul_trunc_(g, 1) f._mul_trunc_(g, 0) f = x^2 - 8*x + 16 f._mul_trunc_(f, 2)
- degree()#
EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(77), implementation='NTL') sage: f = x^4 - x - 1 sage: f.degree() 4 sage: f = 77*x + 1 sage: f.degree() 0
R.<x> = PolynomialRing(Integers(77), implementation='NTL') f = x^4 - x - 1 f.degree() f = 77*x + 1 f.degree()
- int_list()#
Return the coefficients of
self
as efficiently as possible as a list of python ints.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(100), implementation='NTL') sage: from sage.rings.polynomial.polynomial_modn_dense_ntl import Polynomial_dense_mod_n as poly_modn_dense sage: f = poly_modn_dense(R,[5,0,0,1]) sage: f.int_list() [5, 0, 0, 1] sage: [type(a) for a in f.int_list()] [<... 'int'>, <... 'int'>, <... 'int'>, <... 'int'>]
R.<x> = PolynomialRing(Integers(100), implementation='NTL') from sage.rings.polynomial.polynomial_modn_dense_ntl import Polynomial_dense_mod_n as poly_modn_dense f = poly_modn_dense(R,[5,0,0,1]) f.int_list() [type(a) for a in f.int_list()]
- is_gen()#
- ntl_set_directly(v)#
- quo_rem(right)#
Return
and , with the degree of less than the degree ofright
, such thatright
self
.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(125), implementation='NTL') sage: f = x^5+1; g = (x+1)^2 sage: q, r = f.quo_rem(g) sage: q x^3 + 123*x^2 + 3*x + 121 sage: r 5*x + 5 sage: q*g + r x^5 + 1
R.<x> = PolynomialRing(Integers(125), implementation='NTL') f = x^5+1; g = (x+1)^2 q, r = f.quo_rem(g) q r q*g + r
- reverse(degree=None)#
Return the reverse of the input polynomial thought as a polynomial of degree
degree
.If
is a degree- polynomial, its reverse is .INPUT:
degree
(None
or an integer) - if specified, truncate or zero pad the list of coefficients to this degree before reversing it.
EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(77), implementation='NTL') sage: f = x^4 - x - 1 sage: f.reverse() 76*x^4 + 76*x^3 + 1 sage: f.reverse(2) 76*x^2 + 76*x sage: f.reverse(5) 76*x^5 + 76*x^4 + x sage: g = x^3 - x sage: g.reverse() 76*x^2 + 1
R.<x> = PolynomialRing(Integers(77), implementation='NTL') f = x^4 - x - 1 f.reverse() f.reverse(2) f.reverse(5) g = x^3 - x g.reverse()
- shift(n)#
Shift self to left by
, which is multiplication by , truncating if is negative.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(77), implementation='NTL') sage: f = x^7 + x + 1 sage: f.shift(1) x^8 + x^2 + x sage: f.shift(-1) x^6 + 1 sage: f.shift(10).shift(-10) == f True
R.<x> = PolynomialRing(Integers(77), implementation='NTL') f = x^7 + x + 1 f.shift(1) f.shift(-1) f.shift(10).shift(-10) == f
- truncate(n)#
Return this polynomial mod
.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(77), implementation='NTL') sage: f = sum(x^n for n in range(10)); f x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1 sage: f.truncate(6) x^5 + x^4 + x^3 + x^2 + x + 1
R.<x> = PolynomialRing(Integers(77), implementation='NTL') f = sum(x^n for n in range(10)); f f.truncate(6)
- valuation()#
Return the valuation of
self
, that is, the power of the lowest non-zero monomial ofself
.EXAMPLES:
sage: R.<x> = PolynomialRing(Integers(10), implementation='NTL') sage: x.valuation() 1 sage: f = x-3; f.valuation() 0 sage: f = x^99; f.valuation() 99 sage: f = x-x; f.valuation() +Infinity
R.<x> = PolynomialRing(Integers(10), implementation='NTL') x.valuation() f = x-3; f.valuation() f = x^99; f.valuation() f = x-x; f.valuation()
- sage.rings.polynomial.polynomial_modn_dense_ntl.make_element(parent, args)#
- sage.rings.polynomial.polynomial_modn_dense_ntl.small_roots(self, X=None, beta=1.0, epsilon=None, **kwds)#
Let
be the characteristic of the base ring this polynomial is defined over:N = self.base_ring().characteristic()
. This method returns small roots of this polynomial modulo some factor of with the constraint that . Small in this context means that if is a root of modulo then . This is either provided by the user or the maximum is chosen such that this algorithm terminates in polynomial time. If is chosen automatically it is . The algorithm may also return some roots which are larger than . ‘This algorithm’ in this context means Coppersmith’s algorithm for finding small roots using the LLL algorithm. The implementation of this algorithm follows Alexander May’s PhD thesis referenced below.INPUT:
X
– an absolute bound for the root (default: see above)beta
– compute a root mod where is a factor of and . (Default: 1.0, so .)epsilon
– the parameter described above. (Default: )**kwds
– passed through to methodMatrix_integer_dense.LLL()
.
EXAMPLES:
First consider a small example:
sage: N = 10001 sage: K = Zmod(10001) sage: P.<x> = PolynomialRing(K, implementation='NTL') sage: f = x^3 + 10*x^2 + 5000*x - 222
N = 10001 K = Zmod(10001) P.<x> = PolynomialRing(K, implementation='NTL') f = x^3 + 10*x^2 + 5000*x - 222
This polynomial has no roots without modular reduction (i.e. over
):sage: f.change_ring(ZZ).roots() []
f.change_ring(ZZ).roots()
To compute its roots we need to factor the modulus
and use the Chinese remainder theorem:sage: p, q = N.prime_divisors() sage: f.change_ring(GF(p)).roots() [(4, 1)] sage: f.change_ring(GF(q)).roots() [(4, 1)] sage: crt(4, 4, p, q) 4
p, q = N.prime_divisors() f.change_ring(GF(p)).roots() f.change_ring(GF(q)).roots() crt(4, 4, p, q)
This root is quite small compared to
, so we can attempt to recover it without factoring using Coppersmith’s small root method:sage: f.small_roots() [4]
f.small_roots()
An application of this method is to consider RSA. We are using 512-bit RSA with public exponent
to encrypt a 56-bit DES key. Because it would be easy to attack this setting if no padding was used we pad the key with 1s to get a large number:sage: Nbits, Kbits = 512, 56 sage: e = 3
Nbits, Kbits = 512, 56 e = 3
We choose two primes of size 256-bit each:
sage: p = 2^256 + 2^8 + 2^5 + 2^3 + 1 sage: q = 2^256 + 2^8 + 2^5 + 2^3 + 2^2 + 1 sage: N = p*q sage: ZmodN = Zmod( N )
p = 2^256 + 2^8 + 2^5 + 2^3 + 1 q = 2^256 + 2^8 + 2^5 + 2^3 + 2^2 + 1 N = p*q ZmodN = Zmod( N )
We choose a random key:
sage: K = ZZ.random_element(0, 2^Kbits)
K = ZZ.random_element(0, 2^Kbits)
and pad it with
1s:sage: Kdigits = K.digits(2) sage: M = [0]*Kbits + [1]*(Nbits-Kbits) sage: for i in range(len(Kdigits)): M[i] = Kdigits[i] sage: M = ZZ(M, 2)
Kdigits = K.digits(2) M = [0]*Kbits + [1]*(Nbits-Kbits) for i in range(len(Kdigits)): M[i] = Kdigits[i] M = ZZ(M, 2)
Now we encrypt the resulting message:
sage: C = ZmodN(M)^e
C = ZmodN(M)^e
To recover
we consider the following polynomial modulo :sage: P.<x> = PolynomialRing(ZmodN, implementation='NTL') sage: f = (2^Nbits - 2^Kbits + x)^e - C
P.<x> = PolynomialRing(ZmodN, implementation='NTL') f = (2^Nbits - 2^Kbits + x)^e - C
and recover its small roots:
sage: Kbar = f.small_roots()[0] sage: K == Kbar True
Kbar = f.small_roots()[0] K == Kbar
The same algorithm can be used to factor
if partial knowledge about is available. This example is from the Magma handbook:First, we set up
, and :sage: length = 512 sage: hidden = 110 sage: p = next_prime(2^int(round(length/2))) sage: q = next_prime(round(pi.n()*p)) # needs sage.symbolic sage: N = p*q # needs sage.symbolic
length = 512 hidden = 110 p = next_prime(2^int(round(length/2))) q = next_prime(round(pi.n()*p)) # needs sage.symbolic N = p*q # needs sage.symbolic
Now we disturb the low 110 bits of
:sage: qbar = q + ZZ.random_element(0, 2^hidden - 1) # needs sage.symbolic
qbar = q + ZZ.random_element(0, 2^hidden - 1) # needs sage.symbolic
And try to recover
from it:sage: F.<x> = PolynomialRing(Zmod(N), implementation='NTL') # needs sage.symbolic sage: f = x - qbar # needs sage.symbolic
F.<x> = PolynomialRing(Zmod(N), implementation='NTL') # needs sage.symbolic f = x - qbar # needs sage.symbolic
We know that the error is
and that the modulus we are looking for is :sage: from sage.misc.verbose import set_verbose sage: set_verbose(2) sage: d = f.small_roots(X=2^hidden-1, beta=0.5)[0] # time random # needs sage.symbolic verbose 2 (<module>) m = 4 verbose 2 (<module>) t = 4 verbose 2 (<module>) X = 1298074214633706907132624082305023 verbose 1 (<module>) LLL of 8x8 matrix (algorithm fpLLL:wrapper) verbose 1 (<module>) LLL finished (time = 0.006998) sage: q == qbar - d # needs sage.symbolic True
from sage.misc.verbose import set_verbose set_verbose(2) d = f.small_roots(X=2^hidden-1, beta=0.5)[0] # time random # needs sage.symbolic q == qbar - d # needs sage.symbolic
REFERENCES:
Don Coppersmith. Finding a small root of a univariate modular equation. In Advances in Cryptology, EuroCrypt 1996, volume 1070 of Lecture Notes in Computer Science, p. 155–165. Springer, 1996. http://cr.yp.to/bib/2001/coppersmith.pdf
Alexander May. New RSA Vulnerabilities Using Lattice Reduction Methods. PhD thesis, University of Paderborn, 2003. http://www.cs.uni-paderborn.de/uploads/tx_sibibtex/bp.pdf