summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/Contributors.html10
-rw-r--r--crypto/crypto.csproj38
-rw-r--r--crypto/src/asn1/nist/NISTObjectIdentifiers.cs6
-rw-r--r--crypto/src/asn1/x9/X9ECParametersHolder.cs17
-rw-r--r--crypto/src/bcpg/BcpgInputStream.cs18
-rw-r--r--crypto/src/cms/SignerInformation.cs7
-rw-r--r--crypto/src/crypto/IXof.cs22
-rw-r--r--crypto/src/crypto/digests/KeccakDigest.cs534
-rw-r--r--crypto/src/crypto/digests/SHA3Digest.cs538
-rw-r--r--crypto/src/crypto/digests/ShakeDigest.cs111
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs23
-rw-r--r--crypto/src/crypto/engines/AesFastEngine.cs23
-rw-r--r--crypto/src/crypto/engines/AesLightEngine.cs29
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs53
-rw-r--r--crypto/src/crypto/parameters/DHParameters.cs1
-rw-r--r--crypto/src/crypto/signers/Iso9796d2PssSigner.cs50
-rw-r--r--crypto/src/crypto/signers/Iso9796d2Signer.cs61
-rw-r--r--crypto/src/crypto/signers/IsoTrailers.cs57
-rw-r--r--crypto/src/crypto/signers/X931Signer.cs63
-rw-r--r--crypto/src/crypto/util/Pack.cs25
-rw-r--r--crypto/src/math/Primes.cs366
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113Field.cs29
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131Field.cs29
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163Field.cs41
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193Field.cs43
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233Field.cs33
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239Field.cs37
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283Field.cs35
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409Field.cs51
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571Field.cs51
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571FieldElement.cs5
-rw-r--r--crypto/src/math/raw/Interleave.cs109
-rw-r--r--crypto/src/security/DigestUtilities.cs24
-rw-r--r--crypto/test/data/crypto/SHA3TestVectors.txt837
-rw-r--r--crypto/test/data/crypto/SHAKETestVectors.txt770
-rw-r--r--crypto/test/src/crypto/test/KeccakDigestTest.cs374
-rw-r--r--crypto/test/src/crypto/test/RegressionTest.cs4
-rw-r--r--crypto/test/src/crypto/test/SHA3DigestTest.cs468
-rw-r--r--crypto/test/src/crypto/test/ShakeDigestTest.cs290
-rw-r--r--crypto/test/src/math/ec/test/ECPointTest.cs51
48 files changed, 4326 insertions, 1047 deletions
diff --git a/crypto/Contributors.html b/crypto/Contributors.html
index 68ca699cf..c62928932 100644
--- a/crypto/Contributors.html
+++ b/crypto/Contributors.html
@@ -6,7 +6,15 @@
 	</head>
 	<body>
 		<h2>The Bouncy Castle Cryptographic C#&reg; API</h2>
-		<h3>Contributors:</h3>
+		<p>
+		<h3>Donors</h3>
+		<p>
+		The following people and organisations donated financially to help with the release of 1.8:
+		<br />&nbsp;<br />
+		Andrew Grosser, Antonio Royo, dmitry.ribakov&#64gmail.com, PhreePhly, and encryptomatic.com.
+		</p>
+
+		<h3>Code Contributors:</h3>
 		<p>The following people have contributed to the C# Bouncy Castle Cryptography 
 			Package.</p>
 		<p>Thanks, may your castles never deflate!</p>
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 93ca2cf23..b094843f2 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -3094,6 +3094,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\IXof.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\KeyGenerationParameters.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3209,6 +3214,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\digests\KeccakDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\digests\LongDigest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3289,6 +3299,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\digests\ShakeDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\digests\ShortenedDigest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4309,6 +4324,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\signers\IsoTrailers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\signers\PSSSigner.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -7165,6 +7185,14 @@
                     BuildAction = "EmbeddedResource"
                 />
                 <File
+                    RelPath = "test\data\crypto\SHA3TestVectors.txt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\crypto\SHAKETestVectors.txt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
                     RelPath = "test\data\hc256\hc128\ecrypt_HC-128.txt"
                     BuildAction = "EmbeddedResource"
                 />
@@ -11138,6 +11166,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\test\KeccakDigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\test\MacTest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -11388,6 +11421,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\test\ShakeDigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\test\ShortenedDigestTest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
index 8eb5ed437..55b9d8e68 100644
--- a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
+++ b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
@@ -25,6 +25,12 @@ namespace Org.BouncyCastle.Asn1.Nist
         public static readonly DerObjectIdentifier IdSha224 = HashAlgs.Branch("4");
         public static readonly DerObjectIdentifier IdSha512_224 = HashAlgs.Branch("5");
         public static readonly DerObjectIdentifier IdSha512_256 = HashAlgs.Branch("6");
+        public static readonly DerObjectIdentifier IdSha3_224 = HashAlgs.Branch("7");
+        public static readonly DerObjectIdentifier IdSha3_256 = HashAlgs.Branch("8");
+        public static readonly DerObjectIdentifier IdSha3_384 = HashAlgs.Branch("9");
+        public static readonly DerObjectIdentifier IdSha3_512 = HashAlgs.Branch("10");
+        public static readonly DerObjectIdentifier IdShake128 = HashAlgs.Branch("11");
+        public static readonly DerObjectIdentifier IdShake256 = HashAlgs.Branch("12");
 
         public static readonly DerObjectIdentifier Aes = new DerObjectIdentifier(NistAlgorithm + ".1");
 
diff --git a/crypto/src/asn1/x9/X9ECParametersHolder.cs b/crypto/src/asn1/x9/X9ECParametersHolder.cs
index b3455709c..e802b738c 100644
--- a/crypto/src/asn1/x9/X9ECParametersHolder.cs
+++ b/crypto/src/asn1/x9/X9ECParametersHolder.cs
@@ -8,14 +8,17 @@ namespace Org.BouncyCastle.Asn1.X9
 		{
 			get
 			{
-				if (parameters == null)
-				{
-					parameters = CreateParameters();
-				}
+                lock (this)
+                {
+                    if (parameters == null)
+                    {
+                        parameters = CreateParameters();
+                    }
 
-				return parameters;
-			}
-		}
+                    return parameters;
+                }
+            }
+        }
 
 		protected abstract X9ECParameters CreateParameters();
 	}
diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs
index 3c69fbdf5..2e08cd090 100644
--- a/crypto/src/bcpg/BcpgInputStream.cs
+++ b/crypto/src/bcpg/BcpgInputStream.cs
@@ -105,19 +105,15 @@ namespace Org.BouncyCastle.Bcpg
                 next = true;
             }
 
-            if (nextB >= 0)
+            if (nextB < 0)
+                return (PacketTag)nextB;
+
+            int maskB = nextB & 0x3f;
+            if ((nextB & 0x40) == 0)    // old
             {
-                if ((nextB & 0x40) != 0)    // new
-                {
-                    return (PacketTag)(nextB & 0x3f);
-                }
-                else    // old
-                {
-                    return (PacketTag)((nextB & 0x3f) >> 2);
-                }
+                maskB >>= 2;
             }
-
-            return (PacketTag) nextB;
+            return (PacketTag)maskB;
         }
 
         public Packet ReadPacket()
diff --git a/crypto/src/cms/SignerInformation.cs b/crypto/src/cms/SignerInformation.cs
index 20af29a50..581286a3f 100644
--- a/crypto/src/cms/SignerInformation.cs
+++ b/crypto/src/cms/SignerInformation.cs
@@ -345,9 +345,12 @@ namespace Org.BouncyCastle.Cms
 //				if (sigParams != null)
 //					throw new CmsException("unrecognised signature parameters provided");
 
-				string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
+                string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
 
-				sig = Helper.GetSignatureInstance(signatureName);
+                sig = Helper.GetSignatureInstance(signatureName);
+
+                //sig = Helper.GetSignatureInstance(this.EncryptionAlgOid);
+                //sig = SignerUtilities.GetSigner(sigAlgOid);
 			}
 
 			try
diff --git a/crypto/src/crypto/IXof.cs b/crypto/src/crypto/IXof.cs
new file mode 100644
index 000000000..e9e2253a0
--- /dev/null
+++ b/crypto/src/crypto/IXof.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <remarks>
+    /// With FIPS PUB 202 a new kind of message digest was announced which supported extendable output, or variable digest sizes.
+    /// This interface provides the extra method required to support variable output on a digest implementation.
+    /// </remarks>
+    public interface IXof
+        : IDigest
+    {
+        /**
+         * Output the results of the final calculation for this digest to outLen number of bytes.
+         *
+         * @param out output array to write the output bytes to.
+         * @param outOff offset to start writing the bytes at.
+         * @param outLen the number of output bytes requested.
+         * @return the number of bytes written
+         */
+        int DoFinal(byte[] output, int outOff, int outLen);
+    }
+}
diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs
new file mode 100644
index 000000000..2d6cf393c
--- /dev/null
+++ b/crypto/src/crypto/digests/KeccakDigest.cs
@@ -0,0 +1,534 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /// <summary>
+    /// Implementation of Keccak based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+    /// </summary>
+    /// <remarks>
+    /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+    /// </remarks>
+    public class KeccakDigest
+        : IDigest, IMemoable
+    {
+        private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
+
+        private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
+
+        private static ulong[] KeccakInitializeRoundConstants()
+        {
+            ulong[] keccakRoundConstants = new ulong[24];
+            byte LFSRState = 0x01;
+
+            for (int i = 0; i < 24; i++)
+            {
+                keccakRoundConstants[i] = 0;
+                for (int j = 0; j < 7; j++)
+                {
+                    int bitPosition = (1 << j) - 1;
+
+                    // LFSR86540
+
+                    bool loBit = (LFSRState & 0x01) != 0;
+                    if (loBit)
+                    {
+                        keccakRoundConstants[i] ^= 1UL << bitPosition;
+                    }
+
+                    bool hiBit = (LFSRState & 0x80) != 0;
+                    LFSRState <<= 1;
+                    if (hiBit)
+                    {
+                        LFSRState ^= 0x71;
+                    }
+
+                }
+            }
+
+            return keccakRoundConstants;
+        }
+
+        private static int[] KeccakInitializeRhoOffsets()
+        {
+            int[] keccakRhoOffsets = new int[25];
+            int x, y, t, newX, newY;
+
+            int rhoOffset = 0;
+            keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = rhoOffset;
+            x = 1;
+            y = 0;
+            for (t = 1; t < 25; t++)
+            {
+                //rhoOffset = ((t + 1) * (t + 2) / 2) % 64;
+                rhoOffset = (rhoOffset + t) & 63;
+                keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
+                newX = (0 * x + 1 * y) % 5;
+                newY = (2 * x + 3 * y) % 5;
+                x = newX;
+                y = newY;
+            }
+
+            return keccakRhoOffsets;
+        }
+
+        protected byte[] state = new byte[(1600 / 8)];
+        protected byte[] dataQueue = new byte[(1536 / 8)];
+        protected int rate;
+        protected int bitsInQueue;
+        protected int fixedOutputLength;
+        protected bool squeezing;
+        protected int bitsAvailableForSqueezing;
+        protected byte[] chunk;
+        protected byte[] oneByte;
+
+        private void ClearDataQueueSection(int off, int len)
+        {
+            for (int i = off; i != off + len; i++)
+            {
+                dataQueue[i] = 0;
+            }
+        }
+
+        public KeccakDigest()
+            : this(288)
+        {
+        }
+
+        public KeccakDigest(int bitLength)
+        {
+            Init(bitLength);
+        }
+
+        public KeccakDigest(KeccakDigest source)
+        {
+            CopyIn(source);
+        }
+
+        private void CopyIn(KeccakDigest source)
+        {
+            Array.Copy(source.state, 0, this.state, 0, source.state.Length);
+            Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
+            this.rate = source.rate;
+            this.bitsInQueue = source.bitsInQueue;
+            this.fixedOutputLength = source.fixedOutputLength;
+            this.squeezing = source.squeezing;
+            this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
+            this.chunk = Arrays.Clone(source.chunk);
+            this.oneByte = Arrays.Clone(source.oneByte);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "Keccak-" + fixedOutputLength; }
+        }
+
+        public virtual int GetDigestSize()
+        {
+            return fixedOutputLength / 8;
+        }
+
+        public virtual void Update(byte input)
+        {
+            oneByte[0] = input;
+
+            Absorb(oneByte, 0, 8L);
+        }
+
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            Absorb(input, inOff, len * 8L);
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            Squeeze(output, outOff, fixedOutputLength);
+
+            Reset();
+
+            return GetDigestSize();
+        }
+
+        /*
+         * TODO Possible API change to support partial-byte suffixes.
+         */
+        protected virtual int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+        {
+            if (partialBits > 0)
+            {
+                oneByte[0] = partialByte;
+                Absorb(oneByte, 0, partialBits);
+            }
+
+            Squeeze(output, outOff, fixedOutputLength);
+
+            Reset();
+
+            return GetDigestSize();
+        }
+
+        public virtual void Reset()
+        {
+            Init(fixedOutputLength);
+        }
+
+        /**
+         * Return the size of block that the compression function is applied to in bytes.
+         *
+         * @return internal byte length of a block.
+         */
+        public virtual int GetByteLength()
+        {
+            return rate / 8;
+        }
+
+        private void Init(int bitLength)
+        {
+            switch (bitLength)
+            {
+                case 128:
+                    InitSponge(1344, 256);
+                    break;
+                case 224:
+                    InitSponge(1152, 448);
+                    break;
+                case 256:
+                    InitSponge(1088, 512);
+                    break;
+                case 288:
+                    InitSponge(1024, 576);
+                    break;
+                case 384:
+                    InitSponge(832, 768);
+                    break;
+                case 512:
+                    InitSponge(576, 1024);
+                    break;
+                default:
+                    throw new ArgumentException("must be one of 128, 224, 256, 288, 384, or 512.", "bitLength");
+            }
+        }
+
+        private void InitSponge(int rate, int capacity)
+        {
+            if (rate + capacity != 1600)
+            {
+                throw new InvalidOperationException("rate + capacity != 1600");
+            }
+            if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
+            {
+                throw new InvalidOperationException("invalid rate value");
+            }
+
+            this.rate = rate;
+            // this is never read, need to check to see why we want to save it
+            //  this.capacity = capacity;
+            this.fixedOutputLength = 0;
+            Arrays.Fill(this.state, (byte)0);
+            Arrays.Fill(this.dataQueue, (byte)0);
+            this.bitsInQueue = 0;
+            this.squeezing = false;
+            this.bitsAvailableForSqueezing = 0;
+            this.fixedOutputLength = capacity / 2;
+            this.chunk = new byte[rate / 8];
+            this.oneByte = new byte[1];
+        }
+
+        private void AbsorbQueue()
+        {
+            KeccakAbsorb(state, dataQueue, rate / 8);
+
+            bitsInQueue = 0;
+        }
+
+        protected virtual void Absorb(byte[] data, int off, long databitlen)
+        {
+            long i, j, wholeBlocks;
+
+            if ((bitsInQueue % 8) != 0)
+            {
+                throw new InvalidOperationException("attempt to absorb with odd length queue.");
+            }
+            if (squeezing)
+            {
+                throw new InvalidOperationException("attempt to absorb while squeezing.");
+            }
+
+            i = 0;
+            while (i < databitlen)
+            {
+                if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate)))
+                {
+                    wholeBlocks = (databitlen - i) / rate;
+
+                    for (j = 0; j < wholeBlocks; j++)
+                    {
+                        Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length);
+
+                        KeccakAbsorb(state, chunk, chunk.Length);
+                    }
+
+                    i += wholeBlocks * rate;
+                }
+                else
+                {
+                    int partialBlock = (int)(databitlen - i);
+                    if (partialBlock + bitsInQueue > rate)
+                    {
+                        partialBlock = rate - bitsInQueue;
+                    }
+                    int partialByte = partialBlock % 8;
+                    partialBlock -= partialByte;
+                    Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8);
+
+                    bitsInQueue += partialBlock;
+                    i += partialBlock;
+                    if (bitsInQueue == rate)
+                    {
+                        AbsorbQueue();
+                    }
+                    if (partialByte > 0)
+                    {
+                        int mask = (1 << partialByte) - 1;
+                        dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask);
+                        bitsInQueue += partialByte;
+                        i += partialByte;
+                    }
+                }
+            }
+        }
+
+        private void PadAndSwitchToSqueezingPhase()
+        {
+            if (bitsInQueue + 1 == rate)
+            {
+                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
+                AbsorbQueue();
+                ClearDataQueueSection(0, rate / 8);
+            }
+            else
+            {
+                ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
+                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
+            }
+            dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8));
+            AbsorbQueue();
+
+            if (rate == 1024)
+            {
+                KeccakExtract1024bits(state, dataQueue);
+                bitsAvailableForSqueezing = 1024;
+            }
+            else
+            {
+                KeccakExtract(state, dataQueue, rate / 64);
+                bitsAvailableForSqueezing = rate;
+            }
+
+            squeezing = true;
+        }
+
+        protected virtual void Squeeze(byte[] output, int offset, long outputLength)
+        {
+            long i;
+            int partialBlock;
+
+            if (!squeezing)
+            {
+                PadAndSwitchToSqueezingPhase();
+            }
+            if ((outputLength % 8) != 0)
+            {
+                throw new InvalidOperationException("outputLength not a multiple of 8");
+            }
+
+            i = 0;
+            while (i < outputLength)
+            {
+                if (bitsAvailableForSqueezing == 0)
+                {
+                    KeccakPermutation(state);
+
+                    if (rate == 1024)
+                    {
+                        KeccakExtract1024bits(state, dataQueue);
+                        bitsAvailableForSqueezing = 1024;
+                    }
+                    else
+                    {
+                        KeccakExtract(state, dataQueue, rate / 64);
+                        bitsAvailableForSqueezing = rate;
+                    }
+                }
+                partialBlock = bitsAvailableForSqueezing;
+                if ((long)partialBlock > outputLength - i)
+                {
+                    partialBlock = (int)(outputLength - i);
+                }
+
+                Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8);
+                bitsAvailableForSqueezing -= partialBlock;
+                i += partialBlock;
+            }
+        }
+
+        private static void FromBytesToWords(ulong[] stateAsWords, byte[] state)
+        {
+            for (int i = 0; i < (1600 / 64); i++)
+            {
+                stateAsWords[i] = 0;
+                int index = i * (64 / 8);
+                for (int j = 0; j < (64 / 8); j++)
+                {
+                    stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j));
+                }
+            }
+        }
+
+        private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords)
+        {
+            for (int i = 0; i < (1600 / 64); i++)
+            {
+                int index = i * (64 / 8);
+                for (int j = 0; j < (64 / 8); j++)
+                {
+                    state[index + j] = (byte)(stateAsWords[i] >> (8 * j));
+                }
+            }
+        }
+
+        private void KeccakPermutation(byte[] state)
+        {
+            ulong[] longState = new ulong[state.Length / 8];
+
+            FromBytesToWords(longState, state);
+
+            KeccakPermutationOnWords(longState);
+
+            FromWordsToBytes(state, longState);
+        }
+
+        private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes)
+        {
+            for (int i = 0; i < dataLengthInBytes; i++)
+            {
+                state[i] ^= data[i];
+            }
+
+            KeccakPermutation(state);
+        }
+
+        private void KeccakPermutationOnWords(ulong[] state)
+        {
+            int i;
+
+            for (i = 0; i < 24; i++)
+            {
+                Theta(state);
+                Rho(state);
+                Pi(state);
+                Chi(state);
+                Iota(state, i);
+            }
+        }
+
+        ulong[] C = new ulong[5];
+
+        private void Theta(ulong[] A)
+        {
+            for (int x = 0; x < 5; x++)
+            {
+                C[x] = 0;
+                for (int y = 0; y < 5; y++)
+                {
+                    C[x] ^= A[x + 5 * y];
+                }
+            }
+            for (int x = 0; x < 5; x++)
+            {
+                ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5];
+                for (int y = 0; y < 5; y++)
+                {
+                    A[x + 5 * y] ^= dX;
+                }
+            }
+        }
+
+        private void Rho(ulong[] A)
+        {
+            for (int x = 0; x < 5; x++)
+            {
+                for (int y = 0; y < 5; y++)
+                {
+                    int index = x + 5 * y;
+                    A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]);
+                }
+            }
+        }
+
+        ulong[] tempA = new ulong[25];
+
+        private void Pi(ulong[] A)
+        {
+            Array.Copy(A, 0, tempA, 0, tempA.Length);
+
+            for (int x = 0; x < 5; x++)
+            {
+                for (int y = 0; y < 5; y++)
+                {
+                    A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y];
+                }
+            }
+        }
+
+        ulong[] chiC = new ulong[5];
+
+        private void Chi(ulong[] A)
+        {
+            for (int y = 0; y < 5; y++)
+            {
+                for (int x = 0; x < 5; x++)
+                {
+                    chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]);
+                }
+                for (int x = 0; x < 5; x++)
+                {
+                    A[x + 5 * y] = chiC[x];
+                }
+            }
+        }
+
+        private static void Iota(ulong[] A, int indexRound)
+        {
+            A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound];
+        }
+
+        private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes)
+        {
+            KeccakPermutationAfterXor(byteState, data, dataInBytes);
+        }
+
+        private void KeccakExtract1024bits(byte[] byteState, byte[] data)
+        {
+            Array.Copy(byteState, 0, data, 0, 128);
+        }
+
+        private void KeccakExtract(byte[] byteState, byte[] data, int laneCount)
+        {
+            Array.Copy(byteState, 0, data, 0, laneCount * 8);
+        }
+
+        public virtual IMemoable Copy()
+        {
+            return new KeccakDigest(this);
+        }
+
+        public virtual void Reset(IMemoable other)
+        {
+            KeccakDigest d = (KeccakDigest)other;
+
+            CopyIn(d);
+        }
+    }
+}
diff --git a/crypto/src/crypto/digests/SHA3Digest.cs b/crypto/src/crypto/digests/SHA3Digest.cs
index 2c6837b3c..890b665cf 100644
--- a/crypto/src/crypto/digests/SHA3Digest.cs
+++ b/crypto/src/crypto/digests/SHA3Digest.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 
 using Org.BouncyCastle.Utilities;
 
@@ -11,550 +12,75 @@ namespace Org.BouncyCastle.Crypto.Digests
     /// Following the naming conventions used in the C source code to enable easy review of the implementation.
     /// </remarks>
     public class Sha3Digest
-        : IDigest, IMemoable
+        : KeccakDigest
     {
-        private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
-
-        private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
-
-        private static ulong[] KeccakInitializeRoundConstants()
-        {
-            ulong[] keccakRoundConstants = new ulong[24];
-            byte LFSRState = 0x01;
-
-            for (int i = 0; i < 24; i++)
-            {
-                keccakRoundConstants[i] = 0;
-                for (int j = 0; j < 7; j++)
-                {
-                    int bitPosition = (1 << j) - 1;
-
-                    // LFSR86540
-
-                    bool loBit = (LFSRState & 0x01) != 0;
-                    if (loBit)
-                    {
-                        keccakRoundConstants[i] ^= 1UL << bitPosition;
-                    }
-
-                    bool hiBit = (LFSRState & 0x80) != 0;
-                    LFSRState <<= 1;
-                    if (hiBit)
-                    {
-                        LFSRState ^= 0x71;
-                    }
-
-                }
-            }
-
-            return keccakRoundConstants;
-        }
-
-        private static int[] KeccakInitializeRhoOffsets()
-        {
-            int[] keccakRhoOffsets = new int[25];
-            int x, y, t, newX, newY;
-
-            int rhoOffset = 0;
-            keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = rhoOffset;
-            x = 1;
-            y = 0;
-            for (t = 1; t < 25; t++)
-            {
-                //rhoOffset = ((t + 1) * (t + 2) / 2) % 64;
-                rhoOffset = (rhoOffset + t) & 63;
-                keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
-                newX = (0 * x + 1 * y) % 5;
-                newY = (2 * x + 3 * y) % 5;
-                x = newX;
-                y = newY;
-            }
-
-            return keccakRhoOffsets;
-        }
-
-        private byte[] state = new byte[(1600 / 8)];
-        private byte[] dataQueue = new byte[(1536 / 8)];
-        private int rate;
-        private int bitsInQueue;
-        private int fixedOutputLength;
-        private bool squeezing;
-        private int bitsAvailableForSqueezing;
-        private byte[] chunk;
-        private byte[] oneByte;
-
-        private void ClearDataQueueSection(int off, int len)
-        {
-            for (int i = off; i != off + len; i++)
-            {
-                dataQueue[i] = 0;
-            }
-        }
-
-        public Sha3Digest()
-        {
-            Init(0);
-        }
-
-        public Sha3Digest(int bitLength)
-        {
-            Init(bitLength);
-        }
-
-        public Sha3Digest(Sha3Digest source)
-        {
-			CopyIn(source);
-		}
-
-		private void CopyIn(Sha3Digest source)
-		{
-            Array.Copy(source.state, 0, this.state, 0, source.state.Length);
-            Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
-            this.rate = source.rate;
-            this.bitsInQueue = source.bitsInQueue;
-            this.fixedOutputLength = source.fixedOutputLength;
-            this.squeezing = source.squeezing;
-            this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
-            this.chunk = Arrays.Clone(source.chunk);
-            this.oneByte = Arrays.Clone(source.oneByte);
-        }
-
-        public virtual string AlgorithmName
-        {
-            get { return "SHA3-" + fixedOutputLength; }
-        }
-
-        public virtual int GetDigestSize()
-        {
-            return fixedOutputLength / 8;
-        }
-
-        public virtual void Update(byte input)
-        {
-            oneByte[0] = input;
-
-            DoUpdate(oneByte, 0, 8L);
-        }
-
-        public virtual void BlockUpdate(byte[] input, int inOff, int len)
-        {
-            DoUpdate(input, inOff, len * 8L);
-        }
-
-        public virtual int DoFinal(byte[] output, int outOff)
-        {
-            Squeeze(output, outOff, fixedOutputLength);
-
-            Reset();
-
-            return GetDigestSize();
-        }
-
-        public virtual void Reset()
-        {
-            Init(fixedOutputLength);
-        }
-
-        /**
-         * Return the size of block that the compression function is applied to in bytes.
-         *
-         * @return internal byte length of a block.
-         */
-        public virtual int GetByteLength()
-        {
-            return rate / 8;
-        }
-
-        private void Init(int bitLength)
+        private static int CheckBitLength(int bitLength)
         {
             switch (bitLength)
             {
-            case 0:
-            case 288:
-                InitSponge(1024, 576);
-                break;
             case 224:
-                InitSponge(1152, 448);
-                break;
             case 256:
-                InitSponge(1088, 512);
-                break;
             case 384:
-                InitSponge(832, 768);
-                break;
             case 512:
-                InitSponge(576, 1024);
-                break;
+                return bitLength;
             default:
-                throw new ArgumentException("must be one of 224, 256, 384, or 512.", "bitLength");
-            }
-        }
-
-        private void DoUpdate(byte[] data, int off, long databitlen)
-        {
-            if ((databitlen % 8) == 0)
-            {
-                Absorb(data, off, databitlen);
-            }
-            else
-            {
-                Absorb(data, off, databitlen - (databitlen % 8));
-
-                byte[] lastByte = new byte[1];
-
-                lastByte[0] = (byte)(data[off + (int)(databitlen / 8)] >> (int)(8 - (databitlen % 8)));
-                Absorb(lastByte, off, databitlen % 8);
-            }
-        }
-
-        private void InitSponge(int rate, int capacity)
-        {
-            if (rate + capacity != 1600)
-            {
-                throw new InvalidOperationException("rate + capacity != 1600");
-            }
-            if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
-            {
-                throw new InvalidOperationException("invalid rate value");
-            }
-
-            this.rate = rate;
-            // this is never read, need to check to see why we want to save it
-            //  this.capacity = capacity;
-            this.fixedOutputLength = 0;
-            Arrays.Fill(this.state, (byte)0);
-            Arrays.Fill(this.dataQueue, (byte)0);
-            this.bitsInQueue = 0;
-            this.squeezing = false;
-            this.bitsAvailableForSqueezing = 0;
-            this.fixedOutputLength = capacity / 2;
-            this.chunk = new byte[rate / 8];
-            this.oneByte = new byte[1];
-        }
-
-        private void AbsorbQueue()
-        {
-            KeccakAbsorb(state, dataQueue, rate / 8);
-
-            bitsInQueue = 0;
-        }
-
-        private void Absorb(byte[] data, int off, long databitlen)
-        {
-            long i, j, wholeBlocks;
-
-            if ((bitsInQueue % 8) != 0)
-            {
-                throw new InvalidOperationException("attempt to absorb with odd length queue.");
-            }
-            if (squeezing)
-            {
-                throw new InvalidOperationException("attempt to absorb while squeezing.");
-            }
-
-            i = 0;
-            while (i < databitlen)
-            {
-                if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate)))
-                {
-                    wholeBlocks = (databitlen - i) / rate;
-
-                    for (j = 0; j < wholeBlocks; j++)
-                    {
-                        Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length);
-
-                        //displayIntermediateValues.displayBytes(1, "Block to be absorbed", curData, rate / 8);
-
-                        KeccakAbsorb(state, chunk, chunk.Length);
-                    }
-
-                    i += wholeBlocks * rate;
-                }
-                else
-                {
-                    int partialBlock = (int)(databitlen - i);
-                    if (partialBlock + bitsInQueue > rate)
-                    {
-                        partialBlock = rate - bitsInQueue;
-                    }
-                    int partialByte = partialBlock % 8;
-                    partialBlock -= partialByte;
-                    Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8);
-
-                    bitsInQueue += partialBlock;
-                    i += partialBlock;
-                    if (bitsInQueue == rate)
-                    {
-                        AbsorbQueue();
-                    }
-                    if (partialByte > 0)
-                    {
-                        int mask = (1 << partialByte) - 1;
-                        dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask);
-                        bitsInQueue += partialByte;
-                        i += partialByte;
-                    }
-                }
+                throw new ArgumentException(bitLength + " not supported for SHA-3", "bitLength");
             }
         }
 
-        private void PadAndSwitchToSqueezingPhase()
-        {
-            if (bitsInQueue + 1 == rate)
-            {
-                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
-                AbsorbQueue();
-                ClearDataQueueSection(0, rate / 8);
-            }
-            else
-            {
-                ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
-                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
-            }
-            dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8));
-            AbsorbQueue();
-
-            //displayIntermediateValues.displayText(1, "--- Switching to squeezing phase ---");
-
-            if (rate == 1024)
-            {
-                KeccakExtract1024bits(state, dataQueue);
-                bitsAvailableForSqueezing = 1024;
-            }
-            else
-            {
-                KeccakExtract(state, dataQueue, rate / 64);
-                bitsAvailableForSqueezing = rate;
-            }
-
-            //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8);
-
-            squeezing = true;
-        }
-
-        private void Squeeze(byte[] output, int offset, long outputLength)
-        {
-            long i;
-            int partialBlock;
-
-            if (!squeezing)
-            {
-                PadAndSwitchToSqueezingPhase();
-            }
-            if ((outputLength % 8) != 0)
-            {
-                throw new InvalidOperationException("outputLength not a multiple of 8");
-            }
-
-            i = 0;
-            while (i < outputLength)
-            {
-                if (bitsAvailableForSqueezing == 0)
-                {
-                    KeccakPermutation(state);
-
-                    if (rate == 1024)
-                    {
-                        KeccakExtract1024bits(state, dataQueue);
-                        bitsAvailableForSqueezing = 1024;
-                    }
-                    else
-
-                    {
-                        KeccakExtract(state, dataQueue, rate / 64);
-                        bitsAvailableForSqueezing = rate;
-                    }
-
-                    //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8);
-
-                }
-                partialBlock = bitsAvailableForSqueezing;
-                if ((long)partialBlock > outputLength - i)
-                {
-                    partialBlock = (int)(outputLength - i);
-                }
-
-                Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8);
-                bitsAvailableForSqueezing -= partialBlock;
-                i += partialBlock;
-            }
-        }
-
-        private static void FromBytesToWords(ulong[] stateAsWords, byte[] state)
-        {
-            for (int i = 0; i < (1600 / 64); i++)
-            {
-                stateAsWords[i] = 0;
-                int index = i * (64 / 8);
-                for (int j = 0; j < (64 / 8); j++)
-                {
-                    stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j));
-                }
-            }
-        }
-
-        private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords)
+        public Sha3Digest()
+            : this(256)
         {
-            for (int i = 0; i < (1600 / 64); i++)
-            {
-                int index = i * (64 / 8);
-                for (int j = 0; j < (64 / 8); j++)
-                {
-                    state[index + j] = (byte)(stateAsWords[i] >> (8 * j));
-                }
-            }
         }
 
-        private void KeccakPermutation(byte[] state)
+        public Sha3Digest(int bitLength)
+            : base(CheckBitLength(bitLength))
         {
-            ulong[] longState = new ulong[state.Length / 8];
-
-            FromBytesToWords(longState, state);
-
-            //displayIntermediateValues.displayStateAsBytes(1, "Input of permutation", longState);
-
-            KeccakPermutationOnWords(longState);
-
-            //displayIntermediateValues.displayStateAsBytes(1, "State after permutation", longState);
-
-            FromWordsToBytes(state, longState);
         }
 
-        private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes)
+        public Sha3Digest(Sha3Digest source)
+            : base(source)
         {
-            for (int i = 0; i < dataLengthInBytes; i++)
-            {
-                state[i] ^= data[i];
-            }
-
-            KeccakPermutation(state);
         }
 
-        private void KeccakPermutationOnWords(ulong[] state)
+        public override string AlgorithmName
         {
-            int i;
-
-            //displayIntermediateValues.displayStateAs64bitWords(3, "Same, with lanes as 64-bit words", state);
-
-            for (i = 0; i < 24; i++)
-            {
-                //displayIntermediateValues.displayRoundNumber(3, i);
-
-                Theta(state);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After theta", state);
-
-                Rho(state);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After rho", state);
-
-                Pi(state);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After pi", state);
-
-                Chi(state);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After chi", state);
-
-                Iota(state, i);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After iota", state);
-            }
+            get { return "SHA3-" + fixedOutputLength; }
         }
 
-        ulong[] C = new ulong[5];
-
-        private void Theta(ulong[] A)
+        public override int DoFinal(byte[] output, int outOff)
         {
-            for (int x = 0; x < 5; x++)
-            {
-                C[x] = 0;
-                for (int y = 0; y < 5; y++)
-                {
-                    C[x] ^= A[x + 5 * y];
-                }
-            }
-            for (int x = 0; x < 5; x++)
-            {
-                ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5];
-                for (int y = 0; y < 5; y++)
-                {
-                    A[x + 5 * y] ^= dX;
-                }
-            }
-        }
+            Absorb(new byte[]{ 0x02 }, 0, 2);
 
-        private void Rho(ulong[] A)
-        {
-            for (int x = 0; x < 5; x++)
-            {
-                for (int y = 0; y < 5; y++)
-                {
-                    int index = x + 5 * y;
-                    A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]);
-                }
-            }
+            return base.DoFinal(output,  outOff);
         }
 
-        ulong[] tempA = new ulong[25];
-
-        private void Pi(ulong[] A)
+        /*
+         * TODO Possible API change to support partial-byte suffixes.
+         */
+        protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
         {
-            Array.Copy(A, 0, tempA, 0, tempA.Length);
-
-            for (int x = 0; x < 5; x++)
-            {
-                for (int y = 0; y < 5; y++)
-                {
-                    A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y];
-                }
-            }
-        }
+            if (partialBits < 0 || partialBits > 7)
+                throw new ArgumentException("must be in the range [0,7]", "partialBits");
 
-        ulong[] chiC = new ulong[5];
+            int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x02 << partialBits);
+            Debug.Assert(finalInput >= 0);
+            int finalBits = partialBits + 2;
 
-        private void Chi(ulong[] A)
-        {
-            for (int y = 0; y < 5; y++)
+            if (finalBits >= 8)
             {
-                for (int x = 0; x < 5; x++)
-                {
-                    chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]);
-                }
-                for (int x = 0; x < 5; x++)
-                {
-                    A[x + 5 * y] = chiC[x];
-                }
+                oneByte[0] = (byte)finalInput;
+                Absorb(oneByte, 0, 8);
+                finalBits -= 8;
+                finalInput >>= 8;
             }
-        }
-
-        private static void Iota(ulong[] A, int indexRound)
-        {
-            A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound];
-        }
-
-        private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes)
-        {
-            KeccakPermutationAfterXor(byteState, data, dataInBytes);
-        }
-
-        private void KeccakExtract1024bits(byte[] byteState, byte[] data)
-        {
-            Array.Copy(byteState, 0, data, 0, 128);
-        }
 
-        private void KeccakExtract(byte[] byteState, byte[] data, int laneCount)
-        {
-            Array.Copy(byteState, 0, data, 0, laneCount * 8);
+            return base.DoFinal(output, outOff, (byte)finalInput, finalBits);
         }
 
-		public IMemoable Copy()
+        public override IMemoable Copy()
 		{
 			return new Sha3Digest(this);
 		}
-
-		public void Reset(IMemoable other)
-		{
-			Sha3Digest d = (Sha3Digest)other;
-
-			CopyIn(d);
-		}
-
-
     }
 }
diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs
new file mode 100644
index 000000000..fd7d85681
--- /dev/null
+++ b/crypto/src/crypto/digests/ShakeDigest.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /// <summary>
+    /// Implementation of SHAKE based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+    /// </summary>
+    /// <remarks>
+    /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+    /// </remarks>
+    public class ShakeDigest
+        : KeccakDigest, IXof
+    {
+        private static int CheckBitLength(int bitLength)
+        {
+            switch (bitLength)
+            {
+            case 128:
+            case 256:
+                return bitLength;
+            default:
+                throw new ArgumentException(bitLength + " not supported for SHAKE", "bitLength");
+            }
+        }
+
+        public ShakeDigest()
+            : this(128)
+        {
+        }
+
+        public ShakeDigest(int bitLength)
+            : base(CheckBitLength(bitLength))
+        {
+        }
+
+        public ShakeDigest(ShakeDigest source)
+            : base(source)
+        {
+        }
+
+        public override string AlgorithmName
+        {
+            get { return "SHAKE" + fixedOutputLength; }
+        }
+
+        public override int DoFinal(byte[] output, int outOff)
+        {
+            return DoFinal(output, outOff, GetDigestSize());
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff, int outLen)
+        {
+            Absorb(new byte[]{ 0x0F }, 0, 4);
+
+            Squeeze(output, outOff, ((long)outLen) * 8);
+
+            Reset();
+
+            return outLen;
+        }
+
+        /*
+         * TODO Possible API change to support partial-byte suffixes.
+         */
+        protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+        {
+            return DoFinal(output, outOff, GetDigestSize(), partialByte, partialBits);
+        }
+
+        /*
+         * TODO Possible API change to support partial-byte suffixes.
+         */
+        protected virtual int DoFinal(byte[] output, int outOff, int outLen, byte partialByte, int partialBits)
+        {
+            if (partialBits < 0 || partialBits > 7)
+                throw new ArgumentException("must be in the range [0,7]", "partialBits");
+
+            int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x0F << partialBits);
+            Debug.Assert(finalInput >= 0);
+            int finalBits = partialBits + 4;
+
+            if (finalBits >= 8)
+            {
+                oneByte[0] = (byte)finalInput;
+                Absorb(oneByte, 0, 8);
+                finalBits -= 8;
+                finalInput >>= 8;
+            }
+
+            if (finalBits > 0)
+            {
+                oneByte[0] = (byte)finalInput;
+                Absorb(oneByte, 0, finalBits);
+            }
+
+            Squeeze(output, outOff, ((long)outLen) * 8);
+
+            Reset();
+
+            return outLen;
+        }
+
+        public override IMemoable Copy()
+        {
+            return new ShakeDigest(this);
+        }
+    }
+}
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 9d7f76c05..164c43ee9 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -237,12 +237,22 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const uint m1 = 0x80808080;
         private const uint m2 = 0x7f7f7f7f;
         private const uint m3 = 0x0000001b;
+        private const uint m4 = 0xC0C0C0C0;
+        private const uint m5 = 0x3f3f3f3f;
 
         private static uint FFmulX(uint x)
         {
             return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
         }
 
+        private static uint FFmulX2(uint x)
+        {
+            uint t0  = (x & m5) << 2;
+            uint t1  = (x & m4);
+                 t1 ^= (t1 >> 1);
+            return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+        }
+
         /*
         The following defines provide alternative definitions of FFmulX that might
         give improved performance if a fast 32-bit multiply is not available.
@@ -255,12 +265,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private static uint Inv_Mcol(uint x)
         {
-            uint f2 = FFmulX(x);
-            uint f4 = FFmulX(f2);
-            uint f8 = FFmulX(f4);
-            uint f9 = x ^ f8;
-
-            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+            uint t0, t1;
+            t0  = x;
+            t1  = t0 ^ Shift(t0, 8);
+            t0 ^= FFmulX(t1);
+            t1 ^= FFmulX2(t0);
+            t0 ^= t1 ^ Shift(t1, 16);
+            return t0;
         }
 
         private static uint SubWord(uint x)
diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs
index a1b544568..38ce1a946 100644
--- a/crypto/src/crypto/engines/AesFastEngine.cs
+++ b/crypto/src/crypto/engines/AesFastEngine.cs
@@ -573,12 +573,22 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const uint m1 = 0x80808080;
         private const uint m2 = 0x7f7f7f7f;
         private const uint m3 = 0x0000001b;
+        private const uint m4 = 0xC0C0C0C0;
+        private const uint m5 = 0x3f3f3f3f;
 
         private static uint FFmulX(uint x)
         {
             return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
         }
 
+        private static uint FFmulX2(uint x)
+        {
+            uint t0  = (x & m5) << 2;
+            uint t1  = (x & m4);
+                 t1 ^= (t1 >> 1);
+            return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+        }
+
         /*
         The following defines provide alternative definitions of FFmulX that might
         give improved performance if a fast 32-bit multiply is not available.
@@ -591,12 +601,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private static uint Inv_Mcol(uint x)
         {
-            uint f2 = FFmulX(x);
-            uint f4 = FFmulX(f2);
-            uint f8 = FFmulX(f4);
-            uint f9 = x ^ f8;
-
-            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+            uint t0, t1;
+            t0  = x;
+            t1  = t0 ^ Shift(t0, 8);
+            t0 ^= FFmulX(t1);
+            t1 ^= FFmulX2(t0);
+            t0 ^= t1 ^ Shift(t1, 16);
+            return t0;
         }
 
         private static uint SubWord(uint x)
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index a6b9e3bd4..a42b34971 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -126,12 +126,22 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const uint m1 = 0x80808080;
         private const uint m2 = 0x7f7f7f7f;
         private const uint m3 = 0x0000001b;
+        private const uint m4 = 0xC0C0C0C0;
+        private const uint m5 = 0x3f3f3f3f;
 
         private static uint FFmulX(uint x)
         {
             return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
         }
 
+        private static uint FFmulX2(uint x)
+        {
+            uint t0  = (x & m5) << 2;
+            uint t1  = (x & m4);
+                 t1 ^= (t1 >> 1);
+            return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+        }
+
         /*
         The following defines provide alternative definitions of FFmulX that might
         give improved performance if a fast 32-bit multiply is not available.
@@ -144,18 +154,21 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private static uint Mcol(uint x)
         {
-            uint f2 = FFmulX(x);
-            return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24);
+            uint t0, t1;
+            t0 = Shift(x, 8);
+            t1 = x ^ t0;
+            return Shift(t1, 16) ^ t0 ^ FFmulX(t1);
         }
 
         private static uint Inv_Mcol(uint x)
         {
-            uint f2 = FFmulX(x);
-            uint f4 = FFmulX(f2);
-            uint f8 = FFmulX(f4);
-            uint f9 = x ^ f8;
-
-            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+            uint t0, t1;
+            t0  = x;
+            t1  = t0 ^ Shift(t0, 8);
+            t0 ^= FFmulX(t1);
+            t1 ^= FFmulX2(t0);
+            t0 ^= t1 ^ Shift(t1, 16);
+            return t0;
         }
 
         private static uint SubWord(uint x)
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index de41d88f4..d8ab2ca73 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -46,6 +46,13 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             return tmp;
         }
 
+        internal static ulong[] OneAsUlongs()
+        {
+            ulong[] tmp = new ulong[2];
+            tmp[0] = 1UL << 63;
+            return tmp;
+        }
+
         internal static byte[] AsBytes(uint[] x)
         {
             return Pack.UInt32_To_BE(x);
@@ -56,6 +63,18 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             Pack.UInt32_To_BE(x, z, 0);
         }
 
+        internal static byte[] AsBytes(ulong[] x)
+        {
+            byte[] z = new byte[16];
+            Pack.UInt64_To_BE(x, z, 0);
+            return z;
+        }
+
+        internal static void AsBytes(ulong[] x, byte[] z)
+        {
+            Pack.UInt64_To_BE(x, z, 0);
+        }
+
         internal static uint[] AsUints(byte[] bs)
         {
             uint[] output = new uint[4];
@@ -68,6 +87,18 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             Pack.BE_To_UInt32(bs, 0, output);
         }
 
+        internal static ulong[] AsUlongs(byte[] x)
+        {
+            ulong[] z = new ulong[2];
+            Pack.BE_To_UInt64(x, 0, z);
+            return z;
+        }
+
+        public static void AsUlongs(byte[] x, ulong[] z)
+        {
+            Pack.BE_To_UInt64(x, 0, z);
+        }
+
         internal static void Multiply(byte[] x, byte[] y)
         {
             uint[] t1 = GcmUtilities.AsUints(x);
@@ -80,7 +111,7 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
         {
             uint r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3];
             uint r10 = 0, r11 = 0, r12 = 0, r13 = 0;
-        
+
             for (int i = 0; i < 4; ++i)
             {
                 int bits = (int)y[i];
@@ -93,9 +124,9 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
                     r13 ^= (r03 & m1);
 
                     uint m2 = (uint)((int)(r03 << 31) >> 8);
-                    r03 = (r03 >> 1) | (r02 << 63);
-                    r02 = (r02 >> 1) | (r01 << 63);
-                    r01 = (r01 >> 1) | (r00 << 63);
+                    r03 = (r03 >> 1) | (r02 << 31);
+                    r02 = (r02 >> 1) | (r01 << 31);
+                    r01 = (r01 >> 1) | (r00 << 31);
                     r00 = (r00 >> 1) ^ (m2 & E1);
                 }
             }
@@ -119,7 +150,7 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
                     r10 ^= (r00 & m1);
                     r11 ^= (r01 & m1);
 
-                    ulong m2 = (r01 << 63) >> 8;
+                    ulong m2 = (ulong)((long)(r01 << 63) >> 8);
                     r01 = (r01 >> 1) | (r00 << 63);
                     r00 = (r00 >> 1) ^ (m2 & E1L);
                 }
@@ -272,5 +303,17 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             z[2] = x[2] ^ y[2];
             z[3] = x[3] ^ y[3];
         }
+
+        internal static void Xor(ulong[] x, ulong[] y)
+        {
+            x[0] ^= y[0];
+            x[1] ^= y[1];
+        }
+
+        internal static void Xor(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+        }
     }
 }
diff --git a/crypto/src/crypto/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs
index a0544e73b..4258df5c5 100644
--- a/crypto/src/crypto/parameters/DHParameters.cs
+++ b/crypto/src/crypto/parameters/DHParameters.cs
@@ -91,6 +91,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 				throw new ArgumentException("m value must be < bitlength of p", "m");
 			if (l != 0)
 			{ 
+                // TODO Check this against the Java version, which has 'l > p.BitLength' here
 	            if (l >= p.BitLength)
                 	throw new ArgumentException("when l value specified, it must be less than bitlength(p)", "l");
 				if (l < m)
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index 1486656bd..fb117c19d 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -26,29 +26,23 @@ namespace Org.BouncyCastle.Crypto.Signers
             return recoveredMessage;
         }
 
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerImplicit = 0xBC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerRipeMD160 = 0x31CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerRipeMD128 = 0x32CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha1 = 0x33CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha256 = 0x34CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha512 = 0x35CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha384 = 0x36CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerWhirlpool = 0x37CC;
 
-        private static readonly IDictionary trailerMap = Platform.CreateHashtable();
-
-        static Iso9796d2PssSigner()
-        {
-            trailerMap.Add("RIPEMD128", TrailerRipeMD128);
-            trailerMap.Add("RIPEMD160", TrailerRipeMD160);
-            trailerMap.Add("SHA-1", TrailerSha1);
-            trailerMap.Add("SHA-256", TrailerSha256);
-            trailerMap.Add("SHA-384", TrailerSha384);
-            trailerMap.Add("SHA-512", TrailerSha512);
-
-            trailerMap.Add("Whirlpool", TrailerWhirlpool);
-        }
-
         private IDigest digest;
         private IAsymmetricBlockCipher cipher;
 
@@ -71,8 +65,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         private int preTLength;
 
         /// <summary>
-        /// Generate a signer for the with either implicit or explicit trailers
-        /// for ISO9796-2, scheme 2 or 3.
+        /// Generate a signer with either implicit or explicit trailers for ISO9796-2, scheme 2 or 3.
         /// </summary>
         /// <param name="cipher">base cipher to use for signature creation/verification</param>
         /// <param name="digest">digest to use.</param>
@@ -91,15 +84,15 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (isImplicit)
             {
-                trailer = TrailerImplicit;
+                trailer = IsoTrailers.TRAILER_IMPLICIT;
+            }
+            else if (IsoTrailers.NoTrailerAvailable(digest))
+            {
+                throw new ArgumentException("no valid trailer", "digest");
             }
             else
             {
-                string digestAlg = digest.AlgorithmName;
-                if (!trailerMap.Contains(digestAlg))
-                    throw new ArgumentException("no valid trailer for digest");
-
-                trailer = (int)trailerMap[digestAlg];
+                trailer = IsoTrailers.GetTrailer(digest);
             }
         }
 
@@ -180,7 +173,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             block = new byte[(keyBits + 7) / 8];
 
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1];
             }
@@ -247,11 +240,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             {
                 int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
 
-                string digestAlg = digest.AlgorithmName;
-                if (!trailerMap.Contains(digestAlg))
+                if (IsoTrailers.NoTrailerAvailable(digest))
                     throw new ArgumentException("unrecognised hash in signature");
 
-                if (sigTrail != (int)trailerMap[digestAlg])
+                if (sigTrail != IsoTrailers.GetTrailer(digest))
                     throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
 
                 tLength = 2;
@@ -395,7 +387,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             digest.DoFinal(hash, 0);
 
             int tLength = 2;
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 tLength = 1;
             }
@@ -415,9 +407,9 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen);
 
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
-                block[block.Length - 1] = (byte)TrailerImplicit;
+                block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
             }
             else
             {
diff --git a/crypto/src/crypto/signers/Iso9796d2Signer.cs b/crypto/src/crypto/signers/Iso9796d2Signer.cs
index 4bb4d17a6..b90ed8f0b 100644
--- a/crypto/src/crypto/signers/Iso9796d2Signer.cs
+++ b/crypto/src/crypto/signers/Iso9796d2Signer.cs
@@ -21,30 +21,23 @@ namespace Org.BouncyCastle.Crypto.Signers
             return recoveredMessage;
         }
 
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerImplicit = 0xBC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerRipeMD160 = 0x31CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerRipeMD128 = 0x32CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha1 = 0x33CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha256 = 0x34CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha512 = 0x35CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha384 = 0x36CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerWhirlpool = 0x37CC;
 
-        private static IDictionary trailerMap = Platform.CreateHashtable();
-
-        static Iso9796d2Signer()
-        {
-            trailerMap.Add("RIPEMD128", TrailerRipeMD128);
-            trailerMap.Add("RIPEMD160", TrailerRipeMD160);
-
-            trailerMap.Add("SHA-1", TrailerSha1);
-            trailerMap.Add("SHA-256", TrailerSha256);
-            trailerMap.Add("SHA-384", TrailerSha384);
-            trailerMap.Add("SHA-512", TrailerSha512);
-
-            trailerMap.Add("Whirlpool", TrailerWhirlpool);
-        }
-
         private IDigest digest;
         private IAsymmetricBlockCipher cipher;
 
@@ -60,8 +53,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         private byte[] preBlock;
 
         /// <summary>
-        /// Generate a signer for the with either implicit or explicit trailers
-        /// for ISO9796-2.
+        /// Generate a signer with either implicit or explicit trailers for ISO9796-2.
         /// </summary>
         /// <param name="cipher">base cipher to use for signature creation/verification</param>
         /// <param name="digest">digest to use.</param>
@@ -76,20 +68,15 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (isImplicit)
             {
-                trailer = TrailerImplicit;
+                trailer = IsoTrailers.TRAILER_IMPLICIT;
+            }
+            else if (IsoTrailers.NoTrailerAvailable(digest))
+            {
+                throw new ArgumentException("no valid trailer", "digest");
             }
             else
             {
-                string digestName = digest.AlgorithmName;
-
-                if (trailerMap.Contains(digestName))
-                {
-                    trailer = (int)trailerMap[digest.AlgorithmName];
-                }
-                else
-                {
-                    throw new System.ArgumentException("no valid trailer for digest");
-                }
+                trailer = IsoTrailers.GetTrailer(digest);
             }
         }
 
@@ -119,7 +106,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             keyBits = kParam.Modulus.BitLength;
 
             block = new byte[(keyBits + 7) / 8];
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 mBuf = new byte[block.Length - digest.GetDigestSize() - 2];
             }
@@ -195,10 +182,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             {
                 int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
 
-                string digestName = digest.AlgorithmName;
-                if (!trailerMap.Contains(digestName))
+                if (IsoTrailers.NoTrailerAvailable(digest))
                     throw new ArgumentException("unrecognised hash in signature");
-                if (sigTrail != (int)trailerMap[digestName])
+
+                if (sigTrail != IsoTrailers.GetTrailer(digest))
                     throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
 
                 delta = 2;
@@ -319,12 +306,12 @@ namespace Org.BouncyCastle.Crypto.Signers
             int t = 0;
             int delta = 0;
 
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 t = 8;
                 delta = block.Length - digSize - 1;
                 digest.DoFinal(block, delta);
-                block[block.Length - 1] = (byte) TrailerImplicit;
+                block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
             }
             else
             {
@@ -424,10 +411,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             {
                 int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
 
-                string digestName = digest.AlgorithmName;
-                if (!trailerMap.Contains(digestName))
+                if (IsoTrailers.NoTrailerAvailable(digest))
                     throw new ArgumentException("unrecognised hash in signature");
-                if (sigTrail != (int)trailerMap[digestName])
+
+                if (sigTrail != IsoTrailers.GetTrailer(digest))
                     throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
 
                 delta = 2;
diff --git a/crypto/src/crypto/signers/IsoTrailers.cs b/crypto/src/crypto/signers/IsoTrailers.cs
new file mode 100644
index 000000000..497ffaf78
--- /dev/null
+++ b/crypto/src/crypto/signers/IsoTrailers.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class IsoTrailers
+    {
+        public const int TRAILER_IMPLICIT    = 0xBC;
+        public const int TRAILER_RIPEMD160   = 0x31CC;
+        public const int TRAILER_RIPEMD128   = 0x32CC;
+        public const int TRAILER_SHA1        = 0x33CC;
+        public const int TRAILER_SHA256      = 0x34CC;
+        public const int TRAILER_SHA512      = 0x35CC;
+        public const int TRAILER_SHA384      = 0x36CC;
+        public const int TRAILER_WHIRLPOOL   = 0x37CC;
+        public const int TRAILER_SHA224      = 0x38CC;
+        public const int TRAILER_SHA512_224  = 0x39CC;
+        public const int TRAILER_SHA512_256  = 0x40CC;
+
+        private static IDictionary CreateTrailerMap()
+        {
+            IDictionary trailers = Platform.CreateHashtable();
+
+            trailers.Add("RIPEMD128", TRAILER_RIPEMD128);
+            trailers.Add("RIPEMD160", TRAILER_RIPEMD160);
+
+            trailers.Add("SHA-1", TRAILER_SHA1);
+            trailers.Add("SHA-224", TRAILER_SHA224);
+            trailers.Add("SHA-256", TRAILER_SHA256);
+            trailers.Add("SHA-384", TRAILER_SHA384);
+            trailers.Add("SHA-512", TRAILER_SHA512);
+            trailers.Add("SHA-512/224", TRAILER_SHA512_224);
+            trailers.Add("SHA-512/256", TRAILER_SHA512_256);
+
+            trailers.Add("Whirlpool", TRAILER_WHIRLPOOL);
+
+            return CollectionUtilities.ReadOnly(trailers);
+        }
+
+        // IDictionary is (string -> Int32)
+        private static readonly IDictionary trailerMap = CreateTrailerMap();
+
+        public static int GetTrailer(IDigest digest)
+        {
+            return (int)trailerMap[digest.AlgorithmName];
+        }
+
+        public static bool NoTrailerAvailable(IDigest digest)
+        {
+            return !trailerMap.Contains(digest.AlgorithmName);
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/X931Signer.cs b/crypto/src/crypto/signers/X931Signer.cs
index 89f512b78..36483fe17 100644
--- a/crypto/src/crypto/signers/X931Signer.cs
+++ b/crypto/src/crypto/signers/X931Signer.cs
@@ -20,31 +20,24 @@ namespace Org.BouncyCastle.Crypto.Signers
     public class X931Signer
         :   ISigner
     {
-        public const int TRAILER_IMPLICIT    = 0xBC;
-        public const int TRAILER_RIPEMD160   = 0x31CC;
-        public const int TRAILER_RIPEMD128   = 0x32CC;
-        public const int TRAILER_SHA1        = 0x33CC;
-        public const int TRAILER_SHA256      = 0x34CC;
-        public const int TRAILER_SHA512      = 0x35CC;
-        public const int TRAILER_SHA384      = 0x36CC;
-        public const int TRAILER_WHIRLPOOL   = 0x37CC;
-        public const int TRAILER_SHA224      = 0x38CC;
-
-        private static readonly IDictionary trailerMap = Platform.CreateHashtable();
-
-        static X931Signer()
-        {
-            trailerMap.Add("RIPEMD128", TRAILER_RIPEMD128);
-            trailerMap.Add("RIPEMD160", TRAILER_RIPEMD160);
-
-            trailerMap.Add("SHA-1", TRAILER_SHA1);
-            trailerMap.Add("SHA-224", TRAILER_SHA224);
-            trailerMap.Add("SHA-256", TRAILER_SHA256);
-            trailerMap.Add("SHA-384", TRAILER_SHA384);
-            trailerMap.Add("SHA-512", TRAILER_SHA512);
-
-            trailerMap.Add("Whirlpool", TRAILER_WHIRLPOOL);
-        }
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_IMPLICIT = 0xBC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_RIPEMD160 = 0x31CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_RIPEMD128 = 0x32CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA1 = 0x33CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA256 = 0x34CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA512 = 0x35CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA384 = 0x36CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_WHIRLPOOL = 0x37CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA224 = 0x38CC;
 
         private IDigest                     digest;
         private IAsymmetricBlockCipher      cipher;
@@ -55,8 +48,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         private byte[]      block;
 
         /**
-         * Generate a signer for the with either implicit or explicit trailers
-         * for ISO9796-2.
+         * Generate a signer with either implicit or explicit trailers for X9.31.
          *
          * @param cipher base cipher to use for signature creation/verification
          * @param digest digest to use.
@@ -69,15 +61,15 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (isImplicit)
             {
-                trailer = TRAILER_IMPLICIT;
+                trailer = IsoTrailers.TRAILER_IMPLICIT;
+            }
+            else if (IsoTrailers.NoTrailerAvailable(digest))
+            {
+                throw new ArgumentException("no valid trailer", "digest");
             }
             else
             {
-                string name = digest.AlgorithmName;
-                if (!trailerMap.Contains(name))
-                    throw new ArgumentException("no valid trailer", "digest");
-
-                trailer = (int)trailerMap[name];
+                trailer = IsoTrailers.GetTrailer(digest);
             }
         }
 
@@ -161,12 +153,11 @@ namespace Org.BouncyCastle.Crypto.Signers
             int digSize = digest.GetDigestSize();
 
             int delta;
-
-            if (trailer == TRAILER_IMPLICIT)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 delta = block.Length - digSize - 1;
                 digest.DoFinal(block, delta);
-                block[block.Length - 1] = (byte)TRAILER_IMPLICIT;
+                block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
             }
             else
             {
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index 087cb7cea..dc00ab450 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -117,6 +117,22 @@ namespace Org.BouncyCastle.Crypto.Utilities
             UInt32_To_BE((uint)(n), bs, off + 4);
         }
 
+        internal static byte[] UInt64_To_BE(ulong[] ns)
+        {
+            byte[] bs = new byte[8 * ns.Length];
+            UInt64_To_BE(ns, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt64_To_BE(ulong[] ns, byte[] bs, int off)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                UInt64_To_BE(ns[i], bs, off);
+                off += 8;
+            }
+        }
+
         internal static ulong BE_To_UInt64(byte[] bs)
         {
             uint hi = BE_To_UInt32(bs);
@@ -131,6 +147,15 @@ namespace Org.BouncyCastle.Crypto.Utilities
             return ((ulong)hi << 32) | (ulong)lo;
         }
 
+        internal static void BE_To_UInt64(byte[] bs, int off, ulong[] ns)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                ns[i] = BE_To_UInt64(bs, off);
+                off += 8;
+            }
+        }
+
         internal static void UInt16_To_LE(ushort n, byte[] bs)
         {
             bs[0] = (byte)(n);
diff --git a/crypto/src/math/Primes.cs b/crypto/src/math/Primes.cs
index b57977983..420c3cc5a 100644
--- a/crypto/src/math/Primes.cs
+++ b/crypto/src/math/Primes.cs
@@ -1,18 +1,69 @@
 using System;
 
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math
 {
-    public static class Primes
+    /**
+     * Utility methods for generating primes and testing for primality.
+     */
+    public abstract class Primes
     {
         private static readonly BigInteger One = BigInteger.One;
         private static readonly BigInteger Two = BigInteger.Two;
         private static readonly BigInteger Three = BigInteger.Three;
 
         /**
-         * Used to return the output from the {@linkplain #generateSTRandomPrime(Digest) Shawe-Taylor Random_Prime Routine} 
+         * Used to return the output from the
+         * {@linkplain Primes#enhancedMRProbablePrimeTest(BigInteger, SecureRandom, int) Enhanced
+         * Miller-Rabin Probabilistic Primality Test}
+         */
+        public class MROutput
+        {
+            internal static MROutput ProbablyPrime()
+            {
+                return new MROutput(false, null);
+            }
+
+            internal static MROutput ProvablyCompositeWithFactor(BigInteger factor)
+            {
+                return new MROutput(true, factor);
+            }
+
+            internal static MROutput ProvablyCompositeNotPrimePower()
+            {
+                return new MROutput(true, null);
+            }
+
+            private readonly bool mProvablyComposite;
+            private readonly BigInteger mFactor;
+
+            private MROutput(bool provablyComposite, BigInteger factor)
+            {
+                this.mProvablyComposite = provablyComposite;
+                this.mFactor = factor;
+            }
+
+            public BigInteger Factor
+            {
+                get { return mFactor; }
+            }
+
+            public bool IsProvablyComposite
+            {
+                get { return mProvablyComposite; }
+            }
+
+            public bool IsNotPrimePower
+            {
+                get { return mProvablyComposite && mFactor == null; }
+            }
+        }
+
+        /**
+         * Used to return the output from the {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime Routine} 
          */
         public class STOutput
         {
@@ -51,11 +102,11 @@ namespace Org.BouncyCastle.Math
          * @param hash
          *            the {@link Digest} instance to use (as "Hash()"). Cannot be null.
          * @param length
-         *            the length (in bits) of the prime to be generated. Must be >= 2.
+         *            the length (in bits) of the prime to be generated. Must be at least 2.
          * @param inputSeed
          *            the seed to be used for the generation of the requested prime. Cannot be null or
          *            empty.
-         * @returns an {@link STOutput} instance containing the requested prime.
+         * @return an {@link STOutput} instance containing the requested prime.
          */
         public static STOutput GenerateSTRandomPrime(IDigest hash, int length, byte[] inputSeed)
         {
@@ -71,6 +122,269 @@ namespace Org.BouncyCastle.Math
             return ImplSTRandomPrime(hash, length, Arrays.Clone(inputSeed));
         }
 
+        /**
+         * FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test
+         * 
+         * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an
+         * alternative to {@link #isMRProbablePrime(BigInteger, SecureRandom, int)} that provides more
+         * information about a composite candidate, which may be useful when generating or validating
+         * RSA moduli.
+         * 
+         * @param candidate
+         *            the {@link BigInteger} instance to test for primality.
+         * @param random
+         *            the source of randomness to use to choose bases.
+         * @param iterations
+         *            the number of randomly-chosen bases to perform the test for.
+         * @return an {@link MROutput} instance that can be further queried for details.
+         */
+        public static MROutput EnhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations)
+        {
+            CheckCandidate(candidate, "candidate");
+
+            if (random == null)
+                throw new ArgumentNullException("random");
+            if (iterations < 1)
+                throw new ArgumentException("must be > 0", "iterations");
+
+            if (candidate.BitLength == 2)
+                return MROutput.ProbablyPrime();
+
+            if (!candidate.TestBit(0))
+                return MROutput.ProvablyCompositeWithFactor(Two);
+
+            BigInteger w = candidate;
+            BigInteger wSubOne = candidate.Subtract(One);
+            BigInteger wSubTwo = candidate.Subtract(Two);
+
+            int a = wSubOne.GetLowestSetBit();
+            BigInteger m = wSubOne.ShiftRight(a);
+
+            for (int i = 0; i < iterations; ++i)
+            {
+                BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
+                BigInteger g = b.Gcd(w);
+
+                if (g.CompareTo(One) > 0)
+                    return MROutput.ProvablyCompositeWithFactor(g);
+
+                BigInteger z = b.ModPow(m, w);
+
+                if (z.Equals(One) || z.Equals(wSubOne))
+                    continue;
+
+                bool primeToBase = false;
+
+                BigInteger x = z;
+                for (int j = 1; j < a; ++j)
+                {
+                    z = z.ModPow(Two, w);
+
+                    if (z.Equals(wSubOne))
+                    {
+                        primeToBase = true;
+                        break;
+                    }
+
+                    if (z.Equals(One))
+                        break;
+
+                    x = z;
+                }
+
+                if (!primeToBase)
+                {
+                    if (!z.Equals(One))
+                    {
+                        x = z;
+                        z = z.ModPow(Two, w);
+
+                        if (!z.Equals(One))
+                        {
+                            x = z;
+                        }
+                    }
+
+                    g = x.Subtract(One).Gcd(w);
+
+                    if (g.CompareTo(One) > 0)
+                        return MROutput.ProvablyCompositeWithFactor(g);
+
+                    return MROutput.ProvablyCompositeNotPrimePower();
+                }
+            }
+
+            return MROutput.ProbablyPrime();
+        }
+
+        /**
+         * A fast check for small divisors, up to some implementation-specific limit.
+         * 
+         * @param candidate
+         *            the {@link BigInteger} instance to test for division by small factors.
+         * 
+         * @return <code>true</code> if the candidate is found to have any small factors,
+         *         <code>false</code> otherwise.
+         */
+        public static bool HasAnySmallFactors(BigInteger candidate)
+        {
+            CheckCandidate(candidate, "candidate");
+
+            return ImplHasAnySmallFactors(candidate);
+        }
+
+        /**
+         * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test
+         * 
+         * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases.
+         * 
+         * @param candidate
+         *            the {@link BigInteger} instance to test for primality.
+         * @param random
+         *            the source of randomness to use to choose bases.
+         * @param iterations
+         *            the number of randomly-chosen bases to perform the test for.
+         * @return <code>false</code> if any witness to compositeness is found amongst the chosen bases
+         *         (so <code>candidate</code> is definitely NOT prime), or else <code>true</code>
+         *         (indicating primality with some probability dependent on the number of iterations
+         *         that were performed).
+         */
+        public static bool IsMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations)
+        {
+            CheckCandidate(candidate, "candidate");
+
+            if (random == null)
+                throw new ArgumentException("cannot be null", "random");
+            if (iterations < 1)
+                throw new ArgumentException("must be > 0", "iterations");
+
+            if (candidate.BitLength == 2)
+                return true;
+            if (!candidate.TestBit(0))
+                return false;
+
+            BigInteger w = candidate;
+            BigInteger wSubOne = candidate.Subtract(One);
+            BigInteger wSubTwo = candidate.Subtract(Two);
+
+            int a = wSubOne.GetLowestSetBit();
+            BigInteger m = wSubOne.ShiftRight(a);
+
+            for (int i = 0; i < iterations; ++i)
+            {
+                BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
+
+                if (!ImplMRProbablePrimeToBase(w, wSubOne, m, a, b))
+                    return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base).
+         * 
+         * Run a single iteration of the Miller-Rabin algorithm against the specified base.
+         * 
+         * @param candidate
+         *            the {@link BigInteger} instance to test for primality.
+         * @param baseValue
+         *            the base value to use for this iteration.
+         * @return <code>false</code> if the specified base is a witness to compositeness (so
+         *         <code>candidate</code> is definitely NOT prime), or else <code>true</code>.
+         */
+        public static bool IsMRProbablePrimeToBase(BigInteger candidate, BigInteger baseValue)
+        {
+            CheckCandidate(candidate, "candidate");
+            CheckCandidate(baseValue, "baseValue");
+
+            if (baseValue.CompareTo(candidate.Subtract(One)) >= 0)
+                throw new ArgumentException("must be < ('candidate' - 1)", "baseValue");
+
+            if (candidate.BitLength == 2)
+                return true;
+
+            BigInteger w = candidate;
+            BigInteger wSubOne = candidate.Subtract(One);
+
+            int a = wSubOne.GetLowestSetBit();
+            BigInteger m = wSubOne.ShiftRight(a);
+
+            return ImplMRProbablePrimeToBase(w, wSubOne, m, a, baseValue);
+        }
+
+        private static void CheckCandidate(BigInteger n, string name)
+        {
+            if (n == null || n.SignValue < 1 || n.BitLength < 2)
+                throw new ArgumentException("must be non-null and >= 2", name);
+        }
+
+        private static bool ImplHasAnySmallFactors(BigInteger x)
+        {
+            /*
+             * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders.
+             */
+            int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
+            int r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+            if ((r & 1) != 0 && (r % 3) != 0 && (r % 5) != 0 && (r % 7) != 0 && (r % 11) != 0
+                && (r % 13) != 0 && (r % 17) != 0 && (r % 19) != 0 && (r % 23) != 0)
+            {
+                m = 29 * 31 * 37 * 41 * 43;
+                r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                if ((r % 29) != 0 && (r % 31) != 0 && (r % 37) != 0 && (r % 41) != 0 && (r % 43) != 0)
+                {
+                    m = 47 * 53 * 59 * 61 * 67;
+                    r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                    if ((r % 47) != 0 && (r % 53) != 0 && (r % 59) != 0 && (r % 61) != 0 && (r % 67) != 0)
+                    {
+                        m = 71 * 73 * 79 * 83;
+                        r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                        if ((r % 71) != 0 && (r % 73) != 0 && (r % 79) != 0 && (r % 83) != 0)
+                        {
+                            m = 89 * 97 * 101 * 103;
+                            r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                            if ((r % 89) != 0 && (r % 97) != 0 && (r % 101) != 0 && (r % 103) != 0)
+                            {
+                                m = 107 * 109 * 113 * 127;
+                                r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                                if ((r % 107) != 0 && (r % 109) != 0 && (r % 113) != 0 && (r % 127) != 0)
+                                {
+                                    return false;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            return true;
+        }
+
+        private static bool ImplMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b)
+        {
+            BigInteger z = b.ModPow(m, w);
+
+            if (z.Equals(One) || z.Equals(wSubOne))
+                return true;
+
+            bool result = false;
+
+            for (int j = 1; j < a; ++j)
+            {
+                z = z.ModPow(Two, w);
+
+                if (z.Equals(wSubOne))
+                {
+                    result = true;
+                    break;
+                }
+
+                if (z.Equals(One))
+                    return false;
+            }
+
+            return result;
+        }
+
         private static STOutput ImplSTRandomPrime(IDigest d, int length, byte[] primeSeed)
         {
             int dLen = d.GetDigestSize();
@@ -131,7 +445,7 @@ namespace Org.BouncyCastle.Math
 
                 /*
                  * TODO Since the candidate primes are generated by constant steps ('c0x2'),
-                 * sieving could be used here in place of the 'mightBePrime' approach.
+                 * sieving could be used here in place of the 'HasAnySmallFactors' approach.
                  */
                 for (;;)
                 {
@@ -149,7 +463,7 @@ namespace Org.BouncyCastle.Math
                      * 
                      * NOTE: 'primeSeed' is still incremented as if we performed the full check!
                      */
-                    if (MightBePrime(c))
+                    if (!ImplHasAnySmallFactors(c))
                     {
                         BigInteger a = HashGen(d, primeSeed, iterations + 1);
                         a = a.Mod(c.Subtract(Three)).Add(Two);
@@ -266,45 +580,5 @@ namespace Org.BouncyCastle.Math
                 }
             }
         }
-
-        private static bool MightBePrime(BigInteger x)
-        {
-            /*
-             * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders.
-             */
-            int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
-            int r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-            if ((r & 1) != 0 && (r % 3) != 0 && (r % 5) != 0 && (r % 7) != 0 && (r % 11) != 0
-                && (r % 13) != 0 && (r % 17) != 0 && (r % 19) != 0 && (r % 23) != 0)
-            {
-                m = 29 * 31 * 37 * 41 * 43;
-                r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                if ((r % 29) != 0 && (r % 31) != 0 && (r % 37) != 0 && (r % 41) != 0 && (r % 43) != 0)
-                {
-                    m = 47 * 53 * 59 * 61 * 67;
-                    r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                    if ((r % 47) != 0 && (r % 53) != 0 && (r % 59) != 0 && (r % 61) != 0 && (r % 67) != 0)
-                    {
-                        m = 71 * 73 * 79 * 83;
-                        r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                        if ((r % 71) != 0 && (r % 73) != 0 && (r % 79) != 0 && (r % 83) != 0)
-                        {
-                            m = 89 * 97 * 101 * 103;
-                            r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                            if ((r % 89) != 0 && (r % 97) != 0 && (r % 101) != 0 && (r % 103) != 0)
-                            {
-                                m = 107 * 109 * 113 * 127;
-                                r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                                if ((r % 107) != 0 && (r % 109) != 0 && (r % 113) != 0 && (r % 127) != 0)
-                                {
-                                    return true;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            return false;
-        }
     }
 }
diff --git a/crypto/src/math/ec/custom/sec/SecT113Field.cs b/crypto/src/math/ec/custom/sec/SecT113Field.cs
index dbb645e6f..640c6e787 100644
--- a/crypto/src/math/ec/custom/sec/SecT113Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113Field.cs
@@ -37,6 +37,35 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat128.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat128.Create64();
+            ulong[] t1 = Nat128.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 3, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 7, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 14, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 28, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 56, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat128.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
index e3a923f62..f217e28cb 100644
--- a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT113FieldElement(
-                AbstractF2mCurve.Inverse(113, new int[]{ 9 }, ToBigInteger()));
+            ulong[] z = Nat128.Create64();
+            SecT113Field.Invert(x, z);
+            return new SecT113FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT131Field.cs b/crypto/src/math/ec/custom/sec/SecT131Field.cs
index 6a1d2a960..47f97078c 100644
--- a/crypto/src/math/ec/custom/sec/SecT131Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131Field.cs
@@ -40,6 +40,35 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat192.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat192.Create64();
+            ulong[] t1 = Nat192.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 2, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 4, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 8, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 16, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 32, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 65, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat192.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
index 65aaf01ba..0ea00ea07 100644
--- a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT131FieldElement(
-                AbstractF2mCurve.Inverse(131, new int[] { 2, 3, 8 }, ToBigInteger()));
+            ulong[] z = Nat192.Create64();
+            SecT131Field.Invert(x, z);
+            return new SecT131FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT163Field.cs b/crypto/src/math/ec/custom/sec/SecT163Field.cs
index 165d5b841..f921a5bc7 100644
--- a/crypto/src/math/ec/custom/sec/SecT163Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163Field.cs
@@ -41,6 +41,47 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat192.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion with bases { 2, 3 }
+
+            ulong[] t0 = Nat192.Create64();
+            ulong[] t1 = Nat192.Create64();
+
+            Square(x, t0);
+
+            // 3 | 162
+            SquareN(t0, 1, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 1, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 54
+            SquareN(t0, 3, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 3, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 18
+            SquareN(t0, 9, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 9, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 6
+            SquareN(t0, 27, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 27, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 2
+            SquareN(t0, 81, t1);
+            Multiply(t0, t1, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat192.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
index 3ab383a1d..c7a0b5639 100644
--- a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT163FieldElement(
-                AbstractF2mCurve.Inverse(163, new int[] { 3, 6, 7 }, ToBigInteger()));
+            ulong[] z = Nat192.Create64();
+            SecT163Field.Invert(x, z);
+            return new SecT163FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT193Field.cs b/crypto/src/math/ec/custom/sec/SecT193Field.cs
index 85db061c3..5154f1e0a 100644
--- a/crypto/src/math/ec/custom/sec/SecT193Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193Field.cs
@@ -44,6 +44,49 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat256.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion with bases { 2, 3 }
+
+            ulong[] t0 = Nat256.Create64();
+            ulong[] t1 = Nat256.Create64();
+
+            Square(x, t0);
+
+            // 3 | 192
+            SquareN(t0, 1, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 1, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 64
+            SquareN(t0, 3, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 32
+            SquareN(t0, 6, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 16
+            SquareN(t0, 12, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 8
+            SquareN(t0, 24, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 4
+            SquareN(t0, 48, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 2
+            SquareN(t0, 96, t1);
+            Multiply(t0, t1, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat256.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
index 995d2ebdd..eba4d10e6 100644
--- a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT193FieldElement(
-                AbstractF2mCurve.Inverse(193, new int[] { 15 }, ToBigInteger()));
+            ulong[] z = Nat256.Create64();
+            SecT193Field.Invert(x, z);
+            return new SecT193FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT233Field.cs b/crypto/src/math/ec/custom/sec/SecT233Field.cs
index b36ffba2e..a2f73fd5d 100644
--- a/crypto/src/math/ec/custom/sec/SecT233Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233Field.cs
@@ -45,6 +45,39 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat256.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat256.Create64();
+            ulong[] t1 = Nat256.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 3, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 7, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 14, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 29, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 58, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 116, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat256.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
index 60b204604..a9041efde 100644
--- a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT233FieldElement(
-                AbstractF2mCurve.Inverse(233, new int[] { 74 }, ToBigInteger()));
+            ulong[] z = Nat256.Create64();
+            SecT233Field.Invert(x, z);
+            return new SecT233FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT239Field.cs b/crypto/src/math/ec/custom/sec/SecT239Field.cs
index 6dab907dd..6b8ad696f 100644
--- a/crypto/src/math/ec/custom/sec/SecT239Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT239Field.cs
@@ -45,6 +45,43 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat256.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat256.Create64();
+            ulong[] t1 = Nat256.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 3, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 7, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 14, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 29, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 59, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 119, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat256.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
index e7bfffd1f..de074c55f 100644
--- a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT239FieldElement(
-                AbstractF2mCurve.Inverse(239, new int[] { 158 }, ToBigInteger()));
+            ulong[] z = Nat256.Create64();
+            SecT239Field.Invert(x, z);
+            return new SecT239FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT283Field.cs b/crypto/src/math/ec/custom/sec/SecT283Field.cs
index 435787467..903ea02ff 100644
--- a/crypto/src/math/ec/custom/sec/SecT283Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283Field.cs
@@ -48,6 +48,41 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat320.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat320.Create64();
+            ulong[] t1 = Nat320.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 2, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 4, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 8, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 17, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 35, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 70, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 141, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat320.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
index 9181b8685..e02108f73 100644
--- a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT283FieldElement(
-                AbstractF2mCurve.Inverse(283, new int[] { 5, 7, 12 }, ToBigInteger()));
+            ulong[] z = Nat320.Create64();
+            SecT283Field.Invert(x, z);
+            return new SecT283FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT409Field.cs b/crypto/src/math/ec/custom/sec/SecT409Field.cs
index ce6f43f2e..84eada96e 100644
--- a/crypto/src/math/ec/custom/sec/SecT409Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409Field.cs
@@ -47,6 +47,57 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat448.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion with bases { 2, 3 }
+
+            ulong[] t0 = Nat448.Create64();
+            ulong[] t1 = Nat448.Create64();
+            ulong[] t2 = Nat448.Create64();
+
+            Square(x, t0);
+
+            // 3 | 408
+            SquareN(t0, 1, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 1, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 136
+            SquareN(t0, 3, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 68
+            SquareN(t0, 6, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 34
+            SquareN(t0, 12, t1);
+            Multiply(t0, t1, t2);
+
+            // ! {2,3} | 17
+            SquareN(t2, 24, t0);
+            SquareN(t0, 24, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 8
+            SquareN(t0, 48, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 4
+            SquareN(t0, 96, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 2
+            SquareN(t0, 192, t1);
+            Multiply(t0, t1, t0);
+
+            Multiply(t0, t2, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat448.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
index b60ceafee..581ea73df 100644
--- a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT409FieldElement(
-                AbstractF2mCurve.Inverse(409, new int[] { 87 }, ToBigInteger()));
+            ulong[] z = Nat448.Create64();
+            SecT409Field.Invert(x, z);
+            return new SecT409FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT571Field.cs b/crypto/src/math/ec/custom/sec/SecT571Field.cs
index 921c841a9..fc84e336b 100644
--- a/crypto/src/math/ec/custom/sec/SecT571Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571Field.cs
@@ -59,6 +59,57 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat576.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion with bases { 2, 3, 5 }
+
+            ulong[] t0 = Nat576.Create64();
+            ulong[] t1 = Nat576.Create64();
+            ulong[] t2 = Nat576.Create64();
+
+            Square(x, t2);
+
+            // 5 | 570
+            Square(t2, t0);
+            Square(t0, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 2, t1);
+            Multiply(t0, t1, t0);
+            Multiply(t0, t2, t0);
+
+            // 3 | 114
+            SquareN(t0, 5, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 5, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 38
+            SquareN(t0, 15, t1);
+            Multiply(t0, t1, t2);
+
+            // ! {2,3,5} | 19
+            SquareN(t2, 30, t0);
+            SquareN(t0, 30, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 9
+            SquareN(t0, 60, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 60, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 3
+            SquareN(t0, 180, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 180, t1);
+            Multiply(t0, t1, t0);
+
+            Multiply(t0, t2, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat576.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
index a26e1e336..5d5458412 100644
--- a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT571FieldElement(
-                AbstractF2mCurve.Inverse(571, new int[] { 2, 5, 10 }, ToBigInteger()));
+            ulong[] z = Nat576.Create64();
+            SecT571Field.Invert(x, z);
+            return new SecT571FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/raw/Interleave.cs b/crypto/src/math/raw/Interleave.cs
index 9755c9d6f..a45ee1e08 100644
--- a/crypto/src/math/raw/Interleave.cs
+++ b/crypto/src/math/raw/Interleave.cs
@@ -4,67 +4,92 @@ namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Interleave
     {
+        private const ulong M32 = 0x55555555UL;
+        private const ulong M64 = 0x5555555555555555UL;
+
         /*
          * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
          * In a binary field, this operation is the same as squaring an 8 bit number.
          */
-        private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
-        {
-            0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
-            0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
-            0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
-            0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
-            0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
-            0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
-            0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
-            0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
-            0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
-            0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
-            0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
-            0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
-            0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
-            0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
-            0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
-            0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
-            0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
-            0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
-            0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
-            0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
-            0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
-            0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
-            0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
-            0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
-            0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
-            0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
-            0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
-            0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
-            0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
-            0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
-            0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
-            0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
-        };
+        //private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
+        //{
+        //    0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+        //    0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+        //    0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+        //    0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+        //    0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+        //    0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+        //    0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+        //    0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+        //    0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+        //    0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+        //    0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+        //    0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+        //    0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+        //    0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+        //    0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+        //    0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+        //    0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+        //    0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+        //    0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+        //    0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+        //    0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+        //    0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+        //    0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+        //    0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+        //    0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+        //    0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+        //    0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+        //    0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+        //    0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+        //    0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+        //    0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+        //    0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+        //};
 
         internal static uint Expand8to16(uint x)
         {
-            return INTERLEAVE2_TABLE[x & 0xFF];
+            x &= 0xFFU;
+            x = (x | (x << 4)) & 0x0F0FU;
+            x = (x | (x << 2)) & 0x3333U;
+            x = (x | (x << 1)) & 0x5555U;
+            return x;
         }
 
         internal static uint Expand16to32(uint x)
         {
-            return (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16);
+            x &= 0xFFFFU;
+            x = (x | (x << 8)) & 0x00FF00FFU;
+            x = (x | (x << 4)) & 0x0F0F0F0FU;
+            x = (x | (x << 2)) & 0x33333333U;
+            x = (x | (x << 1)) & 0x55555555U;
+            return x;
         }
 
         internal static ulong Expand32to64(uint x)
         {
-            uint r00 = (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16);
-            uint r32 = (uint)(INTERLEAVE2_TABLE[(x >> 16) & 0xFF] | INTERLEAVE2_TABLE[x >> 24] << 16);
-            return (ulong)r32 << 32 | (ulong)r00;
+            // "shuffle" low half to even bits and high half to odd bits
+            uint t;
+            t = (x ^ (x >>  8)) & 0x0000FF00U; x ^= (t ^ (t <<  8));
+            t = (x ^ (x >>  4)) & 0x00F000F0U; x ^= (t ^ (t <<  4));
+            t = (x ^ (x >>  2)) & 0x0C0C0C0CU; x ^= (t ^ (t <<  2));
+            t = (x ^ (x >>  1)) & 0x22222222U; x ^= (t ^ (t <<  1));
+
+            return ((x >> 1) & M32) << 32 | (x & M32);
         }
 
         internal static void Expand64To128(ulong x, ulong[] z, int zOff)
         {
-            z[zOff    ] = Expand32to64((uint)x);
-            z[zOff + 1] = Expand32to64((uint)(x >> 32));
+            // "shuffle" low half to even bits and high half to odd bits
+            ulong t;
+            t = (x ^ (x >> 16)) & 0x00000000FFFF0000UL; x ^= (t ^ (t << 16));
+            t = (x ^ (x >>  8)) & 0x0000FF000000FF00UL; x ^= (t ^ (t <<  8));
+            t = (x ^ (x >>  4)) & 0x00F000F000F000F0UL; x ^= (t ^ (t <<  4));
+            t = (x ^ (x >>  2)) & 0x0C0C0C0C0C0C0C0CUL; x ^= (t ^ (t <<  2));
+            t = (x ^ (x >>  1)) & 0x2222222222222222UL; x ^= (t ^ (t <<  1));
+
+            z[zOff    ] = (x     ) & M64;
+            z[zOff + 1] = (x >> 1) & M64;
         }
     }
 }
diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs
index ec3f63940..7ddf6c8e4 100644
--- a/crypto/src/security/DigestUtilities.cs
+++ b/crypto/src/security/DigestUtilities.cs
@@ -21,11 +21,13 @@ namespace Org.BouncyCastle.Security
     {
         private enum DigestAlgorithm {
             GOST3411,
+            KECCAK_224, KECCAK_256, KECCAK_288, KECCAK_384, KECCAK_512,
             MD2, MD4, MD5,
             RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320,
             SHA_1, SHA_224, SHA_256, SHA_384, SHA_512,
             SHA_512_224, SHA_512_256,
             SHA3_224, SHA3_256, SHA3_384, SHA3_512,
+            SHAKE128, SHAKE256,
             TIGER,
             WHIRLPOOL,
         };
@@ -72,7 +74,12 @@ namespace Org.BouncyCastle.Security
 
             algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411";
 
-
+            algorithms[NistObjectIdentifiers.IdSha3_224.Id] = "SHA3-224";
+            algorithms[NistObjectIdentifiers.IdSha3_256.Id] = "SHA3-256";
+            algorithms[NistObjectIdentifiers.IdSha3_384.Id] = "SHA3-384";
+            algorithms[NistObjectIdentifiers.IdSha3_512.Id] = "SHA3-512";
+            algorithms[NistObjectIdentifiers.IdShake128.Id] = "SHAKE128";
+            algorithms[NistObjectIdentifiers.IdShake256.Id] = "SHAKE256";
 
             oids["MD2"] = PkcsObjectIdentifiers.MD2;
             oids["MD4"] = PkcsObjectIdentifiers.MD4;
@@ -84,6 +91,12 @@ namespace Org.BouncyCastle.Security
             oids["SHA-512"] = NistObjectIdentifiers.IdSha512;
             oids["SHA-512/224"] = NistObjectIdentifiers.IdSha512_224;
             oids["SHA-512/256"] = NistObjectIdentifiers.IdSha512_256;
+            oids["SHA3-224"] = NistObjectIdentifiers.IdSha3_224;
+            oids["SHA3-256"] = NistObjectIdentifiers.IdSha3_256;
+            oids["SHA3-384"] = NistObjectIdentifiers.IdSha3_384;
+            oids["SHA3-512"] = NistObjectIdentifiers.IdSha3_512;
+            oids["SHAKE128"] = NistObjectIdentifiers.IdShake128;
+            oids["SHAKE256"] = NistObjectIdentifiers.IdShake256;
             oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
             oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
             oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
@@ -141,7 +154,12 @@ namespace Org.BouncyCastle.Security
                 switch (digestAlgorithm)
                 {
                     case DigestAlgorithm.GOST3411:      return new Gost3411Digest();
-                    case DigestAlgorithm.MD2:		    return new MD2Digest();
+                    case DigestAlgorithm.KECCAK_224:    return new KeccakDigest(224);
+                    case DigestAlgorithm.KECCAK_256:    return new KeccakDigest(256);
+                    case DigestAlgorithm.KECCAK_288:    return new KeccakDigest(288);
+                    case DigestAlgorithm.KECCAK_384:    return new KeccakDigest(384);
+                    case DigestAlgorithm.KECCAK_512:    return new KeccakDigest(512);
+                    case DigestAlgorithm.MD2:           return new MD2Digest();
                     case DigestAlgorithm.MD4:		    return new MD4Digest();
                     case DigestAlgorithm.MD5:		    return new MD5Digest();
                     case DigestAlgorithm.RIPEMD128:	    return new RipeMD128Digest();
@@ -159,6 +177,8 @@ namespace Org.BouncyCastle.Security
                     case DigestAlgorithm.SHA3_256:      return new Sha3Digest(256);
                     case DigestAlgorithm.SHA3_384:      return new Sha3Digest(384);
                     case DigestAlgorithm.SHA3_512:      return new Sha3Digest(512);
+                    case DigestAlgorithm.SHAKE128:      return new ShakeDigest(128);
+                    case DigestAlgorithm.SHAKE256:      return new ShakeDigest(256);
                     case DigestAlgorithm.TIGER:         return new TigerDigest();
                     case DigestAlgorithm.WHIRLPOOL:     return new WhirlpoolDigest();
                 }
diff --git a/crypto/test/data/crypto/SHA3TestVectors.txt b/crypto/test/data/crypto/SHA3TestVectors.txt
new file mode 100644
index 000000000..c6d0efafc
--- /dev/null
+++ b/crypto/test/data/crypto/SHA3TestVectors.txt
@@ -0,0 +1,837 @@
+# Test vectors for FIPS 202 - SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
+#
+# Downloaded 6th August, 2015 from http://csrc.nist.gov/groups/ST/toolkit/examples.html#aHashing
+#
+# NOTE: The 1605-bit test vectors were initially wrong. Corrections were published on 14th August, 2015
+#       (SHA3-512 corrected on 3rd September, 2015).
+
+SHA3-224 sample of 0-bit message
+
+Msg as bit string
+    #(empty message)
+
+Hash val is
+    6B 4E 03 42 36 67 DB B7 3B 6E 15 45 4F 0E B1 AB
+    D4 59 7F 9A 1B 07 8E 3F 5B 5A 6B C7
+
+SHA3-224 sample of 5-bit message
+
+Msg as bit string
+    1 1 0 0 1
+
+Hash val is
+    FF BA D5 DA 96 BA D7 17 89 33 02 06 DC 67 68 EC
+    AE B1 B3 2D CA 6B 33 01 48 96 74 AB
+
+SHA3-224 sample of 30-bit message
+
+Msg as bit string
+    1 1 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 0 1 1 0
+
+Hash val is
+    D6 66 A5 14 CC 9D BA 25 AC 1B A6 9E D3 93 04 60
+    DE AA C9 85 1B 5F 0B AA B0 07 DF 3B
+
+SHA3-224 sample of 1600-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+
+Hash val is
+    93 76 81 6A BA 50 3F 72 F9 6C E7 EB 65 AC 09 5D
+    EE E3 BE 4B F9 BB C2 A1 CB 7E 11 E0
+
+SHA3-224 sample of 1605-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0
+
+Hash val is
+    22 D2 F7 BB 0B 17 3F D8 C1 96 86 F9 17 31 66 E3
+    EE 62 73 80 47 D7 EA DD 69 EF B2 28
+
+SHA3-224 sample of 1630-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1
+
+Hash val is
+    4E 90 7B B1 05 78 61 F2 00 A5 99 E9 D4 F8 5B 02
+    D8 84 53 BF 5B 8A CE 9A C5 89 13 4C
+
+SHA3-256 sample of 0-bit message
+
+Msg as bit string
+    #(empty message)
+
+Hash val is
+    A7 FF C6 F8 BF 1E D7 66 51 C1 47 56 A0 61 D6 62
+    F5 80 FF 4D E4 3B 49 FA 82 D8 0A 4B 80 F8 43 4A
+
+SHA3-256 sample of 5-bit message
+
+Msg as bit string
+    1 1 0 0 1
+
+Hash val is
+    7B 00 47 CF 5A 45 68 82 36 3C BF 0F B0 53 22 CF
+    65 F4 B7 05 9A 46 36 5E 83 01 32 E3 B5 D9 57 AF
+
+SHA3-256 sample of 30-bit message
+
+Msg as bit string
+    1 1 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 0 1 1 0
+
+Hash val is
+    C8 24 2F EF 40 9E 5A E9 D1 F1 C8 57 AE 4D C6 24
+    B9 2B 19 80 9F 62 AA 8C 07 41 1C 54 A0 78 B1 D0
+
+SHA3-256 sample of 1600-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+
+Hash val is
+    79 F3 8A DE C5 C2 03 07 A9 8E F7 6E 83 24 AF BF
+    D4 6C FD 81 B2 2E 39 73 C6 5F A1 BD 9D E3 17 87
+
+SHA3-256 sample of 1605-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0
+
+Hash val is
+    81 EE 76 9B ED 09 50 86 2B 1D DD ED 2E 84 AA A6
+    AB 7B FD D3 CE AA 47 1B E3 11 63 D4 03 36 36 3C
+
+SHA3-256 sample of 1630-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1
+
+Hash val is
+    52 86 0A A3 01 21 4C 61 0D 92 2A 6B 6C AB 98 1C
+    CD 06 01 2E 54 EF 68 9D 74 40 21 E7 38 B9 ED 20
+
+SHA3-384 sample of 0-bit message
+
+Msg as bit string
+    #(empty message)
+
+Hash val is
+    0C 63 A7 5B 84 5E 4F 7D 01 10 7D 85 2E 4C 24 85
+    C5 1A 50 AA AA 94 FC 61 99 5E 71 BB EE 98 3A 2A
+    C3 71 38 31 26 4A DB 47 FB 6B D1 E0 58 D5 F0 04
+
+SHA3-384 sample of 5-bit message
+
+Msg as bit string
+    1 1 0 0 1
+
+Hash val is
+    73 7C 9B 49 18 85 E9 BF 74 28 E7 92 74 1A 7B F8
+    DC A9 65 34 71 C3 E1 48 47 3F 2C 23 6B 6A 0A 64
+    55 EB 1D CE 9F 77 9B 4B 6B 23 7F EF 17 1B 1C 64
+
+SHA3-384 sample of 30-bit message
+
+Msg as bit string
+    1 1 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 0 1 1 0
+
+Hash val is
+    95 5B 4D D1 BE 03 26 1B D7 6F 80 7A 7E FD 43 24
+    35 C4 17 36 28 11 B8 A5 0C 56 4E 7E E9 58 5E 1A
+    C7 62 6D DE 2F DC 03 0F 87 61 96 EA 26 7F 08 C3
+
+SHA3-384 sample of 1600-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+
+Hash val is
+    18 81 DE 2C A7 E4 1E F9 5D C4 73 2B 8F 5F 00 2B
+    18 9C C1 E4 2B 74 16 8E D1 73 26 49 CE 1D BC DD
+    76 19 7A 31 FD 55 EE 98 9F 2D 70 50 DD 47 3E 8F
+
+SHA3-384 sample of 1605-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0
+
+Hash val is
+    A3 1F DB D8 D5 76 55 1C 21 FB 11 91 B5 4B DA 65
+    B6 C5 FE 97 F0 F4 A6 91 03 42 4B 43 F7 FD B8 35
+    97 9F DB EA E8 B3 FE 16 CB 82 E5 87 38 1E B6 24
+
+SHA3-384 sample of 1630-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1
+
+Hash val is
+    34 85 D3 B2 80 BD 38 4C F4 A7 77 84 4E 94 67 81
+    73 05 5D 1C BC 40 C7 C2 C3 83 3D 9E F1 23 45 17
+    2D 6F CD 31 92 3B B8 79 5A C8 18 47 D3 D8 85 5C
+
+SHA3-512 sample of 0-bit message
+
+Msg as bit string
+    #(empty message)
+
+Hash val is
+    A6 9F 73 CC A2 3A 9A C5 C8 B5 67 DC 18 5A 75 6E
+    97 C9 82 16 4F E2 58 59 E0 D1 DC C1 47 5C 80 A6
+    15 B2 12 3A F1 F5 F9 4C 11 E3 E9 40 2C 3A C5 58
+    F5 00 19 9D 95 B6 D3 E3 01 75 85 86 28 1D CD 26
+
+SHA3-512 sample of 5-bit message
+
+Msg as bit string
+    1 1 0 0 1
+
+Hash val is
+    A1 3E 01 49 41 14 C0 98 00 62 2A 70 28 8C 43 21
+    21 CE 70 03 9D 75 3C AD D2 E0 06 E4 D9 61 CB 27
+    54 4C 14 81 E5 81 4B DC EB 53 BE 67 33 D5 E0 99
+    79 5E 5E 81 91 8A DD B0 58 E2 2A 9F 24 88 3F 37
+
+SHA3-512 sample of 30-bit message
+
+Msg as bit string
+    1 1 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 0 1 1 0
+
+Hash val is
+    98 34 C0 5A 11 E1 C5 D3 DA 9C 74 0E 1C 10 6D 9E
+    59 0A 0E 53 0B 6F 6A AA 78 30 52 5D 07 5C A5 DB
+    1B D8 A6 AA 98 1A 28 61 3A C3 34 93 4A 01 82 3C
+    D4 5F 45 E4 9B 6D 7E 69 17 F2 F1 67 78 06 7B AB
+
+SHA3-512 sample of 1600-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+
+Hash val is
+    E7 6D FA D2 20 84 A8 B1 46 7F CF 2F FA 58 36 1B
+    EC 76 28 ED F5 F3 FD C0 E4 80 5D C4 8C AE EC A8
+    1B 7C 13 C3 0A DF 52 A3 65 95 84 73 9A 2D F4 6B
+    E5 89 C5 1C A1 A4 A8 41 6D F6 54 5A 1C E8 BA 00
+
+SHA3-512 sample of 1605-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0
+
+Hash val is
+    FC 4A 16 7C CB 31 A9 37 D6 98 FD E8 2B 04 34 8C
+    95 39 B2 8F 0C 9D 3B 45 05 70 9C 03 81 23 50 E4
+    99 0E 96 22 97 4F 6E 57 5C 47 86 1C 0D 2E 63 8C
+    CF C2 02 3C 36 5B B6 0A 93 F5 28 55 06 98 78 6B
+
+SHA3-512 sample of 1630-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1
+
+Hash val is
+    CF 9A 30 AC 1F 1F 6A C0 91 6F 9F EF 19 19 C5 95
+    DE BE 2E E8 0C 85 42 12 10 FD F0 5F 1C 6A F7 3A
+    A9 CA C8 81 D0 F9 1D B6 D0 34 A2 BB AD C1 CF 7F
+    BC B2 EC FA 9D 19 1D 3A 50 16 FB 3F AD 87 09 C9
+
diff --git a/crypto/test/data/crypto/SHAKETestVectors.txt b/crypto/test/data/crypto/SHAKETestVectors.txt
new file mode 100644
index 000000000..b5c9be3cd
--- /dev/null
+++ b/crypto/test/data/crypto/SHAKETestVectors.txt
@@ -0,0 +1,770 @@
+# Test vectors for FIPS 202 - SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
+#
+# Downloaded 6th August, 2015 from http://csrc.nist.gov/groups/ST/toolkit/examples.html#aHashing
+
+SHAKE-128 sample of 0-bit message
+
+Msg as bit string
+    #(empty message)
+
+Output val is
+    7F 9C 2B A4 E8 8F 82 7D 61 60 45 50 76 05 85 3E
+    D7 3B 80 93 F6 EF BC 88 EB 1A 6E AC FA 66 EF 26
+    3C B1 EE A9 88 00 4B 93 10 3C FB 0A EE FD 2A 68
+    6E 01 FA 4A 58 E8 A3 63 9C A8 A1 E3 F9 AE 57 E2
+    35 B8 CC 87 3C 23 DC 62 B8 D2 60 16 9A FA 2F 75
+    AB 91 6A 58 D9 74 91 88 35 D2 5E 6A 43 50 85 B2
+    BA DF D6 DF AA C3 59 A5 EF BB 7B CC 4B 59 D5 38
+    DF 9A 04 30 2E 10 C8 BC 1C BF 1A 0B 3A 51 20 EA
+    17 CD A7 CF AD 76 5F 56 23 47 4D 36 8C CC A8 AF
+    00 07 CD 9F 5E 4C 84 9F 16 7A 58 0B 14 AA BD EF
+    AE E7 EE F4 7C B0 FC A9 76 7B E1 FD A6 94 19 DF
+    B9 27 E9 DF 07 34 8B 19 66 91 AB AE B5 80 B3 2D
+    EF 58 53 8B 8D 23 F8 77 32 EA 63 B0 2B 4F A0 F4
+    87 33 60 E2 84 19 28 CD 60 DD 4C EE 8C C0 D4 C9
+    22 A9 61 88 D0 32 67 5C 8A C8 50 93 3C 7A FF 15
+    33 B9 4C 83 4A DB B6 9C 61 15 BA D4 69 2D 86 19
+    F9 0B 0C DF 8A 7B 9C 26 40 29 AC 18 5B 70 B8 3F
+    28 01 F2 F4 B3 F7 0C 59 3E A3 AE EB 61 3A 7F 1B
+    1D E3 3F D7 50 81 F5 92 30 5F 2E 45 26 ED C0 96
+    31 B1 09 58 F4 64 D8 89 F3 1B A0 10 25 0F DA 7F
+    13 68 EC 29 67 FC 84 EF 2A E9 AF F2 68 E0 B1 70
+    0A FF C6 82 0B 52 3A 3D 91 71 35 F2 DF F2 EE 06
+    BF E7 2B 31 24 72 1D 4A 26 C0 4E 53 A7 5E 30 E7
+    3A 7A 9C 4A 95 D9 1C 55 D4 95 E9 F5 1D D0 B5 E9
+    D8 3C 6D 5E 8C E8 03 AA 62 B8 D6 54 DB 53 D0 9B
+    8D CF F2 73 CD FE B5 73 FA D8 BC D4 55 78 BE C2
+    E7 70 D0 1E FD E8 6E 72 1A 3F 7C 6C CE 27 5D AB
+    E6 E2 14 3F 1A F1 8D A7 EF DD C4 C7 B7 0B 5E 34
+    5D B9 3C C9 36 BE A3 23 49 1C CB 38 A3 88 F5 46
+    A9 FF 00 DD 4E 13 00 B9 B2 15 3D 20 41 D2 05 B4
+    43 E4 1B 45 A6 53 F2 A5 C4 49 2C 1A DD 54 45 12
+    DD A2 52 98 33 46 2B 71 A4 1A 45 BE 97 29 0B 6F
+
+SHAKE-128 sample of 5-bit message
+
+Msg as bit string
+    1 1 0 0 1
+
+Output val is
+    2E 0A BF BA 83 E6 72 0B FB C2 25 FF 6B 7A B9 FF
+    CE 58 BA 02 7E E3 D8 98 76 4F EF 28 7D DE CC CA
+    3E 6E 59 98 41 1E 7D DB 32 F6 75 38 F5 00 B1 8C
+    8C 97 C4 52 C3 70 EA 2C F0 AF CA 3E 05 DE 7E 4D
+    E2 7F A4 41 A9 CB 34 FD 17 C9 78 B4 2D 5B 7E 7F
+    9A B1 8F FE FF C3 C5 AC 2F 3A 45 5E EB FD C7 6C
+    EA EB 0A 2C CA 22 EE F6 E6 37 F4 CA BE 5C 51 DE
+    D2 E3 FA D8 B9 52 70 A3 21 84 56 64 F1 07 D1 64
+    96 BB 7A BF BE 75 04 B6 ED E2 E8 9E 4B 99 6F B5
+    8E FD C4 18 1F 91 63 38 1C BE 7B C0 06 A7 A2 05
+    98 9C 52 6C D1 BD 68 98 36 93 B4 BD C5 37 28 B2
+    41 C1 CF F4 2B B6 11 50 2C 35 20 5C AB B2 88 75
+    56 55 D6 20 C6 79 94 F0 64 51 18 7F 6F D1 7E 04
+    66 82 BA 12 86 06 3F F8 8F E2 50 8D 1F CA F9 03
+    5A 12 31 AD 41 50 A9 C9 B2 4C 9B 2D 66 B2 AD 1B
+    DE 0B D0 BB CB 8B E0 5B 83 52 29 EF 79 19 73 73
+    23 42 44 01 E1 D8 37 B6 6E B4 E6 30 FF 1D E7 0C
+    B3 17 C2 BA CB 08 00 1D 34 77 B7 A7 0A 57 6D 20
+    86 90 33 58 9D 85 A0 1D DB 2B 66 46 C0 43 B5 9F
+    C0 11 31 1D A6 66 FA 5A D1 D6 38 7F A9 BC 40 15
+    A3 8A 51 D1 DA 1E A6 1D 64 8D C8 E3 9A 88 B9 D6
+    22 BD E2 07 FD AB C6 F2 82 7A 88 0C 33 0B BF 6D
+    F7 33 77 4B 65 3E 57 30 5D 78 DC E1 12 F1 0A 2C
+    71 F4 CD AD 92 ED 11 3E 1C EA 63 B9 19 25 ED 28
+    19 1E 6D BB B5 AA 5A 2A FD A5 1F C0 5A 3A F5 25
+    8B 87 66 52 43 55 0F 28 94 8A E2 B8 BE B6 BC 9C
+    77 0B 35 F0 67 EA A6 41 EF E6 5B 1A 44 90 9D 1B
+    14 9F 97 EE A6 01 39 1C 60 9E C8 1D 19 30 F5 7C
+    18 A4 E0 FA B4 91 D1 CA DF D5 04 83 44 9E DC 0F
+    07 FF B2 4D 2C 6F 9A 9A 3B FF 39 AE 3D 57 F5 60
+    65 4D 7D 75 C9 08 AB E6 25 64 75 3E AC 39 D7 50
+    3D A6 D3 7C 2E 32 E1 AF 3B 8A EC 8A E3 06 9C D9
+
+SHAKE-128 sample of 30-bit message
+
+Msg as bit string
+    1 1 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 0 1 1 0
+
+Output val is
+    6D 5D 39 C5 5F 3C CA 56 7F EA F4 22 DC 64 BA 17
+    40 1D 07 75 6D 78 B0 FA 3D 54 6D 66 AF C2 76 71
+    E0 01 06 85 FC 69 A7 EC 3C 53 67 B8 FA 5F DA 39
+    D5 7C E5 3F 15 3F A4 03 1D 27 72 06 77 0A EC 6B
+    2D DF 16 AE FA B6 69 11 0D 6E 4A 29 6A 14 FB 14
+    86 B0 84 6B 69 05 43 E4 05 7F 7F 42 AA 8C 0E 6A
+    5A 56 B6 0B 68 8D 55 A1 96 DF 6F 39 76 E3 06 88
+    CB B6 AF D4 85 25 D7 64 90 35 7F 3F D8 97 BA FC
+    87 36 D9 07 B9 BA C8 16 59 1F C2 4E 79 36 0B E3
+    A7 FF A6 29 82 C4 5A BB 0E 58 4C 07 EC 93 A1 95
+    30 50 9D 9F 81 62 15 D7 27 7B B9 99 43 7C 82 14
+    50 F0 75 92 81 CD 8E 16 A3 48 3E 3C C7 52 09 1B
+    7A AE 92 90 9D 2F 50 1E F7 DC E9 89 75 98 91 B3
+    37 7C EA B4 93 FF E4 96 01 0A 0C 7E 51 95 99 94
+    F5 6F 56 5E 63 3A F6 09 3A C6 E1 E0 F0 04 88 71
+    EC 47 78 F4 8E F8 BD 5B CB 80 EA 7D F9 FF 47 11
+    C8 1E 24 C0 22 1C 2A D9 74 4F BA 79 35 EA EC A1
+    14 22 4F D1 08 EF C5 AC 74 C6 62 52 08 92 75 B4
+    27 76 73 70 8C 4A F9 2F 88 13 B1 93 59 9F D6 4B
+    D7 48 4F 2E 5E C3 69 E3 64 64 99 76 8E 58 1D D0
+    53 AA 48 14 D8 BF 1A CF F5 FD 77 45 19 A7 49 BE
+    66 75 47 41 EB C5 36 22 12 A9 FE A8 A8 14 E9 E0
+    10 BC 27 20 B3 B7 D9 4F AB 74 BC 7F 92 3E 10 72
+    B8 A5 DD DD A8 3B A0 15 7D 8C BA 55 C1 92 DF 69
+    65 CB 7D BA 46 A3 34 0D F8 C3 FA 89 C7 C4 DB 53
+    9D 38 DC 40 6F 1D 2C F5 4E 59 05 58 0B 44 04 BF
+    D7 B3 71 95 61 C5 A5 9D 5D FD B1 BF 93 DF 13 82
+    52 25 ED CC E0 FA 7D 87 EF CD 23 9F EB 49 FC 9E
+    2D E9 D8 28 FE EB 1F 2C F5 79 B9 5D D0 50 AB 2C
+    A4 71 05 A8 D3 0F 3F D2 A1 15 4C 15 F8 7F B3 7B
+    2C 71 56 BD 7F 3C F2 B7 45 C9 12 A4 0B C1 B5 59
+    B6 56 E3 E9 03 CC 57 33 E8 6B A1 5D FE F7 06 78
+
+SHAKE-128 sample of 1600-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+
+Output val is
+    13 1A B8 D2 B5 94 94 6B 9C 81 33 3F 9B B6 E0 CE
+    75 C3 B9 31 04 FA 34 69 D3 91 74 57 38 5D A0 37
+    CF 23 2E F7 16 4A 6D 1E B4 48 C8 90 81 86 AD 85
+    2D 3F 85 A5 CF 28 DA 1A B6 FE 34 38 17 19 78 46
+    7F 1C 05 D5 8C 7E F3 8C 28 4C 41 F6 C2 22 1A 76
+    F1 2A B1 C0 40 82 66 02 50 80 22 94 FB 87 18 02
+    13 FD EF 5B 0E CB 7D F5 0C A1 F8 55 5B E1 4D 32
+    E1 0F 6E DC DE 89 2C 09 42 4B 29 F5 97 AF C2 70
+    C9 04 55 6B FC B4 7A 7D 40 77 8D 39 09 23 64 2B
+    3C BD 05 79 E6 09 08 D5 A0 00 C1 D0 8B 98 EF 93
+    3F 80 64 45 BF 87 F8 B0 09 BA 9E 94 F7 26 61 22
+    ED 7A C2 4E 5E 26 6C 42 A8 2F A1 BB EF B7 B8 DB
+    00 66 E1 6A 85 E0 49 3F 07 DF 48 09 AE C0 84 A5
+    93 74 8A C3 DD E5 A6 D7 AA E1 E8 B6 E5 35 2B 2D
+    71 EF BB 47 D4 CA EE D5 E6 D6 33 80 5D 2D 32 3E
+    6F D8 1B 46 84 B9 3A 26 77 D4 5E 74 21 C2 C6 AE
+    A2 59 B8 55 A6 98 FD 7D 13 47 7A 1F E5 3E 5A 4A
+    61 97 DB EC 5C E9 5F 50 5B 52 0B CD 95 70 C4 A8
+    26 5A 7E 01 F8 9C 0C 00 2C 59 BF EC 6C D4 A5 C1
+    09 25 89 53 EE 5E E7 0C D5 77 EE 21 7A F2 1F A7
+    01 78 F0 94 6C 9B F6 CA 87 51 79 34 79 F6 B5 37
+    73 7E 40 B6 ED 28 51 1D 8A 2D 7E 73 EB 75 F8 DA
+    AC 91 2F F9 06 E0 AB 95 5B 08 3B AC 45 A8 E5 E9
+    B7 44 C8 50 6F 37 E9 B4 E7 49 A1 84 B3 0F 43 EB
+    18 8D 85 5F 1B 70 D7 1F F3 E5 0C 53 7A C1 B0 F8
+    97 4F 0F E1 A6 AD 29 5B A4 2F 6A EC 74 D1 23 A7
+    AB ED DE 6E 2C 07 11 CA B3 6B E5 AC B1 A5 A1 1A
+    4B 1D B0 8B A6 98 2E FC CD 71 69 29 A7 74 1C FC
+    63 AA 44 35 E0 B6 9A 90 63 E8 80 79 5C 3D C5 EF
+    32 72 E1 1C 49 7A 91 AC F6 99 FE FE E2 06 22 7A
+    44 C9 FB 35 9F D5 6A C0 A9 A7 5A 74 3C FF 68 62
+    F1 7D 72 59 AB 07 52 16 C0 69 95 11 64 3B 64 39
+
+SHAKE-128 sample of 1605-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0
+
+Output val is
+    4A C3 8E BD 16 78 B4 A4 52 79 2C 56 73 F9 77 7D
+    36 B5 54 51 AA AE 24 24 92 49 42 D3 18 A2 F6 F5
+    1B BC 83 7D CC 70 22 C5 40 3B 69 D2 9A C9 9A 74
+    5F 06 D0 6F 2A 41 B0 CC 24 3C D2 70 FA 44 D4 30
+    65 AF 00 D2 AD 35 8B D5 A5 D0 6D 33 1B C2 30 CD
+    8D DA 46 55 62 8F 91 02 71 1A DA FB 76 36 C1 60
+    B2 D2 5E C6 23 5A 2F E0 F3 73 94 D8 7F C5 FF D7
+    DB F1 99 3E 55 8A EB EA 6C 61 E9 07 18 8C 61 F5
+    FC DE 27 8E 26 4F 95 8F FD 7B 33 82 DC 10 13 9B
+    62 5E 12 41 AB 5B BC 2A 1F BC AC 31 A3 35 CF C7
+    B2 0E 42 77 12 24 6C BB 55 23 22 59 A7 EF 16 02
+    BD 56 F6 56 7D 66 94 2D 4A 71 49 F4 22 22 10 B0
+    74 EA 54 15 4B 38 E8 FD FA 0D CF 4F A3 EC D2 15
+    4E 83 18 A6 57 8B 53 5D BC FC 21 7A 3C AB 52 53
+    29 65 84 6F 89 78 14 57 02 55 63 E2 DC 15 CC 3A
+    F9 02 BA 2A D2 80 FF BB BF A4 C5 2B 60 FA 41 BA
+    C2 1F 4A B2 35 36 26 81 19 FC 98 CD 98 2D A5 CD
+    5D A2 1E 1B 56 92 D4 71 05 DE 9F 1E 01 32 C6 FE
+    31 5D 67 FA 46 49 97 C2 AB 55 33 C7 9F 98 E6 E6
+    4F F8 08 02 A7 FE 96 CA 04 A8 1F 88 55 27 37 0A
+    22 06 B1 0B 39 36 DD 81 B8 24 63 53 F4 CD 90 51
+    10 89 26 8D 74 4F 21 0A C6 89 D4 9D 28 75 05 4A
+    72 7B 60 4D 13 D2 69 B3 71 90 D4 27 C7 D1 5C CC
+    DC D7 87 0E 0B 8A DB EB 97 71 11 A9 BC F7 78 1A
+    16 13 56 A5 94 1C 79 99 07 EF 9D 3B 1A 44 1F 09
+    51 5F 28 31 C4 FA FD E3 DC 7C 1E 9B 5A A5 7D 3E
+    83 CD 67 34 DA 3D 8B 9E F3 FC 44 88 05 EA 29 C9
+    9C BA 6B 35 2B CA BE 2F D9 70 AE 95 80 D2 BF 25
+    15 2B 96 0E 6B 80 6D 87 D7 D0 60 8B 24 7F 61 08
+    9E 29 86 92 C2 7F 19 C5 2D 03 EB E3 95 A3 68 06
+    AD 54 0B EC 2D 04 6C 18 E3 55 FA F8 31 3D 2E F8
+    99 5E E6 AA E4 25 68 F3 14 93 3E 3A 21 E5 BE 40
+
+SHAKE-128 sample of 1630-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1
+
+Output val is
+    89 84 6D C7 76 AC 0F 01 45 72 EA 79 F5 60 77 34
+    51 00 29 38 24 8E 68 82 56 9A C3 2A EA B1 91 FC
+    AC DE 68 EB 07 55 75 39 C4 84 5F B4 44 10 8E 6E
+    05 45 E7 31 FC CA 2D 4F 67 A3 BF D4 1C FF 3E AF
+    35 EE FB 53 44 11 77 96 5B B5 16 95 0C F5 DC B2
+    AA FC BB C6 30 0E 8E EF D9 BC D0 E5 F3 2D 1A 4E
+    87 2E 0F 1D BD 8F 8E 00 CB B8 78 69 8C 58 83 E3
+    CA 18 4B 94 90 38 9E 46 00 2C 08 A0 B1 6B 05 A3
+    6B 2C B5 A1 CA E0 8E 11 AD 97 2F D2 4A F7 01 01
+    CE 47 46 C8 4F 16 71 87 7F 0D F6 C4 15 D1 67 0F
+    F4 0B 8D DE DD 89 CC 3E 65 6D B9 05 80 49 D6 09
+    B6 78 4C C9 D0 5E 60 CC 6A C9 C8 19 49 93 BA 29
+    15 8F D4 DB 8C F2 25 E9 57 4F 18 A7 7F 66 EC 10
+    52 BF 17 99 3B DA 20 6A 17 73 7D 78 5B D4 C1 8C
+    EE 4C 76 AA 57 35 A5 22 3F 3C 55 E7 9D AE C1 3D
+    4B F6 0F 15 62 E0 AD 0F A3 B5 58 EC CF A8 AB 3E
+    EF 61 47 4D 57 6E 8C AF 4C 11 E4 DE 5C CB 36 D7
+    DF 7D 89 2C 1F CA 20 17 BE 8B BD A5 A4 71 95 44
+    8C C6 7A 07 8E 62 8A 2E F7 63 FF E1 DC 9D 9D 6F
+    F7 8E 68 96 1C 33 FF D9 00 0C 11 DE E7 F7 40 8D
+    8D A5 C6 05 B0 B4 D5 6B B5 5E 93 64 C7 7B FA D9
+    C8 19 1E D6 E1 FE 7B 7A 93 7C 6D 07 09 5F E5 EA
+    91 A7 00 B4 BD FC 17 B4 28 D0 36 92 2A A8 AB 5E
+    2C D5 85 84 6F B8 1F C6 93 B8 D5 9B F8 5C 74 BC
+    70 0C D2 BC 3E 6A AB 43 7D 93 D8 A3 0F 1C F6 92
+    EF EF 43 60 20 28 E0 CE 57 42 EB 3F 4F 4D 5B 02
+    91 58 DD 68 96 AC B5 E3 A7 F6 84 D9 AA 89 14 E7
+    09 74 B2 23 A6 FE C3 8D 76 C7 47 3E 86 E4 B9 B3
+    2C 62 1E 20 15 C5 5E 94 7D D0 16 C6 75 C8 23 68
+    CE 26 FB 45 6A 5B 65 88 1A F5 13 BF DC 88 68 7C
+    63 81 67 6A BB D2 D9 10 4E D2 3A 9E 89 31 02 46
+    B0 26 CE DD 57 59 5B 1A B6 FE 88 A7 84 BE 0C 06
+
+SHAKE-256 sample of 0-bit message
+
+Msg as bit string
+    #(empty message)
+
+Output val is
+    46 B9 DD 2B 0B A8 8D 13 23 3B 3F EB 74 3E EB 24
+    3F CD 52 EA 62 B8 1B 82 B5 0C 27 64 6E D5 76 2F
+    D7 5D C4 DD D8 C0 F2 00 CB 05 01 9D 67 B5 92 F6
+    FC 82 1C 49 47 9A B4 86 40 29 2E AC B3 B7 C4 BE
+    14 1E 96 61 6F B1 39 57 69 2C C7 ED D0 B4 5A E3
+    DC 07 22 3C 8E 92 93 7B EF 84 BC 0E AB 86 28 53
+    34 9E C7 55 46 F5 8F B7 C2 77 5C 38 46 2C 50 10
+    D8 46 C1 85 C1 51 11 E5 95 52 2A 6B CD 16 CF 86
+    F3 D1 22 10 9E 3B 1F DD 94 3B 6A EC 46 8A 2D 62
+    1A 7C 06 C6 A9 57 C6 2B 54 DA FC 3B E8 75 67 D6
+    77 23 13 95 F6 14 72 93 B6 8C EA B7 A9 E0 C5 8D
+    86 4E 8E FD E4 E1 B9 A4 6C BE 85 47 13 67 2F 5C
+    AA AE 31 4E D9 08 3D AB 4B 09 9F 8E 30 0F 01 B8
+    65 0F 1F 4B 1D 8F CF 3F 3C B5 3F B8 E9 EB 2E A2
+    03 BD C9 70 F5 0A E5 54 28 A9 1F 7F 53 AC 26 6B
+    28 41 9C 37 78 A1 5F D2 48 D3 39 ED E7 85 FB 7F
+    5A 1A AA 96 D3 13 EA CC 89 09 36 C1 73 CD CD 0F
+    AB 88 2C 45 75 5F EB 3A ED 96 D4 77 FF 96 39 0B
+    F9 A6 6D 13 68 B2 08 E2 1F 7C 10 D0 4A 3D BD 4E
+    36 06 33 E5 DB 4B 60 26 01 C1 4C EA 73 7D B3 DC
+    F7 22 63 2C C7 78 51 CB DD E2 AA F0 A3 3A 07 B3
+    73 44 5D F4 90 CC 8F C1 E4 16 0F F1 18 37 8F 11
+    F0 47 7D E0 55 A8 1A 9E DA 57 A4 A2 CF B0 C8 39
+    29 D3 10 91 2F 72 9E C6 CF A3 6C 6A C6 A7 58 37
+    14 30 45 D7 91 CC 85 EF F5 B2 19 32 F2 38 61 BC
+    F2 3A 52 B5 DA 67 EA F7 BA AE 0F 5F B1 36 9D B7
+    8F 3A C4 5F 8C 4A C5 67 1D 85 73 5C DD DB 09 D2
+    B1 E3 4A 1F C0 66 FF 4A 16 2C B2 63 D6 54 12 74
+    AE 2F CC 86 5F 61 8A BE 27 C1 24 CD 8B 07 4C CD
+    51 63 01 B9 18 75 82 4D 09 95 8F 34 1E F2 74 BD
+    AB 0B AE 31 63 39 89 43 04 E3 58 77 B0 C2 8A 9B
+    1F D1 66 C7 96 B9 CC 25 8A 06 4A 8F 57 E2 7F 2A
+
+SHAKE-256 sample of 5-bit message
+
+Msg as bit string
+    1 1 0 0 1
+
+Output val is
+    48 A5 C1 1A BA EE FF 09 2F 36 46 EF 0D 6B 3D 3F
+    F7 6C 2F 55 F9 C7 32 AC 64 70 C0 37 64 00 82 12
+    E2 1B 14 67 77 8B 18 19 89 F8 88 58 21 1B 45 DF
+    87 99 CF 96 1F 80 0D FA C9 9E 64 40 39 E2 97 9A
+    40 16 F5 45 6F F4 21 C5 B3 85 DA 2B 85 5D A7 E3
+    1C 8C 2E 8E 4B A4 1E B4 09 5C B9 99 D9 75 9C B4
+    03 58 DA 85 62 A2 E6 13 49 E0 5A 2E 13 F1 B7 4E
+    C9 E6 9F 5B 42 6D C7 41 38 FF CD C5 71 C3 2B 39
+    B9 F5 55 63 E1 A9 9D C4 22 C3 06 02 6D 6A 0F 9D
+    E8 51 62 B3 86 79 4C A0 68 8B 76 4B 3D 32 20 0C
+    C4 59 74 97 32 A0 F3 A3 41 C0 EF C9 6A 22 C6 3B
+    AD 7D 96 CC 9B A4 76 8C 6F CF A1 F2 00 10 7C F9
+    FA E5 C0 D7 54 95 8C 5A 75 6B 37 6A 3B E6 9F 88
+    07 4F 20 0E 9E 95 A8 CA 5B CF 96 99 98 DB 1D C3
+    7D 0D 3D 91 6F 6C AA B3 F0 37 82 C9 C4 4A 2E 14
+    E8 07 86 BE CE 45 87 B9 EF 82 CB F4 54 E0 E3 4B
+    D1 75 AE 57 D3 6A F4 E7 26 B2 21 33 2C ED 36 C8
+    CE 2E 06 20 3C 65 6A E8 DA 03 7D 08 E7 16 0B 48
+    0C 1A 85 16 BF 06 DD 97 BF 4A A4 C0 24 93 10 DC
+    0B 06 5D C6 39 57 63 55 38 4D 16 5C 6A 50 9B 12
+    F7 BB D1 E1 5B 22 BC E0 2F A0 48 DD FA AC F7 41
+    5F 49 B6 32 4C 1D 06 7B 52 64 E1 12 5F 7F 75 42
+    7F 31 2B D9 34 6E B4 E4 00 B1 F7 CB 31 28 8C 9E
+    3F 73 5E CA 9C ED 0D B8 88 E2 E2 F4 02 24 3B D6
+    46 18 A2 3E 10 F9 C2 29 39 74 40 54 2D 0A B1 B2
+    E1 0D AC C5 C9 5E 59 7F 2C 7E A3 84 38 10 5F 97
+    80 3D BB 03 FC C0 FD 41 6B 09 05 A4 1D 18 4D EB
+    23 89 05 77 58 91 F9 35 01 FB 41 76 A3 BD 6C 46
+    44 61 D3 6E E8 B0 08 AA BD 9E 26 A3 40 55 E8 0C
+    8C 81 3E EB A0 7F 72 8A B3 2B 15 60 5A D1 61 A0
+    66 9F 6F CE 5C 55 09 FB B6 AF D2 4A EA CC 5F A4
+    A5 15 23 E6 B1 73 24 6E D4 BF A5 21 D7 4F C6 BB
+
+SHAKE-256 sample of 30-bit message
+
+Msg as bit string
+    1 1 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 0 1 1 0
+
+Output val is
+    46 5D 08 1D FF 87 5E 39 62 00 E4 48 1A 3E 9D CD
+    88 D0 79 AA 6D 66 22 6C B6 BA 45 41 07 CB 81 A7
+    84 1A B0 29 60 DE 27 9C CB E3 4B 42 C3 65 85 AD
+    86 96 4D B0 DB 52 B6 E7 B4 36 9E CE 8F 72 48 58
+    9B A7 8A B1 82 8F FC 33 5C B1 23 97 11 9B FD 2B
+    87 EB 78 98 AE B9 56 B6 F2 3D DF 0B D4 00 43 86
+    A8 E5 26 55 4E F4 E4 83 FA CE E3 0D D3 2E 20 4F
+    FF 8C 36 BB D6 02 A5 76 D1 39 08 9C 75 A8 05 02
+    66 FC BF 72 1E 44 43 DE 46 45 83 29 22 EB 8A AE
+    39 D1 F5 72 84 53 64 81 7B 00 33 54 38 99 94 00
+    23 F2 E9 65 A6 0A 80 EB 22 1E B1 9D C5 7B 12 12
+    91 56 4C 6F 69 35 83 B3 AC 7C 6F 27 2F 4F 67 A1
+    9A 76 78 D4 23 4B 0B F4 A2 EB C0 8A A2 35 B9 78
+    8D B7 87 16 1F 66 17 02 28 65 C0 EF 9A A5 33 80
+    2D 13 6C DB C7 AE BA 53 2A CF 1B E1 83 B0 29 5A
+    B0 E3 3A 2E F6 9B E3 56 DA AF 30 96 87 15 3E 2F
+    99 A1 24 36 09 D6 03 12 6A 8C 82 3E 88 43 E4 59
+    BF C7 2B 30 69 1C DC C3 DD B2 7C F0 28 AF D5 1E
+    44 37 EE 3B 71 C0 C1 EC 87 A9 34 36 F0 C2 47 B7
+    E8 C5 0C E9 68 25 C9 70 29 99 7A 74 C3 18 AF AC
+    AA 18 A0 18 0B C7 F2 F0 F1 C5 E7 EF 1A 2D 18 3A
+    C7 EE 7E 49 15 C3 B6 8C 30 97 8A B6 C4 28 19 34
+    41 DF 47 05 B7 22 CE 25 A0 8A 1F AD CA 0E EF 1F
+    AF E8 3A DF 13 02 1D 52 0D E5 C8 27 FF 9A 97 B7
+    55 46 19 3A 9B 92 3F 05 90 38 5D C4 BF F7 C4 9D
+    49 15 B5 A3 65 DB 4C 84 DD CB 18 5D E8 F9 EE B3
+    34 96 5A 42 F1 38 1C 8B AD C2 2B A1 F8 EE 4C 0E
+    4D AA F7 A8 8E 7F 42 DD B8 14 8F 3B F8 D3 B8 D7
+    4F 09 81 55 A3 7C B4 CB 27 87 6B 85 DA 60 2E 5C
+    78 9C 10 E0 3B E7 34 07 BA B8 C4 92 13 F8 C7 4E
+    12 66 CE 9B 11 28 6E 67 4C A9 C1 0C 9C 99 55 04
+    9A 66 E9 05 1D 9A 2B 1F C9 AF E2 67 98 E9 CE C6
+
+SHAKE-256 sample of 1600-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+
+Output val is
+    CD 8A 92 0E D1 41 AA 04 07 A2 2D 59 28 86 52 E9
+    D9 F1 A7 EE 0C 1E 7C 1C A6 99 42 4D A8 4A 90 4D
+    2D 70 0C AA E7 39 6E CE 96 60 44 40 57 7D A4 F3
+    AA 22 AE B8 85 7F 96 1C 4C D8 E0 6F 0A E6 61 0B
+    10 48 A7 F6 4E 10 74 CD 62 9E 85 AD 75 66 04 8E
+    FC 4F B5 00 B4 86 A3 30 9A 8F 26 72 4C 0E D6 28
+    00 1A 10 99 42 24 68 DE 72 6F 10 61 D9 9E B9 E9
+    36 04 D5 AA 74 67 D4 B1 BD 64 84 58 2A 38 43 17
+    D7 F4 7D 75 0B 8F 54 99 51 2B B8 5A 22 6C 42 43
+    55 6E 69 6F 6B D0 72 C5 AA 2D 9B 69 73 02 44 B5
+    68 53 D1 69 70 AD 81 7E 21 3E 47 06 18 17 80 01
+    C9 FB 56 C5 4F EF A5 FE E6 7D 2D A5 24 BB 3B 0B
+    61 EF 0E 91 14 A9 2C DB B6 CC CB 98 61 5C FE 76
+    E3 51 0D D8 8D 1C C2 8F F9 92 87 51 2F 24 BF AF
+    A1 A7 68 77 B6 F3 71 98 E3 A6 41 C6 8A 7C 42 D4
+    5F A7 AC C1 0D AE 5F 3C EF B7 B7 35 F1 2D 4E 58
+    9F 7A 45 6E 78 C0 F5 E4 C4 47 1F FF A5 E4 FA 05
+    14 AE 97 4D 8C 26 48 51 3B 5D B4 94 CE A8 47 15
+    6D 27 7A D0 E1 41 C2 4C 78 39 06 4C D0 88 51 BC
+    2E 7C A1 09 FD 4E 25 1C 35 BB 0A 04 FB 05 B3 64
+    FF 8C 4D 8B 59 BC 30 3E 25 32 8C 09 A8 82 E9 52
+    51 8E 1A 8A E0 FF 26 5D 61 C4 65 89 69 73 D7 49
+    04 99 DC 63 9F B8 50 2B 39 45 67 91 B1 B6 EC 5B
+    CC 5D 9A C3 6A 6D F6 22 A0 70 D4 3F ED 78 1F 5F
+    14 9F 7B 62 67 5E 7D 1A 4D 6D EC 48 C1 C7 16 45
+    86 EA E0 6A 51 20 8C 0B 79 12 44 D3 07 72 65 05
+    C3 AD 4B 26 B6 82 23 77 25 7A A1 52 03 75 60 A7
+    39 71 4A 3C A7 9B D6 05 54 7C 9B 78 DD 1F 59 6F
+    2D 4F 17 91 BC 68 9A 0E 9B 79 9A 37 33 9C 04 27
+    57 33 74 01 43 EF 5D 2B 58 B9 6A 36 3D 4E 08 07
+    6A 1A 9D 78 46 43 6E 4D CA 57 28 B6 F7 60 EE F0
+    CA 92 BF 0B E5 61 5E 96 95 9D 76 71 97 A0 BE EB
+
+SHAKE-256 sample of 1605-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0
+
+Output val is
+    98 D0 93 B0 67 47 57 60 12 4F FB 92 04 A5 B3 27
+    C6 BB 05 C5 4F F2 34 F0 B4 3F AC 72 40 41 51 66
+    A8 C7 05 EA 0D 73 9F 08 08 B0 65 76 D9 96 66 2C
+    1F 37 66 94 D9 8F 51 57 19 B6 64 07 72 0D CF 78
+    1C 51 CD 56 EF 8B 61 0C 66 8D DC 1A C1 C2 C4 29
+    EA 4D 6F 27 4A A7 A7 73 BF 8B 0C AB 30 6F 1E EE
+    2A 17 1B 91 33 4E A0 FA CD 2A AC 1F 51 D4 D5 EB
+    0E 63 A4 E6 75 4E CA FE EC 24 6B 7A AF 58 D0 E0
+    A9 74 C7 FF 40 58 BD BD ED B3 3E D0 4B 0F A4 5D
+    70 C7 C8 4F 3D A1 3E 4F 7D 1B ED DB 53 4D 37 E5
+    AB DF B2 9F 2B 44 C4 FB 0D 6C CA B8 31 D9 0B A4
+    6A 00 53 06 62 F9 07 DE DD 47 9E 9B 54 28 E5 E2
+    DB 80 40 B0 E2 B1 F1 74 CE 34 7F 32 A0 6A 5A C2
+    2B 19 AA FE 92 7B 88 78 D0 C8 10 3A 4D 2F 19 E3
+    23 36 C6 4C FA DC 1B 9A CB 39 78 A8 29 85 71 DC
+    D8 9C 36 A6 56 92 81 6D 0C 61 CE 0E D1 79 42 36
+    70 17 BD 40 F5 9D FB AE 34 63 58 27 92 0A FE 7A
+    27 BF 56 70 09 A1 38 40 3F 06 B6 E4 DE 94 DA 07
+    7D B4 97 73 C2 35 46 61 19 42 6F 79 88 8D 3A 81
+    B4 07 DF EB A8 7E 01 CD 48 F9 0E 01 B6 F9 02 43
+    C4 01 25 DE 47 E8 C8 F3 E6 EA 33 88 CB FE EB 36
+    54 1E F2 3D 2C 83 48 45 8E A2 8C AA 50 66 F4 98
+    37 76 F0 CB 2F DC 66 04 9C F8 8A C8 EA E5 12 12
+    AA CE 86 7B EA 4C 3C AE E4 4F 14 7A 9B F9 9D 04
+    87 4E 87 22 D0 3D 3F 5F F6 EF 3B EB E7 64 2F E4
+    91 6C 5F 10 FF 3F D6 13 87 D5 D9 1B CD 32 F9 E8
+    E4 59 3D CA AD 23 EC CC 05 D2 FC 9B E2 C1 CD 63
+    0E A1 23 DC A9 CB 69 38 D6 0C DD ED C1 1E 1E 9B
+    C9 D2 68 A5 45 6B A9 CC FF 18 59 7C 5F F9 73 57
+    08 41 3B 9D 84 B9 F4 72 19 37 CC 65 95 71 27 97
+    53 2B 48 D6 F1 A2 D1 72 3B 07 D5 46 0B C1 39 16
+    D9 6E 88 18 07 13 AC 33 D2 C2 32 E3 5E 76 4E 04
+
+SHAKE-256 sample of 1630-bit message
+
+Msg as bit string
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1
+    1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 1
+
+Output val is
+    8A 83 25 07 9B 0F C3 26 5D 52 F5 98 55 CA FE 65
+    5D F4 38 AA 63 9F 6F EC 99 1F 24 94 33 0C E3 2F
+    A3 7F 7D B9 0F 69 66 D8 E4 A4 6E 50 C5 ED E5 7B
+    9B 8F 08 2A 96 62 7F 73 04 75 02 9A 61 92 29 D8
+    4F 43 2E D6 9F D0 59 23 4D 4D 7D D3 58 E8 39 3F
+    6A 36 A4 5C CF 04 1F 90 FC 0A 4E 58 02 D7 30 63
+    D3 65 31 33 6A 00 90 EC FE 1A 4D 4D 29 AA 82 4B
+    A4 2B 49 37 B4 BB 98 F4 F3 3A 0E 3B D8 B5 11 E6
+    95 28 D5 95 37 11 0D 75 21 FB 78 AC A0 18 DF 76
+    16 0F 54 A3 42 1B 84 14 92 64 ED 03 2F 6D CE 46
+    7A 73 1A 8E 34 04 8E 3A 46 E9 80 39 DF 3C 32 8D
+    EB FB E5 D1 BC 8B E7 FF 4E F8 91 7B 01 F0 B7 89
+    36 72 49 2D 6E E5 C7 1D F2 D0 53 1F 8B 68 47 64
+    BA 0A 2B 57 EC 6A 4F 60 BA 4F 36 FE 2D B0 E6 5A
+    D7 AA 5F 14 F3 EF 9F 34 A0 AB 5B C3 3D 48 87 33
+    BA 36 BF 4B 2B 4F CE 02 8E FF 8C 6C E0 3B 19 2C
+    F0 75 CC 9F 00 D2 9C 0E 06 C3 5C 44 89 D2 7F 07
+    FA 49 A9 1C A9 24 71 E3 4D AB 77 87 AE 24 A6 E0
+    F3 09 EF 0B A5 3F 7C 8B 29 92 52 0A 07 BE DD 50
+    9A 0B 6D BE A5 70 A5 96 0E D6 24 82 6D D8 EC D1
+    91 5C 87 32 7E 74 49 1C 40 5A 74 11 C1 2C 0D 44
+    97 51 26 89 BD 7F 5A DB ED B0 2C 6D 2E 68 47 4E
+    8B F3 1B 88 40 40 81 8F 4B CA 03 A4 52 17 EA C7
+    08 3A D3 A3 3C B8 47 7A 04 C9 E3 26 6A 13 34 77
+    DE 45 E7 18 30 A4 0E B0 D0 75 AF CC FC D9 DC 54
+    8D 0D 52 94 60 EA 7A C2 AD AC 72 2E 76 78 EF 59
+    7D D3 B4 95 BD 7D 1A 8F F3 94 48 BB AB 1D C6 A8
+    84 81 80 1C F5 A8 01 0E 87 3C 31 E4 79 A5 E3 DB
+    3D 4E 67 D1 D9 48 E6 7C C6 6F D7 5A 4A 19 C1 20
+    66 2E F5 59 77 BD DB AC 07 21 C8 0D 69 90 26 93
+    C8 3D 5E F7 BC 27 EF A3 93 AF 4C 43 9F C3 99 58
+    E0 E7 55 37 35 88 02 EF 08 53 B7 47 0B 0F 19 AC
+
diff --git a/crypto/test/src/crypto/test/KeccakDigestTest.cs b/crypto/test/src/crypto/test/KeccakDigestTest.cs
new file mode 100644
index 000000000..961a5d2e3
--- /dev/null
+++ b/crypto/test/src/crypto/test/KeccakDigestTest.cs
@@ -0,0 +1,374 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * Keccak Digest Test
+     */
+    [TestFixture]
+    public class KeccakDigestTest
+        : SimpleTest
+    {
+        readonly static string[] messages = {
+            "",
+            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67",
+            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e"
+        };
+
+        readonly static string[] digests288 = { // the default settings
+            "6753e3380c09e385d0339eb6b050a68f66cfd60a73476e6fd6adeb72f5edd7c6f04a5d01",  // message[0]    
+            "0bbe6afae0d7e89054085c1cc47b1689772c89a41796891e197d1ca1b76f288154933ded",  // message[1]
+            "82558a209b960ddeb531e6dcb281885b2400ca160472462486e79f071e88a3330a8a303d",  // message[2]
+            "94049e1ad7ef5d5b0df2b880489e7ab09ec937c3bfc1b04470e503e1ac7b1133c18f86da",  // 64k a-test
+            "a9cb5a75b5b81b7528301e72553ed6770214fa963956e790528afe420de33c074e6f4220",  // random alphabet test
+            "eadaf5ba2ad6a2f6f338fce0e1efdad2a61bb38f6be6068b01093977acf99e97a5d5827c"   // extremely long data test
+        };
+
+        readonly static string[] digests224 = {
+            "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd",
+            "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe",
+            "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab",
+            "f621e11c142fbf35fa8c22841c3a812ba1e0151be4f38d80b9f1ff53",
+            "68b5fc8c87193155bba68a2485377e809ee4f81a85ef023b9e64add0",
+            "c42e4aee858e1a8ad2976896b9d23dd187f64436ee15969afdbc68c5"
+        };
+
+        readonly static string[] digests256 = {
+            "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
+            "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15",
+            "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d",
+            "0047a916daa1f92130d870b542e22d3108444f5a7e4429f05762fb647e6ed9ed",
+            "db368762253ede6d4f1db87e0b799b96e554eae005747a2ea687456ca8bcbd03",
+            "5f313c39963dcf792b5470d4ade9f3a356a3e4021748690a958372e2b06f82a4"
+        };
+
+        readonly static string[] digests384 = {
+            "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff",
+            "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3",
+            "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b",
+            "c704cfe7a1a53208ca9526cd24251e0acdc252ecd978eee05acd16425cfb404ea81f5a9e2e5e97784d63ee6a0618a398",
+            "d4fe8586fd8f858dd2e4dee0bafc19b4c12b4e2a856054abc4b14927354931675cdcaf942267f204ea706c19f7beefc4",
+            "9b7168b4494a80a86408e6b9dc4e5a1837c85dd8ff452ed410f2832959c08c8c0d040a892eb9a755776372d4a8732315"
+        };
+
+        readonly static string[] digests512 = {
+            "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e",
+            "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609",
+            "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760",
+            "34341ead153aa1d1fdcf6cf624c2b4f6894b6fd16dc38bd4ec971ac0385ad54fafcb2e0ed86a1e509456f4246fdcb02c3172824cd649d9ad54c51f7fb49ea67c",
+            "dc44d4f4d36b07ab5fc04016cbe53548e5a7778671c58a43cb379fd00c06719b8073141fc22191ffc3db5f8b8983ae8341fa37f18c1c969664393aa5ceade64e",
+            "3e122edaf37398231cfaca4c7c216c9d66d5b899ec1d7ac617c40c7261906a45fc01617a021e5da3bd8d4182695b5cb785a28237cbb167590e34718e56d8aab8"
+        };
+
+        // test vectors from  http://www.di-mgt.com.au/hmac_sha3_testvectors.html
+        readonly static byte[][] macKeys =
+        {
+            Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+            Hex.Decode("4a656665"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+            Hex.Decode("0102030405060708090a0b0c0d0e0f10111213141516171819"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaa"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaa"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
+        };
+
+        readonly static string[] macData =
+        {
+            "4869205468657265",
+            "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+            "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +
+                "dddddddddddddddddddddddddddddddddddd",
+            "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" +
+                "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+            "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" +
+                "65204b6579202d2048617368204b6579204669727374",
+            "5468697320697320612074657374207573696e672061206c6172676572207468" +
+                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
+                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
+                "647320746f20626520686173686564206265666f7265206265696e6720757365" +
+                "642062792074686520484d414320616c676f726974686d2e",
+            "5468697320697320612074657374207573696e672061206c6172676572207468" +
+                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
+                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
+                "647320746f20626520686173686564206265666f7265206265696e6720757365\n" +
+                "642062792074686520484d414320616c676f726974686d2e"
+        };
+
+        readonly static string[] mac224 =
+        {
+            "b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc",
+            "e824fec96c074f22f99235bb942da1982664ab692ca8501053cbd414",
+            "770df38c99d6e2bacd68056dcfe07d4c89ae20b2686a6185e1faa449",
+            "305a8f2dfb94bad28861a03cbc4d590febe775c58cb4961c28428a0b",
+            "e7a52dfa45f95a217c100066b239aa8ad519be9b35d667268b1b57ff",
+            "ba13009405a929f398b348885caa5419191bb948ada32194afc84104",
+            "92649468be236c3c72c189909c063b13f994be05749dc91310db639e"
+        };
+
+        readonly static string[] mac256 =
+        {
+            "9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821",
+            "aa9aed448c7abc8b5e326ffa6a01cdedf7b4b831881468c044ba8dd4566369a1",
+            "95f43e50f8df80a21977d51a8db3ba572dcd71db24687e6f86f47c1139b26260",
+            "6331ba9b4af5804a68725b3663eb74814494b63c6093e35fb320a85d507936fd",
+            "b4d0cdee7ec2ba81a88b86918958312300a15622377929a054a9ce3ae1fac2b6",
+            "1fdc8cb4e27d07c10d897dec39c217792a6e64fa9c63a77ce42ad106ef284e02",
+            "fdaa10a0299aecff9bb411cf2d7748a4022e4a26be3fb5b11b33d8c2b7ef5484"
+        };
+
+        readonly static string[] mac384 =
+        {
+            "892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048",
+            "5af5c9a77a23a6a93d80649e562ab77f4f3552e3c5caffd93bdf8b3cfc6920e3023fc26775d9df1f3c94613146ad2c9d",
+            "4243c29f2201992ff96441e3b91ff81d8c601d706fbc83252684a4bc51101ca9b2c06ddd03677303c502ac5331752a3c",
+            "b730724d3d4090cda1be799f63acbbe389fef7792fc18676fa5453aab398664650ed029c3498bbe8056f06c658e1e693",
+            "d62482ef601d7847439b55236e9679388ffcd53c62cd126f39be6ea63de762e26cd5974cb9a8de401b786b5555040f6f",
+            "4860ea191ac34994cf88957afe5a836ef36e4cc1a66d75bf77defb7576122d75f60660e4cf731c6effac06402787e2b9",
+            "fe9357e3cfa538eb0373a2ce8f1e26ad6590afdaf266f1300522e8896d27e73f654d0631c8fa598d4bb82af6b744f4f5"
+        };
+
+        readonly static string[] mac512 =
+        {
+            "8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755",
+            "c2962e5bbe1238007852f79d814dbbecd4682e6f097d37a363587c03bfa2eb0859d8d9c701e04cececfd3dd7bfd438f20b8b648e01bf8c11d26824b96cebbdcb",
+            "eb0ed9580e0ec11fc66cbb646b1be904eaff6da4556d9334f65ee4b2c85739157bae9027c51505e49d1bb81cfa55e6822db55262d5a252c088a29a5e95b84a66",
+            "b46193bb59f4f696bf702597616da91e2a4558a593f4b015e69141ba81e1e50ea580834c2b87f87baa25a3a03bfc9bb389847f2dc820beae69d30c4bb75369cb",
+            "d05888a6ebf8460423ea7bc85ea4ffda847b32df32291d2ce115fd187707325c7ce4f71880d91008084ce24a38795d20e6a28328a0f0712dc38253370da3ebb5",
+            "2c6b9748d35c4c8db0b4407dd2ed2381f133bdbd1dfaa69e30051eb6badfcca64299b88ae05fdbd3dd3dd7fe627e42e39e48b0fe8c7f1e85f2dbd52c2d753572",
+            "6adc502f14e27812402fc81a807b28bf8a53c87bea7a1df6256bf66f5de1a4cb741407ad15ab8abc136846057f881969fbb159c321c904bfb557b77afb7778c8"
+        };
+
+        readonly static KeyParameter truncKey = new KeyParameter(Hex.Decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"));
+        readonly static byte[] truncData = Hex.Decode("546573742057697468205472756e636174696f6e");
+
+        readonly static byte[] trunc224 = Hex.Decode("f52bbcfd654264e7133085c5e69b72c3");
+        readonly static byte[] trunc256 = Hex.Decode("745e7e687f8335280d54202ef13cecc6");
+        readonly static byte[] trunc384 = Hex.Decode("fa9aea2bc1e181e47cbb8c3df243814d");
+        readonly static byte[] trunc512 = Hex.Decode("04c929fead434bba190dacfa554ce3f5");
+
+        readonly static byte[] xtremeData = Hex.Decode("61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f");
+
+        public override string Name
+        {
+            get { return "Keccak"; }
+        }
+
+        private void TestDigest(IDigest digest, string[] expected)
+        {
+            byte[] hash = new byte[digest.GetDigestSize()];
+
+            for (int i = 0; i != messages.Length; i++)
+            {
+                if (messages.Length != 0)
+                {
+                    byte[] data = Hex.Decode(messages[i]);
+
+                    digest.BlockUpdate(data, 0, data.Length);
+                }
+
+                digest.DoFinal(hash, 0);
+
+                if (!Arrays.AreEqual(Hex.Decode(expected[i]), hash))
+                {
+                    Fail("Keccak mismatch on " + digest.AlgorithmName + " index " + i);
+                }
+            }
+
+            byte[] k64 = new byte[1024 * 64];
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                k64[i] = (byte)'a';
+            }
+
+            digest.BlockUpdate(k64, 0, k64.Length);
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
+            {
+                Fail("Keccak mismatch on " + digest.AlgorithmName + " 64k a");
+            }
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                digest.Update((byte)'a');
+            }
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
+            {
+                Fail("Keccak mismatch on " + digest.AlgorithmName + " 64k a single");
+            }
+
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                k64[i] = (byte)('a' + (i % 26));
+            }
+
+            digest.BlockUpdate(k64, 0, k64.Length);
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+            {
+                Fail("Keccak mismatch on " + digest.AlgorithmName + " 64k alpha");
+            }
+
+            for (int i = 0; i != 64; i++)
+            {
+                digest.Update(k64[i * 1024]);
+                digest.BlockUpdate(k64, i * 1024 + 1, 1023);
+            }
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+            {
+                Fail("Keccak mismatch on " + digest.AlgorithmName + " 64k chunked alpha");
+            }
+
+            TestDigestDoFinal(digest);
+
+            //
+            // extremely long data test
+            //
+            //Console.WriteLine("Starting very long");
+            //for (int i = 0; i != 16384; i++)
+            //{
+            //    for (int j = 0; j != 1024; j++)
+            //    {
+            //        digest.BlockUpdate(xtremeData, 0, xtremeData.Length);
+            //    }
+            //}
+
+            //digest.DoFinal(hash, 0);
+
+            //if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 2]), hash))
+            //{
+            //    Fail("Keccak mismatch on " + digest.AlgorithmName + " extreme data test");
+            //}
+            //Console.WriteLine("Done");
+        }
+
+        private void TestDigestDoFinal(IDigest digest)
+        {
+            byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+            for (int i = 0; i <= digest.GetDigestSize(); ++i)
+            {
+                byte[] cmp = new byte[2 * digest.GetDigestSize()];
+                Array.Copy(hash, 0, cmp, i, hash.Length);
+
+                byte[] buf = new byte[2 * digest.GetDigestSize()];
+                digest.DoFinal(buf, i);
+
+                if (!Arrays.AreEqual(cmp, buf))
+                {
+                    Fail("Keccak offset DoFinal on " + digest.AlgorithmName);
+                }
+            }
+        }
+
+        private void TestMac(IDigest digest, byte[][] keys, String[] data, String[] expected, byte[] truncExpected)
+        {
+            IMac mac = new HMac(digest);
+
+            for (int i = 0; i != keys.Length; i++)
+            {
+                mac.Init(new KeyParameter(keys[i]));
+
+                byte[] mData = Hex.Decode(data[i]);
+
+                mac.BlockUpdate(mData, 0, mData.Length);
+
+                byte[] macV = new byte[mac.GetMacSize()];
+
+                mac.DoFinal(macV, 0);
+
+                if (!Arrays.AreEqual(Hex.Decode(expected[i]), macV))
+                {
+                    Fail("Keccak HMAC mismatch on " + digest.AlgorithmName);
+                }
+            }
+
+            {
+                mac = new HMac(digest);
+
+                mac.Init(truncKey);
+
+                mac.BlockUpdate(truncData, 0, truncData.Length);
+
+                byte[] macV = new byte[mac.GetMacSize()];
+
+                mac.DoFinal(macV, 0);
+
+                for (int i = 0; i != truncExpected.Length; i++)
+                {
+                    if (macV[i] != truncExpected[i])
+                    {
+                        Fail("mismatch on truncated HMAC for " + digest.AlgorithmName);
+                    }
+                }
+            }
+        }
+
+        public override void PerformTest()
+        {
+            TestDigest(new KeccakDigest(), digests288);
+            TestDigest(new KeccakDigest(224), digests224);
+            TestDigest(new KeccakDigest(256), digests256);
+            TestDigest(new KeccakDigest(384), digests384);
+            TestDigest(new KeccakDigest(512), digests512);
+
+            TestMac(new KeccakDigest(224), macKeys, macData, mac224, trunc224);
+            TestMac(new KeccakDigest(256), macKeys, macData, mac256, trunc256);
+            TestMac(new KeccakDigest(384), macKeys, macData, mac384, trunc384);
+            TestMac(new KeccakDigest(512), macKeys, macData, mac512, trunc512);
+        }
+
+        protected virtual IDigest CloneDigest(IDigest digest)
+        {
+            return new KeccakDigest((KeccakDigest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new KeccakDigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs
index 0b7a0f72d..ab6394571 100644
--- a/crypto/test/src/crypto/test/RegressionTest.cs
+++ b/crypto/test/src/crypto/test/RegressionTest.cs
@@ -119,7 +119,9 @@ namespace Org.BouncyCastle.Crypto.Tests
             new Poly1305Test(),
             new OcbTest(),
             new SM3DigestTest(),
-            new X931SignerTest()
+            new X931SignerTest(),
+            new KeccakDigestTest(),
+            new ShakeDigestTest(),
         };
 
         public static void Main(
diff --git a/crypto/test/src/crypto/test/SHA3DigestTest.cs b/crypto/test/src/crypto/test/SHA3DigestTest.cs
index 2b8ae4a63..71f51f43b 100644
--- a/crypto/test/src/crypto/test/SHA3DigestTest.cs
+++ b/crypto/test/src/crypto/test/SHA3DigestTest.cs
@@ -1,11 +1,11 @@
 using System;
+using System.IO;
+using System.Text;
 
 using NUnit.Framework;
 
-using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Macs;
-using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
 using Org.BouncyCastle.Utilities.Test;
@@ -19,346 +19,218 @@ namespace Org.BouncyCastle.Crypto.Tests
     public class Sha3DigestTest
         : SimpleTest
     {
-        readonly static string[] messages = {
-            "",
-            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67",
-            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e"
-        };
-
-        readonly static string[] digests288 = { // the default settings
-            "6753e3380c09e385d0339eb6b050a68f66cfd60a73476e6fd6adeb72f5edd7c6f04a5d01",  // message[0]    
-            "0bbe6afae0d7e89054085c1cc47b1689772c89a41796891e197d1ca1b76f288154933ded",  // message[1]
-            "82558a209b960ddeb531e6dcb281885b2400ca160472462486e79f071e88a3330a8a303d",  // message[2]
-            "94049e1ad7ef5d5b0df2b880489e7ab09ec937c3bfc1b04470e503e1ac7b1133c18f86da",  // 64k a-test
-            "a9cb5a75b5b81b7528301e72553ed6770214fa963956e790528afe420de33c074e6f4220",  // random alphabet test
-            "eadaf5ba2ad6a2f6f338fce0e1efdad2a61bb38f6be6068b01093977acf99e97a5d5827c"   // extremely long data test
-        };
-
-        readonly static string[] digests224 = {
-            "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd",
-            "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe",
-            "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab",
-            "f621e11c142fbf35fa8c22841c3a812ba1e0151be4f38d80b9f1ff53",
-            "68b5fc8c87193155bba68a2485377e809ee4f81a85ef023b9e64add0",
-            "c42e4aee858e1a8ad2976896b9d23dd187f64436ee15969afdbc68c5"
-        };
-
-        readonly static string[] digests256 = {
-            "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
-            "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15",
-            "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d",
-            "0047a916daa1f92130d870b542e22d3108444f5a7e4429f05762fb647e6ed9ed",
-            "db368762253ede6d4f1db87e0b799b96e554eae005747a2ea687456ca8bcbd03",
-            "5f313c39963dcf792b5470d4ade9f3a356a3e4021748690a958372e2b06f82a4"
-        };
-
-        readonly static string[] digests384 = {
-            "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff",
-            "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3",
-            "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b",
-            "c704cfe7a1a53208ca9526cd24251e0acdc252ecd978eee05acd16425cfb404ea81f5a9e2e5e97784d63ee6a0618a398",
-            "d4fe8586fd8f858dd2e4dee0bafc19b4c12b4e2a856054abc4b14927354931675cdcaf942267f204ea706c19f7beefc4",
-            "9b7168b4494a80a86408e6b9dc4e5a1837c85dd8ff452ed410f2832959c08c8c0d040a892eb9a755776372d4a8732315"
-        };
-
-        readonly static string[] digests512 = {
-            "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e",
-            "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609",
-            "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760",
-            "34341ead153aa1d1fdcf6cf624c2b4f6894b6fd16dc38bd4ec971ac0385ad54fafcb2e0ed86a1e509456f4246fdcb02c3172824cd649d9ad54c51f7fb49ea67c",
-            "dc44d4f4d36b07ab5fc04016cbe53548e5a7778671c58a43cb379fd00c06719b8073141fc22191ffc3db5f8b8983ae8341fa37f18c1c969664393aa5ceade64e",
-            "3e122edaf37398231cfaca4c7c216c9d66d5b899ec1d7ac617c40c7261906a45fc01617a021e5da3bd8d4182695b5cb785a28237cbb167590e34718e56d8aab8"
-        };
-
-        // test vectors from  http://www.di-mgt.com.au/hmac_sha3_testvectors.html
-        readonly static byte[][] macKeys =
+        internal class MySha3Digest : Sha3Digest
         {
-            Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
-            Hex.Decode("4a656665"),
-            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
-            Hex.Decode("0102030405060708090a0b0c0d0e0f10111213141516171819"),
-            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaa"),
-            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaa"),
-            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
-                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
-        };
-
-        readonly static string[] macData =
-        {
-            "4869205468657265",
-            "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
-            "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +
-                "dddddddddddddddddddddddddddddddddddd",
-            "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" +
-                "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
-            "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" +
-                "65204b6579202d2048617368204b6579204669727374",
-            "5468697320697320612074657374207573696e672061206c6172676572207468" +
-                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
-                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
-                "647320746f20626520686173686564206265666f7265206265696e6720757365" +
-                "642062792074686520484d414320616c676f726974686d2e",
-            "5468697320697320612074657374207573696e672061206c6172676572207468" +
-                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
-                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
-                "647320746f20626520686173686564206265666f7265206265696e6720757365\n" +
-                "642062792074686520484d414320616c676f726974686d2e"
-        };
-
-        readonly static string[] mac224 =
-        {
-            "b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc",
-            "e824fec96c074f22f99235bb942da1982664ab692ca8501053cbd414",
-            "770df38c99d6e2bacd68056dcfe07d4c89ae20b2686a6185e1faa449",
-            "305a8f2dfb94bad28861a03cbc4d590febe775c58cb4961c28428a0b",
-            "e7a52dfa45f95a217c100066b239aa8ad519be9b35d667268b1b57ff",
-            "ba13009405a929f398b348885caa5419191bb948ada32194afc84104",
-            "92649468be236c3c72c189909c063b13f994be05749dc91310db639e"
-        };
-
-        readonly static string[] mac256 =
-        {
-            "9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821",
-            "aa9aed448c7abc8b5e326ffa6a01cdedf7b4b831881468c044ba8dd4566369a1",
-            "95f43e50f8df80a21977d51a8db3ba572dcd71db24687e6f86f47c1139b26260",
-            "6331ba9b4af5804a68725b3663eb74814494b63c6093e35fb320a85d507936fd",
-            "b4d0cdee7ec2ba81a88b86918958312300a15622377929a054a9ce3ae1fac2b6",
-            "1fdc8cb4e27d07c10d897dec39c217792a6e64fa9c63a77ce42ad106ef284e02",
-            "fdaa10a0299aecff9bb411cf2d7748a4022e4a26be3fb5b11b33d8c2b7ef5484"
-        };
-
-        readonly static string[] mac384 =
-        {
-            "892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048",
-            "5af5c9a77a23a6a93d80649e562ab77f4f3552e3c5caffd93bdf8b3cfc6920e3023fc26775d9df1f3c94613146ad2c9d",
-            "4243c29f2201992ff96441e3b91ff81d8c601d706fbc83252684a4bc51101ca9b2c06ddd03677303c502ac5331752a3c",
-            "b730724d3d4090cda1be799f63acbbe389fef7792fc18676fa5453aab398664650ed029c3498bbe8056f06c658e1e693",
-            "d62482ef601d7847439b55236e9679388ffcd53c62cd126f39be6ea63de762e26cd5974cb9a8de401b786b5555040f6f",
-            "4860ea191ac34994cf88957afe5a836ef36e4cc1a66d75bf77defb7576122d75f60660e4cf731c6effac06402787e2b9",
-            "fe9357e3cfa538eb0373a2ce8f1e26ad6590afdaf266f1300522e8896d27e73f654d0631c8fa598d4bb82af6b744f4f5"
-        };
-
-        readonly static string[] mac512 =
-        {
-            "8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755",
-            "c2962e5bbe1238007852f79d814dbbecd4682e6f097d37a363587c03bfa2eb0859d8d9c701e04cececfd3dd7bfd438f20b8b648e01bf8c11d26824b96cebbdcb",
-            "eb0ed9580e0ec11fc66cbb646b1be904eaff6da4556d9334f65ee4b2c85739157bae9027c51505e49d1bb81cfa55e6822db55262d5a252c088a29a5e95b84a66",
-            "b46193bb59f4f696bf702597616da91e2a4558a593f4b015e69141ba81e1e50ea580834c2b87f87baa25a3a03bfc9bb389847f2dc820beae69d30c4bb75369cb",
-            "d05888a6ebf8460423ea7bc85ea4ffda847b32df32291d2ce115fd187707325c7ce4f71880d91008084ce24a38795d20e6a28328a0f0712dc38253370da3ebb5",
-            "2c6b9748d35c4c8db0b4407dd2ed2381f133bdbd1dfaa69e30051eb6badfcca64299b88ae05fdbd3dd3dd7fe627e42e39e48b0fe8c7f1e85f2dbd52c2d753572",
-            "6adc502f14e27812402fc81a807b28bf8a53c87bea7a1df6256bf66f5de1a4cb741407ad15ab8abc136846057f881969fbb159c321c904bfb557b77afb7778c8"
-        };
-
-        readonly static KeyParameter truncKey = new KeyParameter(Hex.Decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"));
-        readonly static byte[] truncData = Hex.Decode("546573742057697468205472756e636174696f6e");
-
-        readonly static byte[] trunc224 = Hex.Decode("f52bbcfd654264e7133085c5e69b72c3");
-        readonly static byte[] trunc256 = Hex.Decode("745e7e687f8335280d54202ef13cecc6");
-        readonly static byte[] trunc384 = Hex.Decode("fa9aea2bc1e181e47cbb8c3df243814d");
-        readonly static byte[] trunc512 = Hex.Decode("04c929fead434bba190dacfa554ce3f5");
+            internal MySha3Digest(int bitLength)
+                : base(bitLength)
+            {
+            }
 
-        readonly static byte[] xtremeData = Hex.Decode("61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f");
+            internal int MyDoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+            {
+                return DoFinal(output, outOff, partialByte, partialBits);
+            }
+        }
 
         public override string Name
         {
-            get { return "SHA3"; }
+            get { return "SHA-3"; }
         }
 
-        private void TestDigest(IDigest digest, string[] expected)
+        public override void PerformTest()
         {
-            byte[] hash = new byte[digest.GetDigestSize()];
+            TestVectors();
+        }
 
-            for (int i = 0; i != messages.Length; i++)
+        public void TestVectors()
+        {
+            using (StreamReader r = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.SHA3TestVectors.txt")))
             {
-                if (messages.Length != 0)
-                {
-                    byte[] data = Hex.Decode(messages[i]);
-
-                    digest.BlockUpdate(data, 0, data.Length);
-                }
-
-                digest.DoFinal(hash, 0);
-
-                if (!Arrays.AreEqual(Hex.Decode(expected[i]), hash))
+                String line;
+                while (null != (line = ReadLine(r)))
                 {
-                    Fail("sha3 mismatch on " + digest.AlgorithmName + " index " + i);
+                    if (line.Length != 0)
+                    {
+                        TestVector v = ReadTestVector(r, line);
+                        RunTestVector(v);
+                    }
                 }
             }
+        }
 
-            byte[] k64 = new byte[1024 * 64];
-
-            for (int i = 0; i != k64.Length; i++)
+        private MySha3Digest CreateDigest(string algorithm)
+        {
+            if (algorithm.StartsWith("SHA3-"))
             {
-                k64[i] = (byte)'a';
+                int bits = ParseDecimal(algorithm.Substring("SHA3-".Length));
+                return new MySha3Digest(bits);
             }
+            throw new ArgumentException("Unknown algorithm: " + algorithm, "algorithm");
+        }
 
-            digest.BlockUpdate(k64, 0, k64.Length);
-
-            digest.DoFinal(hash, 0);
+        private byte[] DecodeBinary(string block)
+        {
+            int bits = block.Length;
+            int fullBytes = bits / 8;
+            int totalBytes = (bits + 7) / 8;
+            byte[] result = new byte[totalBytes];
 
-            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
+            for (int i = 0; i < fullBytes; ++i)
             {
-                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k a");
+                string byteStr = Reverse(block.Substring(i * 8, 8));
+                result[i] = (byte)ParseBinary(byteStr);
             }
 
-            for (int i = 0; i != k64.Length; i++)
+            if (totalBytes > fullBytes)
             {
-                digest.Update((byte)'a');
+                string byteStr = Reverse(block.Substring(fullBytes * 8));
+                result[fullBytes] = (byte)ParseBinary(byteStr);
             }
 
-            digest.DoFinal(hash, 0);
+            return result;
+        }
 
-            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
-            {
-                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k a single");
-            }
+        private int ParseBinary(string s)
+        {
+            return new BigInteger(s, 2).IntValue;
+        }
 
+        private int ParseDecimal(string s)
+        {
+            return Int32.Parse(s);
+        }
 
-            for (int i = 0; i != k64.Length; i++)
+        private string ReadBlock(StreamReader r)
+        {
+            StringBuilder b = new StringBuilder();
+            string line;
+            while ((line = ReadBlockLine(r)) != null)
             {
-                k64[i] = (byte)('a' + (i % 26));
+                b.Append(line);
             }
+            return b.ToString();
+        }
 
-            digest.BlockUpdate(k64, 0, k64.Length);
-
-            digest.DoFinal(hash, 0);
-
-            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+        private string ReadBlockLine(StreamReader r)
+        {
+            string line = ReadLine(r);
+            if (line == null || line.Length == 0)
             {
-                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k alpha");
+                return null;
             }
+            return line.Replace(" ", "");
+        }
 
-            for (int i = 0; i != 64; i++)
-            {
-                digest.Update(k64[i * 1024]);
-                digest.BlockUpdate(k64, i * 1024 + 1, 1023);
-            }
+        private TestVector ReadTestVector(StreamReader r, string header)
+        {
+            string[] parts = SplitAround(header, TestVector.SAMPLE_OF);
 
-            digest.DoFinal(hash, 0);
+            string algorithm = parts[0];
+            int bits = ParseDecimal(StripFromChar(parts[1], '-'));
 
-            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+            SkipUntil(r, TestVector.MSG_HEADER);
+            string messageBlock = ReadBlock(r);
+            if (messageBlock.Length != bits)
             {
-                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k chunked alpha");
+                throw new InvalidOperationException("Test vector length mismatch");
             }
+            byte[] message = DecodeBinary(messageBlock);
+
+            SkipUntil(r, TestVector.HASH_HEADER);
+            byte[] hash = Hex.Decode(ReadBlock(r));
 
-            TestDigestDoFinal(digest);
-
-            //
-            // extremely long data test
-            //
-            //Console.WriteLine("Starting very long");
-            //for (int i = 0; i != 16384; i++)
-            //{
-            //    for (int j = 0; j != 1024; j++)
-            //    {
-            //        digest.BlockUpdate(xtremeData, 0, xtremeData.Length);
-            //    }
-            //}
-    
-            //digest.DoFinal(hash, 0);
-    
-            //if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 2]), hash))
-            //{
-            //    Fail("sha3 mismatch on " + digest.AlgorithmName + " extreme data test");
-            //}
-            //Console.WriteLine("Done");
+            return new TestVector(algorithm, bits, message, hash);
         }
 
-        private void TestDigestDoFinal(IDigest digest)
+        private string ReadLine(StreamReader r)
         {
-            byte[] hash = new byte[digest.GetDigestSize()];
-            digest.DoFinal(hash, 0);
+            string line = r.ReadLine();
+            return line == null ? null : StripFromChar(line, '#').Trim();
+        }
 
-            for (int i = 0; i <= digest.GetDigestSize(); ++i)
+        private string RequireLine(StreamReader r)
+        {
+            string line = ReadLine(r);
+            if (line == null)
             {
-                byte[] cmp = new byte[2 * digest.GetDigestSize()];
-                Array.Copy(hash, 0, cmp, i, hash.Length);
-
-                byte[] buf = new byte[2 * digest.GetDigestSize()];
-                digest.DoFinal(buf, i);
-
-                if (!Arrays.AreEqual(cmp, buf))
-                {
-                    Fail("sha3 offset DoFinal on " + digest.AlgorithmName);
-                }
+                throw new EndOfStreamException();
             }
+            return line;
         }
 
-        private void TestMac(IDigest digest, byte[][] keys, String[] data, String[] expected, byte[] truncExpected)
+        private string Reverse(string s)
         {
-            IMac mac = new HMac(digest);
-
-            for (int i = 0; i != keys.Length; i++)
-            {
-                mac.Init(new KeyParameter(keys[i]));
-
-                byte[] mData = Hex.Decode(data[i]);
+            char[] cs = s.ToCharArray();
+            Array.Reverse(cs);
+            return new string(cs);
+        }
 
-                mac.BlockUpdate(mData, 0, mData.Length);
+        private void RunTestVector(TestVector v)
+        {
+            int bits = v.Bits;
+            int partialBits = bits % 8;
 
-                byte[] macV = new byte[mac.GetMacSize()];
+            //Console.WriteLine(v.Algorithm + " " + bits + "-bit");
+            //Console.WriteLine(Hex.ToHexString(v.Message).ToUpper());
+            //Console.WriteLine(Hex.ToHexString(v.Hash).ToUpper());
 
-                mac.DoFinal(macV, 0);
+            MySha3Digest d = CreateDigest(v.Algorithm);
+            byte[] output = new byte[d.GetDigestSize()];
 
-                if (!Arrays.AreEqual(Hex.Decode(expected[i]), macV))
-                {
-                    Fail("sha3 HMAC mismatch on " + digest.AlgorithmName);
-                }
+            byte[] m = v.Message;
+            if (partialBits == 0)
+            {
+                d.BlockUpdate(m, 0, m.Length);
+                d.DoFinal(output, 0);
             }
-
+            else
             {
-                mac = new HMac(digest);
-
-                mac.Init(truncKey);
-
-                mac.BlockUpdate(truncData, 0, truncData.Length);
-
-                byte[] macV = new byte[mac.GetMacSize()];
+                d.BlockUpdate(m, 0, m.Length - 1);
+                d.MyDoFinal(output, 0, m[m.Length - 1], partialBits);
+            }
 
-                mac.DoFinal(macV, 0);
+            if (!Arrays.AreEqual(v.Hash, output))
+            {
+                Fail(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
+                //Console.Error.WriteLine(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
+                //Console.Error.WriteLine(Hex.ToHexString(output).ToUpper());
+            }
+        }
 
-                for (int i = 0; i != truncExpected.Length; i++)
-                {
-                    if (macV[i] != truncExpected[i])
-                    {
-                        Fail("mismatch on truncated HMAC for " + digest.AlgorithmName);
-                    }
-                }
+        private void SkipUntil(StreamReader r, string header)
+        {
+            string line;
+            do
+            {
+                line = RequireLine(r);
+            }
+            while (line.Length == 0);
+            if (!line.Equals(header))
+            {
+                throw new IOException("Expected: " + header);
             }
         }
 
-        public override void PerformTest()
+        private string[] SplitAround(string s, string separator)
         {
-            TestDigest(new Sha3Digest(), digests288);
-            TestDigest(new Sha3Digest(224), digests224);
-            TestDigest(new Sha3Digest(256), digests256);
-            TestDigest(new Sha3Digest(384), digests384);
-            TestDigest(new Sha3Digest(512), digests512);
-
-            TestMac(new Sha3Digest(224), macKeys, macData, mac224, trunc224);
-            TestMac(new Sha3Digest(256), macKeys, macData, mac256, trunc256);
-            TestMac(new Sha3Digest(384), macKeys, macData, mac384, trunc384);
-            TestMac(new Sha3Digest(512), macKeys, macData, mac512, trunc512);
+            int i = s.IndexOf(separator);
+            if (i < 0)
+                throw new InvalidOperationException();
+            return new string[] { s.Substring(0, i), s.Substring(i + separator.Length) };
         }
 
-        protected virtual IDigest CloneDigest(IDigest digest)
+        private string StripFromChar(string s, char c)
         {
-            return new Sha3Digest((Sha3Digest)digest);
+            int i = s.IndexOf(c);
+            if (i >= 0)
+            {
+                s = s.Substring(0, i);
+            }
+            return s;
         }
 
         public static void Main(
-            string[] args)
+            string[]    args)
         {
             RunTest(new Sha3DigestTest());
         }
@@ -370,5 +242,45 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             Assert.AreEqual(Name + ": Okay", resultText);
         }
+
+        internal class TestVector
+        {
+            internal static string SAMPLE_OF = " sample of ";
+            internal static string MSG_HEADER = "Msg as bit string";
+            internal static string HASH_HEADER = "Hash val is";
+
+            private readonly string algorithm;
+            private readonly int bits;
+            private readonly byte[] message;
+            private readonly byte[] hash;
+
+            internal TestVector(string algorithm, int bits, byte[] message, byte[] hash)
+            {
+                this.algorithm = algorithm;
+                this.bits = bits;
+                this.message = message;
+                this.hash = hash;
+            }
+
+            public string Algorithm
+            {
+                get { return algorithm; }
+            }
+
+            public int Bits
+            {
+                get { return bits; }
+            }
+
+            public byte[] Message
+            {
+                get { return message; }
+            }
+
+            public byte[] Hash
+            {
+                get { return hash; }
+            }
+        }
     }
 }
diff --git a/crypto/test/src/crypto/test/ShakeDigestTest.cs b/crypto/test/src/crypto/test/ShakeDigestTest.cs
new file mode 100644
index 000000000..ef4696739
--- /dev/null
+++ b/crypto/test/src/crypto/test/ShakeDigestTest.cs
@@ -0,0 +1,290 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * SHAKE Digest Test
+     */
+    [TestFixture]
+    public class ShakeDigestTest
+        : SimpleTest
+    {
+        internal class MyShakeDigest : ShakeDigest
+        {
+            internal MyShakeDigest(int bitLength)
+                : base(bitLength)
+            {
+            }
+
+            internal int MyDoFinal(byte[] output, int outOff, int outLen, byte partialByte, int partialBits)
+            {
+                return DoFinal(output, outOff, outLen, partialByte, partialBits);
+            }
+        }
+
+        public override string Name
+        {
+            get { return "SHAKE"; }
+        }
+
+        public override void PerformTest()
+        {
+            TestVectors();
+        }
+
+        public void TestVectors()
+        {
+            using (StreamReader r = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.SHAKETestVectors.txt")))
+            {
+                String line;
+                while (null != (line = ReadLine(r)))
+                {
+                    if (line.Length != 0)
+                    {
+                        TestVector v = ReadTestVector(r, line);
+                        RunTestVector(v);
+                    }
+                }
+            }
+        }
+
+        private MyShakeDigest CreateDigest(string algorithm)
+        {
+            if (algorithm.StartsWith("SHAKE-"))
+            {
+                int bits = ParseDecimal(algorithm.Substring("SHAKE-".Length));
+                return new MyShakeDigest(bits);
+            }
+            throw new ArgumentException("Unknown algorithm: " + algorithm, "algorithm");
+        }
+
+        private byte[] DecodeBinary(string block)
+        {
+            int bits = block.Length;
+            int fullBytes = bits / 8;
+            int totalBytes = (bits + 7) / 8;
+            byte[] result = new byte[totalBytes];
+
+            for (int i = 0; i < fullBytes; ++i)
+            {
+                string byteStr = Reverse(block.Substring(i * 8, 8));
+                result[i] = (byte)ParseBinary(byteStr);
+            }
+
+            if (totalBytes > fullBytes)
+            {
+                string byteStr = Reverse(block.Substring(fullBytes * 8));
+                result[fullBytes] = (byte)ParseBinary(byteStr);
+            }
+
+            return result;
+        }
+
+        private int ParseBinary(string s)
+        {
+            return new BigInteger(s, 2).IntValue;
+        }
+
+        private int ParseDecimal(string s)
+        {
+            return Int32.Parse(s);
+        }
+
+        private string ReadBlock(StreamReader r)
+        {
+            StringBuilder b = new StringBuilder();
+            string line;
+            while ((line = ReadBlockLine(r)) != null)
+            {
+                b.Append(line);
+            }
+            return b.ToString();
+        }
+
+        private string ReadBlockLine(StreamReader r)
+        {
+            string line = ReadLine(r);
+            if (line == null || line.Length == 0)
+            {
+                return null;
+            }
+            return line.Replace(" ", "");
+        }
+
+        private TestVector ReadTestVector(StreamReader r, string header)
+        {
+            string[] parts = SplitAround(header, TestVector.SAMPLE_OF);
+
+            string algorithm = parts[0];
+            int bits = ParseDecimal(StripFromChar(parts[1], '-'));
+
+            SkipUntil(r, TestVector.MSG_HEADER);
+            string messageBlock = ReadBlock(r);
+            if (messageBlock.Length != bits)
+            {
+                throw new InvalidOperationException("Test vector length mismatch");
+            }
+            byte[] message = DecodeBinary(messageBlock);
+
+            SkipUntil(r, TestVector.OUTPUT_HEADER);
+            byte[] output = Hex.Decode(ReadBlock(r));
+
+            return new TestVector(algorithm, bits, message, output);
+        }
+
+        private string ReadLine(StreamReader r)
+        {
+            string line = r.ReadLine();
+            return line == null ? null : StripFromChar(line, '#').Trim();
+        }
+
+        private string RequireLine(StreamReader r)
+        {
+            string line = ReadLine(r);
+            if (line == null)
+            {
+                throw new EndOfStreamException();
+            }
+            return line;
+        }
+
+        private string Reverse(string s)
+        {
+            char[] cs = s.ToCharArray();
+            Array.Reverse(cs);
+            return new string(cs);
+        }
+
+        private void RunTestVector(TestVector v)
+        {
+            int bits = v.Bits;
+            int partialBits = bits % 8;
+
+            byte[] expected = v.Output;
+
+            //Console.WriteLine(v.Algorithm + " " + bits + "-bit");
+            //Console.WriteLine(Hex.ToHexString(v.Message).ToUpper());
+            //Console.WriteLine(Hex.ToHexString(expected).ToUpper());
+
+            int outLen = expected.Length;
+
+            MyShakeDigest d = CreateDigest(v.Algorithm);
+            byte[] output = new byte[outLen];
+
+            byte[] m = v.Message;
+            if (partialBits == 0)
+            {
+                d.BlockUpdate(m, 0, m.Length);
+                d.DoFinal(output, 0, outLen);
+            }
+            else
+            {
+                d.BlockUpdate(m, 0, m.Length - 1);
+                d.MyDoFinal(output, 0, outLen, m[m.Length - 1], partialBits);
+            }
+
+            if (!Arrays.AreEqual(expected, output))
+            {
+                Fail(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
+                //Console.Error.WriteLine(v.Algorithm + " " + v.Bits + "-bit test vector hash mismatch");
+                //Console.Error.WriteLine(Hex.ToHexString(output).ToUpper());
+            }
+        }
+
+        private void SkipUntil(StreamReader r, string header)
+        {
+            string line;
+            do
+            {
+                line = RequireLine(r);
+            }
+            while (line.Length == 0);
+            if (!line.Equals(header))
+            {
+                throw new IOException("Expected: " + header);
+            }
+        }
+
+        private string[] SplitAround(string s, string separator)
+        {
+            int i = s.IndexOf(separator);
+            if (i < 0)
+                throw new InvalidOperationException();
+            return new string[] { s.Substring(0, i), s.Substring(i + separator.Length) };
+        }
+
+        private string StripFromChar(string s, char c)
+        {
+            int i = s.IndexOf(c);
+            if (i >= 0)
+            {
+                s = s.Substring(0, i);
+            }
+            return s;
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new ShakeDigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        internal class TestVector
+        {
+            internal static string SAMPLE_OF = " sample of ";
+            internal static string MSG_HEADER = "Msg as bit string";
+            internal static string OUTPUT_HEADER = "Output val is";
+
+            private readonly string algorithm;
+            private readonly int bits;
+            private readonly byte[] message;
+            private readonly byte[] output;
+
+            internal TestVector(string algorithm, int bits, byte[] message, byte[] output)
+            {
+                this.algorithm = algorithm;
+                this.bits = bits;
+                this.message = message;
+                this.output = output;
+            }
+
+            public string Algorithm
+            {
+                get { return algorithm; }
+            }
+
+            public int Bits
+            {
+                get { return bits; }
+            }
+
+            public byte[] Message
+            {
+                get { return message; }
+            }
+
+            public byte[] Output
+            {
+                get { return output; }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/test/ECPointTest.cs b/crypto/test/src/math/ec/test/ECPointTest.cs
index 2a62b7740..3c10170f7 100644
--- a/crypto/test/src/math/ec/test/ECPointTest.cs
+++ b/crypto/test/src/math/ec/test/ECPointTest.cs
@@ -487,23 +487,62 @@ namespace Org.BouncyCastle.Math.EC.Tests
 
             foreach (string name in uniqNames)
             {
-                X9ECParameters x9ECParameters = ECNamedCurveTable.GetByName(name);
-                if (x9ECParameters != null)
+                X9ECParameters x9A = ECNamedCurveTable.GetByName(name);
+                X9ECParameters x9B = CustomNamedCurves.GetByName(name);
+
+                if (x9A != null && x9B != null)
+                {
+                    Assert.AreEqual(x9A.Curve.Field, x9B.Curve.Field);
+                    Assert.AreEqual(x9A.Curve.A.ToBigInteger(), x9B.Curve.A.ToBigInteger());
+                    Assert.AreEqual(x9A.Curve.B.ToBigInteger(), x9B.Curve.B.ToBigInteger());
+                    AssertOptionalValuesAgree(x9A.Curve.Cofactor, x9B.Curve.Cofactor);
+                    AssertOptionalValuesAgree(x9A.Curve.Order, x9B.Curve.Order);
+
+                    AssertPointsEqual("Custom curve base-point inconsistency", x9A.G, x9B.G);
+
+                    Assert.AreEqual(x9A.H, x9B.H);
+                    Assert.AreEqual(x9A.N, x9B.N);
+                    AssertOptionalValuesAgree(x9A.GetSeed(), x9B.GetSeed());
+
+                    BigInteger k = new BigInteger(x9A.N.BitLength, secRand);
+                    ECPoint pA = x9A.G.Multiply(k);
+                    ECPoint pB = x9B.G.Multiply(k);
+                    AssertPointsEqual("Custom curve multiplication inconsistency", pA, pB);
+                }
+
+                if (x9A != null)
                 {
-                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9ECParameters);
+                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9A);
                 }
 
-                x9ECParameters = CustomNamedCurves.GetByName(name);
-                if (x9ECParameters != null)
+                if (x9B != null)
                 {
-                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9ECParameters);
+                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9B);
                 }
             }
         }
 
         private void AssertPointsEqual(string message, ECPoint a, ECPoint b)
         {
+            // NOTE: We intentionally test points for equality in both directions
             Assert.AreEqual(a, b, message);
+            Assert.AreEqual(b, a, message);
+        }
+
+        private void AssertOptionalValuesAgree(object a, object b)
+        {
+            if (a != null && b != null)
+            {
+                Assert.AreEqual(a, b);
+            }
+        }
+
+        private void AssertOptionalValuesAgree(byte[] a, byte[] b)
+        {
+            if (a != null && b != null)
+            {
+                Assert.IsTrue(Arrays.AreEqual(a, b));
+            }
         }
     }
 }