/////////////////////////////////////////////////////////////////////////////// // // 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); } } }