/*============================================================================== | | File Name: | | Primpoly.c | | Description: | | Compute primitive polynomials of degree n modulo p. | | Functions: | | main Main driving routine. | | LEGAL | | Primpoly Version 16.2 - A Program for Computing Primitive Polynomials. | Copyright (C) 1999-2024 by Sean Erik O'Connor. All Rights Reserved. | | This program is free software: you can redistribute it and/or modify | it under the terms of the GNU General Public License as published by | the Free Software Foundation, either version 3 of the License, or | (at your option) any later version. | | This program is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU General Public License | along with this program. If not, see . | | The author's address is seanerikoconnor!AT!gmail!DOT!com | with the !DOT! replaced by . and the !AT! replaced by @ | ==============================================================================*/ /*------------------------------------------------------------------------------ | Include Files | ------------------------------------------------------------------------------*/ #include #include #include #include #include "Primpoly.h" /*============================================================================== | main | ================================================================================ DESCRIPTION Program for finding a primitive polynomial of degree n modulo p for use in generating PN sequences and finite fields for error control coding. INPUT Run the program by typing $ Primpoly p n OUTPUT You will get an nth degree primitive polynomial modulo p. EXAMPLE CALLING SEQUENCE Let's find a primitive polynomial of degree 18, modulo the prime 11. After a few seconds, even on a slow PC, we get: $ primpoly -s 5 20 Primpoly Version 16.2 - A Program for Computing Primitive Polynomials. Copyright (C) 1999-2024 by Sean Erik O'Connor. All Rights Reserved. Primpoly comes with ABSOLUTELY NO WARRANTY; for details see the GNU General Public License. This is free software, and you are welcome to redistribute it under certain conditions; see the GNU General Public License for details. Factoring r = 23841857910156 into 2^2 3 11 13 41 71 521 9161 Total number of primitive polynomials = 1280348160000. Begin testing... Primitive polynomial modulo 5 of degree 20 x ^ 20 + x ^ 2 + 2 x + 3 +--------- Statistics ---------------------------- | | Total num. degree 20 polynomials mod 5 : 95367431640625 | Actually tested : 39 | Const. coeff. was primitive root : 16 | Free of linear factors : 5 | Irreducible or irred. to power : 3 | Had order r (x^r = integer) : 1 | Passed const. coeff. test : 1 | Had order m (x^m != integer) : 1 | +------------------------------------------------- METHOD Described in detail in my web pages at http://www.seanerikoconnor.freeservers.com BUGS -------------------------------------------------------------------------------- | Function Call | ------------------------------------------------------------------------------*/ int main( int argc, char * argv[] ) { /*------------------------------------------------------------------------------ | Local Variables | ------------------------------------------------------------------------------*/ int n, /* Degree of the primitive polynomial f(x) to be found, n >= 2. */ p ; /* Modulo p arithmetic on the polynomial coefficients, p >= 2. */ bigint max_p_to_n = MAXPTON, /* Maximum value of p ^ n. */ max_num_poly, /* p ^ n, the number of polynomials to test for primitivity. */ num_poly = 0, /* Number of polynomials tested so far. */ r, /* The number (p ^ n - 1)/(p - 1). */ primes[ MAXNUMPRIMEFACTORS ], /* The distinct prime factors of r. */ prim_poly_count = 0, /* Counter for primitive polynomials found. */ num_prim_poly = 0 ; /* Total number of possible primitive polynomials. */ int count[ MAXNUMPRIMEFACTORS ], /* ... and their multiplicities. */ i, /* Prime index. */ prime_count, /* Primes are stored in array locations 0 through prime_count. */ f[ MAXDEGPOLY + 1 ], /* Coefficients of the polynomial f(x) which we test for primitivity. */ a = 0, /* Integer in the order r test. */ is_primitive_poly = NO, /* Equal to YES as soon as a primitive polynomial is found. */ num_free_of_linear_factors = 0,/* The number of polynomials which have no linear factors. */ num_const_coeff_prim_root = 0, /* Number of polynomials whose constant is a primitive root of p. */ num_passing_const_coeff_test = 0, /* Number of polynomials whose constant term passes a consistency check. */ num_irred_to_power = 0, /* Number of polynomials which are of the form irreducible poly to a power >= 1.*/ num_order_m = 0, num_order_r = 0, /* The number of polynomials which pass the order_m and order_r tests. */ stopTesting = NO, /* When to stop testing polynomials for primitivity. */ testPolynomialForPrimitivity = NO, /* Test a given input polnomial for primitivity? */ testPolynomial[ MAXDEGPOLY + 1 ], /* Coefficients of the test polynomial. */ listAllPrimitivePolynomials = NO, /* Print ALL primitive polynomials? */ printStatistics = NO, /* Print statistics? */ printHelp = NO, /* Print help information? */ selfCheck = NO, /* Do a self-check? Time consuming! */ /* x ^ n , ... , x ^ 2n-2 (mod f(x), p) */ power_table[ MAXDEGPOLY - 1 ] [ MAXDEGPOLY ] ; char outputFormat[ _MAX_PATH ] ; /* Formatting for printf's (used only when printing bigints) */ char * legalNotice = { "\n" "Primpoly Version 16.2 - A Program for Computing Primitive Polynomials.\n" "Copyright (C) 1999-2024 by Sean Erik O'Connor. All Rights Reserved.\n" "\n" "Primpoly comes with ABSOLUTELY NO WARRANTY; for details see the\n" "GNU General Public License. This is free software, and you are welcome\n" "to redistribute it under certain conditions; see the GNU General Public License\n" "for details.\n\n" } ; char * help = { "This program generates a primitive polynomial of degree n modulo p.\n\n" "Usage: primpoly p n\n\n" "Example: primpoly 2 4 \n" " generates the fourth degree polynomial\n\n" " x ^ 4 + x + 1, whose coefficients use modulo 2 arithmetic.\n\n" "Primitive polynomials find many uses in mathematics and communications \n" "engineering:\n" " * Generation of pseudonoise (PN) sequences for spread spectrum\n" " communications and chip fault testing.\n" " * Generation of CRC and Hamming codes.\n" " * Generation of Galois (finite) fields for use in decoding Reed-Solomon\n" " and BCH error correcting codes.\n\n" "Options:\n" " pp -c 2 4\n" " does an addtional time consuming double check on the primitivity.\n" " pp -s 2 4\n" " prints search statistics.\n" " pp -a 2 4\n" " lists ALL primitive polynomials of degree 4 modulo 2.\n" "\n\n" } ; /*------------------------------------------------------------------------------ | Function Body | ------------------------------------------------------------------------------*/ /* Show the legal notice first. */ printf( "%s", legalNotice ) ; /* Read the parameters p and n from the command line. Return with an error message if there are an incorrect number of inputs on the command line, or if p and n are out of bounds. */ parse_command_line( argc, argv, &testPolynomialForPrimitivity, &listAllPrimitivePolynomials, &printStatistics, &printHelp, &selfCheck, &p, &n, testPolynomial ) ; if (printHelp) { printf( "%s", help ) ; exit( 1 ) ; } if (p < 2) { printf( "ERROR: p must be 2 or more.\n\n" ) ; exit( 1 ) ; } if (n > MAXDEGPOLY || n < 2) { printf( "ERROR: n must be between 2 and %d\n\n", MAXDEGPOLY ) ; exit( 1 ) ; } /* Check to see if p is a prime. */ if (!is_almost_surely_prime( p )) { printf( "ERROR: p must be a prime number.\n\n" ) ; exit( 1 ) ; } /* n Return if p > MAXPTON because then we'll exceed the computer integer precision. */ if (n * log( (double) p ) > log( (double) (sbigint) max_p_to_n )) { printf( "ERROR: p to the nth power must be smaller than %llu\n\n", MAXPTON ) ; exit( 1 ) ; } /* n n p - 1 Compute p and r = ------. p - 1 */ max_num_poly = power( p, n ) ; r = (max_num_poly - 1) / (p - 1) ; /* Factor r into distinct primes. */ if (printStatistics) { sprintf( outputFormat, "%s%s%s", "\nFactoring r = ", bigintOutputFormat, " into\n " ) ; printf( outputFormat, r ) ; } prime_count = factor( r, primes, count ) ; if (printStatistics) { for (i = 0 ; i <= prime_count ; ++i) { if (count[ i ] == 1) { sprintf( outputFormat, "%s ", bigintOutputFormat ) ; printf( outputFormat, primes[ i ] ) ; } else { sprintf( outputFormat, "%s%s", bigintOutputFormat, "^%d " ) ; printf( outputFormat, primes[ i ], count[ i ] ) ; } } printf( "\n\n" ) ; } /* n Initialize f(x) to x + (-1). Then, when f(x) passes through function n next_trial_poly for the first time, it will have the correct value, x */ initial_trial_poly( f, n ) ; if (printStatistics || listAllPrimitivePolynomials) { sprintf( outputFormat, "%s%s%s", "Total number of primitive polynomials = ", bigintOutputFormat, ". Begin testing...\n\n" ) ; num_prim_poly = EulerPhi( power( p, n ) - 1 ) / n ; printf( outputFormat, num_prim_poly ) ; } /* Generate and test all possible n th degree, monic, modulo p polynomials f(x). A polynomial is primitive if passes all the tests successfully. */ do { next_trial_poly( f, n, p ) ; /* Try another polynomal. */ ++num_poly ; #ifdef DEBUG_PP_PRIMPOLY printf( "\nNext trial polynomial: " ) ; write_poly( f, n ) ; printf( "\n" ) ; #endif /* n 2n-2 Precompute the powers x , ..., x (mod f(x), p) for use in all later computations. */ construct_power_table( power_table, f, n, p ) ; /* Constant coefficient of f(x) * (-1)^n must be a primitive root of p. */ if (const_coeff_is_primitive_root( f, n, p )) { ++num_const_coeff_prim_root ; #ifdef DEBUG_PP_PRIMPOLY printf( "Coefficient of polynomial is primitive root.\n" ) ; #endif /* f(x) can't have any linear factors. */ if (!linear_factor( f, n, p )) { ++num_free_of_linear_factors ; #ifdef DEBUG_PP_PRIMPOLY printf( "Free of linear factors.\n" ) ; #endif /* f(x) can't have two or more distinct irreducible factors. */ if (!has_multi_irred_factors( power_table, n, p )) { ++num_irred_to_power ; #ifdef DEBUG_PP_PRIMPOLY printf( "Has one unique irreducible factor.\n" ) ; #endif /* x^r (mod f(x), p) = a must be an integer. */ if (order_r( power_table, n, p, r, &a )) { ++num_order_r ; #ifdef DEBUG_PP_PRIMPOLY printf( "Passes the order r test.\n" ) ; #endif /* Const coeff. of f(x)*(-1)^n must equal a mod p. */ if (const_coeff_test( f, n, p, a )) { ++num_passing_const_coeff_test ; #ifdef DEBUG_PP_PRIMPOLY printf( "Passes the constant coefficient test.\n" ) ; #endif /* x^m != integer for all m = r / q, q a prime divisor of r. */ if (order_m( power_table, n, p, r, primes, prime_count )) { ++num_order_m ; is_primitive_poly = YES ; #ifdef DEBUG_PP_PRIMPOLY printf( "Passes the order m tests.\n" ) ; #endif if (listAllPrimitivePolynomials) { printf( "\n\nPrimitive polynomial " ) ; sprintf( outputFormat, "%s of %s ", bigintOutputFormat, bigintOutputFormat ) ; printf( outputFormat, ++prim_poly_count, num_prim_poly ) ; printf( "modulo %d of degree %d\n\n", p, n ) ; write_poly( f, n ) ; printf( "\n\n" ) ; } } } /* end const coeff test */ } /* end order r */ } /* end can't determine if reducible */ } /* end no linear factors */ } /* end constant coefficient primitive. */ /* Stop when we've either checked all possible polynomials or we've not been asked to list all and found the first primtive one. */ stopTesting = (num_poly > max_num_poly) || (!listAllPrimitivePolynomials && is_primitive_poly) ; } while( !stopTesting ) ; printf( "\n\n" ) ; /* Report on success or failure. */ if (listAllPrimitivePolynomials) ; /* We're done */ else if (is_primitive_poly) { printf( "\n\nPrimitive polynomial modulo %d of degree %d\n\n", p, n ) ; write_poly( f, n ) ; printf( "\n\n" ) ; } else { printf( "Internal error: \n" "Tested all possible polynomials (%llu), but failed\n" "to find a primitive polynomial.\n" "Please let the author know by e-mail.\n", max_num_poly ) ; exit( 1 ) ; } /* Print the statistics of the primitivity tests. */ if (printStatistics) { printf( "+--------- Statistics -----------------------------------------------------------------\n" ) ; printf( "|\n" ) ; sprintf( outputFormat, "%s%s%s", "| Total num. degree %3d polynomials mod %3d : ", bigintOutputFormat, "\n" ) ; printf( outputFormat, n, p, max_num_poly ) ; sprintf( outputFormat, "%s%s%s", "| Actually tested : ", bigintOutputFormat, "\n" ) ; printf( outputFormat, num_poly ) ; printf( "| Const. coeff. was primitive root : %10d\n", num_const_coeff_prim_root ) ; printf( "| Free of linear factors : %10d\n", num_free_of_linear_factors ) ; printf( "| Irreducible or irred. to power : %10d\n", num_irred_to_power ) ; printf( "| Had order r (x^r = integer) : %10d\n", num_order_r ) ; printf( "| Passed const. coeff. test : %10d\n", num_passing_const_coeff_test ) ; printf( "| Had order m (x^m != integer) : %10d\n", num_order_m ) ; printf( "|\n" ) ; printf( "+--------------------------------------------------------------------------------------\n" ) ; } /* Confirm f(x) is primitive using a different, but extremely slow test for primitivity. Disabled when we list all primitive polynomials. */ if (selfCheck && !listAllPrimitivePolynomials) { printf( "\nConfirming polynomial is primitive with an independent check.\n" "Warning: You may wait an impossibly long time!\n\n" ) ; if (maximal_order( f, n, p )) printf( " -Polynomial is confirmed to be primitive.\n\n" ) ; else { printf( "Internal error: \n" "Primitive polynomial confirmation test failed.\n" "Please let the author know by e-mail.\n\n" ) ; return 1 ; } } return 0 ; } /* ========================== end of function main ======================== */