// This is the standard modular power algorithm that // you could find in any reference, but its use of // the new modular reduction algorithm is new. // The square and multiply method is in Wikipedia: // https://en.wikipedia.org/wiki/Exponentiation_by_squaring // x^n = (x^2)^((n - 1)/2) if n is odd. // x^n = (x^2)^(n/2) if n is even. internal void ModularPower( Integer Result, Integer Exponent, Integer Modulus, bool UsePresetBaseArray ) { if( Result.IsZero()) return; // With Result still zero. if( Result.IsEqual( Modulus )) { // It is congruent to zero % ModN. Result.SetToZero(); return; } // Result is not zero at this point. if( Exponent.IsZero() ) { Result.SetFromULong( 1 ); return; } if( Modulus.ParamIsGreater( Result )) { // throw( new Exception( "This is not supposed to be input for RSA plain text." )); IntMath.Divide( Result, Modulus, Quotient, Remainder ); Result.Copy( Remainder ); } if( Exponent.IsOne()) { // Result stays the same. return; } if( !UsePresetBaseArray ) SetupGeneralBaseArray( Modulus ); XForModPower.Copy( Result ); ExponentCopy.Copy( Exponent ); int TestIndex = 0; Result.SetFromULong( 1 ); while( true ) { if( (ExponentCopy.GetD( 0 ) & 1) == 1 ) // If the bottom bit is 1. { IntMath.Multiply( Result, XForModPower ); ModularReduction( TempForModPower, Result ); Result.Copy( TempForModPower ); } ExponentCopy.ShiftRight( 1 ); // Divide by 2. if( ExponentCopy.IsZero()) break; // Square it. IntMath.Multiply( XForModPower, XForModPower ); ModularReduction( TempForModPower, XForModPower ); XForModPower.Copy( TempForModPower ); } // When ModularReduction() gets called it multiplies a base number // by a uint sized digit. So that can make the result one digit bigger // than GeneralBase. Then when they are added up you can get carry // bits that can make it a little bigger. int HowBig = Result.GetIndex() - Modulus.GetIndex(); // if( HowBig > 1 ) // throw( new Exception( "This does happen. Diff: " + HowBig.ToString() )); if( HowBig > 2 ) throw( new Exception( "The never happens. Diff: " + HowBig.ToString() )); ModularReduction( TempForModPower, Result ); Result.Copy( TempForModPower ); IntMath.Divide( Result, Modulus, Quotient, Remainder ); Result.Copy( Remainder ); if( Quotient.GetIndex() > 1 ) throw( new Exception( "This never happens. The quotient index is never more than 1." )); }
internal bool FindTwoFactorsWithFermat( Integer Product, Integer P, Integer Q, ulong MinimumX ) { ECTime StartTime = new ECTime(); StartTime.SetToNow(); Integer TestSqrt = new Integer(); Integer TestSquared = new Integer(); Integer SqrRoot = new Integer(); TestSquared.Copy( Product ); IntMath.Multiply( TestSquared, Product ); IntMath.SquareRoot( TestSquared, SqrRoot ); TestSqrt.Copy( SqrRoot ); IntMath.DoSquare( TestSqrt ); // IntMath.Multiply( TestSqrt, SqrRoot ); if( !TestSqrt.IsEqual( TestSquared )) throw( new Exception( "The square test was bad." )); // Some primes: // 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, // 101, 103, 107 P.SetToZero(); Q.SetToZero(); Integer TestX = new Integer(); SetupQuadResArray( Product ); ulong BaseTo37 = QuadResBigBase * 29UL * 31UL * 37UL; // ulong BaseTo31 = QuadResBigBase * 29UL * 31UL; ulong ProdModTo37 = IntMath.GetMod64( Product, BaseTo37 ); // ulong ProdModTo31 = IntMath.GetMod64( Product, BaseTo31 ); for( ulong BaseCount = 0; BaseCount < (29 * 31 * 37); BaseCount++ ) { if( (BaseCount & 0xF) == 0 ) Worker.ReportProgress( 0, "Find with Fermat BaseCount: " + BaseCount.ToString() ); if( Worker.CancellationPending ) return false; ulong Base = (BaseCount + 1) * QuadResBigBase; // BaseCount times 223,092,870. if( Base < MinimumX ) continue; Base = BaseCount * QuadResBigBase; // BaseCount times 223,092,870. for( uint Count = 0; Count < QuadResArrayLast; Count++ ) { // The maximum CountPart can be is just under half the size of // the Product. (Like if Y - X was equal to 1, and Y + X was // equal to the Product.) If it got anywhere near that big it // would be inefficient to try and find it this way. ulong CountPart = Base + QuadResArray[Count]; ulong Test = ProdModTo37 + (CountPart * CountPart); // ulong Test = ProdModTo31 + (CountPart * CountPart); Test = Test % BaseTo37; // Test = Test % BaseTo31; if( !IntegerMath.IsQuadResidue29( Test )) continue; if( !IntegerMath.IsQuadResidue31( Test )) continue; if( !IntegerMath.IsQuadResidue37( Test )) continue; ulong TestBytes = (CountPart & 0xFFFFF); TestBytes *= (CountPart & 0xFFFFF); ulong ProdBytes = Product.GetD( 1 ); ProdBytes <<= 8; ProdBytes |= Product.GetD( 0 ); uint FirstBytes = (uint)(TestBytes + ProdBytes); if( !IntegerMath.FirstBytesAreQuadRes( FirstBytes )) { // Worker.ReportProgress( 0, "First bytes aren't quad res." ); continue; } TestX.SetFromULong( CountPart ); IntMath.MultiplyULong( TestX, CountPart ); TestX.Add( Product ); // uint Mod37 = (uint)IntMath.GetMod32( TestX, 37 ); // if( !IntegerMath.IsQuadResidue37( Mod37 )) // continue; // Do more of these tests with 41, 43, 47... // if( !IntegerMath.IsQuadResidue41( Mod37 )) // continue; // Avoid doing this square root at all costs. if( IntMath.SquareRoot( TestX, SqrRoot )) { Worker.ReportProgress( 0, " " ); if( (CountPart & 1) == 0 ) Worker.ReportProgress( 0, "CountPart was even." ); else Worker.ReportProgress( 0, "CountPart was odd." ); // Found an exact square root. // P + (CountPart * CountPart) = Y*Y // P = (Y + CountPart)Y - CountPart) P.Copy( SqrRoot ); Integer ForSub = new Integer(); ForSub.SetFromULong( CountPart ); IntMath.Subtract( P, ForSub ); // Make Q the bigger one and put them in order. Q.Copy( SqrRoot ); Q.AddULong( CountPart ); if( P.IsOne() || Q.IsOne()) { // This happens when testing with small primes. Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "Went all the way to 1 in FindTwoFactorsWithFermat()." ); Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, " " ); P.SetToZero(); // It has no factors. Q.SetToZero(); return true; // Tested everything, so it's a prime. } Worker.ReportProgress( 0, "Found P: " + IntMath.ToString10( P ) ); Worker.ReportProgress( 0, "Found Q: " + IntMath.ToString10( Q ) ); Worker.ReportProgress( 0, "Seconds: " + StartTime.GetSecondsToNow().ToString( "N1" )); Worker.ReportProgress( 0, " " ); throw( new Exception( "Testing this." )); // return true; // With P and Q. } // else // Worker.ReportProgress( 0, "It was not an exact square root." ); } } // P and Q would still be zero if it never found them. return false; }
internal void VerifyFactors() { Integer TestFactors = new Integer(); TestFactors.SetToOne(); for( int Count = 0; Count < FactorsArrayLast; Count++ ) IntMath.Multiply( TestFactors, FactorsArray[Count].Factor ); if( !TestFactors.IsEqual( OriginalFindFrom )) throw( new Exception( "VerifyFactors didn't come out right." )); }
/* internal void ModularPowerOld( Integer Result, Integer Exponent, Integer ModN ) { if( Result.IsZero()) return; // With Result still zero. if( Result.IsEqual( ModN )) { // It is congruent to zero % ModN. Result.SetToZero(); return; } // Result is not zero at this point. if( Exponent.IsZero() ) { Result.SetFromULong( 1 ); return; } if( ModN.ParamIsGreater( Result )) { Divide( Result, ModN, Quotient, Remainder ); Result.Copy( Remainder ); } if( Exponent.IsEqualToULong( 1 )) { // Result stays the same. return; } XForModPower.Copy( Result ); ExponentCopy.Copy( Exponent ); Result.SetFromULong( 1 ); while( !ExponentCopy.IsZero()) { // If the bit is 1, then do a lot more work here. if( (ExponentCopy.GetD( 0 ) & 1) == 1 ) { // This is a multiplication for every _bit_. So a 1024-bit // modulus means this gets called roughly 512 times. // The commonly used public exponent is 65537, which has // only two bits set to 1, the rest are all zeros. But the // private key exponents are long randomish numbers. // (See: Hamming Weight.) Multiply( Result, XForModPower ); SubtractULong( ExponentCopy, 1 ); // Usually it's true that the Result is greater than ModN. if( ModN.ParamIsGreater( Result )) { // Here is where that really long division algorithm gets used a // lot in a loop. And this Divide() gets called roughly about // 512 times. Divide( Result, ModN, Quotient, Remainder ); Result.Copy( Remainder ); } } // Square it. // This is a multiplication for every _bit_. So a 1024-bit // modulus means this gets called 1024 times. Multiply( XForModPower, XForModPower ); ExponentCopy.ShiftRight( 1 ); // Divide by 2. if( ModN.ParamIsGreater( XForModPower )) { // And this Divide() gets called about 1024 times. Divide( XForModPower, ModN, Quotient, Remainder ); XForModPower.Copy( Remainder ); } } } */ internal void GreatestCommonDivisor( Integer X, Integer Y, Integer Gcd ) { // This is the basic Euclidean Algorithm. if( X.IsZero()) throw( new Exception( "Doing GCD with a parameter that is zero." )); if( Y.IsZero()) throw( new Exception( "Doing GCD with a parameter that is zero." )); if( X.IsEqual( Y )) { Gcd.Copy( X ); return; } // Don't change the original numbers that came in as parameters. if( X.ParamIsGreater( Y )) { GcdX.Copy( Y ); GcdY.Copy( X ); } else { GcdX.Copy( X ); GcdY.Copy( Y ); } while( true ) { Divide( GcdX, GcdY, Quotient, Remainder ); if( Remainder.IsZero()) { Gcd.Copy( GcdY ); // It's the smaller one. // It can't return from this loop until the remainder is zero. return; } GcdX.Copy( GcdY ); GcdY.Copy( Remainder ); } }
internal void MakeBaseNumbers() { try { MakeYBaseToPrimesArray(); if( Worker.CancellationPending ) return; Integer YTop = new Integer(); Integer Y = new Integer(); Integer XSquared = new Integer(); Integer Test = new Integer(); YTop.SetToZero(); uint XSquaredBitLength = 1; ExponentVectorNumber ExpNumber = new ExponentVectorNumber( IntMath ); uint Loops = 0; uint BSmoothCount = 0; uint BSmoothTestsCount = 0; uint IncrementYBy = 0; while( true ) { if( Worker.CancellationPending ) return; Loops++; if( (Loops & 0xF) == 0 ) { Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "Loops: " + Loops.ToString( "N0" )); Worker.ReportProgress( 0, "BSmoothCount: " + BSmoothCount.ToString( "N0" )); Worker.ReportProgress( 0, "BSmoothTestsCount: " + BSmoothTestsCount.ToString( "N0" )); if( BSmoothTestsCount != 0 ) { double TestsRatio = (double)BSmoothCount / (double)BSmoothTestsCount; Worker.ReportProgress( 0, "TestsRatio: " + TestsRatio.ToString( "N3" )); } } /* if( (Loops & 0xFFFFF) == 0 ) { // Use Task Manager to tweak the CPU Utilization if you want // it be below 100 percent. Thread.Sleep( 1 ); } */ // About 98 percent of the time it is running IncrementBy(). IncrementYBy += IncrementConst; uint BitLength = IncrementBy(); const uint SomeOptimumBitLength = 2; if( BitLength < SomeOptimumBitLength ) continue; // This BitLength has to do with how many small factors you want // in the number. But it doesn't limit your factor base at all. // You can still have any size prime in your factor base (up to // IntegerMath.PrimeArrayLength). Compare the size of // YBaseToPrimesArrayLast to IntegerMath.PrimeArrayLength. BSmoothTestsCount++; YTop.AddULong( IncrementYBy ); IncrementYBy = 0; Y.Copy( ProductSqrRoot ); Y.Add( YTop ); XSquared.Copy( Y ); IntMath.DoSquare( XSquared ); if( XSquared.ParamIsGreater( Product )) throw( new Exception( "Bug. XSquared.ParamIsGreater( Product )." )); IntMath.Subtract( XSquared, Product ); XSquaredBitLength = (uint)(XSquared.GetIndex() * 32); uint TopDigit = (uint)XSquared.GetD( XSquared.GetIndex()); uint TopLength = GetBitLength( TopDigit ); XSquaredBitLength += TopLength; if( XSquaredBitLength == 0 ) XSquaredBitLength = 1; // if( ItIsTheAnswerAlready( XSquared )) It's too unlikely. // QuadResCombinatorics could run in parallel to check for that, // and it would be way ahead of this. GetOneMainFactor(); if( OneMainFactor.IsEqual( XSquared )) { MakeFastExpNumber( ExpNumber ); } else { if( OneMainFactor.IsZero()) throw( new Exception( "OneMainFactor.IsZero()." )); IntMath.Divide( XSquared, OneMainFactor, Quotient, Remainder ); ExpNumber.SetFromTraditionalInteger( Quotient ); ExpNumber.Multiply( ExpOneMainFactor ); ExpNumber.GetTraditionalInteger( Test ); if( !Test.IsEqual( XSquared )) throw( new Exception( "!Test.IsEqual( XSquared )." )); } if( ExpNumber.IsBSmooth()) { BSmoothCount++; string DelimS = IntMath.ToString10( Y ) + "\t" + ExpNumber.ToDelimString(); Worker.ReportProgress( 1, DelimS ); if( (BSmoothCount & 0x3F) == 0 ) { Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "BitLength: " + BitLength.ToString()); Worker.ReportProgress( 0, "XSquaredBitLength: " + XSquaredBitLength.ToString()); Worker.ReportProgress( 0, ExpNumber.ToString() ); // What should BSmoothLimit be? // (Since FactorDictionary.cs will reduce the final factor base.) if( BSmoothCount > BSmoothLimit ) { Worker.ReportProgress( 0, "Found enough to make the matrix." ); Worker.ReportProgress( 0, "BSmoothCount: " + BSmoothCount.ToString( "N0" )); Worker.ReportProgress( 0, "BSmoothLimit: " + BSmoothLimit.ToString( "N0" )); Worker.ReportProgress( 0, "Seconds: " + StartTime.GetSecondsToNow().ToString( "N1" )); double Seconds = StartTime.GetSecondsToNow(); int Minutes = (int)Seconds / 60; int Hours = Minutes / 60; Minutes = Minutes % 60; Seconds = Seconds % 60; string ShowS = "Hours: " + Hours.ToString( "N0" ) + " Minutes: " + Minutes.ToString( "N0" ) + " Seconds: " + Seconds.ToString( "N0" ); Worker.ReportProgress( 0, ShowS ); return; } } } } } catch( Exception Except ) { throw( new Exception( "Exception in MakeBaseNumbers():\r\n" + Except.Message )); } }
internal void Subtract( Integer Result, Integer ToSub ) { // This checks that the sign is equal too. if( Result.IsEqual( ToSub )) { Result.SetToZero(); return; } // ParamIsGreater() handles positive and negative values, so if the // parameter is more toward the positive side then it's true. It's greater. // The most common form. They are both positive. if( !Result.IsNegative && !ToSub.IsNegative ) { if( ToSub.ParamIsGreater( Result )) { SubtractPositive( Result, ToSub ); return; } // ToSub is bigger. TempSub1.Copy( Result ); TempSub2.Copy( ToSub ); SubtractPositive( TempSub2, TempSub1 ); Result.Copy( TempSub2 ); Result.IsNegative = true; return; } if( Result.IsNegative && !ToSub.IsNegative ) { TempSub1.Copy( Result ); TempSub1.IsNegative = false; TempSub1.Add( ToSub ); Result.Copy( TempSub1 ); Result.IsNegative = true; return; } if( !Result.IsNegative && ToSub.IsNegative ) { TempSub1.Copy( ToSub ); TempSub1.IsNegative = false; Result.Add( TempSub1 ); return; } if( Result.IsNegative && ToSub.IsNegative ) { TempSub1.Copy( Result ); TempSub1.IsNegative = false; TempSub2.Copy( ToSub ); TempSub2.IsNegative = false; // -12 - -7 = -12 + 7 = -5 // Comparing the positive numbers here. if( TempSub2.ParamIsGreater( TempSub1 )) { SubtractPositive( TempSub1, TempSub2 ); Result.Copy( TempSub1 ); Result.IsNegative = true; return; } // -7 - -12 = -7 + 12 = 5 SubtractPositive( TempSub2, TempSub1 ); Result.Copy( TempSub2 ); Result.IsNegative = false; return; } }
// 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; }
private void DoCRTTest( Integer StartingNumber ) { CRTMath CRTMath1 = new CRTMath( Worker ); ECTime CRTTestTime = new ECTime(); ChineseRemainder CRTTest = new ChineseRemainder( IntMath ); ChineseRemainder CRTTest2 = new ChineseRemainder( IntMath ); ChineseRemainder CRTAccumulate = new ChineseRemainder( IntMath ); ChineseRemainder CRTToTest = new ChineseRemainder( IntMath ); ChineseRemainder CRTTempEqual = new ChineseRemainder( IntMath ); ChineseRemainder CRTTestEqual = new ChineseRemainder( IntMath ); Integer BigBase = new Integer(); Integer ToTest = new Integer(); Integer Accumulate = new Integer(); Integer Test1 = new Integer(); Integer Test2 = new Integer(); CRTTest.SetFromTraditionalInteger( StartingNumber ); // If the digit array size isn't set right in relation to // Integer.DigitArraySize then it can cause an error here. CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( StartingNumber )) throw( new Exception( " !Accumulate.IsEqual( Result )." )); CRTTestEqual.SetFromTraditionalInteger( Accumulate ); if( !CRTMath1.IsEqualToInteger( CRTTestEqual, Accumulate )) throw( new Exception( "IsEqualToInteger() didn't work." )); // Make sure it works with even numbers too. Test1.Copy( StartingNumber ); Test1.SetD( 0, Test1.GetD( 0 ) & 0xFE ); CRTTest.SetFromTraditionalInteger( Test1 ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( Test1 )) throw( new Exception( "For even numbers. !Accumulate.IsEqual( Test )." )); //////////// // Make sure the size of this works with the Integer size because // an overflow is hard to find. CRTTestTime.SetToNow(); Test1.SetToMaxValueForCRT(); CRTTest.SetFromTraditionalInteger( Test1 ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( Test1 )) throw( new Exception( "For the max value. !Accumulate.IsEqual( Test1 )." )); // Worker.ReportProgress( 0, "CRT Max test seconds: " + CRTTestTime.GetSecondsToNow().ToString( "N1" )); // Worker.ReportProgress( 0, "MaxValue: " + IntMath.ToString10( Accumulate )); // Worker.ReportProgress( 0, "MaxValue.Index: " + Accumulate.GetIndex().ToString()); // Multiplicative Inverse test: Integer TestDivideBy = new Integer(); Integer TestProduct = new Integer(); ChineseRemainder CRTTestDivideBy = new ChineseRemainder( IntMath ); ChineseRemainder CRTTestProduct = new ChineseRemainder( IntMath ); TestDivideBy.Copy( StartingNumber ); TestProduct.Copy( StartingNumber ); IntMath.Multiply( TestProduct, TestDivideBy ); CRTTestDivideBy.SetFromTraditionalInteger( TestDivideBy ); CRTTestProduct.SetFromTraditionalInteger( TestDivideBy ); CRTTestProduct.Multiply( CRTTestDivideBy ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTestProduct ); if( !Accumulate.IsEqual( TestProduct )) throw( new Exception( "Multiply test was bad." )); IntMath.Divide( TestProduct, TestDivideBy, Quotient, Remainder ); if( !Remainder.IsZero()) throw( new Exception( "This test won't work unless it divides it exactly." )); ChineseRemainder CRTTestQuotient = new ChineseRemainder( IntMath ); CRTMath1.MultiplicativeInverse( CRTTestProduct, CRTTestDivideBy, CRTTestQuotient ); // Yes, multiplicative inverse is the same number // as with regular division. Integer TestQuotient = new Integer(); CRTMath1.GetTraditionalInteger( TestQuotient, CRTTestQuotient ); if( !TestQuotient.IsEqual( Quotient )) throw( new Exception( "Modular Inverse in DoCRTTest didn't work." )); // Subtract Test1.Copy( StartingNumber ); IntMath.SetFromString( Test2, "12345678901234567890123456789012345" ); CRTTest.SetFromTraditionalInteger( Test1 ); CRTTest2.SetFromTraditionalInteger( Test2 ); CRTTest.Subtract( CRTTest2 ); IntMath.Subtract( Test1, Test2 ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( Test1 )) throw( new Exception( "Subtract test was bad." )); // Add Test1.Copy( StartingNumber ); IntMath.SetFromString( Test2, "12345678901234567890123456789012345" ); CRTTest.SetFromTraditionalInteger( Test1 ); CRTTest2.SetFromTraditionalInteger( Test2 ); CRTTest.Add( CRTTest2 ); IntMath.Add( Test1, Test2 ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( Test1 )) throw( new Exception( "Add test was bad." )); ///////// CRTBaseMath CBaseMath = new CRTBaseMath( Worker, CRTMath1 ); ChineseRemainder CRTInput = new ChineseRemainder( IntMath ); CRTInput.SetFromTraditionalInteger( StartingNumber ); Test1.Copy( StartingNumber ); IntMath.SetFromString( Test2, "12345678901234567890123456789012345" ); IntMath.Add( Test1, Test2 ); Integer TestModulus = new Integer(); TestModulus.Copy( Test1 ); ChineseRemainder CRTTestModulus = new ChineseRemainder( IntMath ); CRTTestModulus.SetFromTraditionalInteger( TestModulus ); Integer Exponent = new Integer(); Exponent.SetFromULong( PubKeyExponentUint ); CBaseMath.ModularPower( CRTInput, Exponent, CRTTestModulus, false ); IntMath.IntMathNew.ModularPower( StartingNumber, Exponent, TestModulus, false ); if( !CRTMath1.IsEqualToInteger( CRTInput, StartingNumber )) throw( new Exception( "CRTBase ModularPower() didn't work." )); CRTBase ExpTest = new CRTBase( IntMath ); CBaseMath.SetFromCRTNumber( ExpTest, CRTInput ); CBaseMath.GetExponentForm( ExpTest, 37 ); // Worker.ReportProgress( 0, "CRT was good." ); }
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. } }
internal bool DecryptWithQInverse( Integer EncryptedNumber, Integer DecryptedNumber, Integer TestDecryptedNumber, Integer PubKeyN, Integer PrivKInverseExponentDP, Integer PrivKInverseExponentDQ, Integer PrimeP, Integer PrimeQ, BackgroundWorker Worker ) { Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "Top of DecryptWithQInverse()." ); // QInv and the dP and dQ numbers are normally already set up before // you start your listening socket. ECTime DecryptTime = new ECTime(); DecryptTime.SetToNow(); // See section 5.1.2 of RFC 2437 for these steps: // http://tools.ietf.org/html/rfc2437 // 2.2 Let m_1 = c^dP mod p. // 2.3 Let m_2 = c^dQ mod q. // 2.4 Let h = qInv ( m_1 - m_2 ) mod p. // 2.5 Let m = m_2 + hq. Worker.ReportProgress( 0, "EncryptedNumber: " + IntMath.ToString10( EncryptedNumber )); // 2.2 Let m_1 = c^dP mod p. TestForDecrypt.Copy( EncryptedNumber ); IntMathNewForP.ModularPower( TestForDecrypt, PrivKInverseExponentDP, PrimeP, true ); if( Worker.CancellationPending ) return false; M1ForInverse.Copy( TestForDecrypt ); // 2.3 Let m_2 = c^dQ mod q. TestForDecrypt.Copy( EncryptedNumber ); IntMathNewForQ.ModularPower( TestForDecrypt, PrivKInverseExponentDQ, PrimeQ, true ); if( Worker.CancellationPending ) return false; M2ForInverse.Copy( TestForDecrypt ); // 2.4 Let h = qInv ( m_1 - m_2 ) mod p. // How many is optimal to avoid the division? int HowManyIsOptimal = (PrimeP.GetIndex() * 3); for( int Count = 0; Count < HowManyIsOptimal; Count++ ) { if( M1ForInverse.ParamIsGreater( M2ForInverse )) M1ForInverse.Add( PrimeP ); else break; } if( M1ForInverse.ParamIsGreater( M2ForInverse )) { M1M2SizeDiff.Copy( M2ForInverse ); IntMath.Subtract( M1M2SizeDiff, M1ForInverse ); // Unfortunately this long Divide() has to be done. IntMath.Divide( M1M2SizeDiff, PrimeP, Quotient, Remainder ); Quotient.AddULong( 1 ); Worker.ReportProgress( 0, "The Quotient for M1M2SizeDiff is: " + IntMath.ToString10( Quotient )); IntMath.Multiply( Quotient, PrimeP ); M1ForInverse.Add( Quotient ); } M1MinusM2.Copy( M1ForInverse ); IntMath.Subtract( M1MinusM2, M2ForInverse ); if( M1MinusM2.IsNegative ) throw( new Exception( "This is a bug. M1MinusM2.IsNegative is true." )); if( QInv.IsNegative ) throw( new Exception( "This is a bug. QInv.IsNegative is true." )); HForQInv.Copy( M1MinusM2 ); IntMath.Multiply( HForQInv, QInv ); if( HForQInv.IsNegative ) throw( new Exception( "This is a bug. HForQInv.IsNegative is true." )); if( PrimeP.ParamIsGreater( HForQInv )) { IntMath.Divide( HForQInv, PrimeP, Quotient, Remainder ); HForQInv.Copy( Remainder ); } // 2.5 Let m = m_2 + hq. DecryptedNumber.Copy( HForQInv ); IntMath.Multiply( DecryptedNumber, PrimeQ ); DecryptedNumber.Add( M2ForInverse ); if( !TestDecryptedNumber.IsEqual( DecryptedNumber )) throw( new Exception( "!TestDecryptedNumber.IsEqual( DecryptedNumber )." )); Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "DecryptedNumber: " + IntMath.ToString10( DecryptedNumber )); Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "TestDecryptedNumber: " + IntMath.ToString10( TestDecryptedNumber )); Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "Decrypt with QInv time seconds: " + DecryptTime.GetSecondsToNow().ToString( "N2" )); Worker.ReportProgress( 0, " " ); return true; }
private bool GetFactors( Integer Y, ExponentVectorNumber XExp ) { Integer XRoot = new Integer(); Integer X = new Integer(); Integer XwithY = new Integer(); Integer Gcd = new Integer(); XExp.GetTraditionalInteger( X ); if( !IntMath.SquareRoot( X, XRoot )) throw( new Exception( "Bug. X should have an exact square root." )); XwithY.Copy( Y ); XwithY.Add( XRoot ); IntMath.GreatestCommonDivisor( Product, XwithY, Gcd ); if( !Gcd.IsOne()) { if( !Gcd.IsEqual( Product )) { SolutionP.Copy( Gcd ); IntMath.Divide( Product, SolutionP, Quotient, Remainder ); if( !Remainder.IsZero()) throw( new Exception( "The Remainder with SolutionP can't be zero." )); SolutionQ.Copy( Quotient ); MForm.ShowStatus( "SolutionP: " + IntMath.ToString10( SolutionP )); MForm.ShowStatus( "SolutionQ: " + IntMath.ToString10( SolutionQ )); return true; } else { MForm.ShowStatus( "GCD was Product." ); } } else { MForm.ShowStatus( "GCD was one." ); } MForm.ShowStatus( "XRoot: " + IntMath.ToString10( XRoot )); MForm.ShowStatus( "Y: " + IntMath.ToString10( Y )); XwithY.Copy( Y ); if( Y.ParamIsGreater( XRoot )) throw( new Exception( "This can't be right. XRoot is bigger than Y." )); IntMath.Subtract( Y, XRoot ); IntMath.GreatestCommonDivisor( Product, XwithY, Gcd ); if( !Gcd.IsOne()) { if( !Gcd.IsEqual( Product )) { SolutionP.Copy( Gcd ); IntMath.Divide( Product, SolutionP, Quotient, Remainder ); if( !Remainder.IsZero()) throw( new Exception( "The Remainder with SolutionP can't be zero." )); SolutionQ.Copy( Quotient ); MForm.ShowStatus( "SolutionP: " + IntMath.ToString10( SolutionP )); MForm.ShowStatus( "SolutionQ: " + IntMath.ToString10( SolutionQ )); return true; } else { MForm.ShowStatus( "GCD was Product." ); } } else { MForm.ShowStatus( "GCD was one." ); } return false; }
internal void ModularPower( Integer Result, Integer Exponent, Integer GeneralBase ) { // The square and multiply method is in Wikipedia: // https://en.wikipedia.org/wiki/Exponentiation_by_squaring // x^n = (x^2)^((n - 1)/2) if n is odd. // x^n = (x^2)^(n/2) if n is even. if( Result.IsZero()) return; // With Result still zero. if( Result.IsEqual( GeneralBase )) { // It is congruent to zero % ModN. Result.SetToZero(); return; } // Result is not zero at this point. if( Exponent.IsZero() ) { Result.SetFromULong( 1 ); return; } if( GeneralBase.ParamIsGreater( Result )) { // throw( new Exception( "This is not supposed to be input for RSA plain text." )); IntMath.Divide( Result, GeneralBase, Quotient, Remainder ); Result.Copy( Remainder ); } if( Exponent.IsEqualToULong( 1 )) { // Result stays the same. return; } // This could also be called ahead of time if the base (the modulus) // doesn't change. Like when your public key doesn't change. SetupGeneralBaseArray( GeneralBase ); XForModPower.Copy( Result ); ExponentCopy.Copy( Exponent ); int TestIndex = 0; Result.SetFromULong( 1 ); while( true ) { if( (ExponentCopy.GetD( 0 ) & 1) == 1 ) // If the bottom bit is 1. { IntMath.Multiply( Result, XForModPower ); // Modular Reduction: AddByGeneralBaseArrays( TempForModPower, Result ); Result.Copy( TempForModPower ); } ExponentCopy.ShiftRight( 1 ); // Divide by 2. if( ExponentCopy.IsZero()) break; // Square it. IntMath.Multiply( XForModPower, XForModPower ); // Modular Reduction: AddByGeneralBaseArrays( TempForModPower, XForModPower ); XForModPower.Copy( TempForModPower ); } // When AddByGeneralBaseArrays() gets called it multiplies a number // by a uint sized digit. So that can make the result one digit bigger // than GeneralBase. Then when they are added up you can get carry // bits that can make it a little bigger. // If by chance you got a carry bit on _every_ addition that was done // in AddByGeneralBaseArrays() then this number could increase in size // by 1 bit for each addition that was done. It would take 32 bits of // carrying for HowBig to increase by 1. // See HowManyToAdd in AddByGeneralBaseArrays() for why this check is done. int HowBig = Result.GetIndex() - GeneralBase.GetIndex(); if( HowBig > 2 ) // I have not seen this happen yet. throw( new Exception( "The difference in index size was more than 2. Diff: " + HowBig.ToString() )); // So this Quotient has only one or two 32-bit digits in it. // And this Divide() is only called once at the end. Not in the loop. IntMath.Divide( Result, GeneralBase, Quotient, Remainder ); Result.Copy( Remainder ); }