99 lines
4.2 KiB
C#
99 lines
4.2 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
}
|
||
|
}
|