// ---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // ---------------------------------------------------------------------------- using System; using System.Diagnostics; namespace Microsoft.Singularity.Crypto.PublicKey { class Prime { const uint _RabinTestN = 50; const uint _IterationsAllowed = 5000; internal static Digits NewPrime(int pBitN, Random generator) { if (pBitN < Digit.BitN) { throw new ArgumentException(); } int pDigitN = (pBitN + (Digit.BitN - 1)) / Digit.BitN; Digits p = new Digits(pDigitN); while (true) { for ( int iteration = 0; iteration < _IterationsAllowed; iteration++ ) { Digits.Random(p, pDigitN, generator); p[pDigitN - 1] >>= Digit.BitN * pDigitN - pBitN; p[0] |= 1; Digits.SetBit(p, pBitN - 1, 1); Digits.SetBit(p, pBitN - 2, 1); if (DivisibleBySomeLowPrime(p, pDigitN)) { continue; } Modulus modulus = new Modulus(p, pDigitN, true); Digits minus1 = new Digits(pDigitN); Modular .Neg(modulus._one, minus1, modulus._mod, modulus._digitN); Digits exp = new Digits(pDigitN); Digits.Shift(p, -1, exp, pDigitN); Digits @base = new Digits(pDigitN); for (int i = 1; i <= _RabinTestN; i++) { if (i == 1) { Modular.Add(modulus._one , modulus._one , @base , modulus._mod , modulus._digitN); } else { Modular.NonZeroRandom( p, @base, pDigitN, generator); } Digits result = new Digits(pDigitN); modulus._Exp(@base, exp, pDigitN, result); if (Digits.Compare(result, minus1, pDigitN) == 0) { return p; } if ( Digits.Compare(result, modulus._one, pDigitN) != 0 ) { break; } } } Debug.Assert(false, "too many iterations"); } } static Digit[] LowPrimesProduct = new Digit[] { 4240068105U, 3842999413U, 3059475739U, 4294251953U, 4294770617U , 4294737533U, 4293835597U, 4294901213U, 4294933861U, 1353041857U , 4148193053U, 4286755457U, 4291682933U, 4294875479U , 4294914791U, 4294097393U, 4289642801U, 4280410741U , 4294824337U, 4294927237U, 4294924747U, 4294928843U }; internal static bool DivisibleBySomeLowPrime(Digits digits, int n) { if (n == 0 || (digits[0] & 1) == 0) { Debug.Assert(false, "untested code"); return true; } for (int l = 0; l != LowPrimesProduct.Length; l++) { Digit product = LowPrimesProduct[l] , productInverse = Digit.TwoAdicInverse(product) , r = 0; for (int i = 0; i != n; i++) { Digit mulby; unchecked { r += digits[i]; if (r < digits[i]) { r -= product; } mulby = productInverse * r; Debug.Assert(mulby * product == r, "internal error"); } r = product - Digit2.Hi((UInt64)mulby * product); } if (Digit.OddGcd(r, product) != 1) { return true; } } return false; } } }