summary refs log tree commit diff
path: root/crypto/test/src/math
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2013-06-28 15:26:06 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2013-06-28 15:26:06 +0700
commit44288db4414158ac9b98a507b15e81d0d3c66ca6 (patch)
treeaa5ef88948ebb68ed6c8df81eb5da889641a9b50 /crypto/test/src/math
parentSet up text/binary handling for existing file types (diff)
downloadBouncyCastle.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.cs27
-rw-r--r--crypto/test/src/math/ec/test/ECPointPerformanceTest.cs73
-rw-r--r--crypto/test/src/math/ec/test/ECPointTest.cs451
-rw-r--r--crypto/test/src/math/ec/test/F2mProofer.cs201
-rw-r--r--crypto/test/src/math/ec/test/TnafTest.cs158
-rw-r--r--crypto/test/src/math/test/AllTests.cs27
-rw-r--r--crypto/test/src/math/test/BigIntegerTest.cs1048
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 };
+	}
+}