diff --git a/crypto/test/src/math/ec/rfc7748/test/X25519Test.cs b/crypto/test/src/math/ec/rfc7748/test/X25519Test.cs
new file mode 100644
index 000000000..89c325fd5
--- /dev/null
+++ b/crypto/test/src/math/ec/rfc7748/test/X25519Test.cs
@@ -0,0 +1,184 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Rfc7748.Tests
+{
+ [TestFixture]
+ public class X25519Test
+ {
+ private static readonly SecureRandom Random = new SecureRandom();
+
+ [SetUp]
+ public void SetUp()
+ {
+ X25519.Precompute();
+ }
+
+ [Test]
+ public void TestConsistency()
+ {
+ byte[] u = new byte[32]; u[0] = 9;
+ byte[] k = new byte[32];
+ byte[] rF = new byte[32];
+ byte[] rV = new byte[32];
+
+ for (int i = 1; i <= 100; ++i)
+ {
+ Random.NextBytes(k);
+ X25519.ScalarMultBase(k, 0, rF, 0);
+ X25519.ScalarMult(k, 0, u, 0, rV, 0);
+ Assert.IsTrue(Arrays.AreEqual(rF, rV), "Consistency #" + i);
+ }
+ }
+
+ [Test]
+ public void TestECDH()
+ {
+ byte[] kA = new byte[32];
+ byte[] kB = new byte[32];
+ byte[] qA = new byte[32];
+ byte[] qB = new byte[32];
+ byte[] sA = new byte[32];
+ byte[] sB = new byte[32];
+
+ for (int i = 1; i <= 100; ++i)
+ {
+ // Each party generates an ephemeral private key, ...
+ Random.NextBytes(kA);
+ Random.NextBytes(kB);
+
+ // ... publishes their public key, ...
+ X25519.ScalarMultBase(kA, 0, qA, 0);
+ X25519.ScalarMultBase(kB, 0, qB, 0);
+
+ // ... computes the shared secret, ...
+ X25519.ScalarMult(kA, 0, qB, 0, sA, 0);
+ X25519.ScalarMult(kB, 0, qA, 0, sB, 0);
+
+ // ... which is the same for both parties.
+ //Assert.IsTrue(Arrays.AreEqual(sA, sB), "ECDH #" + i);
+ if (!Arrays.AreEqual(sA, sB))
+ {
+ Console.WriteLine(" " + i);
+ }
+ }
+ }
+
+ [Test]
+ public void TestECDHVector1()
+ {
+ CheckECDHVector(
+ "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
+ "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
+ "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb",
+ "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
+ "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742",
+ "ECDH Vector #1");
+ }
+
+ [Test]
+ public void TestX25519Iterated()
+ {
+ CheckIterated(1000);
+ }
+
+ //[Test, Explicit]
+ //public void TestX25519IteratedFull()
+ //{
+ // CheckIterated(1000000);
+ //}
+
+ [Test]
+ public void TestX25519Vector1()
+ {
+ CheckX25519Vector(
+ "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
+ "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
+ "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552",
+ "Vector #1");
+ }
+
+ [Test]
+ public void TestX25519Vector2()
+ {
+ CheckX25519Vector(
+ "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d",
+ "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493",
+ "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957",
+ "Vector #2");
+ }
+
+ private static void CheckECDHVector(string sA, string sAPub, string sB, string sBPub, string sK, string text)
+ {
+ byte[] a = Hex.Decode(sA);
+ byte[] b = Hex.Decode(sB);
+
+ byte[] aPub = new byte[32];
+ X25519.ScalarMultBase(a, 0, aPub, 0);
+ CheckValue(aPub, text, sAPub);
+
+ byte[] bPub = new byte[32];
+ X25519.ScalarMultBase(b, 0, bPub, 0);
+ CheckValue(bPub, text, sBPub);
+
+ byte[] aK = new byte[32];
+ X25519.ScalarMult(a, 0, bPub, 0, aK, 0);
+ CheckValue(aK, text, sK);
+
+ byte[] bK = new byte[32];
+ X25519.ScalarMult(b, 0, aPub, 0, bK, 0);
+ CheckValue(bK, text, sK);
+ }
+
+ private static void CheckIterated(int count)
+ {
+ byte[] k = new byte[32]; k[0] = 9;
+ byte[] u = new byte[32]; u[0] = 9;
+ byte[] r = new byte[32];
+
+ int iterations = 0;
+ while (iterations < count)
+ {
+ X25519.ScalarMult(k, 0, u, 0, r, 0);
+
+ Array.Copy(k, 0, u, 0, 32);
+ Array.Copy(r, 0, k, 0, 32);
+
+ switch (++iterations)
+ {
+ case 1:
+ CheckValue(k, "Iterated @1", "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079");
+ break;
+ case 1000:
+ CheckValue(k, "Iterated @1000", "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51");
+ break;
+ case 1000000:
+ CheckValue(k, "Iterated @1000000", "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private static void CheckValue(byte[] n, string text, string se)
+ {
+ byte[] e = Hex.Decode(se);
+ Assert.IsTrue(Arrays.AreEqual(e, n), text);
+ }
+
+ private static void CheckX25519Vector(string sk, string su, string se, string text)
+ {
+ byte[] k = Hex.Decode(sk);
+ byte[] u = Hex.Decode(su);
+ byte[] r = new byte[32];
+ X25519.ScalarMult(k, 0, u, 0, r, 0);
+ CheckValue(r, text, se);
+ }
+ }
+}
diff --git a/crypto/test/src/math/ec/rfc7748/test/X448Test.cs b/crypto/test/src/math/ec/rfc7748/test/X448Test.cs
new file mode 100644
index 000000000..b095eade0
--- /dev/null
+++ b/crypto/test/src/math/ec/rfc7748/test/X448Test.cs
@@ -0,0 +1,183 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Rfc7748.Tests
+{
+ [TestFixture]
+ public class X448Test
+ {
+ private static readonly SecureRandom Random = new SecureRandom();
+
+ [SetUp]
+ public void SetUp()
+ {
+ X448.Precompute();
+ }
+
+ [Test]
+ public void TestConsistency()
+ {
+ byte[] u = new byte[56]; u[0] = 5;
+ byte[] k = new byte[56];
+ byte[] rF = new byte[56];
+ byte[] rV = new byte[56];
+
+ for (int i = 1; i <= 100; ++i)
+ {
+ Random.NextBytes(k);
+ X448.ScalarMultBase(k, 0, rF, 0);
+ X448.ScalarMult(k, 0, u, 0, rV, 0);
+ Assert.IsTrue(Arrays.AreEqual(rF, rV), "Consistency #" + i);
+ }
+ }
+
+ [Test]
+ public void TestECDH()
+ {
+ byte[] kA = new byte[56];
+ byte[] kB = new byte[56];
+ byte[] qA = new byte[56];
+ byte[] qB = new byte[56];
+ byte[] sA = new byte[56];
+ byte[] sB = new byte[56];
+
+ for (int i = 1; i <= 100; ++i)
+ {
+ // Each party generates an ephemeral private key, ...
+ Random.NextBytes(kA);
+ Random.NextBytes(kB);
+
+ // ... publishes their public key, ...
+ X448.ScalarMultBase(kA, 0, qA, 0);
+ X448.ScalarMultBase(kB, 0, qB, 0);
+
+ // ... computes the shared secret, ...
+ X448.ScalarMult(kA, 0, qB, 0, sA, 0);
+ X448.ScalarMult(kB, 0, qA, 0, sB, 0);
+
+ // ... which is the same for both parties.
+ Assert.IsTrue(Arrays.AreEqual(sA, sB), "ECDH #" + i);
+ }
+ }
+
+ [Test]
+ public void TestECDHVector1()
+ {
+ CheckECDHVector(
+ "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b",
+ "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0",
+ "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d",
+ "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609",
+ "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d",
+ "ECDH Vector #1");
+ }
+
+ [Test]
+ public void TestX448Iterated()
+ {
+ CheckIterated(1000);
+ }
+
+ //[Test, Explicit]
+ //public void TestX448IteratedFull()
+ //{
+ // CheckIterated(1000000);
+ //}
+
+ [Test]
+ public void TestX448Vector1()
+ {
+ CheckX448Vector(
+ "3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3",
+ "06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086",
+ "ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f",
+ "Vector #1");
+ }
+
+ [Test]
+ public void TestX448Vector2()
+ {
+ CheckX448Vector(
+ "203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f",
+ "0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db",
+ "884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d",
+ "Vector #2");
+ }
+
+ private static void CheckECDHVector(string sA, string sAPub, string sB, string sBPub, string sK, string text)
+ {
+ byte[] a = Hex.Decode(sA);
+ byte[] b = Hex.Decode(sB);
+
+ byte[] aPub = new byte[56];
+ X448.ScalarMultBase(a, 0, aPub, 0);
+ CheckValue(aPub, text, sAPub);
+
+ byte[] bPub = new byte[56];
+ X448.ScalarMultBase(b, 0, bPub, 0);
+ CheckValue(bPub, text, sBPub);
+
+ byte[] aK = new byte[56];
+ X448.ScalarMult(a, 0, bPub, 0, aK, 0);
+ CheckValue(aK, text, sK);
+
+ byte[] bK = new byte[56];
+ X448.ScalarMult(b, 0, aPub, 0, bK, 0);
+ CheckValue(bK, text, sK);
+ }
+
+ private static void CheckIterated(int count)
+ {
+ byte[] k = new byte[56]; k[0] = 5;
+ byte[] u = new byte[56]; u[0] = 5;
+ byte[] r = new byte[56];
+
+ int iterations = 0;
+ while (iterations < count)
+ {
+ X448.ScalarMult(k, 0, u, 0, r, 0);
+
+ Array.Copy(k, 0, u, 0, 56);
+ Array.Copy(r, 0, k, 0, 56);
+
+ switch (++iterations)
+ {
+ case 1:
+ CheckValue(k, "Iterated @1",
+ "3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113");
+ break;
+ case 1000:
+ CheckValue(k, "Iterated @1000",
+ "aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38");
+ break;
+ case 1000000:
+ CheckValue(k, "Iterated @1000000",
+ "077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private static void CheckValue(byte[] n, String text, String se)
+ {
+ byte[] e = Hex.Decode(se);
+ Assert.IsTrue(Arrays.AreEqual(e, n), text);
+ }
+
+ private static void CheckX448Vector(String sk, String su, String se, String text)
+ {
+ byte[] k = Hex.Decode(sk);
+ byte[] u = Hex.Decode(su);
+ byte[] r = new byte[56];
+ X448.ScalarMult(k, 0, u, 0, r, 0);
+ CheckValue(r, text, se);
+ }
+ }
+}
|