internal uint ModularPowerSmall( ulong Input, Integer Exponent, uint Modulus ) { if( Input == 0 ) return 0; if( Input == Modulus ) { // It is congruent to zero % Modulus. return 0; } // Result is not zero at this point. if( Exponent.IsZero() ) return 1; ulong Result = Input; if( Input > Modulus ) Result = Input % Modulus; if( Exponent.IsOne()) return (uint)Result; ulong XForModPowerU = Result; ExponentCopy.Copy( Exponent ); int TestIndex = 0; Result = 1; while( true ) { if( (ExponentCopy.GetD( 0 ) & 1) == 1 ) // If the bottom bit is 1. { Result = Result * XForModPowerU; Result = Result % Modulus; } ExponentCopy.ShiftRight( 1 ); // Divide by 2. if( ExponentCopy.IsZero()) break; // Square it. XForModPowerU = XForModPowerU * XForModPowerU; XForModPowerU = XForModPowerU % Modulus; } return (uint)Result; }
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(); }
// 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 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 ); }
/* internal void ModularPowerOld( Integer Result, Integer Exponent, Integer ModN ) { if( Result.IsZero()) return; // With Result still zero. if( Result.IsEqual( ModN )) { // It is congruent to zero % ModN. Result.SetToZero(); return; } // Result is not zero at this point. if( Exponent.IsZero() ) { Result.SetFromULong( 1 ); return; } if( ModN.ParamIsGreater( Result )) { Divide( Result, ModN, Quotient, Remainder ); Result.Copy( Remainder ); } if( Exponent.IsEqualToULong( 1 )) { // Result stays the same. return; } XForModPower.Copy( Result ); ExponentCopy.Copy( Exponent ); Result.SetFromULong( 1 ); while( !ExponentCopy.IsZero()) { // If the bit is 1, then do a lot more work here. if( (ExponentCopy.GetD( 0 ) & 1) == 1 ) { // This is a multiplication for every _bit_. So a 1024-bit // modulus means this gets called roughly 512 times. // The commonly used public exponent is 65537, which has // only two bits set to 1, the rest are all zeros. But the // private key exponents are long randomish numbers. // (See: Hamming Weight.) Multiply( Result, XForModPower ); SubtractULong( ExponentCopy, 1 ); // Usually it's true that the Result is greater than ModN. if( ModN.ParamIsGreater( Result )) { // Here is where that really long division algorithm gets used a // lot in a loop. And this Divide() gets called roughly about // 512 times. Divide( Result, ModN, Quotient, Remainder ); Result.Copy( Remainder ); } } // Square it. // This is a multiplication for every _bit_. So a 1024-bit // modulus means this gets called 1024 times. Multiply( XForModPower, XForModPower ); ExponentCopy.ShiftRight( 1 ); // Divide by 2. if( ModN.ParamIsGreater( XForModPower )) { // And this Divide() gets called about 1024 times. Divide( XForModPower, ModN, Quotient, Remainder ); XForModPower.Copy( Remainder ); } } } */ internal void GreatestCommonDivisor( Integer X, Integer Y, Integer Gcd ) { // This is the basic Euclidean Algorithm. if( X.IsZero()) throw( new Exception( "Doing GCD with a parameter that is zero." )); if( Y.IsZero()) throw( new Exception( "Doing GCD with a parameter that is zero." )); if( X.IsEqual( Y )) { Gcd.Copy( X ); return; } // Don't change the original numbers that came in as parameters. if( X.ParamIsGreater( Y )) { GcdX.Copy( Y ); GcdY.Copy( X ); } else { GcdX.Copy( X ); GcdY.Copy( Y ); } while( true ) { Divide( GcdX, GcdY, Quotient, Remainder ); if( Remainder.IsZero()) { Gcd.Copy( GcdY ); // It's the smaller one. // It can't return from this loop until the remainder is zero. return; } GcdX.Copy( GcdY ); GcdY.Copy( Remainder ); } }
internal void 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 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; } }
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; }
// See also: http://en.wikipedia.org/wiki/Karatsuba_algorithm internal void Multiply( Integer Result, Integer ToMul ) { // try // { if( Result.IsZero()) return; if( ToMul.IsULong()) { MultiplyULong( Result, ToMul.GetAsULong()); SetMultiplySign( Result, ToMul ); return; } // It could never get here if ToMul is zero because GetIsULong() // would be true for zero. // if( ToMul.IsZero()) int TotalIndex = Result.GetIndex() + ToMul.GetIndex(); if( TotalIndex >= Integer.DigitArraySize ) throw( new Exception( "Multiply() overflow." )); for( int Row = 0; Row <= ToMul.GetIndex(); Row++ ) { if( ToMul.GetD( Row ) == 0 ) { for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column + Row, Row] = 0; } else { for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column + Row, Row] = ToMul.GetD( Row ) * Result.GetD( Column ); } } // Add the columns up with a carry. Result.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= TotalIndex; Column++ ) { ulong TotalLeft = 0; ulong TotalRight = 0; for( int Row = 0; Row <= ToMul.GetIndex(); Row++ ) { if( Row > Column ) break; if( Column > (Result.GetIndex() + Row) ) continue; // Split the ulongs into right and left sides // so that they don't overflow. TotalRight += M[Column, Row] & 0xFFFFFFFF; TotalLeft += M[Column, Row] >> 32; } TotalRight += Carry; Result.SetD( Column, TotalRight & 0xFFFFFFFF ); Carry = TotalRight >> 32; Carry += TotalLeft; } Result.SetIndex( TotalIndex ); if( Carry != 0 ) { Result.IncrementIndex(); // This can throw an exception if it overflowed the index. Result.SetD( Result.GetIndex(), Carry ); } SetMultiplySign( Result, ToMul ); }
internal void 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 ); }
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 ); }
// 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; } }
// 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; } }