📄 biginteger.cs
字号:
kPlusOne = k + 1,
kMinusOne = k - 1;
BigInteger q1 = new BigInteger();
// q1 = x / b^(k-1)
for (int i = kMinusOne, j = 0; i < x.dataLength; i++, j++)
q1.data[j] = x.data[i];
q1.dataLength = x.dataLength - kMinusOne;
if (q1.dataLength <= 0)
q1.dataLength = 1;
BigInteger q2 = q1 * constant;
BigInteger q3 = new BigInteger();
// q3 = q2 / b^(k+1)
for (int i = kPlusOne, j = 0; i < q2.dataLength; i++, j++)
q3.data[j] = q2.data[i];
q3.dataLength = q2.dataLength - kPlusOne;
if (q3.dataLength <= 0)
q3.dataLength = 1;
// r1 = x mod b^(k+1)
// i.e. keep the lowest (k+1) words
BigInteger r1 = new BigInteger();
int lengthToCopy = (x.dataLength > kPlusOne) ? kPlusOne : x.dataLength;
for (int i = 0; i < lengthToCopy; i++)
r1.data[i] = x.data[i];
r1.dataLength = lengthToCopy;
// r2 = (q3 * n) mod b^(k+1)
// partial multiplication of q3 and n
BigInteger r2 = new BigInteger();
for (int i = 0; i < q3.dataLength; i++)
{
if (q3.data[i] == 0) continue;
ulong mcarry = 0;
int t = i;
for (int j = 0; j < n.dataLength && t < kPlusOne; j++, t++)
{
// t = i + j
ulong val = ((ulong)q3.data[i] * (ulong)n.data[j]) +
(ulong)r2.data[t] + mcarry;
r2.data[t] = (uint)(val & 0xFFFFFFFF);
mcarry = (val >> 32);
}
if (t < kPlusOne)
r2.data[t] = (uint)mcarry;
}
r2.dataLength = kPlusOne;
while (r2.dataLength > 1 && r2.data[r2.dataLength - 1] == 0)
r2.dataLength--;
r1 -= r2;
if ((r1.data[maxLength - 1] & 0x80000000) != 0) // negative
{
BigInteger val = new BigInteger();
val.data[kPlusOne] = 0x00000001;
val.dataLength = kPlusOne + 1;
r1 += val;
}
while (r1 >= n)
r1 -= n;
return r1;
}
//***********************************************************************
// Returns gcd(this, bi)
//***********************************************************************
public BigInteger gcd(BigInteger bi)
{
BigInteger x;
BigInteger y;
if ((data[maxLength - 1] & 0x80000000) != 0) // negative
x = -this;
else
x = this;
if ((bi.data[maxLength - 1] & 0x80000000) != 0) // negative
y = -bi;
else
y = bi;
BigInteger g = y;
while (x.dataLength > 1 || (x.dataLength == 1 && x.data[0] != 0))
{
g = x;
x = y % x;
y = g;
}
return g;
}
//***********************************************************************
// Populates "this" with the specified amount of random bits
//***********************************************************************
public void genRandomBits(int bits, Random rand)
{
int dwords = bits >> 5;
int remBits = bits & 0x1F;
if (remBits != 0)
dwords++;
if (dwords > maxLength)
throw (new ArithmeticException("Number of required bits > maxLength."));
for (int i = 0; i < dwords; i++)
data[i] = (uint)(rand.NextDouble() * 0x100000000);
for (int i = dwords; i < maxLength; i++)
data[i] = 0;
if (remBits != 0)
{
uint mask = (uint)(0x01 << (remBits - 1));
data[dwords - 1] |= mask;
mask = (uint)(0xFFFFFFFF >> (32 - remBits));
data[dwords - 1] &= mask;
}
else
data[dwords - 1] |= 0x80000000;
dataLength = dwords;
if (dataLength == 0)
dataLength = 1;
}
//***********************************************************************
// Returns the position of the most significant bit in the BigInteger.
//
// Eg. The result is 0, if the value of BigInteger is 0...0000 0000
// The result is 1, if the value of BigInteger is 0...0000 0001
// The result is 2, if the value of BigInteger is 0...0000 0010
// The result is 2, if the value of BigInteger is 0...0000 0011
//
//***********************************************************************
public int bitCount()
{
while (dataLength > 1 && data[dataLength - 1] == 0)
dataLength--;
uint value = data[dataLength - 1];
uint mask = 0x80000000;
int bits = 32;
while (bits > 0 && (value & mask) == 0)
{
bits--;
mask >>= 1;
}
bits += ((dataLength - 1) << 5);
return bits;
}
//***********************************************************************
// Probabilistic prime test based on Fermat's little theorem
//
// for any a < p (p does not divide a) if
// a^(p-1) mod p != 1 then p is not prime.
//
// Otherwise, p is probably prime (pseudoprime to the chosen base).
//
// Returns
// -------
// True if "this" is a pseudoprime to randomly chosen
// bases. The number of chosen bases is given by the "confidence"
// parameter.
//
// False if "this" is definitely NOT prime.
//
// Note - this method is fast but fails for Carmichael numbers except
// when the randomly chosen base is a factor of the number.
//
//***********************************************************************
public bool FermatLittleTest(int confidence)
{
BigInteger thisVal;
if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative
thisVal = -this;
else
thisVal = this;
if (thisVal.dataLength == 1)
{
// test small numbers
if (thisVal.data[0] == 0 || thisVal.data[0] == 1)
return false;
else if (thisVal.data[0] == 2 || thisVal.data[0] == 3)
return true;
}
if ((thisVal.data[0] & 0x1) == 0) // even numbers
return false;
int bits = thisVal.bitCount();
BigInteger a = new BigInteger();
BigInteger p_sub1 = thisVal - (new BigInteger(1));
Random rand = new Random();
for (int round = 0; round < confidence; round++)
{
bool done = false;
while (!done) // generate a < n
{
int testBits = 0;
// make sure "a" has at least 2 bits
while (testBits < 2)
testBits = (int)(rand.NextDouble() * bits);
a.genRandomBits(testBits, rand);
int byteLen = a.dataLength;
// make sure "a" is not 0
if (byteLen > 1 || (byteLen == 1 && a.data[0] != 1))
done = true;
}
// check whether a factor exists (fix for version 1.03)
BigInteger gcdTest = a.gcd(thisVal);
if (gcdTest.dataLength == 1 && gcdTest.data[0] != 1)
return false;
// calculate a^(p-1) mod p
BigInteger expResult = a.modPow(p_sub1, thisVal);
int resultLen = expResult.dataLength;
// is NOT prime is a^(p-1) mod p != 1
if (resultLen > 1 || (resultLen == 1 && expResult.data[0] != 1))
{
//Console.WriteLine("a = " + a.ToString());
return false;
}
}
return true;
}
//***********************************************************************
// Probabilistic prime test based on Rabin-Miller's
//
// for any p > 0 with p - 1 = 2^s * t
//
// p is probably prime (strong pseudoprime) if for any a < p,
// 1) a^t mod p = 1 or
// 2) a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1
//
// Otherwise, p is composite.
//
// Returns
// -------
// True if "this" is a strong pseudoprime to randomly chosen
// bases. The number of chosen bases is given by the "confidence"
// parameter.
//
// False if "this" is definitely NOT prime.
//
//***********************************************************************
public bool RabinMillerTest(int confidence)
{
BigInteger thisVal;
if ((this.data[maxLength - 1] & 0x80000000) != 0) // negative
thisVal = -this;
else
thisVal = this;
if (thisVal.dataLength == 1)
{
// test small numbers
if (thisVal.data[0] == 0 || thisVal.data[0] == 1)
return false;
else if (thisVal.data[0] == 2 || thisVal.data[0] == 3)
return true;
}
if ((thisVal.data[0] & 0x1) == 0) // even numbers
return false;
// calculate values of s and t
BigInteger p_sub1 = thisVal - (new BigInteger(1));
int s = 0;
for (int index = 0; index < p_sub1.dataLength; index++)
{
uint mask = 0x01;
for (int i = 0; i < 32; i++)
{
if ((p_sub1.data[index] & mask) != 0)
{
index = p_sub1.dataLength; // to break the outer loop
break;
}
mask <<= 1;
s++;
}
}
BigInteger t = p_sub1 >> s;
int bits = thisVal.bitCount();
BigInteger a = new BigInteger();
Random rand = new Random();
for (int round = 0; round < confidence; round++)
{
bool done = false;
while (!done) // generate a < n
{
int testBits = 0;
// make sure "a" has at least 2 bits
while (testBits < 2)
testBits = (int)(rand.NextDouble() * bits);
a.genRandomBits(testBits, rand);
int byteLen = a.dataLength;
// make sure "a" is not 0
if (byteLen > 1 || (byteLen == 1 && a.data[0] != 1))
done = true;
}
// check whether a factor exists (fix for version 1.03)
BigInteger gcdTest = a.gcd(thisVal);
if (gcdTest.dataLength == 1 && gcdTest.data[0] != 1)
return false;
BigInteger b = a.modPow(t, thisVal);
/*
Console.WriteLine("a = " + a.ToString(10));
Console.WriteLine("b = " + b.ToString(10));
Console.WriteLine("t = " + t.ToString(10));
Console.WriteLine("s = " + s);
*/
bool result = false;
if (b.dataLength == 1 && b.data[0] == 1) // a^t mod p = 1
result = true;
for (int j = 0; result == false && j < s; j++)
{
if (b == p_sub1) // a^((2^j)*t) mod p = p-1 for some
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -