From e03e63e861571d6198c584e4aad42f4f51bef2ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se>
Date: Tue, 17 Dec 2013 22:02:48 +0100
Subject: [PATCH] For prime generation, use stronger variants of Pocklington's
 theorem.

---
 ChangeLog             |   6 ++
 bignum-random-prime.c | 179 +++++++++++++++++++++++++++++++++---------
 2 files changed, 150 insertions(+), 35 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6425460d..2edf4487 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-12-12  Niels Möller  <nisse@lysator.liu.se>
+
+	* bignum-random-prime.c (_nettle_generate_pocklington_prime): Use
+	stronger variants of Pocklington's theorem, to allow p0 of size
+	down to bits/3.
+
 2013-12-15  Niels Möller  <nisse@lysator.liu.se>
 
 	* nettle-internal.h (NETTLE_MAX_BIGNUM_BITS)
diff --git a/bignum-random-prime.c b/bignum-random-prime.c
index 0d906d96..c0cf4b22 100644
--- a/bignum-random-prime.c
+++ b/bignum-random-prime.c
@@ -167,7 +167,8 @@ prime_by_size[9] = {
 };
 
 /* Combined Miller-Rabin test to the base a, and checking the
-   conditions from Pocklington's theorem. */
+   conditions from Pocklington's theorem, nm1dq holds (n-1)/q, with q
+   prime. */
 static int
 miller_rabin_pocklington(mpz_t n, mpz_t nm1, mpz_t nm1dq, mpz_t a)
 {
@@ -229,34 +230,93 @@ miller_rabin_pocklington(mpz_t n, mpz_t nm1, mpz_t nm1dq, mpz_t a)
   return is_prime;
 }
 
-/* The algorithm is based on the following special case of
-   Pocklington's theorem:
+/* The most basic variant of Pocklingtons theorem:
 
-   Assume that n = 1 + f q, where q is a prime, q > sqrt(n) - 1. If we
-   can find an a such that
+   Assume that q^e | (n-1), with q prime. If we can find an a such that
 
      a^{n-1} = 1 (mod n)
-     gcd(a^f - 1, n) = 1
+     gcd(a^{(n-1)/q} - 1, n) = 1
 
-   then n is prime.
+   then any prime divisor p of n satisfies p = 1 (mod q^e).
 
-   Proof: Assume that n is composite, with smallest prime factor p <=
-   sqrt(n). Since q is prime, and q > sqrt(n) - 1 >= p - 1, q and p-1
-   are coprime, so that we can define u = q^{-1} (mod (p-1)). The
-   assumption a^{n-1} = 1 (mod n) implies that also a^{n-1} = 1 (mod
-   p). Since p is prime, we have a^{(p-1)} = 1 (mod p). Now, r =
-   (n-1)/q = (n-1) u (mod (p-1)), and it follows that a^r = a^{(n-1)
-   u} = 1 (mod p). Then p is a common factor of a^r - 1 and n. This
-   contradicts gcd(a^r - 1, n) = 1, and concludes the proof.
+   Proof (Cohen, 8.3.2): Assume p is a prime factor of n. The central
+   idea of the proof is to consider the order, modulo p, of a. Denote
+   this by d.
 
-   If n is specified as k bits, we need q of size ceil(k/2) + 1 bits
-   (or more) to make the theorem apply.
+   a^{n-1} = 1 (mod n) implies a^{n-1} = 1 (mod p), hence d | (n-1).
+   Next, the condition gcd(a^{(n-1)/q} - 1, n) = 1 implies that
+   a^{(n-1)/q} != 1, hence d does not divide (n-1)/q. Since q is
+   prime, this means that q^e | d.
+
+   Finally, we have a^{p-1} = 1 (mod p), hence d | (p-1). So q^e | d |
+   (p-1), which gives the desired result: p = 1 (mod q^e).
+
+
+   * Variant, slightly stronger than Fact 4.59, HAC:
+
+   Assume n = 1 + 2rq, q an odd prime, r <= 2q, and 
+
+     a^{n-1} = 1 (mod n)
+     gcd(a^{(n-1)/q} - 1, n) = 1
+
+   Then n is prime.
+
+   Proof: By Pocklington's theorem, any prime factor p satisfies p = 1
+   (mod q). Neither 1 or q+1 are primes, hence p >= 1 + 2q. If n is
+   composite, we have n >= (1+2q)^2. But the assumption r <= 2q
+   implies n <= 1 + 4q^2, a contradiction.
+
+   In bits, the requirement is that #n <= 2 #q, then
+
+     r = (n-1)/2q < 2^{#n - #q} <= 2^#q = 2 2^{#q-1}< 2 q
+
+
+   * Another variant with an extra test (Variant of Fact 4.42, HAC):
+
+   Assume n = 1 + 2rq, n odd, q an odd prime, 8 q^3 >= n
+
+     a^{n-1} = 1 (mod n)
+     gcd(a^{(n-1)/q} - 1, n) = 1
+
+   Also let x = floor(r / 2q), y = r mod 2q, 
+
+   If y^2 - 4x is not a square, then n is prime.
+
+   Proof (adapted from Maurer, Journal of Cryptology, 8 (1995)):
+
+   Assume n is composite. There are at most two factors, both odd,
+
+     n = (1+2m_1 q)(1+2m_2 q) = 1 + 4 m_1 m_2 q^2 + 2 (m_1 + m_2) q
+     
+   where we can assume m_1 >= m_2. Then the bound n <= 8 q^3 implies m_1
+   m_2 < 2q, restricting (m_1, m_2) to the domain 0 < m_2 <
+   sqrt(2q), 0 < m_1 < 2q / m_2.
+
+   We have the bound
+
+     m_1 + m_2 < 2q / m_2 + m_2 <= 2q + 1 (maximum value for m_2 = 1)
+
+   And the case m_1 = 2q, m_2 = 1 can be excluded, because it gives n
+   > 8q^3. So in fact, m_1 + m_2 < 2q.
+
+   Next, write r = (n-1)/2q = 2 m_1 m_2 q + m_1 + m_2.
+   
+   If follows that m_1 + m_2 = y and m_1 m_2 = x. m_1 and m_2 are
+   thus the roots of the equation
+
+     m^2 - y m + x = 0
+
+   which has integer roots iff y^2 - 4 x is the square of an integer.
+
+   In bits, the requirement is that #n <= 3 #q, then
+
+     n < 2^#n <= 2^{3 #q} = 8 2^{3 (#q-1)} < 8 q^3
 */
 
 /* Generate a prime number p of size bits with 2 p0q dividing (p-1).
-   p0 must be of size >= ceil(bits/2) + 1. The extra factor q can be
-   omitted. If top_bits_set is one, the top most two bits are one,
-   suitable for RSA primes. */
+   p0 must be of size >= ceil(bits/3). The extra factor q can be
+   omitted. If top_bits_set is one, the topmost two bits are set to
+   one, suitable for RSA primes. Also returns r = (p-1)/q. */
 void
 _nettle_generate_pocklington_prime (mpz_t p, mpz_t r,
 				    unsigned bits, int top_bits_set, 
@@ -265,15 +325,34 @@ _nettle_generate_pocklington_prime (mpz_t p, mpz_t r,
 				    const mpz_t q,
 				    const mpz_t p0q)
 {
-  mpz_t r_min, r_range, pm1,a;
-  
-  assert (2*mpz_sizeinbase (p0, 2) > bits + 1);
+  mpz_t r_min, r_range, pm1, a, e;
+  int need_square_test;
+  unsigned p0_bits;
+  mpz_t x, y, p04;
+
+  p0_bits = mpz_sizeinbase (p0, 2);
+
+  assert (bits <= 3*p0_bits);
+  assert (bits > p0_bits);
+
+  need_square_test = (bits > 2 * p0_bits);
 
   mpz_init (r_min);
   mpz_init (r_range);
   mpz_init (pm1);
   mpz_init (a);
 
+  if (need_square_test)
+    {
+      mpz_init (x);
+      mpz_init (y);
+      mpz_init (p04);
+      mpz_mul_2exp (p04, p0, 2);
+    }
+
+  if (q)
+    mpz_init (e);
+
   if (top_bits_set)
     {
       /* i = floor (2^{bits-3} / p0q), then 3I + 3 <= r <= 4I, with I
@@ -293,6 +372,7 @@ _nettle_generate_pocklington_prime (mpz_t p, mpz_t r,
       mpz_fdiv_q (r_range, r_range, p0q);
       mpz_add_ui (r_min, r_range, 1);
     }
+
   for (;;)
     {
       uint8_t buf[1];
@@ -319,25 +399,54 @@ _nettle_generate_pocklington_prime (mpz_t p, mpz_t r,
 
       if (q)
 	{
-	  mpz_t e;
-	  int is_prime;
-	  
-	  mpz_init (e);
-
 	  mpz_mul (e, r, q);
-	  is_prime = miller_rabin_pocklington(p, pm1, e, a);
-	  mpz_clear (e);
-
-	  if (is_prime)
-	    break;
+	  if (!miller_rabin_pocklington(p, pm1, e, a))
+	    continue;
+
+	  if (need_square_test)
+	    {
+	      /* Our e corresponds to 2r in the theorem */
+	      mpz_tdiv_qr (x, y, e, p04);
+	      goto square_test;
+	    }
 	}
-      else if (miller_rabin_pocklington(p, pm1, r, a))
-	break;
+      else
+	{
+	  if (!miller_rabin_pocklington(p, pm1, r, a))
+	    continue;
+	  if (need_square_test)
+	    {
+	      mpz_tdiv_qr (x, y, r, p04);
+	    square_test:
+	      /* We have r' = 2r, x = floor (r/2q) = floor(r'/2q),
+		 and y' = r' - x 4q = 2 (r - x 2q) = 2y.
+
+		 Then y^2 - 4x is a square iff y'^2 - 16 x is a
+		 square. */
+		 
+	      mpz_mul (y, y, y);
+	      mpz_submul_ui (y, x, 16);
+	      if (mpz_perfect_square_p (y))
+		continue;
+	    }
+	}
+
+      /* If we passed all the tests, we have found a prime. */
+      break;
     }
   mpz_clear (r_min);
   mpz_clear (r_range);
   mpz_clear (pm1);
   mpz_clear (a);
+
+  if (need_square_test)
+    {
+      mpz_clear (x);
+      mpz_clear (y);
+      mpz_clear (p04);
+    }
+  if (q)
+    mpz_clear (e);
 }
 
 /* Generate random prime of a given size. Maurer's algorithm (Alg.
-- 
GitLab