From 711507a72609dc2df0b4c876f6d7505443dd719a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 22 Nov 2013 17:35:28 +0100 Subject: [PATCH 1/6] gen_prime: ensure X = 3 mod 4 always (2x speed-up) --- library/bignum.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 2a97a5902..7fac5fafb 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1969,9 +1969,9 @@ int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) goto cleanup; - MPI_CHK( mpi_add_int( &Y, X, 1 ) ); - MPI_CHK( mpi_add_int( X, X, 2 ) ); - MPI_CHK( mpi_shift_r( &Y, 1 ) ); + /* Keep X = 3 mod 4 */ + MPI_CHK( mpi_add_int( X, X, 4 ) ); + MPI_CHK( mpi_add_int( &Y, &Y, 2 ) ); } } From 0160eacc822dd619ee7ac477590495102efbede8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 22 Nov 2013 17:54:59 +0100 Subject: [PATCH 2/6] gen_prime: ensure X = 2 mod 3 -> 2.5x speedup --- include/polarssl/bignum.h | 2 +- library/bignum.c | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h index 9bed027d9..b63a24242 100644 --- a/include/polarssl/bignum.h +++ b/include/polarssl/bignum.h @@ -58,7 +58,7 @@ typedef UINT64 uint64_t; #define POLARSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ #define POLARSSL_ERR_MPI_MALLOC_FAILED -0x0010 /**< Memory allocation failed. */ -#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup +#define MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) /* * Maximum size MPIs are allowed to grow to in number of limbs. diff --git a/library/bignum.c b/library/bignum.c index 7fac5fafb..c81ee5bf9 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1923,6 +1923,7 @@ int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, { int ret; size_t k, n; + t_uint r; mpi Y; if( nbits < 3 || nbits > POLARSSL_MPI_MAX_BITS ) @@ -1952,7 +1953,19 @@ int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, } else { - MPI_CHK( mpi_sub_int( &Y, X, 1 ) ); + /* + * An necessary condition for Y and X = 2Y + 1 to be prime + * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). + * Make sure it is satisfied, while keeping X = 3 mod 4 + */ + MPI_CHK( mpi_mod_int( &r, X, 3 ) ); + if( r == 0 ) + MPI_CHK( mpi_add_int( X, X, 8 ) ); + else if( r == 1 ) + MPI_CHK( mpi_add_int( X, X, 4 ) ); + + /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ + MPI_CHK( mpi_copy( &Y, X ) ); MPI_CHK( mpi_shift_r( &Y, 1 ) ); while( 1 ) @@ -1969,9 +1982,13 @@ int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) goto cleanup; - /* Keep X = 3 mod 4 */ - MPI_CHK( mpi_add_int( X, X, 4 ) ); - MPI_CHK( mpi_add_int( &Y, &Y, 2 ) ); + /* + * Next candidates. We want to preserve + * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) + * so up Y by 6 and X by 12. + */ + MPI_CHK( mpi_add_int( X, X, 12 ) ); + MPI_CHK( mpi_add_int( &Y, &Y, 6 ) ); } } From 378fb4b70ac26945f770c2a148d8aaf6f4ea1575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 22 Nov 2013 18:39:18 +0100 Subject: [PATCH 3/6] Split mpi_is_prime() and make its first arg const --- include/polarssl/bignum.h | 2 +- library/bignum.c | 86 +++++++++++++++++++++----------- tests/suites/test_suite_mpi.data | 12 ++++- 3 files changed, 69 insertions(+), 31 deletions(-) diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h index b63a24242..4e6cc8a95 100644 --- a/include/polarssl/bignum.h +++ b/include/polarssl/bignum.h @@ -653,7 +653,7 @@ int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime */ -int mpi_is_prime( mpi *X, +int mpi_is_prime( const mpi *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); diff --git a/library/bignum.c b/library/bignum.c index c81ee5bf9..1fea9b6d0 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1797,40 +1797,27 @@ static const int small_prime[] = }; /* - * Miller-Rabin primality test (HAC 4.24) + * Small divisors test (X must be positive) + * + * Return values: + * 0: no small factor (possible prime, more tests needed) + * 1: certain prime + * POLARSSL_ERR_MPI_NOT_ACCEPTABLE: certain non-prime + * other negative: error */ -int mpi_is_prime( mpi *X, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) +static int mpi_check_small_factors( const mpi *X ) { - int ret, xs; - size_t i, j, n, s; - mpi W, R, T, A, RR; + int ret = 0; + size_t i; + t_uint r; - if( mpi_cmp_int( X, 0 ) == 0 || - mpi_cmp_int( X, 1 ) == 0 ) - return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); - - if( mpi_cmp_int( X, 2 ) == 0 ) - return( 0 ); - - mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); - mpi_init( &RR ); - - xs = X->s; X->s = 1; - - /* - * test trivial factors first - */ if( ( X->p[0] & 1 ) == 0 ) return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); for( i = 0; small_prime[i] > 0; i++ ) { - t_uint r; - if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) - return( 0 ); + return( 1 ); MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); @@ -1838,6 +1825,24 @@ int mpi_is_prime( mpi *X, return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); } +cleanup: + return( ret ); +} + +/* + * Miller-Rabin pseudo-primality test (HAC 4.24) + */ +static int mpi_miller_rabin( const mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t i, j, n, s; + mpi W, R, T, A, RR; + + mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); + mpi_init( &RR ); + /* * W = |X| - 1 * R = W >> lsb( W ) @@ -1905,15 +1910,40 @@ int mpi_is_prime( mpi *X, } cleanup: - - X->s = xs; - mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A ); mpi_free( &RR ); return( ret ); } +/* + * Pseudo-primality test: small factors, then Miller-Rabin + */ +int mpi_is_prime( const mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + const mpi XX = { 1, X->n, X->p }; /* Abs(X) */ + + if( mpi_cmp_int( &XX, 0 ) == 0 || + mpi_cmp_int( &XX, 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + if( mpi_cmp_int( &XX, 2 ) == 0 ) + return( 0 ); + + if( ( ret = mpi_check_small_factors( &XX ) ) != 0 ) + { + if( ret == 1 ) + return( 0 ); + + return( ret ); + } + + return( mpi_miller_rabin( &XX, f_rng, p_rng ) ); +} + /* * Prime number generation */ diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data index 924f364d9..859a38e22 100644 --- a/tests/suites/test_suite_mpi.data +++ b/tests/suites/test_suite_mpi.data @@ -504,11 +504,19 @@ Base test mpi_is_prime #8 depends_on:POLARSSL_GENPRIME mpi_is_prime:10:"47":0 -Test mpi_is_prime #1 +Test mpi_is_prime #1a +depends_on:POLARSSL_GENPRIME +mpi_is_prime:10:"83726728883146151979668243326097049289208482987685965276439157162337476477581":POLARSSL_ERR_MPI_NOT_ACCEPTABLE + +Test mpi_is_prime #1b +depends_on:POLARSSL_GENPRIME +mpi_is_prime:10:"81248637410584921454869308488899267096530643632730258201256092582281263244641":POLARSSL_ERR_MPI_NOT_ACCEPTABLE + +Test mpi_is_prime #2a depends_on:POLARSSL_GENPRIME mpi_is_prime:10:"827131507221654563937832686696200995595835694437983658840870036586124168186967796809117749047430768825822857042432722828096779098498192459819306321073968735177531164565305635281198148032612029767584644305912099":0 -Test mpi_is_prime #2 +Test mpi_is_prime #2b depends_on:POLARSSL_GENPRIME mpi_is_prime:10:"827131507221654563937832686696200995595835694437983658840870036586124168186967796809117749047430768825822857042432722828096779098498192459819306321073968735177531164565305635281198148032612029767584644305912001":POLARSSL_ERR_MPI_NOT_ACCEPTABLE From ddf7615d49a98f9bce8008970a55a39f345ffdbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 22 Nov 2013 19:58:22 +0100 Subject: [PATCH 4/6] gen_prime: check small primes early (3x speed-up) --- library/bignum.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 1fea9b6d0..dd23195d3 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -2000,20 +2000,23 @@ int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, while( 1 ) { - if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 ) + /* + * First, check small factors for X and Y + * before doing Miller-Rabin on any of them + */ + if( ( ret = mpi_check_small_factors( X ) ) == 0 && + ( ret = mpi_check_small_factors( &Y ) ) == 0 && + ( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 && + ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 ) { - if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 ) - break; - - if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) - goto cleanup; + break; } if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) goto cleanup; /* - * Next candidates. We want to preserve + * Next candidates. We want to preserve Y = (X-1) / 2 and * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) * so up Y by 6 and X by 12. */ From 5e1e61124a1d9192453501831577a90c4be7ced1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 22 Nov 2013 21:16:10 +0100 Subject: [PATCH 5/6] Insert warning about time in dh_genprime --- programs/pkey/dh_genprime.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/programs/pkey/dh_genprime.c b/programs/pkey/dh_genprime.c index 2089fb632..f51465af5 100644 --- a/programs/pkey/dh_genprime.c +++ b/programs/pkey/dh_genprime.c @@ -74,6 +74,8 @@ int main( int argc, char *argv[] ) printf( " predefined DHM parameters from dhm.h instead!\n\n" ); printf( "============================================================\n\n" ); + printf( " ! Generating large primes may take minutes!\n" ); + printf( "\n . Seeding the random number generator..." ); fflush( stdout ); From 45f457d8725f6514aed22104432bc2da125e7e38 Mon Sep 17 00:00:00 2001 From: Paul Bakker Date: Mon, 25 Nov 2013 14:26:52 +0100 Subject: [PATCH 6/6] Reverted API change for mpi_is_prime() --- include/polarssl/bignum.h | 2 +- library/bignum.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h index 4e6cc8a95..b63a24242 100644 --- a/include/polarssl/bignum.h +++ b/include/polarssl/bignum.h @@ -653,7 +653,7 @@ int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime */ -int mpi_is_prime( const mpi *X, +int mpi_is_prime( mpi *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); diff --git a/library/bignum.c b/library/bignum.c index dd23195d3..4de2e9a3e 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1919,7 +1919,7 @@ cleanup: /* * Pseudo-primality test: small factors, then Miller-Rabin */ -int mpi_is_prime( const mpi *X, +int mpi_is_prime( mpi *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) {