internal void SubtractPositive(Integer Result, Integer ToSub) { if (ToSub.IsULong()) { SubtractULong(Result, ToSub.GetAsULong()); return; } if (ToSub.GetIndex() > Result.GetIndex()) { throw(new Exception("In Subtract() ToSub.Index > Index.")); } int Max = ToSub.GetIndex(); for (int Count = 0; Count <= Max; Count++) { SignedD[Count] = (long)Result.GetD(Count) - (long)ToSub.GetD(Count); } Max = Result.GetIndex(); for (int Count = ToSub.GetIndex() + 1; Count <= Max; Count++) { SignedD[Count] = (long)Result.GetD(Count); } Max = Result.GetIndex(); for (int Count = 0; Count < Max; Count++) { if (SignedD[Count] < 0) { SignedD[Count] += (long)0xFFFFFFFF + 1; SignedD[Count + 1]--; } } if (SignedD[Result.GetIndex()] < 0) { throw(new Exception("Subtract() SignedD[Index] < 0.")); } Max = Result.GetIndex(); for (int Count = 0; Count <= Max; Count++) { Result.SetD(Count, (ulong)SignedD[Count]); } for (int Count = Result.GetIndex(); Count >= 0; Count--) { if (Result.GetD(Count) != 0) { Result.SetIndex(Count); return; } } // If it never found a non-zero digit it would get down to here. Result.SetIndex(0); }
// This is a variation on ShortDivide that returns // the remainder. // Also, DivideBy is a ulong. internal ulong ShortDivideRem(Integer ToDivideOriginal, ulong DivideByU, Integer Quotient) { if (ToDivideOriginal.IsULong()) { ulong ToDiv = ToDivideOriginal.GetAsULong(); ulong Q = ToDiv / DivideByU; Quotient.SetFromULong(Q); return(ToDiv % DivideByU); } ToDivide.Copy(ToDivideOriginal); Quotient.Copy(ToDivide); ulong RemainderU = 0; if (DivideByU > Quotient.GetD(Quotient.GetIndex())) { Quotient.SetD(Quotient.GetIndex(), 0); } else { ulong OneDigit = Quotient.GetD(Quotient.GetIndex()); Quotient.SetD(Quotient.GetIndex(), OneDigit / DivideByU); RemainderU = OneDigit % DivideByU; ToDivide.SetD(ToDivide.GetIndex(), RemainderU); } for (int Count = Quotient.GetIndex(); Count >= 1; Count--) { ulong TwoDigits = ToDivide.GetD(Count); TwoDigits <<= 32; TwoDigits |= ToDivide.GetD(Count - 1); Quotient.SetD(Count - 1, TwoDigits / DivideByU); RemainderU = TwoDigits % DivideByU; ToDivide.SetD(Count, 0); ToDivide.SetD(Count - 1, RemainderU); } for (int Count = Quotient.GetIndex(); Count >= 0; Count--) { if (Quotient.GetD(Count) != 0) { Quotient.SetIndex(Count); break; } } return(RemainderU); }
internal string ToString10(Integer From) { if (From.IsULong()) { ulong N = From.GetAsULong(); if (From.IsNegative) { return("-" + N.ToString("N0")); } else { return(N.ToString("N0")); } } string Result = ""; ToDivide.Copy(From); int CommaCount = 0; while (!ToDivide.IsZero()) { uint Digit = (uint)Divider.ShortDivideRem(ToDivide, 10, Quotient); ToDivide.Copy(Quotient); if (((CommaCount % 3) == 0) && (CommaCount != 0)) { Result = Digit.ToString() + "," + Result; // Or use a StringBuilder. } else { Result = Digit.ToString() + Result; } CommaCount++; } if (From.IsNegative) { return("-" + Result); } else { return(Result); } }
// This is a variation on ShortDivide() to get the // remainder only. internal ulong GetMod32(Integer ToDivideOriginal, ulong DivideByU) { if ((DivideByU >> 32) != 0) { throw(new Exception("GetMod32: (DivideByU >> 32) != 0.")); } // If this is _equal_ to a small prime it would return zero. if (ToDivideOriginal.IsULong()) { ulong Result = ToDivideOriginal.GetAsULong(); return(Result % DivideByU); } ToDivide.Copy(ToDivideOriginal); ulong RemainderU = 0; if (DivideByU <= ToDivide.GetD(ToDivide.GetIndex())) { ulong OneDigit = ToDivide.GetD(ToDivide.GetIndex()); RemainderU = OneDigit % DivideByU; ToDivide.SetD(ToDivide.GetIndex(), RemainderU); } for (int Count = ToDivide.GetIndex(); Count >= 1; Count--) { ulong TwoDigits = ToDivide.GetD(Count); TwoDigits <<= 32; TwoDigits |= ToDivide.GetD(Count - 1); RemainderU = TwoDigits % DivideByU; ToDivide.SetD(Count, 0); ToDivide.SetD(Count - 1, RemainderU); } return(RemainderU); }
internal bool FindMultiplicativeInverseSmall(Integer ToFind, Integer KnownNumber, Integer Modulus) { // This method is for: KnownNumber * ToFind = 1 mod Modulus // An example: // PublicKeyExponent * X = 1 mod PhiN. // PublicKeyExponent * X = 1 mod (P - 1)(Q - 1). // This means that // (PublicKeyExponent * X) = (Y * PhiN) + 1 // X is less than PhiN. // So Y is less than PublicKExponent. // Y can't be zero. // If this equation can be solved then it can be solved modulo // any number. So it has to be solvable mod PublicKExponent. // See: Hasse Principle. // This also depends on the idea that the KnownNumber is prime and // that there is one unique modular inverse. // if( !KnownNumber-is-a-prime ) // then it won't work. if (!KnownNumber.IsULong()) { throw(new Exception("FindMultiplicativeInverseSmall() was called with too big of a KnownNumber.")); } ulong KnownNumberULong = KnownNumber.GetAsULong(); // 65537 if (KnownNumberULong > 1000000) { throw(new Exception("KnownNumberULong > 1000000. FindMultiplicativeInverseSmall() was called with too big of an exponent.")); } // (Y * PhiN) + 1 mod PubKExponent has to be zero if Y is a solution. ulong ModulusModKnown = Divider.GetMod32(Modulus, KnownNumberULong); // Worker.ReportProgress( 0, "ModulusModExponent: " + ModulusModKnown.ToString( "N0" )); // if( Worker.CancellationPending ) // return false; // Y can't be zero. // The exponent is a small number like 65537. for (uint Y = 1; Y < (uint)KnownNumberULong; Y++) { ulong X = (ulong)Y * ModulusModKnown; X++; // Add 1 to it for (Y * PhiN) + 1. X = X % KnownNumberULong; if (X == 0) { // if( Worker.CancellationPending ) // return false; // What is PhiN mod 65537? // That gives me Y. // The private key exponent is X*65537 + ModPart // The CipherText raised to that is the PlainText. // P + zN = C^(X*65537 + ModPart) // P + zN = C^(X*65537)(C^ModPart) // P + zN = ((C^65537)^X)(C^ModPart) // Worker.ReportProgress( 0, "Found Y at: " + Y.ToString( "N0" )); ToFind.Copy(Modulus); Multiplier.MultiplyULong(ToFind, Y); ToFind.AddULong(1); Divider.Divide(ToFind, KnownNumber, Quotient, Remainder); if (!Remainder.IsZero()) { throw(new Exception("This can't happen. !Remainder.IsZero()")); } ToFind.Copy(Quotient); // Worker.ReportProgress( 0, "ToFind: " + ToString10( ToFind )); break; } } // if( Worker.CancellationPending ) // return false; TestForModInverse1.Copy(ToFind); Multiplier.MultiplyULong(TestForModInverse1, KnownNumberULong); Divider.Divide(TestForModInverse1, Modulus, Quotient, Remainder); if (!Remainder.IsOne()) { // The definition is that it's congruent to 1 mod the modulus, // so this has to be 1. // I've only seen this happen once. Were the primes P and Q not // really primes? throw(new Exception("Remainder has to be 1: " + ToString10(Remainder))); } return(true); }
internal void SubtractULong(Integer Result, ulong ToSub) { if (Result.IsULong()) { ulong ResultU = Result.GetAsULong(); if (ToSub > ResultU) { throw(new Exception("SubULong() (IsULong() and (ToSub > Result).")); } ResultU = ResultU - ToSub; Result.SetD(0, ResultU & 0xFFFFFFFF); Result.SetD(1, ResultU >> 32); if (Result.GetD(1) == 0) { Result.SetIndex(0); } else { Result.SetIndex(1); } return; } // If it got this far then Index is at least 2. SignedD[0] = (long)Result.GetD(0) - (long)(ToSub & 0xFFFFFFFF); SignedD[1] = (long)Result.GetD(1) - (long)(ToSub >> 32); if ((SignedD[0] >= 0) && (SignedD[1] >= 0)) { // No need to reorganize it. Result.SetD(0, (ulong)SignedD[0]); Result.SetD(1, (ulong)SignedD[1]); return; } int Max = Result.GetIndex(); for (int Count = 2; Count <= Max; Count++) { SignedD[Count] = (long)Result.GetD(Count); } Max = Result.GetIndex(); for (int Count = 0; Count < Max; Count++) { if (SignedD[Count] < 0) { SignedD[Count] += (long)0xFFFFFFFF + 1; SignedD[Count + 1]--; } } if (SignedD[Result.GetIndex()] < 0) { throw(new Exception("SubULong() SignedD[Index] < 0.")); } Max = Result.GetIndex(); for (int Count = 0; Count <= Max; Count++) { Result.SetD(Count, (ulong)SignedD[Count]); } Max = Result.GetIndex(); for (int Count = Max; Count >= 0; Count--) { if (Result.GetD(Count) != 0) { Result.SetIndex(Count); return; } } // If this was zero it wouldn't find a nonzero // digit to set the Index to and it would end up down here. Result.SetIndex(0); }
internal void MakeRSAKeys() { int ShowBits = (PrimeIndex + 1) * 32; // int TestLoops = 0; Worker.ReportProgress(0, "Making RSA keys."); Worker.ReportProgress(0, "Bits size is: " + ShowBits.ToString()); // ulong Loops = 0; while (true) { if (Worker.CancellationPending) { return; } Thread.Sleep(1); // Let other things run. // Make two prime factors. // Normally you'd only make new primes when you pay the Certificate // Authority for a new certificate. if (!MakeAPrime(PrimeP, PrimeIndex, 20)) { return; } if (Worker.CancellationPending) { return; } if (!MakeAPrime(PrimeQ, PrimeIndex, 20)) { return; } if (Worker.CancellationPending) { return; } // This is extremely unlikely. Integer Gcd = new Integer(); IntMath.GreatestCommonDivisor(PrimeP, PrimeQ, Gcd); if (!Gcd.IsOne()) { Worker.ReportProgress(0, "They had a GCD: " + IntMath.ToString10(Gcd)); continue; } if (Worker.CancellationPending) { return; } IntMath.GreatestCommonDivisor(PrimeP, PubKeyExponent, Gcd); if (!Gcd.IsOne()) { Worker.ReportProgress(0, "They had a GCD with PubKeyExponent: " + IntMath.ToString10(Gcd)); continue; } if (Worker.CancellationPending) { return; } IntMath.GreatestCommonDivisor(PrimeQ, PubKeyExponent, Gcd); if (!Gcd.IsOne()) { Worker.ReportProgress(0, "2) They had a GCD with PubKeyExponent: " + IntMath.ToString10(Gcd)); continue; } // For Modular Reduction. This only has to be done // once, when P and Q are made. IntMathForP.ModReduction.SetupGeneralBaseArray(PrimeP); IntMathForQ.ModReduction.SetupGeneralBaseArray(PrimeQ); PrimePMinus1.Copy(PrimeP); IntMath.SubtractULong(PrimePMinus1, 1); PrimeQMinus1.Copy(PrimeQ); IntMath.SubtractULong(PrimeQMinus1, 1); if (Worker.CancellationPending) { return; } // These checks should be more thorough to // make sure the primes P and Q are numbers // that can be used in a secure way. Worker.ReportProgress(0, "The Index of Prime P is: " + PrimeP.GetIndex().ToString()); Worker.ReportProgress(0, "Prime P:"); Worker.ReportProgress(0, IntMath.ToString10(PrimeP)); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Prime Q:"); Worker.ReportProgress(0, IntMath.ToString10(PrimeQ)); Worker.ReportProgress(0, " "); PubKeyN.Copy(PrimeP); IntMath.Multiply(PubKeyN, PrimeQ); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PubKeyN:"); Worker.ReportProgress(0, IntMath.ToString10(PubKeyN)); Worker.ReportProgress(0, " "); // Test Division: Integer QuotientTest = new Integer(); Integer RemainderTest = new Integer(); IntMath.Divider.Divide(PubKeyN, PrimeP, QuotientTest, RemainderTest); if (!RemainderTest.IsZero()) { throw(new Exception("RemainderTest should be zero after divide by PrimeP.")); } IntMath.Multiply(QuotientTest, PrimeP); if (!QuotientTest.IsEqual(PubKeyN)) { throw(new Exception("QuotientTest didn't come out right.")); } // Euler's Theorem: // https://en.wikipedia.org/wiki/Euler's_theorem // ========== // Work on the Least Common Multiple thing for // P - 1 and Q - 1. // ===== IntMath.GreatestCommonDivisor(PrimePMinus1, PrimeQMinus1, Gcd); Worker.ReportProgress(0, "GCD of PrimePMinus1, PrimeQMinus1 is: " + IntMath.ToString10(Gcd)); if (!Gcd.IsULong()) { Worker.ReportProgress(0, "This GCD number is too big: " + IntMath.ToString10(Gcd)); continue; } else { ulong TooBig = Gcd.GetAsULong(); // How big of a GCD is too big? // ============== if (TooBig > 1234567) { // (P - 1)(Q - 1) + (P - 1) + (Q - 1) = PQ - 1 Worker.ReportProgress(0, "This GCD number is bigger than 1234567: " + IntMath.ToString10(Gcd)); continue; } } Integer Temp1 = new Integer(); PhiN.Copy(PrimePMinus1); Temp1.Copy(PrimeQMinus1); IntMath.Multiply(PhiN, Temp1); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PhiN:"); Worker.ReportProgress(0, IntMath.ToString10(PhiN)); Worker.ReportProgress(0, " "); if (Worker.CancellationPending) { return; } // In RFC 2437 there are commonly used letters/symbols to represent // the numbers used. So the number e is the public exponent. // The number e that is used here is called PubKeyExponentUint = 65537. // In the RFC the private key d is the multiplicative inverse of // e mod PhiN. Which is mod (P - 1)(Q - 1). It's called // PrivKInverseExponent here. if (!IntMath.FindMultiplicativeInverseSmall(PrivKInverseExponent, PubKeyExponent, PhiN, Worker)) { return; } if (PrivKInverseExponent.IsZero()) { continue; } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PrivKInverseExponent: " + IntMath.ToString10(PrivKInverseExponent)); if (Worker.CancellationPending) { return; } // In RFC 2437 it defines a number dP which is the multiplicative // inverse, mod (P - 1) of e. That dP is named PrivKInverseExponentDP here. Worker.ReportProgress(0, " "); if (!IntMath.FindMultiplicativeInverseSmall(PrivKInverseExponentDP, PubKeyExponent, PrimePMinus1, Worker)) { return; } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PrivKInverseExponentDP: " + IntMath.ToString10(PrivKInverseExponentDP)); if (PrivKInverseExponentDP.IsZero()) { continue; } // PrivKInverseExponentDP is PrivKInverseExponent mod PrimePMinus1. Integer Test1 = new Integer(); Test1.Copy(PrivKInverseExponent); IntMath.Divider.Divide(Test1, PrimePMinus1, Quotient, Remainder); Test1.Copy(Remainder); if (!Test1.IsEqual(PrivKInverseExponentDP)) { throw(new Exception("This does not match the definition of PrivKInverseExponentDP.")); } if (Worker.CancellationPending) { return; } // In RFC 2437 it defines a number dQ which is the multiplicative // inverse, mod (Q - 1) of e. That dQ is named PrivKInverseExponentDQ here. Worker.ReportProgress(0, " "); if (!IntMath.FindMultiplicativeInverseSmall(PrivKInverseExponentDQ, PubKeyExponent, PrimeQMinus1, Worker)) { return; } if (PrivKInverseExponentDQ.IsZero()) { continue; } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "PrivKInverseExponentDQ: " + IntMath.ToString10(PrivKInverseExponentDQ)); if (Worker.CancellationPending) { return; } Test1.Copy(PrivKInverseExponent); IntMath.Divider.Divide(Test1, PrimeQMinus1, Quotient, Remainder); Test1.Copy(Remainder); if (!Test1.IsEqual(PrivKInverseExponentDQ)) { throw(new Exception("This does not match the definition of PrivKInverseExponentDQ.")); } // Make a random number to test encryption/decryption. Integer ToEncrypt = new Integer(); int HowManyBytes = PrimeIndex * 4; byte[] RandBytes = MakeRandomBytes(HowManyBytes); if (RandBytes == null) { Worker.ReportProgress(0, "Error making random bytes in MakeRSAKeys()."); return; } if (!ToEncrypt.MakeRandomOdd(PrimeIndex - 1, RandBytes)) { Worker.ReportProgress(0, "Error making random number ToEncrypt."); return; } Integer PlainTextNumber = new Integer(); PlainTextNumber.Copy(ToEncrypt); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Before encrypting number: " + IntMath.ToString10(ToEncrypt)); Worker.ReportProgress(0, " "); IntMath.ModReduction.ModularPower(ToEncrypt, PubKeyExponent, PubKeyN, false); if (Worker.CancellationPending) { return; } // Worker.ReportProgress( 0, IntMath.GetStatusString() ); Integer CipherTextNumber = new Integer(); CipherTextNumber.Copy(ToEncrypt); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Encrypted number: " + IntMath.ToString10(CipherTextNumber)); Worker.ReportProgress(0, " "); ECTime DecryptTime = new ECTime(); DecryptTime.SetToNow(); IntMath.ModReduction.ModularPower(ToEncrypt, PrivKInverseExponent, PubKeyN, false); Worker.ReportProgress(0, "Decrypted number: " + IntMath.ToString10(ToEncrypt)); if (!PlainTextNumber.IsEqual(ToEncrypt)) { throw(new Exception("PlainTextNumber not equal to unencrypted value.")); // Because P or Q wasn't really a prime? // Worker.ReportProgress( 0, "PlainTextNumber not equal to unencrypted value." ); // continue; } Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Decrypt time seconds: " + DecryptTime.GetSecondsToNow().ToString("N2")); Worker.ReportProgress(0, " "); if (Worker.CancellationPending) { return; } // Test the standard optimized way of decrypting: if (!ToEncrypt.MakeRandomOdd(PrimeIndex - 1, RandBytes)) { Worker.ReportProgress(0, "Error making random number in MakeRSAKeys()."); return; } PlainTextNumber.Copy(ToEncrypt); IntMath.ModReduction.ModularPower(ToEncrypt, PubKeyExponent, PubKeyN, false); if (Worker.CancellationPending) { return; } CipherTextNumber.Copy(ToEncrypt); // QInv is the multiplicative inverse of PrimeQ mod PrimeP. if (!IntMath.MultiplicativeInverse(PrimeQ, PrimeP, QInv, Worker)) { throw(new Exception("MultiplicativeInverse() returned false.")); } if (QInv.IsNegative) { throw(new Exception("QInv is negative.")); } Worker.ReportProgress(0, "QInv is: " + IntMath.ToString10(QInv)); DecryptWithQInverse(CipherTextNumber, ToEncrypt, // Decrypt it to this. PlainTextNumber, // Test it against this. PubKeyN, PrivKInverseExponentDP, PrivKInverseExponentDQ, PrimeP, PrimeQ, Worker); Worker.ReportProgress(0, " "); Worker.ReportProgress(0, "Found the values:"); Worker.ReportProgress(0, "Seconds: " + StartTime.GetSecondsToNow().ToString("N0")); Worker.ReportProgress(0, " "); Worker.ReportProgress(1, "Prime1: " + IntMath.ToString10(PrimeP)); Worker.ReportProgress(0, " "); Worker.ReportProgress(1, "Prime2: " + IntMath.ToString10(PrimeQ)); Worker.ReportProgress(0, " "); Worker.ReportProgress(1, "PubKeyN: " + IntMath.ToString10(PubKeyN)); Worker.ReportProgress(0, " "); Worker.ReportProgress(1, "PrivKInverseExponent: " + IntMath.ToString10(PrivKInverseExponent)); // return; // Comment this out to just leave it while( true ) for testing. } }
internal void Divide(Integer ToDivideOriginal, Integer DivideByOriginal, Integer Quotient, Integer Remainder) { if (ToDivideOriginal.IsNegative) { throw(new Exception("Divide() can't be called with negative numbers.")); } if (DivideByOriginal.IsNegative) { throw(new Exception("Divide() can't be called with negative numbers.")); } // Returns true if it divides exactly with zero remainder. // This first checks for some basics before trying to divide it: if (DivideByOriginal.IsZero()) { throw(new Exception("Divide() dividing by zero.")); } ToDivide.Copy(ToDivideOriginal); DivideBy.Copy(DivideByOriginal); if (ToDivide.ParamIsGreater(DivideBy)) { Quotient.SetToZero(); Remainder.Copy(ToDivide); return; // false; } if (ToDivide.IsEqual(DivideBy)) { Quotient.SetFromULong(1); Remainder.SetToZero(); return; // true; } // At this point DivideBy is smaller than ToDivide. if (ToDivide.IsULong()) { ulong ToDivideU = ToDivide.GetAsULong(); ulong DivideByU = DivideBy.GetAsULong(); ulong QuotientU = ToDivideU / DivideByU; ulong RemainderU = ToDivideU % DivideByU; Quotient.SetFromULong(QuotientU); Remainder.SetFromULong(RemainderU); // if( RemainderU == 0 ) return; // true; // else // return false; } if (DivideBy.GetIndex() == 0) { ShortDivide(ToDivide, DivideBy, Quotient, Remainder); return; } Integer ToDivideTest2 = new Integer(); Integer DivideByTest2 = new Integer(); Integer QuotientTest2 = new Integer(); Integer RemainderTest2 = new Integer(); Integer ToDivideTest3 = new Integer(); Integer DivideByTest3 = new Integer(); Integer QuotientTest3 = new Integer(); Integer RemainderTest3 = new Integer(); ToDivideTest2.Copy(ToDivide); ToDivideTest3.Copy(ToDivide); DivideByTest2.Copy(DivideBy); DivideByTest3.Copy(DivideBy); LongDivide1(ToDivideTest2, DivideByTest2, QuotientTest2, RemainderTest2); LongDivide2(ToDivideTest3, DivideByTest3, QuotientTest3, RemainderTest3); LongDivide3(ToDivide, DivideBy, Quotient, Remainder); if (!Quotient.IsEqual(QuotientTest2)) { throw(new Exception("!Quotient.IsEqual( QuotientTest2 )")); } if (!Quotient.IsEqual(QuotientTest3)) { throw(new Exception("!Quotient.IsEqual( QuotientTest3 )")); } if (!Remainder.IsEqual(RemainderTest2)) { throw(new Exception("!Remainder.IsEqual( RemainderTest2 )")); } if (!Remainder.IsEqual(RemainderTest3)) { throw(new Exception("!Remainder.IsEqual( RemainderTest3 )")); } }
internal ulong GetMod64(Integer ToDivideOriginal, ulong DivideBy) { if (ToDivideOriginal.IsULong()) { return(ToDivideOriginal.GetAsULong() % DivideBy); } ToDivide.Copy(ToDivideOriginal); ulong Digit1; ulong Digit0; ulong Remainder; if (ToDivide.GetIndex() == 2) { Digit1 = ToDivide.GetD(2); Digit0 = ToDivide.GetD(1) << 32; Digit0 |= ToDivide.GetD(0); return(GetMod64FromTwoULongs(Digit1, Digit0, DivideBy)); } if (ToDivide.GetIndex() == 3) { Digit1 = ToDivide.GetD(3) << 32; Digit1 |= ToDivide.GetD(2); Digit0 = ToDivide.GetD(1) << 32; Digit0 |= ToDivide.GetD(0); return(GetMod64FromTwoULongs(Digit1, Digit0, DivideBy)); } int Where = ToDivide.GetIndex(); while (true) { if (Where <= 3) { if (Where < 2) // This can't happen. { throw(new Exception("GetMod64(): Where < 2.")); } if (Where == 2) { Digit1 = ToDivide.GetD(2); Digit0 = ToDivide.GetD(1) << 32; Digit0 |= ToDivide.GetD(0); return(GetMod64FromTwoULongs(Digit1, Digit0, DivideBy)); } if (Where == 3) { Digit1 = ToDivide.GetD(3) << 32; Digit1 |= ToDivide.GetD(2); Digit0 = ToDivide.GetD(1) << 32; Digit0 |= ToDivide.GetD(0); return(GetMod64FromTwoULongs(Digit1, Digit0, DivideBy)); } } else { // The index is bigger than 3. // This part would get called at least once. Digit1 = ToDivide.GetD(Where) << 32; Digit1 |= ToDivide.GetD(Where - 1); Digit0 = ToDivide.GetD(Where - 2) << 32; Digit0 |= ToDivide.GetD(Where - 3); Remainder = GetMod64FromTwoULongs(Digit1, Digit0, DivideBy); ToDivide.SetD(Where, 0); ToDivide.SetD(Where - 1, 0); ToDivide.SetD(Where - 2, Remainder >> 32); ToDivide.SetD(Where - 3, Remainder & 0xFFFFFFFF); } Where -= 2; } }
internal void Add(Integer ToAdd) { // There is a separate IntegerMath.Add() that is a wrapper to handle // negative numbers too. // if( IsNegative ) // throw( new Exception( "Integer.Add() is being called when it's negative." )); // if( ToAdd.IsNegative ) // throw( new Exception( "Integer.Add() is being called when ToAdd is negative." )); if (ToAdd.IsULong()) { AddULong(ToAdd.GetAsULong()); return; } int LocalIndex = Index; int LocalToAddIndex = ToAdd.Index; if (LocalIndex < ToAdd.Index) { for (int Count = LocalIndex + 1; Count <= LocalToAddIndex; Count++) { D[Count] = ToAdd.D[Count]; } for (int Count = 0; Count <= LocalIndex; Count++) { D[Count] += ToAdd.D[Count]; } Index = ToAdd.Index; } else { for (int Count = 0; Count <= LocalToAddIndex; Count++) { D[Count] += ToAdd.D[Count]; } } // After they've been added, reorganize it. ulong Carry = D[0] >> 32; D[0] = D[0] & 0xFFFFFFFF; LocalIndex = Index; for (int Count = 1; Count <= LocalIndex; Count++) { ulong Total = Carry + D[Count]; D[Count] = Total & 0xFFFFFFFF; Carry = Total >> 32; } if (Carry != 0) { Index++; if (Index >= DigitArraySize) { throw(new Exception("Integer.Add() overflow.")); } D[Index] = Carry; } }
internal void Multiply(Integer Result, Integer ToMul) { // try // { if (Result.IsZero()) { return; } if (ToMul.IsULong()) { MultiplyULong(Result, ToMul.GetAsULong()); SetMultiplySign(Result, ToMul); return; } // It could never get here if ToMul is zero because GetIsULong() // would be true for zero. // if( ToMul.IsZero()) int TotalIndex = Result.GetIndex() + ToMul.GetIndex(); if (TotalIndex >= Integer.DigitArraySize) { throw(new Exception("Multiply() overflow.")); } int CountTo = ToMul.GetIndex(); for (int Row = 0; Row <= CountTo; Row++) { if (ToMul.GetD(Row) == 0) { int CountZeros = Result.GetIndex(); for (int Column = 0; Column <= CountZeros; Column++) { M[Column + Row, Row] = 0; } } else { int CountMult = Result.GetIndex(); for (int Column = 0; Column <= CountMult; Column++) { M[Column + Row, Row] = ToMul.GetD(Row) * Result.GetD(Column); } } } // Add the columns up with a carry. Result.SetD(0, M[0, 0] & 0xFFFFFFFF); ulong Carry = M[0, 0] >> 32; int ResultIndex = Result.GetIndex(); int MulIndex = ToMul.GetIndex(); for (int Column = 1; Column <= TotalIndex; Column++) { ulong TotalLeft = 0; ulong TotalRight = 0; for (int Row = 0; Row <= MulIndex; Row++) { if (Row > Column) { break; } if (Column > (ResultIndex + Row)) { continue; } // Split the ulongs into right and left sides // so that they don't overflow. TotalRight += M[Column, Row] & 0xFFFFFFFF; TotalLeft += M[Column, Row] >> 32; } TotalRight += Carry; Result.SetD(Column, TotalRight & 0xFFFFFFFF); Carry = TotalRight >> 32; Carry += TotalLeft; } Result.SetIndex(TotalIndex); if (Carry != 0) { Result.IncrementIndex(); // This can throw an exception if it overflowed the index. Result.SetD(Result.GetIndex(), Carry); } SetMultiplySign(Result, ToMul); }