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);
        }
示例#2
0
        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);
        }