Use uniformly chosen witnesses for Miller-Rabin test
authorBodo Möller <bodo@openssl.org>
Mon, 3 Sep 2001 12:58:16 +0000 (12:58 +0000)
committerBodo Möller <bodo@openssl.org>
Mon, 3 Sep 2001 12:58:16 +0000 (12:58 +0000)
(by using new BN_pseudo_rand_range function)

CHANGES
crypto/bn/bn.h
crypto/bn/bn_prime.c
crypto/bn/bn_rand.c
doc/crypto/BN_rand.pod
doc/crypto/bn.pod

diff --git a/CHANGES b/CHANGES
index d5aa76976ea1aab9c23f0db5debbf8b6b4dd59a3..3a01e820dbbd30cba201feebbfdd1f095b751543 100644 (file)
--- a/CHANGES
+++ b/CHANGES
          *) applies to 0.9.6a/0.9.6b/0.9.6c and 0.9.7
          +) applies to 0.9.7 only
 
          *) applies to 0.9.6a/0.9.6b/0.9.6c and 0.9.7
          +) applies to 0.9.7 only
 
+  *) Rabin-Miller test analyses assume uniformly distributed witnesses,
+     so use BN_pseudo_rand_range() instead of using BN_pseudo_rand()
+     followed by modular reduction.
+     [Bodo Moeller; pointed out by Adam Young <AYoung1@NCSUS.JNJ.COM>]
+
+  *) Add BN_pseudo_rand_range() with obvious functionality: BN_rand_range()
+     requivalent based on BN_pseudo_rand() instead of BN_rand().
+     [Bodo Moeller]
+
   +) Add a copy() function to EVP_MD.
      [Ben Laurie]
 
   +) Add a copy() function to EVP_MD.
      [Ben Laurie]
 
index 7e4234339bf5c2407777584a7cc7a4e8838de0e1..573666769f93f6a7810ad46fd7ba61745e0b8adc 100644 (file)
@@ -321,6 +321,7 @@ void        BN_CTX_end(BN_CTX *ctx);
 int     BN_rand(BIGNUM *rnd, int bits, int top,int bottom);
 int     BN_pseudo_rand(BIGNUM *rnd, int bits, int top,int bottom);
 int    BN_rand_range(BIGNUM *rnd, BIGNUM *range);
 int     BN_rand(BIGNUM *rnd, int bits, int top,int bottom);
 int     BN_pseudo_rand(BIGNUM *rnd, int bits, int top,int bottom);
 int    BN_rand_range(BIGNUM *rnd, BIGNUM *range);
+int    BN_pseudo_rand_range(BIGNUM *rnd, BIGNUM *range);
 int    BN_num_bits(const BIGNUM *a);
 int    BN_num_bits_word(BN_ULONG);
 BIGNUM *BN_new(void);
 int    BN_num_bits(const BIGNUM *a);
 int    BN_num_bits_word(BN_ULONG);
 BIGNUM *BN_new(void);
index b75e58c6ae244749f8bac1312cc616269f1eba39..5bfc0b682be598c32e52ab65d7ee98dae6cef60b 100644 (file)
@@ -226,12 +226,15 @@ int BN_is_prime_fasttest(const BIGNUM *a, int checks,
        BN_MONT_CTX *mont = NULL;
        const BIGNUM *A = NULL;
 
        BN_MONT_CTX *mont = NULL;
        const BIGNUM *A = NULL;
 
+       if (BN_cmp(a, BN_value_one) <= 0)
+               return 0;
+       
        if (checks == BN_prime_checks)
                checks = BN_prime_checks_for_size(BN_num_bits(a));
 
        /* first look for small factors */
        if (!BN_is_odd(a))
        if (checks == BN_prime_checks)
                checks = BN_prime_checks_for_size(BN_num_bits(a));
 
        /* first look for small factors */
        if (!BN_is_odd(a))
-               return(0);
+               return 0;
        if (do_trial_division)
                {
                for (i = 1; i < NUMPRIMES; i++)
        if (do_trial_division)
                {
                for (i = 1; i < NUMPRIMES; i++)
@@ -290,11 +293,8 @@ int BN_is_prime_fasttest(const BIGNUM *a, int checks,
        
        for (i = 0; i < checks; i++)
                {
        
        for (i = 0; i < checks; i++)
                {
-               if (!BN_pseudo_rand(check, BN_num_bits(A1), 0, 0))
+               if (!BN_pseudo_rand_range(check, A1))
                        goto err;
                        goto err;
-               if (BN_cmp(check, A1) >= 0)
-                       if (!BN_sub(check, check, A1))
-                               goto err;
                if (!BN_add_word(check, 1))
                        goto err;
                /* now 1 <= check < A */
                if (!BN_add_word(check, 1))
                        goto err;
                /* now 1 <= check < A */
index fb583fb358fcb990f5311ca2a6b7e345f89b14fb..b9ce9e5d3fb84fa819b40d4a35519ddd5a829d7b 100644 (file)
  * copied and put under another distribution licence
  * [including the GNU Public Licence.]
  */
  * copied and put under another distribution licence
  * [including the GNU Public Licence.]
  */
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
 
 #include <stdio.h>
 #include <time.h>
 
 #include <stdio.h>
 #include <time.h>
@@ -173,8 +226,9 @@ int     BN_bntest_rand(BIGNUM *rnd, int bits, int top, int bottom)
 
 
 /* random number r:  0 <= r < range */
 
 
 /* random number r:  0 <= r < range */
-int    BN_rand_range(BIGNUM *r, BIGNUM *range)
+static int bn_rand_range(int pseudo, BIGNUM *r, BIGNUM *range)
        {
        {
+       int (*bn_rand)(BIGNUM *, int, int, int) = pseudo ? BN_pseudo_rand : BN_rand;
        int n;
 
        if (range->neg || BN_is_zero(range))
        int n;
 
        if (range->neg || BN_is_zero(range))
@@ -194,7 +248,7 @@ int BN_rand_range(BIGNUM *r, BIGNUM *range)
                do
                        {
                        /* range = 11..._2, so each iteration succeeds with probability >= .75 */
                do
                        {
                        /* range = 11..._2, so each iteration succeeds with probability >= .75 */
-                       if (!BN_rand(r, n, -1, 0)) return 0;
+                       if (!bn_rand(r, n, -1, 0)) return 0;
                        }
                while (BN_cmp(r, range) >= 0);
                }
                        }
                while (BN_cmp(r, range) >= 0);
                }
@@ -204,7 +258,7 @@ int BN_rand_range(BIGNUM *r, BIGNUM *range)
                 * so  3*range (= 11..._2)  is exactly one bit longer than  range */
                do
                        {
                 * so  3*range (= 11..._2)  is exactly one bit longer than  range */
                do
                        {
-                       if (!BN_rand(r, n + 1, -1, 0)) return 0;
+                       if (!bn_rand(r, n + 1, -1, 0)) return 0;
                        /* If  r < 3*range,  use  r := r MOD range
                         * (which is either  r, r - range,  or  r - 2*range).
                         * Otherwise, iterate once more.
                        /* If  r < 3*range,  use  r := r MOD range
                         * (which is either  r, r - range,  or  r - 2*range).
                         * Otherwise, iterate once more.
@@ -222,3 +276,14 @@ int        BN_rand_range(BIGNUM *r, BIGNUM *range)
 
        return 1;
        }
 
        return 1;
        }
+
+
+int    BN_rand_range(BIGNUM *r, BIGNUM *range)
+       {
+       return bn_rand_range(0, r, range);
+       }
+
+int    BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range)
+       {
+       return bn_rand_range(1, r, range);
+       }
index cbae2fca9774ad92cbe66b0ab848d0a6fdf54d0b..ecd410f7f252400f41cd2ca14c99206bd92cbe34 100644 (file)
@@ -14,6 +14,8 @@ BN_rand, BN_pseudo_rand - generate pseudo-random number
 
  int BN_rand_range(BIGNUM *rnd, BIGNUM *range);
 
 
  int BN_rand_range(BIGNUM *rnd, BIGNUM *range);
 
+ int BN_pseudo_rand_range(BIGNUM *rnd, int bits, int top, int bottom);
+
 =head1 DESCRIPTION
 
 BN_rand() generates a cryptographically strong pseudo-random number of
 =head1 DESCRIPTION
 
 BN_rand() generates a cryptographically strong pseudo-random number of
@@ -31,6 +33,8 @@ protocols, but usually not for key generation etc.
 
 BN_rand_range() generates a cryptographically strong pseudo-random
 number B<rnd> in the range 0 <lt>= B<rnd> E<lt> B<range>.
 
 BN_rand_range() generates a cryptographically strong pseudo-random
 number B<rnd> in the range 0 <lt>= B<rnd> E<lt> B<range>.
+BN_pseudo_rand_range() does the same, but is based on BN_pseudo_rand(),
+and hence numbers generated by it are not necessarily unpredictable.
 
 The PRNG must be seeded prior to calling BN_rand() or BN_rand_range().
 
 
 The PRNG must be seeded prior to calling BN_rand() or BN_rand_range().
 
@@ -49,5 +53,6 @@ L<RAND_add(3)|RAND_add(3)>, L<RAND_bytes(3)|RAND_bytes(3)>
 BN_rand() is available in all versions of SSLeay and OpenSSL.
 BN_pseudo_rand() was added in OpenSSL 0.9.5. The B<top> == -1 case
 and the function BN_rand_range() were added in OpenSSL 0.9.6a.
 BN_rand() is available in all versions of SSLeay and OpenSSL.
 BN_pseudo_rand() was added in OpenSSL 0.9.5. The B<top> == -1 case
 and the function BN_rand_range() were added in OpenSSL 0.9.6a.
+BN_pseudo_rand_range() was added in OpenSSL 0.9.6c.
 
 =cut
 
 =cut
index cbe3bc704ff3be2a97a367959f1a06f40666d130..210dfeac08cdce4891d26d83f836121a1310d370 100644 (file)
@@ -69,6 +69,7 @@ bn - multiprecision integer arithmetics
  int BN_rand(BIGNUM *rnd, int bits, int top, int bottom);
  int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom);
  int BN_rand_range(BIGNUM *rnd, BIGNUM *range);
  int BN_rand(BIGNUM *rnd, int bits, int top, int bottom);
  int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom);
  int BN_rand_range(BIGNUM *rnd, BIGNUM *range);
+ int BN_pseudo_rand_range(BIGNUM *rnd, BIGNUM *range);
 
  BIGNUM *BN_generate_prime(BIGNUM *ret, int bits,int safe, BIGNUM *add,
          BIGNUM *rem, void (*callback)(int, int, void *), void *cb_arg);
 
  BIGNUM *BN_generate_prime(BIGNUM *ret, int bits,int safe, BIGNUM *add,
          BIGNUM *rem, void (*callback)(int, int, void *), void *cb_arg);