// the following two functions are based on code and comments provided by Preda Mihailescu static bool ProvePrime(const Integer &p, const Integer &q) { assert(p < q*q*q); assert(p % q == 1); // this is the Quisquater test. Numbers p having passed the Lucas - Lehmer test // for q and verifying p < q^3 can only be built up of two factors, both = 1 mod q, // or be prime. The next two lines build the discriminant of a quadratic equation // which holds iff p is built up of two factors (excercise ... ) Integer r = (p-1)/q; if (((r%q).Squared()-4*(r/q)).IsSquare()) return false; unsigned int primeTableSize; const word16 * primeTable = GetPrimeTable(primeTableSize); assert(primeTableSize >= 50); for (int i=0; i<50; i++) { Integer b = a_exp_b_mod_c(primeTable[i], r, p); if (b != 1) return a_exp_b_mod_c(b, q, p) == 1; } return false; }
void PrimeSieve::DoSieve() { unsigned int primeTableSize; const word16 * primeTable = GetPrimeTable(primeTableSize); const unsigned int maxSieveSize = 32768; unsigned int sieveSize = STDMIN(Integer(maxSieveSize), (m_last-m_first)/m_step+1).ConvertToLong(); m_sieve.clear(); m_sieve.resize(sieveSize, false); if (m_delta == 0) { for (unsigned int i = 0; i < primeTableSize; ++i) SieveSingle(m_sieve, primeTable[i], m_first, m_step, (word16)m_step.InverseMod(primeTable[i])); } else { assert(m_step%2==0); Integer qFirst = (m_first-m_delta) >> 1; Integer halfStep = m_step >> 1; for (unsigned int i = 0; i < primeTableSize; ++i) { word16 p = primeTable[i]; word16 stepInv = (word16)m_step.InverseMod(p); SieveSingle(m_sieve, p, m_first, m_step, stepInv); word16 halfStepInv = 2*stepInv < p ? 2*stepInv : 2*stepInv-p; SieveSingle(m_sieve, p, qFirst, halfStep, halfStepInv); } } }
bool IsSmallPrime(const Integer &p) { unsigned int primeTableSize; const word16 * primeTable = GetPrimeTable(primeTableSize); if (p.IsPositive() && p <= primeTable[primeTableSize-1]) return std::binary_search(primeTable, primeTable+primeTableSize, (word16)p.ConvertToLong()); else return false; }
bool TrialDivision(const Integer &p, unsigned bound) { unsigned int primeTableSize; const word16 * primeTable = GetPrimeTable(primeTableSize); assert(primeTable[primeTableSize-1] >= bound); unsigned int i; for (i = 0; primeTable[i]<bound; i++) if ((p % primeTable[i]) == 0) return true; if (bound == primeTable[i]) return (p % bound == 0); else return false; }
// computes g as h ** ( mult (qi ** n) ) // where qi are all primes smaller than B Integer get_g(const Integer &n, const Integer &h) { const word16 *primes; unsigned available_primes; // get the array of primes primes = GetPrimeTable(available_primes); if (available_primes <= B) { throw ProtocolException("not enough primes"); } Integer mult = 1; for(int i = 0; primes[i] < B; ++i) { mult *= exp(primes[i], BITS); } return a_exp_b_mod_c(h, mult, n); }
Integer MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits) { const unsigned smallPrimeBound = 29, c_opt=10; Integer p; unsigned int primeTableSize; const word16 * primeTable = GetPrimeTable(primeTableSize); if (bits < smallPrimeBound) { do p.Randomize(rng, Integer::Power2(bits-1), Integer::Power2(bits)-1, Integer::ANY, 1, 2); while (TrialDivision(p, 1 << ((bits+1)/2))); } else { const unsigned margin = bits > 50 ? 20 : (bits-10)/2; double relativeSize; do relativeSize = pow(2.0, double(rng.GenerateWord32())/0xffffffff - 1); while (bits * relativeSize >= bits - margin); Integer a,b; Integer q = MaurerProvablePrime(rng, unsigned(bits*relativeSize)); Integer I = Integer::Power2(bits-2)/q; Integer I2 = I << 1; unsigned int trialDivisorBound = (unsigned int)STDMIN((unsigned long)primeTable[primeTableSize-1], (unsigned long)bits*bits/c_opt); bool success = false; while (!success) { p.Randomize(rng, I, I2, Integer::ANY); p *= q; p <<= 1; ++p; if (!TrialDivision(p, trialDivisorBound)) { a.Randomize(rng, 2, p-1, Integer::ANY); b = a_exp_b_mod_c(a, (p-1)/q, p); success = (GCD(b-1, p) == 1) && (a_exp_b_mod_c(b, q, p) == 1); } } } return p; }
bool SmallDivisorsTest(const Integer &p) { unsigned int primeTableSize; const word16 * primeTable = GetPrimeTable(primeTableSize); return !TrialDivision(p, primeTable[primeTableSize-1]); }
bool FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector) { assert(!equiv.IsNegative() && equiv < mod); Integer gcd = GCD(equiv, mod); if (gcd != Integer::One()) { // the only possible prime p such that p%mod==equiv where GCD(mod,equiv)!=1 is GCD(mod,equiv) if (p <= gcd && gcd <= max && IsPrime(gcd) && (!pSelector || pSelector->IsAcceptable(gcd))) { p = gcd; return true; } else return false; } unsigned int primeTableSize; const word16 * primeTable = GetPrimeTable(primeTableSize); if (p <= primeTable[primeTableSize-1]) { const word16 *pItr; --p; if (p.IsPositive()) pItr = std::upper_bound(primeTable, primeTable+primeTableSize, (word)p.ConvertToLong()); else pItr = primeTable; while (pItr < primeTable+primeTableSize && !(*pItr%mod == equiv && (!pSelector || pSelector->IsAcceptable(*pItr)))) ++pItr; if (pItr < primeTable+primeTableSize) { p = *pItr; return p <= max; } p = primeTable[primeTableSize-1]+1; } assert(p > primeTable[primeTableSize-1]); if (mod.IsOdd()) return FirstPrime(p, max, CRT(equiv, mod, 1, 2, 1), mod<<1, pSelector); p += (equiv-p)%mod; if (p>max) return false; PrimeSieve sieve(p, max, mod); while (sieve.NextCandidate(p)) { if ((!pSelector || pSelector->IsAcceptable(p)) && FastProbablePrimeTest(p) && IsPrime(p)) return true; } return false; }