Ejemplo n.º 1
0
        private const uint BitMask = 0x80000000; // битовая маска

        // [1] 14.94 Algorithm Montgomery exponentiation
        // INPUT:
        //      m = (m[l-1] ... m[0]){b},
        //      R = b^l,
        //      mQ = m^-1 mod b,
        //      e = (e[t] ... e[0]){2}
        //           with e[t] = 1,
        //           and an integer x, 1 <= x < m.
        // OUTPUT: x^e mod m.
        public static uint[] PerformMontgomeryExponentiation(uint[] x, uint[] e, uint[] m)
        {
            if (null == x)
            {
                throw new ArgumentNullException(nameof(x));
            }

            if (null == e)
            {
                throw new ArgumentNullException(nameof(e));
            }

            if (null == m)
            {
                throw new ArgumentNullException(nameof(m));
            }

            // 1 <= x
            if (Compare(new uint[] { 1 }, x) > 0)
            {
                throw new ArgumentOutOfRangeException(nameof(x));
            }

            // e[t] = 1
            if (Compare(new uint[] { 1 }, e) > 0)
            {
                throw new ArgumentOutOfRangeException(nameof(e));
            }

            // x < m
            if (Compare(x, m) >= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(m));
            }

            // mQ = m^-1 mod b
            if (0 == m[0] % 2)
            {
                throw new ArgumentOutOfRangeException(nameof(m));
            }

            var mQ = Inverse(m[0]);

            var eLength = GetSignificanceLength(e);
            var mLength = GetSignificanceLength(m);

            // Resize
            if (mLength > x.Length)
            {
                ArrayUtility.Resize(ref x, mLength);
            }

            // 1. temp = Mont(x, R^2 mod m), A = R mod m.
            var r2 = new uint[m.Length * 2 + 1];

            r2[r2.Length - 1] = 1;

            Remainder(r2, m);

            var temp = PerformMontgomeryMultiplication(x, r2, m, mQ);

            var a = new uint[m.Length + 1];

            a[a.Length - 1] = 1;

            Remainder(a, m);

            var pos  = eLength - 1; // позиция
            var mask = BitMask;     // битовая маска

            // Узнаем количество значащих битов степени
            while (0 == (e[pos] & mask))
            {
                mask >>= 1;
            }

            // 2. For i from t down to 0 do the following:
            while (pos >= 0)
            {
                // 2.1 A = Mont(A, A).
                a = PerformMontgomeryMultiplication(a, a, m, mQ);

                // 2.2 If e[i] = 1 then A = Mont(A, temp).
                if (0 != (e[pos] & mask)) // если бит равен 1
                {
                    a = PerformMontgomeryMultiplication(a, temp, m, mQ);
                }

                mask >>= 1;

                if (0 == mask)
                {
                    mask = BitMask;
                    pos--;
                }
            }

            // 3. A Mont(A, 1).
            var one = new uint[m.Length];

            one[0] = 1;

            a = PerformMontgomeryMultiplication(a, one, m, mQ);

            // 4. Return (A).
            return(TrimLeadingZeros(a));
        }
Ejemplo n.º 2
0
        // [1] 14.36 Algorithm Montgomery multiplication
        // INPUT: integers
        //      m = (m[n-1] ... m[1] m[0]){b},
        //      x = (x[n-1] ... x[1] x[0]){b},
        //      y = (y[n-1] ... y[1] y[0]){b}
        //           with 0 <= x, y < m,
        //           R = b^n with gcd(m, b) = 1,
        //           and mQ = m^-1 mod b.
        // OUTPUT: x * y * R^-1 mod m.
        private static uint[] PerformMontgomeryMultiplication(uint[] x, uint[] y, uint[] m, uint mQ)
        {
            var n = GetSignificanceLength(m);

            if (0 == n)
            {
                throw new ArgumentOutOfRangeException(nameof(m), "Attempted to divide by zero.");
            }

            if (x.Length < n)
            {
                ArrayUtility.Resize(ref x, n);
            }

            if (y.Length < n)
            {
                ArrayUtility.Resize(ref y, n);
            }

            // 1. A = 0. (Notation: A = (a[n] a[n-1] ... a[1] a[0]){b})
            var a = new uint[n + 1];

            // 2. For i from 0 to (n - 1) do the following:
            for (var i = 0; i < n; i++)
            {
                // 2.1 u_i = (a[0] + x[i] * y[0]) * mQ mod b.
                var u = (uint)((a[0] + (ulong)x[i] * y[0]) * mQ);

                // 2.2 A = (A + x[i] * y + u_i * m) / b.
                var xy = (ulong)x[i] * y[0];
                var um = (ulong)u * m[0];

                var temp  = (ulong)a[0] + ((uint)xy) + (uint)um;
                var carry = (xy >> Int32Size) + (um >> Int32Size) + (temp >> Int32Size);

                for (var pos = 1; pos < n; pos++)
                {
                    xy = (ulong)x[i] * y[pos];
                    um = (ulong)u * m[pos];

                    temp  = (ulong)a[pos] + ((uint)xy) + (uint)um + (uint)carry;
                    carry = (xy >> Int32Size) + (um >> Int32Size) + (temp >> Int32Size) + (carry >> Int32Size);

                    a[pos - 1] = (uint)temp;
                }

                carry += a[n];

                a[n - 1] = (uint)carry;
                a[n]     = (uint)(carry >> Int32Size);
            }

            // 3. If A >= m then A = A - m
            if (Compare(a, m) >= 0)
            {
                Sub(a, m);
            }

            // 4. Return (A).
            return(a);
        }