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 ); }
private void SetupQuadResArray( Integer Product ) { // I'm doing this differently from finding y^2 = x^2 - N, // which I think would be faster, unless it complicates it too // much by having to use large Integers and doing subtraction. // Here it's looking for when // P + x^2 = y^2. // private uint[] QuadResArraySmall; // private uint[] QuadResArray; uint SmallBase = 2 * 3 * 5 * 7 * 11 * 13; // 30,030 // 2 3 3 4 6 7 int SmallBaseArraySize = 2 * 3 * 3 * 4 * 6 * 7; // This is not exact. uint[] QuadResArraySmall = new uint[SmallBaseArraySize]; uint QuadResArraySmallLast = 0; uint ProductModSmall = (uint)IntMath.GetMod32( Product, SmallBase ); QuadResArraySmallLast = 0; uint ProdMod4 = (uint)Product.GetD( 0 ) & 3; for( ulong Count = 0; Count < SmallBase; Count++ ) { // P is odd. // if x is even then y is odd. // if x is odd then y is even. // If x is even then x^2 is divisible by 4. // If y is even then y^2 is divisible by 4. ulong Test = ProductModSmall + (Count * Count); // The Product plus a square. Test = Test % SmallBase; if( !IntegerMath.IsSmallQuadResidue( (uint)Test )) continue; // What Count was used to make a quad residue? QuadResArraySmall[QuadResArraySmallLast] = (uint)Count; QuadResArraySmallLast++; if( QuadResArraySmallLast >= SmallBaseArraySize ) throw( new Exception( "Went past the small quad res array." )); } // Worker.ReportProgress( 0, "Finished setting up small quad res array." ); QuadResBigBase = SmallBase * 17 * 19 * 23; // 223,092,870 // 17 19 23 int QuadResBaseArraySize = SmallBaseArraySize * 9 * 10 * 12; // This is not exact. QuadResArray = new uint[QuadResBaseArraySize]; uint ProductMod = (uint)IntMath.GetMod32( Product, QuadResBigBase ); int MaxLength = QuadResArray.Length; QuadResArrayLast = 0; for( ulong Count23 = 0; Count23 < (17 * 19 * 23); Count23++ ) { if( Worker.CancellationPending ) return; ulong BasePart = Count23 * SmallBase; for( uint Count = 0; Count < QuadResArraySmallLast; Count++ ) { ulong CountPart = BasePart + QuadResArraySmall[Count]; ulong Test = ProductMod + (CountPart * CountPart); // The Product plus a square. Test = Test % QuadResBigBase; if( !IntegerMath.IsQuadResidue17To23( (uint)Test )) continue; // What Count was used to make a quad residue? QuadResArray[QuadResArrayLast] = (uint)CountPart; QuadResArrayLast++; if( QuadResArrayLast >= MaxLength ) throw( new Exception( "Went past the quad res array." )); } } Worker.ReportProgress( 0, "Finished setting up main quad res array." ); }
// Factor1 is along the top. internal void SetFactor1( Integer UseBigIntToSet ) { Integer BigIntToSet = new Integer(); BigIntToSet.Copy( UseBigIntToSet ); if( (BigIntToSet.GetD( 0 ) & 1 ) != 1 ) throw( new Exception( "Factor1 can't be even." )); uint ToSet = MultArray[0].OneLine[0]; ToSet = SetMult1( ToSet ); ToSet = SetMult2( ToSet ); ToSet = SetMult( ToSet ); ToSet = SetAccumOut( ToSet ); ToSet = ClearCarryOut( ToSet ); MultArray[0].OneLine[0] = ToSet; // Factor1 has to be odd so Mult1 is set to // 1 all the way down the side. SetMult1AtColumn( 0 ); BigIntToSet.ShiftRight( 1 ); if( BigIntToSet.IsZero()) throw( new Exception( "Factor1 can't be 1." )); // 107 = 64 + 32 + 8 + 2 + 1 int Where = 1; for( int Column = 1; Column < MultArraySize; Column++ ) { ToSet = MultArray[0].OneLine[Column]; if( (BigIntToSet.GetD( 0 ) & 1 ) == 1 ) ToSet = SetMult1( ToSet ); else ToSet = ClearMult1( ToSet ); MultArray[0].OneLine[Column] = ToSet; Where = Column; BigIntToSet.ShiftRight( 1 ); if( BigIntToSet.IsZero()) break; } // At the last 1 bit. // ToSet = MultArray[0].OneLine[Where]; for( int Column = Where + 1; Column < MultArraySize; Column++ ) { ToSet = MultArray[0].OneLine[Column]; ToSet = ClearMult1( ToSet ); ToSet = ClearMult( ToSet ); ToSet = ClearAccumOut( ToSet ); ToSet = ClearCarryOut( ToSet ); MultArray[0].OneLine[Column] = ToSet; } }
private void SetupBaseValues() { try { Worker.ReportProgress( 0, " " ); Worker.ReportProgress( 0, "Top of SetupBaseValues()." ); // MakeQuadResDigitsArrayRec() sets up each record and its base, // so that base should already be set in this record. if( QuadResDigitsArray[0].Base == 0 ) throw( new Exception( "Base was zero in SetupBaseValues() at: 0" )); Integer BigBase = new Integer(); BigBase.SetFromULong( QuadResDigitsArray[0].Base ); QuadResDigitsArray[0].BigBase = new Integer(); QuadResDigitsArray[0].BigBase.Copy( BigBase ); // Zero and one have the same base set here. // Count starts at 1, so it's the base at 1. int QRLength = QuadResDigitsArray.Length; for( int Count = 1; Count < QRLength; Count++ ) { if( QuadResDigitsArray[Count].Base == 0 ) throw( new Exception( "Base was zero in SetupBaseValues() at: " + Count.ToString() )); QuadResDigitsArray[Count].BigBase = new Integer(); QuadResDigitsArray[Count].BigBase.Copy( BigBase ); QuadResDigitsArray[Count].BigBaseBottomDigit = (uint)BigBase.GetD( 0 ); QuadResDigitsArray[Count].BigBaseModCurrentBase = (uint)IntMath.GetMod32( QuadResDigitsArray[Count].BigBase, QuadResDigitsArray[Count].Base ); // Multiply it by the current base for the next loop. IntMath.MultiplyUInt( BigBase, QuadResDigitsArray[Count].Base ); } } catch( Exception Except ) { throw( new Exception( "Exception in SetupCRTBaseValues(): " + 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 )); } }
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()." )); }
/* private bool LongDivide1( Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { Integer Test1 = new Integer(); int TestIndex = ToDivide.Index - DivideBy.Index; if( TestIndex != 0 ) { // Is 1 too high? Test1.SetDigitAndClear( TestIndex, 1 ); Test1.MultiplyTopOne( DivideBy ); if( ToDivide.ParamIsGreater( Test1 )) TestIndex--; } Quotient.SetDigitAndClear( TestIndex, 1 ); Quotient.D[TestIndex] = 0; uint BitTest = 0x80000000; while( true ) { // For-loop to test each bit: for( int BitCount = 31; BitCount >= 0; BitCount-- ) { Test1.Copy( Quotient ); Test1.D[TestIndex] |= BitTest; Test1.Multiply( DivideBy ); if( Test1.ParamIsGreaterOrEq( ToDivide )) Quotient.D[TestIndex] |= BitTest; // Then keep the bit. BitTest >>= 1; } if( TestIndex == 0 ) break; TestIndex--; BitTest = 0x80000000; } Test1.Copy( Quotient ); Test1.Multiply( DivideBy ); if( Test1.IsEqual( ToDivide ) ) { Remainder.SetToZero(); return true; // Divides exactly. } Remainder.Copy( ToDivide ); Remainder.Subtract( Test1 ); // Does not divide it exactly. return false; } */ private void TestDivideBits( ulong MaxValue, bool IsTop, int TestIndex, Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { // For a particular value of TestIndex, this does the // for-loop to test each bit. // When you're not testing you wouldn't want to be creating these // and allocating the RAM for them each time it's called. // Integer Test1 = new Integer(); // Integer Test2 = new Integer(); uint BitTest = 0x80000000; for( int BitCount = 31; BitCount >= 0; BitCount-- ) { if( (Quotient.GetD( TestIndex ) | BitTest) > MaxValue ) { // If it's more than the MaxValue then the // multiplication test can be skipped for // this bit. // SkippedMultiplies++; BitTest >>= 1; continue; } // Is it only doing the multiplication for the top digit? if( IsTop ) { TestForBits.Copy( Quotient ); TestForBits.SetD( TestIndex, TestForBits.GetD( TestIndex ) | BitTest ); MultiplyTop( TestForBits, DivideBy ); /* Test2.Copy( Quotient ); Test2.SetD( TestIndex, Test2.GetD( TestIndex ) | BitTest ); Multiply( Test2, DivideBy ); if( !Test1.IsEqual( Test2 )) throw( new Exception( "!Test1.IsEqual( Test2 ) in TestDivideBits()." )); */ } else { TestForBits.Copy( Quotient ); TestForBits.SetD( TestIndex, TestForBits.GetD( TestIndex ) | BitTest ); Multiply( TestForBits, DivideBy ); } if( TestForBits.ParamIsGreaterOrEq( ToDivide )) Quotient.SetD( TestIndex, Quotient.GetD( TestIndex ) | BitTest ); // Keep the bit. BitTest >>= 1; } }
internal uint IsDivisibleBySmallPrime( Integer ToTest ) { if( (ToTest.GetD( 0 ) & 1) == 0 ) return 2; // It's divisible by 2. for( int Count = 1; Count < PrimeArrayLength; Count++ ) { if( 0 == GetMod32( ToTest, PrimeArray[Count] )) return PrimeArray[Count]; } // No small primes divide it. return 0; }
// 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 void AddUpAccumulateArray( Integer Result, int HowManyToAdd, int BiggestIndex ) { try { for( int Count = 0; Count <= (BiggestIndex + 1); Count++ ) Result.SetD( Count, 0 ); Result.SetIndex( BiggestIndex ); for( int Count = 0; Count < HowManyToAdd; Count++ ) { int HowManyDigits = AccumulateArray[Count].GetIndex() + 1; for( int CountDigits = 0; CountDigits < HowManyDigits; CountDigits++ ) { ulong Sum = AccumulateArray[Count].GetD( CountDigits ) + Result.GetD( CountDigits ); Result.SetD( CountDigits, Sum ); } } // This is like ax + by + cz + ... = Result. // You know what a, b, c... are. // But you don't know what x, y, and z are. // So how do you reverse this and get x, y and z? // Is this reversible? Result.OrganizeDigits(); } catch( Exception Except ) { throw( new Exception( "Exception in AddUpAccumulateArray(): " + Except.Message )); } }
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." ); }
// 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 )); } }
// Product is along the right side diagonal. internal void SetProduct( Integer UseBigIntToSet ) { Integer BigIntToSet = new Integer(); BigIntToSet.Copy( UseBigIntToSet ); // Primes: 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, // 71, 73, 79, 83, 89, 97, 101, 103, 107 if( (BigIntToSet.GetD( 0 ) & 1 ) != 1 ) throw( new Exception( "Product can't be even." )); int Where = 0; uint ToSet = 0; for( int Row = 0; Row < MultArraySize; Row++ ) { ToSet = MultArray[Row].OneLine[0]; if( (BigIntToSet.GetD( 0 ) & 1 ) == 1 ) ToSet = SetAccumOut( ToSet ); else ToSet = ClearAccumOut( ToSet ); MultArray[Row].OneLine[0] = ToSet; Where = Row; BigIntToSet.ShiftRight( 1 ); if( BigIntToSet.IsZero()) break; } ProductBitIndex = Where; int HowMany = ProductBitIndex + 1; MForm.ShowStatus( "There were " + HowMany.ToString() + " bits in the product." ); // At the last 1 bit. ToSet = MultArray[Where].OneLine[0]; ToSet = ClearCarryOut( ToSet ); MultArray[Where].OneLine[0] = ToSet; // The ProductBits can be: // Factor1Bits + Factor2Bits // or it can be: // Factor1Bits + Factor2Bits + 1 // ProductBits - Factor1Bits = Factor2Bits ( + 1 or not) int Factor1Bits = GetHighestMult1BitIndex() + 1; int ProductBits = (Where + 1); // Factor2Bits might be this or it might be one // less than this. int MaximumFactor2Bits = ProductBits - Factor1Bits; // Factor2BitIndex = Factor2Bits - 1; // Test if the top bit of Factor2 is in the right place. // ToSet = MultArray[Factor2BitIndex].OneLine[0]; // ToSet = SetMult( ToSet ); // MultArray[Factor2BitIndex].OneLine[0] = ToSet; for( int Row = MaximumFactor2Bits + 1; Row < MultArraySize; Row++ ) { ToSet = MultArray[Row].OneLine[0]; ToSet = ClearMult2( ToSet ); MultArray[Row].OneLine[0] = ToSet; } for( int Row = Where + 1; Row < MultArraySize; Row++ ) { ToSet = MultArray[Row].OneLine[0]; ToSet = ClearMult2( ToSet ); ToSet = ClearMult( ToSet ); ToSet = ClearAccumOut( ToSet ); ToSet = ClearCarryOut( ToSet ); MultArray[Row].OneLine[0] = ToSet; } }
// Factor 2 is along the right side diagonal. internal void SetFactor2( Integer UseBigIntToSet ) { Integer BigIntToSet = new Integer(); BigIntToSet.Copy( UseBigIntToSet ); if( (BigIntToSet.GetD( 0 ) & 1 ) != 1 ) throw( new Exception( "Factor2 can't be even." )); uint ToSet = MultArray[0].OneLine[0]; ToSet = SetMult1( ToSet ); ToSet = SetMult2( ToSet ); ToSet = SetMult( ToSet ); ToSet = SetAccumOut( ToSet ); ToSet = ClearCarryOut( ToSet ); MultArray[0].OneLine[0] = ToSet; // Factor2 has to be odd so Mult2 is set to // 1 all the way across the top. SetMult2AtRow( 0 ); BigIntToSet.ShiftRight( 1 ); if( BigIntToSet.IsZero()) throw( new Exception( "Factor2 can't be 1." )); // 107 = 64 + 32 + 8 + 2 + 1 int Where = 1; for( int Row = 1; Row < MultArraySize; Row++ ) { ToSet = MultArray[Row].OneLine[0]; if( (BigIntToSet.GetD( 0 ) & 1 ) == 1 ) ToSet = SetMult2( ToSet ); else ToSet = ClearMult2( ToSet ); MultArray[Row].OneLine[0] = ToSet; Where = Row; BigIntToSet.ShiftRight( 1 ); if( BigIntToSet.IsZero()) break; } // At the last 1 bit. // ToSet = MultArray[Where].OneLine[0]; for( int Row = Where + 1; Row < MultArraySize; Row++ ) { ToSet = MultArray[Row].OneLine[0]; ToSet = ClearMult2( ToSet ); MultArray[Row].OneLine[0] = ToSet; } }
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 ); }
// 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 } */ }
// 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; }
// 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 } */ }
// 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 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 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 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 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 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 ); } }
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; }
// 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 )); } }
internal bool GetProduct( Integer BigIntToSet ) { BigIntToSet.SetToZero(); if( !AllProductBitsAreKnown()) return false; int Highest = GetHighestProductBitIndex(); for( int Row = Highest; Row >= 0; Row-- ) { // The first time through it will just shift zero // to the left, so nothing happens with zero. BigIntToSet.ShiftLeft( 1 ); uint ToSet = MultArray[Row].OneLine[0]; if( GetAccumOutValue( ToSet )) { ulong D = BigIntToSet.GetD( 0 ); D |= 1; BigIntToSet.SetD( 0, D ); } } return true; }