Browse Source

Improved performance of some BigInteger methods by adding Montgomery Multiplication and extended Euclidan algorithms

tags/2021-05-28
jules 9 years ago
parent
commit
74554a206c
3 changed files with 178 additions and 43 deletions
  1. +1
    -1
      examples/Demo/Source/Demos/CryptographyDemo.cpp
  2. +148
    -29
      modules/juce_core/maths/juce_BigInteger.cpp
  3. +29
    -13
      modules/juce_core/maths/juce_BigInteger.h

+ 1
- 1
examples/Demo/Source/Demos/CryptographyDemo.cpp View File

@@ -70,7 +70,7 @@ public:
private: private:
void createRSAKey() void createRSAKey()
{ {
int bits = jlimit (32, 512, bitSize.getText().getIntValue());
int bits = jlimit (32, 1024, bitSize.getText().getIntValue());
bitSize.setText (String (bits), dontSendNotification); bitSize.setText (String (bits), dontSendNotification);
// Create a key-pair... // Create a key-pair...


+ 148
- 29
modules/juce_core/maths/juce_BigInteger.cpp View File

@@ -385,12 +385,12 @@ BigInteger& BigInteger::operator+= (const BigInteger& other)
BigInteger temp (*this); BigInteger temp (*this);
temp.negate(); temp.negate();
*this = other; *this = other;
operator-= (temp);
*this -= temp;
} }
else else
{ {
negate(); negate();
operator-= (other);
*this -= other;
negate(); negate();
} }
} }
@@ -436,7 +436,7 @@ BigInteger& BigInteger::operator-= (const BigInteger& other)
{ {
BigInteger temp (other); BigInteger temp (other);
swapWith (temp); swapWith (temp);
operator-= (temp);
*this -= temp;
negate(); negate();
return *this; return *this;
} }
@@ -444,7 +444,7 @@ BigInteger& BigInteger::operator-= (const BigInteger& other)
else else
{ {
negate(); negate();
operator+= (other);
*this += other;
negate(); negate();
return *this; return *this;
} }
@@ -476,24 +476,40 @@ BigInteger& BigInteger::operator-= (const BigInteger& other)
BigInteger& BigInteger::operator*= (const BigInteger& other) BigInteger& BigInteger::operator*= (const BigInteger& other)
{ {
BigInteger total;
highestBit = getHighestBit();
int n = getHighestBit();
int t = other.getHighestBit();
const bool wasNegative = isNegative(); const bool wasNegative = isNegative();
setNegative (false); setNegative (false);
for (int i = 0; i <= highestBit; ++i)
BigInteger total;
total.highestBit = n + t + 1;
n >>= 5;
t >>= 5;
total.ensureSize (n + t + 2);
BigInteger m (other);
m.setNegative (false);
for (int i = 0; i <= t; ++i)
{ {
if (operator[](i))
uint32 c = 0;
for (int j = 0; j <= n; ++j)
{ {
BigInteger n (other);
n.setNegative (false);
n <<= i;
total += n;
uint64 uv = (uint64) total.values[i + j] + (uint64) values[j] * (uint64) m.values[i] + (uint64) c;
total.values[i + j] = (uint32) uv;
c = uv >> 32;
} }
total.values[i + n + 1] = c;
} }
total.setNegative (wasNegative ^ other.isNegative()); total.setNegative (wasNegative ^ other.isNegative());
swapWith (total); swapWith (total);
return *this; return *this;
} }
@@ -683,7 +699,7 @@ void BigInteger::shiftLeft (int bits, const int startBit)
if (startBit > 0) if (startBit > 0)
{ {
for (int i = highestBit + 1; --i >= startBit;) for (int i = highestBit + 1; --i >= startBit;)
setBit (i + bits, operator[] (i));
setBit (i + bits, (*this) [i]);
while (--bits >= 0) while (--bits >= 0)
clearBit (bits + startBit); clearBit (bits + startBit);
@@ -726,7 +742,7 @@ void BigInteger::shiftRight (int bits, const int startBit)
if (startBit > 0) if (startBit > 0)
{ {
for (int i = startBit; i <= highestBit; ++i) for (int i = startBit; i <= highestBit; ++i)
setBit (i, operator[] (i + bits));
setBit (i, (*this) [i + bits]);
highestBit = getHighestBit(); highestBit = getHighestBit();
} }
@@ -816,25 +832,128 @@ BigInteger BigInteger::findGreatestCommonDivisor (BigInteger n) const
void BigInteger::exponentModulo (const BigInteger& exponent, const BigInteger& modulus) void BigInteger::exponentModulo (const BigInteger& exponent, const BigInteger& modulus)
{ {
*this %= modulus;
BigInteger exp (exponent); BigInteger exp (exponent);
exp %= modulus; exp %= modulus;
BigInteger value (1);
swapWith (value);
value %= modulus;
if (modulus.getHighestBit() <= 32 || modulus % 2 == 0)
{
BigInteger a (*this);
const int n = exp.getHighestBit();
for (int i = n; --i >= 0;)
{
*this *= *this;
while (! exp.isZero())
if (exp[i])
*this *= a;
if (compareAbsolute (modulus) >= 0)
*this %= modulus;
}
}
else
{ {
if (exp [0])
const int Rfactor = modulus.getHighestBit() + 1;
BigInteger R (1);
R.shiftLeft (Rfactor, 0);
BigInteger R1, m1, g;
g.extendedEuclidean (modulus, R, m1, R1);
if (! g.isOne())
{ {
operator*= (value);
operator%= (modulus);
BigInteger a (*this);
for (int i = exp.getHighestBit(); --i >= 0;)
{
*this *= *this;
if (exp[i])
*this *= a;
if (compareAbsolute (modulus) >= 0)
*this %= modulus;
}
} }
else
{
BigInteger am (((*this) * R) % modulus);
BigInteger xm (am);
BigInteger um (R % modulus);
value *= value;
value %= modulus;
exp >>= 1;
for (int i = exp.getHighestBit(); --i >= 0;)
{
xm.montgomeryMultiplication (xm, modulus, m1, Rfactor);
if (exp[i])
xm.montgomeryMultiplication (am, modulus, m1, Rfactor);
}
xm.montgomeryMultiplication (1, modulus, m1, Rfactor);
swapWith (xm);
}
}
}
void BigInteger::montgomeryMultiplication (const BigInteger& other, const BigInteger& modulus,
const BigInteger& modulusp, const int k)
{
*this *= other;
BigInteger t (*this);
setRange (k, highestBit - k + 1, false);
*this *= modulusp;
setRange (k, highestBit - k + 1, false);
*this *= modulus;
*this += t;
shiftRight (k, 0);
if (compare (modulus) >= 0)
*this -= modulus;
else if (isNegative())
*this += modulus;
}
void BigInteger::extendedEuclidean (const BigInteger& a, const BigInteger& b,
BigInteger& x, BigInteger& y)
{
BigInteger p(a), q(b), gcd(1);
Array<BigInteger> tempValues;
while (! q.isZero())
{
tempValues.add (p / q);
gcd = q;
q = p % q;
p = gcd;
}
x.clear();
y = 1;
for (int i = 1; i < tempValues.size(); ++i)
{
const BigInteger& v = tempValues.getReference (tempValues.size() - i - 1);
if ((i & 1) != 0)
x += y * v;
else
y += x * v;
} }
if (gcd.compareAbsolute (y * b - x * a) != 0)
{
x.negate();
x.swapWith (y);
x.negate();
}
swapWith (gcd);
} }
void BigInteger::inverseModulo (const BigInteger& modulus) void BigInteger::inverseModulo (const BigInteger& modulus)
@@ -846,7 +965,7 @@ void BigInteger::inverseModulo (const BigInteger& modulus)
} }
if (isNegative() || compareAbsolute (modulus) >= 0) if (isNegative() || compareAbsolute (modulus) >= 0)
operator%= (modulus);
*this %= modulus;
if (isOne()) if (isOne())
return; return;
@@ -959,8 +1078,8 @@ void BigInteger::parseString (StringRef text, const int base)
if (((uint32) digit) < (uint32) base) if (((uint32) digit) < (uint32) base)
{ {
operator<<= (bits);
operator+= (digit);
*this <<= bits;
*this += digit;
} }
else if (c == 0) else if (c == 0)
{ {
@@ -978,8 +1097,8 @@ void BigInteger::parseString (StringRef text, const int base)
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
{ {
operator*= (ten);
operator+= ((int) (c - '0'));
*this *= ten;
*this += (int) (c - '0');
} }
else if (c == 0) else if (c == 0)
{ {


+ 29
- 13
modules/juce_core/maths/juce_BigInteger.h View File

@@ -180,6 +180,22 @@ public:
*/ */
int getHighestBit() const noexcept; int getHighestBit() const noexcept;
//==============================================================================
/** Returns true if the value is less than zero.
@see setNegative, negate
*/
bool isNegative() const noexcept;
/** Changes the sign of the number to be positive or negative.
@see isNegative, negate
*/
void setNegative (bool shouldBeNegative) noexcept;
/** Inverts the sign of the number.
@see isNegative, setNegative
*/
void negate() noexcept;
//============================================================================== //==============================================================================
// All the standard arithmetic ops... // All the standard arithmetic ops...
@@ -236,6 +252,7 @@ public:
*/ */
int compareAbsolute (const BigInteger& other) const noexcept; int compareAbsolute (const BigInteger& other) const noexcept;
//==============================================================================
/** Divides this value by another one and returns the remainder. /** Divides this value by another one and returns the remainder.
This number is divided by other, leaving the quotient in this number, This number is divided by other, leaving the quotient in this number,
@@ -243,7 +260,7 @@ public:
*/ */
void divideBy (const BigInteger& divisor, BigInteger& remainder); void divideBy (const BigInteger& divisor, BigInteger& remainder);
/** Returns the largest value that will divide both this value and the one passed-in. */
/** Returns the largest value that will divide both this value and the argument. */
BigInteger findGreatestCommonDivisor (BigInteger other) const; BigInteger findGreatestCommonDivisor (BigInteger other) const;
/** Performs a combined exponent and modulo operation. /** Performs a combined exponent and modulo operation.
@@ -256,21 +273,20 @@ public:
*/ */
void inverseModulo (const BigInteger& modulus); void inverseModulo (const BigInteger& modulus);
//==============================================================================
/** Returns true if the value is less than zero.
@see setNegative, negate
*/
bool isNegative() const noexcept;
/** Changes the sign of the number to be positive or negative.
@see isNegative, negate
/** Performs the Montgomery Multiplication with modulo.
This object is left containing the result value: ((this * other) * R1) % modulus.
To get this result, we need modulus, modulusp and k such as R = 2^k, with
modulus * modulusp - R * R1 = GCD(modulus, R) = 1
*/ */
void setNegative (bool shouldBeNegative) noexcept;
void montgomeryMultiplication (const BigInteger& other, const BigInteger& modulus,
const BigInteger& modulusp, int k);
/** Inverts the sign of the number.
@see isNegative, setNegative
/** Performs the Extended Euclidean algorithm.
This method will set the xOut and yOut arguments such that (a * xOut) - (b * yOut) = GCD (a, b).
On return, this object is left containing the value of the GCD.
*/ */
void negate() noexcept;
void extendedEuclidean (const BigInteger& a, const BigInteger& b,
BigInteger& xOut, BigInteger& yOut);
//============================================================================== //==============================================================================
/** Converts the number to a string. /** Converts the number to a string.


Loading…
Cancel
Save