public ProjectivePoint MontgomeryMul(ProjectivePoint point, ulong power, Curve curve) { if (power == 1) { return(point); } if (power == 2) { return(Double(point, curve)); } var binary = Convert.ToString((long)power, 2); var U = point; var T = Double(point, curve); for (int i = 1; i <= binary.Length - 1; i++) { if (binary[i] == '1') { U = Add(T, U, point, curve); T = Double(T, curve); } else { T = Add(U, T, point, curve); U = Double(U, curve); } } return(U); }
public ProjectivePoint Add(ProjectivePoint point1, ProjectivePoint point2, ProjectivePoint point3, Curve curve) { var T1 = (point1.X * point2.X - point1.Z * point2.Z) % curve.Mod; var T2 = (point1.X * point2.Z - point1.Z * point2.X) % curve.Mod; var newX = (point3.Z * T1 * T1); var newZ = (point3.X * T2 * T2); return(new ProjectivePoint(newX % curve.Mod, 0, newZ % curve.Mod)); }
public ProjectivePoint Double(ProjectivePoint point, Curve curve) { var XX = point.X * point.X; var ZZ = point.Z * point.Z; var XZ = point.X * point.Z; var newX = (XX - ZZ) % curve.Mod; newX = newX * newX; var tmp = (XX + curve.A * XZ + ZZ) % curve.Mod; var newZ = 4 * XZ * tmp; return(new ProjectivePoint(newX % curve.Mod, 0, newZ % curve.Mod)); }
public BigInteger Calculate(Curve curve, ulong b1, ulong b2, ulong b3) { var arithmetic = new MontgomeryArithmetic(); var sieve = new EratosthenesSieve(); var primeManager = new PrimeManager(); var point = curve.Point; ulong prime = 2; var mod = curve.Mod; BigInteger product = 1; while (prime < b1) { point = arithmetic.Double(point, curve); prime = prime * 2; product = (point.Z * product) % mod; } var gcd = BigInteger.GreatestCommonDivisor(product, mod); if (gcd > 1) { return(gcd); } ulong[] primes; ulong upPrimeLimit = 1000000; ulong lowPrimeLimit = 3; ulong sievestep = 10000000; if (b1 < upPrimeLimit) { upPrimeLimit = b1; } ulong partCount = b1 / sievestep; for (ulong j = 0; j <= partCount; j++) { primes = sieve.GetPrimes(lowPrimeLimit, upPrimeLimit); for (int i = 0; i < primes.Length; i++) { var p = primes[i]; prime = p; while (prime < b1) { point = arithmetic.MontgomeryMul(point, p, curve); prime = prime * p; product = (point.Z * product) % mod; } gcd = BigInteger.GreatestCommonDivisor(product, mod); if (gcd > 1) { return(gcd); } } lowPrimeLimit = upPrimeLimit; upPrimeLimit += sievestep; } if (b2 % 2 == 0) { b2--; } ulong precomputedDataSize = 1000; var precomputedData = new ProjectivePoint[precomputedDataSize]; precomputedData[0] = arithmetic.Double(point, curve); precomputedData[1] = arithmetic.Double(precomputedData[0], curve); for (ulong i = 2; i < precomputedDataSize; i++) { precomputedData[i] = arithmetic.Add(precomputedData[i - 1], precomputedData[0], precomputedData[i - 2], curve); } if (b2 <= 2 * precomputedDataSize) { b2 = precomputedDataSize + 2; } product = 1; var R = arithmetic.MontgomeryMul(point, b2, curve); var T = arithmetic.MontgomeryMul(point, b2 - 2 * precomputedDataSize, curve); primeManager.Init(b2 + 1); for (ulong i = b2; i < b3; i = i + 2 * precomputedDataSize) { for (ulong j = 0; j < precomputedDataSize; j++) { prime = primeManager.NextPrime(); var delta = (prime - i) / 2; if (delta >= (ulong)precomputedData.Length) { break; } product = (product * (R.X * precomputedData[delta - 1].Z - R.Z * precomputedData[delta - 1].X)) % curve.Mod; } gcd = BigInteger.GreatestCommonDivisor(curve.Mod, product); if (gcd > 1) { return(gcd); } var temp = T; T = R; R = arithmetic.Add(R, precomputedData[precomputedDataSize - 1], temp, curve); } return(1); }