/// <summary> /// Получение обратного числа по модулю от текущего /// Используется расширенный алгоритм Евклида /// </summary> /// <param name="value">Первое число</param> /// <param name="modulo">Второй число</param> /// <param name="result">Результат</param> unsafe public static void Invert(uint[] value, uint[] modulo, uint[] result, uint[] cache1, uint[] cache2, uint[] cache3, uint[] cache4, uint[] cache5, uint[] cache6) { uint[] a = cache1; uint[] b = cache2; uint[] q = cache3; uint[] r = cache4; uint[] v2 = cache5; uint[] v1 = cache6; int length = value.Length; ArrayCopyHelper.Copy(modulo, a, length); ArrayCopyHelper.Copy(value, b, length); v2[0] = 1; uint[] temp; // Пока целевое число не обнулилось while (!BigHelper.IfZero(b)) { //TODO: Собственно бег по результату надо написать // Получить первый результат деления BigHelper.Divide(a, b, q, r); temp = a; a = b; b = r; r = temp; Multiply(q, v2, modulo, q); Substraction(v1, q, modulo, v1); temp = v1; v1 = v2; v2 = temp; } ArrayCopyHelper.Copy(v1, result, length); }
unsafe public static void RightShift(uint[] value, uint[] result, uint[] modulo, uint[] cache, int shiftValue) { Array.Clear(cache, 0, cache.Length); // Количество сдвигов по индексам int indexShift = shiftValue / 32; // Количество внутренних сдвигов int valueShift = shiftValue % 32; // Заменить на указатели if (valueShift == 0) { Array.Copy(value, 0, cache, indexShift, value.Length); } else { int t1 = value.Length + indexShift; int t2 = 32 - valueShift; // Заполнить старший байт выходного вектора cache[t1] = (value[value.Length - 1] >> t2); t1--; // Заполнить серединку выходного массива for (int i = t1, i1 = value.Length - 1, i2 = value.Length - 2; i > indexShift; i--, i1--, i2--) { cache[i] = (value[i1] << valueShift) + (value[i2] >> t2); } // Заполнить "младший" байт массива cache[indexShift] = (value[0] << valueShift); } BigHelper.Modulo(cache, modulo); ArrayCopyHelper.Copy(cache, result, value.Length); }
/// <summary> /// Умножение по модулю с результатом в отдельный массив /// </summary> /// <param name="value1">Первый массив</param> /// <param name="value2">Второй массив</param> /// <param name="modulo">Модуль</param> /// <param name="result">Итоговый массив, можно не чистить</param> /// <param name="cache">Кэш, в два раза больше длины вектора величин, в него копируются промежуточные результаты умножений</param> unsafe public static void Multiply(uint[] value1, uint value2, uint[] modulo, uint[] result, uint[] cache) { // Внешний цикл для скорости должен иметь меньший размер fixed(uint *value1Pointer = value1, moduloPointer = modulo, cachePointer = cache) { // Этап умножения ulong temp = 0; int length = modulo.Length; // Границы массивов uint *value1EndPointer = value1Pointer + length; uint *tempValueEndPointer = cachePointer + cache.Length; // Переменные указатели uint *ptrCounter1, ptrResult; // Почистить кэш умножения for (ptrCounter1 = cachePointer; ptrCounter1 < tempValueEndPointer; ++ptrCounter1) { *ptrCounter1 = 0; } // Внутренний цикл for (ptrCounter1 = value1Pointer, ptrResult = cachePointer; ptrCounter1 < value1EndPointer; ++ptrCounter1, ++ptrResult) { // Нужно загрузить очередь блоков умножения современных процессоров (ориентировочно, латентность 3 такта, однако загрузка возможна каждый такт) temp += (ulong)value2 * *ptrCounter1 + (ulong)*ptrResult; *ptrResult = (uint)temp; temp >>= 32; } *ptrResult = (uint)temp; BigHelper.Modulo(cache, modulo); ArrayCopyHelper.Copy(cache, result, length); } }
unsafe public static uint[] Pow(uint[] value1, uint[] modulo, int value2) { if (value2 == 0) { return new uint[] { 1 } } ; uint[] returnValue = new uint[value1.Length]; ArrayCopyHelper.Copy(value1, returnValue, value1.Length); if (value2 < 0) { Invert(returnValue, modulo); } value2 = Math.Abs(value2); int nonZeroLength = BigHelper.MaxNonZeroBitIndex((uint)value2) + 1; if (nonZeroLength == 0) { return(null); } for (int i = nonZeroLength - 2; i >= 0; --i) { Multiply(returnValue, returnValue, modulo); if (((value2 >> i) & 1) == 1) { Multiply(returnValue, value1, modulo); } } return(returnValue); } #endregion Pow #endregion Public methods #region Internal methods #endregion Internal methods #region Private methods #endregion Private methods #region Events, overrides #endregion Events, overrides #endregion Methods }