summary refs log tree commit diff
path: root/crypto/test/src
diff options
context:
space:
mode:
authorJeffrey Stedfast <jeff@xamarin.com>2015-10-11 10:26:27 -0400
committerJeffrey Stedfast <jeff@xamarin.com>2015-10-11 10:26:27 -0400
commitb2e562d4efdc221d10b08e9cba782057225ffc0e (patch)
treee1b19aa33900ae6070f2b89b2e6b0e46bd97d2b2 /crypto/test/src
parentUpdated MimeKit.BouncyCastle.nuspec (diff)
parentPort of recent ISO trailer updates from Java (diff)
downloadBouncyCastle.NET-ed25519-b2e562d4efdc221d10b08e9cba782057225ffc0e.tar.xz
Merge branch 'master' into vs2010
Diffstat (limited to 'crypto/test/src')
-rw-r--r--crypto/test/src/crypto/test/KeccakDigestTest.cs374
-rw-r--r--crypto/test/src/crypto/test/RegressionTest.cs4
-rw-r--r--crypto/test/src/crypto/test/SHA3DigestTest.cs468
-rw-r--r--crypto/test/src/crypto/test/ShakeDigestTest.cs290
-rw-r--r--crypto/test/src/math/ec/test/ECPointTest.cs51
5 files changed, 902 insertions, 285 deletions
diff --git a/crypto/test/src/crypto/test/KeccakDigestTest.cs b/crypto/test/src/crypto/test/KeccakDigestTest.cs
new file mode 100644
index 000000000..961a5d2e3
--- /dev/null
+++ b/crypto/test/src/crypto/test/KeccakDigestTest.cs
@@ -0,0 +1,374 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * Keccak Digest Test
+     */
+    [TestFixture]
+    public class KeccakDigestTest
+        : SimpleTest
+    {
+        readonly static string[] messages = {
+            "",
+            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67",
+            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e"
+        };
+
+        readonly static string[] digests288 = { // the default settings
+            "6753e3380c09e385d0339eb6b050a68f66cfd60a73476e6fd6adeb72f5edd7c6f04a5d01",  // message[0]    
+            "0bbe6afae0d7e89054085c1cc47b1689772c89a41796891e197d1ca1b76f288154933ded",  // message[1]
+            "82558a209b960ddeb531e6dcb281885b2400ca160472462486e79f071e88a3330a8a303d",  // message[2]
+            "94049e1ad7ef5d5b0df2b880489e7ab09ec937c3bfc1b04470e503e1ac7b1133c18f86da",  // 64k a-test
+            "a9cb5a75b5b81b7528301e72553ed6770214fa963956e790528afe420de33c074e6f4220",  // random alphabet test
+            "eadaf5ba2ad6a2f6f338fce0e1efdad2a61bb38f6be6068b01093977acf99e97a5d5827c"   // extremely long data test
+        };
+
+        readonly static string[] digests224 = {
+            "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd",
+            "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe",
+            "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab",
+            "f621e11c142fbf35fa8c22841c3a812ba1e0151be4f38d80b9f1ff53",
+            "68b5fc8c87193155bba68a2485377e809ee4f81a85ef023b9e64add0",
+            "c42e4aee858e1a8ad2976896b9d23dd187f64436ee15969afdbc68c5"
+        };
+
+        readonly static string[] digests256 = {
+            "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
+            "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15",
+            "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d",
+            "0047a916daa1f92130d870b542e22d3108444f5a7e4429f05762fb647e6ed9ed",
+            "db368762253ede6d4f1db87e0b799b96e554eae005747a2ea687456ca8bcbd03",
+            "5f313c39963dcf792b5470d4ade9f3a356a3e4021748690a958372e2b06f82a4"
+        };
+
+        readonly static string[] digests384 = {
+            "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff",
+            "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3",
+            "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b",
+            "c704cfe7a1a53208ca9526cd24251e0acdc252ecd978eee05acd16425cfb404ea81f5a9e2e5e97784d63ee6a0618a398",
+            "d4fe8586fd8f858dd2e4dee0bafc19b4c12b4e2a856054abc4b14927354931675cdcaf942267f204ea706c19f7beefc4",
+            "9b7168b4494a80a86408e6b9dc4e5a1837c85dd8ff452ed410f2832959c08c8c0d040a892eb9a755776372d4a8732315"
+        };
+
+        readonly static string[] digests512 = {
+            "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e",
+            "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609",
+            "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760",
+            "34341ead153aa1d1fdcf6cf624c2b4f6894b6fd16dc38bd4ec971ac0385ad54fafcb2e0ed86a1e509456f4246fdcb02c3172824cd649d9ad54c51f7fb49ea67c",
+            "dc44d4f4d36b07ab5fc04016cbe53548e5a7778671c58a43cb379fd00c06719b8073141fc22191ffc3db5f8b8983ae8341fa37f18c1c969664393aa5ceade64e",
+            "3e122edaf37398231cfaca4c7c216c9d66d5b899ec1d7ac617c40c7261906a45fc01617a021e5da3bd8d4182695b5cb785a28237cbb167590e34718e56d8aab8"
+        };
+
+        // test vectors from  http://www.di-mgt.com.au/hmac_sha3_testvectors.html
+        readonly static byte[][] macKeys =
+        {
+            Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+            Hex.Decode("4a656665"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+            Hex.Decode("0102030405060708090a0b0c0d0e0f10111213141516171819"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaa"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaa"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
+        };
+
+        readonly static string[] macData =
+        {
+            "4869205468657265",
+            "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+            "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +
+                "dddddddddddddddddddddddddddddddddddd",
+            "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" +
+                "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+            "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" +
+                "65204b6579202d2048617368204b6579204669727374",
+            "5468697320697320612074657374207573696e672061206c6172676572207468" +
+                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
+                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
+                "647320746f20626520686173686564206265666f7265206265696e6720757365" +
+                "642062792074686520484d414320616c676f726974686d2e",
+            "5468697320697320612074657374207573696e672061206c6172676572207468" +
+                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
+                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
+                "647320746f20626520686173686564206265666f7265206265696e6720757365\n" +
+                "642062792074686520484d414320616c676f726974686d2e"
+        };
+
+        readonly static string[] mac224 =
+        {
+            "b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc",
+            "e824fec96c074f22f99235bb942da1982664ab692ca8501053cbd414",
+            "770df38c99d6e2bacd68056dcfe07d4c89ae20b2686a6185e1faa449",
+            "305a8f2dfb94bad28861a03cbc4d590febe775c58cb4961c28428a0b",
+            "e7a52dfa45f95a217c100066b239aa8ad519be9b35d667268b1b57ff",
+            "ba13009405a929f398b348885caa5419191bb948ada32194afc84104",
+            "92649468be236c3c72c189909c063b13f994be05749dc91310db639e"
+        };
+
+        readonly static string[] mac256 =
+        {
+            "9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821",
+            "aa9aed448c7abc8b5e326ffa6a01cdedf7b4b831881468c044ba8dd4566369a1",
+            "95f43e50f8df80a21977d51a8db3ba572dcd71db24687e6f86f47c1139b26260",
+            "6331ba9b4af5804a68725b3663eb74814494b63c6093e35fb320a85d507936fd",
+            "b4d0cdee7ec2ba81a88b86918958312300a15622377929a054a9ce3ae1fac2b6",
+            "1fdc8cb4e27d07c10d897dec39c217792a6e64fa9c63a77ce42ad106ef284e02",
+            "fdaa10a0299aecff9bb411cf2d7748a4022e4a26be3fb5b11b33d8c2b7ef5484"
+        };
+
+        readonly static string[] mac384 =
+        {
+            "892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048",
+            "5af5c9a77a23a6a93d80649e562ab77f4f3552e3c5caffd93bdf8b3cfc6920e3023fc26775d9df1f3c94613146ad2c9d",
+            "4243c29f2201992ff96441e3b91ff81d8c601d706fbc83252684a4bc51101ca9b2c06ddd03677303c502ac5331752a3c",
+            "b730724d3d4090cda1be799f63acbbe389fef7792fc18676fa5453aab398664650ed029c3498bbe8056f06c658e1e693",
+            "d62482ef601d7847439b55236e9679388ffcd53c62cd126f39be6ea63de762e26cd5974cb9a8de401b786b5555040f6f",
+            "4860ea191ac34994cf88957afe5a836ef36e4cc1a66d75bf77defb7576122d75f60660e4cf731c6effac06402787e2b9",
+            "fe9357e3cfa538eb0373a2ce8f1e26ad6590afdaf266f1300522e8896d27e73f654d0631c8fa598d4bb82af6b744f4f5"
+        };
+
+        readonly static string[] mac512 =
+        {
+            "8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755",
+            "c2962e5bbe1238007852f79d814dbbecd4682e6f097d37a363587c03bfa2eb0859d8d9c701e04cececfd3dd7bfd438f20b8b648e01bf8c11d26824b96cebbdcb",
+            "eb0ed9580e0ec11fc66cbb646b1be904eaff6da4556d9334f65ee4b2c85739157bae9027c51505e49d1bb81cfa55e6822db55262d5a252c088a29a5e95b84a66",
+            "b46193bb59f4f696bf702597616da91e2a4558a593f4b015e69141ba81e1e50ea580834c2b87f87baa25a3a03bfc9bb389847f2dc820beae69d30c4bb75369cb",
+            "d05888a6ebf8460423ea7bc85ea4ffda847b32df32291d2ce115fd187707325c7ce4f71880d91008084ce24a38795d20e6a28328a0f0712dc38253370da3ebb5",
+            "2c6b9748d35c4c8db0b4407dd2ed2381f133bdbd1dfaa69e30051eb6badfcca64299b88ae05fdbd3dd3dd7fe627e42e39e48b0fe8c7f1e85f2dbd52c2d753572",
+            "6adc502f14e27812402fc81a807b28bf8a53c87bea7a1df6256bf66f5de1a4cb741407ad15ab8abc136846057f881969fbb159c321c904bfb557b77afb7778c8"
+        };
+
+        readonly static KeyParameter truncKey = new KeyParameter(Hex.Decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"));
+        readonly static byte[] truncData = Hex.Decode("546573742057697468205472756e636174696f6e");
+
+        readonly static byte[] trunc224 = Hex.Decode("f52bbcfd654264e7133085c5e69b72c3");
+        readonly static byte[] trunc256 = Hex.Decode("745e7e687f8335280d54202ef13cecc6");
+        readonly static byte[] trunc384 = Hex.Decode("fa9aea2bc1e181e47cbb8c3df243814d");
+        readonly static byte[] trunc512 = Hex.Decode("04c929fead434bba190dacfa554ce3f5");
+
+        readonly static byte[] xtremeData = Hex.Decode("61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f");
+
+        public override string Name
+        {
+            get { return "Keccak"; }
+        }
+
+        private void TestDigest(IDigest digest, string[] expected)
+        {
+            byte[] hash = new byte[digest.GetDigestSize()];
+
+            for (int i = 0; i != messages.Length; i++)
+            {
+                if (messages.Length != 0)
+                {
+                    byte[] data = Hex.Decode(messages[i]);
+
+                    digest.BlockUpdate(data, 0, data.Length);
+                }
+
+                digest.DoFinal(hash, 0);
+
+                if (!Arrays.AreEqual(Hex.Decode(expected[i]), hash))
+                {
+                    Fail("Keccak mismatch on " + digest.AlgorithmName + " index " + i);
+                }
+            }
+
+            byte[] k64 = new byte[1024 * 64];
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                k64[i] = (byte)'a';
+            }
+
+            digest.BlockUpdate(k64, 0, k64.Length);
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
+            {
+                Fail("Keccak mismatch on " + digest.AlgorithmName + " 64k a");
+            }
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                digest.Update((byte)'a');
+            }
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
+            {
+                Fail("Keccak mismatch on " + digest.AlgorithmName + " 64k a single");
+            }
+
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                k64[i] = (byte)('a' + (i % 26));
+            }
+
+            digest.BlockUpdate(k64, 0, k64.Length);
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+            {
+                Fail("Keccak mismatch on " + digest.AlgorithmName + " 64k alpha");
+            }
+
+            for (int i = 0; i != 64; i++)
+            {
+                digest.Update(k64[i * 1024]);
+                digest.BlockUpdate(k64, i * 1024 + 1, 1023);
+            }
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+            {
+                Fail("Keccak mismatch on " + digest.AlgorithmName + " 64k chunked alpha");
+            }
+
+            TestDigestDoFinal(digest);
+
+            //
+            // extremely long data test
+            //
+            //Console.WriteLine("Starting very long");
+            //for (int i = 0; i != 16384; i++)
+            //{
+            //    for (int j = 0; j != 1024; j++)
+            //    {
+            //        digest.BlockUpdate(xtremeData, 0, xtremeData.Length);
+            //    }
+            //}
+
+            //digest.DoFinal(hash, 0);
+
+            //if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 2]), hash))
+            //{
+            //    Fail("Keccak mismatch on " + digest.AlgorithmName + " extreme data test");
+            //}
+            //Console.WriteLine("Done");
+        }
+
+        private void TestDigestDoFinal(IDigest digest)
+        {
+            byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+            for (int i = 0; i <= digest.GetDigestSize(); ++i)
+            {
+                byte[] cmp = new byte[2 * digest.GetDigestSize()];
+                Array.Copy(hash, 0, cmp, i, hash.Length);
+
+                byte[] buf = new byte[2 * digest.GetDigestSize()];
+                digest.DoFinal(buf, i);
+
+                if (!Arrays.AreEqual(cmp, buf))
+                {
+                    Fail("Keccak offset DoFinal on " + digest.AlgorithmName);
+                }
+            }
+        }
+
+        private void TestMac(IDigest digest, byte[][] keys, String[] data, String[] expected, byte[] truncExpected)
+        {
+            IMac mac = new HMac(digest);
+
+            for (int i = 0; i != keys.Length; i++)
+            {
+                mac.Init(new KeyParameter(keys[i]));
+
+                byte[] mData = Hex.Decode(data[i]);
+
+                mac.BlockUpdate(mData, 0, mData.Length);
+
+                byte[] macV = new byte[mac.GetMacSize()];
+
+                mac.DoFinal(macV, 0);
+
+                if (!Arrays.AreEqual(Hex.Decode(expected[i]), macV))
+                {
+                    Fail("Keccak HMAC mismatch on " + digest.AlgorithmName);
+                }
+            }
+
+            {
+                mac = new HMac(digest);
+
+                mac.Init(truncKey);
+
+                mac.BlockUpdate(truncData, 0, truncData.Length);
+
+                byte[] macV = new byte[mac.GetMacSize()];
+
+                mac.DoFinal(macV, 0);
+
+                for (int i = 0; i != truncExpected.Length; i++)
+                {
+                    if (macV[i] != truncExpected[i])
+                    {
+                        Fail("mismatch on truncated HMAC for " + digest.AlgorithmName);
+                    }
+                }
+            }
+        }
+
+        public override void PerformTest()
+        {
+            TestDigest(new KeccakDigest(), digests288);
+            TestDigest(new KeccakDigest(224), digests224);
+            TestDigest(new KeccakDigest(256), digests256);
+            TestDigest(new KeccakDigest(384), digests384);
+            TestDigest(new KeccakDigest(512), digests512);
+
+            TestMac(new KeccakDigest(224), macKeys, macData, mac224, trunc224);
+            TestMac(new KeccakDigest(256), macKeys, macData, mac256, trunc256);
+            TestMac(new KeccakDigest(384), macKeys, macData, mac384, trunc384);
+            TestMac(new KeccakDigest(512), macKeys, macData, mac512, trunc512);
+        }
+
+        protected virtual IDigest CloneDigest(IDigest digest)
+        {
+            return new KeccakDigest((KeccakDigest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new KeccakDigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs
index 0b7a0f72d..ab6394571 100644
--- a/crypto/test/src/crypto/test/RegressionTest.cs
+++ b/crypto/test/src/crypto/test/RegressionTest.cs
@@ -119,7 +119,9 @@ namespace Org.BouncyCastle.Crypto.Tests
             new Poly1305Test(),
             new OcbTest(),
             new SM3DigestTest(),
-            new X931SignerTest()
+            new X931SignerTest(),
+            new KeccakDigestTest(),
+            new ShakeDigestTest(),
         };
 
         public static void Main(
diff --git a/crypto/test/src/crypto/test/SHA3DigestTest.cs b/crypto/test/src/crypto/test/SHA3DigestTest.cs
index 2b8ae4a63..71f51f43b 100644
--- a/crypto/test/src/crypto/test/SHA3DigestTest.cs
+++ b/crypto/test/src/crypto/test/SHA3DigestTest.cs
@@ -1,11 +1,11 @@
 using System;
+using System.IO;
+using System.Text;
 
 using NUnit.Framework;
 
-using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Macs;
-using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
 using Org.BouncyCastle.Utilities.Test;
@@ -19,346 +19,218 @@ namespace Org.BouncyCastle.Crypto.Tests
     public class Sha3DigestTest
         : SimpleTest
     {
-        readonly static string[] messages = {
-            "",
-            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67",
-            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e"
-        };
-
-        readonly static string[] digests288 = { // the default settings
-            "6753e3380c09e385d0339eb6b050a68f66cfd60a73476e6fd6adeb72f5edd7c6f04a5d01",  // message[0]    
-            "0bbe6afae0d7e89054085c1cc47b1689772c89a41796891e197d1ca1b76f288154933ded",  // message[1]
-            "82558a209b960ddeb531e6dcb281885b2400ca160472462486e79f071e88a3330a8a303d",  // message[2]
-            "94049e1ad7ef5d5b0df2b880489e7ab09ec937c3bfc1b04470e503e1ac7b1133c18f86da",  // 64k a-test
-            "a9cb5a75b5b81b7528301e72553ed6770214fa963956e790528afe420de33c074e6f4220",  // random alphabet test
-            "eadaf5ba2ad6a2f6f338fce0e1efdad2a61bb38f6be6068b01093977acf99e97a5d5827c"   // extremely long data test
-        };
-
-        readonly static string[] digests224 = {
-            "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd",
-            "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe",
-            "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab",
-            "f621e11c142fbf35fa8c22841c3a812ba1e0151be4f38d80b9f1ff53",
-            "68b5fc8c87193155bba68a2485377e809ee4f81a85ef023b9e64add0",
-            "c42e4aee858e1a8ad2976896b9d23dd187f64436ee15969afdbc68c5"
-        };
-
-        readonly static string[] digests256 = {
-            "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
-            "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15",
-            "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d",
-            "0047a916daa1f92130d870b542e22d3108444f5a7e4429f05762fb647e6ed9ed",
-            "db368762253ede6d4f1db87e0b799b96e554eae005747a2ea687456ca8bcbd03",
-            "5f313c39963dcf792b5470d4ade9f3a356a3e4021748690a958372e2b06f82a4"
-        };
-
-        readonly static string[] digests384 = {
-            "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff",
-            "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3",
-            "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b",
-            "c704cfe7a1a53208ca9526cd24251e0acdc252ecd978eee05acd16425cfb404ea81f5a9e2e5e97784d63ee6a0618a398",
-            "d4fe8586fd8f858dd2e4dee0bafc19b4c12b4e2a856054abc4b14927354931675cdcaf942267f204ea706c19f7beefc4",
-            "9b7168b4494a80a86408e6b9dc4e5a1837c85dd8ff452ed410f2832959c08c8c0d040a892eb9a755776372d4a8732315"
-        };
-
-        readonly static string[] digests512 = {
-            "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e",
-            "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609",
-            "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760",
-            "34341ead153aa1d1fdcf6cf624c2b4f6894b6fd16dc38bd4ec971ac0385ad54fafcb2e0ed86a1e509456f4246fdcb02c3172824cd649d9ad54c51f7fb49ea67c",
-            "dc44d4f4d36b07ab5fc04016cbe53548e5a7778671c58a43cb379fd00c06719b8073141fc22191ffc3db5f8b8983ae8341fa37f18c1c969664393aa5ceade64e",
-            "3e122edaf37398231cfaca4c7c216c9d66d5b899ec1d7ac617c40c7261906a45fc01617a021e5da3bd8d4182695b5cb785a28237cbb167590e34718e56d8aab8"
-        };
-
-        // test vectors from  http://www.di-mgt.com.au/hmac_sha3_testvectors.html
-        readonly static byte[][] macKeys =
+        internal class MySha3Digest : Sha3Digest
         {
-            Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
-            Hex.Decode("4a656665"),
-            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
-            Hex.Decode("0102030405060708090a0b0c0d0e0f10111213141516171819"),
-            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaa"),
-            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaa"),
-            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
-        };
-
-        readonly static string[] macData =
-        {
-            "4869205468657265",
-            "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
-            "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +
-                "dddddddddddddddddddddddddddddddddddd",
-            "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" +
-                "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
-            "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" +
-                "65204b6579202d2048617368204b6579204669727374",
-            "5468697320697320612074657374207573696e672061206c6172676572207468" +
-                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
-                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
-                "647320746f20626520686173686564206265666f7265206265696e6720757365" +
-                "642062792074686520484d414320616c676f726974686d2e",
-            "5468697320697320612074657374207573696e672061206c6172676572207468" +
-                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
-                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
-                "647320746f20626520686173686564206265666f7265206265696e6720757365\n" +
-                "642062792074686520484d414320616c676f726974686d2e"
-        };
-
-        readonly static string[] mac224 =
-        {
-            "b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc",
-            "e824fec96c074f22f99235bb942da1982664ab692ca8501053cbd414",
-            "770df38c99d6e2bacd68056dcfe07d4c89ae20b2686a6185e1faa449",
-            "305a8f2dfb94bad28861a03cbc4d590febe775c58cb4961c28428a0b",
-            "e7a52dfa45f95a217c100066b239aa8ad519be9b35d667268b1b57ff",
-            "ba13009405a929f398b348885caa5419191bb948ada32194afc84104",
-            "92649468be236c3c72c189909c063b13f994be05749dc91310db639e"
-        };
-
-        readonly static string[] mac256 =
-        {
-            "9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821",
-            "aa9aed448c7abc8b5e326ffa6a01cdedf7b4b831881468c044ba8dd4566369a1",
-            "95f43e50f8df80a21977d51a8db3ba572dcd71db24687e6f86f47c1139b26260",
-            "6331ba9b4af5804a68725b3663eb74814494b63c6093e35fb320a85d507936fd",
-            "b4d0cdee7ec2ba81a88b86918958312300a15622377929a054a9ce3ae1fac2b6",
-            "1fdc8cb4e27d07c10d897dec39c217792a6e64fa9c63a77ce42ad106ef284e02",
-            "fdaa10a0299aecff9bb411cf2d7748a4022e4a26be3fb5b11b33d8c2b7ef5484"
-        };
-
-        readonly static string[] mac384 =
-        {
-            "892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048",
-            "5af5c9a77a23a6a93d80649e562ab77f4f3552e3c5caffd93bdf8b3cfc6920e3023fc26775d9df1f3c94613146ad2c9d",
-            "4243c29f2201992ff96441e3b91ff81d8c601d706fbc83252684a4bc51101ca9b2c06ddd03677303c502ac5331752a3c",
-            "b730724d3d4090cda1be799f63acbbe389fef7792fc18676fa5453aab398664650ed029c3498bbe8056f06c658e1e693",
-            "d62482ef601d7847439b55236e9679388ffcd53c62cd126f39be6ea63de762e26cd5974cb9a8de401b786b5555040f6f",
-            "4860ea191ac34994cf88957afe5a836ef36e4cc1a66d75bf77defb7576122d75f60660e4cf731c6effac06402787e2b9",
-            "fe9357e3cfa538eb0373a2ce8f1e26ad6590afdaf266f1300522e8896d27e73f654d0631c8fa598d4bb82af6b744f4f5"
-        };
-
-        readonly static string[] mac512 =
-        {
-            "8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755",
-            "c2962e5bbe1238007852f79d814dbbecd4682e6f097d37a363587c03bfa2eb0859d8d9c701e04cececfd3dd7bfd438f20b8b648e01bf8c11d26824b96cebbdcb",
-            "eb0ed9580e0ec11fc66cbb646b1be904eaff6da4556d9334f65ee4b2c85739157bae9027c51505e49d1bb81cfa55e6822db55262d5a252c088a29a5e95b84a66",
-            "b46193bb59f4f696bf702597616da91e2a4558a593f4b015e69141ba81e1e50ea580834c2b87f87baa25a3a03bfc9bb389847f2dc820beae69d30c4bb75369cb",
-            "d05888a6ebf8460423ea7bc85ea4ffda847b32df32291d2ce115fd187707325c7ce4f71880d91008084ce24a38795d20e6a28328a0f0712dc38253370da3ebb5",
-            "2c6b9748d35c4c8db0b4407dd2ed2381f133bdbd1dfaa69e30051eb6badfcca64299b88ae05fdbd3dd3dd7fe627e42e39e48b0fe8c7f1e85f2dbd52c2d753572",
-            "6adc502f14e27812402fc81a807b28bf8a53c87bea7a1df6256bf66f5de1a4cb741407ad15ab8abc136846057f881969fbb159c321c904bfb557b77afb7778c8"
-        };
-
-        readonly static KeyParameter truncKey = new KeyParameter(Hex.Decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"));
-        readonly static byte[] truncData = Hex.Decode("546573742057697468205472756e636174696f6e");
-
-        readonly static byte[] trunc224 = Hex.Decode("f52bbcfd654264e7133085c5e69b72c3");
-        readonly static byte[] trunc256 = Hex.Decode("745e7e687f8335280d54202ef13cecc6");
-        readonly static byte[] trunc384 = Hex.Decode("fa9aea2bc1e181e47cbb8c3df243814d");
-        readonly static byte[] trunc512 = Hex.Decode("04c929fead434bba190dacfa554ce3f5");
+            internal MySha3Digest(int bitLength)
+                : base(bitLength)
+            {
+            }
 
-        readonly static byte[] xtremeData = Hex.Decode("61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f");
+            internal int MyDoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+            {
+                return DoFinal(output, outOff, partialByte, partialBits);
+            }
+        }
 
         public override string Name
         {
-            get { return "SHA3"; }
+            get { return "SHA-3"; }
         }
 
-        private void TestDigest(IDigest digest, string[] expected)
+        public override void PerformTest()
         {
-            byte[] hash = new byte[digest.GetDigestSize()];
+            TestVectors();
+        }
 
-            for (int i = 0; i != messages.Length; i++)
+        public void TestVectors()
+        {
+            using (StreamReader r = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.SHA3TestVectors.txt")))
             {
-                if (messages.Length != 0)
-                {
-                    byte[] data = Hex.Decode(messages[i]);
-
-                    digest.BlockUpdate(data, 0, data.Length);
-                }
-
-                digest.DoFinal(hash, 0);
-
-                if (!Arrays.AreEqual(Hex.Decode(expected[i]), hash))
+                String line;
+                while (null != (line = ReadLine(r)))
                 {
-                    Fail("sha3 mismatch on " + digest.AlgorithmName + " index " + i);
+                    if (line.Length != 0)
+                    {
+                        TestVector v = ReadTestVector(r, line);
+                        RunTestVector(v);
+                    }
                 }
             }
+        }
 
-            byte[] k64 = new byte[1024 * 64];
-
-            for (int i = 0; i != k64.Length; i++)
+        private MySha3Digest CreateDigest(string algorithm)
+        {
+            if (algorithm.StartsWith("SHA3-"))
             {
-                k64[i] = (byte)'a';
+                int bits = ParseDecimal(algorithm.Substring("SHA3-".Length));
+                return new MySha3Digest(bits);
             }
+            throw new ArgumentException("Unknown algorithm: " + algorithm, "algorithm");
+        }
 
-            digest.BlockUpdate(k64, 0, k64.Length);
-
-            digest.DoFinal(hash, 0);
+        private byte[] DecodeBinary(string block)
+        {
+            int bits = block.Length;
+            int fullBytes = bits / 8;
+            int totalBytes = (bits + 7) / 8;
+            byte[] result = new byte[totalBytes];
 
-            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
+            for (int i = 0; i < fullBytes; ++i)
             {
-                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k a");
+                string byteStr = Reverse(block.Substring(i * 8, 8));
+                result[i] = (byte)ParseBinary(byteStr);
             }
 
-            for (int i = 0; i != k64.Length; i++)
+            if (totalBytes > fullBytes)
             {
-                digest.Update((byte)'a');
+                string byteStr = Reverse(block.Substring(fullBytes * 8));
+                result[fullBytes] = (byte)ParseBinary(byteStr);
             }
 
-            digest.DoFinal(hash, 0);
+            return result;
+        }
 
-            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
-            {
-                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k a single");
-            }
+        private int ParseBinary(string s)
+        {
+            return new BigInteger(s, 2).IntValue;
+        }
 
+        private int ParseDecimal(string s)
+        {
+            return Int32.Parse(s);
+        }
 
-            for (int i = 0; i != k64.Length; i++)
+        private string ReadBlock(StreamReader r)
+        {
+            StringBuilder b = new StringBuilder();
+            string line;
+            while ((line = ReadBlockLine(r)) != null)
             {
-                k64[i] = (byte)('a' + (i % 26));
+                b.Append(line);
             }
+            return b.ToString();
+        }
 
-            digest.BlockUpdate(k64, 0, k64.Length);
-
-            digest.DoFinal(hash, 0);
-
-            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+        private string ReadBlockLine(StreamReader r)
+        {
+            string line = ReadLine(r);
+            if (line == null || line.Length == 0)
             {
-                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k alpha");
+                return null;
             }
+            return line.Replace(" ", "");
+        }
 
-            for (int i = 0; i != 64; i++)
-            {
-                digest.Update(k64[i * 1024]);
-                digest.BlockUpdate(k64, i * 1024 + 1, 1023);
-            }
+        private TestVector ReadTestVector(StreamReader r, string header)
+        {
+            string[] parts = SplitAround(header, TestVector.SAMPLE_OF);
 
-            digest.DoFinal(hash, 0);
+            string algorithm = parts[0];
+            int bits = ParseDecimal(StripFromChar(parts[1], '-'));
 
-            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+            SkipUntil(r, TestVector.MSG_HEADER);
+            string messageBlock = ReadBlock(r);
+            if (messageBlock.Length != bits)
             {
-                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k chunked alpha");
+                throw new InvalidOperationException("Test vector length mismatch");
             }
+            byte[] message = DecodeBinary(messageBlock);
+
+            SkipUntil(r, TestVector.HASH_HEADER);
+            byte[] hash = Hex.Decode(ReadBlock(r));
 
-            TestDigestDoFinal(digest);
-
-            //
-            // extremely long data test
-            //
-            //Console.WriteLine("Starting very long");
-            //for (int i = 0; i != 16384; i++)
-            //{
-            //    for (int j = 0; j != 1024; j++)
-            //    {
-            //        digest.BlockUpdate(xtremeData, 0, xtremeData.Length);
-            //    }
-            //}
-    
-            //digest.DoFinal(hash, 0);
-    
-            //if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 2]), hash))
-            //{
-            //    Fail("sha3 mismatch on " + digest.AlgorithmName + " extreme data test");
-            //}
-            //Console.WriteLine("Done");
+            return new TestVector(algorithm, bits, message, hash);
         }
 
-        private void TestDigestDoFinal(IDigest digest)
+        private string ReadLine(StreamReader r)
         {
-            byte[] hash = new byte[digest.GetDigestSize()];
-            digest.DoFinal(hash, 0);
+            string line = r.ReadLine();
+            return line == null ? null : StripFromChar(line, '#').Trim();
+        }
 
-            for (int i = 0; i <= digest.GetDigestSize(); ++i)
+        private string RequireLine(StreamReader r)
+        {
+            string line = ReadLine(r);
+            if (line == null)
             {
-                byte[] cmp = new byte[2 * digest.GetDigestSize()];
-                Array.Copy(hash, 0, cmp, i, hash.Length);
-
-                byte[] buf = new byte[2 * digest.GetDigestSize()];
-                digest.DoFinal(buf, i);
-
-                if (!Arrays.AreEqual(cmp, buf))
-                {
-                    Fail("sha3 offset DoFinal on " + digest.AlgorithmName);
-                }
+                throw new EndOfStreamException();
             }
+            return line;
         }
 
-        private void TestMac(IDigest digest, byte[][] keys, String[] data, String[] expected, byte[] truncExpected)
+        private string Reverse(string s)
         {
-            IMac mac = new HMac(digest);
-
-            for (int i = 0; i != keys.Length; i++)
-            {
-                mac.Init(new KeyParameter(keys[i]));
-
-                byte[] mData = Hex.Decode(data[i]);
+            char[] cs = s.ToCharArray();
+            Array.Reverse(cs);
+            return new string(cs);
+        }
 
-                mac.BlockUpdate(mData, 0, mData.Length);
+        private void RunTestVector(TestVector v)
+        {
+            int bits = v.Bits;
+            int partialBits = bits % 8;
 
-                byte[] macV = new byte[mac.GetMacSize()];
+            //Console.WriteLine(v.Algorithm + " " + bits + "-bit");
+            //Console.WriteLine(Hex.ToHexString(v.Message).ToUpper());
+            //Console.WriteLine(Hex.ToHexString(v.Hash).ToUpper());
 
-                mac.DoFinal(macV, 0);
+            MySha3Digest d = CreateDigest(v.Algorithm);
+            byte[] output = new byte[d.GetDigestSize()];
 
-                if (!Arrays.AreEqual(Hex.Decode(expected[i]), macV))
-                {
-                    Fail("sha3 HMAC mismatch on " + digest.AlgorithmName);
-                }
+            byte[] m = v.Message;
+            if (partialBits == 0)
+            {
+                d.BlockUpdate(m, 0, m.Length);
+                d.DoFinal(output, 0);
             }
-
+            else
             {
-                mac = new HMac(digest);
-
-                mac.Init(truncKey);
-
-                mac.BlockUpdate(truncData, 0, truncData.Length);
-
-                byte[] macV = new byte[mac.GetMacSize()];
+                d.BlockUpdate(m, 0, m.Length - 1);
+                d.MyDoFinal(output, 0, m[m.Length - 1], partialBits);
+            }
 
-                mac.DoFinal(macV, 0);
+            if (!Arrays.AreEqual(v.Hash, output))
+            {
+                Fail(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
+                //Console.Error.WriteLine(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
+                //Console.Error.WriteLine(Hex.ToHexString(output).ToUpper());
+            }
+        }
 
-                for (int i = 0; i != truncExpected.Length; i++)
-                {
-                    if (macV[i] != truncExpected[i])
-                    {
-                        Fail("mismatch on truncated HMAC for " + digest.AlgorithmName);
-                    }
-                }
+        private void SkipUntil(StreamReader r, string header)
+        {
+            string line;
+            do
+            {
+                line = RequireLine(r);
+            }
+            while (line.Length == 0);
+            if (!line.Equals(header))
+            {
+                throw new IOException("Expected: " + header);
             }
         }
 
-        public override void PerformTest()
+        private string[] SplitAround(string s, string separator)
         {
-            TestDigest(new Sha3Digest(), digests288);
-            TestDigest(new Sha3Digest(224), digests224);
-            TestDigest(new Sha3Digest(256), digests256);
-            TestDigest(new Sha3Digest(384), digests384);
-            TestDigest(new Sha3Digest(512), digests512);
-
-            TestMac(new Sha3Digest(224), macKeys, macData, mac224, trunc224);
-            TestMac(new Sha3Digest(256), macKeys, macData, mac256, trunc256);
-            TestMac(new Sha3Digest(384), macKeys, macData, mac384, trunc384);
-            TestMac(new Sha3Digest(512), macKeys, macData, mac512, trunc512);
+            int i = s.IndexOf(separator);
+            if (i < 0)
+                throw new InvalidOperationException();
+            return new string[] { s.Substring(0, i), s.Substring(i + separator.Length) };
         }
 
-        protected virtual IDigest CloneDigest(IDigest digest)
+        private string StripFromChar(string s, char c)
         {
-            return new Sha3Digest((Sha3Digest)digest);
+            int i = s.IndexOf(c);
+            if (i >= 0)
+            {
+                s = s.Substring(0, i);
+            }
+            return s;
         }
 
         public static void Main(
-            string[] args)
+            string[]    args)
         {
             RunTest(new Sha3DigestTest());
         }
@@ -370,5 +242,45 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             Assert.AreEqual(Name + ": Okay", resultText);
         }
+
+        internal class TestVector
+        {
+            internal static string SAMPLE_OF = " sample of ";
+            internal static string MSG_HEADER = "Msg as bit string";
+            internal static string HASH_HEADER = "Hash val is";
+
+            private readonly string algorithm;
+            private readonly int bits;
+            private readonly byte[] message;
+            private readonly byte[] hash;
+
+            internal TestVector(string algorithm, int bits, byte[] message, byte[] hash)
+            {
+                this.algorithm = algorithm;
+                this.bits = bits;
+                this.message = message;
+                this.hash = hash;
+            }
+
+            public string Algorithm
+            {
+                get { return algorithm; }
+            }
+
+            public int Bits
+            {
+                get { return bits; }
+            }
+
+            public byte[] Message
+            {
+                get { return message; }
+            }
+
+            public byte[] Hash
+            {
+                get { return hash; }
+            }
+        }
     }
 }
diff --git a/crypto/test/src/crypto/test/ShakeDigestTest.cs b/crypto/test/src/crypto/test/ShakeDigestTest.cs
new file mode 100644
index 000000000..ef4696739
--- /dev/null
+++ b/crypto/test/src/crypto/test/ShakeDigestTest.cs
@@ -0,0 +1,290 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * SHAKE Digest Test
+     */
+    [TestFixture]
+    public class ShakeDigestTest
+        : SimpleTest
+    {
+        internal class MyShakeDigest : ShakeDigest
+        {
+            internal MyShakeDigest(int bitLength)
+                : base(bitLength)
+            {
+            }
+
+            internal int MyDoFinal(byte[] output, int outOff, int outLen, byte partialByte, int partialBits)
+            {
+                return DoFinal(output, outOff, outLen, partialByte, partialBits);
+            }
+        }
+
+        public override string Name
+        {
+            get { return "SHAKE"; }
+        }
+
+        public override void PerformTest()
+        {
+            TestVectors();
+        }
+
+        public void TestVectors()
+        {
+            using (StreamReader r = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.SHAKETestVectors.txt")))
+            {
+                String line;
+                while (null != (line = ReadLine(r)))
+                {
+                    if (line.Length != 0)
+                    {
+                        TestVector v = ReadTestVector(r, line);
+                        RunTestVector(v);
+                    }
+                }
+            }
+        }
+
+        private MyShakeDigest CreateDigest(string algorithm)
+        {
+            if (algorithm.StartsWith("SHAKE-"))
+            {
+                int bits = ParseDecimal(algorithm.Substring("SHAKE-".Length));
+                return new MyShakeDigest(bits);
+            }
+            throw new ArgumentException("Unknown algorithm: " + algorithm, "algorithm");
+        }
+
+        private byte[] DecodeBinary(string block)
+        {
+            int bits = block.Length;
+            int fullBytes = bits / 8;
+            int totalBytes = (bits + 7) / 8;
+            byte[] result = new byte[totalBytes];
+
+            for (int i = 0; i < fullBytes; ++i)
+            {
+                string byteStr = Reverse(block.Substring(i * 8, 8));
+                result[i] = (byte)ParseBinary(byteStr);
+            }
+
+            if (totalBytes > fullBytes)
+            {
+                string byteStr = Reverse(block.Substring(fullBytes * 8));
+                result[fullBytes] = (byte)ParseBinary(byteStr);
+            }
+
+            return result;
+        }
+
+        private int ParseBinary(string s)
+        {
+            return new BigInteger(s, 2).IntValue;
+        }
+
+        private int ParseDecimal(string s)
+        {
+            return Int32.Parse(s);
+        }
+
+        private string ReadBlock(StreamReader r)
+        {
+            StringBuilder b = new StringBuilder();
+            string line;
+            while ((line = ReadBlockLine(r)) != null)
+            {
+                b.Append(line);
+            }
+            return b.ToString();
+        }
+
+        private string ReadBlockLine(StreamReader r)
+        {
+            string line = ReadLine(r);
+            if (line == null || line.Length == 0)
+            {
+                return null;
+            }
+            return line.Replace(" ", "");
+        }
+
+        private TestVector ReadTestVector(StreamReader r, string header)
+        {
+            string[] parts = SplitAround(header, TestVector.SAMPLE_OF);
+
+            string algorithm = parts[0];
+            int bits = ParseDecimal(StripFromChar(parts[1], '-'));
+
+            SkipUntil(r, TestVector.MSG_HEADER);
+            string messageBlock = ReadBlock(r);
+            if (messageBlock.Length != bits)
+            {
+                throw new InvalidOperationException("Test vector length mismatch");
+            }
+            byte[] message = DecodeBinary(messageBlock);
+
+            SkipUntil(r, TestVector.OUTPUT_HEADER);
+            byte[] output = Hex.Decode(ReadBlock(r));
+
+            return new TestVector(algorithm, bits, message, output);
+        }
+
+        private string ReadLine(StreamReader r)
+        {
+            string line = r.ReadLine();
+            return line == null ? null : StripFromChar(line, '#').Trim();
+        }
+
+        private string RequireLine(StreamReader r)
+        {
+            string line = ReadLine(r);
+            if (line == null)
+            {
+                throw new EndOfStreamException();
+            }
+            return line;
+        }
+
+        private string Reverse(string s)
+        {
+            char[] cs = s.ToCharArray();
+            Array.Reverse(cs);
+            return new string(cs);
+        }
+
+        private void RunTestVector(TestVector v)
+        {
+            int bits = v.Bits;
+            int partialBits = bits % 8;
+
+            byte[] expected = v.Output;
+
+            //Console.WriteLine(v.Algorithm + " " + bits + "-bit");
+            //Console.WriteLine(Hex.ToHexString(v.Message).ToUpper());
+            //Console.WriteLine(Hex.ToHexString(expected).ToUpper());
+
+            int outLen = expected.Length;
+
+            MyShakeDigest d = CreateDigest(v.Algorithm);
+            byte[] output = new byte[outLen];
+
+            byte[] m = v.Message;
+            if (partialBits == 0)
+            {
+                d.BlockUpdate(m, 0, m.Length);
+                d.DoFinal(output, 0, outLen);
+            }
+            else
+            {
+                d.BlockUpdate(m, 0, m.Length - 1);
+                d.MyDoFinal(output, 0, outLen, m[m.Length - 1], partialBits);
+            }
+
+            if (!Arrays.AreEqual(expected, output))
+            {
+                Fail(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
+                //Console.Error.WriteLine(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
+                //Console.Error.WriteLine(Hex.ToHexString(output).ToUpper());
+            }
+        }
+
+        private void SkipUntil(StreamReader r, string header)
+        {
+            string line;
+            do
+            {
+                line = RequireLine(r);
+            }
+            while (line.Length == 0);
+            if (!line.Equals(header))
+            {
+                throw new IOException("Expected: " + header);
+            }
+        }
+
+        private string[] SplitAround(string s, string separator)
+        {
+            int i = s.IndexOf(separator);
+            if (i < 0)
+                throw new InvalidOperationException();
+            return new string[] { s.Substring(0, i), s.Substring(i + separator.Length) };
+        }
+
+        private string StripFromChar(string s, char c)
+        {
+            int i = s.IndexOf(c);
+            if (i >= 0)
+            {
+                s = s.Substring(0, i);
+            }
+            return s;
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new ShakeDigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        internal class TestVector
+        {
+            internal static string SAMPLE_OF = " sample of ";
+            internal static string MSG_HEADER = "Msg as bit string";
+            internal static string OUTPUT_HEADER = "Output val is";
+
+            private readonly string algorithm;
+            private readonly int bits;
+            private readonly byte[] message;
+            private readonly byte[] output;
+
+            internal TestVector(string algorithm, int bits, byte[] message, byte[] output)
+            {
+                this.algorithm = algorithm;
+                this.bits = bits;
+                this.message = message;
+                this.output = output;
+            }
+
+            public string Algorithm
+            {
+                get { return algorithm; }
+            }
+
+            public int Bits
+            {
+                get { return bits; }
+            }
+
+            public byte[] Message
+            {
+                get { return message; }
+            }
+
+            public byte[] Output
+            {
+                get { return output; }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/test/ECPointTest.cs b/crypto/test/src/math/ec/test/ECPointTest.cs
index 2a62b7740..3c10170f7 100644
--- a/crypto/test/src/math/ec/test/ECPointTest.cs
+++ b/crypto/test/src/math/ec/test/ECPointTest.cs
@@ -487,23 +487,62 @@ namespace Org.BouncyCastle.Math.EC.Tests
 
             foreach (string name in uniqNames)
             {
-                X9ECParameters x9ECParameters = ECNamedCurveTable.GetByName(name);
-                if (x9ECParameters != null)
+                X9ECParameters x9A = ECNamedCurveTable.GetByName(name);
+                X9ECParameters x9B = CustomNamedCurves.GetByName(name);
+
+                if (x9A != null && x9B != null)
+                {
+                    Assert.AreEqual(x9A.Curve.Field, x9B.Curve.Field);
+                    Assert.AreEqual(x9A.Curve.A.ToBigInteger(), x9B.Curve.A.ToBigInteger());
+                    Assert.AreEqual(x9A.Curve.B.ToBigInteger(), x9B.Curve.B.ToBigInteger());
+                    AssertOptionalValuesAgree(x9A.Curve.Cofactor, x9B.Curve.Cofactor);
+                    AssertOptionalValuesAgree(x9A.Curve.Order, x9B.Curve.Order);
+
+                    AssertPointsEqual("Custom curve base-point inconsistency", x9A.G, x9B.G);
+
+                    Assert.AreEqual(x9A.H, x9B.H);
+                    Assert.AreEqual(x9A.N, x9B.N);
+                    AssertOptionalValuesAgree(x9A.GetSeed(), x9B.GetSeed());
+
+                    BigInteger k = new BigInteger(x9A.N.BitLength, secRand);
+                    ECPoint pA = x9A.G.Multiply(k);
+                    ECPoint pB = x9B.G.Multiply(k);
+                    AssertPointsEqual("Custom curve multiplication inconsistency", pA, pB);
+                }
+
+                if (x9A != null)
                 {
-                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9ECParameters);
+                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9A);
                 }
 
-                x9ECParameters = CustomNamedCurves.GetByName(name);
-                if (x9ECParameters != null)
+                if (x9B != null)
                 {
-                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9ECParameters);
+                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9B);
                 }
             }
         }
 
         private void AssertPointsEqual(string message, ECPoint a, ECPoint b)
         {
+            // NOTE: We intentionally test points for equality in both directions
             Assert.AreEqual(a, b, message);
+            Assert.AreEqual(b, a, message);
+        }
+
+        private void AssertOptionalValuesAgree(object a, object b)
+        {
+            if (a != null && b != null)
+            {
+                Assert.AreEqual(a, b);
+            }
+        }
+
+        private void AssertOptionalValuesAgree(byte[] a, byte[] b)
+        {
+            if (a != null && b != null)
+            {
+                Assert.IsTrue(Arrays.AreEqual(a, b));
+            }
         }
     }
 }