summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorroyb <roy.basmacier@primekey.com>2022-09-28 18:12:41 -0400
committerroyb <roy.basmacier@primekey.com>2022-09-28 18:12:41 -0400
commitd9c526408daf0c379a588d0a10e72ec71b490e0e (patch)
treedc8eaaeac7d113c331f201f87ef6fe2c9cc044ae /crypto/src
parentAdded Dilithium AES support + some optimizations (diff)
downloadBouncyCastle.NET-ed25519-d9c526408daf0c379a588d0a10e72ec71b490e0e.tar.xz
Added Kyber AES support
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/CBD.cs4
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs93
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs103
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs11
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs25
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs37
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs29
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs20
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs20
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/Poly.cs31
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs8
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs166
12 files changed, 341 insertions, 206 deletions
diff --git a/crypto/src/pqc/crypto/crystals/kyber/CBD.cs b/crypto/src/pqc/crypto/crystals/kyber/CBD.cs
index be0ed7296..e87edc007 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/CBD.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/CBD.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                     {
                         short a = (short)((d >> (4 * j + 0)) & 0x3);
                         short b = (short)((d >> (4 * j + eta)) & 0x3);
-                        r.Coeffs[8 * i + j] = (short) (a - b);
+                        r.m_coeffs[8 * i + j] = (short) (a - b);
                     }
                 }
                 break;
@@ -39,7 +39,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                     {
                         short a = (short)((d >> (6 * j + 0)) & 0x7);
                         short b = (short)((d >> (6 * j + 3)) & 0x7);
-                        r.Coeffs[4 * i + j] = (short)(a - b);
+                        r.m_coeffs[4 * i + j] = (short)(a - b);
                     }
                 }
                 break;
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs
index 556803e57..bf9d5ee3c 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberEngine.cs
@@ -1,6 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
@@ -10,7 +9,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
     {
         private SecureRandom m_random;
         private KyberIndCpa m_indCpa;
-
         // Constant Parameters
         public const int N = 256;
         public const int Q = 3329;
@@ -24,6 +22,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
         public const int Eta2 = 2;
 
         public int IndCpaMsgBytes = SymBytes;
+        public Symmetric Symmetric { get; private set; }
 
 
         // Parameters
@@ -45,7 +44,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
         public int CryptoPublicKeyBytes { get; private set; }
         public int CryptoCipherTextBytes { get; private set; }
 
-        internal KyberEngine(int k)
+        public KyberEngine(int k, bool usingAes)
         {
             K = k;
             switch (k)
@@ -65,8 +64,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                 PolyCompressedBytes = 160;
                 PolyVecCompressedBytes = K * 352;
                 break;
-            default:
-                break;
             }
 
             PolyVecBytes = k * PolyBytes;
@@ -83,6 +80,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
             CryptoPublicKeyBytes = PublicKeyBytes;
             CryptoCipherTextBytes = CipherTextBytes;
 
+            if (usingAes)
+            {
+                Symmetric = new Symmetric.AesSymmetric();
+            }
+            else
+            {
+                Symmetric = new Symmetric.ShakeSymmetric();
+            }
+
             m_indCpa = new KyberIndCpa(this);
         }
 
@@ -91,83 +97,71 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
             m_random = random;
         }
 
-        internal void UpdateSeed(byte[] seed)
+        internal void GenerateKemKeyPair(out byte[] t, out byte[] rho, out byte[] s, out byte[] hpk, out byte[] nonce)
         {
-            m_random.SetSeed(seed);
-        }
+            byte[] pk, sk;
+            m_indCpa.GenerateKeyPair(out pk, out sk);
+            s = Arrays.CopyOfRange(sk, 0, IndCpaSecretKeyBytes);
+            
+            hpk = new byte[32];
+            Symmetric.Hash_h(hpk, pk, 0);
+
+            nonce = new byte[SymBytes];
+            m_random.NextBytes(nonce);
+            
+            t = Arrays.CopyOfRange(pk, 0, IndCpaPublicKeyBytes - 32);
+            rho = Arrays.CopyOfRange(pk, IndCpaPublicKeyBytes - 32, IndCpaPublicKeyBytes);
 
-        internal void GenerateKemKeyPair(byte[] pk, byte[] sk)
-        {
-            Sha3Digest Sha3Digest256 = new Sha3Digest(256);
-            m_indCpa.GenerateKeyPair(pk, sk);
-            Array.Copy(pk, 0, sk, IndCpaSecretKeyBytes, IndCpaPublicKeyBytes);
-            Sha3Digest256.BlockUpdate(pk, 0, PublicKeyBytes);
-            Sha3Digest256.DoFinal(sk, SecretKeyBytes - 2 * SymBytes);
-            m_random.NextBytes(sk, SecretKeyBytes - SymBytes, SymBytes);            
         }
 
         internal void KemEncrypt(byte[] cipherText, byte[] sharedSecret, byte[] pk)
         {
+            byte[] randBytes = new byte[SymBytes];
             byte[] buf = new byte[2 * SymBytes];
             byte[] kr = new byte[2 * SymBytes];
 
-            Sha3Digest Sha3Digest256 = new Sha3Digest(256);
-
-            m_random.NextBytes(buf, 0, SymBytes);
+            m_random.NextBytes(randBytes, 0, SymBytes);
 
-            Sha3Digest256.BlockUpdate(buf, 0, SymBytes);
-            Sha3Digest256.DoFinal(buf, 0);
+            Symmetric.Hash_h(randBytes, randBytes, 0);
+            Array.Copy(randBytes, 0, buf, 0, SymBytes);
 
-            Sha3Digest256.BlockUpdate(pk, 0, PublicKeyBytes);
-            Sha3Digest256.DoFinal(buf, SymBytes);
-
-            Sha3Digest Sha3Digest512 = new Sha3Digest(512);
-            Sha3Digest512.BlockUpdate(buf, 0, 2 * SymBytes);
-            Sha3Digest512.DoFinal(kr, 0);
+            Symmetric.Hash_h(buf, pk, SymBytes);
 
+            Symmetric.Hash_g(kr, buf);
+            
             m_indCpa.Encrypt(cipherText, Arrays.CopyOfRange(buf, 0, SymBytes), pk, Arrays.CopyOfRange(kr, SymBytes, 2 * SymBytes));
-            Sha3Digest256.BlockUpdate(cipherText, 0, CipherTextBytes);
-            Sha3Digest256.DoFinal(kr, SymBytes);
 
-            ShakeDigest ShakeDigest128 = new ShakeDigest(256);
-            
-            ShakeDigest128.BlockUpdate(kr, 0, 2 * SymBytes);
-            ShakeDigest128.DoFinal(sharedSecret, 0, SymBytes);
+            Symmetric.Hash_h(kr, cipherText, SymBytes);
+
+            Symmetric.Kdf(sharedSecret, kr);
         }
 
         internal void KemDecrypt(byte[] sharedSecret, byte[] cipherText, byte[] secretKey)
         {
+            int i;
             byte[] buf = new byte[2 * SymBytes], kr = new byte[2 * SymBytes], cmp = new byte[CipherTextBytes];
             byte[] pk = Arrays.CopyOfRange(secretKey, IndCpaSecretKeyBytes, secretKey.Length);
             m_indCpa.Decrypt(buf, cipherText, secretKey);
             Array.Copy(secretKey, SecretKeyBytes - 2 * SymBytes, buf, SymBytes, SymBytes);
 
-            Sha3Digest Sha3Digest512 = new Sha3Digest(512);
-            Sha3Digest512.BlockUpdate(buf, 0, 2 * SymBytes);
-            Sha3Digest512.DoFinal(kr, 0);
+            Symmetric.Hash_g(kr, buf);
+
 
             m_indCpa.Encrypt(cmp, Arrays.CopyOf(buf, SymBytes), pk, Arrays.CopyOfRange(kr, SymBytes, kr.Length));
 
             bool fail = !Arrays.ConstantTimeAreEqual(cipherText, cmp);
+            
+            Symmetric.Hash_h(kr, cipherText, SymBytes);
 
-            Sha3Digest Sha3Digest256 = new Sha3Digest(256);
-            Sha3Digest256.BlockUpdate(cipherText, 0, CipherTextBytes);
-            Sha3Digest256.DoFinal(kr, SymBytes);
 
             CMov(kr, Arrays.CopyOfRange(secretKey, SecretKeyBytes - SymBytes, SecretKeyBytes), SymBytes, fail);
 
-            ShakeDigest ShakeDigest256 = new ShakeDigest(256);
-            ShakeDigest256.BlockUpdate(kr, 0, 2 * SymBytes);
-            ShakeDigest256.DoFinal(sharedSecret, 0, SymBytes);
-        }
-
-        internal void RandomBytes(byte[] buf, int len)
-        {
-            m_random.NextBytes(buf, 0, len);
+            Symmetric.Kdf(sharedSecret, kr);
         }
 
         private void CMov(byte[] r, byte[] x, int len, bool b)
         {
+            int i;
             if (b)
             {
                 Array.Copy(x, 0, r, 0, len);
@@ -177,6 +171,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                 Array.Copy(r, 0, r, 0, len);
             }
         }
+        
+        internal void RandomBytes(byte[] buf, int len)
+        {
+            m_random.NextBytes(buf,0,len);
+        }
     }
 }
 
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs
index 1628ed90d..b3be4770d 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberIndCpa.cs
@@ -1,6 +1,5 @@
 using System;
 
-using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
@@ -8,37 +7,35 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
     internal class KyberIndCpa
     {
         private readonly KyberEngine m_engine;
-
-        internal KyberIndCpa(KyberEngine engine)
+        private Symmetric m_symmetric;
+        internal KyberIndCpa(KyberEngine mEngine)
         {
-            m_engine = engine;
+            m_engine = mEngine;
+            m_symmetric = mEngine.Symmetric;
         }
-
-        private int XofBlockBytes => Symmetric.Shake128Rate;
-
-        private int GenerateMatrixNBlocks => ((12 * KyberEngine.N / 8 * (1 << 12) / KyberEngine.Q + XofBlockBytes) / XofBlockBytes);
+        
+        private int GenerateMatrixNBlocks => ((12 * KyberEngine.N / 8 * (1 << 12) / KyberEngine.Q + m_symmetric.XofBlockBytes) / m_symmetric.XofBlockBytes);
 
         private void GenerateMatrix(PolyVec[] a, byte[] seed, bool transposed)
         {
             int K = m_engine.K;
-            ShakeDigest shake128 = new ShakeDigest(128);
-            byte[] buf = new byte[GenerateMatrixNBlocks * XofBlockBytes + 2];
 
+            byte[] buf = new byte[GenerateMatrixNBlocks * m_symmetric.XofBlockBytes + 2];
             for (int i = 0; i < K; i++)
             {
                 for (int j = 0; j < K; j++)
                 {
                     if (transposed)
                     {
-                        shake128 = Symmetric.Xof(seed, (byte) i, (byte) j);
+                        m_symmetric.XofAbsorb(seed, (byte) i, (byte) j);
                     }
                     else
                     {
-                        shake128 = Symmetric.Xof(seed, (byte) j, (byte) i);
+                        m_symmetric.XofAbsorb(seed, (byte) j, (byte) i);
                     }
-                    shake128.DoOutput(buf, 0, GenerateMatrixNBlocks * XofBlockBytes);
-                    int buflen = GenerateMatrixNBlocks * XofBlockBytes;
-                    int ctr = RejectionSampling(a[i].m_vec[j].Coeffs, 0, KyberEngine.N, buf, buflen);
+                    m_symmetric.XofSqueezeBlocks(buf, 0, GenerateMatrixNBlocks * m_symmetric.XofBlockBytes);
+                    int buflen = GenerateMatrixNBlocks * m_symmetric.XofBlockBytes;
+                    int ctr = RejectionSampling(a[i].m_vec[j].m_coeffs, 0, KyberEngine.N, buf, buflen);
                     while (ctr < KyberEngine.N)
                     {
                         int off = buflen % 3;
@@ -46,13 +43,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                         {
                             buf[k] = buf[buflen - off + k];
                         }
-                        shake128.DoOutput(buf, off, XofBlockBytes * 2);
-                        buflen = off + XofBlockBytes;
-                        ctr += RejectionSampling(a[i].m_vec[j].Coeffs, ctr, KyberEngine.N - ctr, buf, buflen);
+                        m_symmetric.XofSqueezeBlocks(buf, off, m_symmetric.XofBlockBytes * 2);
+                        buflen = off + m_symmetric.XofBlockBytes;
+                        ctr += RejectionSampling(a[i].m_vec[j].m_coeffs, ctr, KyberEngine.N - ctr, buf, buflen);
                     }
 
                 }
             }
+            return;
         }
 
         private int RejectionSampling(short[] r, int off, int len, byte[] buf, int buflen)
@@ -77,7 +75,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
             return ctr;
         }
 
-        internal void GenerateKeyPair(byte[] pk, byte[] sk)
+        internal void GenerateKeyPair(out byte[] pk, out byte[] sk)
         {
             int K = m_engine.K;
 
@@ -85,14 +83,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
             byte nonce = 0;
             PolyVec[] Matrix = new PolyVec[K];
             PolyVec e = new PolyVec(m_engine), pkpv = new PolyVec(m_engine), skpv = new PolyVec(m_engine);
-            Sha3Digest Sha3Digest512 = new Sha3Digest(512);
 
-            m_engine.RandomBytes(buf, KyberEngine.SymBytes);
+            byte[] d = new byte[32];
+            m_engine.RandomBytes(d, 32);
             
-            Sha3Digest512.BlockUpdate(buf, 0, KyberEngine.SymBytes);
-            Sha3Digest512.DoFinal(buf, 0);
+            m_symmetric.Hash_g(buf, d);
 
-            //Console.WriteLine(string.Format("buf = {0}", Convert.ToHexString(buf)));
             byte[] PublicSeed = Arrays.CopyOfRange(buf, 0, KyberEngine.SymBytes);
             byte[] NoiseSeed = Arrays.CopyOfRange(buf, KyberEngine.SymBytes, 2 * KyberEngine.SymBytes);
 
@@ -112,61 +108,26 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
             {
                 e.m_vec[i].GetNoiseEta1(NoiseSeed, nonce++);
             }
-
+            
             skpv.Ntt();
             e.Ntt();
-
-            //Console.WriteLine("skpv = ");
-            //for (int i = 0; i < K; i++)
-            //{
-            //    Console.Write(String.Format("{0} [", i));
-            //    foreach (short coeff in skpv.Vec[i].Coeffs)
-            //    {
-            //        Console.Write(String.Format("{0}, ", coeff));
-            //    }
-            //    Console.Write("]\n");
-            //}
-
-            //for (int i = 0; i < K; i++)
-            //{
-            //    Console.Write("[");
-            //    for (int j = 0; j < K; j++)
-            //    {
-            //        Console.Write("[");
-            //        for (int k = 0; k < KyberEngine.N; k++)
-            //        {
-            //            Console.Write(String.Format("{0:G}, ", Matrix[i].Vec[j].Coeffs[k]));
-            //        }
-            //        Console.Write("], \n");
-            //    }
-            //    Console.Write("] \n");
-            //}
-
+            
             for (int i = 0; i < K; i++)
             {
                 PolyVec.PointwiseAccountMontgomery(pkpv.m_vec[i], Matrix[i], skpv, m_engine);
                 pkpv.m_vec[i].ToMont();
             }
-
-            //Console.WriteLine("pkpv = ");
-            //for (int i = 0; i < K; i++)
-            //{
-            //    Console.Write(String.Format("{0} [", i));
-            //    foreach (short coeff in pkpv.Vec[i].Coeffs)
-            //    {
-            //        Console.Write(String.Format("{0}, ", coeff));
-            //    }
-            //    Console.Write("]\n");
-            //}
+            
             pkpv.Add(e);
             pkpv.Reduce();
 
-            PackSecretKey(sk, skpv);
-            PackPublicKey(pk, pkpv, PublicSeed);
+            PackSecretKey(out sk, skpv);
+            PackPublicKey(out pk, pkpv, PublicSeed);
         }
 
-        private void PackSecretKey(byte[] sk, PolyVec skpv)
+        private void PackSecretKey(out byte[] sk, PolyVec skpv)
         {
+            sk = new byte[m_engine.PolyVecBytes];
             skpv.ToBytes(sk);
         }
 
@@ -175,26 +136,28 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
             skpv.FromBytes(sk);
         }
 
-        private void PackPublicKey(byte[] pk, PolyVec pkpv, byte[] seed)
+        private void PackPublicKey(out byte[] pk, PolyVec pkpv, byte[] seed)
         {
+            int i;
+            pk = new byte[m_engine.IndCpaPublicKeyBytes];
             pkpv.ToBytes(pk);
             Array.Copy(seed, 0, pk, m_engine.PolyVecBytes, KyberEngine.SymBytes);
         }
 
         private void UnpackPublicKey(PolyVec pkpv, byte[] seed, byte[] pk)
         {
+            int i;
             pkpv.FromBytes(pk);
             Array.Copy(pk, m_engine.PolyVecBytes, seed, 0, KyberEngine.SymBytes);
         }
 
-        internal void Encrypt(byte[] c, byte[] m, byte[] pk, byte[] coins)
+        public void Encrypt(byte[] c, byte[] m, byte[] pk, byte[] coins)
         {
             int K = m_engine.K;
 
             byte[] seed = new byte[KyberEngine.SymBytes];
             byte nonce = 0;
-            PolyVec sp = new PolyVec(m_engine), pkpv = new PolyVec(m_engine), ep = new PolyVec(m_engine),
-                bp = new PolyVec(m_engine);
+            PolyVec sp = new PolyVec(m_engine), pkpv = new PolyVec(m_engine), ep = new PolyVec(m_engine), bp = new PolyVec(m_engine);
             PolyVec[] MatrixTransposed = new PolyVec[K];
             Poly v = new Poly(m_engine), k = new Poly(m_engine), epp = new Poly(m_engine);
 
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs
index a9f27c4ed..6dac60625 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberKEMExtractor.cs
@@ -9,6 +9,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
         private readonly KyberKeyParameters m_key;
         private readonly KyberEngine m_engine;
 
+
         public KyberKemExtractor(KyberKeyParameters privParams)
         {
             m_key = privParams;
@@ -17,13 +18,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
 
         public byte[] ExtractSecret(byte[] encapsulation)
         {
-            byte[] sessionKey = new byte[m_engine.CryptoBytes];
-            m_engine.KemDecrypt(sessionKey, encapsulation, ((KyberPrivateKeyParameters)m_key).m_privateKey);
-            byte[] rv = Arrays.CopyOfRange(sessionKey, 0, m_key.Parameters.DefaultKeySize / 8);
-            Arrays.Clear(sessionKey);
-            return rv;
+            byte[] sharedSecret = new byte[m_engine.CryptoBytes];
+            m_engine.KemDecrypt(sharedSecret, encapsulation, ((KyberPrivateKeyParameters)m_key).GetEncoded());
+            return sharedSecret;
         }
 
         public int EncapsulationLength => m_engine.CryptoCipherTextBytes;
     }
-}
+}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs
index a0c070069..394890838 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberKEMGenerator.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
         : IEncapsulatedSecretGenerator
     {
         // the source of randomness
-        private readonly SecureRandom m_random;
+        private SecureRandom m_random;
 
         public KyberKemGenerator(SecureRandom random)
         {
@@ -19,15 +19,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
 
         public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey)
         {
-            KyberPublicKeyParameters key = (KyberPublicKeyParameters)recipientKey;
+            KyberPublicKeyParameters key = (KyberPublicKeyParameters) recipientKey;
             KyberEngine engine = key.Parameters.Engine;
             engine.Init(m_random);
             byte[] cipherText = new byte[engine.CryptoCipherTextBytes];
             byte[] sessionKey = new byte[engine.CryptoBytes];
-            engine.KemEncrypt(cipherText, sessionKey, key.m_publicKey);
-            byte[] rv = Arrays.CopyOfRange(sessionKey, 0, key.Parameters.DefaultKeySize / 8);
-            Arrays.Clear(sessionKey);
-            return new SecretWithEncapsulationImpl(rv, cipherText);
+            engine.KemEncrypt(cipherText, sessionKey, key.GetEncoded());
+            return new SecretWithEncapsulationImpl(sessionKey, cipherText);
         }
 
         private sealed class SecretWithEncapsulationImpl
@@ -35,8 +33,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
         {
             private volatile bool m_hasBeenDestroyed = false;
 
-            private readonly byte[] m_sessionKey;
-            private readonly byte[] m_cipherText;
+            private byte[] m_sessionKey;
+            private byte[] m_cipherText;
 
             internal SecretWithEncapsulationImpl(byte[] sessionKey, byte[] cipher_text)
             {
@@ -68,13 +66,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                 }
             }
 
-            internal bool IsDestroyed => m_hasBeenDestroyed;
+            internal bool IsDestroyed()
+            {
+                return m_hasBeenDestroyed;
+            }
 
             private void CheckDestroyed()
             {
-                if (IsDestroyed)
+                if (IsDestroyed())
+                {
                     throw new ArgumentException("data has been destroyed");
+                }
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs
index fde26f727..442944042 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberKeyPairGenerator.cs
@@ -6,26 +6,37 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
     public class KyberKeyPairGenerator
         : IAsymmetricCipherKeyPairGenerator
     {
-        private KyberKeyGenerationParameters m_kyberParams;
-        private SecureRandom m_random;
+        private KyberParameters KyberParams;
+        
+        private SecureRandom random;
 
-        public void Init(KeyGenerationParameters param)
+        private void Initialize(
+            KeyGenerationParameters param)
         {
-            m_kyberParams = (KyberKeyGenerationParameters)param;
-            m_random = param.Random;
+            this.KyberParams = ((KyberKeyGenerationParameters)param).Parameters;;
+            this.random = param.Random; 
         }
 
-        public AsymmetricCipherKeyPair GenerateKeyPair()
+        private AsymmetricCipherKeyPair GenKeyPair()
         {
-            KyberEngine engine = m_kyberParams.Parameters.Engine;
-            engine.Init(m_random);
-            byte[] sk = new byte[engine.CryptoSecretKeyBytes];
-            byte[] pk = new byte[engine.CryptoPublicKeyBytes];
-            engine.GenerateKemKeyPair(pk, sk);
+            KyberEngine engine = KyberParams.Engine;
+            engine.Init(random);
+            byte[] s, hpk, nonce, t, rho;
+            engine.GenerateKemKeyPair(out t, out rho, out s, out hpk, out nonce);
 
-            KyberPublicKeyParameters pubKey = new KyberPublicKeyParameters(m_kyberParams.Parameters, pk);
-            KyberPrivateKeyParameters privKey = new KyberPrivateKeyParameters(m_kyberParams.Parameters, sk);
+            KyberPublicKeyParameters pubKey = new KyberPublicKeyParameters(KyberParams, t, rho);
+            KyberPrivateKeyParameters privKey = new KyberPrivateKeyParameters(KyberParams, s, hpk, nonce, t, rho);
             return new AsymmetricCipherKeyPair(pubKey, privKey);
         }
+
+        public void Init(KeyGenerationParameters param)
+        {
+            this.Initialize(param);
+        }
+
+        public AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+            return GenKeyPair();
+        }
     }
 }
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs
index ea9f90c98..f1a4ae921 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs
@@ -1,31 +1,36 @@
 using System;
-
 using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
 {
-    public sealed class KyberParameters
+    public class KyberParameters
         : ICipherParameters
     {
-        public static KyberParameters kyber512 = new KyberParameters("kyber512", 2);
-        public static KyberParameters kyber768 = new KyberParameters("kyber768", 3);
-        public static KyberParameters kyber1024 = new KyberParameters("kyber1024", 4);
 
-        private string m_name;
+        public static KyberParameters kyber512 = new KyberParameters("kyber512", 2, 128, false);
+        public static KyberParameters kyber768 = new KyberParameters("kyber768", 3, 192, false);
+        public static KyberParameters kyber1024 = new KyberParameters("kyber1024", 4, 256, false);
+        public static KyberParameters kyber512_aes = new KyberParameters("kyber512-aes", 2, 128, true);
+        public static KyberParameters kyber768_aes = new KyberParameters("kyber768-aes", 3, 192, true);
+        public static KyberParameters kyber1024_aes = new KyberParameters("kyber1024-aes", 4, 256, true);
+
+
+        private String m_name;
+        private int m_sessionKeySize;
         private KyberEngine m_engine;
 
-        public KyberParameters(string name, int k)
+        public KyberParameters(String name, int k, int sessionKeySize, bool usingAes)
         {
             m_name = name;
-            m_engine = new KyberEngine(k);
+            this.m_sessionKeySize = sessionKeySize;
+            m_engine = new KyberEngine(k, usingAes);
         }
 
-        public string Name => m_name;
+        public String Name => m_name;
 
         public int K => m_engine.K;
-
-        public int DefaultKeySize => 64 * m_engine.K;
+        public int SessionKeySize => m_sessionKeySize;
 
         internal KyberEngine Engine => m_engine;
     }
-}
+}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs
index d58a59c40..ab355be54 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs
@@ -2,20 +2,28 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
 {
-    public sealed class KyberPrivateKeyParameters
+    public class KyberPrivateKeyParameters
         : KyberKeyParameters
     {
-        internal readonly byte[] m_privateKey;
+        private readonly byte[] m_s;
+        private readonly byte[] m_hpk;
+        private readonly byte[] m_nonce;
+        private readonly byte[] m_t;
+        private readonly byte[] m_rho;
 
-        public KyberPrivateKeyParameters(KyberParameters parameters, byte[] privateKey)
+        public KyberPrivateKeyParameters(KyberParameters parameters, byte[] s, byte[] hpk, byte[] nonce, byte[] t, byte[] rho)
             : base(true, parameters)
         {
-            m_privateKey = Arrays.Clone(privateKey);
+            m_s = Arrays.Clone(s);
+            m_hpk = Arrays.Clone(hpk);
+            m_nonce = Arrays.Clone(nonce);
+            m_t = Arrays.Clone(t);
+            m_rho = Arrays.Clone(rho);
         }
 
         public byte[] GetEncoded()
         {
-            return Arrays.Clone(m_privateKey);
+            return Arrays.ConcatenateAll(m_s, m_t, m_rho, m_hpk, m_nonce);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs
index 02e467530..56d80f535 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs
@@ -5,17 +5,27 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
     public sealed class KyberPublicKeyParameters
         : KyberKeyParameters
     {
-        internal readonly byte[] m_publicKey;
+        private readonly byte[] m_t;
+        private readonly byte[] m_rho;
 
-        public KyberPublicKeyParameters(KyberParameters parameters, byte[] publicKey)
+        public byte[] GetEncoded()
+        {
+            return Arrays.Concatenate(m_t, m_rho);
+        }
+
+        public KyberPublicKeyParameters(KyberParameters parameters, byte[] encoding)
             : base(false, parameters)
         {
-            m_publicKey = Arrays.Clone(publicKey);
+            m_t = Arrays.CopyOfRange(encoding, 0, encoding.Length - KyberEngine.SymBytes);
+            m_rho = Arrays.CopyOfRange(encoding, encoding.Length - KyberEngine.SymBytes, encoding.Length);
         }
 
-        public byte[] GetEncoded()
+        public KyberPublicKeyParameters(KyberParameters parameters, byte[] t, byte[] rho)
+            : base(false, parameters)
         {
-            return Arrays.Clone(m_publicKey);
+            m_t = Arrays.Clone(t);
+            m_rho = Arrays.Clone(rho);
         }
     }
 }
+    
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/crystals/kyber/Poly.cs b/crypto/src/pqc/crypto/crystals/kyber/Poly.cs
index fc2f7ec70..db996f41a 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/Poly.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/Poly.cs
@@ -1,31 +1,32 @@
-using System;
+
+using System;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
 {
     internal class Poly
     {
-        private short[] m_coeffs = new short[KyberEngine.N];
-
         private KyberEngine m_engine;
-
-        internal Poly(KyberEngine engine)
+        public short[] m_coeffs = new short[KyberEngine.N];
+        private Symmetric m_symmetric;
+        public Poly(KyberEngine mEngine)
         {
-            m_engine = engine;
+            m_engine = mEngine;
+            m_symmetric = mEngine.Symmetric;
         }
-
+        
         internal short[] Coeffs => m_coeffs;
 
         internal void GetNoiseEta1(byte[] seed, byte nonce)
         {
             byte[] buf = new byte[m_engine.Eta1 * KyberEngine.N / 4];
-            Symmetric.Prf(buf, buf.Length, seed, nonce);
+            m_symmetric.Prf(buf, seed, nonce);
             Cbd.Eta(this, buf, m_engine.Eta1);
         }
 
         internal void GetNoiseEta2(byte[] seed, byte nonce)
         {
             byte[] buf = new byte[KyberEngine.Eta2 * KyberEngine.N / 4];
-            Symmetric.Prf(buf, buf.Length, seed, nonce);
+            m_symmetric.Prf(buf, seed, nonce);
             Cbd.Eta(this, buf, KyberEngine.Eta2);
         }
 
@@ -76,7 +77,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
         {
             for (int i = 0; i < KyberEngine.N; i++)
             {
-                Coeffs[i] = (short)(a.Coeffs[i] - Coeffs[i]);
+                Coeffs[i] = (short) (a.Coeffs[i] - Coeffs[i]);
             }
         }
 
@@ -90,12 +91,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
 
         internal void CompressPoly(byte[] r, int off)
         {
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-            Span<byte> t = stackalloc byte[8];
-#else
             byte[] t = new byte[8];
-#endif
-
             int count = 0;
             CondSubQ();
 
@@ -186,7 +182,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                 throw new ArgumentException("PolyCompressedBytes is neither 128 or 160!");
             }
         }
-
+        
         internal void ToBytes(byte[] r, int off)
         {
             CondSubQ();
@@ -228,8 +224,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
         internal void FromMsg(byte[] m)
         {
             if (m.Length != KyberEngine.N / 8)
+            {
                 throw new ArgumentException("KYBER_INDCPA_MSGBYTES must be equal to KYBER_N/8 bytes!");
-
+            }
             for (int i = 0; i < KyberEngine.N / 8; i++)
             {
                 for (int j = 0; j < 8; j++)
diff --git a/crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs b/crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs
index 5c92441b9..325b35e95 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/PolyVec.cs
@@ -82,7 +82,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                             t[k] = (short)
                                 (
                                     (
-                                        (((uint) m_vec[i].Coeffs[4 * j + k] << 10)
+                                        (((uint) m_vec[i].m_coeffs[4 * j + k] << 10)
                                             + (KyberEngine.Q / 2))
                                             / KyberEngine.Q)
                                         & 0x3ff);
@@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                             t[k] = (short)
                                 (
                                     (
-                                        (((uint) m_vec[i].Coeffs[8 * j + k] << 11)
+                                        (((uint) m_vec[i].m_coeffs[8 * j + k] << 11)
                                             + (KyberEngine.Q / 2))
                                             / KyberEngine.Q)
                                         & 0x7ff);
@@ -162,7 +162,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                         count += 5;
                         for (int k = 0; k < 4; k++)
                         {
-                            m_vec[i].Coeffs[4 * j + k] = (short)(((t[k] & 0x3FF) * KyberEngine.Q + 512) >> 10);
+                            m_vec[i].m_coeffs[4 * j + k] = (short)(((t[k] & 0x3FF) * KyberEngine.Q + 512) >> 10);
                         }
                     }
                 }
@@ -190,7 +190,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
                         count += 11;
                         for (int k = 0; k < 8; k++)
                         {
-                            m_vec[i].Coeffs[8 * j + k] = (short)(((t[k] & 0x7FF) * KyberEngine.Q + 1024) >> 11);
+                            m_vec[i].m_coeffs[8 * j + k] = (short)(((t[k] & 0x7FF) * KyberEngine.Q + 1024) >> 11);
                         }
                     }
                 }
diff --git a/crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs b/crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs
index d02990635..1ceb76b98 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/Symmetric.cs
@@ -1,26 +1,166 @@
 using Org.BouncyCastle.Crypto.Digests;
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
 {
-    internal static class Symmetric
+    public abstract class Symmetric
     {
-        internal const int Shake128Rate = 168;
+        internal readonly int XofBlockBytes;
+        
+        internal abstract void Hash_h(byte[] output, byte[] input, int outOffset);
 
-        internal static void Prf(byte[] outbuf, int outlen, byte[] key, byte nonce)
+        internal abstract void Hash_g(byte[] output, byte[] input);
+
+        internal abstract void XofAbsorb(byte[] seed, byte x, byte y);
+
+        internal abstract void XofSqueezeBlocks(byte[] output, int outOffset, int outLen);
+
+        internal abstract void Prf(byte[] output, byte[] key, byte nonce);
+
+        internal abstract void Kdf(byte[] output, byte[] input);
+
+        Symmetric(int xofBlockBytes)
+        {
+            this.XofBlockBytes = xofBlockBytes;
+        }
+
+        internal class ShakeSymmetric
+            : Symmetric
         {
-            ShakeDigest shake256 = new ShakeDigest(256);
-            shake256.BlockUpdate(key, 0, KyberEngine.SymBytes);
-            shake256.Update(nonce);
-            shake256.DoFinal(outbuf, 0, outlen);
+            private ShakeDigest xof;
+            private Sha3Digest sha3Digest512;
+            private Sha3Digest sha3Digest256;
+            private ShakeDigest shakeDigest;
+
+            
+            internal ShakeSymmetric()
+                : base(164)
+            {
+                xof = new ShakeDigest(128);
+                shakeDigest = new ShakeDigest(256);
+                sha3Digest256 = new Sha3Digest(256);
+                sha3Digest512 = new Sha3Digest(512);
+            }
+
+            internal override void Hash_h(byte[] output, byte[] input, int outOffset)
+            {
+                sha3Digest256.BlockUpdate(input, 0, input.Length);
+                sha3Digest256.DoFinal(output, outOffset);
+            }
+
+            internal override void Hash_g(byte[] output, byte[] input)
+            {
+                sha3Digest512.BlockUpdate(input, 0, input.Length);
+                sha3Digest512.DoFinal(output, 0);
+            }
+
+            internal override void XofAbsorb(byte[] seed, byte x, byte y)
+            {
+                xof.Reset();
+                byte[] buf = new byte[seed.Length + 2];
+                Array.Copy(seed, 0, buf, 0, seed.Length);
+                buf[seed.Length] = x;
+                buf[seed.Length + 1] = y;
+                xof.BlockUpdate(buf, 0, seed.Length + 2);
+            }
+
+            internal override void XofSqueezeBlocks(byte[] output, int outOffset, int outLen)
+            {
+                xof.DoOutput(output, outOffset, outLen);
+            }
+
+            internal override void Prf(byte[] output, byte[] seed, byte nonce)
+            {
+                byte[] extSeed = new byte[seed.Length + 1];
+                Array.Copy(seed, 0, extSeed, 0, seed.Length);
+                extSeed[seed.Length] = nonce;
+                shakeDigest.BlockUpdate(extSeed, 0, extSeed.Length);
+                shakeDigest.DoFinal(output, 0, output.Length);
+            }
+
+            internal override void Kdf(byte[] output, byte[] input)
+            {
+                shakeDigest.BlockUpdate(input, 0, input.Length);
+                shakeDigest.DoFinal(output, 0, output.Length);
+            }
         }
 
-        internal static ShakeDigest Xof(byte[] seed, byte a, byte b)
+        internal class AesSymmetric
+            : Symmetric
         {
-            ShakeDigest shake128 = new ShakeDigest(128);
-            shake128.BlockUpdate(seed, 0, seed.Length);
-            shake128.Update(a);
-            shake128.Update(b);
-            return shake128;
+            private Sha256Digest sha256Digest;
+            private Sha512Digest sha512Digest;
+            private SicBlockCipher cipher;
+
+            internal AesSymmetric()
+                : base(64)
+            {
+                this.sha256Digest = new Sha256Digest();
+                this.sha512Digest = new Sha512Digest();
+                this.cipher = new SicBlockCipher(new AesEngine());
+            }
+            private void DoDigest(IDigest digest, byte[] output, byte[] input, int outOffset)
+            {
+                digest.BlockUpdate(input, 0, input.Length);
+                digest.DoFinal(output, outOffset);
+            }
+            
+            private void Aes128(byte[] output, int offset, int size)
+            {
+                byte[] buf = new byte[size + offset];   // TODO: there might be a more efficient way of doing this...
+                for (int i = 0; i < size; i += 16)
+                {
+                    cipher.ProcessBlock(buf, i + offset, output, i + offset);
+                }
+            }
+            
+            internal override void Hash_h(byte[] output, byte[] input, int outOffset)
+            {
+                DoDigest(sha256Digest, output, input, outOffset);
+            }
+
+            internal override void Hash_g(byte[] output, byte[] input)
+            {
+                DoDigest(sha512Digest, output, input, 0);
+            }
+
+            internal override void XofAbsorb(byte[] key, byte x, byte y)
+            {
+                byte[] expnonce = new byte[12];
+                expnonce[0] = x;
+                expnonce[1] = y;
+
+                ParametersWithIV kp = new ParametersWithIV(new KeyParameter(Arrays.CopyOfRange(key, 0, 32)), expnonce);
+                cipher.Init(true, kp);
+            }
+
+            internal override void XofSqueezeBlocks(byte[] output, int outOffset, int outLen)
+            {
+                Aes128(output, outOffset, outLen);
+            }
+
+            internal override void Prf(byte[] output, byte[] key, byte nonce)
+            {
+                byte[] expnonce = new byte[12];
+                expnonce[0] = nonce;
+
+                ParametersWithIV kp = new ParametersWithIV(new KeyParameter(Arrays.CopyOfRange(key, 0, 32)), expnonce);
+                cipher.Init(true, kp);
+                Aes128(output, 0, output.Length);
+            }
+
+            internal override void Kdf(byte[] output, byte[] input)
+            {
+                byte[] buf = new byte[32];
+                DoDigest(sha256Digest, buf, input, 0);
+                Array.Copy(buf, 0, output, 0, output.Length);            
+            }
         }
+
     }
 }