_Exp(Digits @base, Digits exp, int expDigitN, Digits answer) { int expBitNUsed = Digits.SigBitN(exp, expDigitN); ushort[] widthCutoffs = new ushort[] { 6, 24, 80, 240, 672 }; Digits basepower = answer; int bucketWidth = 1; while ( bucketWidth < 5 && widthCutoffs[bucketWidth - 1] < expBitNUsed ) { bucketWidth++; } Modular.ValidateData(@base, _mod, _digitN); UInt32 bucketMask = (1U << bucketWidth) - 1; UInt32 maxBucket = bucketMask; Digits bucketData = new Digits((int)(_digitN * maxBucket)); Temps2000 temps = new Temps2000(); temps._modulus = this; temps._bucket[0] = null; Modular.Add(_one, _one, bucketData, _mod, _digitN); bool base2 = Digits.Compare(@base, bucketData, _digitN) == 0; if (base2 && expBitNUsed != 0) { int shiftMax = Digit.BitN * _digitN > 1024 ? 1024 : Digit.BitN * _digitN; int highExponBitN = 0; bool bighBitNProcessed = false; Digits temp = bucketData; for (int i = expBitNUsed; i-- != 0;) { Digit expBit = Digits.GetBit(exp, i); if (bighBitNProcessed) { _Mul(temp, temp, temp); if (expBit != 0) { Modular.Add(temp, temp, temp, _mod, _digitN); } } else { highExponBitN = (int)(2 * highExponBitN + expBit); if (i == 0 || 2 * highExponBitN >= shiftMax) { bighBitNProcessed = true; _Shift(_one, highExponBitN, temp); } } } temps._bucket[1] = temp; Debug.Assert(bighBitNProcessed, "internal error"); } else { UInt32 ibucket; for (ibucket = 1; ibucket <= maxBucket; ibucket++) { Digits bloc = bucketData + (int)(_digitN * (ibucket - 1 + ((ibucket & 1) == 0 ? maxBucket : 0)) / 2); temps._bucket[ibucket] = bloc; temps._bucketBusy[ibucket] = false; bloc._Set(_one, _digitN); } basepower._Set(@base, _digitN); Digit carried = 0; int ndoubling = 0; for (int i = 0; i != expBitNUsed; i++) { Digit bitNow = Digits.GetBit(exp, i); Debug.Assert(carried >> bucketWidth + 2 == 0 , "internal error"); if (bitNow != 0) { while (ndoubling >= bucketWidth + 1) { if ((carried & 1) != 0) { ibucket = carried & bucketMask; carried -= ibucket; temps._modulus ._BucketMul(ibucket, basepower, temps); } temps._modulus._BasePowerSquaring(basepower); carried /= 2; ndoubling--; } carried |= 1U << ndoubling; } ndoubling++; } while (carried != 0) { bool squareNow = false; if (carried <= maxBucket) { ibucket = carried; } else if ((carried & 1) == 0) { squareNow = true; } else if (carried <= 3 * maxBucket) { ibucket = maxBucket; } else { Debug.Assert(false, "untested code"); ibucket = carried & bucketMask; } if (squareNow) { carried /= 2; temps._modulus._BasePowerSquaring(basepower); } else { carried -= ibucket; temps._modulus._BucketMul(ibucket, basepower, temps); } } for (ibucket = maxBucket; ibucket >= 2; ibucket--) { if (temps._bucketBusy[ibucket]) { bool found = false; UInt32 jbucket, jbucketMax, kbucket; Digits bloci; if ((ibucket & 1) == 0) { jbucketMax = ibucket / 2; } else { jbucketMax = 1; } for ( jbucket = ibucket >> 1; jbucket != ibucket && !found; jbucket++ ) { if (temps._bucketBusy[jbucket]) { jbucketMax = jbucket; found = temps._bucketBusy[ibucket - jbucket]; } } jbucket = jbucketMax; kbucket = ibucket - jbucket; bloci = temps._bucket[ibucket]; temps._modulus._BucketMul(jbucket, bloci, temps); temps._modulus._BucketMul(kbucket, bloci, temps); } } } answer._Set(temps._bucket[1], _digitN); }
public Key(int bitN, Random generator) { _modBitN = bitN; // The public exponent is 2^16 + 1 _eBitN = 17; _eBytes = new byte[] { 1, 0, 1 }; int p1BitN = (bitN + 1) / 2 , p1ByteN = (p1BitN + 7) / 8 , p1DigitN = (p1BitN + (Digit.BitN - 1)) / Digit.BitN , p2BitN = bitN / 2 , p2ByteN = (p2BitN + 7) / 8 , p2DigitN = (p2BitN + (Digit.BitN - 1)) / Digit.BitN , longerDigitN = p1DigitN > p2DigitN ? p1DigitN : p2DigitN; Digits d1 = new Digits(p1DigitN), d2 = new Digits(p2DigitN); _modDigits = new Digits(_modDigitN); _eDigits = new Digits(1); Digits gcd = new Digits(longerDigitN) , temp = new Digits(longerDigitN); Digits.BytesToDigits(_eBytes, 0, _eDigits, _eBitN); int[] pBitN = new int[] { p1BitN, p2BitN }; int nPrimeFound = 0; Digits p1 = null, p2 = null; while (nPrimeFound != 2) { int pNowBitN = pBitN[nPrimeFound] , pNowDigitN = (pNowBitN + (Digit.BitN - 1)) / Digit.BitN; Digits pNow = Prime.NewPrime(pNowBitN, generator); if (nPrimeFound == 0) { p1 = pNow; } else { p2 = pNow; } Digits.Sub(pNow, 1, temp, pNowDigitN); int lgcd; Digits.ExtendedGcd(_eDigits , _eDigitN , temp , pNowDigitN , nPrimeFound == 0 ? d1 : d2 , null , gcd , out lgcd); if (Digits.Compare(gcd, 1, lgcd) != 0) { Debug.Assert(false, "untested code"); continue; } if ( nPrimeFound == 1 && Digits.Compare(p1, p1DigitN, p2, p2DigitN) == 0 ) { Debug.Assert(false, "untested code"); continue; } nPrimeFound++; } Digits.Mul(p1, p1DigitN, p2, p2DigitN, _modDigits); int modBitN = Digits.SigBitN(_modDigits, _modDigitN); Debug.Assert(modBitN == p1BitN + p2BitN && modBitN == _modBitN , "internal error"); _primeBitN = new int[2] { p1BitN, p2BitN }; _modBytes = new byte[_modByteN]; _primeBytes = new byte[2][] { new byte[p1ByteN], new byte[p2ByteN] }; _dBytes = new byte[2][] { new byte[p1ByteN], new byte[p2ByteN] }; Digits.DigitsToBytes(_modDigits, _modBytes, 0, _modBitN); for (int ip = 0; ip != 2; ip++) { Digits.DigitsToBytes( ip == 0 ? p1 : p2, _primeBytes[ip], 0, pBitN[ip]); Digits.DigitsToBytes( ip == 0 ? d1 : d2, _dBytes[ip], 0, pBitN[ip]); } int moduliCreated = 0; Digits.BytesToDigits(_eBytes, 0, _eDigits, _eBitN); _modulus = new Modulus(_modDigits, _modDigitN, true); _privateModulus = new Modulus[2]; _dDigits = new Digits[2]; _chineseDigits = new Digits[2]; for (int ip = 0; ip != 2; ip++) { Digits temp2 = new Digits(_modDigitN); _dDigits[ip] = new Digits(p1DigitN); _chineseDigits[ip] = new Digits(p1DigitN); Digits.BytesToDigits( _primeBytes[ip], 0, temp2, _primeBitN[ip]); _privateModulus[ip] = new Modulus(temp2 , (_primeBitN[ip] + (Digit.BitN - 1)) / Digit.BitN , true); moduliCreated++; Digits.BytesToDigits( _dBytes[ip], 0, _dDigits[ip], _primeBitN[ip]); } int lgcd2 = 0; Digits gcd2 = new Digits(_modDigitN); Digits.ExtendedGcd(_privateModulus[0]._mod , p1DigitN , _privateModulus[1]._mod , p2DigitN , _chineseDigits[1] , _chineseDigits[0] , gcd2 , out lgcd2); if (Digits.Compare(gcd2, 1, lgcd2) != 0) { throw new ArgumentException(); } }