private static int CompareBaseBits(int bitsPerDigit, long n) { //middle digit <= n * (base - 1) ^ 2 + [2^(128 - bitsPerDigit)] <= P - 1 ulong[] value = new ulong[1]; ulong[] square = new ulong[value.Length * 2]; ulong[] multiplier = new ulong[square.Length]; ulong[] result = new ulong[square.Length * 2]; ulong[] adder = new ulong[result.Length]; value[0] = (1UL << bitsPerDigit) - 1; multiplier[0] = (ulong)n; AsmX64Operations.Square(value, square, value.Length); AsmX64Operations.Multiply(square, multiplier, result, square.Length); if (128 - bitsPerDigit < 64) { adder[0] = 1UL << (128 - bitsPerDigit); } else { adder[1] = 1UL << (64 - bitsPerDigit); } AsmX64Operations.Add(result, adder, result, 0, result.Length); if (result[2] > 0 || result[3] > 0 || (result[0] >= FourierPoint.PrimeModulo.Low && result[1] == ulong.MaxValue)) { return(1); } if (result[0] == FourierPoint.PrimeModulo.Low - 1 && result[1] == ulong.MaxValue) { return(0); } return(-1); }
public static bool UnitTest() { Random random = new Random(101); int n = 2048 / 64; ulong[] a = new ulong[n]; ulong[] b = new ulong[n]; ulong[] m = new ulong[n]; ulong[] am1 = new ulong[n]; ulong[] am3 = new ulong[n]; ulong[] c1 = new ulong[n * 2]; ulong[] c2 = new ulong[n * 2]; ulong[] c3 = new ulong[n * 2]; ulong[] s0 = new ulong[n * 2]; ulong[] s1 = new ulong[n * 2]; ulong[] s2 = new ulong[n * 2]; BigInteger a0, b0, m0; TimeSpan elapsedMontgomeryExpMod = TimeSpan.Zero, elapsedExpMod = TimeSpan.Zero, elapsedBigIntegerExpMod = TimeSpan.Zero; bool ok = true; for (int iteration = 1; --iteration >= 0;) { getRandom(a, random); getRandom(b, random); getRandom(m, random); m[0] &= ulong.MaxValue - 1; a0 = new BigInteger(a.SelectMany(l => BitConverter.GetBytes(l)).Concat(Enumerable.Repeat((byte)0, 1)).ToArray()); b0 = new BigInteger(b.SelectMany(l => BitConverter.GetBytes(l)).Concat(Enumerable.Repeat((byte)0, 1)).ToArray()); m0 = new BigInteger(m.SelectMany(l => BitConverter.GetBytes(l)).Concat(Enumerable.Repeat((byte)0, 1)).ToArray()); a.CopyTo(am1, 0); ExpMod(am1, b, m, n, 5); BigInteger am2 = BigInteger.Zero; elapsedBigIntegerExpMod += MeasureTime(() => { am2 = BigInteger.ModPow(a0, b0, m0); }); var bytes1 = am1.SelectMany(l => BitConverter.GetBytes(l)).ToArray(); var bytes2 = am2.ToByteArray(); ok &= Enumerable.Range(0, Math.Min(bytes1.Length, bytes2.Length)).All(idx => bytes1[idx] == bytes2[idx]); } for (int iteration = 1; --iteration >= 0;) { getRandom(a, random); getRandom(b, random); getRandom(m, random); m[0] |= 1; a.CopyTo(am1, 0); a.CopyTo(am3, 0); elapsedMontgomeryExpMod += MeasureTime(() => { MontgomeryExpMod(am1, b, m, n, 6); }); elapsedExpMod += MeasureTime(() => { ExpMod(am3, b, m, n, 5); }); ok &= Enumerable.Range(0, n).All(idx => am3[idx] == am1[idx]); } TimeSpan elapsedMulDirect = TimeSpan.Zero, elapsedKaratsuba = TimeSpan.Zero; ulong[] temporaryKaratsubaBuffer = new ulong[GetKaratsubaMultiplicationBufferSize(n)]; for (int iteration = 128; --iteration >= 0;) { getRandom(a, random); getRandom(b, random); AsmX64Operations.Multiply(a, a, s0, n); elapsedMulDirect += MeasureTime(() => { AsmX64Operations.Multiply(a, b, c1, n); AsmX64Operations.Square(a, s1, n); }); elapsedKaratsuba += MeasureTime(() => { AsmX64Operations.Karatsuba(a, b, c2, n, temporaryKaratsubaBuffer); AsmX64Operations.KaratsubaSquare(a, s2, n, temporaryKaratsubaBuffer); }); ok &= Enumerable.Range(0, n * 2).All(idx => c1[idx] == c2[idx]); ok &= Enumerable.Range(0, n * 2).All(idx => s0[idx] == s1[idx]); ok &= Enumerable.Range(0, n * 2).All(idx => s1[idx] == s2[idx]); } if (!ok) { //MessageBox.Show("not ok - error"); return(false); } //MessageBox.Show( // "elapsedMontgomeryExpMod: " + elapsedMontgomeryExpMod.ToString() + "\r\n" + // "elapsedExpMod: " + elapsedExpMod.ToString() + "\r\n" + // "elapsedBigIntegerExpMod: " + elapsedBigIntegerExpMod.ToString() + "\r\n" + // "normal: " + elapsedMulDirect.ToString() + " karatsuba: " + elapsedKaratsuba.ToString()); return(true); }
public static bool UnitTestBigMul(int seed) { Random random = new Random(seed); byte[] data = new byte[16]; int length = 6 * 1024; //1024; ulong[] xx = new ulong[length]; ulong[] yy = new ulong[length]; ulong[] zz = new ulong[length * 2]; ulong[] tt = new ulong[length * 2]; ulong[] uu = new ulong[length * 2]; int tries = 1; ulong[] temporaryBuffer = new ulong[AsmX64Operations.GetKaratsubaMultiplicationBufferSize(xx.Length)]; TimeSpan directTime = TimeSpan.Zero; TimeSpan karatsubaTime = TimeSpan.Zero; TimeSpan fourierTime = TimeSpan.Zero; for (int step = tries; --step >= 0;) { for (int i = xx.Length; --i >= 0;) { random.NextBytes(data); xx[i] = BitConverter.ToUInt64(data, 0); yy[i] = BitConverter.ToUInt64(data, 8); } directTime += AsmX64Operations.MeasureTime(() => { AsmX64Operations.Multiply(xx, yy, zz, length); }); karatsubaTime += AsmX64Operations.MeasureTime(() => { AsmX64Operations.Karatsuba(xx, yy, tt, length); }); fourierTime += AsmX64Operations.MeasureTime(() => { AsmX64Operations.FastestMultiplication(xx, yy, uu, length); }); for (int i = length * 2; --i >= 0;) { if (zz[i] != tt[i] || tt[i] != uu[i]) { return(false); } } } int fftBitsPerDigit, fftLog2Size; GetFFTParameters(length, out fftBitsPerDigit, out fftLog2Size); double directOpsSecond = (1.0 * tries * length * length / directTime.TotalSeconds); double karaOpsSecond = tries * Math.Pow(length, LOG2_3) / karatsubaTime.TotalSeconds; double fftOpsSecond = tries * Math.Pow(2.0, fftLog2Size) * (3.0 * fftLog2Size + 4.0) / fourierTime.TotalSeconds; //MessageBox.Show( // "Direct: " + directTime.ToString() + " " + directOpsSecond.ToString("N3") + " ops/sec\r\n" + // "Karatsuba: " + karatsubaTime.ToString() + " " + (directOpsSecond / karaOpsSecond).ToString("N3") + " x constant\r\n" + // "Fourier: " + fourierTime.ToString() + " " + (directOpsSecond / fftOpsSecond).ToString("N3") + " x constant\r\n", "Timings"); return(true); }