ext-cryptopp/nbtheory.cpp
Jeffrey Walton 642cf3aa74
Add "stdcpp.h" to bench1.cpp and bench2.cpp (GH #520)
This is the first of possibly two or three for Borland compilers. We have to be careful because its very easy to break something due to math overloads with other compilers like SunCC or XL/C
2017-10-12 21:52:23 -04:00

1124 lines
25 KiB
C++

// nbtheory.cpp - originally written and placed in the public domain by Wei Dai
#include "pch.h"
#ifndef CRYPTOPP_IMPORTS
#include "nbtheory.h"
#include "integer.h"
#include "modarith.h"
#include "algparam.h"
#include "smartptr.h"
#include "misc.h"
#include "stdcpp.h"
#ifdef _OPENMP
# include <omp.h>
#endif
NAMESPACE_BEGIN(CryptoPP)
const word s_lastSmallPrime = 32719;
struct NewPrimeTable
{
std::vector<word16> * operator()() const
{
const unsigned int maxPrimeTableSize = 3511;
member_ptr<std::vector<word16> > pPrimeTable(new std::vector<word16>);
std::vector<word16> &primeTable = *pPrimeTable;
primeTable.reserve(maxPrimeTableSize);
primeTable.push_back(2);
unsigned int testEntriesEnd = 1;
for (unsigned int p=3; p<=s_lastSmallPrime; p+=2)
{
unsigned int j;
for (j=1; j<testEntriesEnd; j++)
if (p%primeTable[j] == 0)
break;
if (j == testEntriesEnd)
{
primeTable.push_back(word16(p));
testEntriesEnd = UnsignedMin(54U, primeTable.size());
}
}
return pPrimeTable.release();
}
};
const word16 * GetPrimeTable(unsigned int &size)
{
const std::vector<word16> &primeTable = Singleton<std::vector<word16>, NewPrimeTable>().Ref();
size = (unsigned int)primeTable.size();
return &primeTable[0];
}
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);
CRYPTOPP_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;
}
bool SmallDivisorsTest(const Integer &p)
{
unsigned int primeTableSize;
const word16 * primeTable = GetPrimeTable(primeTableSize);
return !TrialDivision(p, primeTable[primeTableSize-1]);
}
bool IsFermatProbablePrime(const Integer &n, const Integer &b)
{
if (n <= 3)
return n==2 || n==3;
CRYPTOPP_ASSERT(n>3 && b>1 && b<n-1);
return a_exp_b_mod_c(b, n-1, n)==1;
}
bool IsStrongProbablePrime(const Integer &n, const Integer &b)
{
if (n <= 3)
return n==2 || n==3;
CRYPTOPP_ASSERT(n>3 && b>1 && b<n-1);
if ((n.IsEven() && n!=2) || GCD(b, n) != 1)
return false;
Integer nminus1 = (n-1);
unsigned int a;
// calculate a = largest power of 2 that divides (n-1)
for (a=0; ; a++)
if (nminus1.GetBit(a))
break;
Integer m = nminus1>>a;
Integer z = a_exp_b_mod_c(b, m, n);
if (z==1 || z==nminus1)
return true;
for (unsigned j=1; j<a; j++)
{
z = z.Squared()%n;
if (z==nminus1)
return true;
if (z==1)
return false;
}
return false;
}
bool RabinMillerTest(RandomNumberGenerator &rng, const Integer &n, unsigned int rounds)
{
if (n <= 3)
return n==2 || n==3;
CRYPTOPP_ASSERT(n>3);
Integer b;
for (unsigned int i=0; i<rounds; i++)
{
b.Randomize(rng, 2, n-2);
if (!IsStrongProbablePrime(n, b))
return false;
}
return true;
}
bool IsLucasProbablePrime(const Integer &n)
{
if (n <= 1)
return false;
if (n.IsEven())
return n==2;
CRYPTOPP_ASSERT(n>2);
Integer b=3;
unsigned int i=0;
int j;
while ((j=Jacobi(b.Squared()-4, n)) == 1)
{
if (++i==64 && n.IsSquare()) // avoid infinite loop if n is a square
return false;
++b; ++b;
}
if (j==0)
return false;
else
return Lucas(n+1, b, n)==2;
}
bool IsStrongLucasProbablePrime(const Integer &n)
{
if (n <= 1)
return false;
if (n.IsEven())
return n==2;
CRYPTOPP_ASSERT(n>2);
Integer b=3;
unsigned int i=0;
int j;
while ((j=Jacobi(b.Squared()-4, n)) == 1)
{
if (++i==64 && n.IsSquare()) // avoid infinite loop if n is a square
return false;
++b; ++b;
}
if (j==0)
return false;
Integer n1 = n+1;
unsigned int a;
// calculate a = largest power of 2 that divides n1
for (a=0; ; a++)
if (n1.GetBit(a))
break;
Integer m = n1>>a;
Integer z = Lucas(m, b, n);
if (z==2 || z==n-2)
return true;
for (i=1; i<a; i++)
{
z = (z.Squared()-2)%n;
if (z==n-2)
return true;
if (z==2)
return false;
}
return false;
}
struct NewLastSmallPrimeSquared
{
Integer * operator()() const
{
return new Integer(Integer(s_lastSmallPrime).Squared());
}
};
bool IsPrime(const Integer &p)
{
if (p <= s_lastSmallPrime)
return IsSmallPrime(p);
else if (p <= Singleton<Integer, NewLastSmallPrimeSquared>().Ref())
return SmallDivisorsTest(p);
else
return SmallDivisorsTest(p) && IsStrongProbablePrime(p, 3) && IsStrongLucasProbablePrime(p);
}
bool VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level)
{
bool pass = IsPrime(p) && RabinMillerTest(rng, p, 1);
if (level >= 1)
pass = pass && RabinMillerTest(rng, p, 10);
return pass;
}
unsigned int PrimeSearchInterval(const Integer &max)
{
return max.BitCount();
}
static inline bool FastProbablePrimeTest(const Integer &n)
{
return IsStrongProbablePrime(n,2);
}
AlgorithmParameters MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength)
{
if (productBitLength < 16)
throw InvalidArgument("invalid bit length");
Integer minP, maxP;
if (productBitLength%2==0)
{
minP = Integer(182) << (productBitLength/2-8);
maxP = Integer::Power2(productBitLength/2)-1;
}
else
{
minP = Integer::Power2((productBitLength-1)/2);
maxP = Integer(181) << ((productBitLength+1)/2-8);
}
return MakeParameters("RandomNumberType", Integer::PRIME)("Min", minP)("Max", maxP);
}
class PrimeSieve
{
public:
// delta == 1 or -1 means double sieve with p = 2*q + delta
PrimeSieve(const Integer &first, const Integer &last, const Integer &step, signed int delta=0);
bool NextCandidate(Integer &c);
void DoSieve();
static void SieveSingle(std::vector<bool> &sieve, word16 p, const Integer &first, const Integer &step, word16 stepInv);
Integer m_first, m_last, m_step;
signed int m_delta;
word m_next;
std::vector<bool> m_sieve;
};
PrimeSieve::PrimeSieve(const Integer &first, const Integer &last, const Integer &step, signed int delta)
: m_first(first), m_last(last), m_step(step), m_delta(delta), m_next(0)
{
DoSieve();
}
bool PrimeSieve::NextCandidate(Integer &c)
{
bool safe = SafeConvert(std::find(m_sieve.begin()+m_next, m_sieve.end(), false) - m_sieve.begin(), m_next);
CRYPTOPP_UNUSED(safe); CRYPTOPP_ASSERT(safe);
if (m_next == m_sieve.size())
{
m_first += long(m_sieve.size())*m_step;
if (m_first > m_last)
return false;
else
{
m_next = 0;
DoSieve();
return NextCandidate(c);
}
}
else
{
c = m_first + long(m_next)*m_step;
++m_next;
return true;
}
}
void PrimeSieve::SieveSingle(std::vector<bool> &sieve, word16 p, const Integer &first, const Integer &step, word16 stepInv)
{
if (stepInv)
{
size_t sieveSize = sieve.size();
size_t j = (word32(p-(first%p))*stepInv) % p;
// if the first multiple of p is p, skip it
if (first.WordCount() <= 1 && first + step*long(j) == p)
j += p;
for (; j < sieveSize; j += p)
sieve[j] = true;
}
}
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
{
CRYPTOPP_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 FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector)
{
CRYPTOPP_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;
}
CRYPTOPP_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;
}
// the following two functions are based on code and comments provided by Preda Mihailescu
static bool ProvePrime(const Integer &p, const Integer &q)
{
CRYPTOPP_ASSERT(p < q*q*q);
CRYPTOPP_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 (exercise ... )
Integer r = (p-1)/q;
if (((r%q).Squared()-4*(r/q)).IsSquare())
return false;
unsigned int primeTableSize;
const word16 * primeTable = GetPrimeTable(primeTableSize);
CRYPTOPP_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;
}
Integer MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int pbits)
{
Integer p;
Integer minP = Integer::Power2(pbits-1);
Integer maxP = Integer::Power2(pbits) - 1;
if (maxP <= Integer(s_lastSmallPrime).Squared())
{
// Randomize() will generate a prime provable by trial division
p.Randomize(rng, minP, maxP, Integer::PRIME);
return p;
}
unsigned int qbits = (pbits+2)/3 + 1 + rng.GenerateWord32(0, pbits/36);
Integer q = MihailescuProvablePrime(rng, qbits);
Integer q2 = q<<1;
while (true)
{
// this initializes the sieve to search in the arithmetic
// progression p = p_0 + \lambda * q2 = p_0 + 2 * \lambda * q,
// with q the recursively generated prime above. We will be able
// to use Lucas tets for proving primality. A trick of Quisquater
// allows taking q > cubic_root(p) rather then square_root: this
// decreases the recursion.
p.Randomize(rng, minP, maxP, Integer::ANY, 1, q2);
PrimeSieve sieve(p, STDMIN(p+PrimeSearchInterval(maxP)*q2, maxP), q2);
while (sieve.NextCandidate(p))
{
if (FastProbablePrimeTest(p) && ProvePrime(p, q))
return p;
}
}
// not reached
return p;
}
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 = std::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;
}
Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u)
{
// isn't operator overloading great?
return p * (u * (xq-xp) % q) + xp;
/*
Integer t1 = xq-xp;
cout << hex << t1 << endl;
Integer t2 = u * t1;
cout << hex << t2 << endl;
Integer t3 = t2 % q;
cout << hex << t3 << endl;
Integer t4 = p * t3;
cout << hex << t4 << endl;
Integer t5 = t4 + xp;
cout << hex << t5 << endl;
return t5;
*/
}
Integer ModularSquareRoot(const Integer &a, const Integer &p)
{
if (p%4 == 3)
return a_exp_b_mod_c(a, (p+1)/4, p);
Integer q=p-1;
unsigned int r=0;
while (q.IsEven())
{
r++;
q >>= 1;
}
Integer n=2;
while (Jacobi(n, p) != -1)
++n;
Integer y = a_exp_b_mod_c(n, q, p);
Integer x = a_exp_b_mod_c(a, (q-1)/2, p);
Integer b = (x.Squared()%p)*a%p;
x = a*x%p;
Integer tempb, t;
while (b != 1)
{
unsigned m=0;
tempb = b;
do
{
m++;
b = b.Squared()%p;
if (m==r)
return Integer::Zero();
}
while (b != 1);
t = y;
for (unsigned i=0; i<r-m-1; i++)
t = t.Squared()%p;
y = t.Squared()%p;
r = m;
x = x*t%p;
b = tempb*y%p;
}
CRYPTOPP_ASSERT(x.Squared()%p == a);
return x;
}
bool SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p)
{
Integer D = (b.Squared() - 4*a*c) % p;
switch (Jacobi(D, p))
{
default:
CRYPTOPP_ASSERT(false); // not reached
return false;
case -1:
return false;
case 0:
r1 = r2 = (-b*(a+a).InverseMod(p)) % p;
CRYPTOPP_ASSERT(((r1.Squared()*a + r1*b + c) % p).IsZero());
return true;
case 1:
Integer s = ModularSquareRoot(D, p);
Integer t = (a+a).InverseMod(p);
r1 = (s-b)*t % p;
r2 = (-s-b)*t % p;
CRYPTOPP_ASSERT(((r1.Squared()*a + r1*b + c) % p).IsZero());
CRYPTOPP_ASSERT(((r2.Squared()*a + r2*b + c) % p).IsZero());
return true;
}
}
Integer ModularRoot(const Integer &a, const Integer &dp, const Integer &dq,
const Integer &p, const Integer &q, const Integer &u)
{
Integer p2, q2;
#pragma omp parallel
#pragma omp sections
{
#pragma omp section
p2 = ModularExponentiation((a % p), dp, p);
#pragma omp section
q2 = ModularExponentiation((a % q), dq, q);
}
return CRT(p2, p, q2, q, u);
}
Integer ModularRoot(const Integer &a, const Integer &e,
const Integer &p, const Integer &q)
{
Integer dp = EuclideanMultiplicativeInverse(e, p-1);
Integer dq = EuclideanMultiplicativeInverse(e, q-1);
Integer u = EuclideanMultiplicativeInverse(p, q);
CRYPTOPP_ASSERT(!!dp && !!dq && !!u);
return ModularRoot(a, dp, dq, p, q, u);
}
/*
Integer GCDI(const Integer &x, const Integer &y)
{
Integer a=x, b=y;
unsigned k=0;
CRYPTOPP_ASSERT(!!a && !!b);
while (a[0]==0 && b[0]==0)
{
a >>= 1;
b >>= 1;
k++;
}
while (a[0]==0)
a >>= 1;
while (b[0]==0)
b >>= 1;
while (1)
{
switch (a.Compare(b))
{
case -1:
b -= a;
while (b[0]==0)
b >>= 1;
break;
case 0:
return (a <<= k);
case 1:
a -= b;
while (a[0]==0)
a >>= 1;
break;
default:
CRYPTOPP_ASSERT(false);
}
}
}
Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b)
{
CRYPTOPP_ASSERT(b.Positive());
if (a.Negative())
return EuclideanMultiplicativeInverse(a%b, b);
if (b[0]==0)
{
if (!b || a[0]==0)
return Integer::Zero(); // no inverse
if (a==1)
return 1;
Integer u = EuclideanMultiplicativeInverse(b, a);
if (!u)
return Integer::Zero(); // no inverse
else
return (b*(a-u)+1)/a;
}
Integer u=1, d=a, v1=b, v3=b, t1, t3, b2=(b+1)>>1;
if (a[0])
{
t1 = Integer::Zero();
t3 = -b;
}
else
{
t1 = b2;
t3 = a>>1;
}
while (!!t3)
{
while (t3[0]==0)
{
t3 >>= 1;
if (t1[0]==0)
t1 >>= 1;
else
{
t1 >>= 1;
t1 += b2;
}
}
if (t3.Positive())
{
u = t1;
d = t3;
}
else
{
v1 = b-t1;
v3 = -t3;
}
t1 = u-v1;
t3 = d-v3;
if (t1.Negative())
t1 += b;
}
if (d==1)
return u;
else
return Integer::Zero(); // no inverse
}
*/
int Jacobi(const Integer &aIn, const Integer &bIn)
{
CRYPTOPP_ASSERT(bIn.IsOdd());
Integer b = bIn, a = aIn%bIn;
int result = 1;
while (!!a)
{
unsigned i=0;
while (a.GetBit(i)==0)
i++;
a>>=i;
if (i%2==1 && (b%8==3 || b%8==5))
result = -result;
if (a%4==3 && b%4==3)
result = -result;
std::swap(a, b);
a %= b;
}
return (b==1) ? result : 0;
}
Integer Lucas(const Integer &e, const Integer &pIn, const Integer &n)
{
unsigned i = e.BitCount();
if (i==0)
return Integer::Two();
MontgomeryRepresentation m(n);
Integer p=m.ConvertIn(pIn%n), two=m.ConvertIn(Integer::Two());
Integer v=p, v1=m.Subtract(m.Square(p), two);
i--;
while (i--)
{
if (e.GetBit(i))
{
// v = (v*v1 - p) % m;
v = m.Subtract(m.Multiply(v,v1), p);
// v1 = (v1*v1 - 2) % m;
v1 = m.Subtract(m.Square(v1), two);
}
else
{
// v1 = (v*v1 - p) % m;
v1 = m.Subtract(m.Multiply(v,v1), p);
// v = (v*v - 2) % m;
v = m.Subtract(m.Square(v), two);
}
}
return m.ConvertOut(v);
}
// This is Peter Montgomery's unpublished Lucas sequence evalutation algorithm.
// The total number of multiplies and squares used is less than the binary
// algorithm (see above). Unfortunately I can't get it to run as fast as
// the binary algorithm because of the extra overhead.
/*
Integer Lucas(const Integer &n, const Integer &P, const Integer &modulus)
{
if (!n)
return 2;
#define f(A, B, C) m.Subtract(m.Multiply(A, B), C)
#define X2(A) m.Subtract(m.Square(A), two)
#define X3(A) m.Multiply(A, m.Subtract(m.Square(A), three))
MontgomeryRepresentation m(modulus);
Integer two=m.ConvertIn(2), three=m.ConvertIn(3);
Integer A=m.ConvertIn(P), B, C, p, d=n, e, r, t, T, U;
while (d!=1)
{
p = d;
unsigned int b = WORD_BITS * p.WordCount();
Integer alpha = (Integer(5)<<(2*b-2)).SquareRoot() - Integer::Power2(b-1);
r = (p*alpha)>>b;
e = d-r;
B = A;
C = two;
d = r;
while (d!=e)
{
if (d<e)
{
swap(d, e);
swap(A, B);
}
unsigned int dm2 = d[0], em2 = e[0];
unsigned int dm3 = d%3, em3 = e%3;
// if ((dm6+em6)%3 == 0 && d <= e + (e>>2))
if ((dm3+em3==0 || dm3+em3==3) && (t = e, t >>= 2, t += e, d <= t))
{
// #1
// t = (d+d-e)/3;
// t = d; t += d; t -= e; t /= 3;
// e = (e+e-d)/3;
// e += e; e -= d; e /= 3;
// d = t;
// t = (d+e)/3
t = d; t += e; t /= 3;
e -= t;
d -= t;
T = f(A, B, C);
U = f(T, A, B);
B = f(T, B, A);
A = U;
continue;
}
// if (dm6 == em6 && d <= e + (e>>2))
if (dm3 == em3 && dm2 == em2 && (t = e, t >>= 2, t += e, d <= t))
{
// #2
// d = (d-e)>>1;
d -= e; d >>= 1;
B = f(A, B, C);
A = X2(A);
continue;
}
// if (d <= (e<<2))
if (d <= (t = e, t <<= 2))
{
// #3
d -= e;
C = f(A, B, C);
swap(B, C);
continue;
}
if (dm2 == em2)
{
// #4
// d = (d-e)>>1;
d -= e; d >>= 1;
B = f(A, B, C);
A = X2(A);
continue;
}
if (dm2 == 0)
{
// #5
d >>= 1;
C = f(A, C, B);
A = X2(A);
continue;
}
if (dm3 == 0)
{
// #6
// d = d/3 - e;
d /= 3; d -= e;
T = X2(A);
C = f(T, f(A, B, C), C);
swap(B, C);
A = f(T, A, A);
continue;
}
if (dm3+em3==0 || dm3+em3==3)
{
// #7
// d = (d-e-e)/3;
d -= e; d -= e; d /= 3;
T = f(A, B, C);
B = f(T, A, B);
A = X3(A);
continue;
}
if (dm3 == em3)
{
// #8
// d = (d-e)/3;
d -= e; d /= 3;
T = f(A, B, C);
C = f(A, C, B);
B = T;
A = X3(A);
continue;
}
CRYPTOPP_ASSERT(em2 == 0);
// #9
e >>= 1;
C = f(C, B, A);
B = X2(B);
}
A = f(A, B, C);
}
#undef f
#undef X2
#undef X3
return m.ConvertOut(A);
}
*/
Integer InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u)
{
Integer d = (m*m-4);
Integer p2, q2;
#pragma omp parallel
#pragma omp sections
{
#pragma omp section
{
p2 = p-Jacobi(d,p);
p2 = Lucas(EuclideanMultiplicativeInverse(e,p2), m, p);
}
#pragma omp section
{
q2 = q-Jacobi(d,q);
q2 = Lucas(EuclideanMultiplicativeInverse(e,q2), m, q);
}
}
return CRT(p2, p, q2, q, u);
}
unsigned int FactoringWorkFactor(unsigned int n)
{
// extrapolated from the table in Odlyzko's "The Future of Integer Factorization"
// updated to reflect the factoring of RSA-130
if (n<5) return 0;
else return (unsigned int)(2.4 * std::pow((double)n, 1.0/3.0) * std::pow(::log(double(n)), 2.0/3.0) - 5);
}
unsigned int DiscreteLogWorkFactor(unsigned int n)
{
// assuming discrete log takes about the same time as factoring
if (n<5) return 0;
else return (unsigned int)(2.4 * std::pow((double)n, 1.0/3.0) * std::pow(::log(double(n)), 2.0/3.0) - 5);
}
// ********************************************************
void PrimeAndGenerator::Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits)
{
// no prime exists for delta = -1, qbits = 4, and pbits = 5
CRYPTOPP_ASSERT(qbits > 4);
CRYPTOPP_ASSERT(pbits > qbits);
if (qbits+1 == pbits)
{
Integer minP = Integer::Power2(pbits-1);
Integer maxP = Integer::Power2(pbits) - 1;
bool success = false;
while (!success)
{
p.Randomize(rng, minP, maxP, Integer::ANY, 6+5*delta, 12);
PrimeSieve sieve(p, STDMIN(p+PrimeSearchInterval(maxP)*12, maxP), 12, delta);
while (sieve.NextCandidate(p))
{
CRYPTOPP_ASSERT(IsSmallPrime(p) || SmallDivisorsTest(p));
q = (p-delta) >> 1;
CRYPTOPP_ASSERT(IsSmallPrime(q) || SmallDivisorsTest(q));
if (FastProbablePrimeTest(q) && FastProbablePrimeTest(p) && IsPrime(q) && IsPrime(p))
{
success = true;
break;
}
}
}
if (delta == 1)
{
// find g such that g is a quadratic residue mod p, then g has order q
// g=4 always works, but this way we get the smallest quadratic residue (other than 1)
for (g=2; Jacobi(g, p) != 1; ++g) {}
// contributed by Walt Tuvell: g should be the following according to the Law of Quadratic Reciprocity
CRYPTOPP_ASSERT((p%8==1 || p%8==7) ? g==2 : (p%12==1 || p%12==11) ? g==3 : g==4);
}
else
{
CRYPTOPP_ASSERT(delta == -1);
// find g such that g*g-4 is a quadratic non-residue,
// and such that g has order q
for (g=3; ; ++g)
if (Jacobi(g*g-4, p)==-1 && Lucas(q, g, p)==2)
break;
}
}
else
{
Integer minQ = Integer::Power2(qbits-1);
Integer maxQ = Integer::Power2(qbits) - 1;
Integer minP = Integer::Power2(pbits-1);
Integer maxP = Integer::Power2(pbits) - 1;
do
{
q.Randomize(rng, minQ, maxQ, Integer::PRIME);
} while (!p.Randomize(rng, minP, maxP, Integer::PRIME, delta%q, q));
// find a random g of order q
if (delta==1)
{
do
{
Integer h(rng, 2, p-2, Integer::ANY);
g = a_exp_b_mod_c(h, (p-1)/q, p);
} while (g <= 1);
CRYPTOPP_ASSERT(a_exp_b_mod_c(g, q, p)==1);
}
else
{
CRYPTOPP_ASSERT(delta==-1);
do
{
Integer h(rng, 3, p-1, Integer::ANY);
if (Jacobi(h*h-4, p)==1)
continue;
g = Lucas((p+1)/q, h, p);
} while (g <= 2);
CRYPTOPP_ASSERT(Lucas(q, g, p) == 2);
}
}
}
NAMESPACE_END
#endif