Пример #1
0
 internal void Copy( ChineseRemainder ToCopy )
 {
     for( int Count = 0; Count < DigitsArraySize; Count++ )
       {
       DigitsArray[Count] = ToCopy.DigitsArray[Count];
       }
 }
Пример #2
0
        internal CRTBaseMath( BackgroundWorker UseWorker, CRTMath UseCRTMath )
        {
            // Most of these are created ahead of time so that
            // they don't have to be created inside a loop.
            Worker = UseWorker;
            IntMath = new IntegerMath();
            CRTMath1 = UseCRTMath;
            Quotient = new Integer();
            Remainder = new Integer();
            CRTAccumulateBase = new ChineseRemainder( IntMath );
            CRTAccumulateBasePart = new ChineseRemainder( IntMath );
            CRTAccumulateForBaseMultiples = new ChineseRemainder( IntMath );
            CRTAccumulatePart = new ChineseRemainder( IntMath );
            BaseModArrayModulus = new Integer();
            CRTTempForIsEqual = new ChineseRemainder( IntMath );
            CRTWorkingTemp = new ChineseRemainder( IntMath );
            ExponentCopy = new Integer();
            CRTXForModPower = new ChineseRemainder( IntMath );
            CRTAccumulate = new ChineseRemainder( IntMath );
            CRTCopyForSquare = new ChineseRemainder( IntMath );
            FermatExponent = new Integer();
            CRTFermatModulus = new ChineseRemainder( IntMath );
            FermatModulus = new Integer();
            CRTTestFermat = new ChineseRemainder( IntMath );

            Worker.ReportProgress( 0, "Setting up numbers array." );
            SetupNumbersArray();

            Worker.ReportProgress( 0, "Setting up base array." );
            SetupBaseArray();

            Worker.ReportProgress( 0, "Setting up multiplicative inverses." );
            SetMultiplicativeInverses();
        }
        internal void Add( ChineseRemainder ToAdd )
        {
            for( int Count = 0; Count < DigitsArraySize; Count++ )
              {
              // Operations like this could be very fast if they were done in
              // hardware, and the small mod operations could be done in very
              // small hardware lookup tables.  They could also be done in parallel,
              // which would make it a lot faster than the way this is done, one
              // digit at a time.  Notice that there is no carry operation here.
              // As Claud Shannon would say, there is no diffusion here.
              // Like he wrote about in A Mathematical Theory of Cryptography.
              DigitsArray[Count].Value += ToAdd.DigitsArray[Count].Value;
              if( DigitsArray[Count].Value >= DigitsArray[Count].Prime )
            DigitsArray[Count].Value -= DigitsArray[Count].Prime;
            // DigitsArray[Count].Value = DigitsArray[Count].Value % DigitsArray[Count].Prime;

              }
        }
Пример #4
0
        internal void Add( ChineseRemainder ToAdd )
        {
            for( int Count = 0; Count < DigitsArraySize; Count++ )
              {
              // Operations like this could be very fast if
              // they were done in hardware, and the small
              // mod operations could be done in very small
              // hardware lookup tables.  They could also be
              // done in parallel, which would make it a lot
              // faster than the way this is done, one digit
              // at a time.  Notice that there is no carry
              // operation here.  As Claud Shannon would say,
              // there is no diffusion here.
              DigitsArray[Count] += ToAdd.DigitsArray[Count];
              int Prime = (int)IntMath.GetPrimeAt( Count );
              if( DigitsArray[Count] >= Prime )
            DigitsArray[Count] -= Prime;
            // DigitsArray[Count] = DigitsArray[Count] % Prime;

              }
        }
        internal bool IsEqual( ChineseRemainder ToCheck )
        {
            for( int Count = 0; Count < DigitsArraySize; Count++ )
              {
              if( DigitsArray[Count].Value != ToCheck.DigitsArray[Count].Value )
            return false;

              }

            return true;
        }
Пример #6
0
 private void SetupNumbersArray()
 {
     try
     {
     uint BiggestPrime = IntMath.GetPrimeAt( CRTBase.DigitsArraySize + 1 );
     NumbersArray = new ChineseRemainder[BiggestPrime];
     Integer SetNumber = new Integer();
     for( uint Count = 0; Count < BiggestPrime; Count++ )
       {
       SetNumber.SetFromULong( Count );
       ChineseRemainder CRTSetNumber = new ChineseRemainder( IntMath );
       CRTSetNumber.SetFromTraditionalInteger( SetNumber );
       NumbersArray[Count] = CRTSetNumber;
       }
     }
     catch( Exception Except )
       {
       throw( new Exception( "Exception in SetupNumbersArray(): " + Except.Message ));
       }
 }
Пример #7
0
        // These bottom digits are 0 for each prime that gets
        // multiplied by the base.  So they keep getting one
        // more zero at the bottom of each one.
        // But the digits in BaseModArray only have the zeros
        // at the bottom on the ones that are smaller than the
        // modulus.
        // At BaseArray[0] it's 1, 1, 1, 1, 1, .... for all of them.
        // 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0
        // 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 0, 0
        // 30, 30, 30, 30, 1, 7, 11, 13, 4, 8, 2, 0, 0, 0
        private void SetupBaseArray()
        {
            // The first few numbers for the base:
            // 2             2
            // 3             6
            // 5            30
            // 7           210
            // 11        2,310
            // 13       30,030
            // 17      510,510
            // 19    9,699,690
            // 23  223,092,870

            try
            {
            if( NumbersArray == null )
              throw( new Exception( "NumbersArray should have already been setup in SetupBaseArray()." ));

            BaseStringsArray = new string[ChineseRemainder.DigitsArraySize];
            BaseArray = new Integer[ChineseRemainder.DigitsArraySize];
            CRTBaseArray = new ChineseRemainder[ChineseRemainder.DigitsArraySize];

            Integer SetBase = new Integer();
            ChineseRemainder CRTSetBase = new ChineseRemainder( IntMath );

            Integer BigBase = new Integer();
            ChineseRemainder CRTBigBase = new ChineseRemainder( IntMath );

            BigBase.SetFromULong( 2 );
            CRTBigBase.SetFromUInt( 2 );
            string BaseS = "2";

            SetBase.SetToOne();
            CRTSetBase.SetToOne();

            // The base at zero is 1.
            BaseArray[0] = SetBase;
            CRTBaseArray[0] = CRTSetBase;
            BaseStringsArray[0] = "1";

            ChineseRemainder CRTTemp = new ChineseRemainder( IntMath );

            // The first time through the loop the base
            // is set to 2.
            // So BaseArray[0] = 1;
            // So BaseArray[1] = 2;
            // So BaseArray[2] = 6;
            // So BaseArray[3] = 30;
            // And so on...
            // In BaseArray[3] digits at 2, 3 and 5 are set to zero.
            // In BaseArray[4] digits at 2, 3, 5 and 7 are set to zero.
            for( int Count = 1; Count < ChineseRemainder.DigitsArraySize; Count++ )
              {
              SetBase = new Integer();
              CRTSetBase = new ChineseRemainder( IntMath );

              SetBase.Copy( BigBase );
              CRTSetBase.Copy( CRTBigBase );

              BaseStringsArray[Count] = BaseS;
              BaseArray[Count] = SetBase;
              CRTBaseArray[Count] = CRTSetBase;
              // if( Count < 50 )
            // Worker.ReportProgress( 0, CRTBaseArray[Count].GetString() );

              if( !IsEqualToInteger( CRTBaseArray[Count],
                             BaseArray[Count] ))
            throw( new Exception( "Bug.  The bases aren't equal." ));

              // Multiply it for the next BigBase.
              uint Prime = IntMath.GetPrimeAt( Count );
              BaseS = BaseS + "*" + Prime.ToString();
              IntMath.MultiplyUInt( BigBase, Prime );
              CRTBigBase.Multiply( NumbersArray[IntMath.GetPrimeAt( Count )] );
              }
            }
            catch( Exception Except )
              {
              throw( new Exception( "Exception in SetupBaseArray(): " + Except.Message ));
              }
        }
Пример #8
0
        // CRTBaseModArray doesn't have the pattern of zeros
        // down to the end like in CRTBaseArray.
        internal void SetupBaseModArray( Integer Modulus )
        {
            try
            {
            BaseModArrayModulus = Modulus;

            if( NumbersArray == null )
              throw( new Exception( "NumbersArray should have already been setup in SetupBaseModArray()." ));

            CRTBaseModArray = new ChineseRemainder[ChineseRemainder.DigitsArraySize];

            ChineseRemainder CRTSetBase = new ChineseRemainder( IntMath );

            Integer BigBase = new Integer();
            ChineseRemainder CRTBigBase = new ChineseRemainder( IntMath );

            BigBase.SetFromULong( 2 );
            CRTBigBase.SetFromUInt( 2 );

            CRTSetBase.SetToOne();
            CRTBaseModArray[0] = CRTSetBase;

            ChineseRemainder CRTTemp = new ChineseRemainder( IntMath );

            for( int Count = 1; Count < ChineseRemainder.DigitsArraySize; Count++ )
              {
              CRTSetBase = new ChineseRemainder( IntMath );
              CRTSetBase.Copy( CRTBigBase );
              CRTBaseModArray[Count] = CRTSetBase;

              // Multiply it for the next BigBase.
              IntMath.MultiplyUInt( BigBase, IntMath.GetPrimeAt( Count ));
              IntMath.Divide( BigBase, Modulus, Quotient, Remainder );
              BigBase.Copy( Remainder );
              CRTBigBase.SetFromTraditionalInteger( BigBase );
              }
            }
            catch( Exception Except )
              {
              throw( new Exception( "Exception in SetupBaseModArray(): " + Except.Message ));
              }
        }
Пример #9
0
 // Copyright Eric Chauvin.
 internal void Multiply( ChineseRemainder ToMul )
 {
     for( int Count = 0; Count < DigitsArraySize; Count++ )
       {
       // There is no Diffusion here either, like the
       // kind that Claude Shannon wrote about in
       // A Mathematical Theory of Cryptography.
       DigitsArray[Count] *= ToMul.DigitsArray[Count];
       DigitsArray[Count] %= (int)IntMath.GetPrimeAt( Count );
       }
 }
        internal void Subtract( ChineseRemainder ToSub )
        {
            for( int Count = 0; Count < DigitsArraySize; Count++ )
              {
              DigitsArray[Count].Value -= ToSub.DigitsArray[Count].Value;
              if( DigitsArray[Count].Value < 0 )
            DigitsArray[Count].Value += DigitsArray[Count].Prime;

              }
        }
Пример #11
0
        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 );
        }
Пример #12
0
        // http://en.wikipedia.org/wiki/Primality_test
        // http://en.wikipedia.org/wiki/Fermat_primality_test
        internal bool IsFermatPrimeForOneValue( ChineseRemainder CRTToTest, uint Base  )
        {
            // http://en.wikipedia.org/wiki/Carmichael_number

            // Assume ToTest is not a small number.  (Not the size of a small prime.)
            // Normally it would be something like a 1024 bit number or bigger,
            // but I assume it's at least bigger than a 32 bit number.
            // Assume this has already been checked to see if it's divisible
            // by a small prime.

            // A has to be coprime to P and it is here because ToTest is not
            // divisible by a small prime.

            // Fermat's little theorem:
            // A ^ (P - 1) is congruent to 1 mod P if P is a prime.
            // Or: A^P - A is congrunt to A mod P.
            // If you multiply A by itself P times then divide it by P,
            // the remainder is A.  (A^P / P)
            // 5^3 = 125.  125 - 5 = 120.  A multiple of 5.
            // 2^7 = 128.  128 - 2 = 7 * 18 (a multiple of 7.)
            CRTMath1.GetTraditionalInteger( FermatExponent, CRTToTest );
            IntMath.SubtractULong( FermatExponent, 1 );
            // This is a very small Modulus since it's being set from a uint.
            CRTTestFermat.SetFromUInt( Base );
            CRTFermatModulus.Copy( CRTToTest );
            CRTMath1.GetTraditionalInteger( FermatModulus, CRTFermatModulus );

            ModularPower( CRTTestFermat, FermatExponent, CRTFermatModulus, false );
            if( CRTTestFermat.IsOne())
              return true; // It passed the test. It _might_ be a prime.
            else
              return false; // It is _definitely_ a composite number.
        }
Пример #13
0
        internal bool IsFermatPrime( ChineseRemainder CRTToTest, int HowMany )
        {
            // Also see Rabin-Miller test.
            // Also see Solovay-Strassen test.

            // This Fermat primality test is usually described
            // as using random primes to test with, and you
            // could do it that way too.
            // IntegerMath.PrimeArrayLength = 1024 * 32;

            int StartAt = 1024 * 16; // Or much bigger.
            for( int Count = StartAt; Count < (HowMany + StartAt); Count++ )
              {
              if( !IsFermatPrimeForOneValue( CRTToTest, IntMath.GetPrimeAt( Count )))
            return false;

              }

            // It _might_ be a prime if it passed this test.
            // Increasing HowMany increases the probability that it's a prime.
            return true;
        }
Пример #14
0
 internal bool IsEqualToInteger( ChineseRemainder CRTTest, Integer Test )
 {
     CRTTempForIsEqual.SetFromTraditionalInteger( Test );
     if( CRTTest.IsEqual( CRTTempForIsEqual ))
       return true;
     else
       return false;
 }
Пример #15
0
        internal void Subtract( ChineseRemainder ToSub )
        {
            for( int Count = 0; Count < DigitsArraySize; Count++ )
              {
              DigitsArray[Count] -= ToSub.DigitsArray[Count];
              if( DigitsArray[Count] < 0 )
            DigitsArray[Count] += (int)IntMath.GetPrimeAt( Count );

              }
        }
 // This is the closest this has to Divide().
 internal void ModularInverse( ChineseRemainder ToDivide )
 {
     // ToDivide times what equals this number?
     for( int Count = 0; Count < DigitsArraySize; Count++ )
       {
       for( int CountPrime = 0; CountPrime < DigitsArray[Count].Prime; CountPrime++ )
     {
     int Test = CountPrime * ToDivide.DigitsArray[Count].Value;
     Test = Test % DigitsArray[Count].Prime;
     if( Test == DigitsArray[Count].Value )
       {
       DigitsArray[Count].Value = CountPrime;
       break;
       }
     }
       }
 }
 internal void Multiply( ChineseRemainder ToMul )
 {
     for( int Count = 0; Count < DigitsArraySize; Count++ )
       {
       // There is no Diffusion here either, like the kind that
       // Claude Shannon wrote about in A Mathematical Theory of
       // Cryptography.
       DigitsArray[Count].Value *= ToMul.DigitsArray[Count].Value;
       DigitsArray[Count].Value %= DigitsArray[Count].Prime;
       }
 }
Пример #18
0
        // Copyright Eric Chauvin.
        internal void ModularReduction( ChineseRemainder CRTInput,
                                  ChineseRemainder CRTAccumulate )
        {
            try
            {
            if( NumbersArray == null )
              throw( new Exception( "Bug: The NumbersArray should have been set up already." ));

            if( CRTBaseModArray == null )
              throw( new Exception( "Bug: The BaseModArray should have been set up already." ));

            // This first one has the prime 2 as its base so it's going to
            // be set to either zero or one.
            if( CRTInput.GetDigitAt( 0 ) == 1 )
              {
              CRTAccumulate.SetToOne();
              }
            else
              {
              CRTAccumulate.SetToZero();
              }

            CRTBase CRTBaseInput = new CRTBase( IntMath );
            int HowManyToAdd = SetFromCRTNumber( CRTBaseInput, CRTInput );

            // Integer Test = new Integer();
            // ChineseRemainder CRTTest = new ChineseRemainder( IntMath );
            // GetTraditionalInteger( CRTBaseInput, Test );
            // CRTTest.SetFromTraditionalInteger( Test );
            // if( !CRTTest.IsEqual( CRTInput ))
              // throw( new Exception( "CRTTest for CRTInput isn't right." ));

            // Count starts at 1, so it's the prime 3.
            for( int Count = 1; Count <= HowManyToAdd; Count++ )
              {
              // BaseMultiple is a number that is not bigger
              // than the prime at this point.  (The prime at:
              // IntMath.GetPrimeAt( Count ).)
              uint BaseMultiple = (uint)CRTBaseInput.GetDigitAt( Count );

              // It uses the CRTBaseModArray here:
              CRTWorkingTemp.Copy( CRTBaseModArray[Count] );
              CRTWorkingTemp.Multiply( NumbersArray[BaseMultiple] );
              CRTAccumulate.Add( CRTWorkingTemp );
              }
            }
            catch( Exception Except )
              {
              throw( new Exception( "Exception in ModularReduction(): " + Except.Message ));
              }
        }
Пример #19
0
        internal int SetFromCRTNumber( CRTBase ToSet, ChineseRemainder SetFrom )
        {
            try
            {
            if( NumbersArray == null )
              throw( new Exception( "Bug: The NumbersArray should have been set up already." ));

            // ToSet.SetToZero();

            // CRTBaseArray[0] is 1.
            if( SetFrom.GetDigitAt( 0 ) == 1 )
              {
              ToSet.SetToOne(); // 1 times 1 for this base.
              CRTAccumulateForBaseMultiples.SetToOne();
              }
            else
              {
              ToSet.SetToZero();
              CRTAccumulateForBaseMultiples.SetToZero();
              }

            int HighestNonZeroDigit = 1;
            // Count starts at 1, so it's at the prime 3.
            for( int Count = 1; Count < ChineseRemainder.DigitsArraySize; Count++ )
              {
              int Prime = (int)IntMath.GetPrimeAt( Count );
              int AccumulateDigit = CRTAccumulateForBaseMultiples.GetDigitAt( Count );
              int CRTInputTestDigit = SetFrom.GetDigitAt( Count );
              int BaseDigit = CRTBaseArray[Count].GetDigitAt( Count );
              if( BaseDigit == 0 )
            throw( new Exception( "This never happens. BaseDigit == 0." ));

              int BaseMult = CRTInputTestDigit;
              if( BaseMult < AccumulateDigit )
            BaseMult += Prime;

              BaseMult -= AccumulateDigit;
              int Inverse = MultInverseArray[Count, BaseDigit];
              BaseMult = (BaseMult * Inverse) % Prime;

              ToSet.SetDigitAt( BaseMult, Count );
              if( BaseMult != 0 )
            HighestNonZeroDigit = Count;

              // Notice that this is using CRTBaseArray and not
              // CRTBaseModArray.
              // This would be very fast in parallel hardware,
              // but not in software that has to do each digit
              // one at a time.
              CRTAccumulatePart.Copy( CRTBaseArray[Count] );
              CRTAccumulatePart.Multiply( NumbersArray[BaseMult] );
              CRTAccumulateForBaseMultiples.Add( CRTAccumulatePart );
              }

            return HighestNonZeroDigit;
            }
            catch( Exception Except )
              {
              throw( new Exception( "Exception in SetFromCRTNumber(): " + Except.Message ));
              }
        }
Пример #20
0
        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." );
        }