summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-04-26 20:05:40 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-04-26 20:05:40 +0700
commit8e23b0e1a4e8394bc68e2de9e6bb636a7aeef059 (patch)
tree5c1504fb86edacf761fdd776f79d8a5be31e257f
parentSparkleDigest perf. opts. (Sse2) (diff)
downloadBouncyCastle.NET-ed25519-8e23b0e1a4e8394bc68e2de9e6bb636a7aeef059.tar.xz
Refactor AsconTest
-rw-r--r--crypto/src/crypto/engines/AsconEngine.cs13
-rw-r--r--crypto/test/src/crypto/test/AsconTest.cs823
2 files changed, 557 insertions, 279 deletions
diff --git a/crypto/src/crypto/engines/AsconEngine.cs b/crypto/src/crypto/engines/AsconEngine.cs
index 4bda8a02a..fc38764d1 100644
--- a/crypto/src/crypto/engines/AsconEngine.cs
+++ b/crypto/src/crypto/engines/AsconEngine.cs
@@ -99,15 +99,9 @@ namespace Org.BouncyCastle.Crypto.Engines
             m_buf = new byte[m_bufferSizeDecrypt];
         }
 
-        public int GetKeyBytesSize()
-        {
-            return CRYPTO_KEYBYTES;
-        }
+        public int GetKeyBytesSize() => CRYPTO_KEYBYTES;
 
-        public int GetIVBytesSize()
-        {
-            return CRYPTO_ABYTES;
-        }
+        public int GetIVBytesSize() => CRYPTO_ABYTES;
 
         public string AlgorithmName => algorithmName;
 
@@ -1060,6 +1054,9 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
+#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
         private static ulong PAD(int i)
         {
             return 0x8000000000000000UL >> (i << 3);
diff --git a/crypto/test/src/crypto/test/AsconTest.cs b/crypto/test/src/crypto/test/AsconTest.cs
index 313f7d45e..eabf7e043 100644
--- a/crypto/test/src/crypto/test/AsconTest.cs
+++ b/crypto/test/src/crypto/test/AsconTest.cs
@@ -15,164 +15,347 @@ namespace Org.BouncyCastle.Crypto.Tests
 {
     [TestFixture]
     public class AsconTest
-        : SimpleTest
     {
-        public override string Name => "ASCON";
+        [Test, Explicit]
+        public void BenchDigest_AsconHash()
+        {
+            ImplBenchDigest(AsconDigest.AsconParameters.AsconHash);
+        }
+
+        [Test, Explicit]
+        public void BenchDigest_AsconHashA()
+        {
+            ImplBenchDigest(AsconDigest.AsconParameters.AsconHashA);
+        }
+
+        [Test, Explicit]
+        public void BenchEngineAuth_ascon128()
+        {
+            ImplBenchEngineAuth(AsconEngine.AsconParameters.ascon128);
+        }
+
+        [Test, Explicit]
+        public void BenchEngineAuth_ascon128a()
+        {
+            ImplBenchEngineAuth(AsconEngine.AsconParameters.ascon128a);
+        }
+
+        [Test, Explicit]
+        public void BenchEngineAuth_ascon80pq()
+        {
+            ImplBenchEngineAuth(AsconEngine.AsconParameters.ascon80pq);
+        }
+
+        [Test, Explicit]
+        public void BenchEngineDecrypt_ascon128()
+        {
+            ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon128, false);
+        }
+
+        [Test, Explicit]
+        public void BenchEngineDecrypt_ascon128a()
+        {
+            ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon128a, false);
+        }
 
         [Test, Explicit]
-        public void BenchAuth80pq()
+        public void BenchEngineDecrypt_ascon80pq()
+        {
+            ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon80pq, false);
+        }
+
+        [Test, Explicit]
+        public void BenchEngineEncrypt_ascon128()
+        {
+            ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon128, true);
+        }
+
+        [Test, Explicit]
+        public void BenchEngineEncrypt_ascon128a()
+        {
+            ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon128a, true);
+        }
+
+        [Test, Explicit]
+        public void BenchEngineEncrypt_ascon80pq()
+        {
+            ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon80pq, true);
+        }
+
+        [Test, Explicit]
+        public void BenchXof_AsconXof()
+        {
+            ImplBenchXof(AsconXof.AsconParameters.AsconXof);
+        }
+
+        [Test, Explicit]
+        public void BenchXof_AsconXofA()
+        {
+            ImplBenchXof(AsconXof.AsconParameters.AsconXofA);
+        }
+
+        [Test]
+        public void TestExceptionsDigest_AsconHash()
+        {
+            ImplTestExceptionsDigest(AsconDigest.AsconParameters.AsconHash);
+        }
+
+        [Test]
+        public void TestExceptionsDigest_AsconHashA()
+        {
+            ImplTestExceptionsDigest(AsconDigest.AsconParameters.AsconHashA);
+        }
+
+        [Test]
+        public void TestExceptionsEngine_ascon128()
+        {
+            ImplTestExceptionsEngine(AsconEngine.AsconParameters.ascon128);
+        }
+
+        [Test]
+        public void TestExceptionsEngine_ascon128a()
+        {
+            ImplTestExceptionsEngine(AsconEngine.AsconParameters.ascon128a);
+        }
+
+        [Test]
+        public void TestExceptionsEngine_ascon80pq()
+        {
+            ImplTestExceptionsEngine(AsconEngine.AsconParameters.ascon80pq);
+        }
+
+        [Test]
+        public void TestExceptionsXof_AsconXof()
+        {
+            ImplTestExceptionsXof(AsconXof.AsconParameters.AsconXof);
+        }
+
+        [Test]
+        public void TestExceptionsXof_AsconXofA()
+        {
+            ImplTestExceptionsXof(AsconXof.AsconParameters.AsconXofA);
+        }
+
+        [Test]
+        public void TestParametersDigest_AsconHash()
+        {
+            ImplTestParametersDigest(AsconDigest.AsconParameters.AsconHash, 32);
+        }
+
+        [Test]
+        public void TestParametersDigest_AsconHashA()
+        {
+            ImplTestParametersDigest(AsconDigest.AsconParameters.AsconHashA, 32);
+        }
+
+        [Test]
+        public void TestParametersEngine_ascon128()
+        {
+            ImplTestParametersEngine(AsconEngine.AsconParameters.ascon128, 16, 16, 16);
+        }
+
+        [Test]
+        public void TestParametersEngine_ascon128a()
+        {
+            ImplTestParametersEngine(AsconEngine.AsconParameters.ascon128a, 16, 16, 16);
+        }
+
+        [Test]
+        public void TestParametersEngine_ascon80pq()
+        {
+            ImplTestParametersEngine(AsconEngine.AsconParameters.ascon80pq, 20, 16, 16);
+        }
+
+        [Test]
+        public void TestParametersXof_AsconXof()
+        {
+            ImplTestParametersXof(AsconXof.AsconParameters.AsconXof, 32);
+        }
+
+        [Test]
+        public void TestParametersXof_AsconXofA()
+        {
+            ImplTestParametersXof(AsconXof.AsconParameters.AsconXofA, 32);
+        }
+
+        [Test]
+        public void TestVectorsDigest_AsconHash()
+        {
+            ImplTestVectorsDigest(AsconDigest.AsconParameters.AsconHash, "asconhash");
+        }
+
+        [Test]
+        public void TestVectorsDigest_AsconHashA()
+        {
+            ImplTestVectorsDigest(AsconDigest.AsconParameters.AsconHashA, "asconhasha");
+        }
+
+        [Test]
+        public void TestVectorsEngine_ascon128()
+        {
+            ImplTestVectorsEngine(AsconEngine.AsconParameters.ascon128, "128_128");
+        }
+
+        [Test]
+        public void TestVectorsEngine_ascon128a()
+        {
+            ImplTestVectorsEngine(AsconEngine.AsconParameters.ascon128a, "128_128_a");
+        }
+
+        [Test]
+        public void TestVectorsEngine_ascon80pq()
+        {
+            ImplTestVectorsEngine(AsconEngine.AsconParameters.ascon80pq, "160_128");
+        }
+
+        [Test]
+        public void TestVectorsXof_AsconXof()
         {
-            var parameters = new AeadParameters(new KeyParameter(new byte[20]), 128, new byte[16], null);
-            var engine = new AsconEngine(AsconEngine.AsconParameters.ascon80pq);
-            engine.Init(false, parameters);
+            ImplTestVectorsXof(AsconXof.AsconParameters.AsconXof, "asconxof");
+        }
+
+        [Test]
+        public void TestVectorsXof_AsconXofA()
+        {
+            ImplTestVectorsXof(AsconXof.AsconParameters.AsconXofA, "asconxofa");
+        }
+
+        private static AsconDigest CreateDigest(AsconDigest.AsconParameters asconParameters)
+        {
+            return new AsconDigest(asconParameters);
+        }
+
+        private static AsconEngine CreateEngine(AsconEngine.AsconParameters asconParameters)
+        {
+            return new AsconEngine(asconParameters);
+        }
+
+        private static AsconXof CreateXof(AsconXof.AsconParameters asconParameters)
+        {
+            return new AsconXof(asconParameters);
+        }
+
+        private static void ImplBenchDigest(AsconDigest.AsconParameters asconParameters)
+        {
+            var ascon = CreateDigest(asconParameters);
 
             byte[] data = new byte[1024];
-            for (int i = 0; i < 1024 * 1024; ++i)
+            for (int i = 0; i < 1024; ++i)
             {
-#if NET6_0_OR_GREATER
-                engine.ProcessAadBytes(data.AsSpan(0, 1024));
+                for (int j = 0; j < 1024; ++j)
+                {
+                    // NOTE: .NET Core 3.1 has Span<T>, but is tested against our .NET Standard 2.0 assembly.
+//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                    ascon.BlockUpdate(data);
+#else
+                    ascon.BlockUpdate(data, 0, 1024);
+#endif
+                }
+
+                // NOTE: .NET Core 3.1 has Span<T>, but is tested against our .NET Standard 2.0 assembly.
+//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ascon.DoFinal(data);
 #else
-                engine.ProcessAadBytes(data, 0, 1024);
+                ascon.DoFinal(data, 0);
 #endif
             }
         }
 
-        [Test, Explicit]
-        public void BenchDecrypt80pq()
+        private static void ImplBenchEngineAuth(AsconEngine.AsconParameters asconParameters)
         {
-            var parameters = new AeadParameters(new KeyParameter(new byte[20]), 128, new byte[16], null);
-            var engine = new AsconEngine(AsconEngine.AsconParameters.ascon80pq);
-            engine.Init(false, parameters);
+            var ascon = CreateEngine(asconParameters);
+            InitEngine(ascon, true);
 
             byte[] data = new byte[1024];
             for (int i = 0; i < 1024 * 1024; ++i)
             {
-#if NET6_0_OR_GREATER
-                engine.ProcessBytes(data.AsSpan(0, 1024), data);
+                // NOTE: .NET Core 3.1 has Span<T>, but is tested against our .NET Standard 2.0 assembly.
+//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ascon.ProcessAadBytes(data);
 #else
-                engine.ProcessBytes(data, 0, 1024, data, 0);
+                ascon.ProcessAadBytes(data, 0, 1024);
 #endif
             }
         }
 
-        [Test, Explicit]
-        public void BenchEncrypt80pq()
+        private static void ImplBenchEngineCrypt(AsconEngine.AsconParameters asconParameters, bool forEncryption)
         {
-            var parameters = new AeadParameters(new KeyParameter(new byte[20]), 128, new byte[16], null);
-            var engine = new AsconEngine(AsconEngine.AsconParameters.ascon80pq);
-            engine.Init(true, parameters);
+            var ascon = CreateEngine(asconParameters);
+            InitEngine(ascon, forEncryption);
 
-            byte[] data = new byte[engine.GetUpdateOutputSize(1024)];
+            byte[] data = new byte[1024 + 64];
             for (int i = 0; i < 1024 * 1024; ++i)
             {
-#if NET6_0_OR_GREATER
-                engine.ProcessBytes(data.AsSpan(0, 1024), data);
+                // NOTE: .NET Core 3.1 has Span<T>, but is tested against our .NET Standard 2.0 assembly.
+//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ascon.ProcessBytes(data.AsSpan(0, 1024), data);
 #else
-                engine.ProcessBytes(data, 0, 1024, data, 0);
+                ascon.ProcessBytes(data, 0, 1024, data, 0);
 #endif
             }
         }
 
-        [Test]
-        public override void PerformTest()
+        private static void ImplBenchXof(AsconXof.AsconParameters asconParameters)
         {
-            ImplTestVectorsHash(AsconDigest.AsconParameters.AsconHashA, "asconhasha");
-            ImplTestVectorsHash(AsconDigest.AsconParameters.AsconHash, "asconhash");
-            ImplTestVectorsXof(AsconXof.AsconParameters.AsconXof, "asconxof");
-            ImplTestVectorsXof(AsconXof.AsconParameters.AsconXofA, "asconxofa");
-
-            ImplTestExceptions(new AsconDigest(AsconDigest.AsconParameters.AsconHashA), 32);
-            ImplTestExceptions(new AsconDigest(AsconDigest.AsconParameters.AsconHash), 32);
-            ImplTestExceptions(new AsconXof(AsconXof.AsconParameters.AsconXof), 32);
-            ImplTestExceptions(new AsconXof(AsconXof.AsconParameters.AsconXofA), 32);
-
-            AsconEngine asconEngine = new AsconEngine(AsconEngine.AsconParameters.ascon80pq);
-            ImplTestExceptions(asconEngine);
-            ImplTestParameters(asconEngine, 20, 16, 16);
-
-            asconEngine = new AsconEngine(AsconEngine.AsconParameters.ascon128a);
-            ImplTestExceptions(asconEngine);
-            ImplTestParameters(asconEngine, 16, 16, 16);
+            var ascon = CreateXof(asconParameters);
 
-            asconEngine = new AsconEngine(AsconEngine.AsconParameters.ascon128);
-            ImplTestExceptions(asconEngine);
-            ImplTestParameters(asconEngine, 16, 16, 16);
-
-            ImplTestVectors(AsconEngine.AsconParameters.ascon80pq, "160_128");
-            ImplTestVectors(AsconEngine.AsconParameters.ascon128a, "128_128_a");
-            ImplTestVectors(AsconEngine.AsconParameters.ascon128, "128_128");
-        }
-
-        private void ImplTestVectors(AsconEngine.AsconParameters asconParameters, string filename)
-        {
-            Random random = new Random();
-            AsconEngine asconEngine = new AsconEngine(asconParameters);
-            var buf = new Dictionary<string, string>();
-            //TestSampler sampler = new TestSampler();
-            using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.ascon.LWC_AEAD_KAT_" + filename + ".txt")))
+            byte[] data = new byte[1024];
+            for (int i = 0; i < 1024; ++i)
             {
-                Dictionary<string, string> map = new Dictionary<string, string>();
-                string line;
-                while ((line = src.ReadLine()) != null)
+                for (int j = 0; j < 1024; ++j)
                 {
-                    var data = line.Split(' ');
-                    if (data.Length == 1)
-                    {
-                        byte[] key = Hex.Decode(map["Key"]);
-                        byte[] nonce = Hex.Decode(map["Nonce"]);
-                        byte[] ad = Hex.Decode(map["AD"]);
-                        byte[] pt = Hex.Decode(map["PT"]);
-                        byte[] ct = Hex.Decode(map["CT"]);
-                        map.Clear();
-
-                        var parameters = new ParametersWithIV(new KeyParameter(key), nonce);
-
-                        // Encrypt
-                        {
-                            asconEngine.Init(true, parameters);
-
-                            var rv = new byte[asconEngine.GetOutputSize(pt.Length)];
-                            random.NextBytes(rv); // should overwrite any existing data
-
-                            asconEngine.ProcessAadBytes(ad, 0, ad.Length);
-                            int len = asconEngine.ProcessBytes(pt, 0, pt.Length, rv, 0);
-                            len += asconEngine.DoFinal(rv, len);
-
-                            Assert.True(Arrays.AreEqual(rv, 0, len, ct, 0, ct.Length));
-                        }
+                    // NOTE: .NET Core 3.1 has Span<T>, but is tested against our .NET Standard 2.0 assembly.
+//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                    ascon.BlockUpdate(data);
+#else
+                    ascon.BlockUpdate(data, 0, 1024);
+#endif
+                }
 
-                        // Decrypt
-                        {
-                            asconEngine.Init(false, parameters);
+                // NOTE: .NET Core 3.1 has Span<T>, but is tested against our .NET Standard 2.0 assembly.
+//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                ascon.OutputFinal(data);
+#else
+                ascon.OutputFinal(data, 0, data.Length);
+#endif
+            }
+        }
 
-                            var rv = new byte[asconEngine.GetOutputSize(ct.Length)];
-                            random.NextBytes(rv); // should overwrite any existing data
+        private static void ImplTestExceptionsDigest(AsconDigest.AsconParameters asconParameters)
+        {
+            var ascon = new AsconDigest(asconParameters);
 
-                            asconEngine.ProcessAadBytes(ad, 0, ad.Length);
-                            int len = asconEngine.ProcessBytes(ct, 0, ct.Length, rv, 0);
-                            len += asconEngine.DoFinal(rv, len);
+            try
+            {
+                ascon.BlockUpdate(new byte[1], 1, 1);
+                Assert.Fail(ascon.AlgorithmName + ": input for BlockUpdate is too short");
+            }
+            catch (DataLengthException)
+            {
+                //expected
+            }
 
-                            Assert.True(Arrays.AreEqual(rv, 0, len, pt, 0, pt.Length));
-                        }
-                    }
-                    else
-                    {
-                        if (data.Length >= 3)
-                        {
-                            map[data[0].Trim()] = data[2].Trim();
-                        }
-                        else
-                        {
-                            map[data[0].Trim()] = "";
-                        }
-                    }
-                }
+            try
+            {
+                ascon.DoFinal(new byte[ascon.GetDigestSize() - 1], 2);
+                Assert.Fail(ascon.AlgorithmName + ": output for DoFinal is too short");
+            }
+            catch (OutputLengthException)
+            {
+                //expected
             }
         }
 
-        private void ImplTestExceptions(AsconEngine asconEngine)
+        private void ImplTestExceptionsEngine(AsconEngine.AsconParameters asconParameters)
         {
-            int keySize = asconEngine.GetKeyBytesSize(), ivSize = asconEngine.GetIVBytesSize();
+            var ascon = CreateEngine(asconParameters);
+            int keySize = ascon.GetKeyBytesSize(), ivSize = ascon.GetIVBytesSize();
             int offset;
             byte[] k = new byte[keySize];
             byte[] iv = new byte[ivSize];
@@ -180,8 +363,8 @@ namespace Org.BouncyCastle.Crypto.Tests
             var param = new ParametersWithIV(new KeyParameter(k), iv);
             try
             {
-                asconEngine.ProcessBytes(m, 0, m.Length, null, 0);
-                Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before ProcessBytes");
+                ascon.ProcessBytes(m, 0, m.Length, null, 0);
+                Assert.Fail(ascon.AlgorithmName + " needs to be initialized before ProcessBytes");
             }
             catch (InvalidOperationException)
             {
@@ -190,8 +373,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             try
             {
-                asconEngine.ProcessByte(0x00, null, 0);
-                Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before ProcessByte");
+                ascon.ProcessByte(0x00, null, 0);
+                Assert.Fail(ascon.AlgorithmName + " needs to be initialized before ProcessByte");
             }
             catch (InvalidOperationException)
             {
@@ -200,8 +383,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             try
             {
-                asconEngine.Reset();
-                Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before Reset");
+                ascon.Reset();
+                Assert.Fail(ascon.AlgorithmName + " needs to be initialized before Reset");
             }
             catch (InvalidOperationException)
             {
@@ -210,8 +393,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             try
             {
-                asconEngine.DoFinal(null, m.Length);
-                Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before DoFinal");
+                ascon.DoFinal(null, m.Length);
+                Assert.Fail(ascon.AlgorithmName + " needs to be initialized before DoFinal");
             }
             catch (InvalidOperationException)
             {
@@ -220,14 +403,14 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             try
             {
-                asconEngine.GetMac();
-                asconEngine.GetOutputSize(0);
-                asconEngine.GetUpdateOutputSize(0);
+                ascon.GetMac();
+                ascon.GetOutputSize(0);
+                ascon.GetUpdateOutputSize(0);
             }
             catch (InvalidOperationException)
             {
                 //expected
-                Assert.Fail(asconEngine.AlgorithmName + " functions can be called before initialization");
+                Assert.Fail(ascon.AlgorithmName + " functions can be called before initialization");
             }
 
             Random rand = new Random();
@@ -238,8 +421,8 @@ namespace Org.BouncyCastle.Crypto.Tests
             byte[] iv1 = new byte[randomNum];
             try
             {
-                asconEngine.Init(true, new ParametersWithIV(new KeyParameter(k1), iv));
-                Assert.Fail(asconEngine.AlgorithmName + " k size does not match");
+                ascon.Init(true, new ParametersWithIV(new KeyParameter(k1), iv));
+                Assert.Fail(ascon.AlgorithmName + " k size does not match");
             }
             catch (ArgumentException)
             {
@@ -247,25 +430,25 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
             try
             {
-                asconEngine.Init(true, new ParametersWithIV(new KeyParameter(k), iv1));
-                Assert.Fail(asconEngine.AlgorithmName + "iv size does not match");
+                ascon.Init(true, new ParametersWithIV(new KeyParameter(k), iv1));
+                Assert.Fail(ascon.AlgorithmName + "iv size does not match");
             }
             catch (ArgumentException)
             {
                 //expected
             }
 
-            asconEngine.Init(true, param);
-            byte[] c1 = new byte[asconEngine.GetOutputSize(m.Length)];
+            ascon.Init(true, param);
+            byte[] c1 = new byte[ascon.GetOutputSize(m.Length)];
             try
             {
-                asconEngine.DoFinal(c1, m.Length);
+                ascon.DoFinal(c1, m.Length);
             }
             catch (Exception)
             {
-                Assert.Fail(asconEngine.AlgorithmName + " allows no input for AAD and plaintext");
+                Assert.Fail(ascon.AlgorithmName + " allows no input for AAD and plaintext");
             }
-            byte[] mac2 = asconEngine.GetMac();
+            byte[] mac2 = ascon.GetMac();
             if (mac2 == null)
             {
                 Assert.Fail("mac should not be empty after DoFinal");
@@ -276,21 +459,21 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            asconEngine.ProcessAadByte(0x00);
-            byte[] mac1 = new byte[asconEngine.GetOutputSize(0)];
-            asconEngine.DoFinal(mac1, 0);
+            ascon.Init(true, param);
+            ascon.ProcessAadByte(0x00);
+            byte[] mac1 = new byte[ascon.GetOutputSize(0)];
+            ascon.DoFinal(mac1, 0);
             if (Arrays.AreEqual(mac1, mac2))
             {
                 Assert.Fail("mac should not match");
             }
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            asconEngine.ProcessByte(0, null, 0);
+            ascon.Init(true, param);
+            ascon.ProcessByte(0, null, 0);
             try
             {
-                asconEngine.ProcessAadByte(0x00);
+                ascon.ProcessAadByte(0x00);
                 Assert.Fail("ProcessAadByte cannot be called after encryption/decryption");
             }
             catch (InvalidOperationException)
@@ -299,7 +482,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
             try
             {
-                asconEngine.ProcessAadBytes(new byte[1], 0, 1);
+                ascon.ProcessAadBytes(new byte[1], 0, 1);
                 Assert.Fail("ProcessAadBytes cannot be called after encryption/decryption");
             }
             catch (InvalidOperationException)
@@ -308,10 +491,10 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
+            ascon.Init(true, param);
             try
             {
-                asconEngine.ProcessAadBytes(new byte[1], 1, 1);
+                ascon.ProcessAadBytes(new byte[1], 1, 1);
                 Assert.Fail("input for ProcessAadBytes is too short");
             }
             catch (DataLengthException)
@@ -320,28 +503,16 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
             try
             {
-                asconEngine.ProcessBytes(new byte[1], 1, 1, c1, 0);
+                ascon.ProcessBytes(new byte[1], 1, 1, c1, 0);
                 Assert.Fail("input for ProcessBytes is too short");
             }
             catch (DataLengthException)
             {
                 //expected
             }
-
-            try
-            {
-                int inputSize = rand.Next(32, 64);
-                int outputSize = asconEngine.GetUpdateOutputSize(inputSize);
-                asconEngine.ProcessBytes(new byte[inputSize], 0, inputSize, new byte[outputSize], 1);
-                Assert.Fail("output for ProcessBytes is too short");
-            }
-            catch (OutputLengthException)
-            {
-                //expected
-            }
             try
             {
-                asconEngine.DoFinal(new byte[2], 2);
+                ascon.DoFinal(new byte[2], 2);
                 Assert.Fail("output for DoFinal is too short");
             }
             catch (OutputLengthException)
@@ -349,19 +520,22 @@ namespace Org.BouncyCastle.Crypto.Tests
                 //expected
             }
 
-            mac1 = new byte[asconEngine.GetOutputSize(0)];
-            mac2 = new byte[asconEngine.GetOutputSize(0)];
+            ImplTestExceptionsGetUpdateOutputSize(ascon, false, param, 100);
+            ImplTestExceptionsGetUpdateOutputSize(ascon, true, param, 100);
+
+            mac1 = new byte[ascon.GetOutputSize(0)];
+            mac2 = new byte[ascon.GetOutputSize(0)];
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            asconEngine.ProcessAadBytes(new byte[2], 0, 2);
-            asconEngine.DoFinal(mac1, 0);
+            ascon.Init(true, param);
+            ascon.ProcessAadBytes(new byte[2], 0, 2);
+            ascon.DoFinal(mac1, 0);
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            asconEngine.ProcessAadByte(0x00);
-            asconEngine.ProcessAadByte(0x00);
-            asconEngine.DoFinal(mac2, 0);
+            ascon.Init(true, param);
+            ascon.ProcessAadByte(0x00);
+            ascon.ProcessAadByte(0x00);
+            ascon.DoFinal(mac2, 0);
 
             if (!Arrays.AreEqual(mac1, mac2))
             {
@@ -373,20 +547,20 @@ namespace Org.BouncyCastle.Crypto.Tests
             byte[] m2 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
             byte[] m3 = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
             byte[] m4 = new byte[m2.Length];
-            byte[] c2 = new byte[asconEngine.GetOutputSize(m2.Length)];
-            byte[] c3 = new byte[asconEngine.GetOutputSize(m3.Length)];
+            byte[] c2 = new byte[ascon.GetOutputSize(m2.Length)];
+            byte[] c3 = new byte[ascon.GetOutputSize(m3.Length)];
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
-            offset = asconEngine.ProcessBytes(m2, 0, m2.Length, c2, 0);
-            asconEngine.DoFinal(c2, offset);
+            ascon.Init(true, param);
+            ascon.ProcessAadBytes(aad2, 0, aad2.Length);
+            offset = ascon.ProcessBytes(m2, 0, m2.Length, c2, 0);
+            ascon.DoFinal(c2, offset);
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            asconEngine.ProcessAadBytes(aad3, 1, aad2.Length);
-            offset = asconEngine.ProcessBytes(m3, 1, m2.Length, c3, 1);
-            asconEngine.DoFinal(c3, offset + 1);
+            ascon.Init(true, param);
+            ascon.ProcessAadBytes(aad3, 1, aad2.Length);
+            offset = ascon.ProcessBytes(m3, 1, m2.Length, c3, 1);
+            ascon.DoFinal(c3, offset + 1);
 
             byte[] c3_partial = new byte[c2.Length];
             Array.Copy(c3, 1, c3_partial, 0, c2.Length);
@@ -395,10 +569,10 @@ namespace Org.BouncyCastle.Crypto.Tests
                 Assert.Fail("mac should match for the same AAD and message with different offset for both input and output");
             }
 
-            asconEngine.Init(false, param);
-            asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
-            offset = asconEngine.ProcessBytes(c2, 0, c2.Length, m4, 0);
-            asconEngine.DoFinal(m4, offset);
+            ascon.Init(false, param);
+            ascon.ProcessAadBytes(aad2, 0, aad2.Length);
+            offset = ascon.ProcessBytes(c2, 0, c2.Length, m4, 0);
+            ascon.DoFinal(m4, offset);
             if (!Arrays.AreEqual(m2, m4))
             {
                 Assert.Fail("The encryption and decryption does not recover the plaintext");
@@ -406,11 +580,11 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             c2[c2.Length - 1] ^= 1;
 
-            asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
-            offset = asconEngine.ProcessBytes(c2, 0, c2.Length, m4, 0);
+            ascon.ProcessAadBytes(aad2, 0, aad2.Length);
+            offset = ascon.ProcessBytes(c2, 0, c2.Length, m4, 0);
             try
             {
-                asconEngine.DoFinal(m4, offset);
+                ascon.DoFinal(m4, offset);
                 Assert.Fail("The decryption should fail");
             }
             catch (InvalidCipherTextException)
@@ -423,51 +597,52 @@ namespace Org.BouncyCastle.Crypto.Tests
             rand.NextBytes(m7);
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            byte[] c7 = new byte[asconEngine.GetOutputSize(m7.Length)];
+            ascon.Init(true, param);
+            byte[] c7 = new byte[ascon.GetOutputSize(m7.Length)];
             byte[] c8 = new byte[c7.Length];
             byte[] c9 = new byte[c7.Length];
-            asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
-            offset = asconEngine.ProcessBytes(m7, 0, m7.Length, c7, 0);
-            offset += asconEngine.DoFinal(c7, offset);
+            ascon.ProcessAadBytes(aad2, 0, aad2.Length);
+            offset = ascon.ProcessBytes(m7, 0, m7.Length, c7, 0);
+            offset += ascon.DoFinal(c7, offset);
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
-            offset = asconEngine.ProcessBytes(m7, 0, m7.Length / 2, c8, 0);
-            offset += asconEngine.ProcessBytes(m7, m7.Length / 2, m7.Length - m7.Length / 2, c8, offset);
-            offset += asconEngine.DoFinal(c8, offset);
+            ascon.Init(true, param);
+            ascon.ProcessAadBytes(aad2, 0, aad2.Length);
+            offset = ascon.ProcessBytes(m7, 0, m7.Length / 2, c8, 0);
+            offset += ascon.ProcessBytes(m7, m7.Length / 2, m7.Length - m7.Length / 2, c8, offset);
+            offset += ascon.DoFinal(c8, offset);
 
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
+            ascon.Init(true, param);
             int split = rand.Next(1, m7.Length);
-            asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
-            offset = asconEngine.ProcessBytes(m7, 0, split, c9, 0);
-            offset += asconEngine.ProcessBytes(m7, split, m7.Length - split, c9, offset);
-            offset += asconEngine.DoFinal(c9, offset);
+            ascon.ProcessAadBytes(aad2, 0, aad2.Length);
+            offset = ascon.ProcessBytes(m7, 0, split, c9, 0);
+            offset += ascon.ProcessBytes(m7, split, m7.Length - split, c9, offset);
+            offset += ascon.DoFinal(c9, offset);
             if (!Arrays.AreEqual(c7, c8) || !Arrays.AreEqual(c7, c9))
             {
                 Assert.Fail("Splitting input of plaintext should output the same ciphertext");
             }
+
             // NOTE: .NET Core 3.1 has Span<T>, but is tested against our .NET Standard 2.0 assembly.
-            //#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
 #if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             // TODO Maybe use a different IV for this
-            asconEngine.Init(true, param);
-            Span<byte> c4 = new byte[asconEngine.GetOutputSize(m2.Length)];
-            asconEngine.ProcessAadBytes(aad2);
-            offset = asconEngine.ProcessBytes(m2, c4);
-            offset += asconEngine.DoFinal(c4[offset..]);
+            ascon.Init(true, param);
+            Span<byte> c4 = new byte[ascon.GetOutputSize(m2.Length)];
+            ascon.ProcessAadBytes(aad2);
+            offset = ascon.ProcessBytes(m2, c4);
+            offset += ascon.DoFinal(c4[offset..]);
             if (!c4[..offset].SequenceEqual(c2))
             {
                 Assert.Fail("Encryption should match for the same AAD and message with/without Span-based API");
             }
 
-            asconEngine.Init(false, param);
+            ascon.Init(false, param);
             Span<byte> m6 = new byte[m2.Length];
-            asconEngine.ProcessAadBytes(aad2);
-            offset = asconEngine.ProcessBytes(c2, m6);
-            offset += asconEngine.DoFinal(m6[offset..]);
+            ascon.ProcessAadBytes(aad2);
+            offset = ascon.ProcessBytes(c2, m6);
+            offset += ascon.DoFinal(m6[offset..]);
             if (!m6[..offset].SequenceEqual(m2))
             {
                 Assert.Fail("Decryption should match for the same AAD and message with/without Span-based API");
@@ -475,27 +650,106 @@ namespace Org.BouncyCastle.Crypto.Tests
 #endif
         }
 
-        private void ImplTestParameters(AsconEngine asconEngine, int keySize, int ivSize, int macSize)
+        private static void ImplTestExceptionsGetUpdateOutputSize(AsconEngine ascon, bool forEncryption,
+            ICipherParameters parameters, int maxInputSize)
+        {
+            // TODO Maybe use a different IV for this
+            ascon.Init(forEncryption, parameters);
+
+            int maxOutputSize = ascon.GetUpdateOutputSize(maxInputSize);
+
+            byte[] input = new byte[maxInputSize];
+            byte[] output = new byte[maxOutputSize];
+
+            for (int inputSize = 0; inputSize <= maxInputSize; ++inputSize)
+            {
+                // TODO Maybe use a different IV for this
+                ascon.Init(forEncryption, parameters);
+
+                int outputSize = ascon.GetUpdateOutputSize(inputSize);
+                if (outputSize > 0)
+                {
+                    try
+                    {
+                        ascon.ProcessBytes(input, 0, inputSize, output, maxOutputSize - outputSize + 1);
+                        Assert.Fail("output for ProcessBytes is too short");
+                    }
+                    catch (OutputLengthException)
+                    {
+                        //expected
+                    }
+                }
+                else
+                {
+                    ascon.ProcessBytes(input, 0, inputSize, null, 0);
+                }
+            }
+        }
+
+        private static void ImplTestExceptionsXof(AsconXof.AsconParameters asconParameters)
+        {
+            var ascon = CreateXof(asconParameters);
+
+            try
+            {
+                ascon.BlockUpdate(new byte[1], 1, 1);
+                Assert.Fail(ascon.AlgorithmName + ": input for BlockUpdate is too short");
+            }
+            catch (DataLengthException)
+            {
+                //expected
+            }
+
+            try
+            {
+                ascon.DoFinal(new byte[ascon.GetDigestSize() - 1], 2);
+                Assert.Fail(ascon.AlgorithmName + ": output for DoFinal is too short");
+            }
+            catch (OutputLengthException)
+            {
+                //expected
+            }
+        }
+
+        private static void ImplTestParametersDigest(AsconDigest.AsconParameters asconParameters, int digestSize)
+        {
+            var ascon = CreateDigest(asconParameters);
+
+            Assert.AreEqual(digestSize, ascon.GetDigestSize(), ascon.AlgorithmName + ": digest size is not correct");
+        }
+
+        private static void ImplTestParametersEngine(AsconEngine.AsconParameters asconParameters, int keySize,
+            int ivSize, int macSize)
         {
-            Assert.AreEqual(keySize, asconEngine.GetKeyBytesSize(),
-                "key bytes of " + asconEngine.AlgorithmName + " is not correct");
-            Assert.AreEqual(ivSize, asconEngine.GetIVBytesSize(),
-                "iv bytes of " + asconEngine.AlgorithmName + " is not correct");
+            var ascon = CreateEngine(asconParameters);
+
+            Assert.AreEqual(keySize, ascon.GetKeyBytesSize(),
+                "key bytes of " + ascon.AlgorithmName + " is not correct");
+            Assert.AreEqual(ivSize, ascon.GetIVBytesSize(),
+                "iv bytes of " + ascon.AlgorithmName + " is not correct");
 
             var parameters = new ParametersWithIV(new KeyParameter(new byte[keySize]), new byte[ivSize]);
+            ascon.Init(true, parameters);
 
-            asconEngine.Init(true, parameters);
-            Assert.AreEqual(macSize, asconEngine.GetOutputSize(0),
-                "GetOutputSize of " + asconEngine.AlgorithmName + " is incorrect for encryption");
+            Assert.AreEqual(macSize, ascon.GetOutputSize(0),
+                "GetOutputSize of " + ascon.AlgorithmName + " is incorrect for encryption");
 
-            asconEngine.Init(false, parameters);
-            Assert.AreEqual(0, asconEngine.GetOutputSize(macSize),
-                "GetOutputSize of " + asconEngine.AlgorithmName + " is incorrect for decryption");
+            ascon.Init(false, parameters);
+            Assert.AreEqual(0, ascon.GetOutputSize(macSize),
+                "GetOutputSize of " + ascon.AlgorithmName + " is incorrect for decryption");
         }
 
-        private void ImplTestVectorsHash(AsconDigest.AsconParameters asconParameters, string filename)
+        private static void ImplTestParametersXof(AsconXof.AsconParameters asconParameters, int digestSize)
         {
-            AsconDigest ascon = new AsconDigest(asconParameters);
+            var ascon = CreateXof(asconParameters);
+
+            Assert.AreEqual(digestSize, ascon.GetDigestSize(),
+                ascon.AlgorithmName + ": digest size is not correct");
+        }
+
+        private static void ImplTestVectorsDigest(AsconDigest.AsconParameters asconParameters, string filename)
+        {
+            var ascon = CreateDigest(asconParameters);
             var map = new Dictionary<string, string>();
             using (var src = new StreamReader(
                 SimpleTest.GetTestDataAsStream("crypto.ascon." + filename + "_LWC_HASH_KAT_256.txt")))
@@ -530,7 +784,74 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
         }
 
-        private void ImplTestVectorsXof(AsconXof.AsconParameters asconParameters, string filename)
+        private static void ImplTestVectorsEngine(AsconEngine.AsconParameters asconParameters, string filename)
+        {
+            Random random = new Random();
+            var asconEngine = CreateEngine(asconParameters);
+            var buf = new Dictionary<string, string>();
+            //TestSampler sampler = new TestSampler();
+            using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.ascon.LWC_AEAD_KAT_" + filename + ".txt")))
+            {
+                Dictionary<string, string> map = new Dictionary<string, string>();
+                string line;
+                while ((line = src.ReadLine()) != null)
+                {
+                    var data = line.Split(' ');
+                    if (data.Length == 1)
+                    {
+                        byte[] key = Hex.Decode(map["Key"]);
+                        byte[] nonce = Hex.Decode(map["Nonce"]);
+                        byte[] ad = Hex.Decode(map["AD"]);
+                        byte[] pt = Hex.Decode(map["PT"]);
+                        byte[] ct = Hex.Decode(map["CT"]);
+                        map.Clear();
+
+                        var parameters = new ParametersWithIV(new KeyParameter(key), nonce);
+
+                        // Encrypt
+                        {
+                            asconEngine.Init(true, parameters);
+
+                            var rv = new byte[asconEngine.GetOutputSize(pt.Length)];
+                            random.NextBytes(rv); // should overwrite any existing data
+
+                            asconEngine.ProcessAadBytes(ad, 0, ad.Length);
+                            int len = asconEngine.ProcessBytes(pt, 0, pt.Length, rv, 0);
+                            len += asconEngine.DoFinal(rv, len);
+
+                            Assert.True(Arrays.AreEqual(rv, 0, len, ct, 0, ct.Length));
+                        }
+
+                        // Decrypt
+                        {
+                            asconEngine.Init(false, parameters);
+
+                            var rv = new byte[asconEngine.GetOutputSize(ct.Length)];
+                            random.NextBytes(rv); // should overwrite any existing data
+
+                            asconEngine.ProcessAadBytes(ad, 0, ad.Length);
+                            int len = asconEngine.ProcessBytes(ct, 0, ct.Length, rv, 0);
+                            len += asconEngine.DoFinal(rv, len);
+
+                            Assert.True(Arrays.AreEqual(rv, 0, len, pt, 0, pt.Length));
+                        }
+                    }
+                    else
+                    {
+                        if (data.Length >= 3)
+                        {
+                            map[data[0].Trim()] = data[2].Trim();
+                        }
+                        else
+                        {
+                            map[data[0].Trim()] = "";
+                        }
+                    }
+                }
+            }
+        }
+
+        private static void ImplTestVectorsXof(AsconXof.AsconParameters asconParameters, string filename)
         {
             AsconXof ascon = new AsconXof(asconParameters);
             var buf = new Dictionary<string, string>();
@@ -568,54 +889,14 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
         }
 
-        private void ImplTestExceptions(AsconDigest asconDigest, int digestSize)
+        private static void InitEngine(AsconEngine ascon, bool forEncryption)
         {
-            Assert.AreEqual(digestSize, asconDigest.GetDigestSize(),
-                asconDigest.AlgorithmName + ": digest size is not correct");
+            int keySize = ascon.GetKeyBytesSize();
+            int ivSize = ascon.GetIVBytesSize();
+            int macSize = ivSize * 8;
 
-            try
-            {
-                asconDigest.BlockUpdate(new byte[1], 1, 1);
-                Assert.Fail(asconDigest.AlgorithmName + ": input for BlockUpdate is too short");
-            }
-            catch (DataLengthException)
-            {
-                //expected
-            }
-            try
-            {
-                asconDigest.DoFinal(new byte[digestSize - 1], 2);
-                Assert.Fail(asconDigest.AlgorithmName + ": output for DoFinal is too short");
-            }
-            catch (OutputLengthException)
-            {
-                //expected
-            }
-        }
-
-        private void ImplTestExceptions(AsconXof asconXof, int digestSize)
-        {
-            Assert.AreEqual(digestSize, asconXof.GetDigestSize(),
-                asconXof.AlgorithmName + ": digest size is not correct");
-
-            try
-            {
-                asconXof.BlockUpdate(new byte[1], 1, 1);
-                Assert.Fail(asconXof.AlgorithmName + ": input for BlockUpdate is too short");
-            }
-            catch (DataLengthException)
-            {
-                //expected
-            }
-            try
-            {
-                asconXof.DoFinal(new byte[digestSize - 1], 2);
-                Assert.Fail(asconXof.AlgorithmName + ": output for DoFinal is too short");
-            }
-            catch (OutputLengthException)
-            {
-                //expected
-            }
+            var parameters = new AeadParameters(new KeyParameter(new byte[keySize]), macSize, new byte[ivSize], null);
+            ascon.Init(forEncryption, parameters);
         }
     }
 }