// ---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // ---------------------------------------------------------------------------- using System; using System.Diagnostics; namespace Microsoft.Singularity.Crypto.PublicKey { struct Digit { readonly UInt32 _digit; Digit(UInt32 digit) { _digit = digit; } public static implicit operator UInt32(Digit d) { return d._digit; } public static explicit operator long(Digit d) { return (long)d._digit; } public static implicit operator Digit(UInt32 digit) { return new Digit(digit); } public override string ToString() { return _digit.ToString(); } public static Digit operator <<(Digit d, int n) { Debug.Assert(0 <= n && n < BitN, "internal error"); return new Digit(d._digit << n); } public static Digit operator >>(Digit d, int n) { Debug.Assert(0 <= n && n < BitN, "internal error"); return new Digit(d._digit >> n); } internal const int BitN = 32; internal const UInt32 MaxValue = UInt32.MaxValue; static byte[] leadingZeroBitN = new byte[] { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; internal static int SigBitN(Digit d) { d |= 1; int bitN = BitN; while (d < 1U << BitN - 5) { bitN -= 5; d <<= 5; } return bitN - leadingZeroBitN[d >> BitN - 4]; } internal static Digit TwoAdicInverse(Digit d) { if ((d & 1) == 0) { throw new ArgumentException(); } UInt32 dInverse = unchecked(3 * d ^ 2) , error = unchecked(1 - d * dInverse); Debug.Assert((error & 31) == 0, "internal error"); for (int bitN = 5; bitN < BitN / 2; bitN *= 2) { unchecked { dInverse += dInverse * error; error = error * error; Debug.Assert(error == 1 - d * dInverse, "internal error"); } } return unchecked(dInverse * error + dInverse); } static byte[] trailingZeroN = new byte[] { 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; internal static Digit OddGcd(Digit d1, Digit d2) { if (((d1 | d2) & 1) == 0) { throw new ArgumentException(); } if (d1 == 0 || d2 == 0) { Debug.Assert(false, "untested code"); return d1 + d2; } do { d1 >>= trailingZeroN[d1 & 15]; } while ((d1 & 1) == 0); do { d2 >>= trailingZeroN[d2 & 15]; } while ((d2 & 1) == 0); while (d1 != d2) { int sh1 = 1 + trailingZeroN[(d1 ^ d2) >> 1 & 15]; UInt32 n12Max = d1 > d2 ? d1 : d2; d1 = d1 ^ d2 ^ n12Max; d2 = n12Max - d1 >> sh1; do { d2 >>= trailingZeroN[d2 & 15]; } while ((d2 & 1) == 0); Debug.Assert((d1 & d2 & 1) != 0, "internal error"); } return d1; } internal static Digit Random(Random generator) { return (UInt32)generator.Next(65536) << 16 | (UInt32)generator.Next(65536); } internal static Digit Random(UInt32 dlow, UInt32 dhigh, Random generator) { if (dhigh < dlow) { throw new ArgumentException(); } UInt32 spread = dhigh - dlow; int shiftBitN = BitN - SigBitN(spread | 1); UInt32 result = 0; do { result = Random(generator)._digit >> shiftBitN; } while (result > spread); return dlow + result; } } }