| /* bigint_ext - external portion of large integer package |
| ** |
| ** Copyright © 2000 by Jef Poskanzer <jef@mail.acme.com>. |
| ** 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. |
| ** |
| ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| ** ANY EXPRESS 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 AUTHOR OR 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. |
| */ |
| |
| #include <sys/types.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <time.h> |
| |
| #include "bigint.h" |
| #include "low_primes.h" |
| |
| |
| bigint bi_0, bi_1, bi_2, bi_10, bi_m1, bi_maxint, bi_minint; |
| |
| |
| /* Forwards. */ |
| static void print_pos( FILE* f, bigint bi ); |
| |
| |
| bigint |
| str_to_bi( char* str ) |
| { |
| int sign; |
| bigint biR; |
| |
| sign = 1; |
| if ( *str == '-' ) |
| { |
| sign = -1; |
| ++str; |
| } |
| for ( biR = bi_0; *str >= '0' && *str <= '9'; ++str ) |
| biR = bi_int_add( bi_int_multiply( biR, 10 ), *str - '0' ); |
| if ( sign == -1 ) |
| biR = bi_negate( biR ); |
| return biR; |
| } |
| |
| |
| void |
| bi_print( FILE* f, bigint bi ) |
| { |
| if ( bi_is_negative( bi_copy( bi ) ) ) |
| { |
| putc( '-', f ); |
| bi = bi_negate( bi ); |
| } |
| print_pos( f, bi ); |
| } |
| |
| |
| bigint |
| bi_scan( FILE* f ) |
| { |
| int sign; |
| int c; |
| bigint biR; |
| |
| sign = 1; |
| c = getc( f ); |
| if ( c == '-' ) |
| sign = -1; |
| else |
| ungetc( c, f ); |
| |
| biR = bi_0; |
| for (;;) |
| { |
| c = getc( f ); |
| if ( c < '0' || c > '9' ) |
| break; |
| biR = bi_int_add( bi_int_multiply( biR, 10 ), c - '0' ); |
| } |
| |
| if ( sign == -1 ) |
| biR = bi_negate( biR ); |
| return biR; |
| } |
| |
| |
| static void |
| print_pos( FILE* f, bigint bi ) |
| { |
| if ( bi_compare( bi_copy( bi ), bi_10 ) >= 0 ) |
| print_pos( f, bi_int_divide( bi_copy( bi ), 10 ) ); |
| putc( bi_int_mod( bi, 10 ) + '0', f ); |
| } |
| |
| |
| int |
| bi_int_mod( bigint bi, int m ) |
| { |
| int r; |
| |
| if ( m <= 0 ) |
| { |
| (void) fprintf( stderr, "bi_int_mod: zero or negative modulus\n" ); |
| (void) kill( getpid(), SIGFPE ); |
| } |
| r = bi_int_rem( bi, m ); |
| if ( r < 0 ) |
| r += m; |
| return r; |
| } |
| |
| |
| bigint |
| bi_rem( bigint bia, bigint bim ) |
| { |
| return bi_subtract( |
| bia, bi_multiply( bi_divide( bi_copy( bia ), bi_copy( bim ) ), bim ) ); |
| } |
| |
| |
| bigint |
| bi_mod( bigint bia, bigint bim ) |
| { |
| bigint biR; |
| |
| if ( bi_compare( bi_copy( bim ), bi_0 ) <= 0 ) |
| { |
| (void) fprintf( stderr, "bi_mod: zero or negative modulus\n" ); |
| (void) kill( getpid(), SIGFPE ); |
| } |
| biR = bi_rem( bia, bi_copy( bim ) ); |
| if ( bi_is_negative( bi_copy( biR ) ) ) |
| biR = bi_add( biR, bim ); |
| else |
| bi_free( bim ); |
| return biR; |
| } |
| |
| |
| bigint |
| bi_square( bigint bi ) |
| { |
| bigint biR; |
| |
| biR = bi_multiply( bi_copy( bi ), bi_copy( bi ) ); |
| bi_free( bi ); |
| return biR; |
| } |
| |
| |
| bigint |
| bi_power( bigint bi, bigint biexp ) |
| { |
| bigint biR; |
| |
| if ( bi_is_negative( bi_copy( biexp ) ) ) |
| { |
| (void) fprintf( stderr, "bi_power: negative exponent\n" ); |
| (void) kill( getpid(), SIGFPE ); |
| } |
| biR = bi_1; |
| for (;;) |
| { |
| if ( bi_is_odd( bi_copy( biexp ) ) ) |
| biR = bi_multiply( biR, bi_copy( bi ) ); |
| biexp = bi_half( biexp ); |
| if ( bi_compare( bi_copy( biexp ), bi_0 ) <= 0 ) |
| break; |
| bi = bi_multiply( bi_copy( bi ), bi ); |
| } |
| bi_free( bi ); |
| bi_free( biexp ); |
| return biR; |
| } |
| |
| |
| bigint |
| bi_factorial( bigint bi ) |
| { |
| bigint biR; |
| |
| biR = bi_1; |
| while ( bi_compare( bi_copy( bi ), bi_1 ) > 0 ) |
| { |
| biR = bi_multiply( biR, bi_copy( bi ) ); |
| bi = bi_int_subtract( bi, 1 ); |
| } |
| bi_free( bi ); |
| return biR; |
| } |
| |
| |
| int |
| bi_is_even( bigint bi ) |
| { |
| return ! bi_is_odd( bi ); |
| } |
| |
| |
| bigint |
| bi_mod_power( bigint bi, bigint biexp, bigint bim ) |
| { |
| int invert; |
| bigint biR; |
| |
| invert = 0; |
| if ( bi_is_negative( bi_copy( biexp ) ) ) |
| { |
| biexp = bi_negate( biexp ); |
| invert = 1; |
| } |
| |
| biR = bi_1; |
| for (;;) |
| { |
| if ( bi_is_odd( bi_copy( biexp ) ) ) |
| biR = bi_mod( bi_multiply( biR, bi_copy( bi ) ), bi_copy( bim ) ); |
| biexp = bi_half( biexp ); |
| if ( bi_compare( bi_copy( biexp ), bi_0 ) <= 0 ) |
| break; |
| bi = bi_mod( bi_multiply( bi_copy( bi ), bi ), bi_copy( bim ) ); |
| } |
| bi_free( bi ); |
| bi_free( biexp ); |
| |
| if ( invert ) |
| biR = bi_mod_inverse( biR, bim ); |
| else |
| bi_free( bim ); |
| return biR; |
| } |
| |
| |
| bigint |
| bi_mod_inverse( bigint bi, bigint bim ) |
| { |
| bigint gcd, mul0, mul1; |
| |
| gcd = bi_egcd( bi_copy( bim ), bi, &mul0, &mul1 ); |
| |
| /* Did we get gcd == 1? */ |
| if ( ! bi_is_one( gcd ) ) |
| { |
| (void) fprintf( stderr, "bi_mod_inverse: not relatively prime\n" ); |
| (void) kill( getpid(), SIGFPE ); |
| } |
| |
| bi_free( mul0 ); |
| return bi_mod( mul1, bim ); |
| } |
| |
| |
| /* Euclid's algorithm. */ |
| bigint |
| bi_gcd( bigint bim, bigint bin ) |
| { |
| bigint bit; |
| |
| bim = bi_abs( bim ); |
| bin = bi_abs( bin ); |
| while ( ! bi_is_zero( bi_copy( bin ) ) ) |
| { |
| bit = bi_mod( bim, bi_copy( bin ) ); |
| bim = bin; |
| bin = bit; |
| } |
| bi_free( bin ); |
| return bim; |
| } |
| |
| |
| /* Extended Euclidean algorithm. */ |
| bigint |
| bi_egcd( bigint bim, bigint bin, bigint* bim_mul, bigint* bin_mul ) |
| { |
| bigint a0, b0, c0, a1, b1, c1, q, t; |
| |
| if ( bi_is_negative( bi_copy( bim ) ) ) |
| { |
| bigint biR; |
| |
| biR = bi_egcd( bi_negate( bim ), bin, &t, bin_mul ); |
| *bim_mul = bi_negate( t ); |
| return biR; |
| } |
| if ( bi_is_negative( bi_copy( bin ) ) ) |
| { |
| bigint biR; |
| |
| biR = bi_egcd( bim, bi_negate( bin ), bim_mul, &t ); |
| *bin_mul = bi_negate( t ); |
| return biR; |
| } |
| |
| a0 = bi_1; b0 = bi_0; c0 = bim; |
| a1 = bi_0; b1 = bi_1; c1 = bin; |
| |
| while ( ! bi_is_zero( bi_copy( c1 ) ) ) |
| { |
| q = bi_divide( bi_copy( c0 ), bi_copy( c1 ) ); |
| t = a0; |
| a0 = bi_copy( a1 ); |
| a1 = bi_subtract( t, bi_multiply( bi_copy( q ), a1 ) ); |
| t = b0; |
| b0 = bi_copy( b1 ); |
| b1 = bi_subtract( t, bi_multiply( bi_copy( q ), b1 ) ); |
| t = c0; |
| c0 = bi_copy( c1 ); |
| c1 = bi_subtract( t, bi_multiply( bi_copy( q ), c1 ) ); |
| bi_free( q ); |
| } |
| |
| bi_free( a1 ); |
| bi_free( b1 ); |
| bi_free( c1 ); |
| *bim_mul = a0; |
| *bin_mul = b0; |
| return c0; |
| } |
| |
| |
| bigint |
| bi_lcm( bigint bia, bigint bib ) |
| { |
| bigint biR; |
| |
| biR = bi_divide( |
| bi_multiply( bi_copy( bia ), bi_copy( bib ) ), |
| bi_gcd( bi_copy( bia ), bi_copy( bib ) ) ); |
| bi_free( bia ); |
| bi_free( bib ); |
| return biR; |
| } |
| |
| |
| /* The Jacobi symbol. */ |
| bigint |
| bi_jacobi( bigint bia, bigint bib ) |
| { |
| bigint biR; |
| |
| if ( bi_is_even( bi_copy( bib ) ) ) |
| { |
| (void) fprintf( stderr, "bi_jacobi: don't know how to compute Jacobi(n, even)\n" ); |
| (void) kill( getpid(), SIGFPE ); |
| } |
| |
| if ( bi_compare( bi_copy( bia ), bi_copy( bib ) ) >= 0 ) |
| return bi_jacobi( bi_mod( bia, bi_copy( bib ) ), bib ); |
| |
| if ( bi_is_zero( bi_copy( bia ) ) || bi_is_one( bi_copy( bia ) ) ) |
| { |
| bi_free( bib ); |
| return bia; |
| } |
| |
| if ( bi_compare( bi_copy( bia ), bi_2 ) == 0 ) |
| { |
| bi_free( bia ); |
| switch ( bi_int_mod( bib, 8 ) ) |
| { |
| case 1: case 7: |
| return bi_1; |
| case 3: case 5: |
| return bi_m1; |
| } |
| } |
| |
| if ( bi_is_even( bi_copy( bia ) ) ) |
| { |
| biR = bi_multiply( |
| bi_jacobi( bi_2, bi_copy( bib ) ), |
| bi_jacobi( bi_half( bia ), bi_copy( bib ) ) ); |
| bi_free( bib ); |
| return biR; |
| } |
| |
| if ( bi_int_mod( bi_copy( bia ), 4 ) == 3 && |
| bi_int_mod( bi_copy( bib ), 4 ) == 3 ) |
| return bi_negate( bi_jacobi( bib, bia ) ); |
| else |
| return bi_jacobi( bib, bia ); |
| } |
| |
| |
| /* Probabalistic prime checking. */ |
| int |
| bi_is_probable_prime( bigint bi, int certainty ) |
| { |
| int i, p; |
| bigint bim1; |
| |
| /* First do trial division by a list of small primes. This eliminates |
| ** many candidates. |
| */ |
| for ( i = 0; i < sizeof(low_primes)/sizeof(*low_primes); ++i ) |
| { |
| p = low_primes[i]; |
| switch ( bi_compare( int_to_bi( p ), bi_copy( bi ) ) ) |
| { |
| case 0: |
| bi_free( bi ); |
| return 1; |
| case 1: |
| bi_free( bi ); |
| return 0; |
| } |
| if ( bi_int_mod( bi_copy( bi ), p ) == 0 ) |
| { |
| bi_free( bi ); |
| return 0; |
| } |
| } |
| |
| /* Now do the probabilistic tests. */ |
| bim1 = bi_int_subtract( bi_copy( bi ), 1 ); |
| for ( i = 0; i < certainty; ++i ) |
| { |
| bigint a, j, jac; |
| |
| /* Pick random test number. */ |
| a = bi_random( bi_copy( bi ) ); |
| |
| /* Decide whether to run the Fermat test or the Solovay-Strassen |
| ** test. The Fermat test is fast but lets some composite numbers |
| ** through. Solovay-Strassen runs slower but is more certain. |
| ** So the compromise here is we run the Fermat test a couple of |
| ** times to quickly reject most composite numbers, and then do |
| ** the rest of the iterations with Solovay-Strassen so nothing |
| ** slips through. |
| */ |
| if ( i < 2 && certainty >= 5 ) |
| { |
| /* Fermat test. Note that this is not state of the art. There's a |
| ** class of numbers called Carmichael numbers which are composite |
| ** but look prime to this test - it lets them slip through no |
| ** matter how many reps you run. However, it's nice and fast so |
| ** we run it anyway to help quickly reject most of the composites. |
| */ |
| if ( ! bi_is_one( bi_mod_power( bi_copy( a ), bi_copy( bim1 ), bi_copy( bi ) ) ) ) |
| { |
| bi_free( bi ); |
| bi_free( bim1 ); |
| bi_free( a ); |
| return 0; |
| } |
| } |
| else |
| { |
| /* GCD test. This rarely hits, but we need it for Solovay-Strassen. */ |
| if ( ! bi_is_one( bi_gcd( bi_copy( bi ), bi_copy( a ) ) ) ) |
| { |
| bi_free( bi ); |
| bi_free( bim1 ); |
| bi_free( a ); |
| return 0; |
| } |
| |
| /* Solovay-Strassen test. First compute pseudo Jacobi. */ |
| j = bi_mod_power( |
| bi_copy( a ), bi_half( bi_copy( bim1 ) ), bi_copy( bi ) ); |
| if ( bi_compare( bi_copy( j ), bi_copy( bim1 ) ) == 0 ) |
| { |
| bi_free( j ); |
| j = bi_m1; |
| } |
| |
| /* Now compute real Jacobi. */ |
| jac = bi_jacobi( bi_copy( a ), bi_copy( bi ) ); |
| |
| /* If they're not equal, the number is definitely composite. */ |
| if ( bi_compare( j, jac ) != 0 ) |
| { |
| bi_free( bi ); |
| bi_free( bim1 ); |
| bi_free( a ); |
| return 0; |
| } |
| } |
| |
| bi_free( a ); |
| } |
| |
| bi_free( bim1 ); |
| |
| bi_free( bi ); |
| return 1; |
| } |
| |
| |
| bigint |
| bi_generate_prime( int bits, int certainty ) |
| { |
| bigint bimo2, bip; |
| int i, inc = 0; |
| |
| bimo2 = bi_power( bi_2, int_to_bi( bits - 1 ) ); |
| for (;;) |
| { |
| bip = bi_add( bi_random( bi_copy( bimo2 ) ), bi_copy( bimo2 ) ); |
| /* By shoving the candidate numbers up to the next highest multiple |
| ** of six plus or minus one, we pre-eliminate all multiples of |
| ** two and/or three. |
| */ |
| switch ( bi_int_mod( bi_copy( bip ), 6 ) ) |
| { |
| case 0: inc = 4; bip = bi_int_add( bip, 1 ); break; |
| case 1: inc = 4; break; |
| case 2: inc = 2; bip = bi_int_add( bip, 3 ); break; |
| case 3: inc = 2; bip = bi_int_add( bip, 2 ); break; |
| case 4: inc = 2; bip = bi_int_add( bip, 1 ); break; |
| case 5: inc = 2; break; |
| } |
| /* Starting from the generated random number, check a bunch of |
| ** numbers in sequence. This is just to avoid calls to bi_random(), |
| ** which is more expensive than a simple add. |
| */ |
| for ( i = 0; i < 1000; ++i ) /* arbitrary */ |
| { |
| if ( bi_is_probable_prime( bi_copy( bip ), certainty ) ) |
| { |
| bi_free( bimo2 ); |
| return bip; |
| } |
| bip = bi_int_add( bip, inc ); |
| inc = 6 - inc; |
| } |
| /* We ran through the whole sequence and didn't find a prime. |
| ** Shrug, just try a different random starting point. |
| */ |
| bi_free( bip ); |
| } |
| } |