diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2013-06-28 15:26:06 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2013-06-28 15:26:06 +0700 |
commit | 44288db4414158ac9b98a507b15e81d0d3c66ca6 (patch) | |
tree | aa5ef88948ebb68ed6c8df81eb5da889641a9b50 /crypto/test/src/math | |
parent | Set up text/binary handling for existing file types (diff) | |
download | BouncyCastle.NET-ed25519-44288db4414158ac9b98a507b15e81d0d3c66ca6.tar.xz |
Initial import of old CVS repository
Diffstat (limited to 'crypto/test/src/math')
-rw-r--r-- | crypto/test/src/math/ec/test/AllTests.cs | 27 | ||||
-rw-r--r-- | crypto/test/src/math/ec/test/ECPointPerformanceTest.cs | 73 | ||||
-rw-r--r-- | crypto/test/src/math/ec/test/ECPointTest.cs | 451 | ||||
-rw-r--r-- | crypto/test/src/math/ec/test/F2mProofer.cs | 201 | ||||
-rw-r--r-- | crypto/test/src/math/ec/test/TnafTest.cs | 158 | ||||
-rw-r--r-- | crypto/test/src/math/test/AllTests.cs | 27 | ||||
-rw-r--r-- | crypto/test/src/math/test/BigIntegerTest.cs | 1048 |
7 files changed, 1985 insertions, 0 deletions
diff --git a/crypto/test/src/math/ec/test/AllTests.cs b/crypto/test/src/math/ec/test/AllTests.cs new file mode 100644 index 000000000..f5d7d2249 --- /dev/null +++ b/crypto/test/src/math/ec/test/AllTests.cs @@ -0,0 +1,27 @@ +using System; + +using NUnit.Core; +using NUnit.Framework; + +namespace Org.BouncyCastle.Math.EC.Tests +{ + public class AllTests + { + public static void Main( + string[] args) + { +// junit.textui.TestRunner.run(suite()); + EventListener el = new NullListener(); + suite().Run(el); + } + + public static TestSuite suite() + { + TestSuite suite = new TestSuite("EC Math tests"); + + suite.Add(new ECPointTest()); + + return suite; + } + } +} diff --git a/crypto/test/src/math/ec/test/ECPointPerformanceTest.cs b/crypto/test/src/math/ec/test/ECPointPerformanceTest.cs new file mode 100644 index 000000000..e71ee653a --- /dev/null +++ b/crypto/test/src/math/ec/test/ECPointPerformanceTest.cs @@ -0,0 +1,73 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Math.EC.Tests +{ + /** + * Compares the performance of the the window NAF point multiplication against + * conventional point multiplication. + */ + [TestFixture, Explicit] + public class ECPointPerformanceTest + { + public const int NUM_ROUNDS = 100; + + private void randMult(string curveName) + { + X9ECParameters spec = SecNamedCurves.GetByName(curveName); + + BigInteger n = spec.N; + ECPoint g = (ECPoint) spec.G; + SecureRandom random = new SecureRandom(); //SecureRandom.getInstance("SHA1PRNG", "SUN"); + BigInteger k = new BigInteger(n.BitLength - 1, random); + + ECPoint qMultiply = null; + long startTime = DateTimeUtilities.CurrentUnixMs(); + for (int i = 0; i < NUM_ROUNDS; i++) + { + qMultiply = g.Multiply(k); + } + long endTime = DateTimeUtilities.CurrentUnixMs(); + + double avgDuration = (double) (endTime - startTime) / NUM_ROUNDS; + Console.WriteLine(curveName); + Console.Write("Millis : "); + Console.WriteLine(avgDuration); + Console.WriteLine(); + } + + [Test] + public void TestMultiply() + { + randMult("sect163k1"); + randMult("sect163r2"); + randMult("sect233k1"); + randMult("sect233r1"); + randMult("sect283k1"); + randMult("sect283r1"); + randMult("sect409k1"); + randMult("sect409r1"); + randMult("sect571k1"); + randMult("sect571r1"); + randMult("secp224k1"); + randMult("secp224r1"); + randMult("secp256k1"); + randMult("secp256r1"); + randMult("secp521r1"); + } + + // public static void Main(string argv[]) + // { + // ECMultiplyPerformanceTest test = new ECMultiplyPerformanceTest(); + // Test.testMultiply(); + // } + } +} diff --git a/crypto/test/src/math/ec/test/ECPointTest.cs b/crypto/test/src/math/ec/test/ECPointTest.cs new file mode 100644 index 000000000..4c8b2d8fc --- /dev/null +++ b/crypto/test/src/math/ec/test/ECPointTest.cs @@ -0,0 +1,451 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Math.EC.Tests +{ + /** + * Test class for {@link org.bouncycastle.math.ec.ECPoint ECPoint}. All + * literature values are taken from "Guide to elliptic curve cryptography", + * Darrel Hankerson, Alfred J. Menezes, Scott Vanstone, 2004, Springer-Verlag + * New York, Inc. + */ + [TestFixture] + public class ECPointTest + { + /** + * Random source used to generate random points + */ + private SecureRandom secRand = new SecureRandom(); + +// private ECPointTest.Fp fp = null; + +// private ECPointTest.F2m f2m = null; + + /** + * Nested class containing sample literature values for <code>Fp</code>. + */ + public class Fp + { + internal static readonly BigInteger q = new BigInteger("29"); + + internal static readonly BigInteger a = new BigInteger("4"); + + internal static readonly BigInteger b = new BigInteger("20"); + + internal static readonly FpCurve curve = new FpCurve(q, a, b); + + internal static readonly FpPoint infinity = (FpPoint) curve.Infinity; + + internal static readonly int[] pointSource = { 5, 22, 16, 27, 13, 6, 14, 6 }; + + internal static FpPoint[] p = new FpPoint[pointSource.Length / 2]; + + /** + * Creates the points on the curve with literature values. + */ + internal static void createPoints() + { + for (int i = 0; i < pointSource.Length / 2; i++) + { + FpFieldElement x = new FpFieldElement(q, new BigInteger( + pointSource[2 * i].ToString())); + FpFieldElement y = new FpFieldElement(q, new BigInteger( + pointSource[2 * i + 1].ToString())); + p[i] = new FpPoint(curve, x, y); + } + } + } + + /** + * Nested class containing sample literature values for <code>F2m</code>. + */ + public class F2m + { + // Irreducible polynomial for TPB z^4 + z + 1 + internal const int m = 4; + + internal const int k1 = 1; + + // a = z^3 + internal static readonly F2mFieldElement aTpb = new F2mFieldElement(m, k1, + new BigInteger("8", 16)); + + // b = z^3 + 1 + internal static readonly F2mFieldElement bTpb = new F2mFieldElement(m, k1, + new BigInteger("9", 16)); + + internal static readonly F2mCurve curve = new F2mCurve(m, k1, aTpb + .ToBigInteger(), bTpb.ToBigInteger()); + + internal static readonly F2mPoint infinity = (F2mPoint) curve.Infinity; + + internal static readonly string[] pointSource = { "2", "f", "c", "c", "1", "1", "b", "2" }; + + internal static F2mPoint[] p = new F2mPoint[pointSource.Length / 2]; + + /** + * Creates the points on the curve with literature values. + */ + internal static void createPoints() + { + for (int i = 0; i < pointSource.Length / 2; i++) + { + F2mFieldElement x = new F2mFieldElement(m, k1, + new BigInteger(pointSource[2 * i], 16)); + F2mFieldElement y = new F2mFieldElement(m, k1, + new BigInteger(pointSource[2 * i + 1], 16)); + p[i] = new F2mPoint(curve, x, y); + } + } + } + + [SetUp] + public void setUp() + { +// fp = new ECPointTest.Fp(); + Fp.createPoints(); + +// f2m = new ECPointTest.F2m(); + F2m.createPoints(); + } + + /** + * Tests, if inconsistent points can be created, i.e. points with exactly + * one null coordinate (not permitted). + */ + [Test] + public void TestPointCreationConsistency() + { + try + { + FpPoint bad = new FpPoint(Fp.curve, new FpFieldElement( + Fp.q, new BigInteger("12")), null); + Assert.Fail(); + } + catch (ArgumentException) + { + // Expected + } + + try + { + FpPoint bad = new FpPoint(Fp.curve, null, + new FpFieldElement(Fp.q, new BigInteger("12"))); + Assert.Fail(); + } + catch (ArgumentException) + { + // Expected + } + + try + { + F2mPoint bad = new F2mPoint(F2m.curve, new F2mFieldElement( + F2m.m, F2m.k1, new BigInteger("1011")), null); + Assert.Fail(); + } + catch (ArgumentException) + { + // Expected + } + + try + { + F2mPoint bad = new F2mPoint(F2m.curve, null, + new F2mFieldElement(F2m.m, F2m.k1, + new BigInteger("1011"))); + Assert.Fail(); + } + catch (ArgumentException) + { + // Expected + } + } + + /** + * Tests <code>ECPoint.add()</code> against literature values. + * + * @param p + * The array of literature values. + * @param infinity + * The point at infinity on the respective curve. + */ + private void implTestAdd(ECPoint[] p, ECPoint infinity) + { + Assert.AreEqual(p[2], p[0].Add(p[1]), "p0 plus p1 does not equal p2"); + Assert.AreEqual(p[2], p[1].Add(p[0]), "p1 plus p0 does not equal p2"); + for (int i = 0; i < p.Length; i++) + { + Assert.AreEqual(p[i], p[i].Add(infinity), "Adding infinity failed"); + Assert.AreEqual(p[i], infinity.Add(p[i]), "Adding to infinity failed"); + } + } + + /** + * Calls <code>implTestAdd()</code> for <code>Fp</code> and + * <code>F2m</code>. + */ + [Test] + public void TestAdd() + { + implTestAdd(Fp.p, Fp.infinity); + implTestAdd(F2m.p, F2m.infinity); + } + + /** + * Tests <code>ECPoint.twice()</code> against literature values. + * + * @param p + * The array of literature values. + */ + private void implTestTwice(ECPoint[] p) + { + Assert.AreEqual(p[3], p[0].Twice(), "Twice incorrect"); + Assert.AreEqual(p[3], p[0].Add(p[0]), "Add same point incorrect"); + } + + /** + * Calls <code>implTestTwice()</code> for <code>Fp</code> and + * <code>F2m</code>. + */ + [Test] + public void TestTwice() + { + implTestTwice(Fp.p); + implTestTwice(F2m.p); + } + + /** + * Goes through all points on an elliptic curve and checks, if adding a + * point <code>k</code>-times is the same as multiplying the point by + * <code>k</code>, for all <code>k</code>. Should be called for points + * on very small elliptic curves only. + * + * @param p + * The base point on the elliptic curve. + * @param infinity + * The point at infinity on the elliptic curve. + */ + private void implTestAllPoints(ECPoint p, ECPoint infinity) + { + ECPoint adder = infinity; + ECPoint multiplier = infinity; + int i = 1; + do + { + adder = adder.Add(p); + multiplier = p.Multiply(new BigInteger(i.ToString())); + Assert.AreEqual(adder, multiplier, + "Results of add() and multiply() are inconsistent " + i); + i++; + } + while (!(adder.Equals(infinity))); + } + + /** + * Calls <code>implTestAllPoints()</code> for the small literature curves, + * both for <code>Fp</code> and <code>F2m</code>. + */ + [Test] + public void TestAllPoints() + { + for (int i = 0; i < Fp.p.Length; i++) + { + implTestAllPoints(Fp.p[0], Fp.infinity); + } + + for (int i = 0; i < F2m.p.Length; i++) + { + implTestAllPoints(F2m.p[0], F2m.infinity); + } + } + + /** + * Simple shift-and-add multiplication. Serves as reference implementation + * to verify (possibly faster) implementations in + * {@link org.bouncycastle.math.ec.ECPoint ECPoint}. + * + * @param p + * The point to multiply. + * @param k + * The multiplier. + * @return The result of the point multiplication <code>kP</code>. + */ + private ECPoint multiply(ECPoint p, BigInteger k) + { + ECPoint q = p.Curve.Infinity; + int t = k.BitLength; + for (int i = 0; i < t; i++) + { + if (k.TestBit(i)) + { + q = q.Add(p); + } + p = p.Twice(); + } + return q; + } + + /** + * Checks, if the point multiplication algorithm of the given point yields + * the same result as point multiplication done by the reference + * implementation given in <code>multiply()</code>. This method chooses a + * random number by which the given point <code>p</code> is multiplied. + * + * @param p + * The point to be multiplied. + * @param numBits + * The bitlength of the random number by which <code>p</code> + * is multiplied. + */ + private void implTestMultiply(ECPoint p, int numBits) + { + BigInteger k = new BigInteger(numBits, secRand); + ECPoint reff = multiply(p, k); + ECPoint q = p.Multiply(k); + Assert.AreEqual(reff, q, "ECPoint.multiply is incorrect"); + } + + /** + * Checks, if the point multiplication algorithm of the given point yields + * the same result as point multiplication done by the reference + * implementation given in <code>multiply()</code>. This method tests + * multiplication of <code>p</code> by every number of bitlength + * <code>numBits</code> or less. + * + * @param p + * The point to be multiplied. + * @param numBits + * Try every multiplier up to this bitlength + */ + private void implTestMultiplyAll(ECPoint p, int numBits) + { + BigInteger bound = BigInteger.Two.Pow(numBits); + BigInteger k = BigInteger.Zero; + + do + { + ECPoint reff = multiply(p, k); + ECPoint q = p.Multiply(k); + Assert.AreEqual(reff, q, "ECPoint.multiply is incorrect"); + k = k.Add(BigInteger.One); + } + while (k.CompareTo(bound) < 0); + } + + /** + * Tests <code>ECPoint.add()</code> and <code>ECPoint.subtract()</code> + * for the given point and the given point at infinity. + * + * @param p + * The point on which the tests are performed. + * @param infinity + * The point at infinity on the same curve as <code>p</code>. + */ + private void implTestAddSubtract(ECPoint p, ECPoint infinity) + { + Assert.AreEqual(p.Twice(), p.Add(p), "Twice and Add inconsistent"); + Assert.AreEqual(p, p.Twice().Subtract(p), "Twice p - p is not p"); + Assert.AreEqual(infinity, p.Subtract(p), "p - p is not infinity"); + Assert.AreEqual(p, p.Add(infinity), "p plus infinity is not p"); + Assert.AreEqual(p, infinity.Add(p), "infinity plus p is not p"); + Assert.AreEqual(infinity, infinity.Add(infinity), "infinity plus infinity is not infinity "); + } + + /** + * Calls <code>implTestAddSubtract()</code> for literature values, both + * for <code>Fp</code> and <code>F2m</code>. + */ + [Test] + public void TestAddSubtractMultiplySimple() + { + for (int iFp = 0; iFp < Fp.pointSource.Length / 2; iFp++) + { + implTestAddSubtract(Fp.p[iFp], Fp.infinity); + + // Could be any numBits, 6 is chosen at will + implTestMultiplyAll(Fp.p[iFp], 6); + implTestMultiplyAll(Fp.infinity, 6); + } + + for (int iF2m = 0; iF2m < F2m.pointSource.Length / 2; iF2m++) + { + implTestAddSubtract(F2m.p[iF2m], F2m.infinity); + + // Could be any numBits, 6 is chosen at will + implTestMultiplyAll(F2m.p[iF2m], 6); + implTestMultiplyAll(F2m.infinity, 6); + } + } + + /** + * Test encoding with and without point compression. + * + * @param p + * The point to be encoded and decoded. + */ + private void implTestEncoding(ECPoint p) + { + // Not Point Compression + ECPoint unCompP; + + // Point compression + ECPoint compP; + + if (p is FpPoint) + { + unCompP = new FpPoint(p.Curve, p.X, p.Y, false); + compP = new FpPoint(p.Curve, p.X, p.Y, true); + } + else + { + unCompP = new F2mPoint(p.Curve, p.X, p.Y, false); + compP = new F2mPoint(p.Curve, p.X, p.Y, true); + } + + byte[] unCompBarr = unCompP.GetEncoded(); + ECPoint decUnComp = p.Curve.DecodePoint(unCompBarr); + Assert.AreEqual(p, decUnComp, "Error decoding uncompressed point"); + + byte[] compBarr = compP.GetEncoded(); + ECPoint decComp = p.Curve.DecodePoint(compBarr); + Assert.AreEqual(p, decComp, "Error decoding compressed point"); + } + + /** + * Calls <code>implTestAddSubtract()</code>, + * <code>implTestMultiply</code> and <code>implTestEncoding</code> for + * the standard elliptic curves as given in <code>SecNamedCurves</code>. + */ + [Test] + public void TestAddSubtractMultiplyTwiceEncoding() + { + foreach (string name in SecNamedCurves.Names) + { + X9ECParameters x9ECParameters = SecNamedCurves.GetByName(name); + + BigInteger n = x9ECParameters.N; + + // The generator is multiplied by random b to get random q + BigInteger b = new BigInteger(n.BitLength, secRand); + ECPoint g = x9ECParameters.G; + ECPoint q = g.Multiply(b); + + // Get point at infinity on the curve + ECPoint infinity = x9ECParameters.Curve.Infinity; + + implTestAddSubtract(q, infinity); + implTestMultiply(q, n.BitLength); + implTestMultiply(infinity, n.BitLength); + implTestEncoding(q); + } + } + } +} \ No newline at end of file diff --git a/crypto/test/src/math/ec/test/F2mProofer.cs b/crypto/test/src/math/ec/test/F2mProofer.cs new file mode 100644 index 000000000..88e868c34 --- /dev/null +++ b/crypto/test/src/math/ec/test/F2mProofer.cs @@ -0,0 +1,201 @@ +// TODO Need a replacement for the Java properties class to finish this class + +//using System; +//using System.IO; +//using System.Text; +// +//using Org.BouncyCastle.Asn1.Sec; +//using Org.BouncyCastle.Asn1.X9; +//using Org.BouncyCastle.Math.EC; +//using Org.BouncyCastle.Security; +// +//namespace Org.BouncyCastle.Math.EC.Tests +//{ +// public class F2mProofer +// { +// private const int NUM_SAMPLES = 1000; +// +// private static readonly string PATH = "crypto/test/src/org/bouncycastle/math/ec/test/samples/"; +// +// private static readonly string INPUT_FILE_NAME_PREFIX = "Input_"; +// +// private static readonly string RESULT_FILE_NAME_PREFIX = "Output_"; +// +// /** +// * The standard curves on which the tests are done +// */ +// public static readonly string[] Curves = { "sect163r2", "sect233r1", +// "sect283r1", "sect409r1", "sect571r1" }; +// +// private string pointToString(F2mPoint p) +// { +// F2mFieldElement x = (F2mFieldElement) p.X; +// F2mFieldElement y = (F2mFieldElement) p.Y; +// +// int m = x.M; +// int len = m / 2 + 5; +// +// StringBuilder sb = new StringBuilder(len); +// sb.Append('('); +// sb.Append(x.ToBigInteger().ToString(16)); +// sb.Append(", "); +// sb.Append(y.ToBigInteger().ToString(16)); +// sb.Append(')'); +// +// return sb.ToString(); +// } +// +// private void generateRandomInput(X9ECParameters x9ECParameters) +// { +// F2mPoint g = (F2mPoint) x9ECParameters.G; +// int m = ((F2mFieldElement) g.X).M; +// +// SecureRandom secRand = new SecureRandom(); //SecureRandom.GetInstance("SHA1PRNG"); +// Properties inputProps = new Properties(); +// for (int i = 0; i < NUM_SAMPLES; i++) +// { +// BigInteger rand = new BigInteger(m, secRand); +// inputProps.put(i.ToString(), rand.ToString(16)); +// } +// string bits = m.ToString(); +// FileStream fos = File.Create(PATH +// + INPUT_FILE_NAME_PREFIX + bits + ".properties"); +// inputProps.store(fos, "Input Samples of length" + bits); +// fos.Close(); +// } +// +// private void multiplyPoints(X9ECParameters x9ECParameters, +// string classPrefix) +// { +// F2mPoint g = (F2mPoint) x9ECParameters.G; +// int m = ((F2mFieldElement) g.X).M; +// +// string inputFileName = PATH + INPUT_FILE_NAME_PREFIX + m +// + ".properties"; +// Properties inputProps = new Properties(); +// FileStream fis = File.OpenRead(inputFileName); +// inputProps.load(fis); +// fis.Close(); +// +// Properties outputProps = new Properties(); +// +// for (int i = 0; i < NUM_SAMPLES; i++) +// { +// BigInteger rand = new BigInteger(inputProps.getProperty(Integer +// .ToString(i)), 16); +// F2mPoint result = (F2mPoint) g.Multiply(rand); +// string resultStr = pointToString(result); +// outputProps.setProperty(i.ToString(), resultStr); +// } +// +// string outputFileName = PATH + RESULT_FILE_NAME_PREFIX + classPrefix +// + "_" + m + ".properties"; +// FileStream fos = File.Create(outputFileName); +// outputProps.store(fos, "Output Samples of length" + m); +// fos.Close(); +// } +// +// private Properties loadResults(string classPrefix, int m) +// { +// FileStream fis = File.OpenRead(PATH +// + RESULT_FILE_NAME_PREFIX + classPrefix + "_" + m + ".properties"); +// Properties res = new Properties(); +// res.load(fis); +// fis.Close(); +// return res; +// } +// +// private void compareResult(X9ECParameters x9ECParameters, +// string classPrefix1, string classPrefix2) +// { +// F2mPoint g = (F2mPoint) x9ECParameters.G; +// int m = ((F2mFieldElement) g.X).M; +// +// Properties res1 = loadResults(classPrefix1, m); +// Properties res2 = loadResults(classPrefix2, m); +// +// Set keys = res1.keySet(); +// Iterator iter = keys.iterator(); +// while (iter.hasNext()) +// { +// string key = (string) iter.next(); +// string result1 = res1.getProperty(key); +// string result2 = res2.getProperty(key); +// if (!(result1.Equals(result2))) +// { +// Console.Error.WriteLine("Difference found: m = " + m + ", " +// + result1 + " does not equal " + result2); +// } +// } +// +// } +// +// private static void usage() +// { +// Console.Error.WriteLine("Usage: F2mProofer [-init | -Multiply <className> " +// + "| -compare <className1> <className2>]"); +// } +// +// public static void Main(string[] args) +// { +// if (args.Length == 0) +// { +// usage(); +// return; +// } +// F2mProofer proofer = new F2mProofer(); +// if (args[0].Equals("-init")) +// { +// Console.WriteLine("Generating random input..."); +// for (int i = 0; i < Curves.Length; i++) +// { +// X9ECParameters x9ECParameters = SecNamedCurves +// .GetByName(Curves[i]); +// proofer.generateRandomInput(x9ECParameters); +// } +// Console.WriteLine("Successfully generated random input in " + PATH); +// } +// else if (args[0].Equals("-compare")) +// { +// if (args.Length < 3) +// { +// usage(); +// return; +// } +// string classPrefix1 = args[1]; +// string classPrefix2 = args[2]; +// Console.WriteLine("Comparing results..."); +// for (int i = 0; i < Curves.Length; i++) +// { +// X9ECParameters x9ECParameters = SecNamedCurves +// .GetByName(Curves[i]); +// proofer.compareResult(x9ECParameters, classPrefix1, +// classPrefix2); +// } +// Console.WriteLine("Successfully compared results in " + PATH); +// } +// else if (args[0].Equals("-Multiply")) +// { +// if (args.Length < 2) +// { +// usage(); +// return; +// } +// string classPrefix = args[1]; +// Console.WriteLine("Multiplying points..."); +// for (int i = 0; i < Curves.Length; i++) +// { +// X9ECParameters x9ECParameters = SecNamedCurves +// .GetByName(Curves[i]); +// proofer.multiplyPoints(x9ECParameters, classPrefix); +// } +// Console.WriteLine("Successfully generated multiplied points in " +// + PATH); +// } +// else +// { +// usage(); +// } +// } +// } +//} diff --git a/crypto/test/src/math/ec/test/TnafTest.cs b/crypto/test/src/math/ec/test/TnafTest.cs new file mode 100644 index 000000000..c04ae00d2 --- /dev/null +++ b/crypto/test/src/math/ec/test/TnafTest.cs @@ -0,0 +1,158 @@ +//using System; +//using System.Text; +// +//using NUnit.Framework; +// +//using Org.BouncyCastle.Asn1.Sec; +//using Org.BouncyCastle.Asn1.X9; +//using Org.BouncyCastle.Math.EC.Multiplier; +//using Org.BouncyCastle.Utilities.Date; +// +//namespace Org.BouncyCastle.Math.EC.Tests +//{ +// [TestFixture, Explicit] +// public class TnafTest +// { +// private Random m_rand = new Random(); +// +// private string ecPointToString( +// ECPoint p) +// { +// StringBuilder sb = new StringBuilder("x = "); +// sb.Append(p.X.ToBigInteger().ToString()); +// sb.Append("; y = "); +// sb.Append(p.Y.ToBigInteger().ToString()); +// return sb.ToString(); +// } +// +// private ECPoint repeatedMultiply(ECPoint p, BigInteger k) +// { +// ECPoint result = p.Multiply(k); +// for (int i = 1; i < 10; ++i) +// { +// ECPoint check = p.Multiply(k); +// Assert.AreEqual(result, check); +// } +// return result; +// } +// +// private void ImplTestMultiplyTnaf(string curveName) +// { +// X9ECParameters x9ECParameters = SecNamedCurves.GetByName(curveName); +// +// F2mCurve curve = (F2mCurve)x9ECParameters.Curve; +// BigInteger n = curve.N; +// +// // The generator is multiplied by random b to get random q +// BigInteger b = new BigInteger(n.BitLength, m_rand); +// ECPoint g = x9ECParameters.G; +// F2mPoint p = (F2mPoint) g.Multiply(b); +// +// BigInteger k = new BigInteger(n.BitLength, m_rand); +// long now1 = DateTimeUtilities.CurrentUnixMs(); +// p.SetECMultiplier(new WTauNafMultiplier()); +// ECPoint refRWTnaf = repeatedMultiply(p, k); +// long now2 = DateTimeUtilities.CurrentUnixMs(); +// p.SetECMultiplier(new WNafMultiplier()); +// ECPoint refWnaf = repeatedMultiply(p, k); +// long now3 = DateTimeUtilities.CurrentUnixMs(); +// p.SetECMultiplier(new FpNafMultiplier()); +// ECPoint refFpNaf = repeatedMultiply(p, k); +// long now4 = DateTimeUtilities.CurrentUnixMs(); +// p.SetECMultiplier(new ReferenceMultiplier()); +// ECPoint reference = repeatedMultiply(p, k); +// long now5 = DateTimeUtilities.CurrentUnixMs(); +// +// Assert.AreEqual(reference, refRWTnaf, "WTNAF multiplication is incorrect"); +// Assert.AreEqual(reference, refFpNaf, "FPNAF multiplication is incorrect"); +// Assert.AreEqual(reference, refWnaf, "WNAF multiplication is incorrect"); +// +// Console.WriteLine(curveName + ": Multiply WTNAF took millis: " + (now2 - now1)); +// Console.WriteLine(curveName + ": Multiply WNAF took millis: " + (now3 - now2)); +// Console.WriteLine(curveName + ": Multiply FPNAF took millis: " + (now4 - now3)); +// Console.WriteLine(curveName + ": Multiply REFE took millis: " + (now5 - now4)); +// +//// Console.WriteLine(curveName + ": refRWTnaf = " + ecPointToString(refRWTnaf)); +//// Console.WriteLine(curveName + ": refWnaf = " + ecPointToString(refWnaf)); +//// Console.WriteLine(curveName + ": refFpNaf = " + ecPointToString(refFpNaf)); +//// Console.WriteLine(curveName + ": reference = " + ecPointToString(reference) + "\n"); +// Console.WriteLine(); +// } +// +// [Test] +// public void TestMultiplyTnaf() +// { +// Console.WriteLine("\n\n\n***** Start test multiplications on F2m (Koblitz) *****"); +// ImplTestMultiplyTnaf("sect163k1"); +// ImplTestMultiplyTnaf("sect233k1"); +// ImplTestMultiplyTnaf("sect239k1"); +// ImplTestMultiplyTnaf("sect283k1"); +// ImplTestMultiplyTnaf("sect409k1"); +// ImplTestMultiplyTnaf("sect571k1"); +// } +// +// private void ImplTestMultiplyWnaf(String curveName) +// { +// X9ECParameters x9ECParameters = SecNamedCurves.GetByName(curveName); +// +// BigInteger r = x9ECParameters.N; +// +// // The generator is multiplied by random b to get random q +// BigInteger b = new BigInteger(r.BitLength, m_rand); +// ECPoint g = x9ECParameters.G; +// ECPoint p = g.Multiply(b); +// +// BigInteger k = new BigInteger(r.BitLength, m_rand); +// long now1 = DateTimeUtilities.CurrentUnixMs(); +// p.SetECMultiplier(new WNafMultiplier()); +// ECPoint refWnaf = repeatedMultiply(p, k); +// long now2 = DateTimeUtilities.CurrentUnixMs(); +// p.SetECMultiplier(new FpNafMultiplier()); +// ECPoint refFpNaf = repeatedMultiply(p, k); +// long now3 = DateTimeUtilities.CurrentUnixMs(); +// p.SetECMultiplier(new ReferenceMultiplier()); +// ECPoint reference = repeatedMultiply(p, k); +// long now4 = DateTimeUtilities.CurrentUnixMs(); +// +// Assert.AreEqual(reference, refWnaf, "WNAF multiplication is incorrect"); +// Assert.AreEqual(reference, refFpNaf, "FPNAF multiplication is incorrect"); +// +// Console.WriteLine(curveName + ": Multiply WNAF took millis: " + (now2 - now1)); +// Console.WriteLine(curveName + ": Multiply FPNAF took millis: " + (now3 - now2)); +// Console.WriteLine(curveName + ": Multiply REFE took millis: " + (now4 - now3)); +// +//// Console.WriteLine(curveName + ": refWnaf = " + ecPointToString(refWnaf)); +//// Console.WriteLine(curveName + ": refFpNaf = " + ecPointToString(refFpNaf)); +//// Console.WriteLine(curveName + ": reference = " + ecPointToString(reference)); +// Console.WriteLine(); +// } +// +// [Test] +// public void TestMultiplyWnaf() +// { +// Console.WriteLine("\n\n\n***** Start test multiplications on F2m *****"); +// ImplTestMultiplyWnaf("sect113r1"); +// ImplTestMultiplyWnaf("sect113r2"); +// ImplTestMultiplyWnaf("sect131r1"); +// ImplTestMultiplyWnaf("sect131r2"); +// ImplTestMultiplyWnaf("sect163r1"); +// ImplTestMultiplyWnaf("sect163r2"); +// ImplTestMultiplyWnaf("sect193r1"); +// ImplTestMultiplyWnaf("sect193r2"); +// ImplTestMultiplyWnaf("sect233r1"); +// ImplTestMultiplyWnaf("sect283r1"); +// ImplTestMultiplyWnaf("sect409r1"); +// ImplTestMultiplyWnaf("sect571r1"); +// +// Console.WriteLine("\n\n\n***** Start test multiplications on Fp *****"); +// ImplTestMultiplyWnaf("secp112r1"); +// ImplTestMultiplyWnaf("secp128r1"); +// ImplTestMultiplyWnaf("secp160r1"); +// ImplTestMultiplyWnaf("secp192r1"); +// ImplTestMultiplyWnaf("secp224r1"); +// ImplTestMultiplyWnaf("secp256r1"); +// ImplTestMultiplyWnaf("secp384r1"); +// ImplTestMultiplyWnaf("secp521r1"); +// } +// } +//} diff --git a/crypto/test/src/math/test/AllTests.cs b/crypto/test/src/math/test/AllTests.cs new file mode 100644 index 000000000..6f2b50140 --- /dev/null +++ b/crypto/test/src/math/test/AllTests.cs @@ -0,0 +1,27 @@ +using System; + +using NUnit.Core; +using NUnit.Framework; + +namespace Org.BouncyCastle.Math.Tests +{ + public class AllTests + { + public static void Main( + string[] args) + { +// junit.textui.TestRunner.run(suite()); + EventListener el = new NullListener(); + suite().Run(el); + } + + public static TestSuite suite() + { + TestSuite suite = new TestSuite("Math tests"); + + suite.Add(new BigIntegerTest()); + + return suite; + } + } +} diff --git a/crypto/test/src/math/test/BigIntegerTest.cs b/crypto/test/src/math/test/BigIntegerTest.cs new file mode 100644 index 000000000..2f66a4b59 --- /dev/null +++ b/crypto/test/src/math/test/BigIntegerTest.cs @@ -0,0 +1,1048 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Math.Tests +{ + [TestFixture] + public class BigIntegerTest + { + private static Random random = new Random(); + + [Test] + public void MonoBug81857() + { + BigInteger b = new BigInteger("18446744073709551616"); + BigInteger exp = BigInteger.Two; + BigInteger mod = new BigInteger("48112959837082048697"); + BigInteger expected = new BigInteger("4970597831480284165"); + + BigInteger manual = b.Multiply(b).Mod(mod); + Assert.AreEqual(expected, manual, "b * b % mod"); + } + + [Test] + public void TestAbs() + { + Assert.AreEqual(zero, zero.Abs()); + + Assert.AreEqual(one, one.Abs()); + Assert.AreEqual(one, minusOne.Abs()); + + Assert.AreEqual(two, two.Abs()); + Assert.AreEqual(two, minusTwo.Abs()); + } + + [Test] + public void TestAdd() + { + for (int i = -10; i <= 10; ++i) + { + for (int j = -10; j <= 10; ++j) + { + Assert.AreEqual( + val(i + j), + val(i).Add(val(j)), + "Problem: " + i + ".Add(" + j + ") should be " + (i + j)); + } + } + } + + [Test] + public void TestAnd() + { + for (int i = -10; i <= 10; ++i) + { + for (int j = -10; j <= 10; ++j) + { + Assert.AreEqual( + val(i & j), + val(i).And(val(j)), + "Problem: " + i + " AND " + j + " should be " + (i & j)); + } + } + } + + [Test] + public void TestAndNot() + { + for (int i = -10; i <= 10; ++i) + { + for (int j = -10; j <= 10; ++j) + { + Assert.AreEqual( + val(i & ~j), + val(i).AndNot(val(j)), + "Problem: " + i + " AND NOT " + j + " should be " + (i & ~j)); + } + } + } + + [Test] + public void TestBitCount() + { + Assert.AreEqual(0, zero.BitCount); + Assert.AreEqual(1, one.BitCount); + Assert.AreEqual(0, minusOne.BitCount); + Assert.AreEqual(1, two.BitCount); + Assert.AreEqual(1, minusTwo.BitCount); + + for (int i = 0; i < 100; ++i) + { + BigInteger pow2 = one.ShiftLeft(i); + + Assert.AreEqual(1, pow2.BitCount); + Assert.AreEqual(i, pow2.Negate().BitCount); + } + + for (int i = 0; i < 10; ++i) + { + BigInteger test = new BigInteger(128, 0, random); + int bitCount = 0; + + for (int bit = 0; bit < test.BitLength; ++bit) + { + if (test.TestBit(bit)) + { + ++bitCount; + } + } + + Assert.AreEqual(bitCount, test.BitCount); + } + } + + [Test] + public void TestBitLength() + { + Assert.AreEqual(0, zero.BitLength); + Assert.AreEqual(1, one.BitLength); + Assert.AreEqual(0, minusOne.BitLength); + Assert.AreEqual(2, two.BitLength); + Assert.AreEqual(1, minusTwo.BitLength); + + for (int i = 0; i < 100; ++i) + { + int bit = i + random.Next(64); + BigInteger odd = new BigInteger(bit, random).SetBit(bit + 1).SetBit(0); + BigInteger pow2 = one.ShiftLeft(bit); + + Assert.AreEqual(bit + 2, odd.BitLength); + Assert.AreEqual(bit + 2, odd.Negate().BitLength); + Assert.AreEqual(bit + 1, pow2.BitLength); + Assert.AreEqual(bit, pow2.Negate().BitLength); + } + } + + [Test] + public void TestClearBit() + { + Assert.AreEqual(zero, zero.ClearBit(0)); + Assert.AreEqual(zero, one.ClearBit(0)); + Assert.AreEqual(two, two.ClearBit(0)); + + Assert.AreEqual(zero, zero.ClearBit(1)); + Assert.AreEqual(one, one.ClearBit(1)); + Assert.AreEqual(zero, two.ClearBit(1)); + + // TODO Tests for clearing bits in negative numbers + + // TODO Tests for clearing extended bits + + for (int i = 0; i < 10; ++i) + { + BigInteger n = new BigInteger(128, random); + + for (int j = 0; j < 10; ++j) + { + int pos = random.Next(128); + BigInteger m = n.ClearBit(pos); + bool test = m.ShiftRight(pos).Remainder(two).Equals(one); + + Assert.IsFalse(test); + } + } + + for (int i = 0; i < 100; ++i) + { + BigInteger pow2 = one.ShiftLeft(i); + BigInteger minusPow2 = pow2.Negate(); + + Assert.AreEqual(zero, pow2.ClearBit(i)); + Assert.AreEqual(minusPow2.ShiftLeft(1), minusPow2.ClearBit(i)); + + BigInteger bigI = BigInteger.ValueOf(i); + BigInteger negI = bigI.Negate(); + + for (int j = 0; j < 10; ++j) + { + string data = "i=" + i + ", j=" + j; + Assert.AreEqual(bigI.AndNot(one.ShiftLeft(j)), bigI.ClearBit(j), data); + Assert.AreEqual(negI.AndNot(one.ShiftLeft(j)), negI.ClearBit(j), data); + } + } + } + + [Test] + public void TestCompareTo() + { + Assert.AreEqual(0, minusTwo.CompareTo(minusTwo)); + Assert.AreEqual(-1, minusTwo.CompareTo(minusOne)); + Assert.AreEqual(-1, minusTwo.CompareTo(zero)); + Assert.AreEqual(-1, minusTwo.CompareTo(one)); + Assert.AreEqual(-1, minusTwo.CompareTo(two)); + + Assert.AreEqual(1, minusOne.CompareTo(minusTwo)); + Assert.AreEqual(0, minusOne.CompareTo(minusOne)); + Assert.AreEqual(-1, minusOne.CompareTo(zero)); + Assert.AreEqual(-1, minusOne.CompareTo(one)); + Assert.AreEqual(-1, minusOne.CompareTo(two)); + + Assert.AreEqual(1, zero.CompareTo(minusTwo)); + Assert.AreEqual(1, zero.CompareTo(minusOne)); + Assert.AreEqual(0, zero.CompareTo(zero)); + Assert.AreEqual(-1, zero.CompareTo(one)); + Assert.AreEqual(-1, zero.CompareTo(two)); + + Assert.AreEqual(1, one.CompareTo(minusTwo)); + Assert.AreEqual(1, one.CompareTo(minusOne)); + Assert.AreEqual(1, one.CompareTo(zero)); + Assert.AreEqual(0, one.CompareTo(one)); + Assert.AreEqual(-1, one.CompareTo(two)); + + Assert.AreEqual(1, two.CompareTo(minusTwo)); + Assert.AreEqual(1, two.CompareTo(minusOne)); + Assert.AreEqual(1, two.CompareTo(zero)); + Assert.AreEqual(1, two.CompareTo(one)); + Assert.AreEqual(0, two.CompareTo(two)); + } + + [Test] + public void TestConstructors() + { + Assert.AreEqual(BigInteger.Zero, new BigInteger(new byte[]{ 0 })); + Assert.AreEqual(BigInteger.Zero, new BigInteger(new byte[]{ 0, 0 })); + + for (int i = 0; i < 10; ++i) + { + Assert.IsTrue(new BigInteger(i + 3, 0, random).TestBit(0)); + } + + // TODO Other constructors + } + + [Test] + public void TestDivide() + { + for (int i = -5; i <= 5; ++i) + { + try + { + val(i).Divide(zero); + Assert.Fail("expected ArithmeticException"); + } + catch (ArithmeticException) {} + } + + int product = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9; + int productPlus = product + 1; + + BigInteger bigProduct = val(product); + BigInteger bigProductPlus = val(productPlus); + + for (int divisor = 1; divisor < 10; ++divisor) + { + // Exact division + BigInteger expected = val(product / divisor); + + Assert.AreEqual(expected, bigProduct.Divide(val(divisor))); + Assert.AreEqual(expected.Negate(), bigProduct.Negate().Divide(val(divisor))); + Assert.AreEqual(expected.Negate(), bigProduct.Divide(val(divisor).Negate())); + Assert.AreEqual(expected, bigProduct.Negate().Divide(val(divisor).Negate())); + + expected = val((product + 1)/divisor); + + Assert.AreEqual(expected, bigProductPlus.Divide(val(divisor))); + Assert.AreEqual(expected.Negate(), bigProductPlus.Negate().Divide(val(divisor))); + Assert.AreEqual(expected.Negate(), bigProductPlus.Divide(val(divisor).Negate())); + Assert.AreEqual(expected, bigProductPlus.Negate().Divide(val(divisor).Negate())); + } + + for (int rep = 0; rep < 10; ++rep) + { + BigInteger a = new BigInteger(100 - rep, 0, random); + BigInteger b = new BigInteger(100 + rep, 0, random); + BigInteger c = new BigInteger(10 + rep, 0, random); + BigInteger d = a.Multiply(b).Add(c); + BigInteger e = d.Divide(a); + + Assert.AreEqual(b, e); + } + + // Special tests for power of two since uses different code path internally + for (int i = 0; i < 100; ++i) + { + int shift = random.Next(64); + BigInteger a = one.ShiftLeft(shift); + BigInteger b = new BigInteger(64 + random.Next(64), random); + BigInteger bShift = b.ShiftRight(shift); + + string data = "shift=" + shift +", b=" + b.ToString(16); + + Assert.AreEqual(bShift, b.Divide(a), data); + Assert.AreEqual(bShift.Negate(), b.Divide(a.Negate()), data); + Assert.AreEqual(bShift.Negate(), b.Negate().Divide(a), data); + Assert.AreEqual(bShift, b.Negate().Divide(a.Negate()), data); + } + + // Regression + { + int shift = 63; + BigInteger a = one.ShiftLeft(shift); + BigInteger b = new BigInteger(1, Hex.Decode("2504b470dc188499")); + BigInteger bShift = b.ShiftRight(shift); + + string data = "shift=" + shift +", b=" + b.ToString(16); + + Assert.AreEqual(bShift, b.Divide(a), data); + Assert.AreEqual(bShift.Negate(), b.Divide(a.Negate()), data); +// Assert.AreEqual(bShift.Negate(), b.Negate().Divide(a), data); + Assert.AreEqual(bShift, b.Negate().Divide(a.Negate()), data); + } + } + + [Test] + public void TestDivideAndRemainder() + { + // TODO More basic tests + + BigInteger n = new BigInteger(48, random); + BigInteger[] qr = n.DivideAndRemainder(n); + Assert.AreEqual(one, qr[0]); + Assert.AreEqual(zero, qr[1]); + qr = n.DivideAndRemainder(one); + Assert.AreEqual(n, qr[0]); + Assert.AreEqual(zero, qr[1]); + + for (int rep = 0; rep < 10; ++rep) + { + BigInteger a = new BigInteger(100 - rep, 0, random); + BigInteger b = new BigInteger(100 + rep, 0, random); + BigInteger c = new BigInteger(10 + rep, 0, random); + BigInteger d = a.Multiply(b).Add(c); + BigInteger[] es = d.DivideAndRemainder(a); + + Assert.AreEqual(b, es[0]); + Assert.AreEqual(c, es[1]); + } + + // Special tests for power of two since uses different code path internally + for (int i = 0; i < 100; ++i) + { + int shift = random.Next(64); + BigInteger a = one.ShiftLeft(shift); + BigInteger b = new BigInteger(64 + random.Next(64), random); + BigInteger bShift = b.ShiftRight(shift); + BigInteger bMod = b.And(a.Subtract(one)); + + string data = "shift=" + shift +", b=" + b.ToString(16); + + qr = b.DivideAndRemainder(a); + Assert.AreEqual(bShift, qr[0], data); + Assert.AreEqual(bMod, qr[1], data); + + qr = b.DivideAndRemainder(a.Negate()); + Assert.AreEqual(bShift.Negate(), qr[0], data); + Assert.AreEqual(bMod, qr[1], data); + + qr = b.Negate().DivideAndRemainder(a); + Assert.AreEqual(bShift.Negate(), qr[0], data); + Assert.AreEqual(bMod.Negate(), qr[1], data); + + qr = b.Negate().DivideAndRemainder(a.Negate()); + Assert.AreEqual(bShift, qr[0], data); + Assert.AreEqual(bMod.Negate(), qr[1], data); + } + } + + [Test] + public void TestFlipBit() + { + for (int i = 0; i < 10; ++i) + { + BigInteger a = new BigInteger(128, 0, random); + BigInteger b = a; + + for (int x = 0; x < 100; ++x) + { + // Note: Intentionally greater than initial size + int pos = random.Next(256); + + a = a.FlipBit(pos); + b = b.TestBit(pos) ? b.ClearBit(pos) : b.SetBit(pos); + } + + Assert.AreEqual(a, b); + } + + for (int i = 0; i < 100; ++i) + { + BigInteger pow2 = one.ShiftLeft(i); + BigInteger minusPow2 = pow2.Negate(); + + Assert.AreEqual(zero, pow2.FlipBit(i)); + Assert.AreEqual(minusPow2.ShiftLeft(1), minusPow2.FlipBit(i)); + + BigInteger bigI = BigInteger.ValueOf(i); + BigInteger negI = bigI.Negate(); + + for (int j = 0; j < 10; ++j) + { + string data = "i=" + i + ", j=" + j; + Assert.AreEqual(bigI.Xor(one.ShiftLeft(j)), bigI.FlipBit(j), data); + Assert.AreEqual(negI.Xor(one.ShiftLeft(j)), negI.FlipBit(j), data); + } + } + } + + [Test] + public void TestGcd() + { + for (int i = 0; i < 10; ++i) + { + BigInteger fac = new BigInteger(32, random).Add(two); + BigInteger p1 = BigInteger.ProbablePrime(63, random); + BigInteger p2 = BigInteger.ProbablePrime(64, random); + + BigInteger gcd = fac.Multiply(p1).Gcd(fac.Multiply(p2)); + + Assert.AreEqual(fac, gcd); + } + } + + [Test] + public void TestGetLowestSetBit() + { + for (int i = 1; i <= 100; ++i) + { + BigInteger test = new BigInteger(i + 1, 0, random).Add(one); + int bit1 = test.GetLowestSetBit(); + Assert.AreEqual(test, test.ShiftRight(bit1).ShiftLeft(bit1)); + int bit2 = test.ShiftLeft(i + 1).GetLowestSetBit(); + Assert.AreEqual(i + 1, bit2 - bit1); + int bit3 = test.ShiftLeft(3 * i).GetLowestSetBit(); + Assert.AreEqual(3 * i, bit3 - bit1); + } + } + + [Test] + public void TestIntValue() + { + int[] tests = new int[]{ int.MinValue, -1234, -10, -1, 0, ~0, 1, 10, 5678, int.MaxValue }; + + foreach (int test in tests) + { + Assert.AreEqual(test, val(test).IntValue); + } + + // TODO Tests for large numbers + } + + [Test] + public void TestIsProbablePrime() + { + Assert.IsFalse(zero.IsProbablePrime(100)); + Assert.IsFalse(zero.IsProbablePrime(100)); + Assert.IsTrue(zero.IsProbablePrime(0)); + Assert.IsTrue(zero.IsProbablePrime(-10)); + Assert.IsFalse(minusOne.IsProbablePrime(100)); + Assert.IsTrue(minusTwo.IsProbablePrime(100)); + Assert.IsTrue(val(-17).IsProbablePrime(100)); + Assert.IsTrue(val(67).IsProbablePrime(100)); + Assert.IsTrue(val(773).IsProbablePrime(100)); + + foreach (int p in firstPrimes) + { + Assert.IsTrue(val(p).IsProbablePrime(100)); + Assert.IsTrue(val(-p).IsProbablePrime(100)); + } + + foreach (int c in nonPrimes) + { + Assert.IsFalse(val(c).IsProbablePrime(100)); + Assert.IsFalse(val(-c).IsProbablePrime(100)); + } + + foreach (int e in mersennePrimeExponents) + { + Assert.IsTrue(mersenne(e).IsProbablePrime(100)); + Assert.IsTrue(mersenne(e).Negate().IsProbablePrime(100)); + } + + foreach (int e in nonPrimeExponents) + { + Assert.IsFalse(mersenne(e).IsProbablePrime(100)); + Assert.IsFalse(mersenne(e).Negate().IsProbablePrime(100)); + } + + // TODO Other examples of 'tricky' values? + } + + [Test] + public void TestLongValue() + { + long[] tests = new long[]{ long.MinValue, -1234, -10, -1, 0L, ~0L, 1, 10, 5678, long.MaxValue }; + + foreach (long test in tests) + { + Assert.AreEqual(test, val(test).LongValue); + } + + // TODO Tests for large numbers + } + + [Test] + public void TestMax() + { + for (int i = -10; i <= 10; ++i) + { + for (int j = -10; j <= 10; ++j) + { + Assert.AreEqual(val(System.Math.Max(i, j)), val(i).Max(val(j))); + } + } + } + + [Test] + public void TestMin() + { + for (int i = -10; i <= 10; ++i) + { + for (int j = -10; j <= 10; ++j) + { + Assert.AreEqual(val(System.Math.Min(i, j)), val(i).Min(val(j))); + } + } + } + + [Test] + public void TestMod() + { + // TODO Basic tests + + for (int rep = 0; rep < 100; ++rep) + { + int diff = random.Next(25); + BigInteger a = new BigInteger(100 - diff, 0, random); + BigInteger b = new BigInteger(100 + diff, 0, random); + BigInteger c = new BigInteger(10 + diff, 0, random); + + BigInteger d = a.Multiply(b).Add(c); + BigInteger e = d.Mod(a); + Assert.AreEqual(c, e); + + BigInteger pow2 = one.ShiftLeft(random.Next(128)); + Assert.AreEqual(b.And(pow2.Subtract(one)), b.Mod(pow2)); + } + } + + [Test] + public void TestModInverse() + { + for (int i = 0; i < 10; ++i) + { + BigInteger p = BigInteger.ProbablePrime(64, random); + BigInteger q = new BigInteger(63, random).Add(one); + BigInteger inv = q.ModInverse(p); + BigInteger inv2 = inv.ModInverse(p); + + Assert.AreEqual(q, inv2); + Assert.AreEqual(one, q.Multiply(inv).Mod(p)); + } + + // ModInverse a power of 2 for a range of powers + for (int i = 1; i <= 128; ++i) + { + BigInteger m = one.ShiftLeft(i); + BigInteger d = new BigInteger(i, random).SetBit(0); + BigInteger x = d.ModInverse(m); + BigInteger check = x.Multiply(d).Mod(m); + + Assert.AreEqual(one, check); + } + } + + [Test] + public void TestModPow() + { + try + { + two.ModPow(one, zero); + Assert.Fail("expected ArithmeticException"); + } + catch (ArithmeticException) {} + + Assert.AreEqual(zero, zero.ModPow(zero, one)); + Assert.AreEqual(one, zero.ModPow(zero, two)); + Assert.AreEqual(zero, two.ModPow(one, one)); + Assert.AreEqual(one, two.ModPow(zero, two)); + + for (int i = 0; i < 100; ++i) + { + BigInteger m = BigInteger.ProbablePrime(10 + i, random); + BigInteger x = new BigInteger(m.BitLength - 1, random); + + Assert.AreEqual(x, x.ModPow(m, m)); + if (x.SignValue != 0) + { + Assert.AreEqual(zero, zero.ModPow(x, m)); + Assert.AreEqual(one, x.ModPow(m.Subtract(one), m)); + } + + BigInteger y = new BigInteger(m.BitLength - 1, random); + BigInteger n = new BigInteger(m.BitLength - 1, random); + BigInteger n3 = n.ModPow(three, m); + + BigInteger resX = n.ModPow(x, m); + BigInteger resY = n.ModPow(y, m); + BigInteger res = resX.Multiply(resY).Mod(m); + BigInteger res3 = res.ModPow(three, m); + + Assert.AreEqual(res3, n3.ModPow(x.Add(y), m)); + + BigInteger a = x.Add(one); // Make sure it's not zero + BigInteger b = y.Add(one); // Make sure it's not zero + + Assert.AreEqual(a.ModPow(b, m).ModInverse(m), a.ModPow(b.Negate(), m)); + } + } + + [Test] + public void TestMultiply() + { + BigInteger one = BigInteger.One; + + Assert.AreEqual(one, one.Negate().Multiply(one.Negate())); + + for (int i = 0; i < 100; ++i) + { + int aLen = 64 + random.Next(64); + int bLen = 64 + random.Next(64); + + BigInteger a = new BigInteger(aLen, random).SetBit(aLen); + BigInteger b = new BigInteger(bLen, random).SetBit(bLen); + BigInteger c = new BigInteger(32, random); + + BigInteger ab = a.Multiply(b); + BigInteger bc = b.Multiply(c); + + Assert.AreEqual(ab.Add(bc), a.Add(c).Multiply(b)); + Assert.AreEqual(ab.Subtract(bc), a.Subtract(c).Multiply(b)); + } + + // Special tests for power of two since uses different code path internally + for (int i = 0; i < 100; ++i) + { + int shift = random.Next(64); + BigInteger a = one.ShiftLeft(shift); + BigInteger b = new BigInteger(64 + random.Next(64), random); + BigInteger bShift = b.ShiftLeft(shift); + + Assert.AreEqual(bShift, a.Multiply(b)); + Assert.AreEqual(bShift.Negate(), a.Multiply(b.Negate())); + Assert.AreEqual(bShift.Negate(), a.Negate().Multiply(b)); + Assert.AreEqual(bShift, a.Negate().Multiply(b.Negate())); + + Assert.AreEqual(bShift, b.Multiply(a)); + Assert.AreEqual(bShift.Negate(), b.Multiply(a.Negate())); + Assert.AreEqual(bShift.Negate(), b.Negate().Multiply(a)); + Assert.AreEqual(bShift, b.Negate().Multiply(a.Negate())); + } + } + + [Test] + public void TestNegate() + { + for (int i = -10; i <= 10; ++i) + { + Assert.AreEqual(val(-i), val(i).Negate()); + } + } + + [Test] + public void TestNextProbablePrime() + { + BigInteger firstPrime = BigInteger.ProbablePrime(32, random); + BigInteger nextPrime = firstPrime.NextProbablePrime(); + + Assert.IsTrue(firstPrime.IsProbablePrime(10)); + Assert.IsTrue(nextPrime.IsProbablePrime(10)); + + BigInteger check = firstPrime.Add(one); + + while (check.CompareTo(nextPrime) < 0) + { + Assert.IsFalse(check.IsProbablePrime(10)); + check = check.Add(one); + } + } + + [Test] + public void TestNot() + { + for (int i = -10; i <= 10; ++i) + { + Assert.AreEqual( + val(~i), + val(i).Not(), + "Problem: ~" + i + " should be " + ~i); + } + } + + [Test] + public void TestOr() + { + for (int i = -10; i <= 10; ++i) + { + for (int j = -10; j <= 10; ++j) + { + Assert.AreEqual( + val(i | j), + val(i).Or(val(j)), + "Problem: " + i + " OR " + j + " should be " + (i | j)); + } + } + } + + [Test] + public void TestPow() + { + Assert.AreEqual(one, zero.Pow(0)); + Assert.AreEqual(zero, zero.Pow(123)); + Assert.AreEqual(one, one.Pow(0)); + Assert.AreEqual(one, one.Pow(123)); + + Assert.AreEqual(two.Pow(147), one.ShiftLeft(147)); + Assert.AreEqual(one.ShiftLeft(7).Pow(11), one.ShiftLeft(77)); + + BigInteger n = new BigInteger("1234567890987654321"); + BigInteger result = one; + + for (int i = 0; i < 10; ++i) + { + try + { + val(i).Pow(-1); + Assert.Fail("expected ArithmeticException"); + } + catch (ArithmeticException) {} + + Assert.AreEqual(result, n.Pow(i)); + + result = result.Multiply(n); + } + } + + [Test] + public void TestRemainder() + { + // TODO Basic tests + + for (int rep = 0; rep < 10; ++rep) + { + BigInteger a = new BigInteger(100 - rep, 0, random); + BigInteger b = new BigInteger(100 + rep, 0, random); + BigInteger c = new BigInteger(10 + rep, 0, random); + BigInteger d = a.Multiply(b).Add(c); + BigInteger e = d.Remainder(a); + + Assert.AreEqual(c, e); + } + } + + [Test] + public void TestSetBit() + { + Assert.AreEqual(one, zero.SetBit(0)); + Assert.AreEqual(one, one.SetBit(0)); + Assert.AreEqual(three, two.SetBit(0)); + + Assert.AreEqual(two, zero.SetBit(1)); + Assert.AreEqual(three, one.SetBit(1)); + Assert.AreEqual(two, two.SetBit(1)); + + // TODO Tests for setting bits in negative numbers + + // TODO Tests for setting extended bits + + for (int i = 0; i < 10; ++i) + { + BigInteger n = new BigInteger(128, random); + + for (int j = 0; j < 10; ++j) + { + int pos = random.Next(128); + BigInteger m = n.SetBit(pos); + bool test = m.ShiftRight(pos).Remainder(two).Equals(one); + + Assert.IsTrue(test); + } + } + + for (int i = 0; i < 100; ++i) + { + BigInteger pow2 = one.ShiftLeft(i); + BigInteger minusPow2 = pow2.Negate(); + + Assert.AreEqual(pow2, pow2.SetBit(i)); + Assert.AreEqual(minusPow2, minusPow2.SetBit(i)); + + BigInteger bigI = BigInteger.ValueOf(i); + BigInteger negI = bigI.Negate(); + + for (int j = 0; j < 10; ++j) + { + string data = "i=" + i + ", j=" + j; + Assert.AreEqual(bigI.Or(one.ShiftLeft(j)), bigI.SetBit(j), data); + Assert.AreEqual(negI.Or(one.ShiftLeft(j)), negI.SetBit(j), data); + } + } + } + + [Test] + public void TestShiftLeft() + { + for (int i = 0; i < 100; ++i) + { + int shift = random.Next(128); + + BigInteger a = new BigInteger(128 + i, random).Add(one); + int bits = a.BitCount; // Make sure nBits is set + + BigInteger negA = a.Negate(); + bits = negA.BitCount; // Make sure nBits is set + + BigInteger b = a.ShiftLeft(shift); + BigInteger c = negA.ShiftLeft(shift); + + Assert.AreEqual(a.BitCount, b.BitCount); + Assert.AreEqual(negA.BitCount + shift, c.BitCount); + Assert.AreEqual(a.BitLength + shift, b.BitLength); + Assert.AreEqual(negA.BitLength + shift, c.BitLength); + + int j = 0; + for (; j < shift; ++j) + { + Assert.IsFalse(b.TestBit(j)); + } + + for (; j < b.BitLength; ++j) + { + Assert.AreEqual(a.TestBit(j - shift), b.TestBit(j)); + } + } + } + + [Test] + public void TestShiftRight() + { + for (int i = 0; i < 10; ++i) + { + int shift = random.Next(128); + BigInteger a = new BigInteger(256 + i, random).SetBit(256 + i); + BigInteger b = a.ShiftRight(shift); + + Assert.AreEqual(a.BitLength - shift, b.BitLength); + + for (int j = 0; j < b.BitLength; ++j) + { + Assert.AreEqual(a.TestBit(j + shift), b.TestBit(j)); + } + } + } + + [Test] + public void TestSignValue() + { + for (int i = -10; i <= 10; ++i) + { + Assert.AreEqual(i < 0 ? -1 : i > 0 ? 1 : 0, val(i).SignValue); + } + } + + [Test] + public void TestSubtract() + { + for (int i = -10; i <= 10; ++i) + { + for (int j = -10; j <= 10; ++j) + { + Assert.AreEqual( + val(i - j), + val(i).Subtract(val(j)), + "Problem: " + i + ".Subtract(" + j + ") should be " + (i - j)); + } + } + } + + [Test] + public void TestTestBit() + { + for (int i = 0; i < 10; ++i) + { + BigInteger n = new BigInteger(128, random); + + Assert.IsFalse(n.TestBit(128)); + Assert.IsTrue(n.Negate().TestBit(128)); + + for (int j = 0; j < 10; ++j) + { + int pos = random.Next(128); + bool test = n.ShiftRight(pos).Remainder(two).Equals(one); + + Assert.AreEqual(test, n.TestBit(pos)); + } + } + } + + [Test] + public void TestToByteArray() + { + byte[] z = BigInteger.Zero.ToByteArray(); + Assert.IsTrue(Arrays.AreEqual(new byte[1], z)); + + for (int i = 16; i <= 48; ++i) + { + BigInteger x = BigInteger.ProbablePrime(i, random); + byte[] b = x.ToByteArray(); + Assert.AreEqual((i / 8 + 1), b.Length); + BigInteger y = new BigInteger(b); + Assert.AreEqual(x, y); + + x = x.Negate(); + b = x.ToByteArray(); + Assert.AreEqual((i / 8 + 1), b.Length); + y = new BigInteger(b); + Assert.AreEqual(x, y); + } + } + + [Test] + public void TestToByteArrayUnsigned() + { + byte[] z = BigInteger.Zero.ToByteArrayUnsigned(); + Assert.IsTrue(Arrays.AreEqual(new byte[0], z)); + + for (int i = 16; i <= 48; ++i) + { + BigInteger x = BigInteger.ProbablePrime(i, random); + byte[] b = x.ToByteArrayUnsigned(); + Assert.AreEqual((i + 7) / 8, b.Length); + BigInteger y = new BigInteger(1, b); + Assert.AreEqual(x, y); + + x = x.Negate(); + b = x.ToByteArrayUnsigned(); + Assert.AreEqual(i / 8 + 1, b.Length); + y = new BigInteger(b); + Assert.AreEqual(x, y); + } + } + + [Test] + public void TestToString() + { + string s = "12345667890987654321"; + + Assert.AreEqual(s, new BigInteger(s).ToString()); + Assert.AreEqual(s, new BigInteger(s, 10).ToString(10)); + Assert.AreEqual(s, new BigInteger(s, 16).ToString(16)); + + for (int i = 0; i < 100; ++i) + { + BigInteger n = new BigInteger(i, random); + + Assert.AreEqual(n, new BigInteger(n.ToString(2), 2)); + Assert.AreEqual(n, new BigInteger(n.ToString(10), 10)); + Assert.AreEqual(n, new BigInteger(n.ToString(16), 16)); + } + + // Radix version + int[] radices = new int[] { 2, 8, 10, 16 }; + int trials = 256; + + BigInteger[] tests = new BigInteger[trials]; + for (int i = 0; i < trials; ++i) + { + int len = random.Next(i + 1); + tests[i] = new BigInteger(len, random); + } + + foreach (int radix in radices) + { + for (int i = 0; i < trials; ++i) + { + BigInteger n1 = tests[i]; + string str = n1.ToString(radix); + BigInteger n2 = new BigInteger(str, radix); + Assert.AreEqual(n1, n2); + } + } + } + + [Test] + public void TestValueOf() + { + Assert.AreEqual(-1, BigInteger.ValueOf(-1).SignValue); + Assert.AreEqual(0, BigInteger.ValueOf(0).SignValue); + Assert.AreEqual(1, BigInteger.ValueOf(1).SignValue); + + for (long i = -5; i < 5; ++i) + { + Assert.AreEqual(i, BigInteger.ValueOf(i).IntValue); + } + } + + [Test] + public void TestXor() + { + for (int i = -10; i <= 10; ++i) + { + for (int j = -10; j <= 10; ++j) + { + Assert.AreEqual( + val(i ^ j), + val(i).Xor(val(j)), + "Problem: " + i + " XOR " + j + " should be " + (i ^ j)); + } + } + } + + private static BigInteger val(long n) + { + return BigInteger.ValueOf(n); + } + + private static BigInteger mersenne(int e) + { + return two.Pow(e).Subtract(one); + } + + private static readonly BigInteger minusTwo = BigInteger.Two.Negate(); + private static readonly BigInteger minusOne = BigInteger.One.Negate(); + private static readonly BigInteger zero = BigInteger.Zero; + private static readonly BigInteger one = BigInteger.One; + private static readonly BigInteger two = BigInteger.Two; + private static readonly BigInteger three = BigInteger.Three; + + private static int[] firstPrimes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }; + private static int[] nonPrimes = { 0, 1, 4, 10, 20, 21, 22, 25, 26, 27 }; + + private static int[] mersennePrimeExponents = { 2, 3, 5, 7, 13, 17, 19, 31, 61, 89 }; + private static int[] nonPrimeExponents = { 1, 4, 6, 9, 11, 15, 23, 29, 37, 41 }; + } +} |