105 lines
4.1 KiB
C#
105 lines
4.1 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
|
|
namespace Microsoft.Singularity.Crypto.PublicKey {
|
|
class Modular {
|
|
internal static void
|
|
Add(Digits a, Digits b, Digits c, Digits mod, int n) {
|
|
Debug.Assert(n != 0, "internal error");
|
|
Digit alead = a[n - 1], blead = b[n - 1], mlead = mod[n - 1];
|
|
if (alead >= mlead) { ValidateData(a, mod, n); }
|
|
if (blead >= mlead) { ValidateData(b, mod, n); }
|
|
int test;
|
|
if (blead > mlead - alead) {
|
|
test = +1;
|
|
} else if (mlead - alead - blead > 1) {
|
|
test = -1;
|
|
} else {
|
|
test = Digits.CompareSum(a, b, mod, n);
|
|
}
|
|
if (test >= 0) {
|
|
int carry = Digits.AddSub(a, b, mod, c, n);
|
|
Debug.Assert(carry == 0, "internal error");
|
|
} else {
|
|
uint carry = Digits.Add(a, b, c, n);
|
|
Debug.Assert(carry == 0, "internal error");
|
|
}
|
|
}
|
|
internal static void Neg(Digits a, Digits b, Digits mod, int n) {
|
|
Digit allZero = 0;
|
|
for (int i = 0; i != n; i++) { allZero |= a[i]; b[i] = a[i]; }
|
|
if (allZero != 0) {
|
|
if (Digits.Sub(mod, b, b, n) != 0) {
|
|
throw new ArgumentException();
|
|
}
|
|
}
|
|
}
|
|
internal static void
|
|
Sub(Digits a, Digits b, Digits c, Digits mod, int n) {
|
|
Debug.Assert(n > 0, "internal error");
|
|
Digit alead = a[n - 1], blead = b[n - 1], mlead = mod[n - 1];
|
|
int itest;
|
|
if (alead == blead) {
|
|
itest = Digits.Compare(a, b, n - 1);
|
|
} else {
|
|
itest = alead < blead ? -1 : +1;
|
|
}
|
|
if (itest < 0) {
|
|
if (blead >= mlead) { ValidateData(b, mod, n); }
|
|
int carry = Digits.AddSub(a, mod, b, c, n);
|
|
Debug.Assert(carry == 0, "internal error");
|
|
} else {
|
|
if (alead >= mlead) {
|
|
Debug.Assert(false, "untested code");
|
|
ValidateData(a, mod, n);
|
|
}
|
|
uint borrow = Digits.Sub(a, b, c, n);
|
|
Debug.Assert(borrow == 0, "internal error");
|
|
}
|
|
}
|
|
internal static void ValidateData(Digits data, Digits mod, int n) {
|
|
if (Digits.Compare(data, mod, n) >= 0) {
|
|
throw new ArgumentException();
|
|
}
|
|
}
|
|
static void Random(Digits mod, Digits arr, int n, Random generator) {
|
|
Debug.Assert(!arr._Overlaps(mod), "overlapping arguments");
|
|
int sigDigitN = n;
|
|
while (sigDigitN > 0 && mod[sigDigitN - 1] == 0) {
|
|
Debug.Assert(false, "untested code");
|
|
arr[sigDigitN - 1] = 0;
|
|
sigDigitN--;
|
|
}
|
|
if (sigDigitN == 0) { throw new ArgumentException(); }
|
|
Digit nlead = mod[sigDigitN - 1];
|
|
int ntry = 0;
|
|
do {
|
|
ntry++;
|
|
Debug.Assert(ntry <= 100, "too many iterations");
|
|
Digits.Random(arr, sigDigitN - 1, generator);
|
|
arr[sigDigitN - 1] = Digit.Random(0, nlead, generator);
|
|
} while (Digits.Compare(arr, mod, sigDigitN) >= 0);
|
|
}
|
|
internal static void
|
|
NonZeroRandom(Digits mod, Digits arr, int n, Random generator) {
|
|
if (Digits.Compare(mod, 1U, n) <= 0) {
|
|
throw new ArgumentException();
|
|
}
|
|
int ntry = 0;
|
|
do {
|
|
ntry++;
|
|
Debug.Assert(ntry <= 100, "too many iterations");
|
|
Random(mod, arr, n, generator);
|
|
} while (Digits.SigDigitN(arr, n) == 0);
|
|
}
|
|
}
|
|
}
|