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 FindAllFactors( Integer FindFromNotChanged ) { // ShowStats(); // So far. OriginalFindFrom.Copy( FindFromNotChanged ); FindFrom.Copy( FindFromNotChanged ); NumbersTested++; ClearFactorsArray(); Integer OneFactor; OneFactorRec Rec; // while( not forever ) for( int Count = 0; Count < 1000; Count++ ) { if( Worker.CancellationPending ) return; uint SmallPrime = IntMath.IsDivisibleBySmallPrime( FindFrom ); if( SmallPrime == 0 ) break; // No more small primes. // Worker.ReportProgress( 0, "Found a small prime factor: " + SmallPrime.ToString() ); AddToStats( SmallPrime ); OneFactor = new Integer(); OneFactor.SetFromULong( SmallPrime ); Rec = new OneFactorRec(); Rec.Factor = OneFactor; Rec.IsDefinitelyAPrime = true; AddFactorRec( Rec ); if( FindFrom.IsULong()) { ulong CheckLast = FindFrom.GetAsULong(); if( CheckLast == SmallPrime ) { Worker.ReportProgress( 0, "It only had small prime factors." ); VerifyFactors(); return; // It had only small prime factors. } } IntMath.Divide( FindFrom, OneFactor, Quotient, Remainder ); if( !Remainder.IsZero()) throw( new Exception( "Bug in FindAllFactors. Remainder is not zero." )); FindFrom.Copy( Quotient ); if( FindFrom.IsOne()) throw( new Exception( "Bug in FindAllFactors. This was already checked for 1." )); } // Worker.ReportProgress( 0, "No more small primes." ); if( IsFermatPrimeAdded( FindFrom )) { VerifyFactors(); return; } // while( not forever ) for( int Count = 0; Count < 1000; Count++ ) { if( Worker.CancellationPending ) return; // If FindFrom is a ulong then this will go up to the square root of // FindFrom and return zero if it doesn't find it there. So it can't // go up to the whole value of FindFrom. uint SmallFactor = NumberIsDivisibleByUInt( FindFrom ); if( SmallFactor == 0 ) break; // This is necessarily a prime because it was the smallest one found. AddToStats( SmallFactor ); // Worker.ReportProgress( 0, "Found a small factor: " + SmallFactor.ToString( "N0" )); OneFactor = new Integer(); OneFactor.SetFromULong( SmallFactor ); Rec = new OneFactorRec(); Rec.Factor = OneFactor; Rec.IsDefinitelyAPrime = true; // The smallest factor. It is necessarily a prime. AddFactorRec( Rec ); IntMath.Divide( FindFrom, OneFactor, Quotient, Remainder ); if( !Remainder.IsZero()) throw( new Exception( "Bug in FindAllFactors. Remainder is not zero. Second part." )); if( Quotient.IsOne()) throw( new Exception( "This can't happen here. It can't go that high." )); FindFrom.Copy( Quotient ); if( IsFermatPrimeAdded( FindFrom )) { VerifyFactors(); return; } } if( IsFermatPrimeAdded( FindFrom )) { VerifyFactors(); return; } // If it got this far then it's definitely composite or definitely // small enough to factor. Integer P = new Integer(); Integer Q = new Integer(); bool TestedAllTheWay = FindTwoFactorsWithFermat( FindFrom, P, Q, 0 ); if( !P.IsZero()) { // Q is necessarily prime because it's bigger than the square root. // But P is not necessarily prime. // P is the smaller one, so add it first. if( IsFermatPrimeAdded( P )) { Worker.ReportProgress( 0, "P from Fermat method was probably a prime." ); } else { OneFactor = new Integer(); OneFactor.Copy( P ); Rec = new OneFactorRec(); Rec.Factor = OneFactor; Rec.IsDefinitelyNotAPrime = true; AddFactorRec( Rec ); } Worker.ReportProgress( 0, "Q is necessarily prime." ); OneFactor = new Integer(); OneFactor.Copy( Q ); Rec = new OneFactorRec(); Rec.Factor = OneFactor; Rec.IsDefinitelyAPrime = true; AddFactorRec( Rec ); } else { // Didn't find any with Fermat. OneFactor = new Integer(); OneFactor.Copy( FindFrom ); Rec = new OneFactorRec(); Rec.Factor = OneFactor; if( TestedAllTheWay ) Rec.IsDefinitelyAPrime = true; else Rec.IsDefinitelyNotAPrime = true; AddFactorRec( Rec ); } Worker.ReportProgress( 0, "That's all it could find." ); VerifyFactors(); }
internal void SetupGeneralBaseArray( Integer GeneralBase ) { // The input to the accumulator can be twice the bit length of GeneralBase. int HowMany = ((GeneralBase.GetIndex() + 1) * 2) + 10; // Plus some extra for carries... if( GeneralBaseArray == null ) { GeneralBaseArray = new Integer[HowMany]; } if( GeneralBaseArray.Length < HowMany ) { GeneralBaseArray = new Integer[HowMany]; } Integer Base = new Integer(); Integer BaseValue = new Integer(); Base.SetFromULong( 256 ); // 0x100 IntMath.MultiplyUInt( Base, 256 ); // 0x10000 IntMath.MultiplyUInt( Base, 256 ); // 0x1000000 IntMath.MultiplyUInt( Base, 256 ); // 0x100000000 is the base of this number system. BaseValue.SetFromULong( 1 ); for( int Count = 0; Count < HowMany; Count++ ) { if( GeneralBaseArray[Count] == null ) GeneralBaseArray[Count] = new Integer(); IntMath.Divide( BaseValue, GeneralBase, Quotient, Remainder ); GeneralBaseArray[Count].Copy( Remainder ); // If this ever happened it would be a bug because // the point of copying the Remainder in to BaseValue // is to keep it down to a reasonable size. // And Base here is one bit bigger than a uint. if( Base.ParamIsGreater( Quotient )) throw( new Exception( "Bug. This never happens: Base.ParamIsGreater( Quotient )" )); // Keep it to mod GeneralBase so Divide() doesn't // have to do so much work. BaseValue.Copy( Remainder ); IntMath.Multiply( BaseValue, Base ); } }
internal void GetTraditionalInteger( Integer BigBase, Integer BasePart, Integer ToTest, Integer Accumulate ) { // This takes several seconds for a large number. try { // The first few numbers for the base: // 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 // This first one has the prime 2 as its base so it's going to // be set to either zero or one. Accumulate.SetFromULong( (uint)DigitsArray[0].Value ); BigBase.SetFromULong( 2 ); // Count starts at 1, so it's the prime 3. for( int Count = 1; Count < DigitsArraySize; Count++ ) { for( uint CountPrime = 0; CountPrime < DigitsArray[Count].Prime; CountPrime++ ) { ToTest.Copy( BigBase ); IntMath.MultiplyUInt( ToTest, CountPrime ); // Notice that the first time through this loop it's zero, so the // base part isn't added if it's already congruent to the Value. // So even though it goes all the way up through the DigitsArray, // this whole thing could add up to a small number like 7. // Compare this part with how GetMod32() is used in // SetFromTraditionalInteger(). And also, compare this with how // IntegerMath.NumberIsDivisibleByUInt() works. BasePart.Copy( ToTest ); ToTest.Add( Accumulate ); // If it's congruent to the Value mod Prime then it's the right number. if( (uint)DigitsArray[Count].Value == IntMath.GetMod32( ToTest, (uint)DigitsArray[Count].Prime )) { Accumulate.Add( BasePart ); break; } } // The Integers have to be big enough to multiply this base. IntMath.MultiplyUInt( BigBase, (uint)DigitsArray[Count].Prime ); } // Returns with Accumulate for the value. } catch( Exception Except ) { throw( new Exception( "Exception in GetTraditionalInteger(): " + Except.Message )); } }
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 bool FindTheFactors() { MakeQuadResToPrimesArray(); if( Worker.CancellationPending ) return false; // =========== MakeQuadResDigitsArrayRec( 0, 0, 7 ); MakeQuadResDigitsArrayRec( 1, 8, 9 ); MakeQuadResDigitsArrayRec( 2, 10, 10 ); // The last one should have an array that is // as large as possible because of // IncrementDigitsWithBitTest(). MakeQuadResDigitsArrayRec( 3, 11, 12 ); if( Worker.CancellationPending ) return false; SetupBaseValues(); if( Worker.CancellationPending ) return false; MakeMatchingInverseArrays(); if( Worker.CancellationPending ) return false; Worker.ReportProgress( 0, "After MakeMatchingInverseArrays()." ); Integer X = new Integer(); Integer XSquared = new Integer(); Integer SqrRoot = new Integer(); Integer YSquared = new Integer(); MakeGoodXBitsArray(); Worker.ReportProgress( 0, "After MakeGoodXBitsArray();." ); uint Loops = 0; while( true ) { if( Worker.CancellationPending ) return false; Loops++; if( (Loops & 0x3FFFFF) == 0 ) { Worker.ReportProgress( 0, "Loops: " + Loops.ToString()); } GetIntegerValue( X ); if( !IsInGoodXBitsArray( (uint)X.GetD( 0 ))) { // This happens with the increment bit test // because sometimes it just increments to the // next full accumulated value. if( !IncrementDigitsWithBitTest()) { Worker.ReportProgress( 0, "Incremented to the end." ); return false; } continue; } if( !IsGoodXForAllPrimes( X )) { if( !IncrementDigitsWithBitTest()) { Worker.ReportProgress( 0, "Incremented to the end." ); return false; } continue; } XSquared.Copy( X ); IntMath.DoSquare( XSquared ); YSquared.Copy( Product ); YSquared.Add( XSquared ); if( IntMath.SquareRoot( YSquared, SqrRoot )) { return IsSolution( X, SqrRoot ); } if( !IncrementDigitsWithBitTest()) { Worker.ReportProgress( 0, "Incremented to the end." ); return false; } } }
internal void TestBigDigits() { try { uint Base = 2 * 3 * 5; Integer BigBase = new Integer(); Integer Minus1 = new Integer(); Integer IntExponent = new Integer(); Integer IntBase = new Integer(); Integer Gcd = new Integer(); BigBase.SetFromULong( Base ); IntBase.SetFromULong( Base ); for( uint Count = 2; Count < 200; Count++ ) { // At Count = 2 BigBase will be 100, or 10^2. IntMath.MultiplyULong( BigBase, Base ); uint Exponent = Count + 1; IntExponent.SetFromULong( Exponent ); IntMath.GreatestCommonDivisor( IntBase, IntExponent, Gcd ); if( !Gcd.IsOne() ) { // ShowStatus( Exponent.ToString() + " has a factor in common with base." ); continue; } Minus1.Copy( BigBase ); IntMath.SubtractULong( Minus1, 1 ); ShowStatus( " " ); ulong ModExponent = IntMath.GetMod32( Minus1, Exponent ); if( ModExponent != 0 ) ShowStatus( Exponent.ToString() + " is not a prime." ); else ShowStatus( Exponent.ToString() + " might or might not be a prime." ); uint FirstFactor = IntMath.GetFirstPrimeFactor( Exponent ); if( (FirstFactor == 0) || (FirstFactor == Exponent)) { ShowStatus( Exponent.ToString() + " is a prime." ); } else { ShowStatus( Exponent.ToString() + " is composite with a factor of " + FirstFactor.ToString() ); } } } catch( Exception Except ) { ShowStatus( "Exception in TestDigits()." ); ShowStatus( Except.Message ); } }
// These bottom digits are 0 for each prime that gets // multiplied by the base. So they keep getting one // more zero at the bottom of each one. // But the digits in BaseModArray only have the zeros // at the bottom on the ones that are smaller than the // modulus. // At BaseArray[0] it's 1, 1, 1, 1, 1, .... for all of them. // 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 // 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 0, 0 // 30, 30, 30, 30, 1, 7, 11, 13, 4, 8, 2, 0, 0, 0 private void SetupBaseArray() { // The first few numbers for the base: // 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 try { if( NumbersArray == null ) throw( new Exception( "NumbersArray should have already been setup in SetupBaseArray()." )); BaseStringsArray = new string[ChineseRemainder.DigitsArraySize]; BaseArray = new Integer[ChineseRemainder.DigitsArraySize]; CRTBaseArray = new ChineseRemainder[ChineseRemainder.DigitsArraySize]; Integer SetBase = new Integer(); ChineseRemainder CRTSetBase = new ChineseRemainder( IntMath ); Integer BigBase = new Integer(); ChineseRemainder CRTBigBase = new ChineseRemainder( IntMath ); BigBase.SetFromULong( 2 ); CRTBigBase.SetFromUInt( 2 ); string BaseS = "2"; SetBase.SetToOne(); CRTSetBase.SetToOne(); // The base at zero is 1. BaseArray[0] = SetBase; CRTBaseArray[0] = CRTSetBase; BaseStringsArray[0] = "1"; ChineseRemainder CRTTemp = new ChineseRemainder( IntMath ); // The first time through the loop the base // is set to 2. // So BaseArray[0] = 1; // So BaseArray[1] = 2; // So BaseArray[2] = 6; // So BaseArray[3] = 30; // And so on... // In BaseArray[3] digits at 2, 3 and 5 are set to zero. // In BaseArray[4] digits at 2, 3, 5 and 7 are set to zero. for( int Count = 1; Count < ChineseRemainder.DigitsArraySize; Count++ ) { SetBase = new Integer(); CRTSetBase = new ChineseRemainder( IntMath ); SetBase.Copy( BigBase ); CRTSetBase.Copy( CRTBigBase ); BaseStringsArray[Count] = BaseS; BaseArray[Count] = SetBase; CRTBaseArray[Count] = CRTSetBase; // if( Count < 50 ) // Worker.ReportProgress( 0, CRTBaseArray[Count].GetString() ); if( !IsEqualToInteger( CRTBaseArray[Count], BaseArray[Count] )) throw( new Exception( "Bug. The bases aren't equal." )); // Multiply it for the next BigBase. uint Prime = IntMath.GetPrimeAt( Count ); BaseS = BaseS + "*" + Prime.ToString(); IntMath.MultiplyUInt( BigBase, Prime ); CRTBigBase.Multiply( NumbersArray[IntMath.GetPrimeAt( Count )] ); } } catch( Exception Except ) { throw( new Exception( "Exception in SetupBaseArray(): " + Except.Message )); } }
internal bool MultiplicativeInverse( Integer X, Integer Modulus, Integer MultInverse, BackgroundWorker Worker ) { // This is the extended Euclidean Algorithm. // A*X + B*Y = Gcd // A*X + B*Y = 1 If there's a multiplicative inverse. // A*X = 1 - B*Y so A is the multiplicative inverse of X mod Y. if( X.IsZero()) throw( new Exception( "Doing Multiplicative Inverse with a parameter that is zero." )); if( Modulus.IsZero()) throw( new Exception( "Doing Multiplicative Inverse with a parameter that is zero." )); // This happens sometimes: // if( Modulus.ParamIsGreaterOrEq( X )) // throw( new Exception( "Modulus.ParamIsGreaterOrEq( X ) for Euclid." )); // Worker.ReportProgress( 0, " " ); // Worker.ReportProgress( 0, " " ); // Worker.ReportProgress( 0, "Top of mod inverse." ); // U is the old part to keep. U0.SetToZero(); U1.SetToOne(); U2.Copy( Modulus ); // Don't change the original numbers that came in as parameters. // V is the new part. V0.SetToOne(); V1.SetToZero(); V2.Copy( X ); T0.SetToZero(); T1.SetToZero(); T2.SetToZero(); Quotient.SetToZero(); // while( not forever if there's a problem ) for( int Count = 0; Count < 10000; Count++ ) { if( U2.IsNegative ) throw( new Exception( "U2 was negative." )); if( V2.IsNegative ) throw( new Exception( "V2 was negative." )); Divide( U2, V2, Quotient, Remainder ); if( Remainder.IsZero()) { Worker.ReportProgress( 0, "Remainder is zero. No multiplicative-inverse." ); return false; } TempEuclid1.Copy( U0 ); TempEuclid2.Copy( V0 ); Multiply( TempEuclid2, Quotient ); Subtract( TempEuclid1, TempEuclid2 ); T0.Copy( TempEuclid1 ); TempEuclid1.Copy( U1 ); TempEuclid2.Copy( V1 ); Multiply( TempEuclid2, Quotient ); Subtract( TempEuclid1, TempEuclid2 ); T1.Copy( TempEuclid1 ); TempEuclid1.Copy( U2 ); TempEuclid2.Copy( V2 ); Multiply( TempEuclid2, Quotient ); Subtract( TempEuclid1, TempEuclid2 ); T2.Copy( TempEuclid1 ); U0.Copy( V0 ); U1.Copy( V1 ); U2.Copy( V2 ); V0.Copy( T0 ); V1.Copy( T1 ); V2.Copy( T2 ); if( Remainder.IsOne()) { // Worker.ReportProgress( 0, " " ); // Worker.ReportProgress( 0, "Remainder is 1. There is a multiplicative-inverse." ); break; } } MultInverse.Copy( T0 ); if( MultInverse.IsNegative ) { Add( MultInverse, Modulus ); } // Worker.ReportProgress( 0, "MultInverse: " + ToString10( MultInverse )); TestForModInverse1.Copy( MultInverse ); TestForModInverse2.Copy( X ); Multiply( TestForModInverse1, TestForModInverse2 ); Divide( TestForModInverse1, Modulus, Quotient, Remainder ); if( !Remainder.IsOne()) // By the definition of Multiplicative inverse: throw( new Exception( "Bug. MultInverse is wrong: " + ToString10( Remainder ))); // Worker.ReportProgress( 0, "MultInverse is the right number: " + ToString10( MultInverse )); return true; }
internal void ModularPower( ChineseRemainder CRTResult, Integer Exponent, ChineseRemainder CRTModulus, bool UsePresetBaseArray ) { // The square and multiply method is in Wikipedia: // https://en.wikipedia.org/wiki/Exponentiation_by_squaring if( Worker.CancellationPending ) return; if( CRTResult.IsZero()) return; // With CRTResult still zero. if( CRTResult.IsEqual( CRTModulus )) { // It is congruent to zero % ModN. CRTResult.SetToZero(); return; } // Result is not zero at this point. if( Exponent.IsZero() ) { CRTResult.SetToOne(); return; } Integer Result = new Integer(); CRTMath1.GetTraditionalInteger( Result, CRTResult ); Integer Modulus = new Integer(); CRTMath1.GetTraditionalInteger( Modulus, CRTModulus ); 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 ); CRTResult.SetFromTraditionalInteger( Remainder ); } if( Exponent.IsEqualToULong( 1 )) { // Result stays the same. return; } if( !UsePresetBaseArray ) SetupBaseModArray( Modulus ); if( CRTBaseModArray == null ) throw( new Exception( "SetupBaseModArray() should have already been done here." )); CRTXForModPower.Copy( CRTResult ); ExponentCopy.Copy( Exponent ); int TestIndex = 0; CRTResult.SetToOne(); int LoopsTest = 0; while( true ) { LoopsTest++; if( (ExponentCopy.GetD( 0 ) & 1) == 1 ) // If the bottom bit is 1. { CRTResult.Multiply( CRTXForModPower ); ModularReduction( CRTResult, CRTAccumulate ); CRTResult.Copy( CRTAccumulate ); } ExponentCopy.ShiftRight( 1 ); // Divide by 2. if( ExponentCopy.IsZero()) break; // Square it. CRTCopyForSquare.Copy( CRTXForModPower ); CRTXForModPower.Multiply( CRTCopyForSquare ); ModularReduction( CRTXForModPower, CRTAccumulate ); CRTXForModPower.Copy( CRTAccumulate ); } ModularReduction( CRTResult, CRTAccumulate ); CRTResult.Copy( CRTAccumulate ); // Division is never used in the loop above. // This is a very small Quotient. // See SetupBaseMultiples() for a description of how to calculate // the maximum size of this quotient. CRTMath1.GetTraditionalInteger( Result, CRTResult ); IntMath.Divide( Result, Modulus, Quotient, Remainder ); // Is the Quotient bigger than a 32 bit integer? if( Quotient.GetIndex() > 0 ) throw( new Exception( "I haven't ever seen this happen. Quotient.GetIndex() > 0. It is: " + Quotient.GetIndex().ToString() )); QuotientForTest = Quotient.GetAsULong(); if( QuotientForTest > 2097867 ) throw( new Exception( "This can never happen unless I increase ChineseRemainder.DigitsArraySize." )); Result.Copy( Remainder ); CRTResult.SetFromTraditionalInteger( Remainder ); }
// CRTBaseModArray doesn't have the pattern of zeros // down to the end like in CRTBaseArray. internal void SetupBaseModArray( Integer Modulus ) { try { BaseModArrayModulus = Modulus; if( NumbersArray == null ) throw( new Exception( "NumbersArray should have already been setup in SetupBaseModArray()." )); CRTBaseModArray = new ChineseRemainder[ChineseRemainder.DigitsArraySize]; ChineseRemainder CRTSetBase = new ChineseRemainder( IntMath ); Integer BigBase = new Integer(); ChineseRemainder CRTBigBase = new ChineseRemainder( IntMath ); BigBase.SetFromULong( 2 ); CRTBigBase.SetFromUInt( 2 ); CRTSetBase.SetToOne(); CRTBaseModArray[0] = CRTSetBase; ChineseRemainder CRTTemp = new ChineseRemainder( IntMath ); for( int Count = 1; Count < ChineseRemainder.DigitsArraySize; Count++ ) { CRTSetBase = new ChineseRemainder( IntMath ); CRTSetBase.Copy( CRTBigBase ); CRTBaseModArray[Count] = CRTSetBase; // Multiply it for the next BigBase. IntMath.MultiplyUInt( BigBase, IntMath.GetPrimeAt( Count )); IntMath.Divide( BigBase, Modulus, Quotient, Remainder ); BigBase.Copy( Remainder ); CRTBigBase.SetFromTraditionalInteger( BigBase ); } } catch( Exception Except ) { throw( new Exception( "Exception in SetupBaseModArray(): " + Except.Message )); } }
internal void GetTraditionalInteger( CRTBase ToGetFrom, Integer ToSet ) { try { if( CRTBaseArray == null ) throw( new Exception( "Bug: The BaseArray should have been set up already." )); // This first one has the prime 2 as its base so // it's going to be set to either zero or one. if( ToGetFrom.GetDigitAt( 0 ) == 1 ) ToSet.SetToOne(); else ToSet.SetToZero(); Integer WorkingBase = new Integer(); for( int Count = 1; Count < ChineseRemainder.DigitsArraySize; Count++ ) { int BaseMult = ToGetFrom.GetDigitAt( Count ); WorkingBase.Copy( BaseArray[Count] ); IntMath.MultiplyUInt( WorkingBase, (uint)BaseMult ); ToSet.Add( WorkingBase ); } } catch( Exception Except ) { throw( new Exception( "Exception in GetTraditionalInteger(): " + Except.Message )); } }
private void FindXTheHardWay( Integer B, Integer Temp, ulong A ) { Integer CountX = new Integer(); CountX.SetToOne(); while( true ) { if( Worker.CancellationPending ) return; Temp.Copy( CountX ); IntMath.Multiply( Temp, B ); Temp.AddULong( A ); IntMath.Divide( Product, Temp, Quotient, Remainder ); if( Remainder.IsZero()) { if( !Quotient.IsOne()) { SolutionP.Copy( Temp ); SolutionQ.Copy( Quotient ); return; } } CountX.Increment(); if( MaxX.ParamIsGreater( CountX )) { // Worker.ReportProgress( 0, "Tried everything up to MaxX." ); return; } } }
private void FindFactorsFromLeft( ulong A, ulong C, Integer Left, Integer Temp, Integer B ) { if( Worker.CancellationPending ) return; /* // (323 - 2*4 / 5) = xy5 + 2y + 4x // (315 / 5) = xy5 + 2y + 4x // 63 = xy5 + 2y + 4x // 21 * 3 = xy5 + 2y + 4x // 3*7*3 = xy5 + 2y + 4x // 3*7*3 = 3y5 + 2y + 4*3 // 3*7*3 = 15y + 2y + 12 // 3*7*3 - 12 = y(15 + 2) // 3*7*3 - 3*4 = y(15 + 2) // 51 = 3 * 17 // (323 - 1*3 / 5) = xy5 + 1y + 3x // (320 / 5) = xy5 + 1y + 3x // 64 = xy5 + 1y + 3x // 64 - 3x = xy5 + 1y // 64 - 3x = y(x5 + 1) // 64 - 3x = y(x5 + 1) 1 = y(x5 + 1) mod 3 */ Left.Copy( Product ); Temp.SetFromULong( A * C ); IntMath.Subtract( Left, Temp ); IntMath.Divide( Left, B, Quotient, Remainder ); if( !Remainder.IsZero()) throw( new Exception( "Remainder is not zero for Left." )); Left.Copy( Quotient ); // Worker.ReportProgress( 0, "Left: " + IntMath.ToString10( Left )); // Worker.ReportProgress( 0, "A: " + A.ToString() + " C: " + C.ToString()); FindFactors1.FindSmallPrimeFactorsOnly( Left ); FindFactors1.ShowAllFactors(); MaxX.Copy( ProductSqrRoot ); Temp.SetFromULong( A ); if( MaxX.ParamIsGreater( Temp )) return; // MaxX would be less than zero. IntMath.Subtract( MaxX, Temp ); IntMath.Divide( MaxX, B, Quotient, Remainder ); MaxX.Copy( Quotient ); // Worker.ReportProgress( 0, "MaxX: " + IntMath.ToString10( MaxX )); Temp.Copy( MaxX ); IntMath.MultiplyULong( Temp, C ); if( Left.ParamIsGreater( Temp )) { throw( new Exception( "Does this happen? MaxX can't be that big." )); /* Worker.ReportProgress( 0, "MaxX can't be that big." ); MaxX.Copy( Left ); Temp.SetFromULong( C ); IntMath.Divide( MaxX, Temp, Quotient, Remainder ); MaxX.Copy( Quotient ); Worker.ReportProgress( 0, "MaxX was set to: " + IntMath.ToString10( MaxX )); */ } // P = (xB + a)(yB + c) // P = (xB + a)(yB + c) // P - ac = xyBB + ayB + xBc // ((P - ac) / B) = xyB + ay + xc // ((P - ac) / B) = y(xB + a) + xc // This is congruent to zero mod one really big prime. // ((P - ac) / B) - xc = y(xB + a) // BottomPart is when x is at max in: // ((P - ac) / B) - xc Integer BottomPart = new Integer(); BottomPart.Copy( Left ); Temp.Copy( MaxX ); IntMath.MultiplyULong( Temp, C ); IntMath.Subtract( BottomPart, Temp ); if( BottomPart.IsNegative ) throw( new Exception( "Bug. BottomPart is negative." )); // Worker.ReportProgress( 0, "BottomPart: " + IntMath.ToString10( BottomPart )); Integer Gcd = new Integer(); Temp.SetFromULong( C ); IntMath.GreatestCommonDivisor( BottomPart, Temp, Gcd ); if( !Gcd.IsOne()) throw( new Exception( "This can't happen with the GCD." )); // FindFactors1.FindSmallPrimeFactorsOnly( BottomPart ); // Temp.SetFromULong( C ); // FindFactors1.FindSmallPrimeFactorsOnly( Temp ); // FindFactors1.ShowAllFactors(); MakeXYRecArray( Left, B, A, C ); FindXTheHardWay( B, Temp, A ); }
private void CalculateLastAccumulatePart( Integer Accumulate ) { try { Accumulate.Copy( LastAccumulateValue ); uint CurrentBase = QuadResDigitsArray[DigitsArrayLength - 1].Base; // uint AccumulateDigit = GetMod32( Accumulate, CurrentBase ); int DigitsIndex = QuadResDigitsArray[DigitsArrayLength - 1].DigitIndex; uint CountB = QuadResDigitsArray[DigitsArrayLength - 1].MatchingInverseArray[DigitsIndex, LastAccumulateDigit]; GetValueBasePart.Copy( QuadResDigitsArray[DigitsArrayLength - 1].BigBase ); IntMath.MultiplyUInt( GetValueBasePart, CountB ); Accumulate.Add( GetValueBasePart ); } catch( Exception Except ) { throw( new Exception( "Exception in CalculateLastAccumulatePart(): " + Except.Message )); } }
// 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; }
private bool IsQuadResModProduct( uint Prime ) { // Euler's Criterion: Integer Exponent = new Integer(); Integer Result = new Integer(); Integer Modulus = new Integer(); Exponent.SetFromULong( Prime ); IntMath.SubtractULong( Exponent, 1 ); Exponent.ShiftRight( 1 ); // Divide by 2. Result.Copy( Product ); Modulus.SetFromULong( Prime ); IntMath.IntMathNew.ModularPower( Result, Exponent, Modulus, false ); if( Result.IsOne() ) return true; else return false; // Result should be Prime - 1. }
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; } }
private Integer MakeBigBase( Integer Max ) { Integer Base = new Integer(); Base.SetFromULong( 2 ); Integer LastBase = new Integer(); // Start at the prime 3. for( int Count = 1; Count < IntegerMath.PrimeArrayLength; Count++ ) { uint Prime = IntMath.GetPrimeAt( Count ); IntMath.MultiplyULong( Base, Prime ); if( Max.ParamIsGreater( Base )) return LastBase; LastBase.Copy( Base ); } return null; }
private void LongDivide3( Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { int TestIndex = ToDivide.GetIndex() - DivideBy.GetIndex(); if( TestIndex < 0 ) throw( new Exception( "TestIndex < 0 in Divide3." )); if( TestIndex != 0 ) { // Is 1 too high? TestForDivide1.SetDigitAndClear( TestIndex, 1 ); MultiplyTopOne( TestForDivide1, DivideBy ); if( ToDivide.ParamIsGreater( TestForDivide1 )) TestIndex--; } // Keep a copy of the originals. ToDivideKeep.Copy( ToDivide ); DivideByKeep.Copy( DivideBy ); ulong TestBits = DivideBy.GetD( DivideBy.GetIndex()); int ShiftBy = FindShiftBy( TestBits ); ToDivide.ShiftLeft( ShiftBy ); // Multiply the numerator and the denominator DivideBy.ShiftLeft( ShiftBy ); // by the same amount. ulong MaxValue; if( (ToDivide.GetIndex() - 1) > (DivideBy.GetIndex() + TestIndex) ) { MaxValue = ToDivide.GetD( ToDivide.GetIndex()); } else { MaxValue = ToDivide.GetD( ToDivide.GetIndex()) << 32; MaxValue |= ToDivide.GetD( ToDivide.GetIndex() - 1 ); } ulong Denom = DivideBy.GetD( DivideBy.GetIndex()); if( Denom != 0 ) MaxValue = MaxValue / Denom; else MaxValue = 0xFFFFFFFF; if( MaxValue > 0xFFFFFFFF ) MaxValue = 0xFFFFFFFF; if( MaxValue == 0 ) throw( new Exception( "MaxValue is zero at the top in LongDivide3()." )); Quotient.SetDigitAndClear( TestIndex, 1 ); Quotient.SetD( TestIndex, 0 ); TestForDivide1.Copy( Quotient ); TestForDivide1.SetD( TestIndex, MaxValue ); MultiplyTop( TestForDivide1, DivideBy ); /* Test2.Copy( Quotient ); Test2.SetD( TestIndex, MaxValue ); Multiply( Test2, DivideBy ); if( !Test2.IsEqual( TestForDivide1 )) throw( new Exception( "In Divide3() !IsEqual( Test2, TestForDivide1 )" )); */ if( TestForDivide1.ParamIsGreaterOrEq( ToDivide )) { // ToMatchExactCount++; // Most of the time (roughly 5 out of every 6 times) // this MaxValue estimate is exactly right: Quotient.SetD( TestIndex, MaxValue ); } else { // MaxValue can't be zero here. If it was it would // already be low enough before it got here. MaxValue--; if( MaxValue == 0 ) throw( new Exception( "After decrement: MaxValue is zero in LongDivide3()." )); TestForDivide1.Copy( Quotient ); TestForDivide1.SetD( TestIndex, MaxValue ); MultiplyTop( TestForDivide1, DivideBy ); /* Test2.Copy( Quotient ); Test2.SetD( TestIndex, MaxValue ); Multiply( Test2, DivideBy ); if( !Test2.IsEqual( Test1 )) throw( new Exception( "Top one. !Test2.IsEqual( Test1 ) in LongDivide3()" )); */ if( TestForDivide1.ParamIsGreaterOrEq( ToDivide )) { // ToMatchDecCount++; Quotient.SetD( TestIndex, MaxValue ); } else { // TestDivideBits is done as a last resort, but it's rare. // But it does at least limit it to a worst case scenario // of trying 32 bits, rather than 4 billion or so decrements. TestDivideBits( MaxValue, true, TestIndex, ToDivide, DivideBy, Quotient, Remainder ); } // TestGap = MaxValue - LgQuotient.D[TestIndex]; // if( TestGap > HighestToMatchGap ) // HighestToMatchGap = TestGap; // HighestToMatchGap: 4,294,967,293 // uint size: 4,294,967,295 uint } // If it's done. if( TestIndex == 0 ) { TestForDivide1.Copy( Quotient ); Multiply( TestForDivide1, DivideByKeep ); Remainder.Copy( ToDivideKeep ); Subtract( Remainder, TestForDivide1 ); //if( DivideByKeep.ParamIsGreater( Remainder )) // throw( new Exception( "Remainder > DivideBy in LongDivide3()." )); return; } // Now do the rest of the digits. TestIndex--; while( true ) { TestForDivide1.Copy( Quotient ); // First Multiply() for each digit. Multiply( TestForDivide1, DivideBy ); // if( ToDivide.ParamIsGreater( TestForDivide1 )) // throw( new Exception( "Bug here in LongDivide3()." )); Remainder.Copy( ToDivide ); Subtract( Remainder, TestForDivide1 ); MaxValue = Remainder.GetD( Remainder.GetIndex()) << 32; int CheckIndex = Remainder.GetIndex() - 1; if( CheckIndex > 0 ) MaxValue |= Remainder.GetD( CheckIndex ); Denom = DivideBy.GetD( DivideBy.GetIndex()); if( Denom != 0 ) MaxValue = MaxValue / Denom; else MaxValue = 0xFFFFFFFF; if( MaxValue > 0xFFFFFFFF ) MaxValue = 0xFFFFFFFF; TestForDivide1.Copy( Quotient ); TestForDivide1.SetD( TestIndex, MaxValue ); // There's a minimum of two full Multiply() operations per digit. Multiply( TestForDivide1, DivideBy ); if( TestForDivide1.ParamIsGreaterOrEq( ToDivide )) { // Most of the time this MaxValue estimate is exactly right: // ToMatchExactCount++; Quotient.SetD( TestIndex, MaxValue ); } else { MaxValue--; TestForDivide1.Copy( Quotient ); TestForDivide1.SetD( TestIndex, MaxValue ); Multiply( TestForDivide1, DivideBy ); if( TestForDivide1.ParamIsGreaterOrEq( ToDivide )) { // ToMatchDecCount++; Quotient.SetD( TestIndex, MaxValue ); } else { TestDivideBits( MaxValue, false, TestIndex, ToDivide, DivideBy, Quotient, Remainder ); // TestGap = MaxValue - LgQuotient.D[TestIndex]; // if( TestGap > HighestToMatchGap ) // HighestToMatchGap = TestGap; } } if( TestIndex == 0 ) break; TestIndex--; } TestForDivide1.Copy( Quotient ); Multiply( TestForDivide1, DivideByKeep ); Remainder.Copy( ToDivideKeep ); Subtract( Remainder, TestForDivide1 ); // if( DivideByKeep.ParamIsGreater( Remainder )) // throw( new Exception( "Remainder > DivideBy in LongDivide3()." )); }
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 )); } }
// The ShortDivide() algorithm works like dividing a polynomial which // looks like: // (ax3 + bx2 + cx + d) / N = (ax3 + bx2 + cx + d) * (1/N) // The 1/N distributes over the polynomial: // (ax3 * (1/N)) + (bx2 * (1/N)) + (cx * (1/N)) + (d * (1/N)) // (ax3/N) + (bx2/N) + (cx/N) + (d/N) // The algorithm goes from left to right and reduces that polynomial // expression. So it starts with Quotient being a copy of ToDivide // and then it reduces Quotient from left to right. private bool ShortDivide( Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { Quotient.Copy( ToDivide ); // DivideBy has an Index of zero: ulong DivideByU = DivideBy.GetD( 0 ); ulong RemainderU = 0; // Get the first one set up. 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 ); } // Now do the rest. 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 ); // What's left to divide. } // Set the index for the quotient. // The quotient would have to be at least 1 here, // so it will find where to set the index. for( int Count = Quotient.GetIndex(); Count >= 0; Count-- ) { if( Quotient.GetD( Count ) != 0 ) { Quotient.SetIndex( Count ); break; } } Remainder.SetD( 0, RemainderU ); Remainder.SetIndex( 0 ); if( RemainderU == 0 ) return true; else return false; }
internal void FindSmallPrimeFactorsOnly( Integer FindFromNotChanged ) { OriginalFindFrom.Copy( FindFromNotChanged ); FindFrom.Copy( FindFromNotChanged ); ClearFactorsArray(); Integer OneFactor; OneFactorRec Rec; // while( not forever ) for( int Count = 0; Count < 1000; Count++ ) { if( Worker.CancellationPending ) return; uint SmallPrime = IntMath.IsDivisibleBySmallPrime( FindFrom ); if( SmallPrime == 0 ) break; // No more small primes. // Worker.ReportProgress( 0, "Found a small prime factor: " + SmallPrime.ToString() ); OneFactor = new Integer(); OneFactor.SetFromULong( SmallPrime ); Rec = new OneFactorRec(); Rec.Factor = OneFactor; Rec.IsDefinitelyAPrime = true; AddFactorRec( Rec ); if( FindFrom.IsULong()) { ulong CheckLast = FindFrom.GetAsULong(); if( CheckLast == SmallPrime ) { // Worker.ReportProgress( 0, "It only had small prime factors." ); VerifyFactors(); return; // It had only small prime factors. } } IntMath.Divide( FindFrom, OneFactor, Quotient, Remainder ); if( !Remainder.IsZero()) throw( new Exception( "Bug in FindSmallPrimeFactorsOnly(). Remainder is not zero." )); FindFrom.Copy( Quotient ); if( FindFrom.IsOne()) throw( new Exception( "Bug in FindSmallPrimeFactorsOnly(). This was already checked for 1." )); } // Worker.ReportProgress( 0, "One factor was not a small prime." ); OneFactor = new Integer(); OneFactor.Copy( FindFrom ); Rec = new OneFactorRec(); Rec.Factor = OneFactor; AddFactorRec( Rec ); // Worker.ReportProgress( 0, "No more small primes." ); }
internal void Add( Integer Result, Integer ToAdd ) { if( ToAdd.IsZero()) return; // The most common form. They are both positive. if( !Result.IsNegative && !ToAdd.IsNegative ) { Result.Add( ToAdd ); return; } if( !Result.IsNegative && ToAdd.IsNegative ) { TempAdd1.Copy( ToAdd ); TempAdd1.IsNegative = false; if( TempAdd1.ParamIsGreater( Result )) { Subtract( Result, TempAdd1 ); return; } else { Subtract( TempAdd1, Result ); Result.Copy( TempAdd1 ); Result.IsNegative = true; return; } } if( Result.IsNegative && !ToAdd.IsNegative ) { TempAdd1.Copy( Result ); TempAdd1.IsNegative = false; TempAdd2.Copy( ToAdd ); if( TempAdd1.ParamIsGreater( TempAdd2 )) { Subtract( TempAdd2, TempAdd1 ); Result.Copy( TempAdd2 ); return; } else { Subtract( TempAdd1, TempAdd2 ); Result.Copy( TempAdd2 ); Result.IsNegative = true; return; } } if( Result.IsNegative && ToAdd.IsNegative ) { TempAdd1.Copy( Result ); TempAdd1.IsNegative = false; TempAdd2.Copy( ToAdd ); TempAdd2.IsNegative = false; TempAdd1.Add( TempAdd2 ); Result.Copy( TempAdd1 ); Result.IsNegative = true; return; } }
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 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; } // return LongDivide1( ToDivide, DivideBy, Quotient, Remainder ); // return LongDivide2( ToDivide, DivideBy, Quotient, Remainder ); LongDivide3( ToDivide, DivideBy, Quotient, Remainder ); }
// 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 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 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; }
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. } }