summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-02-13 16:00:19 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-02-13 16:00:19 +0700
commitc091f2d5eba02afa4dd5bedc30c8003a4631b970 (patch)
treeea2225ad4f8322ef1586995cafb9fd434dcfe01c
parentFix/refactor LWC algorithms (diff)
downloadBouncyCastle.NET-ed25519-c091f2d5eba02afa4dd5bedc30c8003a4631b970.tar.xz
Refactor LWC algorithms
-rw-r--r--crypto/src/crypto/digests/AsconDigest.cs32
-rw-r--r--crypto/src/crypto/digests/ISAPDigest.cs17
-rw-r--r--crypto/src/crypto/digests/PhotonBeetleDigest.cs61
-rw-r--r--crypto/src/crypto/digests/SparkleDigest.cs169
-rw-r--r--crypto/src/crypto/digests/XoodyakDigest.cs211
-rw-r--r--crypto/src/crypto/engines/ElephantEngine.cs71
-rw-r--r--crypto/src/crypto/engines/ISAPEngine.cs14
-rw-r--r--crypto/src/crypto/engines/PhotonBeetleEngine.cs44
-rw-r--r--crypto/src/crypto/engines/SparkleEngine.cs188
-rw-r--r--crypto/src/crypto/engines/XoodyakEngine.cs95
-rw-r--r--crypto/test/src/crypto/test/ElephantTest.cs2
-rw-r--r--crypto/test/src/crypto/test/ISAPTest.cs2
-rw-r--r--crypto/test/src/crypto/test/PhotonBeetleTest.cs2
-rw-r--r--crypto/test/src/crypto/test/SparkleTest.cs2
-rw-r--r--crypto/test/src/crypto/test/XoodyakTest.cs2
15 files changed, 423 insertions, 489 deletions
diff --git a/crypto/src/crypto/digests/AsconDigest.cs b/crypto/src/crypto/digests/AsconDigest.cs
index 343036b99..20d39ce77 100644
--- a/crypto/src/crypto/digests/AsconDigest.cs
+++ b/crypto/src/crypto/digests/AsconDigest.cs
@@ -8,6 +8,11 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
+    /// <summary>ASCON v1.2 Hash, https://ascon.iaik.tugraz.at/ .</summary>
+    /// <remarks>
+    /// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/ascon-spec-final.pdf<br/>
+    /// ASCON v1.2 Hash with reference to C Reference Impl from: https://github.com/ascon/ascon-c .
+    /// </remarks>
     public sealed class AsconDigest
         : IDigest
     {
@@ -247,15 +252,18 @@ namespace Org.BouncyCastle.Crypto.Digests
 
         private void P(int nr)
         {
-            if (nr == 12)
+            //if (nr >= 8)
             {
-                ROUND(0xf0UL);
-                ROUND(0xe1UL);
-                ROUND(0xd2UL);
-                ROUND(0xc3UL);
+                if (nr == 12)
+                {
+                    ROUND(0xf0UL);
+                    ROUND(0xe1UL);
+                    ROUND(0xd2UL);
+                    ROUND(0xc3UL);
+                }
+                ROUND(0xb4UL);
+                ROUND(0xa5UL);
             }
-            ROUND(0xb4UL);
-            ROUND(0xa5UL);
             ROUND(0x96UL);
             ROUND(0x87UL);
             ROUND(0x78UL);
@@ -267,12 +275,12 @@ namespace Org.BouncyCastle.Crypto.Digests
 #if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
 #endif
-        private void ROUND(ulong C)
+        private void ROUND(ulong c)
         {
-            ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
-            ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
-            ulong t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
-            ulong t3 = x0 ^ x1 ^ x2 ^ C ^ (~x0 & (x3 ^ x4));
+            ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ c ^ (x1 & (x0 ^ x2 ^ x4 ^ c));
+            ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ c ^ ((x1 ^ x2 ^ c) & (x1 ^ x3));
+            ulong t2 = x1 ^ x2 ^ x4 ^ c ^ (x3 & x4);
+            ulong t3 = x0 ^ x1 ^ x2 ^ c ^ (~x0 & (x3 ^ x4));
             ulong t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
             x0 = t0 ^ Longs.RotateRight(t0, 19) ^ Longs.RotateRight(t0, 28);
             x1 = t1 ^ Longs.RotateRight(t1, 39) ^ Longs.RotateRight(t1, 61);
diff --git a/crypto/src/crypto/digests/ISAPDigest.cs b/crypto/src/crypto/digests/ISAPDigest.cs
index 348242e6e..83214fe6b 100644
--- a/crypto/src/crypto/digests/ISAPDigest.cs
+++ b/crypto/src/crypto/digests/ISAPDigest.cs
@@ -12,9 +12,8 @@ namespace Org.BouncyCastle.Crypto.Digests
     public sealed class IsapDigest
         : IDigest
     {
+        private readonly MemoryStream buffer = new MemoryStream();
         private ulong x0, x1, x2, x3, x4;
-        private ulong t0, t1, t2, t3, t4;
-        private MemoryStream buffer = new MemoryStream();
 
         public string AlgorithmName => "ISAP Hash";
 
@@ -48,8 +47,6 @@ namespace Org.BouncyCastle.Crypto.Digests
 #else
             Check.OutputLength(output, outOff, 32, "output buffer is too short");
 
-            t0 = t1 = t2 = t3 = t4 = 0;
-
             /* init state */
             x0 = 17191252062196199485UL;
             x1 = 10066134719181819906UL;
@@ -89,8 +86,6 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             Check.OutputLength(output, 32, "output buffer is too short");
 
-            t0 = t1 = t2 = t3 = t4 = 0;
-
             /* init state */
             x0 = 17191252062196199485UL;
             x1 = 10066134719181819906UL;
@@ -150,11 +145,11 @@ namespace Org.BouncyCastle.Crypto.Digests
 #endif
         private void ROUND(ulong C)
         {
-            t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
-            t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
-            t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
-            t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
-            t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+            ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
+            ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
+            ulong t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
+            ulong t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
+            ulong t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
             x0 = t0 ^ Longs.RotateRight(t0, 19) ^ Longs.RotateRight(t0, 28);
             x1 = t1 ^ Longs.RotateRight(t1, 39) ^ Longs.RotateRight(t1, 61);
             x2 = ~(t2 ^ Longs.RotateRight(t2, 1) ^ Longs.RotateRight(t2, 6));
diff --git a/crypto/src/crypto/digests/PhotonBeetleDigest.cs b/crypto/src/crypto/digests/PhotonBeetleDigest.cs
index 1af8aee2c..c7cbfdfca 100644
--- a/crypto/src/crypto/digests/PhotonBeetleDigest.cs
+++ b/crypto/src/crypto/digests/PhotonBeetleDigest.cs
@@ -12,7 +12,7 @@ namespace Org.BouncyCastle.Crypto.Digests
      * Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software
      * </p>
      */
-    public class PhotonBeetleDigest
+    public sealed class PhotonBeetleDigest
         : IDigest
     {
         private byte[] state;
@@ -64,7 +64,6 @@ namespace Org.BouncyCastle.Crypto.Digests
             }
         }
 
-
         public String AlgorithmName => "Photon-Beetle Hash";
 
         public int GetDigestSize() => TAG_INBYTES;
@@ -80,22 +79,24 @@ namespace Org.BouncyCastle.Crypto.Digests
             buffer.WriteByte(input);
         }
 
-        public void BlockUpdate(byte[] input, int inOff, int len)
+        public void BlockUpdate(byte[] input, int inOff, int inLen)
         {
-            if ((inOff + len) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-            buffer.Write(input, inOff, len);
+            Check.DataLength(input, inOff, inLen, "input buffer too short");
+
+            buffer.Write(input, inOff, inLen);
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            buffer.Write(input);
+        }
+#endif
 
         public int DoFinal(byte[] output, int outOff)
         {
-            if (32 + outOff > output.Length)
-            {
-                throw new OutputLengthException("output buffer is too short");
-            }
+            Check.OutputLength(output, outOff, 32, "output buffer is too short");
+
             byte[] input = buffer.GetBuffer();
             int inlen = (int)buffer.Length;
             if (inlen == 0)
@@ -120,11 +121,11 @@ namespace Org.BouncyCastle.Crypto.Digests
                 for (i = 0; i < Dlen_inblocks - 1; i++)
                 {
                     PHOTON_Permutation();
-                    XOR(input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, RATE_INBYTES);
+                    Bytes.XorTo(RATE_INBYTES, input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, state, 0);
                 }
                 PHOTON_Permutation();
                 LastDBlocklen = inlen - i * RATE_INBYTES;
-                XOR(input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, LastDBlocklen);
+                Bytes.XorTo(LastDBlocklen, input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, state, 0);
                 if (LastDBlocklen < RATE_INBYTES)
                 {
                     state[LastDBlocklen] ^= 0x01; // ozs
@@ -138,14 +139,15 @@ namespace Org.BouncyCastle.Crypto.Digests
             return TAG_INBYTES;
         }
 
-        void XOR(byte[] in_right, int rOff, int iolen_inbytes)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
         {
-            for (int i = 0; i < iolen_inbytes; i++)
-            {
-                state[i] ^= in_right[i + rOff];
-            }
+            byte[] rv = new byte[32];
+            int rlt = DoFinal(rv, 0);
+            rv.AsSpan(0, 32).CopyTo(output);
+            return rlt;
         }
-
+#endif
 
         public void Reset()
         {
@@ -153,7 +155,7 @@ namespace Org.BouncyCastle.Crypto.Digests
             Arrays.Fill(state, (byte)0);
         }
 
-        void PHOTON_Permutation()
+        private void PHOTON_Permutation()
         {
             int i, j, k, l;
             for (i = 0; i < DSquare; i++)
@@ -222,22 +224,5 @@ namespace Org.BouncyCastle.Crypto.Digests
                 state[i >> 1] = (byte)(((state_2d[i >> Dq][i & Dr] & 0xf)) | ((state_2d[i >> Dq][(i + 1) & Dr] & 0xf) << 4));
             }
         }
-
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-
-        public int DoFinal(Span<byte> output)
-        {
-            byte[] rv = new byte[32];
-            int rlt = DoFinal(rv, 0);
-            rv.AsSpan(0, 32).CopyTo(output);
-            return rlt;
-        }
-
-        public void BlockUpdate(ReadOnlySpan<byte> input)
-        {
-            buffer.Write(input.ToArray(), 0, input.Length);
-        }
-
-#endif
     }
 }
diff --git a/crypto/src/crypto/digests/SparkleDigest.cs b/crypto/src/crypto/digests/SparkleDigest.cs
index ad558effc..bd03fdf0d 100644
--- a/crypto/src/crypto/digests/SparkleDigest.cs
+++ b/crypto/src/crypto/digests/SparkleDigest.cs
@@ -12,7 +12,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     /// Specification:
     /// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/sparkle-spec-final.pdf .
     /// </remarks>
-    public class SparkleDigest
+    public sealed class SparkleDigest
         : IDigest
     {
         public enum SparkleParameters
@@ -21,9 +21,12 @@ namespace Org.BouncyCastle.Crypto.Digests
             ESCH384
         }
 
+        private static readonly uint[] RCON = { 0xB7E15162U, 0xBF715880U, 0x38B4DA56U, 0x324E7738U, 0xBB1185EBU,
+            0x4F7C7B57U, 0xCFBFA1C8U, 0xC2B3293DU };
+
         private string algorithmName;
         private readonly uint[] state;
-        private MemoryStream message = new MemoryStream();
+        private readonly MemoryStream message = new MemoryStream();
         private readonly int DIGEST_BYTES;
         private readonly int SPARKLE_STEPS_SLIM;
         private readonly int SPARKLE_STEPS_BIG;
@@ -64,85 +67,35 @@ namespace Org.BouncyCastle.Crypto.Digests
             state = new uint[STATE_WORDS];
         }
 
-        private uint ELL(uint x)
-        {
-            return Integers.RotateRight(x ^ (x << 16), 16);
-        }
+        public string AlgorithmName => algorithmName;
 
-        private static readonly uint[] RCON = {0xB7E15162, 0xBF715880, 0x38B4DA56, 0x324E7738, 0xBB1185EB, 0x4F7C7B57,
-        0xCFBFA1C8, 0xC2B3293D};
+        public int GetDigestSize() => DIGEST_BYTES;
 
-        void sparkle_opt(uint[] state, int brans, int steps)
+        public int GetByteLength() => RATE_BYTES;
+
+        public void Update(byte input)
         {
-            uint i, j, rc, tmpx, tmpy, x0, y0;
-            for (i = 0; i < steps; i++)
-            {
-                // Add round ant
-                state[1] ^= RCON[i & 7];
-                state[3] ^= i;
-                // ARXBOX layer
-                for (j = 0; j < 2 * brans; j += 2)
-                {
-                    rc = RCON[j >> 1];
-                    state[j] += Integers.RotateRight(state[j + 1], 31);
-                    state[j + 1] ^= Integers.RotateRight(state[j], 24);
-                    state[j] ^= rc;
-                    state[j] += Integers.RotateRight(state[j + 1], 17);
-                    state[j + 1] ^= Integers.RotateRight(state[j], 17);
-                    state[j] ^= rc;
-                    state[j] += state[j + 1];
-                    state[j + 1] ^= Integers.RotateRight(state[j], 31);
-                    state[j] ^= rc;
-                    state[j] += Integers.RotateRight(state[j + 1], 24);
-                    state[j + 1] ^= Integers.RotateRight(state[j], 16);
-                    state[j] ^= rc;
-                }
-                // Linear layer
-                tmpx = x0 = state[0];
-                tmpy = y0 = state[1];
-                for (j = 2; j < brans; j += 2)
-                {
-                    tmpx ^= state[j];
-                    tmpy ^= state[j + 1];
-                }
-                tmpx = ELL(tmpx);
-                tmpy = ELL(tmpy);
-                for (j = 2; j < brans; j += 2)
-                {
-                    state[j - 2] = state[j + brans] ^ state[j] ^ tmpy;
-                    state[j + brans] = state[j];
-                    state[j - 1] = state[j + brans + 1] ^ state[j + 1] ^ tmpx;
-                    state[j + brans + 1] = state[j + 1];
-                }
-                state[brans - 2] = state[brans] ^ x0 ^ tmpy;
-                state[brans] = x0;
-                state[brans - 1] = state[brans + 1] ^ y0 ^ tmpx;
-                state[brans + 1] = y0;
-            }
+            message.WriteByte(input);
         }
 
-        public int GetDigestSize()
+        public void BlockUpdate(byte[] input, int inOff, int inLen)
         {
-            return DIGEST_BYTES;
-        }
+            Check.DataLength(input, inOff, inLen, "input buffer too short");
 
+            message.Write(input, inOff, inLen);
+        }
 
-        public void BlockUpdate(byte[] input, int inOff, int len)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
         {
-            if (inOff + len > input.Length)
-            {
-                throw new DataLengthException(algorithmName + " input buffer too short");
-            }
-            message.Write(input, inOff, len);
+            message.Write(input);
         }
-
+#endif
 
         public int DoFinal(byte[] output, int outOff)
         {
-            if (outOff + DIGEST_BYTES > output.Length)
-            {
-                throw new OutputLengthException(algorithmName + " input buffer too short");
-            }
+            Check.OutputLength(output, outOff, DIGEST_BYTES, "output buffer too short");
+
             byte[] input = message.GetBuffer();
             int inlen = (int)message.Length, i, inOff = 0;
             uint tmpx, tmpy;
@@ -220,40 +173,80 @@ namespace Org.BouncyCastle.Crypto.Digests
                 outOff += RATE_BYTES;
             }
             return DIGEST_BYTES;
-        }
 
-        public string AlgorithmName => algorithmName;
+            // TODO Reset?
+        }
 
-        public void Update(byte input)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
         {
-            message.Write(new byte[] { input }, 0, 1);
+            byte[] rv = new byte[DIGEST_BYTES];
+            DoFinal(rv, 0);
+            // TODO Remove duplicate if added in other DoFinal
+            Reset();
+            rv.AsSpan(0, rv.Length).CopyTo(output);
+            return DIGEST_BYTES;
         }
+#endif
 
         public void Reset()
         {
             message.SetLength(0);
-            Arrays.Fill(state, (byte)0);
+            Arrays.Fill(state, 0U);
         }
 
-        public int GetByteLength()
+        private void sparkle_opt(uint[] state, int brans, int steps)
         {
-            return RATE_BYTES;
-        }
-
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public void BlockUpdate(ReadOnlySpan<byte> input)
-        {
-            message.Write(input);
+            uint i, j, rc, tmpx, tmpy, x0, y0;
+            for (i = 0; i < steps; i++)
+            {
+                // Add round ant
+                state[1] ^= RCON[i & 7];
+                state[3] ^= i;
+                // ARXBOX layer
+                for (j = 0; j < 2 * brans; j += 2)
+                {
+                    rc = RCON[j >> 1];
+                    state[j] += Integers.RotateRight(state[j + 1], 31);
+                    state[j + 1] ^= Integers.RotateRight(state[j], 24);
+                    state[j] ^= rc;
+                    state[j] += Integers.RotateRight(state[j + 1], 17);
+                    state[j + 1] ^= Integers.RotateRight(state[j], 17);
+                    state[j] ^= rc;
+                    state[j] += state[j + 1];
+                    state[j + 1] ^= Integers.RotateRight(state[j], 31);
+                    state[j] ^= rc;
+                    state[j] += Integers.RotateRight(state[j + 1], 24);
+                    state[j + 1] ^= Integers.RotateRight(state[j], 16);
+                    state[j] ^= rc;
+                }
+                // Linear layer
+                tmpx = x0 = state[0];
+                tmpy = y0 = state[1];
+                for (j = 2; j < brans; j += 2)
+                {
+                    tmpx ^= state[j];
+                    tmpy ^= state[j + 1];
+                }
+                tmpx = ELL(tmpx);
+                tmpy = ELL(tmpy);
+                for (j = 2; j < brans; j += 2)
+                {
+                    state[j - 2] = state[j + brans] ^ state[j] ^ tmpy;
+                    state[j + brans] = state[j];
+                    state[j - 1] = state[j + brans + 1] ^ state[j + 1] ^ tmpx;
+                    state[j + brans + 1] = state[j + 1];
+                }
+                state[brans - 2] = state[brans] ^ x0 ^ tmpy;
+                state[brans] = x0;
+                state[brans - 1] = state[brans + 1] ^ y0 ^ tmpx;
+                state[brans + 1] = y0;
+            }
         }
 
-        public int DoFinal(Span<byte> output)
+        private static uint ELL(uint x)
         {
-            byte[] rv=new byte[DIGEST_BYTES];
-            DoFinal(rv, 0);
-            Reset();
-            rv.AsSpan(0, rv.Length).CopyTo(output);
-            return DIGEST_BYTES;
+            return Integers.RotateRight(x ^ (x << 16), 16);
         }
-#endif
     }
 }
diff --git a/crypto/src/crypto/digests/XoodyakDigest.cs b/crypto/src/crypto/digests/XoodyakDigest.cs
index cf1afcc10..4836f4d2b 100644
--- a/crypto/src/crypto/digests/XoodyakDigest.cs
+++ b/crypto/src/crypto/digests/XoodyakDigest.cs
@@ -1,11 +1,25 @@
 using System;
 using System.IO;
+
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
-    public class XoodyakDigest : IDigest
+    public sealed class XoodyakDigest
+        : IDigest
     {
+        private enum MODE
+        {
+            ModeHash,
+            ModeKeyed
+        }
+
+        private const int Rkin = 44;
+
+        private static readonly uint[] RC = { 0x00000058U, 0x00000038U, 0x000003C0U, 0x000000D0U, 0x00000120U,
+            0x00000014U, 0x00000060U, 0x0000002CU, 0x00000380U, 0x000000F0U, 0x000001A0U, 0x00000012U };
+
         private byte[] state;
         private int phase;
         private MODE mode;
@@ -16,19 +30,11 @@ namespace Org.BouncyCastle.Crypto.Digests
         private const int PhaseUp = 2;
         private const int NLANES = 12;
         private const int NROWS = 3;
-        private const int NCOLUMS = 4;
+        private const int NCOLUMNS = 4;
         private const int MAXROUNDS = 12;
         private const int TAGLEN = 16;
         private const int Rhash = 16;
-        const int Rkin = 44;
-        private readonly uint[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060,
-        0x0000002C, 0x00000380, 0x000000F0, 0x000001A0, 0x00000012};
-        private MemoryStream buffer = new MemoryStream();
-        enum MODE
-        {
-            ModeHash,
-            ModeKeyed
-        }
+        private readonly MemoryStream buffer = new MemoryStream();
 
         public XoodyakDigest()
         {
@@ -38,6 +44,78 @@ namespace Org.BouncyCastle.Crypto.Digests
 
         public string AlgorithmName => "Xoodyak Hash";
 
+        public int GetDigestSize() => 32;
+
+        public int GetByteLength() => Rabsorb;
+
+        public void Update(byte input)
+        {
+            buffer.WriteByte(input);
+        }
+
+        public void BlockUpdate(byte[] input, int inOff, int inLen)
+        {
+            Check.DataLength(input, inOff, inLen, "input buffer too short");
+
+            buffer.Write(input, inOff, inLen);
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            buffer.Write(input);
+        }
+#endif
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            Check.OutputLength(output, outOff, 32, "output buffer is too short");
+
+            byte[] input = buffer.GetBuffer();
+            int inLen = (int)buffer.Length;
+            int inOff = 0;
+            uint Cd = 0x03;
+            int splitLen;
+            do
+            {
+                if (phase != PhaseUp)
+                {
+                    Up(null, 0, 0, 0);
+                }
+                splitLen = System.Math.Min(inLen, Rabsorb);
+                Down(input, inOff, splitLen, Cd);
+                Cd = 0;
+                inOff += splitLen;
+                inLen -= splitLen;
+            }
+            while (inLen != 0);
+            Up(output, outOff, TAGLEN, 0x40);
+            Down(null, 0, 0, 0);
+            Up(output, outOff + TAGLEN, TAGLEN, 0);
+            return 32;
+
+            // TODO Reset?
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            byte[] rv = new byte[32];
+            int rlt = DoFinal(rv, 0);
+            rv.AsSpan(0, 32).CopyTo(output);
+            return rlt;
+        }
+#endif
+
+        public void Reset()
+        {
+            Array.Clear(state, 0, state.Length);
+            phase = PhaseUp;
+            mode = MODE.ModeHash;
+            Rabsorb = Rhash;
+            buffer.SetLength(0);
+        }
+
         private void Up(byte[] Yi, int YiOff, int YiLen, uint Cu)
         {
             if (mode != MODE.ModeHash)
@@ -48,21 +126,21 @@ namespace Org.BouncyCastle.Crypto.Digests
             Pack.LE_To_UInt32(state, 0, a, 0, a.Length);
             uint x, y;
             uint[] b = new uint[NLANES];
-            uint[] p = new uint[NCOLUMS];
-            uint[] e = new uint[NCOLUMS];
+            uint[] p = new uint[NCOLUMNS];
+            uint[] e = new uint[NCOLUMNS];
             for (int i = 0; i < MAXROUNDS; ++i)
             {
                 /* Theta: Column Parity Mixer */
-                for (x = 0; x < NCOLUMS; ++x)
+                for (x = 0; x < NCOLUMNS; ++x)
                 {
                     p[x] = a[index(x, 0)] ^ a[index(x, 1)] ^ a[index(x, 2)];
                 }
-                for (x = 0; x < NCOLUMS; ++x)
+                for (x = 0; x < NCOLUMNS; ++x)
                 {
                     y = p[(x + 3) & 3];
-                    e[x] = ROTL32(y, 5) ^ ROTL32(y, 14);
+                    e[x] = Integers.RotateLeft(y, 5) ^ Integers.RotateLeft(y, 14);
                 }
-                for (x = 0; x < NCOLUMS; ++x)
+                for (x = 0; x < NCOLUMNS; ++x)
                 {
                     for (y = 0; y < NROWS; ++y)
                     {
@@ -70,16 +148,16 @@ namespace Org.BouncyCastle.Crypto.Digests
                     }
                 }
                 /* Rho-west: plane shift */
-                for (x = 0; x < NCOLUMS; ++x)
+                for (x = 0; x < NCOLUMNS; ++x)
                 {
                     b[index(x, 0)] = a[index(x, 0)];
                     b[index(x, 1)] = a[index(x + 3, 1)];
-                    b[index(x, 2)] = ROTL32(a[index(x, 2)], 11);
+                    b[index(x, 2)] = Integers.RotateLeft(a[index(x, 2)], 11);
                 }
                 /* Iota: round ant */
                 b[0] ^= RC[i];
                 /* Chi: non linear layer */
-                for (x = 0; x < NCOLUMS; ++x)
+                for (x = 0; x < NCOLUMNS; ++x)
                 {
                     for (y = 0; y < NROWS; ++y)
                     {
@@ -87,11 +165,11 @@ namespace Org.BouncyCastle.Crypto.Digests
                     }
                 }
                 /* Rho-east: plane shift */
-                for (x = 0; x < NCOLUMS; ++x)
+                for (x = 0; x < NCOLUMNS; ++x)
                 {
                     b[index(x, 0)] = a[index(x, 0)];
-                    b[index(x, 1)] = ROTL32(a[index(x, 1)], 1);
-                    b[index(x, 2)] = ROTL32(a[index(x + 2, 2)], 8);
+                    b[index(x, 1)] = Integers.RotateLeft(a[index(x, 1)], 1);
+                    b[index(x, 2)] = Integers.RotateLeft(a[index(x + 2, 2)], 8);
                 }
                 Array.Copy(b, 0, a, 0, NLANES);
             }
@@ -116,92 +194,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 
         private uint index(uint x, uint y)
         {
-            return (((y % NROWS) * NCOLUMS) + ((x) % NCOLUMS));
-        }
-
-        private uint ROTL32(uint a, int offset)
-        {
-            return (a << (offset & 31)) ^ (a >> ((32 - (offset)) & 31));
-        }
-
-        public void BlockUpdate(byte[] input, int inOff, int inLen)
-        {
-            if (inOff + inLen > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-            buffer.Write(input, inOff, inLen);
-        }
-
-        public int DoFinal(byte[] output, int outOff)
-        {
-            if (32 + outOff > output.Length)
-            {
-                throw new OutputLengthException("output buffer is too short");
-            }
-            byte[] input = buffer.GetBuffer();
-            int inLen = (int)buffer.Length;
-            int inOff = 0;
-            uint Cd = 0x03;
-            int splitLen;
-            do
-            {
-                if (phase != PhaseUp)
-                {
-                    Up(null, 0, 0, 0);
-                }
-                splitLen = System.Math.Min(inLen, Rabsorb);
-                Down(input, inOff, splitLen, Cd);
-                Cd = 0;
-                inOff += splitLen;
-                inLen -= splitLen;
-            }
-            while (inLen != 0);
-            Up(output, outOff, TAGLEN, 0x40);
-            Down(null, 0, 0, 0);
-            Up(output, outOff + TAGLEN, TAGLEN, 0);
-            return 32;
-        }
-
-        public int GetByteLength()
-        {
-            throw new NotImplementedException();
-        }
-
-        public int GetDigestSize()
-        {
-            return 32;
+            return (((y % NROWS) * NCOLUMNS) + ((x) % NCOLUMNS));
         }
-
-        public void Reset()
-        {
-            for (int i = 0; i < state.Length; ++i)
-            {
-                state[i] = 0;
-            }
-            phase = PhaseUp;
-            mode = MODE.ModeHash;
-            Rabsorb = Rhash;
-            buffer.SetLength(0);
-        }
-
-        public void Update(byte input)
-        {
-            buffer.Write(new byte[] { input }, 0, 1);
-        }
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public int DoFinal(Span<byte> output)
-        {
-            byte[] rv = new byte[32];
-            int rlt = DoFinal(rv, 0);
-            rv.AsSpan(0, 32).CopyTo(output);
-            return rlt;
-        }
-
-        public void BlockUpdate(ReadOnlySpan<byte> input)
-        {
-            buffer.Write(input.ToArray(), 0, input.Length);
-        }
-#endif
     }
 }
diff --git a/crypto/src/crypto/engines/ElephantEngine.cs b/crypto/src/crypto/engines/ElephantEngine.cs
index 4e0e3216d..89d2ca6be 100644
--- a/crypto/src/crypto/engines/ElephantEngine.cs
+++ b/crypto/src/crypto/engines/ElephantEngine.cs
@@ -1,8 +1,10 @@
 using System;
+using System.Drawing;
 using System.IO;
 
 using Org.BouncyCastle.Crypto.Modes;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
@@ -13,6 +15,7 @@ namespace Org.BouncyCastle.Crypto.Engines
      * Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/elephant-spec-final.pdf
      */
     public class ElephantEngine
+        // TODO IAeadCipher only
         : IAeadBlockCipher
     {
         public enum ElephantParameters
@@ -22,7 +25,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             elephant200
         }
 
-        private bool forEncryption;
+        private bool forEncryption = true; // Safe output sizes before initialization
         private readonly string algorithmName;
         private ElephantParameters parameters;
         private int BLOCK_SIZE;
@@ -226,28 +229,20 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             switch (parameters)
             {
-                case ElephantParameters.elephant160:
-                    output[BLOCK_SIZE - 1] = (byte)((((input[0] & 0xFF) << 3) | ((input[0] & 0xFF) >> 5)) ^
-                        ((input[3] & 0xFF) << 7) ^ ((input[13] & 0xFF) >> 7));
-                    break;
-                case ElephantParameters.elephant176:
-                    output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ ((input[3] & 0xFF) << 7) ^ ((input[19] & 0xFF) >> 7));
-                    break;
-                case ElephantParameters.elephant200:
-                    output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ rotl(input[2]) ^ (input[13] << 1));
-                    break;
+            case ElephantParameters.elephant160:
+                output[BLOCK_SIZE - 1] = (byte)((((input[0] & 0xFF) << 3) | ((input[0] & 0xFF) >> 5)) ^
+                    ((input[3] & 0xFF) << 7) ^ ((input[13] & 0xFF) >> 7));
+                break;
+            case ElephantParameters.elephant176:
+                output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ ((input[3] & 0xFF) << 7) ^ ((input[19] & 0xFF) >> 7));
+                break;
+            case ElephantParameters.elephant200:
+                output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ rotl(input[2]) ^ (input[13] << 1));
+                break;
             }
             Array.Copy(input, 1, output, 0, BLOCK_SIZE - 1);
         }
 
-        private void xor_block(byte[] state, byte[] block, int bOff, int size)
-        {
-            for (int i = 0; i < size; ++i)
-            {
-                state[i] ^= block[i + bOff];
-            }
-        }
-
         // Write the ith assocated data block to "output".
         // The nonce is prepended and padding is added as required.
         // adlen is the length of the associated data in bytes
@@ -412,14 +407,13 @@ namespace Org.BouncyCastle.Crypto.Engines
                     // Compute ciphertext block
                     Array.Copy(npub, 0, buffer, 0, CRYPTO_NPUBBYTES);
                     Arrays.Fill(buffer, CRYPTO_NPUBBYTES, BLOCK_SIZE, (byte)0);
-                    xor_block(buffer, current_mask, 0, BLOCK_SIZE);
-                    xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+                    Bytes.XorTo(BLOCK_SIZE, current_mask, buffer);
+                    Bytes.XorTo(BLOCK_SIZE, next_mask, buffer);
                     permutation(buffer);
-                    xor_block(buffer, current_mask, 0, BLOCK_SIZE);
-                    xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+                    Bytes.XorTo(BLOCK_SIZE, current_mask, buffer);
+                    Bytes.XorTo(BLOCK_SIZE, next_mask, buffer);
                     int r_size = (i == nblocks_m - 1) ? mlen - offset : BLOCK_SIZE;
-                    xor_block(buffer, m, offset, r_size);
-                    Array.Copy(buffer, 0, output, offset + outOff, r_size);
+                    Bytes.Xor(r_size, m, offset, buffer, 0, output, outOff + offset);
                 }
                 if (i > 0 && i <= nblocks_c)
                 {
@@ -432,21 +426,21 @@ namespace Org.BouncyCastle.Crypto.Engines
                     {
                         get_c_block(buffer, m, 0, mlen, i - 1);
                     }
-                    xor_block(buffer, previous_mask, 0, BLOCK_SIZE);
-                    xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+                    Bytes.XorTo(BLOCK_SIZE, previous_mask, buffer);
+                    Bytes.XorTo(BLOCK_SIZE, next_mask, buffer);
                     permutation(buffer);
-                    xor_block(buffer, previous_mask, 0, BLOCK_SIZE);
-                    xor_block(buffer, next_mask, 0, BLOCK_SIZE);
-                    xor_block(tag_buffer, buffer, 0, BLOCK_SIZE);
+                    Bytes.XorTo(BLOCK_SIZE, previous_mask, buffer);
+                    Bytes.XorTo(BLOCK_SIZE, next_mask, buffer);
+                    Bytes.XorTo(BLOCK_SIZE, buffer, tag_buffer);
                 }
                 // If there is any AD left, compute tag for AD block
                 if (i + 1 < nblocks_ad)
                 {
                     get_ad_block(buffer, ad, adlen, npub, i + 1);
-                    xor_block(buffer, next_mask, 0, BLOCK_SIZE);
+                    Bytes.XorTo(BLOCK_SIZE, next_mask, buffer);
                     permutation(buffer);
-                    xor_block(buffer, next_mask, 0, BLOCK_SIZE);
-                    xor_block(tag_buffer, buffer, 0, BLOCK_SIZE);
+                    Bytes.XorTo(BLOCK_SIZE, next_mask, buffer);
+                    Bytes.XorTo(BLOCK_SIZE, buffer, tag_buffer);
                 }
                 // Cyclically shift the mask buffers
                 // Value of next_mask will be computed in the next iteration
@@ -458,9 +452,9 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
             outOff += mlen;
             tag = new byte[CRYPTO_ABYTES];
-            xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE);
+            Bytes.XorTo(BLOCK_SIZE, expanded_key, tag_buffer);
             permutation(tag_buffer);
-            xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE);
+            Bytes.XorTo(BLOCK_SIZE, expanded_key, tag_buffer);
             if (forEncryption)
             {
                 Array.Copy(tag_buffer, 0, tag, 0, CRYPTO_ABYTES);
@@ -483,11 +477,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public int GetUpdateOutputSize(int len)
         {
+            // TODO
             return len;
         }
 
         public int GetOutputSize(int len)
         {
+            // TODO
             return len + CRYPTO_ABYTES;
         }
 
@@ -514,13 +510,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public int ProcessByte(byte input, Span<byte> output)
         {
-            message.Write(new byte[]{ input });
+            message.WriteByte(input);
             return 0;
         }
 
         public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
         {
-            message.Write(input.ToArray());
+            message.Write(input);
             return 0;
         }
 
@@ -558,4 +554,3 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
     }
 }
-
diff --git a/crypto/src/crypto/engines/ISAPEngine.cs b/crypto/src/crypto/engines/ISAPEngine.cs
index 7ef629d1b..17c679439 100644
--- a/crypto/src/crypto/engines/ISAPEngine.cs
+++ b/crypto/src/crypto/engines/ISAPEngine.cs
@@ -35,7 +35,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const int ISAP_STATE_SZ = 40;
 
         private string algorithmName;
-        private bool forEncryption;
+        private bool forEncryption = true; // Safe output sizes before initialization
         private bool initialised;
         private byte[] mac;
         private MemoryStream aadData = new MemoryStream();
@@ -112,7 +112,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             protected ulong ISAP_IV1_64;
             protected ulong ISAP_IV2_64;
             protected ulong ISAP_IV3_64;
-            protected ulong x0, x1, x2, x3, x4, t0, t1, t2, t3, t4;
+            protected ulong x0, x1, x2, x3, x4;
 
             public override void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ)
             {
@@ -248,11 +248,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 #endif
             protected void ROUND(ulong C)
             {
-                t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
-                t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
-                t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
-                t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
-                t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+                ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
+                ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
+                ulong t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
+                ulong t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
+                ulong t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
                 x0 = t0 ^ Longs.RotateRight(t0, 19) ^ Longs.RotateRight(t0, 28);
                 x1 = t1 ^ Longs.RotateRight(t1, 39) ^ Longs.RotateRight(t1, 61);
                 x2 = ~(t2 ^ Longs.RotateRight(t2, 1) ^ Longs.RotateRight(t2, 6));
diff --git a/crypto/src/crypto/engines/PhotonBeetleEngine.cs b/crypto/src/crypto/engines/PhotonBeetleEngine.cs
index e593bb6f5..5d96213a1 100644
--- a/crypto/src/crypto/engines/PhotonBeetleEngine.cs
+++ b/crypto/src/crypto/engines/PhotonBeetleEngine.cs
@@ -14,7 +14,8 @@ namespace Org.BouncyCastle.Crypto.Engines
      * Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software
      * </p>
      */
-    public class PhotonBeetleEngine
+    public sealed class PhotonBeetleEngine
+        // TODO IAeadCipher only
         : IAeadBlockCipher
     {
         public enum PhotonBeetleParameters
@@ -24,7 +25,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 
         private bool input_empty;
-        private bool forEncryption;
+        private bool forEncryption = true; // Safe output sizes before initialization
         private bool initialised;
         private byte[] K;
         private byte[] N;
@@ -94,6 +95,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public string AlgorithmName => "Photon-Beetle AEAD";
 
+        // TODO
         public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
 
         public byte[] GetMac()
@@ -103,37 +105,33 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public int GetOutputSize(int len)
         {
+            // TODO
             return len + TAG_INBYTES;
         }
 
         public int GetUpdateOutputSize(int len)
         {
+            // TODO
             return len;
         }
 
         public void Init(bool forEncryption, ICipherParameters parameters)
         {
             this.forEncryption = forEncryption;
-            if (!(parameters is ParametersWithIV param))
-            {
+
+            if (!(parameters is ParametersWithIV ivParams))
                 throw new ArgumentException("Photon-Beetle AEAD init parameters must include an IV");
-            }
-            ParametersWithIV ivParams = param;
+
             N = ivParams.GetIV();
             if (N == null || N.Length != CRYPTO_NPUBBYTES)
-            {
                 throw new ArgumentException("Photon-Beetle AEAD requires exactly 16 bytes of IV");
-            }
-            if (!(ivParams.Parameters is KeyParameter))
-            {
+
+            if (!(ivParams.Parameters is KeyParameter key))
                 throw new ArgumentException("Photon-Beetle AEAD init parameters must include a key");
-            }
-            KeyParameter key = (KeyParameter)ivParams.Parameters;
+
             K = key.GetKey();
             if (K.Length != CRYPTO_KEYBYTES)
-            {
                 throw new ArgumentException("Photon-Beetle AEAD key must be 128 bits long");
-            }
 
             state = new byte[STATE_INBYTES];
             state_2d = new byte[D][];
@@ -148,7 +146,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public void ProcessAadByte(byte input)
         {
-            aadData.Write(new byte[] { input }, 0, 1);
+            aadData.WriteByte(input);
         }
 
         public void ProcessAadBytes(byte[] inBytes, int inOff, int len)
@@ -300,19 +298,11 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
             if (forEncryption)
             {
-                XOR(plaintext, inOff, DBlen_inbytes);
+                Bytes.XorTo(DBlen_inbytes, plaintext, inOff, state, 0);
             }
             else
             {
-                XOR(ciphertext, inOff, DBlen_inbytes);
-            }
-        }
-
-        void XOR(byte[] in_right, int rOff, int iolen_inbytes)
-        {
-            for (int i = 0; i < iolen_inbytes; i++)
-            {
-                state[i] ^= in_right[rOff++];
+                Bytes.XorTo(DBlen_inbytes, ciphertext, inOff, state, 0);
             }
         }
 
@@ -344,11 +334,11 @@ namespace Org.BouncyCastle.Crypto.Engines
                 for (i = 0; i < Dlen_inblocks - 1; i++)
                 {
                     PHOTON_Permutation();
-                    XOR(A, i * RATE_INBYTES, RATE_INBYTES);
+                    Bytes.XorTo(RATE_INBYTES, A, i * RATE_INBYTES, state, 0);
                 }
                 PHOTON_Permutation();
                 LastDBlocklen = adlen - i * RATE_INBYTES;
-                XOR(A, i * RATE_INBYTES, LastDBlocklen);
+                Bytes.XorTo(LastDBlocklen, A, i * RATE_INBYTES, state, 0);
                 if (LastDBlocklen < RATE_INBYTES)
                 {
                     state[LastDBlocklen] ^= 0x01; // ozs
diff --git a/crypto/src/crypto/engines/SparkleEngine.cs b/crypto/src/crypto/engines/SparkleEngine.cs
index 63e400d4c..7d8c28f8e 100644
--- a/crypto/src/crypto/engines/SparkleEngine.cs
+++ b/crypto/src/crypto/engines/SparkleEngine.cs
@@ -14,7 +14,8 @@ namespace Org.BouncyCastle.Crypto.Engines
     /// Specification:
     /// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/sparkle-spec-final.pdf .
     /// </remarks>
-    public class SparkleEngine
+    public sealed class SparkleEngine
+        // TODO IAeadCipher only
         : IAeadBlockCipher
     {
         public enum SparkleParameters
@@ -24,8 +25,9 @@ namespace Org.BouncyCastle.Crypto.Engines
             SCHWAEMM192_192,
             SCHWAEMM256_256
         }
+
         private string algorithmName;
-        private bool forEncryption;
+        private bool forEncryption = true; // Safe output sizes before initialization
         private readonly uint[] state;
         private readonly uint[] k;
         private readonly uint[] npub;
@@ -60,48 +62,48 @@ namespace Org.BouncyCastle.Crypto.Engines
             int SPARKLE_CAPACITY;
             switch (sparkleParameters)
             {
-                case SparkleParameters.SCHWAEMM128_128:
-                    SCHWAEMM_KEY_LEN = 128;
-                    SCHWAEMM_NONCE_LEN = 128;
-                    SCHWAEMM_TAG_LEN = 128;
-                    SPARKLE_STATE = 256;
-                    SPARKLE_CAPACITY = 128;
-                    SPARKLE_STEPS_SLIM = 7;
-                    SPARKLE_STEPS_BIG = 10;
-                    algorithmName = "SCHWAEMM128-128";
-                    break;
-                case SparkleParameters.SCHWAEMM256_128:
-                    SCHWAEMM_KEY_LEN = 128;
-                    SCHWAEMM_NONCE_LEN = 256;
-                    SCHWAEMM_TAG_LEN = 128;
-                    SPARKLE_STATE = 384;
-                    SPARKLE_CAPACITY = 128;
-                    SPARKLE_STEPS_SLIM = 7;
-                    SPARKLE_STEPS_BIG = 11;
-                    algorithmName = "SCHWAEMM256-128";
-                    break;
-                case SparkleParameters.SCHWAEMM192_192:
-                    SCHWAEMM_KEY_LEN = 192;
-                    SCHWAEMM_NONCE_LEN = 192;
-                    SCHWAEMM_TAG_LEN = 192;
-                    SPARKLE_STATE = 384;
-                    SPARKLE_CAPACITY = 192;
-                    SPARKLE_STEPS_SLIM = 7;
-                    SPARKLE_STEPS_BIG = 11;
-                    algorithmName = "SCHWAEMM192-192";
-                    break;
-                case SparkleParameters.SCHWAEMM256_256:
-                    SCHWAEMM_KEY_LEN = 256;
-                    SCHWAEMM_NONCE_LEN = 256;
-                    SCHWAEMM_TAG_LEN = 256;
-                    SPARKLE_STATE = 512;
-                    SPARKLE_CAPACITY = 256;
-                    SPARKLE_STEPS_SLIM = 8;
-                    SPARKLE_STEPS_BIG = 12;
-                    algorithmName = "SCHWAEMM256-256";
-                    break;
-                default:
-                    throw new ArgumentException("Invalid definition of SCHWAEMM instance");
+            case SparkleParameters.SCHWAEMM128_128:
+                SCHWAEMM_KEY_LEN = 128;
+                SCHWAEMM_NONCE_LEN = 128;
+                SCHWAEMM_TAG_LEN = 128;
+                SPARKLE_STATE = 256;
+                SPARKLE_CAPACITY = 128;
+                SPARKLE_STEPS_SLIM = 7;
+                SPARKLE_STEPS_BIG = 10;
+                algorithmName = "SCHWAEMM128-128";
+                break;
+            case SparkleParameters.SCHWAEMM256_128:
+                SCHWAEMM_KEY_LEN = 128;
+                SCHWAEMM_NONCE_LEN = 256;
+                SCHWAEMM_TAG_LEN = 128;
+                SPARKLE_STATE = 384;
+                SPARKLE_CAPACITY = 128;
+                SPARKLE_STEPS_SLIM = 7;
+                SPARKLE_STEPS_BIG = 11;
+                algorithmName = "SCHWAEMM256-128";
+                break;
+            case SparkleParameters.SCHWAEMM192_192:
+                SCHWAEMM_KEY_LEN = 192;
+                SCHWAEMM_NONCE_LEN = 192;
+                SCHWAEMM_TAG_LEN = 192;
+                SPARKLE_STATE = 384;
+                SPARKLE_CAPACITY = 192;
+                SPARKLE_STEPS_SLIM = 7;
+                SPARKLE_STEPS_BIG = 11;
+                algorithmName = "SCHWAEMM192-192";
+                break;
+            case SparkleParameters.SCHWAEMM256_256:
+                SCHWAEMM_KEY_LEN = 256;
+                SCHWAEMM_NONCE_LEN = 256;
+                SCHWAEMM_TAG_LEN = 256;
+                SPARKLE_STATE = 512;
+                SPARKLE_CAPACITY = 256;
+                SPARKLE_STEPS_SLIM = 8;
+                SPARKLE_STEPS_BIG = 12;
+                algorithmName = "SCHWAEMM256-256";
+                break;
+            default:
+                throw new ArgumentException("Invalid definition of SCHWAEMM instance");
             }
             KEY_WORDS = SCHWAEMM_KEY_LEN >> 5;
             KEY_BYTES = SCHWAEMM_KEY_LEN >> 3;
@@ -124,14 +126,9 @@ namespace Org.BouncyCastle.Crypto.Engines
             initialised = false;
         }
 
-        private uint ROT(uint x, int n)
-        {
-            return (((x) >> n) | ((x) << (32 - n)));
-        }
-
         private uint ELL(uint x)
         {
-            return ROT(((x) ^ ((x) << 16)), 16);
+            return Integers.RotateRight(x ^ (x << 16), 16);
         }
 
         private static readonly uint[] RCON = {0xB7E15162, 0xBF715880, 0x38B4DA56, 0x324E7738, 0xBB1185EB, 0x4F7C7B57,
@@ -149,17 +146,17 @@ namespace Org.BouncyCastle.Crypto.Engines
                 for (j = 0; j < 2 * brans; j += 2)
                 {
                     rc = RCON[j >> 1];
-                    state[j] += ROT(state[j + 1], 31);
-                    state[j + 1] ^= ROT(state[j], 24);
+                    state[j] += Integers.RotateRight(state[j + 1], 31);
+                    state[j + 1] ^= Integers.RotateRight(state[j], 24);
                     state[j] ^= rc;
-                    state[j] += ROT(state[j + 1], 17);
-                    state[j + 1] ^= ROT(state[j], 17);
+                    state[j] += Integers.RotateRight(state[j + 1], 17);
+                    state[j + 1] ^= Integers.RotateRight(state[j], 17);
                     state[j] ^= rc;
                     state[j] += state[j + 1];
-                    state[j + 1] ^= ROT(state[j], 31);
+                    state[j + 1] ^= Integers.RotateRight(state[j], 31);
                     state[j] ^= rc;
-                    state[j] += ROT(state[j + 1], 24);
-                    state[j + 1] ^= ROT(state[j], 16);
+                    state[j] += Integers.RotateRight(state[j + 1], 24);
+                    state[j + 1] ^= Integers.RotateRight(state[j], 16);
                     state[j] ^= rc;
                 }
                 // Linear layer
@@ -308,31 +305,22 @@ namespace Org.BouncyCastle.Crypto.Engines
         public void Init(bool forEncryption, ICipherParameters param)
         {
             this.forEncryption = forEncryption;
-            if (!(param is ParametersWithIV))
-            {
+            if (!(param is ParametersWithIV ivParams))
                 throw new ArgumentException(algorithmName + " init parameters must include an IV");
-            }
 
-            ParametersWithIV ivParams = (ParametersWithIV)param;
             byte[] iv = ivParams.GetIV();
-
             if (iv == null || iv.Length != SCHWAEMM_NONCE_LEN >> 3)
-            {
                 throw new ArgumentException(algorithmName + " requires exactly 16 bytes of IV");
-            }
+
             Pack.LE_To_UInt32(iv, 0, npub, 0, RATE_WORDS);
 
-            if (!(ivParams.Parameters is KeyParameter))
-            {
+            if (!(ivParams.Parameters is KeyParameter key))
                 throw new ArgumentException(algorithmName + " init parameters must include a key");
-            }
 
-            KeyParameter key = (KeyParameter)ivParams.Parameters;
             byte[] key8 = key.GetKey();
             if (key8.Length != SCHWAEMM_KEY_LEN >> 3)
-            {
                 throw new ArgumentException(algorithmName + " key must be 128 bits long");
-            }
+
             Pack.LE_To_UInt32(key8, 0, k, 0, KEY_WORDS);
             initialised = true;
             reset(false);
@@ -345,9 +333,9 @@ namespace Org.BouncyCastle.Crypto.Engines
                 throw new ArgumentException(algorithmName + ": AAD cannot be added after reading a full block(" +
                     GetBlockSize() + " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
             }
-            aadData.Write(new byte[] { input }, 0, 1);
-        }
 
+            aadData.WriteByte(input);
+        }
 
         public void ProcessAadBytes(byte[] input, int inOff, int len)
         {
@@ -356,61 +344,53 @@ namespace Org.BouncyCastle.Crypto.Engines
                 throw new ArgumentException(algorithmName + ": AAD cannot be added after reading a full block(" +
                     GetBlockSize() + " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
             }
-            if (inOff + len > input.Length)
-            {
-                throw new DataLengthException(algorithmName + " input buffer too short");
-            }
+
+            Check.DataLength(input, inOff, len, "input buffer too short");
+
             aadData.Write(input, inOff, len);
         }
 
-
         public int ProcessByte(byte input, byte[] output, int outOff)
         {
-            return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+            return ProcessBytes(new byte[]{ input }, 0, 1, output, outOff);
         }
 
-
         public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
         {
             if (!initialised)
-            {
                 throw new ArgumentException(algorithmName + " Need call init function before encryption/decryption");
-            }
-            if (inOff + len > input.Length)
-            {
-                throw new DataLengthException(algorithmName + " input buffer too short");
-            }
+
+            Check.DataLength(input, inOff, len, "input buffer too short");
+
             message.Write(input, inOff, len);
+
+            int msgLen = Convert.ToInt32(message.Length);
+
             len = 0;
-            if ((forEncryption && (int)message.Length > GetBlockSize()) ||
-                (!forEncryption && (int)message.Length - TAG_BYTES > GetBlockSize()))
+            if ((forEncryption && msgLen > GetBlockSize()) ||
+                (!forEncryption && msgLen - TAG_BYTES > GetBlockSize()))
             {
-                len = ((int)message.Length - (forEncryption ? 0 : TAG_BYTES));
-                if (len / RATE_BYTES * RATE_BYTES + outOff > output.Length)
-                {
-                    throw new OutputLengthException(algorithmName + " output buffer is too short");
-                }
+                len = msgLen - (forEncryption ? 0 : TAG_BYTES);
+                Check.OutputLength(output, outOff, len / RATE_BYTES * RATE_BYTES, "output buffer is too short");
                 byte[] m = message.GetBuffer();
                 ProcessAssocData(state);
                 if (len != 0)
                 {
                     len = ProcessPlainText(state, output, m, 0, len);
                 }
-                int mlen = (int)message.Length;
                 message.SetLength(0);
-                message.Write(m, len, mlen - len);
+                // TODO Sketchy writing back to the buffer after setting length to 0
+                message.Write(m, len, msgLen - len);
             }
             return len;
         }
 
-
         public int DoFinal(byte[] output, int outOff)
         {
             if (!initialised)
-            {
-                throw new ArgumentException(algorithmName + " needs call init function before dofinal");
-            }
-            int inlen = (int)message.Length - (forEncryption ? 0 : TAG_BYTES);
+                throw new ArgumentException(algorithmName + " needs to call Init before DoFinal");
+
+            int inlen = Convert.ToInt32(message.Length) - (forEncryption ? 0 : TAG_BYTES);
             if ((forEncryption && inlen + TAG_BYTES + outOff > output.Length) ||
                 (!forEncryption && inlen + outOff > output.Length))
             {
@@ -495,25 +475,23 @@ namespace Org.BouncyCastle.Crypto.Engines
             return tag;
         }
 
-
         public int GetUpdateOutputSize(int len)
         {
+            // TODO
             return len;
         }
 
-
         public int GetOutputSize(int len)
         {
+            // TODO
             return len + TAG_BYTES;
         }
 
-
         public void Reset()
         {
             if (!initialised)
-            {
-                throw new ArgumentException(algorithmName + " needs call init function before reset");
-            }
+                throw new ArgumentException(algorithmName + " needs to call Init before Reset");
+
             reset(true);
         }
 
diff --git a/crypto/src/crypto/engines/XoodyakEngine.cs b/crypto/src/crypto/engines/XoodyakEngine.cs
index e0263272e..2eb563525 100644
--- a/crypto/src/crypto/engines/XoodyakEngine.cs
+++ b/crypto/src/crypto/engines/XoodyakEngine.cs
@@ -13,11 +13,23 @@ namespace Org.BouncyCastle.Crypto.Engines
     * <p>
     * Xoodyak with reference to C Reference Impl from: https://github.com/XKCP/XKCP
     * </p>
-*/
+    */
     public sealed class XoodyakEngine
+        // TODO IAeadCipher only
         : IAeadBlockCipher
     {
-        private bool forEncryption;
+        private enum MODE
+        {
+            ModeHash,
+            ModeKeyed
+        }
+
+        private const int Rkin = 44;
+
+        private static readonly uint[] RC = { 0x00000058U, 0x00000038U, 0x000003C0U, 0x000000D0U, 0x00000120U,
+            0x00000014U, 0x00000060U, 0x0000002CU, 0x00000380U, 0x000000F0U, 0x000001A0U, 0x00000012U };
+
+        private bool forEncryption = true; // Safe output sizes before initialization
         private byte[] state;
         private int phase;
         private MODE mode;
@@ -33,49 +45,36 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const int NCOLUMS = 4;
         private const int MAXROUNDS = 12;
         private const int TAGLEN = 16;
-        const int Rkin = 44;
         private byte[] tag;
-        private readonly uint[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060,
-        0x0000002C, 0x00000380, 0x000000F0, 0x000001A0, 0x00000012};
         private bool aadFinished;
         private bool encrypted;
         private bool initialised = false;
-        public string AlgorithmName => "Xoodak AEAD";
-
-        public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
 
         private MemoryStream aadData = new MemoryStream();
         private MemoryStream message = new MemoryStream();
 
-        enum MODE
-        {
-            ModeHash,
-            ModeKeyed
-        }
+        public string AlgorithmName => "Xoodak AEAD";
+
+        public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
 
-        public void Init(bool forEncryption, ICipherParameters param)
+        public void Init(bool forEncryption, ICipherParameters parameters)
         {
             this.forEncryption = forEncryption;
-            if (!(param is ParametersWithIV))
-            {
+
+            if (!(parameters is ParametersWithIV ivParams))
                 throw new ArgumentException("Xoodyak init parameters must include an IV");
-            }
-            ParametersWithIV ivParams = (ParametersWithIV)param;
+
             iv = ivParams.GetIV();
             if (iv == null || iv.Length != 16)
-            {
                 throw new ArgumentException("Xoodyak requires exactly 16 bytes of IV");
-            }
-            if (!(ivParams.Parameters is KeyParameter))
-            {
+
+            if (!(ivParams.Parameters is KeyParameter key))
                 throw new ArgumentException("Xoodyak init parameters must include a key");
-            }
-            KeyParameter key = (KeyParameter)ivParams.Parameters;
+
             K = key.GetKey();
             if (K.Length != 16)
-            {
                 throw new ArgumentException("Xoodyak key must be 128 bits long");
-            }
+
             state = new byte[48];
             tag = new byte[TAGLEN];
             initialised = true;
@@ -89,9 +88,9 @@ namespace Org.BouncyCastle.Crypto.Engines
                 throw new ArgumentException("AAD cannot be added after reading a full block(" + GetBlockSize() +
                     " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
             }
-            aadData.Write(new byte[] { input }, 0, 1);
-        }
 
+            aadData.WriteByte(input);
+        }
 
         public void ProcessAadBytes(byte[] input, int inOff, int len)
         {
@@ -100,17 +99,15 @@ namespace Org.BouncyCastle.Crypto.Engines
                 throw new ArgumentException("AAD cannot be added after reading a full block(" + GetBlockSize() +
                     " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
             }
-            if ((inOff + len) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
+
+            Check.DataLength(input, inOff, len, "input buffer too short");
+
             aadData.Write(input, inOff, len);
         }
 
-
-        public int ProcessByte(byte input, byte[] output, int outOff)
+        public int ProcessByte(byte input, byte[] outBytes, int outOff)
         {
-            return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+            return ProcessBytes(new byte[]{ input }, 0, 1, outBytes, outOff);
         }
 
         private void processAAD()
@@ -123,7 +120,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+        public int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff)
         {
             if (!initialised)
                 throw new ArgumentException("Need to call Init before encryption/decryption");
@@ -131,17 +128,17 @@ namespace Org.BouncyCastle.Crypto.Engines
             if (mode != MODE.ModeKeyed)
                 throw new ArgumentException("Xoodyak has not been initialised");
 
-            Check.DataLength(input, inOff, len, "input buffer too short");
+            Check.DataLength(inBytes, inOff, len, "input buffer too short");
 
-            message.Write(input, inOff, len);
+            message.Write(inBytes, inOff, len);
             int blockLen = (int)message.Length - (forEncryption ? 0 : TAGLEN);
             if (blockLen >= GetBlockSize())
             {
                 byte[] blocks = message.GetBuffer();
                 len = blockLen / GetBlockSize() * GetBlockSize();
-                Check.OutputLength(output, outOff, len, "output buffer is too short");
+                Check.OutputLength(outBytes, outOff, len, "output buffer is too short");
                 processAAD();
-                encrypt(blocks, 0, len, output, outOff);
+                encrypt(blocks, 0, len, outBytes, outOff);
                 int messageLen = (int)message.Length;
                 message.SetLength(0);
                 message.Write(blocks, len, messageLen - len);
@@ -186,15 +183,15 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 
 
-        public int DoFinal(byte[] output, int outOff)
+        public int DoFinal(byte[] outBytes, int outOff)
         {
             if (!initialised)
                 throw new ArgumentException("Need to call Init before encryption/decryption");
 
             byte[] blocks = message.GetBuffer();
             int len = (int)message.Length;
-            if ((forEncryption && len + TAGLEN + outOff > output.Length) ||
-                (!forEncryption && len - TAGLEN + outOff > output.Length))
+            if ((forEncryption && len + TAGLEN + outOff > outBytes.Length) ||
+                (!forEncryption && len - TAGLEN + outOff > outBytes.Length))
             {
                 throw new OutputLengthException("output buffer too short");
             }
@@ -202,18 +199,18 @@ namespace Org.BouncyCastle.Crypto.Engines
             int rv = 0;
             if (forEncryption)
             {
-                encrypt(blocks, 0, len, output, outOff);
+                encrypt(blocks, 0, len, outBytes, outOff);
                 outOff += len;
                 tag = new byte[TAGLEN];
                 Up(tag, TAGLEN, 0x40);
-                Array.Copy(tag, 0, output, outOff, TAGLEN);
+                Array.Copy(tag, 0, outBytes, outOff, TAGLEN);
                 rv = len + TAGLEN;
             }
             else
             {
                 int inOff = len - TAGLEN;
                 rv = inOff;
-                encrypt(blocks, 0, inOff, output, outOff);
+                encrypt(blocks, 0, inOff, outBytes, outOff);
                 tag = new byte[TAGLEN];
                 Up(tag, TAGLEN, 0x40);
 
@@ -231,11 +228,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public int GetUpdateOutputSize(int len)
         {
+            // TODO
             return len;
         }
 
         public int GetOutputSize(int len)
         {
+            // TODO
             return len + TAGLEN;
         }
 
@@ -427,8 +426,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             rv.AsSpan(0, len).CopyTo(output);
             return rv.Length;
         }
-
 #endif
-
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/test/src/crypto/test/ElephantTest.cs b/crypto/test/src/crypto/test/ElephantTest.cs
index 406be7c6f..7e7e131ab 100644
--- a/crypto/test/src/crypto/test/ElephantTest.cs
+++ b/crypto/test/src/crypto/test/ElephantTest.cs
@@ -270,7 +270,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             elephantEngine.DoFinal(mac2, 0);
             if (!Arrays.AreEqual(mac1, mac2))
             {
-                Assert.Fail("mac should match for the same AAD with different ways of inputing");
+                Assert.Fail("mac should match for the same AAD with different ways of inputting");
             }
 
             byte[] c2 = new byte[elephantEngine.GetOutputSize(10)];
diff --git a/crypto/test/src/crypto/test/ISAPTest.cs b/crypto/test/src/crypto/test/ISAPTest.cs
index e7b0bd25c..500026bf9 100644
--- a/crypto/test/src/crypto/test/ISAPTest.cs
+++ b/crypto/test/src/crypto/test/ISAPTest.cs
@@ -330,7 +330,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             isapEngine.DoFinal(mac2, 0);
             if (!Arrays.AreEqual(mac1, mac2))
             {
-                Assert.Fail("mac should match for the same AAD with different ways of inputing");
+                Assert.Fail("mac should match for the same AAD with different ways of inputting");
             }
 
             byte[] c2 = new byte[isapEngine.GetOutputSize(10)];
diff --git a/crypto/test/src/crypto/test/PhotonBeetleTest.cs b/crypto/test/src/crypto/test/PhotonBeetleTest.cs
index 80e34ad4b..cd551432c 100644
--- a/crypto/test/src/crypto/test/PhotonBeetleTest.cs
+++ b/crypto/test/src/crypto/test/PhotonBeetleTest.cs
@@ -310,7 +310,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             aeadBlockCipher.DoFinal(mac2, 0);
             if (!Arrays.AreEqual(mac1, mac2))
             {
-                Assert.Fail("mac should match for the same AAD with different ways of inputing");
+                Assert.Fail("mac should match for the same AAD with different ways of inputting");
             }
 
             byte[] c2 = new byte[aeadBlockCipher.GetOutputSize(10)];
diff --git a/crypto/test/src/crypto/test/SparkleTest.cs b/crypto/test/src/crypto/test/SparkleTest.cs
index 245a1831c..ea4520226 100644
--- a/crypto/test/src/crypto/test/SparkleTest.cs
+++ b/crypto/test/src/crypto/test/SparkleTest.cs
@@ -324,7 +324,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             sparkleEngine.DoFinal(mac2, 0);
             if (!Arrays.AreEqual(mac1, mac2))
             {
-                Assert.Fail("mac should match for the same AAD with different ways of inputing");
+                Assert.Fail("mac should match for the same AAD with different ways of inputting");
             }
 
             byte[] c2 = new byte[sparkleEngine.GetOutputSize(10)];
diff --git a/crypto/test/src/crypto/test/XoodyakTest.cs b/crypto/test/src/crypto/test/XoodyakTest.cs
index d8664e82f..b73d998f4 100644
--- a/crypto/test/src/crypto/test/XoodyakTest.cs
+++ b/crypto/test/src/crypto/test/XoodyakTest.cs
@@ -300,7 +300,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             xoodyakEngine.DoFinal(mac2, 0);
             if (!Arrays.AreEqual(mac1, mac2))
             {
-                Assert.Fail("mac should match for the same AAD with different ways of inputing");
+                Assert.Fail("mac should match for the same AAD with different ways of inputting");
             }
 
             byte[] c2 = new byte[xoodyakEngine.GetOutputSize(10)];