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; } // Tell the compiler these aren't going to change for the for-loop. 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 bool FindMultiplicativeInverseSmall( Integer ToFind, Integer KnownNumber, Integer Modulus, BackgroundWorker Worker ) { // 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 = IntMath.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 ); IntMath.MultiplyULong( ToFind, Y ); ToFind.AddULong( 1 ); IntMath.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 ); IntMath.MultiplyULong( TestForModInverse1, KnownNumberULong ); IntMath.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( "This is a bug. Remainder has to be 1: " + IntMath.ToString10( Remainder ) )); } return true; }
private bool IsFermatPrimeAdded( Integer FindFrom ) { if( FindFrom.IsULong()) { // The biggest size that NumberIsDivisibleByUInt() will check to // see if it has primes for sure. if( FindFrom.GetAsULong() < (223092870UL * 223092870UL)) return false; // Factor this. } int HowManyTimes = 20; // How many primes it will be checked with. if( !IntMath.IsFermatPrime( FindFrom, HowManyTimes )) return false; Integer OneFactor = new Integer(); OneFactor.Copy( FindFrom ); OneFactorRec Rec = new OneFactorRec(); Rec.Factor = OneFactor; // Neither one of these is set to true here because it's probably // a prime, but not definitely. // Rec.IsDefinitelyAPrime = false; // Rec.IsDefinitelyNotAPrime = false; AddFactorRec( Rec ); Worker.ReportProgress( 0, "Fermat thinks this one is a prime." ); return true; // It's a Fermat prime and it was added. }
internal uint NumberIsDivisibleByUInt( Integer ToCheck ) { if( DivisionArray == null ) SetupDivisionArray(); // Set it up once, when it's needed. uint Max = 0; if( ToCheck.IsULong()) { ulong ForMax = ToCheck.GetAsULong(); // It can't be bigger than the square root. Max = (uint)IntMath.FindULSqrRoot( ForMax ); } uint Base = 2 * 3 * 5 * 7 * 11 * 13 * 17; uint EulerPhi = 2 * 4 * 6 * 10 * 12 * 16; uint Base19 = Base * 19; uint Base23 = Base19 * 23; // The first few base numbers like this: // 2 2 // 3 6 // 5 30 // 7 210 // 11 2,310 // 13 30,030 // 17 510,510 // 19 9,699,690 // 23 223,092,870 // These loops count up to 223,092,870 - 1. for( uint Count23 = 0; Count23 < 23; Count23++ ) { Worker.ReportProgress( 0, "Count23 loop: " + Count23.ToString()); uint Base23Part = (Base19 * Count23); for( uint Count19 = 0; Count19 < 19; Count19++ ) { uint Base19Part = Base * Count19; if( Worker.CancellationPending ) return 0; for( int Count = 0; Count < EulerPhi; Count++ ) { if( Worker.CancellationPending ) return 0; uint Test = Base23Part + Base19Part + DivisionArray[Count]; if( Test == 1 ) continue; if( (Test % 19) == 0 ) continue; if( (Test % 23) == 0 ) continue; if( Max > 0 ) { if( Test > Max ) return 0; } if( 0 == IntMath.GetMod32( ToCheck, Test )) { Worker.ReportProgress( 0, "The number is divisible by: " + Test.ToString( "N0" )); return Test; } } } } return 0; // Didn't find a number to divide it. }
/* private bool IsQuadResidue( uint Test, int Index ) { uint TestMod = Test % IntMath.GetPrimeAt( Index ); return QuadResToPrimesArray[Index].QuadRes[TestMod]; } */ private uint GetMod32( Integer ToDivideOriginal, uint DivideByU ) { if( ToDivideOriginal.IsULong()) { ulong Result = ToDivideOriginal.GetAsULong(); return (uint)(Result % DivideByU); } ToDivideMod32.Copy( ToDivideOriginal ); ulong RemainderU = 0; if( DivideByU <= ToDivideMod32.GetD( ToDivideMod32.GetIndex() )) { ulong OneDigit = ToDivideMod32.GetD( ToDivideMod32.GetIndex() ); RemainderU = OneDigit % DivideByU; ToDivideMod32.SetD( ToDivideMod32.GetIndex(), RemainderU ); } for( int Count = ToDivideMod32.GetIndex(); Count >= 1; Count-- ) { ulong TwoDigits = ToDivideMod32.GetD( Count ); TwoDigits <<= 32; TwoDigits |= ToDivideMod32.GetD( Count - 1 ); RemainderU = TwoDigits % DivideByU; ToDivideMod32.SetD( Count, 0 ); ToDivideMod32.SetD( Count - 1, RemainderU ); } return (uint)RemainderU; }
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( "Bug: 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; } }
// 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 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)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; }
// Finding the square root of a number is similar to division since // it is a search algorithm. The TestSqrtBits method shown next is // very much like TestDivideBits(). It works the same as // FindULSqrRoot(), but on a bigger scale. /* private void TestSqrtBits( int TestIndex, Integer Square, Integer SqrRoot ) { Integer Test1 = new Integer(); uint BitTest = 0x80000000; for( int BitCount = 31; BitCount >= 0; BitCount-- ) { Test1.Copy( SqrRoot ); Test1.D[TestIndex] |= BitTest; Test1.Square(); if( !Square.ParamIsGreater( Test1 ) ) SqrRoot.D[TestIndex] |= BitTest; // Use the bit. BitTest >>= 1; } } */ // In the SquareRoot() method SqrRoot.Index is half of Square.Index. // Compare this to the Square() method where the Carry might or // might not increment the index to an odd number. (So if the Index // was 5 its square root would have an Index of 5 / 2 = 2.) // The SquareRoot1() method uses FindULSqrRoot() either to find the // whole answer, if it's a small number, or it uses it to find the // top part. Then from there it goes on to a bit by bit search // with TestSqrtBits(). public bool SquareRoot( Integer Square, Integer SqrRoot ) { ulong ToMatch; if( Square.IsULong() ) { ToMatch = Square.GetAsULong(); SqrRoot.SetD( 0, FindULSqrRoot( ToMatch )); SqrRoot.SetIndex( 0 ); if( (SqrRoot.GetD(0 ) * SqrRoot.GetD( 0 )) == ToMatch ) return true; else return false; } int TestIndex = Square.GetIndex() >> 1; // LgSquare.Index / 2; SqrRoot.SetDigitAndClear( TestIndex, 1 ); // if( (TestIndex * 2) > (LgSquare.Index - 1) ) if( (TestIndex << 1) > (Square.GetIndex() - 1) ) { ToMatch = Square.GetD( Square.GetIndex()); } else { // LgSquare.Index is at least 2 here. ToMatch = Square.GetD( Square.GetIndex()) << 32; ToMatch |= Square.GetD( Square.GetIndex() - 1 ); } SqrRoot.SetD( TestIndex, FindULSqrRoot( ToMatch )); TestIndex--; while( true ) { // TestSqrtBits( TestIndex, LgSquare, LgSqrRoot ); SearchSqrtXPart( TestIndex, Square, SqrRoot ); if( TestIndex == 0 ) break; TestIndex--; } // Avoid squaring the whole thing to see if it's an exact square root: if( ((SqrRoot.GetD( 0 ) * SqrRoot.GetD( 0 )) & 0xFFFFFFFF) != Square.GetD( 0 )) return false; TestForSquareRoot.Copy( SqrRoot ); DoSquare( TestForSquareRoot ); if( Square.IsEqual( TestForSquareRoot )) return true; else return false; }
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; } for( int Count = 2; Count <= Result.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ); for( int Count = 0; Count < Result.GetIndex(); 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." )); for( int Count = 0; Count <= Result.GetIndex(); 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 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 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." )); for( int Count = 0; Count <= ToSub.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ) - (long)ToSub.GetD( Count ); for( int Count = ToSub.GetIndex() + 1; Count <= Result.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ); for( int Count = 0; Count < Result.GetIndex(); 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." )); for( int Count = 0; Count <= Result.GetIndex(); 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; }
// See also: http://en.wikipedia.org/wiki/Karatsuba_algorithm 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." )); for( int Row = 0; Row <= ToMul.GetIndex(); Row++ ) { if( ToMul.GetD( Row ) == 0 ) { for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column + Row, Row] = 0; } else { for( int Column = 0; Column <= Result.GetIndex(); 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; for( int Column = 1; Column <= TotalIndex; Column++ ) { ulong TotalLeft = 0; ulong TotalRight = 0; for( int Row = 0; Row <= ToMul.GetIndex(); Row++ ) { if( Row > Column ) break; if( Column > (Result.GetIndex() + 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 ); }
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 ); // Give up the time slice. Let other things on the server 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; IntegerBase TestP = new IntegerBase(); IntegerBaseMath IntBaseMath = new IntegerBaseMath( IntMath ); string TestS = IntMath.ToString10( PrimeP ); IntBaseMath.SetFromString( TestP, TestS ); string TestS2 = IntBaseMath.ToString10( TestP ); if( TestS != TestS2 ) throw( new Exception( "TestS != TestS2 for IntegerBase." )); 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; // This would never happen since the public key exponent used here // is one of the small primes in the array in IntegerMath that it // was checked against. But it does show here in the code that // they have to be co-prime to each other. And in the future it // might be found that the public key exponent has to be much larger // than the one used here. 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. IntMathNewForP.SetupGeneralBaseArray( PrimeP ); IntMathNewForQ.SetupGeneralBaseArray( PrimeQ ); PrimePMinus1.Copy( PrimeP ); IntMath.SubtractULong( PrimePMinus1, 1 ); PrimeQMinus1.Copy( PrimeQ ); IntMath.SubtractULong( PrimeQMinus1, 1 ); // These checks should be more thorough. if( Worker.CancellationPending ) return; 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, " " ); // Euler's Theorem: // https://en.wikipedia.org/wiki/Euler's_theorem // if x ≡ y (mod φ(n)), // then a^x ≡ a^y (mod n). // Euler's Phi function (aka Euler's Totient function) is calculated // next. // PhiN is made from the two factors: (P - 1)(Q - 1) // PhiN is: (P - 1)(Q - 1) = PQ - P - Q + 1 // If I add (P - 1) to PhiN I get: // PQ - P - Q + 1 + (P - 1) = PQ - Q. // If I add (Q - 1) to that I get: // PQ - Q + (Q - 1) = PQ - 1. // (P - 1)(Q - 1) + (P - 1) + (Q - 1) = PQ - 1 // If (P - 1) and (Q - 1) had a larger GCD then PQ - 1 would have // that same factor too. 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.IntMathNew.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.IntMathNew.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.Divide( Test1, PrimePMinus1, Quotient, Remainder ); Test1.Copy( Remainder ); if( !Test1.IsEqual( PrivKInverseExponentDP )) throw( new Exception( "Bug. 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.IntMathNew.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.Divide( Test1, PrimeQMinus1, Quotient, Remainder ); Test1.Copy( Remainder ); if( !Test1.IsEqual( PrivKInverseExponentDQ )) throw( new Exception( "Bug. 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.IntMathNew.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.IntMathNew.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.IntMathNew.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( "This is a bug. 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 )); /* Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, " " ); DoCRTTest( PrivKInverseExponent ); Worker.ReportProgress( 0, "Finished CRT test." ); Worker.ReportProgress( 0, " " ); */ return; // Comment this out to just leave it while( true ) for testing. } }