// 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 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 SubtractPositive( Integer Result, Integer ToSub ) { if( ToSub.IsULong() ) { SubtractULong( Result, ToSub.GetAsULong()); return; } if( ToSub.GetIndex() > Result.GetIndex() ) throw( new Exception( "In Subtract() ToSub.Index > Index." )); for( int Count = 0; Count <= ToSub.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ) - (long)ToSub.GetD( Count ); for( int Count = ToSub.GetIndex() + 1; Count <= Result.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ); for( int Count = 0; Count < Result.GetIndex(); Count++ ) { if( SignedD[Count] < 0 ) { SignedD[Count] += (long)0xFFFFFFFF + 1; SignedD[Count + 1]--; } } if( SignedD[Result.GetIndex()] < 0 ) throw( new Exception( "Subtract() SignedD[Index] < 0." )); for( int Count = 0; Count <= Result.GetIndex(); Count++ ) Result.SetD( Count, (ulong)SignedD[Count] ); for( int Count = Result.GetIndex(); Count >= 0; Count-- ) { if( Result.GetD( Count ) != 0 ) { Result.SetIndex( Count ); return; } } // If it never found a non-zero digit it would get down to here. Result.SetIndex( 0 ); }
internal void SubtractULong( Integer Result, ulong ToSub ) { if( Result.IsULong()) { ulong ResultU = Result.GetAsULong(); if( ToSub > ResultU ) throw( new Exception( "SubULong() (IsULong() and (ToSub > Result)." )); ResultU = ResultU - ToSub; Result.SetD( 0, ResultU & 0xFFFFFFFF ); Result.SetD( 1, ResultU >> 32 ); if( Result.GetD( 1 ) == 0 ) Result.SetIndex( 0 ); else Result.SetIndex( 1 ); return; } // If it got this far then Index is at least 2. SignedD[0] = (long)Result.GetD( 0 ) - (long)(ToSub & 0xFFFFFFFF); SignedD[1] = (long)Result.GetD( 1 ) - (long)(ToSub >> 32); if( (SignedD[0] >= 0) && (SignedD[1] >= 0) ) { // No need to reorganize it. Result.SetD( 0, (ulong)SignedD[0] ); Result.SetD( 1, (ulong)SignedD[1] ); return; } for( int Count = 2; Count <= Result.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ); for( int Count = 0; Count < Result.GetIndex(); Count++ ) { if( SignedD[Count] < 0 ) { SignedD[Count] += (long)0xFFFFFFFF + 1; SignedD[Count + 1]--; } } if( SignedD[Result.GetIndex()] < 0 ) throw( new Exception( "SubULong() SignedD[Index] < 0." )); for( int Count = 0; Count <= Result.GetIndex(); Count++ ) Result.SetD( Count, (ulong)SignedD[Count] ); for( int Count = Result.GetIndex(); Count >= 0; Count-- ) { if( Result.GetD( Count ) != 0 ) { Result.SetIndex( Count ); return; } } // If this was zero it wouldn't find a nonzero // digit to set the Index to and it would end up down here. Result.SetIndex( 0 ); }
internal void 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 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 ); }
internal void MultiplyUInt( Integer Result, ulong ToMul ) { try { if( ToMul == 0 ) { Result.SetToZero(); return; } if( ToMul == 1 ) return; for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column, 0] = ToMul * Result.GetD( Column ); // Add these up with a carry. Result.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= Result.GetIndex(); Column++ ) { // Using a compile-time check on this constant, // this Test value does not overflow: // const ulong Test = ((ulong)0xFFFFFFFF * (ulong)(0xFFFFFFFF)) + 0xFFFFFFFF; // ulong Total = checked( M[Column, 0] + Carry ); ulong Total = M[Column, 0] + Carry; Result.SetD( Column, Total & 0xFFFFFFFF ); Carry = Total >> 32; } if( Carry != 0 ) { Result.IncrementIndex(); // This might throw an exception if it overflows. Result.SetD( Result.GetIndex(), Carry ); } } catch( Exception Except ) { throw( new Exception( "Exception in MultiplyUInt(): " + Except.Message )); } }
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 )); } }
// This is an optimization for multiplying when only the top digit // of a number has been set and all of the other digits are zero. internal void MultiplyTop( Integer Result, Integer ToMul ) { // try // { int TotalIndex = Result.GetIndex() + ToMul.GetIndex(); if( TotalIndex >= Integer.DigitArraySize ) throw( new Exception( "MultiplyTop() overflow." )); // Just like Multiply() except that all the other rows are zero: for( int Column = 0; Column <= ToMul.GetIndex(); Column++ ) M[Column + Result.GetIndex(), Result.GetIndex()] = Result.GetD( Result.GetIndex() ) * ToMul.GetD( Column ); for( int Column = 0; Column < Result.GetIndex(); Column++ ) Result.SetD( Column, 0 ); ulong Carry = 0; for( int Column = 0; Column <= ToMul.GetIndex(); Column++ ) { ulong Total = M[Column + Result.GetIndex(), Result.GetIndex()] + Carry; Result.SetD( Column + Result.GetIndex(), Total & 0xFFFFFFFF ); Carry = Total >> 32; } Result.SetIndex( TotalIndex ); if( Carry != 0 ) { Result.SetIndex( Result.GetIndex() + 1 ); if( Result.GetIndex() >= Integer.DigitArraySize ) throw( new Exception( "MultiplyTop() overflow." )); Result.SetD( Result.GetIndex(), Carry ); } /* } catch( Exception ) // Except ) { // "Bug in MultiplyTop: " + Except.Message } */ }
// This is another optimization. This is used when the top digit // is 1 and all of the other digits are zero. // This is effectively just a shift-left operation. internal void MultiplyTopOne( Integer Result, Integer ToMul ) { // try // { int TotalIndex = Result.GetIndex() + ToMul.GetIndex(); if( TotalIndex >= Integer.DigitArraySize ) throw( new Exception( "MultiplyTopOne() overflow." )); for( int Column = 0; Column <= ToMul.GetIndex(); Column++ ) Result.SetD( Column + Result.GetIndex(), ToMul.GetD( Column )); for( int Column = 0; Column < Result.GetIndex(); Column++ ) Result.SetD( Column, 0 ); // No Carrys need to be done. Result.SetIndex( TotalIndex ); /* } catch( Exception ) // Except ) { // "Bug in MultiplyTopOne: " + Except.Message } */ }
// See also: http://en.wikipedia.org/wiki/Karatsuba_algorithm internal void Multiply( Integer Result, Integer ToMul ) { // try // { if( Result.IsZero()) return; if( ToMul.IsULong()) { MultiplyULong( Result, ToMul.GetAsULong()); SetMultiplySign( Result, ToMul ); return; } // It could never get here if ToMul is zero because GetIsULong() // would be true for zero. // if( ToMul.IsZero()) int TotalIndex = Result.GetIndex() + ToMul.GetIndex(); if( TotalIndex >= Integer.DigitArraySize ) throw( new Exception( "Multiply() overflow." )); for( int Row = 0; Row <= ToMul.GetIndex(); Row++ ) { if( ToMul.GetD( Row ) == 0 ) { for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column + Row, Row] = 0; } else { for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column + Row, Row] = ToMul.GetD( Row ) * Result.GetD( Column ); } } // Add the columns up with a carry. Result.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= TotalIndex; Column++ ) { ulong TotalLeft = 0; ulong TotalRight = 0; for( int Row = 0; Row <= ToMul.GetIndex(); Row++ ) { if( Row > Column ) break; if( Column > (Result.GetIndex() + Row) ) continue; // Split the ulongs into right and left sides // so that they don't overflow. TotalRight += M[Column, Row] & 0xFFFFFFFF; TotalLeft += M[Column, Row] >> 32; } TotalRight += Carry; Result.SetD( Column, TotalRight & 0xFFFFFFFF ); Carry = TotalRight >> 32; Carry += TotalLeft; } Result.SetIndex( TotalIndex ); if( Carry != 0 ) { Result.IncrementIndex(); // This can throw an exception if it overflowed the index. Result.SetD( Result.GetIndex(), Carry ); } SetMultiplySign( Result, ToMul ); }
private bool MakeAPrime( Integer Result, int SetToIndex, int HowMany ) { try { int Attempts = 0; while( true ) { Attempts++; if( Worker.CancellationPending ) return false; // Don't hog the server's resources too much. Thread.Sleep( 1 ); // Give up the time slice. Let other things run. int HowManyBytes = (SetToIndex * 4) + 4; byte[] RandBytes = MakeRandomBytes( HowManyBytes ); if( RandBytes == null ) { Worker.ReportProgress( 0, "Error making random bytes in MakeAPrime()." ); return false; } if( !Result.MakeRandomOdd( SetToIndex, RandBytes )) { Worker.ReportProgress( 0, "Error making random number in MakeAPrime()." ); return false; } // Make sure that it's the size I think it is. if( Result.GetIndex() < SetToIndex ) throw( new Exception( "Bug. The size of the random prime is not right." )); uint TestPrime = IntMath.IsDivisibleBySmallPrime( Result ); if( 0 != TestPrime) continue; if( !IntMath.IsFermatPrime( Result, HowMany )) { Worker.ReportProgress( 0, "Did not pass Fermat test." ); continue; } // IsFermatPrime() could take a long time. if( Worker.CancellationPending ) return false; Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "Found a probable prime." ); Worker.ReportProgress( 0, "Attempts: " + Attempts.ToString() ); Worker.ReportProgress( 0, " " ); return true; // With Result. } } catch( Exception Except ) { Worker.ReportProgress( 0, "Error in MakeAPrime()" ); Worker.ReportProgress( 0, Except.Message ); return false; } }
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; }
// 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 int MultiplyUIntFromCopy( Integer Result, Integer FromCopy, ulong ToMul ) { int FromCopyIndex = FromCopy.GetIndex(); // The compiler knows that FromCopyIndex doesn't change here so // it can do its range checking on the for-loop before it starts. Result.SetIndex( FromCopyIndex ); for( int Column = 0; Column <= FromCopyIndex; Column++ ) Scratch[Column] = ToMul * FromCopy.GetD( Column ); // Add these up with a carry. Result.SetD( 0, Scratch[0] & 0xFFFFFFFF ); ulong Carry = Scratch[0] >> 32; for( int Column = 1; Column <= FromCopyIndex; Column++ ) { ulong Total = Scratch[Column] + Carry; Result.SetD( Column, Total & 0xFFFFFFFF ); Carry = Total >> 32; } if( Carry != 0 ) { Result.IncrementIndex(); // This might throw an exception if it overflows. Result.SetD( FromCopyIndex + 1, Carry ); } return Result.GetIndex(); }
internal void DoSquare( Integer ToSquare ) { if( ToSquare.GetIndex() == 0 ) { ToSquare.Square0(); return; } if( ToSquare.GetIndex() == 1 ) { ToSquare.Square1(); return; } if( ToSquare.GetIndex() == 2 ) { ToSquare.Square2(); return; } // Now Index is at least 3: int DoubleIndex = ToSquare.GetIndex() << 1; if( DoubleIndex >= Integer.DigitArraySize ) { throw( new Exception( "Square() overflowed." )); } for( int Row = 0; Row <= ToSquare.GetIndex(); Row++ ) { if( ToSquare.GetD( Row ) == 0 ) { for( int Column = 0; Column <= ToSquare.GetIndex(); Column++ ) M[Column + Row, Row] = 0; } else { for( int Column = 0; Column <= ToSquare.GetIndex(); Column++ ) M[Column + Row, Row] = ToSquare.GetD( Row ) * ToSquare.GetD( Column ); } } // Add the columns up with a carry. ToSquare.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= DoubleIndex; Column++ ) { ulong TotalLeft = 0; ulong TotalRight = 0; for( int Row = 0; Row <= Column; Row++ ) { if( Row > ToSquare.GetIndex() ) break; if( Column > (ToSquare.GetIndex() + Row) ) continue; TotalRight += M[Column, Row] & 0xFFFFFFFF; TotalLeft += M[Column, Row] >> 32; } TotalRight += Carry; ToSquare.SetD( Column, TotalRight & 0xFFFFFFFF ); Carry = TotalRight >> 32; Carry += TotalLeft; } ToSquare.SetIndex( DoubleIndex ); if( Carry != 0 ) { ToSquare.SetIndex( ToSquare.GetIndex() + 1 ); if( ToSquare.GetIndex() >= Integer.DigitArraySize ) throw( new Exception( "Square() overflow." )); ToSquare.SetD( ToSquare.GetIndex(), Carry ); } }
internal void MultiplyULong( Integer Result, ulong ToMul ) { // Using compile-time checks, this one overflows: // const ulong Test = ((ulong)0xFFFFFFFF + 1) * ((ulong)0xFFFFFFFF + 1); // This one doesn't: // const ulong Test = (ulong)0xFFFFFFFF * ((ulong)0xFFFFFFFF + 1); if( Result.IsZero()) return; // Then the answer is zero, which it already is. if( ToMul == 0 ) { Result.SetToZero(); return; } ulong B0 = ToMul & 0xFFFFFFFF; ulong B1 = ToMul >> 32; if( B1 == 0 ) { MultiplyUInt( Result, (uint)B0 ); return; } // Since B1 is not zero: if( (Result.GetIndex() + 1) >= Integer.DigitArraySize ) throw( new Exception( "Overflow in MultiplyULong." )); for( int Column = 0; Column <= Result.GetIndex(); Column++ ) { M[Column, 0] = B0 * Result.GetD( Column ); // Column + 1 and Row is 1, so it's just like pen and paper. M[Column + 1, 1] = B1 * Result.GetD( Column ); } // Since B1 is not zero, the index is set one higher. Result.IncrementIndex(); // Might throw an exception if it goes out of range. M[Result.GetIndex(), 0] = 0; // Otherwise it would be undefined // when it's added up below. // Add these up with a carry. Result.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= Result.GetIndex(); Column++ ) { // This does overflow: // const ulong Test = ((ulong)0xFFFFFFFF * (ulong)(0xFFFFFFFF)) // + ((ulong)0xFFFFFFFF * (ulong)(0xFFFFFFFF)); // Split the ulongs into right and left sides // so that they don't overflow. ulong TotalLeft = 0; ulong TotalRight = 0; // There's only the two rows for this. for( int Row = 0; Row <= 1; Row++ ) { TotalRight += M[Column, Row] & 0xFFFFFFFF; TotalLeft += M[Column, Row] >> 32; } TotalRight += Carry; Result.SetD( Column, TotalRight & 0xFFFFFFFF ); Carry = TotalRight >> 32; Carry += TotalLeft; } if( Carry != 0 ) { Result.IncrementIndex(); // This can throw an exception. Result.SetD( Result.GetIndex(), Carry ); } }
// 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." )); }
// 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; }
// Copyright Eric Chauvin 2015. private int ModularReduction( Integer Result, Integer ToReduce ) { try { if( GeneralBaseArray == null ) throw( new Exception( "SetupGeneralBaseArray() should have already been called." )); Result.SetToZero(); int HowManyToAdd = ToReduce.GetIndex() + 1; if( HowManyToAdd > GeneralBaseArray.Length ) throw( new Exception( "Bug. The Input number should have been reduced first. HowManyToAdd > GeneralBaseArray.Length" )); int BiggestIndex = 0; for( int Count = 0; Count < HowManyToAdd; Count++ ) { // The size of the numbers in GeneralBaseArray are // all less than the size of GeneralBase. // This multiplication by a uint is with a number // that is not bigger than GeneralBase. Compare // this with the two full Muliply() calls done on // each digit of the quotient in LongDivide3(). // AccumulateBase is set to a new value here. int CheckIndex = IntMath.MultiplyUIntFromCopy( AccumulateBase, GeneralBaseArray[Count], ToReduce.GetD( Count )); if( CheckIndex > BiggestIndex ) BiggestIndex = CheckIndex; Result.Add( AccumulateBase ); } return Result.GetIndex(); } catch( Exception Except ) { throw( new Exception( "Exception in ModularReduction(): " + Except.Message )); } }
// This is the Modular Reduction algorithm. It reduces // ToAdd to Result. private int AddByGeneralBaseArrays( Integer Result, Integer ToAdd ) { try { if( GeneralBaseArray == null ) throw( new Exception( "SetupGeneralBaseArray() should have already been called." )); Result.SetToZero(); // The Index size of ToAdd is usually double the length of the modulus // this is reducing it to. Like if you multiply P and Q to get N, then // the ToAdd that comes in here is about the size of N and the GeneralBase // is about the size of P. So the amount of work done here is proportional // to P times N. int HowManyToAdd = ToAdd.GetIndex() + 1; int BiggestIndex = 0; for( int Count = 0; Count < HowManyToAdd; Count++ ) { // The size of the numbers in GeneralBaseArray are all less than // the size of GeneralBase. // This multiplication by a uint is with a number that is not bigger // than GeneralBase. Compare this with the two full Muliply() // calls done on each digit of the quotient in LongDivide3(). // AccumulateArray[Count] is set to a new value here. int CheckIndex = IntMath.MultiplyUIntFromCopy( AccumulateArray[Count], GeneralBaseArray[Count], ToAdd.GetD( Count )); if( CheckIndex > BiggestIndex ) BiggestIndex = CheckIndex; } // Add all of them up at once. AddUpAccumulateArray( Result, HowManyToAdd, BiggestIndex ); return Result.GetIndex(); } catch( Exception Except ) { throw( new Exception( "Exception in AddByGeneralBaseArrays(): " + Except.Message )); } }