1. Computational Number Theory for Security
By: Abhijit Mondal
Mersenne Primes:
Mersenne primes are prime numbers of the form Mq = 2q – 1.
Theorem: If Mq = 2q – 1 is prime, then q is prime.
Proof: A number 2c -1 with c composite having a proper divisor d can be written as 2c -1= (2d-1)
(1+2+22+.....+2c/d-1) hence we see that 2d-1 is a factor of 2c -1.
Theorem: For prime q>2, any prime factor of Mq = 2q – 1 must be congruent to 1(mod q) .
Proof: Let r be a prime factor of 2q – 1, with q prime, q>2. Then 2q≡1(mod r) and since q is prime,
the least positive exponent h with 2h≡1(mod r) must be q itself. Thus in the multiplicative group of
nonzero residues modulo r ( a group of order r-1 ) , the residue 2 has order q. But since
2r-1≡1(mod r) it implies that r≡1(mod q).
Fermats Little Theorem:
If for integers a and p, gcd(a,p)=1, the Fermat's theorem states that ap-1≡1(mod p). This will always
hold for p prime since gcd(a,p)=1 for all a∈Z.
Theorem: If p = 2m+1 is an odd prime , then m is a power of two.
Proof: Assume that m=ab where a is the largest odd divisor of m and b is the largest power of 2 that
divides m. Then 2m+1=(2b+1)(1-2+22-...2a-1). Hence p has a factor (2b+1). Therefore the necessary
condition for p to be prime is that p = (2b+1), i.e. A=1 and m=b a power of 2.
Euclid's algorithms for GCD and Inverse modulo:
Algorithm for GCD:
gcd(a,b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
If each a and b are of the magnitude N, then the complexity of the Euclid's algorith is O(ln2N) bit
operations.
Finding inverse modulo in the field ZP for prime p:
If for integers a,b ∈ZP , ab ≡1(mod p), then a ≡b-1(mod p) can be found for known b, by the help of
Extended euclid's algorithm:
inverse(b)
{
c = p, t0 = 0, t1 = 1, r = 0, a;
if(b = = 0) return 0;
if(b = = 1) return 1;
else{
while(r!=1){
q = p/b ; r = p%b;
a = (t0-q*t1)%c;
p = b; b = r; t0 = t1; t1 = a;
}
return a;
}
}
2. Euler's Theorem:
For positive a,m and gcd(a,m) = 1, a(m)≡1(mod m), where (m) is the Euler totient function: it
denotes the number of integers <= m which are coprime to m, i.e. gcd(x,m) = 1,x<=m. If m has the
factorisation m = p1a1p2a2.....prar then (m) = m*(1-1/p1)(1-1/p2)...(1-1/pr).
For prime p, (p) = p-1, thus ap-1≡1(mod p).
One can also calculate a-1(mod m) = a(m)-1(mod m).
Integer Powering modulo Prime:
For positive integer x and prime p , recursive algorithm to find xn(mod p).
powering(x,n)
{
if(n = = 1) return x%p;
else if(n%2 = = 0){
y = powering(x,n/2);
return y2 % p;
}
else{
y = powering(x,(n-1)/2);
return x*y2 % p;
}
}
If x,n and p are of size m, then the complexity of the algorithm is O(ln3m) bit operations.
Chinese Remainder Theorem:
Let m0,m1,m2,.....mr-1 be positive , pairwise coprime moduli with the product M = ∏i=0r-1 mi. Let r
respective residues ni also be given. Then the system comprising the r relations and inequality:
n≡ni (mod mi), 0<=n< M
has a unique solution. This solution is given explicitly by the least non-negative residue modulo M
of ∑i=0r-1niviMi, where Mi = M/mi and vi = Mi-1(mod mi).
Polynomial Arithmetic:
• Finding the remainder and the quotient on dividing g(x) by f(x), where the coefficients of all
polynomials belongs to the field Zp for prime p.
g(x) = q(x)f(x)+ r(x) and either r(x) = 0 or deg r(x) < deg f(x).
moduli(g(x),f(x))
{
r(x) = g(x);
while( deg(g(x)) >= deg(f(x)) )
{
d = deg(g(x)) – deg(f(x));
coeff( d , q(x) ) = inverse( coeff( deg(f(x)), f(x) ) )* coeff( deg(r(x)), r(x) )%p;
for( i = deg(r(x)); i>= d; i--)
{
y = coeff( i,r(x) ) - ( coeff( d,q(x) )*coeff( i-d, g(x) ) )%p ;
coeff( i ,r(x) ) = y%p;
}
deg(r(x))--;
}
return r(x);
}
C++ code for finding polynomial remainder : polymod.cpp
3. • Finding the gcd(f(x), g(x)) where the coefficients of all polynomials belongs to the field Zp
for prime p.
polygcd( f(x),g(x) )
{
u(x) = f(x); v(x) = g(x);
if( g(x) = = 0 ) return u(x);
else return polygcd( v(x), moduli(u(x),v(x)) );
}
u(x) = inverse( coeff( deg(u(x)), u(x) ) )*u(x) // make the leading coefficient of gcd equal
to 1.
C++ code for finding polynomial gcd : polygcd.cpp
• Finding f(x) when g(x) and h(x) is given and f(x)h(x) ≡1(mod g(x)), for polygcd( f(x),g(x) )
= 1, where the coefficients of all polynomials belongs to the field Zp for prime p.
polyinverse( f(x), g(x) )
{
c(x) = g(x), t0(x) = 0, t1(x) = 1, r(x) = 0;
if(f(x) = = 0) h(x) = 0;
if(f(x) = = 1) h(x) = 1;
else{
while(r(x)!=1){
q(x) = g(x)/f(x) ; r(x) = moduli( g(x), f(x) );
h(x) = moduli( (t0(x)-q(x)*t1(x)),c(x) );
g(x) = f(x); f(x) = r(x); t0(x) = t1(x); t1(x) = h(x);
}
return h(x);
}
}
C++ code for finding inverse modulo primitive polynomial : polyinverse.cpp
Finite Field Arithmetic:
Theorem : If F is a field and f(x) ∈ F[x] has positive degree, then F[x]/f(x) is a field if and only if
f(x) is irreducible in F[x], i.e. if f(x) do not have any roots in F[x].
Example: For the field F7 , choosing an irreducible f(x) = x2 +1 ( which has no roots in F7 ), we can
produce another field F7[x]/(x2+1) which has elements a+bi where a,b ∈ F7 and this new field has 49
elements and is abbreviated as F72 .
More generally if p is prime and f(x) ∈ Fp[x] is irreducible and has degree d>=1, then Fp[x]/f(x) is
again a finite field and it has pd elements.
Basic results on Finite fields:
• A finite field F has nonzero characteristic, which must be a prime.
• Every finite field has pk elements for some positive integer k, wher p is the chracteristic.
• For a given prime p aand exponent k, there is exactly one field with pk elements.
• Fpk contains as subfields unique copies of Fpj for each j|k and no other subfields.
• The multiplicative group Fpk * of non zero elements in Fpk is cyclic: there is a single element
whose powers constitute the whole group.
Polynomial Arithmetic in Fpk :
A polynomial a(x) ∈ Fpk[x] will be represented as a(x) = a0 + a1 x + a2 x2 +......ak-1 xk-1, ai ∈ Fp, where
the variable x can take values ranging over the roots of the polynomial f(x), but none of the x should
be in Fp .
4. For a(x), b(x) ∈ Fpk[x] the sum c(x) = (a(x) + b(x))%p and product d(x) = moduli(a(x)*b(x),f(x))%p
A primitive root of a field Fpk is an element whose powers constitute all of Fpk* , i.e. a primitive root
is a generator of the cyclic group Fpk*. A cyclic group with n elements has (n) generators in total.
Thus a finite field Fpk has (pk -1) primitive roots.
Finding primitive roots of the field Fpk* :
Theorem : An element g in Fpk* is a primitive root if and only if g(p^k-1)/q 1 for every prime q
dividing pk-1.
Irreducible polynomials:
Suppose that f(x) is a polynomial in Fp[x] of positive degree k. The f(x) is irreducible if and only if
gcd( f(x), xp^j-x ) = 1 for each j = 1,2,.....[k/2].
Algorithm to determine whether f(x) is irreducible over Fp :
irreduce( f(x) )
{
g(x) = x;
for(1<=i<=[k/2])
{
g(x) = moduli( g(x)p,f(x) );
d(x)= gcd( f(x), g(x)-x );
if( d(x)!=1 ) return “reducible”
}
return “irreducible”
}
C++ code for testing irreducibility of polynomials : polyirreducible.cpp
Quadratic Residues:
For coprime integers a,m with m positive, a is a quadratic residue (mod m) if and only if the
congruence:
x2≡a(mod m)
is solvable for integer x, else a is called quadratic nonresidue.
Legendre symbol:
For odd prime p, Legendre symbol (a/p) is defined as:
• (a/p) = 0 if a≡0(mod p)
• (a/p) = 1 if a is a quadratic residue (mod p)
• (a/p) = -1 if a is quadratic non residue (mod p)
Jacobi Symbol:
For odd natural number m, and any integer a, the Jacobi symbol (a/m) is defined as follows:
If the prime facorization of m = ∏piti , then the Jacobi symbol:
(a/m) = ∏(a/pi)ti
where (a/pi) are the Legendre symbols.
(a/m) can be 1 even if a is not a quadratic residue, but if (a/m) = -1 then a is coprime to m and is
quadratic non residue for sure.
5. Euler's test for Quadratic Residues:
Let p be an odd prime, m and n are positive odd integers, and a,b are integers, Then Euler's test:
(a/p)≡a(p-1)/2(mod p)
and the relations:
• (ab/m) = (a/m)(b/m)
• (a/mn) = (a/m)(a/n)
• (-1/m) = (-1)(m-1)/2
• (2/m) = (-1)(m^2-1)/8
Algorithm to calculate Legendre/Jacobi symbol:
Jacobi(a)
{
a = a%m;
t = 1;
while( a != 0 )
{
while( a even )
{
a = a/2;
if( m%8 = = 3 or 5 ) t = -t;
}
swap( a,m )
if( a≡m≡3(mod 4) ) t = -t;
a = a%m;
}
if ( m = = 1 ) return t;
return 0;
}
The above algorithm runs in O(ln2m) bit operations.
C++ code for finding Jacobi symbol : jacobi.cpp
Finding Square roots for Quadratic Residues modulo prime:
Algorithm1: Over Finite field Fp
Sqroot(a)
{
if( p≡3(mod 8) or p≡5(mod 8) or p≡7(mod 8) )
{
a = a%p;
if( p≡3(mod 8) or p≡7(mod 8) )
{
x = a(p+1)/4 % p; // a(p-1)/2 ≡1(mod p) => a(p+1)/2 ≡a (mod p)
return x;
}
else if ( p≡5(mod 8) )
{
x = a(p+3)/8 % p; // a(p+1)/2 ≡a (mod p) => a(p+3)/2 ≡a2 (mod p) raising to the
power (1/4)
2
c = x % p;
if ( c != a%p ) x = x* a(p-1)/4 % p;
return x;
}
6. }
else if ( p≡1(mod 8) )
{
Find a random integer d ∈ [2,p-1], with (d/p) = -1 // d< 2ln2p
Represent p-1 = 2st where t is the largest odd number that divides p-1.
A = at % p;
D = dt % p;
m = 0;
for( 0<=i<s)
{
if( (ADm )2^(s-1-i) ≡-1(mod p) m = m+2i;
}
x = a(t+1)/2Dm/2 % p;
return x;
}
}
The complexity of the algorithm on average is O(ln3p) bit operations.
C++ code for finding square root : sqroot.cpp
Algorithm2: Over finite field Fp2
Given an odd prime p and a quadratic residue a(mod p) , this algorithm returns a solution x to
x2≡a(mod 8).
Sqroot2(a)
{
Find a random integer t ∈ [0,p-1], with Jacobi(t2-a) = -1;
x = ( t + ( t2 – a )1/2 )(p+1)/2 ; // using Fp2 arithmetic.
return x;
}
C++ code for finding square root over Fp2 : sqroot2.cpp
The probability that a random value t will be successfull with Jacobi(t2-a) = -1 is (p-1)/2p.
An element x ∈ Fp2 is actually an element of the subfield Fp of Fp2 . 'a' has the same square root in Fp
as it has in the larger field Fp2 .
Using Fp2 arithmetic:
We use the irreducible polynomial f(x) = x2 - ( t2 – a ) to produce the finite field Fp[x]/f(x) which is
Fp2 . Since f(x) do not have any root in FP ( Jacobi(t2-a) = -1 ).
Let w = ( t2 – a )1/2
Then we represent the field Fp2 = {x+wy : x,y∈ Fp} = (x,y)
Multiplication (x,y)*(u,v) = ( x+wy )*(u+wv ) = xu+yvw2+(xv+yu)w = (xu+yv(t2 – a ),xv+yu), all
products are modulo p.
w2 should be substituted with (t2 – a ).
Thus (t + ( t2 – a )1/2 ) = (t ,1) which we multiply (p+1)/2 times to itself.
7. Finding Polynomial roots modulo prime:
Let g ∈ Fp[x] be a polynomial with coefficients modulo p. Find the gcd of g(x) with xp-x because
the latter polynomial is the product of (x-a) where a runs from 0 to p-1. Since the roots of g(x) will
be in [0,p-1] thus we find the gcd polynomial which is the product of (x – b ) where b belongs to all
the roots of g(x).
Polyroots(g(x))
{
r = {};
g(x) = gcd( xp – x, g(x) );
if( g(0) = = 0) // 0 is a root of g(x) or x is a factor of g(x).
{
r = r ∪{0};
g(x) = g(x)/x;
}
r = r ∪roots(g(x));
return r;
}
roots(g(x))
{
if( deg(g) = = 1 ) // if g(x) = cx + d
{
r = r ∪{inverse(c)*(p-d) % p} ;
return r;
}
else if( deg(g) = = 2 ) // if g(x) = ax2 + bx + c , multiply g(x) by (2a)-1(mod p)
{
g(x) = g(x)*(2a)-1(mod p); // now g(x) = 2-1x2 + b'x + c'
d = (b'2 – 2*c') % p;
r = r ∪{(p-b'+sqroot2(d)) % p}∪{(p-b'-sqroot2(d)) % p} ;
return r;
}
h(x) = g(x);
while( h(x) = = 1 || h(x) = = g(x) )
{
Choose random a∈ [0,p-1];
h(x) = gcd( (x+a)(p-1)/2 – 1, g(x) ); // splitting g(x) into 2 smaller polynomials h(x) and
// g(x)/h(x), from Euler's criterion for any b!=0, b is a root of the polynomial
// (x+a)(p-1)/2 – 1 with probability (p-1)/2p
}
r = r ∪{roots(h)}∪{roots(g/h)} ;
return r;
}
C++ code for finding polynomial roots : polyroots.cpp
8. Elliptic Curves Arithmetic:
Elliptic curves over prime field Zp :
An elliptic curve y2 = x3 + ax + b defined over Zp where a, b ∈ Zp · An elliptic curve (EC) can be
made into an abelian group with all points on an EC, including the point at infinity O under the
condition of 4a 3 + 27b2 = 0 (mod p). If two distinct points P (x1 , y1 ) and Q(x2 , y2 ) are on an
elliptic curve, the third point R is defined as P + Q = R(x3 , y3 ) . The third point R is defined as
follows: first draw a line through P and Q, find the intersection point −R on the elliptic curve, and
finally determine the reflection point R with respect to the x -axis, which is the sum of P and Q.
If P (x, y) is a point on an elliptic curve (EC), then P + P = R(x3 , y3 ) (double of P ) is defined
as follows: first draw a tangent line to the elliptic curve at P . This tangent line will intersect the EC
at a second point (−R ). Then R(x3 , y3 ) is the reflection point of −R with respect to the x -axis .
9. If the points on an elliptic curve y 2 = x 3 + ax + b over Zp are represented by the points P (x1 , y1 ),
Q(x2 , y2 ) and R(x3 , y3 ) = P + Q, the following theorems will hold:
• When P ≠ Q, x3 = α 2 − x1 − x2 (mod p), y3 = −y1 + α (x1 − x3 ) (mod p) when
α = (y2 − y1 )*(x2 − x1 )-1 (mod p).
• When P = Q (i.e. 2P (x3 , y3 )), x3 = β 2 − 2x1 (mod p) , y3 = −y1 + β(x1 − x3 ) (mod p) when
β = (3x12 + a)*(2y1)-1 (mod p).
Elliptic_equal( P(x,y) )
{
β = (3x2 + a)*(2y)-1 (mod p);
x3 = β 2 − 2x (mod p) ;
y3 = −y + β(x − x3 ) (mod p) ;
return R(x3 , y3 );
}
Elliptic_notequal( P (x1 , y1 ), Q(x2 , y2 ) )
{
α = (y2 − y1 )*(x2 − x1 )-1 (mod p). ;
x3 = α 2 − x1 − x2 (mod p);
y3 = −y1 + α (x1 − x3 ) (mod p);
return R(x3 , y3 );
}
Computing points on the elliptic curve over the prime field:
For the elliptic curve y 2 = x 3 + ax + b over Zp , choose a random x ∈[0,p-1] and calculate z ≡ x 3 +
ax + b (mod p) , if z is a quadratic residue mod p, then we will have a solution y ∈[0,p-1] for
y 2 ≡ z (mod p).
Let EC be an elliptic curve over Zp . Hasse states that the number of points on an elliptic curve,
including the point at infinity O , is p+1-2√p <= #EC(Zp ) <= p+1+2√p . #EC(Zp ) is called the order
of EC and t is called the trace of EC.
Algorithm to generate all points on the elliptic curve y 2 = x 3 + ax + b over Zp after finding any one
point G(x,y) :
If P(x,y) is a point on the elliptic curve, then it's reflection on the x-axis Q(x, p-y) is also a point on
the elliptic curve. Thus for each x coordinate on the curve there are 2 different points.
Generate( G(x,y) )
{
G'( x',y' ) = Elliptic_equal( G(x,y) );
while( for each x' there are less than equal to 2 points on EC )
{
G'( x',y' ) = Elliptic_notequal( G'( x',y' ), G(x,y) );
}
}
C++ code for generating points on elliptic finite field curves : elliptic_finite.cpp
Elliptic curve over finite field GF(2m ) :
An elliptic curve over GF(2m ) is defined by the following equation:
y 2 + xy = x 3 + ax 2 + b
where a, b ∈ GF(2m ) and b = 0. The set of EC over GF(2m ) consists of all points (x, y), x, y ∈
GF(2m ), that satisfy the above defining equation, together with the point of infinite O .
The algebraic formula for the sum of two points and the doubling point are defined as follows:
• If P ∈ EC(GF(2m )), then P + (−P ) = O , where P = (x, y) and −P = (x, x + y) are indeed the
points on the EC.
10. • If P and Q (but P ≠ Q) are the points on the EC(GF(2m )), then P + Q = P (x1 , y1 )+ Q(x2 ,y2 )
= R(x3 , y3 ), where x3 = λ2 + λ + x1 + x2 + a and y3 = λ(x1 + x3 ) + x3 + y1 , where λ =
(y1+y2 )/(x1 + x2 ).
• If P is a point on the EC (GF(2m )), but (P ≠ −P ), then the point of doubling is 2P = R(x3,y3),
where
x3 = x12 + b/x12 and y3 = x12 + ( x1 + y/x1 ) x3 + x3
C++ code for generating points on elliptic galois field curves : elliptic_galois.cpp
Sieve of Eratosthenes to generate Primes:
Given a positive integer N>1, the algorithm to generate all the primes from 2 to N is as follows:
Start with (N-1)/2 '1's corresponding to odd numbers from 3 to N. Starting with '1' at 3, we change
all 1's to 0's at locations starting from 32 = 9 and then multiples of 2*3 = 6, i.e 9,15,21,....... upto the
last multiple of three <=N. Since at location 4 it is already 0, we skip it and go to 5 and again
change the 1's at locations starting from 52 = 25 and then multiples of 2*5 = 10 to 0's. Thus if at
location p there is 1, we change all 1's to 0's at locations starting from p2 and then multiples of 2*p
upto the last multiple <=N. Note that p<=√N. After all done the locations at which there are 1's are
the prime numbers.
If N is very large then we split it into √N parts and perform operations on each part separately.
C++ code for sieving to generate primes : sieve.cpp
Primality Testing and Primality Proving:
Pseudoprimes and Probable primes:
From Fermat's little theorem: “If n is prime, then for any integer a, we have an≡a (mod n) or an-1≡1
(mod n)”
we find that all prime numbers will pass this test, but we cannot guarantee that all composites will
fail this test, i.e. we have not completely separated the composites from the primes and thus a
number n which passes this test will be a Probable prime and a composite number passing this test
will be a Pseudoprime.
The number of pseudoprimes must be rarer than the number of actual primes, then the test will be a
“good” primality test.
Carmichael Numbers:
A composite number n for which an≡a (mod n) for every integer a is called a Carmichael number.
Theorem : An integer n is a Carmichael number if and only if n is positive, squarefree, and for each
prime p dividing n we have p-1 dividing n-1.
Proof : Suppose n is a Carmichael number. Then n is composite. Let p be a prime factor of n. From
the definition pn≡p (mod n) implies p(p-1)(1+p+p2+.....pn-2) 0 (mod p2) and so p2 does not divide n.
Thus n is squarefree. Let a be a primitive root mod p. Since an≡a (mod n), we have an≡a (mod p )
from which we see that an-1≡1 (mod p). But a(mod p) has order p-1, so that p-1 divides n-1.
Now conversely assume that n is composite, squarefree, and for each prime p dividing n, we have p-
1 dividing n-1. We are to show that an≡a (mod n) for every integer a. Since n is squarefree, it
suffices to show that an≡a (mod p ) for every integer a and each prime p dividing n. If a is not
divisible by p then we have ap-1≡1 (mod p), and since p-1 divides n-1, we have an-1≡1 (mod p). Thus
an≡a (mod p). But this congruence clearly hold when a is divisible by p, so it holds for all a.
11. Strong probable Prime test:
Theorem : Suppose n is an odd prime and n-1 = 2st, where t is odd. If a is not divisible by n then
either at≡1 (mod n) or a(2^i)t≡-1 (mod n) for some i with 0<=i<=s-1.
Strong_prime_test(n)
{
b=at mod n;
if( b = = 1 or b = = n-1) return “n is a strong probable prime base a”;
for(1<=j<=s-1)
{
b = b2 mod n;
if(b = = n-1) return “n is a strong probable prime base a”;
}
return “n is composite”;
}
C++ code for Rabin's primality test : rabin_test.cpp
Primality Proving:
Lucas Theorem : If a,n are integer with n>1 and an-1≡1 (mod n), but a(n-1)/q ≠1 (mod n) for every
prime q|n-1, then n is prime.
Proof : The first condition implies that the order of a in Zn is a divisor of n-1, while the second
condition implies that the order of a is not a proper divisor of n-1; that is it is equal to n-1. But the
order of a is also equal to φ(n). Hence φ(n) = n-1 which is possible only if n is prime.
Partial Factorization test:
Expressing n-1 not as the product of it's prime factors but in terms of some composite factors, i.e.
Without finding prime factorization of n-1, find R and F such that n-1 = FR, where complete
factorization of F is known.
Algorithm for the (n-1) primality test:
Assume that n-1 = FR holds for F>=n1/3.
n-1_test(n)
{
g = n;
while( g = = n)
{
choose random a∈[2,n-2];
if ( an-1≠1 (mod n) ) return “n is not prime”;
for( prime q|F )
{
g = gcd ( (a(n-1)/q mod n) -1, n);
if( 1<g<n ) return “n is not prime”;
if( g = = n) { break; }
}
}
if( F>=n1/2 ) return “n is prime”;
if ( n1/3 <= F < n1/2 )
{
c2 = n mod F2 ;
c1 = (n – c2 * F2 )/F;
if ( c12 - 4c2 not a square ) return “n is prime”;
return “n is not prime”;
}
}
12. C++ code for Lucas primality test : lucastest.cpp
C++ code for modified primality test: prime_test.cpp
Prime Factorization of Composite integers:
Pollard's p-1 method:
pollard(n)
{
g = 1;
while(g = = 1 or g = = n )
{
Choose some bound B >2;
k = B! or k = lcm{1,2,...,B};
Choose integer a ∈ [2,n-2];
b = ak mod n;
g = gcd (n, b-1);
}
return g;
}
C++ code for Pollards p-1 method : pollard.cpp
Explanation of Pollard’s p - 1 Method:
Let B be larger than any prime factor of p -1 where p is a prime factor of n. If k is the least common
multiple of all integers i with (1<= i <=B) , then by Fermat’s Little Theorem, a k ≡ a C( p-1) ≡ 1
(modulo p). This implies p divides both b-1 ≡ (a k - 1) (modulo n) and n, ensuring that d = gcd{b- 1,
n} is a nontrivial divisor of n.
Pollards ρ-algorithm:
If positive integers x and y in ZN can be found so that 1<d=gcd{x - y, N}<N, then d is a factor of N.
Pairs (x, y) can be found by random trials, hence the name Monte Carlo; accordingly, a random
function f mapping the integers in ZN - {0} into themselves is selected. The sequence x1, x2, . . . is
determined by the rule :
x1 = s
xi = f(xi-1), for 2<=i<n.
The f(n) must repeat before N - 1 iterations and the sequence x1 → x2 = f (x1 ) → x3 = f (x2 ) →....
has :
a tail x1 → x2 = f (x1 ) →.......→xk = f(xk-1),
and then enters a loop or cycle xk = f(xk-1) →.....→xj+k = f(xj+k-1) = xk .
For large N finding xj = xk would trivially have to consider searching all the N-1 numbers. But if we
assume that the values xi are totally random and each occurs with equal probability (1/(N-1)) then
from the Birthday Paradox, i.e. “What is the probability that in a class of n students, 2 students have
the same birthday?” we modify it and state “what is the probabilty that in a set of n integers, the
probabilty that 2 integers are equal is greater than 0.5, where the integers are from the set {1,2,...N-
1}?”
Hence Pn = 1 – (N-1)(N-2)....(N-n)/(N-1)n ≈ 1 - e-n(n-1)/(2*(N-1)) >= 0.5 implies that
n(n-1) <= 2(N-1) ln 2 which implies n = O(√N). Thus we need to search over √N integers before we
find a collision with probability >= 0.5.
But searching all the pairs from √N integers would take √NC2 searches which itself goes as N.
To modify it, we consider the Floyd cycle-finding method: if the loop begins with xk and xj+k = xk,
then j must be a multiple of the cycle length. Therefore, if two indices i1 < i2 are found such that
xi1= xi2, then i2 - i1 must be a multiple of the cycle length.
13. So the basic idea is to compute the sequence gcd( f i (x) – f 2i (x) , N ) for i=1,2,... and this should
terminate with a non trivial factorization of n in O(√p) steps, where p is the least prime factor of N.
rho(n)
{
while(g = = n)
{
choose random a∈ [1,n-3];
choose random s∈ [0,n-1];
u = v = s;
Define function f(x) = ( x2 + a ) mod n;
while( g = = 1)
{
u = f(u);
v = f(v);
v = f(v);
g = gcd ( v-u,n );
}
}
return g;
}
C++ code : rho.cpp
The Quadratic Sieve Factorization:
We assume that N is both composite and odd. If integers x and y can be found so that x 2 ≡ y 2
(modulo N ), then (x - y)(x + y) ≡ 0 (modulo N ). If x ≠ +y (modulo N ), then either gcd{N, x - y}
or gcd{N, x + y} is a nontrivial factor of N.
In fact, the factorizations N = ab are in 1 –1 correspondence with pairs of integers s, t such that 0 =
(t 2 - s 2) (modulo N ) in the sense that t = (a+b)/2 and s = (a-b)/2.
When m = [√N] and x is small compared to m, then :
q(x) = (x+m)2 – N = x2 + 2mx + m2 -N ≈ x2 + 2mx is of the order √N and hence the prime
factors of q(x) will be small.
If a prime p divides q(x) then :
q(x) ≡ 0 (mod p) then q(x) = (x+m)2 – N ≡ 0 (mod p) and hence N is a quadratic residue
modulo p and only these primes occur in the factorization of q(x). Since we require q(x) to
factorize N and we see that it implies that N is a quadratic residue modulo the prime factors of q(x) .
Thus we preselect a finite base S consisting of all the primes such that N is a quadratic residue
modulo the primes in S.
Algorithm:
1. Select a factor base : The factor base S= {-1 , 2 , p2 , p3 , ........, pt } where N is quadratic
residue modulo the primes pi, where 2<=i<=t.
2. Find Smooth x-Values: An integer x is smooth relative to the factor base S provided the
factorization of q(x) = (x+m)2 – N involves only primes in S. p0 = -1 is included in S as q(x)
may be negative.
3. For x = 0, 1, -1, 2, -2, . . . , r, -r with r ≈ 40 to 60 compute q(x). Construct a table whose ith
row for i = 1, 2, . . . contains the ith smooth value of x denoted by xi and
qi = (xi+m)2 – N = ∏(j=0 to t) pjei,j , bi = (xi+m)2 (mod N) , ai = (xi+m) (mod N)
ei = ( ei,0 , ei,1 , ei,2 , .......ei,r )
4. Find Dependency Sets T: Use Gaussian elimination to determine subsets T ={i1, i2, . . . , ik}
for which the exponent of each of the t primes in the product.
bT = ∏(s = 1 to r) bis is even.
14. Defining aT = ∏(s = 1 to r) ais , √bT = ∏(j = 1 to t) pjlj , lj = (1/2)∑( s = 1 to r ) eis,j
2 2
1<=j<=t, we have bi (modulo n) = (xi+m) (modulo n) = ai (modulo N)
This implies : aT2 (modulo N) = bT (modulo N)
5. Use the Euclidean algorithm to compute gcd{aT ± √bT}. If aT ≠ ± √bT (modulo N), then
either gcd{aT + √bT , N} or gcd{aT - √bT , N} is a nontrivial factor of N.
If aT = ± √bT (modulo N), then test another linear dependency T.
C++ code for Quadratic sieve factorization: qsieve.cpp
Lenstra's Elliptic Curve Factorization:
Algorithm:
1. Randomly choose x, y∈ ZN.
2. Randomly choose a and b subject to y 2 = x 3 + ax + b (modulo N ).
3. Test if D = 4a 3 + 27b 2 ≡ 0 (modulo N ); return to (2) if D = 0.
4. Choose a bound M and define E = ∏(primes q<=M) qlog(M)(base q) .
5. Let P = (x, y) and compute P E by repeated squaring. Before multiplying (x1, y1) by (x2, y2)
compute g = gcd{x1 - x2, N}. If 1< g < N, return g and END.
Running time of the algorithm is O(e√((2+∈)log p log log p) ).
C++ code for lenstra's ecm : ecm.cpp
The Discrete Logarithm Problem:
The discrete logarithm problem (modulo p) (DLP) is :
Given: A prime p, q a primitive root of p and y = q x (modulo p);
Find: x = logqy (modulo p).
A solution to the DLP modulo p can be found by exhaustive trial; that is, computing q x (modulo p)
for x = 1, 2, . . . until an x is found for which y = q x (modulo p). This solution, which requires O( p)
steps, is not computationally practical for p>1010. A feasible solution technique is one for which a
solution is found in O(log2k p) steps.
Solution of the DLP given a prime factorization of p-1:
Pohlig-Hellman Algorithm:
Given: p - 1 = p1n1 p2n2 . . . pknk, q a primitive root of p, and y = q x (modulo p);
Find: x = logqy (modulo p).
The important observation is that it suffices to solve the DLP if x is replaced by its residues modulo
pini for each prime factor. Write the base-pini representation of x for the prime factor pini of p - 1:
x = x( pini ) + Cpini , where x( pini ) = x (modulo pini )
Thus x( pi ) = xi,0 + xi,1pi + xi,2pi2 + ........xi,ni-1pini-1 ,
ni
0<=xi,j<pi , 0<= j< ni -1
y(p-1)/pi (modulo p) = qx*(p-1)/pi (modulo p) = q^( (x( pini ) + Cpini )(p-1)/pi ) (modulo p)
= q^(x( pini )(p-1)/pi ) (modulo p) * q^( Cpini (p-1)) (modulo p)
But by Fermat's Little Theorem: q^( Cpini (p-1)) (modulo p) = 1 (modulo p).
Hence: y(p-1)/pi (modulo p) = q^(x( pini )(p-1)/pi ) (modulo p)
Thus instead of solving for x we now solve for x( pini ) for each pini and then compute x using the
Chinese Remainder Theorem.
Precompute gi,j = q^(j(p-1)/pi ) (modulo p) for 0<= j< ni and 1<=i<=k.
Computation of xi,m :
m=0:
Compute y(p-1)/pi (modulo p) = q^((xi,0 + xi,1pi + xi,2pi2 + ........xi,ni-1pini-1 )(p-1)/pi ) (modulo p)
= q^(xi,0(p-1)/pi ) (modulo p) * q^((xi,1+ xi,2pi + ........xi,ni-1pini-2 )(p-1)) (modulo p)
By Fermat's Little Theorem : q^((xi,1+ xi,2pi + ........xi,ni-1pini-2 )(p-1)) (modulo p) = 1 (modulo p).
15. Thus y(p-1)/pi (modulo p) = q^(xi,0(p-1)/pi ) (modulo p) = gi,j0 , then xi,0 = j0 .
m=1:
Calculate new y = y*q^(-xi,0) (modulo p).
Compute y(p-1)/pi (modulo p) = q^((xi,1+ xi,2pi + ........xi,ni-1pini-2 )(p-1)/pi ) (modulo p)
= q^(xi,1(p-1)/pi ) (modulo p) * q^((xi,2+ xi,3pi + ........xi,ni-1pini-3 )(p-1)) (modulo p)
By Fermat's Little Theorem : q^((xi,2+ xi,3pi + ........xi,ni-1pini-3 )(p-1)) (modulo p) = 1 (modulo p).
Thus y(p-1)/pi (modulo p) = q^(xi,1(p-1)/pi ) (modulo p) = gi,j1 , then xi,0 = j1 .
m=2:
Calculate new y = y*q^(-xi,1pi) (modulo p).
Compute y(p-1)/pi (modulo p) = q^((xi,2+ xi,3pi + ........xi,ni-1pini-3 )(p-1)/pi ) (modulo p)
= q^(xi,2(p-1)/pi ) (modulo p) * q^((xi,3+ xi,4pi + ........xi,ni-1pini-4 )(p-1)) (modulo p)
By Fermat's Little Theorem : q^((xi,3+ xi,4pi + ........xi,ni-1pini-4 )(p-1)) (modulo p) = 1 (modulo p).
Thus y(p-1)/pi (modulo p) = q^(xi,2(p-1)/pi ) (modulo p) = gi,j2 , then xi,0 = j2 .
And so on upto m= ni -1 .
so we obtain x( pini ) = xi,0 + xi,1pi + xi,2pi2 + ........xi,ni-1pini-1 . Then using Chinese Remainder Theorem
we calculate x.
C++ code for Pohlig-Hellman algorithm : dlp_pohlig.cpp
Shank's Baby Step Giant Step Algorithm:
Suppose q is a generator of G and m = ceil(√n); the exponent x of y = q x has a representation
x = im + j where 0< i, j < m. Write yq-im = q j and construct a table of size O(√ n) whose entries
( j,qj ) are sorted according to the second term. The cost of the sort is O(√n log √n) = O(√n log n)
comparisons. Now instead of searching for x of O(n) we separately work with 2 lists of length
O(√n) where i and j are the variables and then find the intersection between the two lists.
Initialization: Compute q-m and set g = y.
For i = 0 to m-1 do
• Search( by doing a binary search ) if g is the second component of some term q j in the table;
if so, return x = im + j.
• Replace g by gq-m .
C++ code for Shank's Baby Step Giant Step Algorithm : shank.cpp
C++ code for modified Shank's algorithm : shank2.cpp
The index-Calculus Method:
Initialization: Select a factor base S = { p1, p2, . . . , ps} consisting of elements of G. S is chosen so
that a significant proportion of the elements of G can be expressed in the form p1n1 p2 n2 . . . psns with
ni >= 0.
1. Select a random k with 0 <= k < p-1 and compute q k (modulo p).
2. Try to write q k (modulo p) as a product p1c1 p2 c2 . . . pscs with ci >= 0.
◦ if unsuccessful, choose another value for k;
◦ if successful, write k = [c1 logq p1 + c2 logq p2 +....+ cs logq ps] (modulo p – 1) because k
belongs to the residue class modulo (p-1).
3. Repeat steps 1 and 2 and find s random k's and form s simulteneous linear equations which
will be solved modulo p-1 for logq pi for 1<=i<=s.
4. Select a random k with 0<= k< p-1 and compute yq k (modulo p).
5. Try to write yq k (modulo p) as a product p1d1 p2 d2 . . . psds with di >= 0.
• if unsuccessful, return to Step 4 and choose another value for k;
• if successful, write x = [d1 logq p1 + d2 logq p2 +....+ ds logq ps - k] (modulo p – 1).
C++ code for index-calculus method for solving DLP : index_calculus.cpp
16. Pollard's ρ-algorithm for the DLP:
Given: q is a generator in a cyclic group G of order p-1 and x in G;
Find: x is in Zp-1, satisfying y = qx (mod p)
Algorithm:
1. Start with a0 = 0, b0 = 0 and t0 = qa0yb0 (mod p)
2. Compute ai+1 from ai as follows:
• ai+1 = ai (mod p-1) if 0 <ti< p/3
• ai+1 = 2ai (mod p-1) if p/3 <ti< 2p/3
• ai+1 = ai + 1 (mod p-1) if 2p/3 <ti< p
3. Compute bi+1 from bi as follows:
• bi+1 = bi + 1 (mod p-1) if 0 <ti< p/3
• bi+1 = 2bi (mod p-1) if p/3 <ti< 2p/3
• bi+1 = bi (mod p-1) if 2p/3 <ti< p
4. Since ti = qaiybi (mod p), hence ti+1 can be computed as:
• xi+1 = yxi (mod p-1) if 0 <ti< p/3
2
• xi+1 = xi (mod p-1) if p/3 <ti< 2p/3
• xi+1 = qxi (mod p-1) if 2p/3 <ti< p
5. Now if x2i = xi then we have q y (mod p) = qaiybi (mod p), which implies that if the inverse
a2i b2i
(b2i – bi )-1 modulo (p-1) exists then our solution x = (ai – a2i )(b2i – bi )-1 modulo (p-1) else
compute gcd((b2i – bi )mod(p-1) , p-1) = g, and then compute b'= ((b2i – bi )mod(p-1))/g and
a' = ((ai – a2i ) mod(p-1))/g, then compute x = x' + m*(p-1)/g where m runs from 0 to g-1,
and for each m, x' = (a')(b')-1 modulo(p-1), check for each m whether y = qx (mod p).
The equality x2i = xi will be found in O(√p) iterations.
C++ code for Pollard's rho algorithm for the DLP : rho_dlp.cpp