// ec-function: Y^2 = X^3 + a*X + b 'modulo' P //P = {Xp, Yp}; Q = {Xq, Yq} //ADD: S = (Yp - Yq) / (Xp - Xq) // RESULT = {Xr = S * S - Xp - Xq; Yr = S(Xp - Xr) - Yp} //DUB: S = (3 * Xp * Xp + a) / (2 * Yp) // RESULT = {Xr = S * S - 2 * Xp ; Yr = S(Xp - Xr) - Yp} public void GetDouble(ref OwnECPoint p) { //return: 2 * p if (p.IsInfinity) { return; } if (IsZero(p.Y)) { p.SetInfinity(); return; } Let(S1, p.X); SquareModP(S1); AddScaledModP(S1, S1, 2); AddModP(S1, A); Let(S2, p.Y); AddModP(S2, S2); this.RemodFriendlyPrime(S1); this.RemodFriendlyPrime(S2); AsmX64Operations.DivideModuloPrime(S1, S2, P, N); Let(R1, S1); SquareModP(S1); SubScaledModP(S1, p.X, 2); //S1 = Rx = S * S - 2 * Px SubtractModP(p.X, S1, S2); //S2 = Px - Rx MultiplyModP(S2, R1); SubModP(S2, p.Y); //S2 = S(Px - Rx) - Py p.SetFrom(S1, S2, false); }
//return: P * factor on the elliptic curves domain. public OwnECPoint MultiplyWithEndomorphism(OwnECPoint p, ulong[] factor) { OwnECPoint result; if (!this.SupportsEndomorphism) { result = this.Multiply(p, factor); return(result); } BigInteger lambda = W1ModOrder.ToBigInteger(); BigInteger k = factor.ToBigInteger(), k1, k2; SplitKToHalfBits(k, lambda, out k1, out k2); OwnECPoint q = p.Copy(); MultiplyModP(q.X, W1ModP); //OwnECPoint test1 = Multiply(p, W1ModOrder); //bool testok = test1.ToString() == q.ToString(); //if (!testok) //{ // Debugger.Break(); //} result = DualMultiply(p, k1, q, k2); return(result); }
public OwnECPoint Negative(OwnECPoint point) { OwnECPoint result = point.Copy(); SubtractModP(this.P, result.Y, result.Y); return(result); }
public static bool IsSameAs(this OwnECPoint point1, ECPoint point2) { if (point1.IsInfinity || point2.IsInfinity) { return(point1.IsInfinity && point2.IsInfinity); } point2 = point2.Normalize(); return(point1.X.ToBigInteger() == point2.X && point1.Y.ToBigInteger() == point2.Y); }
public bool IsSameAs(OwnECPoint other) { if (this.IsInfinity != other.IsInfinity) { return(false); } if (this.IsInfinity) { return(true); } return(this.X.IsEqual(other.X) && this.Y.IsEqual(other.Y)); }
public void Add(ref OwnECPoint p, OwnECPoint q, bool subtract = false) { //returns: P + Q if (p.IsInfinity || q.IsInfinity) { if (!q.IsInfinity) { p.SetFrom(q.X, q.Y, q.IsInfinity); if (subtract) { SubtractModP(P, p.Y, p.Y); } } return; } SubtractModP(p.X, q.X, S2); //s2 = Px - Qx if (subtract) { //s1 = Py - Qy; in case of subtract real Q.Y is -Q.Y so we add the value modulo P. AdditionModP(p.Y, q.Y, S1); //s1 = Py - Qy } else { SubtractModP(p.Y, q.Y, S1); } if (IsZero(S2)) { //Px == Qx if (IsZero(S1)) { // P == Q GetDouble(ref p); return; } p.SetInfinity(); return; } this.RemodFriendlyPrime(S1); this.RemodFriendlyPrime(S2); AsmX64Operations.DivideModuloPrime(S1, S2, P, N); //S = s1 = s1 / s2 'modulo' P. Let(R1, S1); SquareModP(S1); SubModP(S1, p.X); SubModP(S1, q.X); //s1 = Result.x = S * S - Px - Qx SubtractModP(p.X, S1, S2); //s2 = Px - Rx MultiplyModP(S2, R1); SubModP(S2, p.Y); //s2 = S(Px - Rx) - Py p.SetFrom(S1, S2, false); }
public bool Verify(OwnECPoint point) { //Y^2 = X^3 + a*X + b 'modulo' P if (point.IsInfinity) { return(true); } Let(x1, point.X); Let(y1, point.Y); SquareModP(y1); SquareModP(x1); AddModP(x1, A); MultiplyModP(x1, point.X); AddModP(x1, B); SubModP(x1, y1); return(IsZero(x1)); }
//https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates#Mixed_Addition_(with_affine_point)_(8M_+_3S) //U1 = X1 [*Z2^2] //U2 = X2*Z1^2 //S1 = Y1 [*Z2^3] //S2 = Y2*Z1^3 //if (U1 == U2) // if (S1 != S2) // return POINT_AT_INFINITY // else // return POINT_DOUBLE(X1, Y1, Z1) //H = U2 - U1 //R = S2 - S1 //X3 = R^2 - H^3 - 2*U1*H^2 //Y3 = R*(U1*H^2 - X3) - S1*H^3 //Z3 = H*Z1*Z2 //return (X3, Y3, Z3) //http://www.hyperelliptic.org/EFD/oldefd/jacobian.html#mADD //Z2 = [p.Z]^2 //S1 = [q.X] * Z2 - [p.X] //R1 = [+/-q.Y] * [p.Z] * Z2 - [p.Y] //S2 = S1^2 //Z3 = ([p.Z]+S1)^2 - S2 - Z2 //S2 *= 4 //S1 *= S2 //R1 = 2*R1 //Y3 = [p.X]*S2 //X3 = R1^2-S1-2*Y3 //Y3 = R1*(Y3-X3)-2*[p.y]*S1 public void Add(ref JacobianECPoint p, OwnECPoint q, bool subtract = false) { //Mixed addition returns p + q in "7M + 4S" if (p.IsInfinity || q.IsInfinity) { if (!q.IsInfinity) { p.SetFrom(q.X, q.Y, One, q.IsInfinity); if (subtract) { SubtractModP(P, p.Y, p.Y); } } return; } Let(Z2, p.Z); SquareModP(Z2); //Z2 = [p.Z]^2 Let(S1, q.X); MultiplyModP(S1, Z2); SubModP(S1, p.X); //S1 = [q.X] * Z2 - [p.X] Let(R1, q.Y); if (subtract) { SubtractModP(P, R1, R1); } MultiplyModP(R1, p.Z); MultiplyModP(R1, Z2); SubModP(R1, p.Y); //R1 = [+/-q.Y] * [p.Z] * Z2 - [p.Y] if (IsZero(S1)) { if (IsZero(R1)) { //now: p == q GetDouble(ref p); return; } p.SetInfinity(); return; } Let(S2, S1); SquareModP(S2); //S2 = S1^2 Let(Z3, p.Z); AddModP(Z3, S1); SquareModP(Z3); SubModP(Z3, S2); SubModP(Z3, Z2); //Z3 = ([p.Z]+S1)^2 - S2 - Z2 AddScaledModP(S2, S2, 3); //S2 *= 4 MultiplyModP(S1, S2); //S1 *= S2 AddModP(R1, R1); //R1 = 2*R1 Let(y1, p.X); MultiplyModP(y1, S2); //Y3 = [p.X]*S2 Let(x1, R1); SquareModP(x1); SubModP(x1, S1); SubScaledModP(x1, y1, 2); //X3 = R1^2-S1-2*Y3 MultiplyModP(S1, p.Y); SubModP(y1, x1); MultiplyModP(y1, R1); SubScaledModP(y1, S1, 2); //Y3 = R1*(Y3-X3)-2*[p.y]*S1 p.SetFrom(x1, y1, Z3, false); }
//return: P * factor on the elliptic curves domain. public OwnECPoint Multiply(OwnECPoint p, ulong[] factor) { ulong[] exp = new ulong[factor.Length + 1]; ulong[] exp3 = new ulong[factor.Length + 1]; factor.CopyTo(exp, 0); exp3[factor.Length] = AsmX64Operations.MultiplyDigitAndAdd(exp, 3, exp3, factor.Length); for (int i = exp.Length; --i >= 0;) { exp3[i] ^= exp[i]; //exp3= (exp*3) ^ exp } int high = HighBit(exp3); if (high < 0) { return(new OwnECPoint(p.X, p.Y, true)); } JacobianECPoint x = new JacobianECPoint(p.X, p.Y, true); ulong mask = 1UL << (high & 63); for (int i = high; --i >= 0;) { GetDouble(ref x); if ((exp3[(i + 1) >> 6] & mask) != 0) { if ((exp[(i + 1) >> 6] & mask) != 0) { Subtract(ref x, p); } else { Add(ref x, p); } } mask = (mask >> 1) | (mask << 63); } OwnECPoint result = x.ToECPoint(this); return(result); }
//return: P * factor on the elliptic curves domain. public OwnECPoint MultiplyReference(OwnECPoint p, ulong[] factor) { int high = HighBit(factor); if (high < 0) { return(new OwnECPoint(p.X, p.Y, true)); } OwnECPoint result = p.Copy(); for (int i = high; --i >= 0;) { GetDouble(ref result); if ((factor[i >> 6] & (1UL << (i & 63))) != 0) { Add(ref result, p); } } RemodFriendlyPrime(result.X); RemodFriendlyPrime(result.Y); return(result); }
public static bool ECCUnitTest() { Random random = new Random(104); int n = 8; bool ok = true; TimeSpan elapsedInvertFast = TimeSpan.Zero, elapsedInvertSlow = TimeSpan.Zero; byte[] randomBytes = new byte[16 * n]; for (int i = 20; --i >= 0;) { ulong[] a0 = new ulong[n * 2]; a0[0] = 1UL; random.NextBytes(randomBytes); ulong[] x = Enumerable.Range(0, n * 2).Select(idx => idx >= n ? 0 : BitConverter.ToUInt64(randomBytes, idx * 8)).ToArray(); random.NextBytes(randomBytes); ulong[] p = Enumerable.Range(0, n).Select(idx => BitConverter.ToUInt64(randomBytes, idx * 8)).ToArray(); p[0] |= 1; GetDivMod(a0, p, n); GetDivMod(x, p, n); ulong[] a1 = a0.ToArray(); ulong[] a2 = a0.ToArray(); var fx = new FastInteger(x); var fp = new FastInteger(p); var f0 = new FastInteger(a0); if (fx.ToString() != x.ToBigInteger().ToString() || fp.ToString() != p.ToBigInteger().ToString() || f0.ToString() != a0.ToBigInteger().ToString()) { ok = false; } FastInteger idv = f0.DivideModulo(fx, fp); elapsedInvertFast += MeasureTime(() => { AsmX64Operations.DivideModuloPrime(a1, x, p, n); }); elapsedInvertSlow += MeasureTime(() => { AsmX64Operations.DivideModPSlow(a2, x, p, n); }); if (a1.ToBigInteger().ToString() != idv.ToString()) { ok = false; } ulong[] r1 = new ulong[n * 2]; Multiply(a1, x, r1, n); GetDivMod(r1, p, n); ulong[] r2 = new ulong[n * 2]; Multiply(a2, x, r2, n); GetDivMod(r2, p, n); if (!Enumerable.Range(0, n).All(idx => r1[idx] == r2[idx])) { ok = false; } } TimeSpan elapsedExponentiationSlow = TimeSpan.Zero, elapsedExponentiation521 = TimeSpan.Zero, elapsedExponentiationBigInt = TimeSpan.Zero, elapsedExponentiationFastInt = TimeSpan.Zero, elapsedExponentiationBigInt521 = TimeSpan.Zero, elapsedExponentiationFast = TimeSpan.Zero; SECP256K1Base ecc = new SECP256K1Base(); SECP521R1Base ecc2 = new SECP521R1Base(); ECCSecP256K1FastInteger fastEcc = new ECCSecP256K1FastInteger(); ECCSecP521R1 ecc521 = new ECCSecP521R1(); random = new Random(105); OwnECPoint point = ecc.G; OwnECPoint point521 = ecc2.G; ok = ok && ecc.Verify(point); ok = ok && ecc2.Verify(point521); ok = ok && ecc2.UnitTest(); randomBytes = new byte[ecc.N * 8]; ECC other = new ECC(); int ops = 1; ulong[] order521 = ecc2.Order.ToArray(); order521[0]--; for (int i = ops; --i >= 0;) { random.NextBytes(randomBytes); BigInteger orderInteger = randomBytes.ToBigInteger(); ulong[] order = Enumerable.Range(0, ecc.N).Select(idx => BitConverter.ToUInt64(randomBytes, idx * 8)).ToArray(); OwnECPoint point2 = ecc.MultiplyReference(point, order); OwnECPoint point3 = new OwnECPoint(); OwnECPoint point521_O = new OwnECPoint(); ECPoint point8_521 = null; elapsedExponentiation521 += MeasureTime(() => { point521_O = ecc2.MultiplyWithEndomorphism(point521, order521); }); elapsedExponentiationBigInt521 += MeasureTime(() => { point8_521 = ecc521.ECMultiplication(order521.ToBigInteger()); }); ok = ok && point521_O.X.IsEqual(point521.X) && point521_O.Y.ToBigInteger() + point521.Y.ToBigInteger() == (BigInteger.One << 521) - BigInteger.One; ok = ok && point8_521.X == point521.X.ToBigInteger() && point8_521.Y + point521.Y.ToBigInteger() == (BigInteger.One << 521) - BigInteger.One; FastECPoint point6 = ecc.ECMultiplication(randomBytes.ToFastInteger()); OwnECPoint point4 = new OwnECPoint(); ECPoint point5 = null; ECPoint point7 = null; elapsedExponentiationSlow += MeasureTime(() => { point3 = ecc.Multiply(point, order); }); elapsedExponentiationFast += MeasureTime(() => { point4 = ecc.MultiplyWithEndomorphism(point, order); }); elapsedExponentiationBigInt += MeasureTime(() => { point5 = other.ECMultiplication(orderInteger); }); elapsedExponentiationFastInt += MeasureTime(() => { point7 = fastEcc.ECMultiplication(orderInteger); }); ok &= ecc.Verify(point2); ok &= ecc.Verify(point3); ok &= ecc.Verify(point4); ok &= other.Verify(point5); if (!ok || !point2.IsSameAs(point3) || !point2.IsSameAs(point4) || !point2.IsSameAs(point5) || !point2.IsSameAs(point6) || !point2.IsSameAs(point7)) { ok = false; } } //MessageBox.Show( // "secP521r1 ecc multiplication: " + elapsedExponentiation521.ToString() + " ops/sec = " + (ops / elapsedExponentiation521.TotalSeconds).ToString("N3") + "\r\n" + // "P521R1 BigInt ecc multiplication: " + elapsedExponentiationBigInt521.ToString() + " ops/sec = " + (ops / elapsedExponentiationBigInt521.TotalSeconds).ToString("N3") + "\r\n" + // "Fast ecc multiplication: " + elapsedExponentiationFast.ToString() + " ops/sec = " + (ops / elapsedExponentiationFast.TotalSeconds).ToString("N3") + "\r\n" + // "BigInteger ecc multiplication: " + elapsedExponentiationBigInt.ToString() + " ops/sec = " + (ops / elapsedExponentiationBigInt.TotalSeconds).ToString("N3") + "\r\n" + // "FastInteger ecc multiplication: " + elapsedExponentiationFastInt.ToString() + " ops/sec = " + (ops / elapsedExponentiationFastInt.TotalSeconds).ToString("N3") + "\r\n" + // "Slow ecc multiplication: " + elapsedExponentiationSlow.ToString() + " ops/sec = " + (ops / elapsedExponentiationSlow.TotalSeconds).ToString("N3") + "\r\n", "Time", // MessageBoxButtons.OK, MessageBoxIcon.Information); return(ok); }
public bool UnitTest() { OwnECPoint S = new OwnECPoint( FromHex(@"000001d5 c693f66c 08ed03ad 0f031f93 7443458f 601fd098 d3d0227b 4bf62873 af50740b 0bb84aa1 57fc847b cf8dc16a 8b2b8bfd 8e2d0a7d 39af04b0 89930ef6 dad5c1b4"), FromHex(@"00000144 b7770963 c63a3924 8865ff36 b074151e ac33549b 224af5c8 664c5401 2b818ed0 37b2b7c1 a63ac89e baa11e07 db89fcee 5b556e49 764ee3fa 66ea7ae6 1ac01823"), false); OwnECPoint T = new OwnECPoint( FromHex(@"000000f4 11f2ac2e b971a267 b80297ba 67c322db a4bb21ce c8b70073 bf88fc1c a5fde3ba 09e5df6d 39acb2c0 762c03d7 bc224a3e 197feaf7 60d63240 06fe3be9 a548c7d5"), FromHex(@"000001fd f842769c 707c93c6 30df6d02 eff399a0 6f1b36fb 9684f0b3 73ed0648 89629abb 92b1ae32 8fdb4553 42683849 43f0e922 2afe0325 9b32274d 35d1b958 4c65e305"), false); OwnECPoint ST = new OwnECPoint( FromHex(@"00000126 4ae115ba 9cbc2ee5 6e6f0059 e24b52c8 04632160 2c59a339 cfb757c8 9a59c358 a9a8e1f8 6d384b3f 3b255ea3 f73670c6 dc9f45d4 6b6a196d c37bbe0f 6b2dd9e9"), FromHex(@"00000062 a9c72b8f 9f88a271 690bfa01 7a6466c3 1b9cadc2 fc544744 aeb81707 2349cfdd c5ad0e81 b03f1897 bd9c8c6e fbdf6823 7dc3bb00 445979fb 373b20c9 a967ac55"), false); OwnECPoint STSub = new OwnECPoint( FromHex(@"00000129 2cb58b17 95ba4770 63fef7cd 22e42c20 f57ae94c eaad86e0 d21ff229 18b0dd3b 076d63be 253de24b c20c6da2 90fa54d8 3771a225 deecf914 9f79a8e6 14c3c4cd"), FromHex(@"00000169 5e3821e7 2c7cacaa dcf62909 cd83463a 21c6d033 93c527c6 43b36239 c46af117 ab7c7ad1 9a4c8cf0 ae95ed51 72988546 1aa2ce27 00a6365b ca3733d2 920b2267"), false); OwnECPoint S2X = new OwnECPoint( FromHex(@"00000128 79442f24 50c119e7 119a5f73 8be1f1eb a9e9d7c6 cf41b325 d9ce6d64 3106e9d6 1124a91a 96bcf201 305a9dee 55fa7913 6dc70083 1e54c3ca 4ff2646b d3c36bc6"), FromHex(@"00000198 64a8b885 5c2479cb efe375ae 553e2393 271ed36f adfc4494 fc0583f6 bd035988 96f39854 abeae5f9 a6515a02 1e2c0eef 139e71de 610143f5 3382f410 4dccb543"), false); JacobianECPoint ST1 = S.ToJacobian; JacobianECPoint ST2 = S.ToJacobian; JacobianECPoint S2 = S.ToJacobian; Add(ref ST1, T, false); Add(ref ST2, T, true); GetDouble(ref S2); OwnECPoint ST1a = ST1.ToECPoint(this); OwnECPoint ST2a = ST2.ToECPoint(this); OwnECPoint S2a = S2.ToECPoint(this); if (!IsEqual(ST1a.X, ST.X) || !IsEqual(ST1a.Y, ST.Y)) { return(false); } if (!IsEqual(ST2a.X, STSub.X) || !IsEqual(ST2a.Y, STSub.Y)) { return(false); } if (!IsEqual(S2a.X, S2X.X) || !IsEqual(S2a.Y, S2X.Y)) { return(false); } ulong[] factorD = FromHex(@"000001eb 7f81785c 9629f136 a7e8f8c6 74957109 73555411 1a2a866f a5a16669 9419bfa9 936c78b6 2653964d f0d6da94 0a695c72 94d41b2d 6600de6d fcf0edcf c89fdcb1"); OwnECPoint dS = new OwnECPoint( FromHex(@"00000091 b15d09d0 ca0353f8 f96b93cd b13497b0 a4bb582a e9ebefa3 5eee61bf 7b7d041b 8ec34c6c 00c0c067 1c4ae063 318fb75b e87af4fe 859608c9 5f0ab477 4f8c95bb"), FromHex(@"00000130 f8f8b5e1 abb4dd94 f6baaf65 4a2d5810 411e77b7 423965e0 c7fd79ec 1ae563c2 07bd255e e9828eb7 a03fed56 5240d2cc 80ddd2ce cbb2eb50 f0951f75 ad87977f"), false); OwnECPoint rsd = Multiply(S, factorD); if (!IsEqual(rsd.X, dS.X) || !IsEqual(rsd.Y, dS.Y)) { return(false); } ulong[] factorE = FromHex(@"00000137 e6b73d38 f153c3a7 57561581 2608f2ba b3229c92 e21c0d1c 83cfad92 61dbb17b b77a6368 2000031b 9122c2f0 cdab2af7 2314be95 254de429 1a8f85f7 c70412e3"); OwnECPoint dSeT = new OwnECPoint( FromHex(@"0000009d 3802642b 3bea152b eb9e05fb a247790f 7fc16807 2d363340 133402f2 585588dc 1385d40e bcb8552f 8db02b23 d687cae4 6185b275 28adb1bf 9729716e 4eba653d"), FromHex(@"0000000f e44344e7 9da6f49d 87c10637 44e5957d 9ac0a505 bafa8281 c9ce9ff2 5ad53f8d a084a2de b0923e46 501de579 7850c61b 229023dd 9cf7fc7f 04cd35eb b026d89d"), false); OwnECPoint ret = Multiply(T, factorE); Add(ref ret, rsd, false); if (!IsEqual(ret.X, dSeT.X) || !IsEqual(ret.Y, dSeT.Y)) { return(false); } return(true); }
public override string ToString() { return(this.IsInfinity ? "Infinity" : "X = " + OwnECPoint.ToHexa(this.X) + " ; Y = " + OwnECPoint.ToHexa(this.Y) + " ; Z = " + OwnECPoint.ToHexa(this.Z)); }
//return: P * factor on the elliptic curves domain. public OwnECPoint DualMultiply(OwnECPoint p1, BigInteger k1, OwnECPoint p2, BigInteger k2) { if (k1 < 0) { p1 = Negative(p1); k1 = -k1; } if (k2 < 0) { p2 = Negative(p2); k2 = -k2; } BigInteger exp1 = k1 ^ (k1 * 3); BigInteger exp2 = k2 ^ (k2 * 3); BigInteger max = BigInteger.Max(exp1, exp2); int high = max <= 0 ? 0 : 1 + (int)Math.Ceiling(BigInteger.Log(max, 2)); JacobianECPoint x = new JacobianECPoint(p1.X, p1.Y, true); OwnECPoint cacheAdd = p1.Copy(); OwnECPoint cacheSub = p1.Copy(); Add(ref cacheAdd, p2); Subtract(ref cacheSub, p2); BigInteger bit = BigInteger.One << high; for (int i = high; --i >= 0; bit >>= 1) { GetDouble(ref x); if ((exp1 & bit) != 0 && (exp2 & bit) != 0) { int branch = ((k1 & bit) != 0 ? 0 : 1) + ((k2 & bit) != 0 ? 0 : 2); switch (branch) { case 0: Subtract(ref x, cacheAdd); break; case 1: Add(ref x, cacheSub); break; case 2: Subtract(ref x, cacheSub); break; case 3: Add(ref x, cacheAdd); break; } continue; } if ((exp1 & bit) != 0) { if ((k1 & bit) != 0) { Subtract(ref x, p1); } else { Add(ref x, p1); } continue; } if ((exp2 & bit) != 0) { if ((k2 & bit) != 0) { Subtract(ref x, p2); } else { Add(ref x, p2); } continue; } } OwnECPoint result = x.ToECPoint(this); return(result); }
public void Subtract(ref JacobianECPoint p, OwnECPoint q) { Add(ref p, q, true); }