diff options
Diffstat (limited to 'vendor/gmp-6.3.0/mpz/millerrabin.c')
| -rw-r--r-- | vendor/gmp-6.3.0/mpz/millerrabin.c | 216 | 
1 files changed, 216 insertions, 0 deletions
| diff --git a/vendor/gmp-6.3.0/mpz/millerrabin.c b/vendor/gmp-6.3.0/mpz/millerrabin.c new file mode 100644 index 0000000..98c4d6a --- /dev/null +++ b/vendor/gmp-6.3.0/mpz/millerrabin.c @@ -0,0 +1,216 @@ +/* mpz_millerrabin(n,reps) -- An implementation of the probabilistic primality +   test found in Knuth's Seminumerical Algorithms book.  If the function +   mpz_millerrabin() returns 0 then n is not prime.  If it returns 1, then n is +   'probably' prime.  The probability of a false positive is (1/4)**reps, where +   reps is the number of internal passes of the probabilistic algorithm.  Knuth +   indicates that 25 passes are reasonable. + +   With the current implementation, the first 24 MR-tests are substituted by a +   Baillie-PSW probable prime test. + +   This implementation of the Baillie-PSW test was checked up to 2463*10^12, +   for smaller values no MR-test is performed, regardless of reps, and +   2 ("surely prime") is returned if the number was not proved composite. + +   If GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS is defined as non-zero, +   the code assumes that the Baillie-PSW test was checked up to 2^64. + +   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST +   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN +   FUTURE GNU MP RELEASES. + +Copyright 1991, 1993, 1994, 1996-2002, 2005, 2014, 2018-2022 Free +Software Foundation, Inc. + +Contributed by John Amanatides. +Changed to "BPSW, then Miller Rabin if required" by Marco Bodrato. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of either: + +  * the GNU Lesser General Public License as published by the Free +    Software Foundation; either version 3 of the License, or (at your +    option) any later version. + +or + +  * the GNU General Public License as published by the Free Software +    Foundation; either version 2 of the License, or (at your option) any +    later version. + +or both in parallel, as here. + +The GNU MP Library 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 copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library.  If not, +see https://www.gnu.org/licenses/.  */ + +#include "gmp-impl.h" + +#ifndef GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS +#define GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS 0 +#endif + +static int millerrabin (mpz_srcptr, +			mpz_ptr, mpz_ptr, +			mpz_srcptr, unsigned long int); + +int +mpz_millerrabin (mpz_srcptr n, int reps) +{ +  mpz_t nm, x, y, q; +  mp_bitcnt_t k; +  int is_prime; +  TMP_DECL; +  TMP_MARK; + +  ASSERT (SIZ (n) > 0); +  MPZ_TMP_INIT (nm, SIZ (n) + 1); +  mpz_tdiv_q_2exp (nm, n, 1); + +  MPZ_TMP_INIT (x, SIZ (n) + 1); +  MPZ_TMP_INIT (y, 2 * SIZ (n)); /* mpz_powm_ui needs excessive memory!!! */ +  MPZ_TMP_INIT (q, SIZ (n)); + +  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */ +  k = mpn_scan1 (PTR (nm), 0); +  mpz_tdiv_q_2exp (q, nm, k); +  ++k; + +  /* BPSW test */ +  mpz_set_ui (x, 2); +  is_prime = millerrabin (n, x, y, q, k) && mpz_stronglucas (n, x, y); + +  if (is_prime) +    { +      if ( +#if GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS +	  /* Consider numbers up to 2^64 that pass the BPSW test as primes. */ +#if GMP_NUMB_BITS <= 64 +	  SIZ (n) <= 64 / GMP_NUMB_BITS +#else +	  0 +#endif +#if 64 % GMP_NUMB_BITS != 0 +	  || SIZ (n) - 64 / GMP_NUMB_BITS == (PTR (n) [64 / GMP_NUMB_BITS] < CNST_LIMB(1) << 64 % GMP_NUMB_BITS) +#endif +#else +	  /* Consider numbers up to 35*2^46 that pass the BPSW test as primes. +	     This implementation was tested up to 2463*10^12 > 2^51+2^47+2^46 */ +	  /* 2^5 < 35 = 0b100011 < 2^6 */ +#define GMP_BPSW_LIMB_CONST CNST_LIMB(35) +#define GMP_BPSW_BITS_CONST (LOG2C(35) - 1) +#define GMP_BPSW_BITS_LIMIT (46 + GMP_BPSW_BITS_CONST) + +#define GMP_BPSW_LIMBS_LIMIT (GMP_BPSW_BITS_LIMIT / GMP_NUMB_BITS) +#define GMP_BPSW_BITS_MOD (GMP_BPSW_BITS_LIMIT % GMP_NUMB_BITS) + +#if GMP_NUMB_BITS <=  GMP_BPSW_BITS_LIMIT +	  SIZ (n) <= GMP_BPSW_LIMBS_LIMIT +#else +	  0 +#endif +#if GMP_BPSW_BITS_MOD >=  GMP_BPSW_BITS_CONST +	  || SIZ (n) - GMP_BPSW_LIMBS_LIMIT == (PTR (n) [GMP_BPSW_LIMBS_LIMIT] < GMP_BPSW_LIMB_CONST << (GMP_BPSW_BITS_MOD - GMP_BPSW_BITS_CONST)) +#else +#if GMP_BPSW_BITS_MOD != 0 +	  || SIZ (n) - GMP_BPSW_LIMBS_LIMIT == (PTR (n) [GMP_BPSW_LIMBS_LIMIT] < GMP_BPSW_LIMB_CONST >> (GMP_BPSW_BITS_CONST -  GMP_BPSW_BITS_MOD)) +#else +#if GMP_NUMB_BITS > GMP_BPSW_BITS_CONST +	  || SIZ (nm) - GMP_BPSW_LIMBS_LIMIT + 1 == (PTR (nm) [GMP_BPSW_LIMBS_LIMIT - 1] < GMP_BPSW_LIMB_CONST << (GMP_NUMB_BITS - 1 - GMP_BPSW_BITS_CONST)) +#endif +#endif +#endif + +#undef GMP_BPSW_BITS_LIMIT +#undef GMP_BPSW_LIMB_CONST +#undef GMP_BPSW_BITS_CONST +#undef GMP_BPSW_LIMBS_LIMIT +#undef GMP_BPSW_BITS_MOD + +#endif +	  ) +	is_prime = 2; +      else +	{ +	  reps -= 24; +	  if (reps > 0) +	    { +	      gmp_randstate_t rstate; +	      /* (n-5)/2 */ +	      mpz_sub_ui (nm, nm, 2L); +	      ASSERT (mpz_cmp_ui (nm, 1L) >= 0); + +	      gmp_randinit_default (rstate); + +	      do +		{ +		  /* 3 to (n-1)/2 inclusive, don't want 1, 0 or 2 */ +		  mpz_urandomm (x, rstate, nm); +		  mpz_add_ui (x, x, 3L); + +		  is_prime = millerrabin (n, x, y, q, k); +		} while (--reps > 0 && is_prime); + +	      gmp_randclear (rstate); +	    } +	} +    } +  TMP_FREE; +  return is_prime; +} + +static int +mod_eq_m1 (mpz_srcptr x, mpz_srcptr m) +{ +  mp_size_t ms; +  mp_srcptr mp, xp; + +  ms = SIZ (m); +  if (SIZ (x) != ms) +    return 0; +  ASSERT (ms > 0); + +  mp = PTR (m); +  xp = PTR (x); +  ASSERT ((mp[0] - 1) == (mp[0] ^ 1)); /* n is odd */ + +  if ((*xp ^ CNST_LIMB(1) ^ *mp) != CNST_LIMB(0)) /* xp[0] != mp[0] - 1 */ +    return 0; +  else +    { +      int cmp; + +      --ms; +      ++xp; +      ++mp; + +      MPN_CMP (cmp, xp, mp, ms); + +      return cmp == 0; +    } +} + +static int +millerrabin (mpz_srcptr n, mpz_ptr x, mpz_ptr y, +	     mpz_srcptr q, mp_bitcnt_t k) +{ +  mpz_powm (y, x, q, n); + +  if (mpz_cmp_ui (y, 1L) == 0 || mod_eq_m1 (y, n)) +    return 1; + +  for (mp_bitcnt_t i = 1; i < k; ++i) +    { +      mpz_powm_ui (y, y, 2L, n); +      if (mod_eq_m1 (y, n)) +	return 1; +    } +  return 0; +} |