108 lines
4.4 KiB
C#
108 lines
4.4 KiB
C#
// ----------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
}
|