/// <summary> /// Удвоить точку на кривой /// </summary> /// <param name="value"></param> /// <returns></returns> public IEllipticCurvePoint Doubling() { if (m_Y.Zero) { return(GetInfinity()); } // Исходные координаты uint[] a = m_a4.m_Value; uint[] x = m_X.m_Value; uint[] y = m_Y.m_Value; uint[] z = m_Z.m_Value; uint[] modulo = m_Modulo.m_Value; int maxModuloBitIndex = BigHelper.MaxNonZeroBitIndex(modulo); int length = modulo.Length; // Выделим кэш операций умножения uint[] cache = new uint[length * 2]; uint[] s = new uint[length]; uint[] m = new uint[length]; uint[] x1 = new uint[length]; uint[] y1 = new uint[length]; uint[] z1 = new uint[length]; // Расчитаем m // Первое слагаемое a*Z1^4 ModuloOperations.Multiply(z, z, modulo, z1, cache); ModuloOperations.Multiply(z1, z1, modulo, z1, cache); ModuloOperations.Multiply(z1, a, modulo, z1, cache); // Второе слагаемое 3*X1^2 ModuloOperations.Multiply(x, x, modulo, m, cache); ModuloOperations.Multiply(m, 3, modulo, m, cache); // Результат m = 3*X1^2 + a*Z1^4 ModuloOperations.Addition(m, z1, modulo); // Расчитаем s = 4*X1*Y1^2 ModuloOperations.Multiply(y, y, modulo, z1, cache); ModuloOperations.Multiply(z1, x, modulo, s, cache); ModuloOperations.Multiply(s, 4, modulo, s, cache); // Расчитаем X3 = m^2 - 2*s ModuloOperations.Multiply(m, m, modulo, x1, cache); ModuloOperations.Multiply(s, 2, modulo, y1, cache); ModuloOperations.Substraction(x1, y1, modulo); // Расчитаем Y3 = m*(s - X3) - 8*Y1^4 ModuloOperations.Multiply(z1, z1, modulo, z1, cache); ModuloOperations.Multiply(z1, 8, modulo, z1, cache); ModuloOperations.Substraction(s, x1, modulo, y1); ModuloOperations.Multiply(y1, m, modulo, y1, cache); ModuloOperations.Substraction(y1, z1, modulo); // Расчитаем Z3 = 2*Y1*Z1 ModuloOperations.Multiply(y, z, modulo, z1, cache); ModuloOperations.Multiply(z1, 2, modulo, z1, cache); return(new EllipticCurvePointB(x1, y1, z1, this)); }
/// <summary> /// Doubling the point in elliptic curve /// </summary> /// <returns></returns> public IEllipticCurvePoint Doubling() { if (Infinity) { return(GetInfinity()); } // Coordinates uint[] a = m_a4.m_Value; uint[] b = m_a6.m_Value; uint[] x = m_X.m_Value; uint[] y = m_Y.m_Value; uint[] z = m_Z.m_Value; uint[] modulo = m_Modulo.m_Value; int maxModuloBitIndex = BigHelper.MaxNonZeroBitIndex(modulo); int length = modulo.Length; // Get the cache uint[] cache = new uint[length * 2]; uint[] s = new uint[length]; uint[] m = new uint[length]; uint[] x1 = new uint[length]; uint[] y1 = new uint[length]; uint[] z1 = new uint[length]; // X^2 ModuloOperations.Multiply(x, x, modulo, x1, cache); // Z^2 ModuloOperations.Multiply(z, z, modulo, y1, cache); // Z1 = Z^2*X^2 ModuloOperations.Multiply(x1, y1, modulo, z1, cache); // X^4 ModuloOperations.Multiply(x1, x1, modulo, x1, cache); // Z^4 ModuloOperations.Multiply(y1, y1, modulo, y1, cache); // b*Z^4 ModuloOperations.Multiply(y1, y1, modulo, y1, cache); // X1 = X^4 + b*Z^4 ModuloOperations.Addition(x1, y1, modulo); // a*Z1 ModuloOperations.Multiply(z1, a, modulo, s, cache); // Y^2 ModuloOperations.Multiply(y, y, modulo, m, cache); // a*Z1 + Y^2 ModuloOperations.Addition(s, m, modulo); // a*Z1 + Y^2 + b*Z^4 ModuloOperations.Addition(s, y1, modulo); // X1*(a*Z1 + Y^2 + b*Z^4) ModuloOperations.Multiply(s, x1, modulo, s, cache); // b*Z^4*Z1 ModuloOperations.Multiply(y1, z1, modulo, y1, cache); // Y1 = b*Z^4*Z1 + X1*(a*Z1 + Y^2 + b*Z^4) ModuloOperations.Addition(y1, s, modulo); return(new EllipticCurvePointC(x1, y1, z1, this)); }
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="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); }
/// <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); } }
/// <summary> /// Умножить точку на число на эллиптической кривой /// </summary> /// <param name="value1">Точка на эллиптической кривой</param> /// <param name="value2">Множитель к точке</param> /// <returns></returns> public IEllipticCurvePoint Multiply(IntBig value2) { EllipticCurvePointB tempPoint = null; // Массив значений для этапа "предвычислений" // !!!!!!!!!!!!!!Занимательная задачка: надо подумать над графом вычислений, ибо почти стопроцентная уверенность, что не все значения массива понадобятся... Налицо оптимизация EllipticCurvePointB[] points = new EllipticCurvePointB[16]; points[0] = GetInfinity() as EllipticCurvePointB; points[1] = this; points[2] = points[1].Doubling() as EllipticCurvePointB; points[3] = points[1].Addition(points[2]) as EllipticCurvePointB; points[4] = points[2].Doubling() as EllipticCurvePointB; points[5] = points[1].Addition(points[4]) as EllipticCurvePointB; points[6] = points[3].Doubling() as EllipticCurvePointB; points[7] = points[1].Addition(points[6]) as EllipticCurvePointB; points[8] = points[4].Doubling() as EllipticCurvePointB; points[9] = points[1].Addition(points[8]) as EllipticCurvePointB; points[10] = points[5].Doubling() as EllipticCurvePointB; points[11] = points[1].Addition(points[10]) as EllipticCurvePointB; points[12] = points[6].Doubling() as EllipticCurvePointB; points[13] = points[1].Addition(points[12]) as EllipticCurvePointB; points[14] = points[7].Doubling() as EllipticCurvePointB; points[15] = points[1].Addition(points[14]) as EllipticCurvePointB; // Начальный индекс множителя, от него начинается движение по двоичному представлению большого числа int index = BigHelper.MaxNonZeroBitIndex(value2.m_Value); int howManyDouble = 0; int howMuchAdd = 0; //if (index < 0) // break; index = GetWindow(value2, index, out howManyDouble, out howMuchAdd); tempPoint = points[howMuchAdd]; while (true) { if (index < 0) { break; } index = GetWindow(value2, index, out howManyDouble, out howMuchAdd); if (howManyDouble > 0) { for (int t = 0; t < howManyDouble; ++t) { tempPoint = tempPoint.Doubling() as EllipticCurvePointB; } } if (howMuchAdd > 0) { tempPoint = tempPoint.Addition(points[howMuchAdd]) as EllipticCurvePointB; } } return(tempPoint); }
/// <summary> /// Multiplies the this value at IntBig value /// </summary> /// <param name="value">IntBig multiplier</param> /// <returns>Result of operation</returns> public IEllipticCurvePoint Multiply(IntBig value2) { EllipticCurvePointC tempPoint = null; EllipticCurvePointC[] points = new EllipticCurvePointC[16]; points[0] = GetInfinity() as EllipticCurvePointC; points[1] = this; points[2] = points[1].Doubling() as EllipticCurvePointC; points[3] = points[1].Addition(points[2]) as EllipticCurvePointC; points[4] = points[2].Doubling() as EllipticCurvePointC; points[5] = points[1].Addition(points[4]) as EllipticCurvePointC; points[6] = points[3].Doubling() as EllipticCurvePointC; points[7] = points[1].Addition(points[6]) as EllipticCurvePointC; points[8] = points[4].Doubling() as EllipticCurvePointC; points[9] = points[1].Addition(points[8]) as EllipticCurvePointC; points[10] = points[5].Doubling() as EllipticCurvePointC; points[11] = points[1].Addition(points[10]) as EllipticCurvePointC; points[12] = points[6].Doubling() as EllipticCurvePointC; points[13] = points[1].Addition(points[12]) as EllipticCurvePointC; points[14] = points[7].Doubling() as EllipticCurvePointC; points[15] = points[1].Addition(points[14]) as EllipticCurvePointC; // First index int index = BigHelper.MaxNonZeroBitIndex(value2.m_Value); int howManyDouble = 0; int howMuchAdd = 0; //if (index < 0) // break; index = GetWindow(value2, index, out howManyDouble, out howMuchAdd); tempPoint = points[howMuchAdd]; while (true) { if (index < 0) { break; } index = GetWindow(value2, index, out howManyDouble, out howMuchAdd); if (howManyDouble > 0) { for (int t = 0; t < howManyDouble; ++t) { tempPoint = tempPoint.Doubling() as EllipticCurvePointC; } } if (howMuchAdd > 0) { tempPoint = tempPoint.Addition(points[howMuchAdd]) as EllipticCurvePointC; } } return(tempPoint); }
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 }
/// <summary> /// Adds the this value with another value in elliptic curve /// </summary> /// <param name="value">The value to add with this value</param> /// <returns>The sum of values</returns> public IEllipticCurvePoint Addition(IEllipticCurvePoint value) { EllipticCurvePointC value2 = value as EllipticCurvePointC; if (value2 as object == null) { throw new Exception("Incorrect point type!"); } if (m_a4 != value2.m_a4 || m_a6 != value2.m_a6 || m_Modulo != value2.m_Modulo) { throw new Exception("Incorrect value elliptic curve parameters!"); } if (value2.Infinity) { return(new EllipticCurvePointC(m_X, m_Y, m_Z, this)); } if (Infinity) { return(new EllipticCurvePointC(value2.m_X, value2.m_Y, value2.m_Z, value2)); } if (Equals(value2)) { return(Doubling()); } // Coordinates uint[] a = m_a4.m_Value; uint[] x1 = m_X.m_Value; uint[] y1 = m_Y.m_Value; uint[] z1 = m_Z.m_Value; uint[] x2 = value2.m_X.m_Value; uint[] y2 = value2.m_Y.m_Value; uint[] z2 = value2.m_Z.m_Value; uint[] modulo = m_Modulo.m_Value; int maxModuloBitIndex = BigHelper.MaxNonZeroBitIndex(modulo); int length = modulo.Length; // Get the cache uint[] cache = new uint[length * 2]; uint[] A = new uint[length]; uint[] D = new uint[length]; uint[] B = new uint[length]; uint[] C = new uint[length]; uint[] xr = new uint[length]; uint[] yr = new uint[length]; uint[] zr = new uint[length]; // Z1^2 ModuloOperations.Multiply(z1, z1, modulo, A, cache); // Z1^2 * a ModuloOperations.Multiply(z1, a, modulo, D, cache); // X2 * Z1 ModuloOperations.Multiply(x2, z1, modulo, B, cache); // B = X2 * Z1 + X1 ModuloOperations.Addition(B, x1, modulo); // C = Z1*B ModuloOperations.Multiply(z1, B, modulo, C, cache); // C + Z1^2 * a ModuloOperations.Addition(D, C, modulo); // B * (C + Z1^2 * a) ModuloOperations.Multiply(D, B, modulo, D, cache); // D = B^2 * (C + Z1^2 * a) ModuloOperations.Multiply(D, B, modulo, D, cache); // Y2 * Z1^2 ModuloOperations.Multiply(A, y2, modulo, A, cache); // A = Y2 * Z1^2 + Y1 ModuloOperations.Addition(A, y1, modulo); if (BigHelper.IfZero(B)) { if (BigHelper.IfZero(A)) { return(value2.Doubling()); } else { return(GetInfinity()); } } // Z3 = C^2 ModuloOperations.Multiply(C, C, modulo, zr, cache); // E = A * C ModuloOperations.Multiply(C, A, modulo, C, cache); // A^2 ModuloOperations.Multiply(A, A, modulo, xr, cache); // A^2 + D ModuloOperations.Addition(xr, D, modulo); // X3 = A^2 + D + E ModuloOperations.Addition(xr, C, modulo); // X2 * Z3 ModuloOperations.Multiply(x2, zr, modulo, A, cache); // F = X3 + X2 * Z3 ModuloOperations.Addition(A, xr, modulo); // X2 + Y2 ModuloOperations.Addition(x2, y2, modulo, B); // (X2 + Y2) * Z3 ModuloOperations.Multiply(B, zr, modulo, B, cache); // G = (X2 + Y2) * Z3^2 ModuloOperations.Multiply(B, zr, modulo, B, cache); // E + Z3 ModuloOperations.Addition(C, zr, modulo, yr); // (E + Z3) * F ModuloOperations.Multiply(yr, A, modulo, yr, cache); // (E + Z3) * F + G ModuloOperations.Addition(yr, B, modulo, yr); return(new EllipticCurvePointC(xr, yr, zr, this)); }
/// <summary> /// Сложить две точки на кривой /// </summary> /// <param name="value1"></param> /// <param name="value2"></param> /// <returns></returns> public IEllipticCurvePoint Addition(IEllipticCurvePoint value) { EllipticCurvePointB value2 = value as EllipticCurvePointB; if (value2 as object == null) { throw new Exception("Incorrect point type!"); } if (m_a4 != value2.m_a4 || m_a6 != value2.m_a6 || m_Modulo != value2.m_Modulo) { throw new Exception("Incorrect value elliptic curve parameters!"); } if (Equals(value2)) { return(Doubling()); } // Исходные координаты uint[] a = m_a4.m_Value; uint[] x1 = m_X.m_Value; uint[] y1 = m_Y.m_Value; uint[] z1 = m_Z.m_Value; uint[] x2 = value2.m_X.m_Value; uint[] y2 = value2.m_Y.m_Value; uint[] z2 = value2.m_Z.m_Value; uint[] modulo = m_Modulo.m_Value; int maxModuloBitIndex = BigHelper.MaxNonZeroBitIndex(modulo); int length = modulo.Length; // Выделим кэш операций умножения uint[] cache = new uint[length * 2]; // Временные переменные uint[] u1 = new uint[length]; uint[] u2 = new uint[length]; uint[] s1 = new uint[length]; uint[] s2 = new uint[length]; uint[] xr = new uint[length]; uint[] yr = new uint[length]; uint[] zr = new uint[length]; // Вычислить U1, U2, S1, S2 ModuloOperations.Multiply(z2, z2, modulo, u1, cache); ModuloOperations.Multiply(z1, z1, modulo, u2, cache); ModuloOperations.Multiply(u1, z2, modulo, s1, cache); ModuloOperations.Multiply(u2, z1, modulo, s2, cache); ModuloOperations.Multiply(u1, x1, modulo, u1, cache); ModuloOperations.Multiply(u2, x2, modulo, u2, cache); ModuloOperations.Multiply(s1, y1, modulo, s1, cache); ModuloOperations.Multiply(s2, y2, modulo, s2, cache); // Проверим, может расчет if (Eguals(u1, u2)) { if (Eguals(s1, s2)) { return(Doubling()); } else { return(GetInfinity()); } } ModuloOperations.Substraction(u2, u1, modulo); ModuloOperations.Substraction(s2, s1, modulo); //H^2 ModuloOperations.Multiply(u2, u2, modulo, yr, cache); //H^3 ModuloOperations.Multiply(yr, u2, modulo, zr, cache); //R^2 ModuloOperations.Multiply(s2, s2, modulo, xr, cache); //R^2 - H^3 ModuloOperations.Substraction(xr, zr, modulo); //U1*H^2 ModuloOperations.Multiply(u1, yr, modulo, yr, cache); //2*U1*H^2 ModuloOperations.Multiply(yr, 2, modulo, u1, cache); //X3 = R^2 - H^3 - 2*U1*H^2 ModuloOperations.Substraction(xr, u1, modulo); //U1*H^2 - X3 ModuloOperations.Substraction(yr, xr, modulo); //R*(U1*H^2 - X3) ModuloOperations.Multiply(yr, s2, modulo, yr, cache); //S1*H^3 ModuloOperations.Multiply(s1, zr, modulo, zr, cache); //R*(U1*H^2 - X3) - S1*H^3 ModuloOperations.Substraction(yr, zr, modulo); //Z1*Z2 ModuloOperations.Multiply(z1, z2, modulo, zr, cache); //Z3 = H*Z1*Z2 ModuloOperations.Multiply(zr, u2, modulo, zr, cache); return(new EllipticCurvePointB(xr, yr, zr, this)); }
/// <summary> /// Converts the value to its equivalent string representation by using the specified format /// </summary> /// <param name="value"></param> /// <param name="format">A standard or custom numeric format string</param> /// <param name="littleEndian">true if value must be represents as little-Endian</param> /// <returns></returns> public static string ToString(MIntBig value, string format, bool littleEndian) { return(BigHelper.ToString(value.m_Value.m_Value, format, littleEndian) + " mod " + BigHelper.ToString(value.m_Modulo.m_Value, format, littleEndian)); }