summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-05-01 17:50:05 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-05-01 17:50:05 +0700
commitd5116b38e5b8a0425d31e5fe711866515bc91af6 (patch)
tree19d43d38824512db369b739dcab78f71304c221a
parentPQC test cleanup (diff)
downloadBouncyCastle.NET-ed25519-d5116b38e5b8a0425d31e5fe711866515bc91af6.tar.xz
Update Pqc.Crypto.Crystals from bc-java
- add PqcOtherInfoGenerator and supporting code
-rw-r--r--crypto/src/asn1/bc/BCObjectIdentifiers.cs12
-rw-r--r--crypto/src/crypto/util/DerOtherInfo.cs90
-rw-r--r--crypto/src/crypto/util/DerUtilities.cs21
-rw-r--r--crypto/src/pqc/asn1/CmcePrivateKey.cs15
-rw-r--r--crypto/src/pqc/asn1/KyberPrivateKey.cs115
-rw-r--r--crypto/src/pqc/crypto/IKemParameters.cs9
-rw-r--r--crypto/src/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.cs64
-rw-r--r--crypto/src/pqc/crypto/crystals/dilithium/DilithiumPublicKeyParameters.cs26
-rw-r--r--crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs7
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs2
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs28
-rw-r--r--crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs20
-rw-r--r--crypto/src/pqc/crypto/ntru/NtruParameters.cs2
-rw-r--r--crypto/src/pqc/crypto/utils/PqcOtherInfoGenerator.cs203
-rw-r--r--crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs62
-rw-r--r--crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs18
-rw-r--r--crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs4
-rw-r--r--crypto/test/src/pqc/crypto/test/CrystalsDilithiumTest.cs29
-rw-r--r--crypto/test/src/pqc/crypto/test/CrystalsKyberTest.cs128
-rw-r--r--crypto/test/src/pqc/crypto/test/FalconTest.cs19
20 files changed, 707 insertions, 167 deletions
diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
index face6f8d3..675350ccf 100644
--- a/crypto/src/asn1/bc/BCObjectIdentifiers.cs
+++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -232,12 +232,12 @@ namespace Org.BouncyCastle.Asn1.BC
          */
         public static readonly DerObjectIdentifier pqc_kem_kyber = bc_kem.Branch("6");
 
-        public static readonly DerObjectIdentifier kyber512 = new DerObjectIdentifier("1.3.6.1.4.1.2.267.8.2.2"); // pqc_kem_kyber.Branch("1");
-        public static readonly DerObjectIdentifier kyber768 = new DerObjectIdentifier("1.3.6.1.4.1.2.267.8.3.3"); // pqc_kem_kyber.Branch("2");
-        public static readonly DerObjectIdentifier kyber1024 = new DerObjectIdentifier("1.3.6.1.4.1.2.267.8.4.4"); // pqc_kem_kyber.Branch("3");
-        public static readonly DerObjectIdentifier kyber512_aes = new DerObjectIdentifier("1.3.6.1.4.1.2.267.10.2.2"); // pqc_kem_kyber.Branch("4");
-        public static readonly DerObjectIdentifier kyber768_aes = new DerObjectIdentifier("1.3.6.1.4.1.2.267.10.3.3"); // pqc_kem_kyber.Branch("5");
-        public static readonly DerObjectIdentifier kyber1024_aes = new DerObjectIdentifier("1.3.6.1.4.1.2.267.10.4.4"); // pqc_kem_kyber.Branch("6");
+        public static readonly DerObjectIdentifier kyber512 = pqc_kem_kyber.Branch("1");
+        public static readonly DerObjectIdentifier kyber768 = pqc_kem_kyber.Branch("2");
+        public static readonly DerObjectIdentifier kyber1024 = pqc_kem_kyber.Branch("3");
+        public static readonly DerObjectIdentifier kyber512_aes = pqc_kem_kyber.Branch("4");
+        public static readonly DerObjectIdentifier kyber768_aes = pqc_kem_kyber.Branch("5");
+        public static readonly DerObjectIdentifier kyber1024_aes = pqc_kem_kyber.Branch("6");
 
         /**
          * BIKE
diff --git a/crypto/src/crypto/util/DerOtherInfo.cs b/crypto/src/crypto/util/DerOtherInfo.cs
new file mode 100644
index 000000000..158e5aca0
--- /dev/null
+++ b/crypto/src/crypto/util/DerOtherInfo.cs
@@ -0,0 +1,90 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Crypto.Utilities
+{
+    /**
+     * Builder and holder class for preparing SP 800-56A compliant OtherInfo. The data is ultimately encoded as a DER SEQUENCE.
+     * Empty octet strings are used to represent nulls in compulsory fields.
+     */
+    public sealed class DerOtherInfo
+    {
+        /**
+         * Builder to create OtherInfo
+         */
+        public sealed class Builder
+        {
+            private readonly AlgorithmIdentifier m_algorithmID;
+            private readonly Asn1OctetString m_partyUInfo;
+            private readonly Asn1OctetString m_partyVInfo;
+
+            private Asn1TaggedObject m_suppPubInfo;
+            private Asn1TaggedObject m_suppPrivInfo;
+
+            /**
+             * Create a basic builder with just the compulsory fields.
+             *
+             * @param algorithmID the algorithm associated with this invocation of the KDF.
+             * @param partyUInfo  sender party info.
+             * @param partyVInfo  receiver party info.
+             */
+            public Builder(AlgorithmIdentifier algorithmID, byte[] partyUInfo, byte[] partyVInfo)
+            {
+                m_algorithmID = algorithmID;
+                m_partyUInfo = DerUtilities.GetOctetString(partyUInfo);
+                m_partyVInfo = DerUtilities.GetOctetString(partyVInfo);
+            }
+
+            /**
+             * Add optional supplementary public info (DER tagged, implicit, 0).
+             *
+             * @param suppPubInfo supplementary public info.
+             * @return  the current builder instance.
+             */
+            public Builder WithSuppPubInfo(byte[] suppPubInfo)
+            {
+                m_suppPubInfo = new DerTaggedObject(false, 0, DerUtilities.GetOctetString(suppPubInfo));
+                return this;
+            }
+
+            /**
+             * Add optional supplementary private info (DER tagged, implicit, 1).
+             *
+             * @param suppPrivInfo supplementary private info.
+             * @return the current builder instance.
+             */
+            public Builder WithSuppPrivInfo(byte[] suppPrivInfo)
+            {
+                m_suppPrivInfo = new DerTaggedObject(false, 1, DerUtilities.GetOctetString(suppPrivInfo));
+                return this;
+            }
+
+            /**
+             * Build the KTSOtherInfo.
+             *
+             * @return an KTSOtherInfo containing the data.
+             */
+            public DerOtherInfo Build()
+            {
+                Asn1EncodableVector v = new Asn1EncodableVector(5);
+
+                v.Add(m_algorithmID);
+                v.Add(m_partyUInfo);
+                v.Add(m_partyVInfo);
+                v.AddOptional(m_suppPubInfo);
+                v.AddOptional(m_suppPrivInfo);
+
+                return new DerOtherInfo(new DerSequence(v));
+            }
+        }
+
+        private readonly DerSequence m_sequence;
+
+        private DerOtherInfo(DerSequence sequence)
+        {
+            m_sequence = sequence;
+        }
+
+        public byte[] GetEncoded() => m_sequence.GetEncoded();
+    }
+}
diff --git a/crypto/src/crypto/util/DerUtilities.cs b/crypto/src/crypto/util/DerUtilities.cs
new file mode 100644
index 000000000..9334e644a
--- /dev/null
+++ b/crypto/src/crypto/util/DerUtilities.cs
@@ -0,0 +1,21 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Crypto.Utilities
+{
+    internal class DerUtilities
+    {
+        internal static Asn1OctetString GetOctetString(byte[] data)
+        {
+            byte[] contents = data == null ? Array.Empty<byte>() : (byte[])data.Clone();
+
+            return new DerOctetString(contents);
+        }
+
+        internal static byte[] ToByteArray(Asn1Object asn1Object)
+        {
+            return asn1Object.GetEncoded();
+        }
+    }
+}
diff --git a/crypto/src/pqc/asn1/CmcePrivateKey.cs b/crypto/src/pqc/asn1/CmcePrivateKey.cs
index 042325d1d..44b52ca56 100644
--- a/crypto/src/pqc/asn1/CmcePrivateKey.cs
+++ b/crypto/src/pqc/asn1/CmcePrivateKey.cs
@@ -42,11 +42,10 @@ namespace Org.BouncyCastle.Pqc.Asn1
         
         public CmcePrivateKey(int version, byte[] delta, byte[] c, byte[] g, byte[] alpha, byte[] s, CmcePublicKey pubKey = null)
         {
-            this.version = version;
             if (version != 0)
-            {
-                 throw new Exception("unrecognized version");
-            }
+                throw new Exception("unrecognized version");
+
+            this.version = version;
             this.delta = Arrays.Clone(delta);
             this.c = Arrays.Clone(c);
             this.g = Arrays.Clone(g);
@@ -57,11 +56,10 @@ namespace Org.BouncyCastle.Pqc.Asn1
 
         private CmcePrivateKey(Asn1Sequence seq)
         {
-            version = DerInteger.GetInstance(seq[0]).Value.IntValue;
+            version = DerInteger.GetInstance(seq[0]).IntValueExact;
             if (version != 0)
-            {
                  throw new Exception("unrecognized version");
-            }
+
             delta = Arrays.Clone(Asn1OctetString.GetInstance(seq[1]).GetOctets());
 
             c = Arrays.Clone(Asn1OctetString.GetInstance(seq[2]).GetOctets());
@@ -72,8 +70,7 @@ namespace Org.BouncyCastle.Pqc.Asn1
 
             s = Arrays.Clone(Asn1OctetString.GetInstance(seq[5]).GetOctets());
 
-            // todo optional publickey
-            if(seq.Count == 7)
+            if (seq.Count == 7)
             {
                 publicKey = CmcePublicKey.GetInstance(seq[6]);
             }
diff --git a/crypto/src/pqc/asn1/KyberPrivateKey.cs b/crypto/src/pqc/asn1/KyberPrivateKey.cs
new file mode 100644
index 000000000..ee71e4f97
--- /dev/null
+++ b/crypto/src/pqc/asn1/KyberPrivateKey.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Asn1
+{
+    /**
+     *    Crystal Kyber Private Key Format.
+     *    See https://www.ietf.org/archive/id/draft-uni-qsckeys-kyber-00.html for details.
+     *    <pre>
+     *        KyberPrivateKey ::= SEQUENCE {
+     *        version     INTEGER {v0(0)}   -- version (round 3)
+     *        s           OCTET STRING,     -- EMPTY
+     *        hpk         OCTET STRING      -- EMPTY
+     *        nonce       OCTET STRING,     -- d
+     *        publicKey   [0] IMPLICIT KyberPublicKey OPTIONAL,
+     *                                      -- see next section
+     *        }
+     *    </pre>
+     */
+    public sealed class KyberPrivateKey
+        : Asn1Encodable
+    {
+        public static KyberPrivateKey GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is KyberPrivateKey kyberPublicKey)
+                return kyberPublicKey;
+            return new KyberPrivateKey(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static KyberPrivateKey GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private int version;
+        private byte[] s;
+#pragma warning disable CS0618 // Type or member is obsolete
+        private KyberPublicKey publicKey;
+#pragma warning restore CS0618 // Type or member is obsolete
+        private byte[] hpk;
+        private byte[] nonce;
+
+#pragma warning disable CS0618 // Type or member is obsolete
+        public KyberPrivateKey(int version, byte[] s, byte[] hpk, byte[] nonce, KyberPublicKey publicKey)
+        {
+            this.version = version;
+            this.s = s;
+            this.publicKey = publicKey;
+            this.hpk = hpk;
+            this.nonce = nonce;
+        }
+#pragma warning restore CS0618 // Type or member is obsolete
+
+        public KyberPrivateKey(int version, byte[] s, byte[] hpk, byte[] nonce)
+            : this(version, s, hpk, nonce, null)
+        {
+        }
+
+        private KyberPrivateKey(Asn1Sequence seq)
+        {
+            version = DerInteger.GetInstance(seq[0]).IntValueExact;
+            if (version != 0)
+                throw new ArgumentException("unrecognized version");
+
+            s = Arrays.Clone(Asn1OctetString.GetInstance(seq[1]).GetOctets());
+
+            int skipPubKey = 1;
+            if (seq.Count == 5)
+            {
+                skipPubKey = 0;
+#pragma warning disable CS0618 // Type or member is obsolete
+                publicKey = KyberPublicKey.GetInstance(seq[2]);
+#pragma warning restore CS0618 // Type or member is obsolete
+            }
+
+            hpk = Arrays.Clone(Asn1OctetString.GetInstance(seq[3 - skipPubKey]).GetOctets());
+
+            nonce = Arrays.Clone(Asn1OctetString.GetInstance(seq[4 - skipPubKey]).GetOctets());
+        }
+
+        public int Version => version;
+
+        public byte[] GetS() => Arrays.Clone(s);
+
+#pragma warning disable CS0618 // Type or member is obsolete
+        public KyberPublicKey PublicKey => publicKey;
+#pragma warning restore CS0618 // Type or member is obsolete
+
+        public byte[] GetHpk() => Arrays.Clone(hpk);
+
+        public byte[] GetNonce() => Arrays.Clone(nonce);
+
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(5);
+
+            v.Add(new DerInteger(version));
+            v.Add(new DerOctetString(s));
+            if (publicKey != null)
+            {
+#pragma warning disable CS0618 // Type or member is obsolete
+                v.Add(new KyberPublicKey(publicKey.T, publicKey.Rho));
+#pragma warning restore CS0618 // Type or member is obsolete
+            }
+            v.Add(new DerOctetString(hpk));
+            v.Add(new DerOctetString(nonce));
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/IKemParameters.cs b/crypto/src/pqc/crypto/IKemParameters.cs
new file mode 100644
index 000000000..9852946ba
--- /dev/null
+++ b/crypto/src/pqc/crypto/IKemParameters.cs
@@ -0,0 +1,9 @@
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Pqc.Crypto
+{
+    public interface IKemParameters
+        : ICipherParameters
+    {
+    }
+}
diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.cs
index b5f3c2a32..66a518c93 100644
--- a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.cs
@@ -5,45 +5,47 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium
     public sealed class DilithiumPrivateKeyParameters
         : DilithiumKeyParameters
     {
-        internal byte[] rho;
-        internal byte[] k;
-        internal byte[] tr;
-        internal byte[] s1;
-        internal byte[] s2;
-        internal byte[] t0;
-        
-        private byte[] t1;
-
-        public DilithiumPrivateKeyParameters(DilithiumParameters parameters,  byte[] rho, byte[] K, byte[] tr, byte[] s1, byte[] s2, byte[] t0, byte[] t1)
+        internal byte[] m_rho;
+        internal byte[] m_k;
+        internal byte[] m_tr;
+        internal byte[] m_s1;
+        internal byte[] m_s2;
+        internal byte[] m_t0;
+
+        private byte[] m_t1;
+
+        public DilithiumPrivateKeyParameters(DilithiumParameters parameters,  byte[] rho, byte[] K, byte[] tr,
+            byte[] s1, byte[] s2, byte[] t0, byte[] t1)
             : base(true, parameters)
         {
-            this.rho = Arrays.Clone(rho);
-            this.k = Arrays.Clone(K);
-            this.tr = Arrays.Clone(tr);
-            this.s1 = Arrays.Clone(s1);
-            this.s2 = Arrays.Clone(s2);
-            this.t0 = Arrays.Clone(t0);
-            this.t1 = Arrays.Clone(t1);
+            m_rho = Arrays.Clone(rho);
+            m_k = Arrays.Clone(K);
+            m_tr = Arrays.Clone(tr);
+            m_s1 = Arrays.Clone(s1);
+            m_s2 = Arrays.Clone(s2);
+            m_t0 = Arrays.Clone(t0);
+            m_t1 = Arrays.Clone(t1);
         }
-        
-        public byte[] Rho => Arrays.Clone(rho);
 
-        public byte[] K => Arrays.Clone(k);
+        public byte[] GetEncoded() => Arrays.ConcatenateAll(m_rho, m_k, m_tr, m_s1, m_s2, m_t0);
 
-        public byte[] Tr => Arrays.Clone(tr);
+        public byte[] K => Arrays.Clone(m_k);
 
-        public byte[] S1 => Arrays.Clone(s1);
+        public byte[] GetPublicKey() => DilithiumPublicKeyParameters.GetEncoded(m_rho, m_t1);
 
-        public byte[] S2 => Arrays.Clone(s2);
-        
+        public DilithiumPublicKeyParameters GetPublicKeyParameters() =>
+            new DilithiumPublicKeyParameters(Parameters, m_rho, m_t1);
 
-        public byte[] T0 => Arrays.Clone(t0);
+        public byte[] Rho => Arrays.Clone(m_rho);
 
-        public byte[] T1 => t1;
+        public byte[] S1 => Arrays.Clone(m_s1);
 
-        public byte[] GetEncoded()
-        {
-            return Arrays.ConcatenateAll(rho, k, tr, s1, s2, t0);
-        }
+        public byte[] S2 => Arrays.Clone(m_s2);
+
+        public byte[] T0 => Arrays.Clone(m_t0);
+
+        public byte[] T1 => Arrays.Clone(m_t1);
+
+        public byte[] Tr => Arrays.Clone(m_tr);
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPublicKeyParameters.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPublicKeyParameters.cs
index 681435439..d47c4804e 100644
--- a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumPublicKeyParameters.cs
@@ -5,31 +5,29 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium
     public sealed class DilithiumPublicKeyParameters
         : DilithiumKeyParameters
     {
-        internal byte[] rho;
-        internal byte[] t1;
+        internal static byte[] GetEncoded(byte[] rho, byte[] t1) => Arrays.Concatenate(rho, t1);
 
-        public DilithiumPublicKeyParameters(DilithiumParameters parameters, byte[] pkEncoded)
-            : base(false, parameters)
-        {
-            this.rho = Arrays.CopyOfRange(pkEncoded, 0, DilithiumEngine.SeedBytes);
-            this.t1 = Arrays.CopyOfRange(pkEncoded, DilithiumEngine.SeedBytes, pkEncoded.Length);
-        }
+        internal readonly byte[] m_rho;
+        internal readonly byte[] m_t1;
 
         public DilithiumPublicKeyParameters(DilithiumParameters parameters, byte[] rho, byte[] t1)
             : base(false, parameters)
         {
-            this.rho = Arrays.Clone(rho);
-            this.t1 = Arrays.Clone(t1);
+            m_rho = Arrays.Clone(rho);
+            m_t1 = Arrays.Clone(t1);
         }
 
-        public byte[] GetEncoded()
+        public DilithiumPublicKeyParameters(DilithiumParameters parameters, byte[] pkEncoded)
+            : base(false, parameters)
         {
-            return Arrays.Concatenate(rho, t1);
+            m_rho = Arrays.CopyOfRange(pkEncoded, 0, DilithiumEngine.SeedBytes);
+            m_t1 = Arrays.CopyOfRange(pkEncoded, DilithiumEngine.SeedBytes, pkEncoded.Length);
         }
 
-        internal byte[] Rho => rho;
+        public byte[] GetEncoded() => GetEncoded(m_rho, m_t1);
 
-        internal byte[] T1 => t1;
+        public byte[] GetRho() => Arrays.Clone(m_rho);
 
+        public byte[] GetT1() => Arrays.Clone(m_t1);
     }
 }
diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs
index d60c24222..7611f3032 100644
--- a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs
+++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs
@@ -42,14 +42,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium
         {
             DilithiumEngine engine = privKey.Parameters.GetEngine(random);
             byte[] sig = new byte[engine.CryptoBytes];
-            engine.Sign(sig, sig.Length, message, message.Length, privKey.rho, privKey.k, privKey.tr, privKey.t0, privKey.s1, privKey.s2);
+            engine.Sign(sig, sig.Length, message, message.Length, privKey.m_rho, privKey.m_k, privKey.m_tr,
+                privKey.m_t0, privKey.m_s1, privKey.m_s2);
             return sig;
         }
 
         public bool VerifySignature(byte[] message, byte[] signature)
         {
             DilithiumEngine engine = pubKey.Parameters.GetEngine(random);
-            return engine.SignOpen(message,signature, signature.Length, pubKey.rho, pubKey.t1 );
+            return engine.SignOpen(message,signature, signature.Length, pubKey.m_rho, pubKey.m_t1);
         }
     }
-}
\ 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 5b3f71000..195831433 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberParameters.cs
@@ -3,7 +3,7 @@ using Org.BouncyCastle.Crypto;
 namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
 {
     public sealed class KyberParameters
-        : ICipherParameters
+        : IKemParameters
     {
         public static KyberParameters kyber512 = new KyberParameters("kyber512", 2, 128, false);
         public static KyberParameters kyber768 = new KyberParameters("kyber768", 3, 192, false);
diff --git a/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs b/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs
index 0fac30e47..08b4fbe86 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberPrivateKeyParameters.cs
@@ -11,7 +11,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
         private readonly byte[] m_t;
         private readonly byte[] m_rho;
 
-        public KyberPrivateKeyParameters(KyberParameters parameters, byte[] s, byte[] hpk, byte[] nonce, byte[] t, byte[] rho)
+        public KyberPrivateKeyParameters(KyberParameters parameters, byte[] s, byte[] hpk, byte[] nonce, byte[] t,
+            byte[] rho)
             : base(true, parameters)
         {
             m_s = Arrays.Clone(s);
@@ -21,16 +22,21 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
             m_rho = Arrays.Clone(rho);
         }
 
-        public byte[] GetEncoded()
-        {
-            return Arrays.ConcatenateAll(m_s, m_t, m_rho, m_hpk, m_nonce);
-        }
+        public byte[] GetEncoded() => Arrays.ConcatenateAll(m_s, m_t, m_rho, m_hpk, m_nonce);
+
+        public byte[] GetHpk() => Arrays.Clone(m_hpk);
+
+        public byte[] GetNonce() => Arrays.Clone(m_nonce);
+
+        public byte[] GetPublicKey() => KyberPublicKeyParameters.GetEncoded(m_t, m_rho);
+
+        public KyberPublicKeyParameters GetPublicKeyParameters() =>
+            new KyberPublicKeyParameters(Parameters, m_t, m_rho);
+
+        public byte[] GetRho() => Arrays.Clone(m_rho);
 
-        internal byte[] S => m_s;
-        internal byte[] Hpk => m_hpk;
-        internal byte[] Nonce => m_nonce;
-        internal byte[] T => m_t;
-        internal byte[] Rho => m_rho;
+        public byte[] GetS() => Arrays.Clone(m_s);
 
+        public byte[] GetT() => Arrays.Clone(m_t);
     }
-}
\ 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 efc582abc..dadfe8498 100644
--- a/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/crystals/kyber/KyberPublicKeyParameters.cs
@@ -5,12 +5,16 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
     public sealed class KyberPublicKeyParameters
         : KyberKeyParameters
     {
+        internal static byte[] GetEncoded(byte[] t, byte[] rho) => Arrays.Concatenate(t, rho);
+
         private readonly byte[] m_t;
         private readonly byte[] m_rho;
 
-        public byte[] GetEncoded()
+        public KyberPublicKeyParameters(KyberParameters parameters, byte[] t, byte[] rho)
+            : base(false, parameters)
         {
-            return Arrays.Concatenate(m_t, m_rho);
+            m_t = Arrays.Clone(t);
+            m_rho = Arrays.Clone(rho);
         }
 
         public KyberPublicKeyParameters(KyberParameters parameters, byte[] encoding)
@@ -20,15 +24,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber
             m_rho = Arrays.CopyOfRange(encoding, encoding.Length - KyberEngine.SymBytes, encoding.Length);
         }
 
-        public KyberPublicKeyParameters(KyberParameters parameters, byte[] t, byte[] rho)
-            : base(false, parameters)
-        {
-            m_t = Arrays.Clone(t);
-            m_rho = Arrays.Clone(rho);
-        }
+        public byte[] GetEncoded() => GetEncoded(m_t, m_rho);
+
+        public byte[] GetRho() => Arrays.Clone(m_rho);
 
-        internal byte[] T => m_t;
-        internal byte[] Rho => m_rho;
+        public byte[] GetT() => Arrays.Clone(m_t);
     }
 }
     
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/ntru/NtruParameters.cs b/crypto/src/pqc/crypto/ntru/NtruParameters.cs
index 934cc21cb..0c5158f5f 100644
--- a/crypto/src/pqc/crypto/ntru/NtruParameters.cs
+++ b/crypto/src/pqc/crypto/ntru/NtruParameters.cs
@@ -4,7 +4,7 @@ using Org.BouncyCastle.Pqc.Crypto.Ntru.ParameterSets;
 namespace Org.BouncyCastle.Pqc.Crypto.Ntru
 {
     public sealed class NtruParameters
-        : ICipherParameters
+        : IKemParameters
     {
         public static readonly NtruParameters NtruHps2048509 =
             new NtruParameters("ntruhps2048509", new NtruHps2048509());
diff --git a/crypto/src/pqc/crypto/utils/PqcOtherInfoGenerator.cs b/crypto/src/pqc/crypto/utils/PqcOtherInfoGenerator.cs
new file mode 100644
index 000000000..0d3af4a51
--- /dev/null
+++ b/crypto/src/pqc/crypto/utils/PqcOtherInfoGenerator.cs
@@ -0,0 +1,203 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
+using Org.BouncyCastle.Pqc.Crypto.Ntru;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Utilities
+{
+    /**
+     * OtherInfo Generator for which can be used for populating the SuppPrivInfo field used to provide shared
+     * secret data used with NIST SP 800-56A agreement algorithms.
+     */
+    public abstract class PqcOtherInfoGenerator
+    {
+        protected readonly DerOtherInfo.Builder m_otherInfoBuilder;
+        protected readonly SecureRandom m_random;
+
+        protected bool m_used = false;
+
+        /**
+         * Create a basic builder with just the compulsory fields.
+         *
+         * @param algorithmID the algorithm associated with this invocation of the KDF.
+         * @param partyUInfo  sender party info.
+         * @param partyVInfo  receiver party info.
+         * @param random a source of randomness.
+         */
+        internal PqcOtherInfoGenerator(AlgorithmIdentifier algorithmID, byte[] partyUInfo, byte[] partyVInfo,
+            SecureRandom random)
+        {
+            m_otherInfoBuilder = new DerOtherInfo.Builder(algorithmID, partyUInfo, partyVInfo);
+            m_random = random;
+        }
+
+        /**
+         * Party U (initiator) generation.
+         */
+        public sealed class PartyU
+            : PqcOtherInfoGenerator
+        {
+            private AsymmetricCipherKeyPair m_aKp;
+            private IEncapsulatedSecretExtractor m_encSE;
+
+            /**
+             * Create a basic builder with just the compulsory fields for the initiator.
+             *
+             * @param kemParams the key type parameters for populating the private info field.
+             * @param algorithmID the algorithm associated with this invocation of the KDF.
+             * @param partyUInfo  sender party info.
+             * @param partyVInfo  receiver party info.
+             * @param random a source of randomness.
+             */
+            public PartyU(IKemParameters kemParams, AlgorithmIdentifier algorithmID, byte[] partyUInfo,
+                byte[] partyVInfo, SecureRandom random)
+                : base(algorithmID, partyUInfo, partyVInfo, random)
+            {
+                if (kemParams is KyberParameters kyberParameters)
+                {
+                    KyberKeyPairGenerator kpg = new KyberKeyPairGenerator();
+                    kpg.Init(new KyberKeyGenerationParameters(random, kyberParameters));
+
+                    m_aKp = kpg.GenerateKeyPair();
+
+                    m_encSE = new KyberKemExtractor((KyberPrivateKeyParameters)m_aKp.Private);
+                }
+                else if (kemParams is NtruParameters ntruParameters)
+                {
+                    NtruKeyPairGenerator kpg = new NtruKeyPairGenerator();
+                    kpg.Init(new NtruKeyGenerationParameters(random, ntruParameters));
+
+                    m_aKp = kpg.GenerateKeyPair();
+
+                    m_encSE = new NtruKemExtractor((NtruPrivateKeyParameters)m_aKp.Private);
+                }
+                else
+                {
+                    throw new ArgumentException("unknown IKemParameters");
+                }
+            }
+
+            /**
+             * Add optional supplementary public info (DER tagged, implicit, 0).
+             *
+             * @param suppPubInfo supplementary public info.
+             * @return the current builder instance.
+             */
+            public PqcOtherInfoGenerator WithSuppPubInfo(byte[] suppPubInfo)
+            {
+                m_otherInfoBuilder.WithSuppPubInfo(suppPubInfo);
+                return this;
+            }
+
+            public byte[] GetSuppPrivInfoPartA()
+            {
+                return GetEncoded(m_aKp.Public);
+            }
+
+            public DerOtherInfo Generate(byte[] suppPrivInfoPartB)
+            {
+                m_otherInfoBuilder.WithSuppPrivInfo(m_encSE.ExtractSecret(suppPrivInfoPartB));
+
+                return m_otherInfoBuilder.Build();
+            }
+        }
+
+        /**
+         * Party V (responder) generation.
+         */
+        public sealed class PartyV
+            : PqcOtherInfoGenerator
+        {
+            private IEncapsulatedSecretGenerator m_encSG;
+
+            /**
+             * Create a basic builder with just the compulsory fields for the responder.
+             *
+             * @param kemParams the key type parameters for populating the private info field.
+             * @param algorithmID the algorithm associated with this invocation of the KDF.
+             * @param partyUInfo  sender party info.
+             * @param partyVInfo  receiver party info.
+             * @param random a source of randomness.
+             */
+            public PartyV(IKemParameters kemParams, AlgorithmIdentifier algorithmID, byte[] partyUInfo,
+                byte[] partyVInfo, SecureRandom random)
+                : base(algorithmID, partyUInfo, partyVInfo, random)
+            {
+                if (kemParams is KyberParameters)
+                {
+                    m_encSG = new KyberKemGenerator(random);
+                }
+                else if (kemParams is NtruParameters)
+                {
+                    m_encSG = new NtruKemGenerator(random);
+                }
+                else
+                {
+                    throw new ArgumentException("unknown IKemParameters");
+                }
+            }
+
+            /**
+             * Add optional supplementary public info (DER tagged, implicit, 0).
+             *
+             * @param suppPubInfo supplementary public info.
+             * @return the current builder instance.
+             */
+            public PqcOtherInfoGenerator WithSuppPubInfo(byte[] suppPubInfo)
+            {
+                m_otherInfoBuilder.WithSuppPubInfo(suppPubInfo);
+                return this;
+            }
+
+            public byte[] GetSuppPrivInfoPartB(byte[] suppPrivInfoPartA)
+            {
+                m_used = false;
+
+                try
+                {
+                    ISecretWithEncapsulation bEp = m_encSG.GenerateEncapsulated(GetPublicKey(suppPrivInfoPartA));
+
+                    m_otherInfoBuilder.WithSuppPrivInfo(bEp.GetSecret());
+
+                    return bEp.GetEncapsulation();
+                }
+                catch (IOException e)
+                {
+                    throw new ArgumentException("cannot decode public key", e);
+                }
+            }
+
+            public DerOtherInfo Generate()
+            {
+                if (m_used)
+                    throw new InvalidOperationException("builder already used");
+
+                m_used = true;
+
+                return m_otherInfoBuilder.Build();
+            }
+        }
+
+        private static byte[] GetEncoded(AsymmetricKeyParameter pubKey)
+        {
+            try
+            {
+                return PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey).GetEncoded();
+            }
+            catch (IOException)
+            {
+                return null;
+            }
+        }
+
+        private static AsymmetricKeyParameter GetPublicKey(byte[] enc)
+        {
+            return PqcPublicKeyFactory.CreateKey(enc);
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs b/crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs
index 01566c8b0..1deb2c8d6 100644
--- a/crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcPrivateKeyFactory.cs
@@ -134,55 +134,35 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 
                 return new HqcPrivateKeyParameters(hqcParams, keyEnc);
             }
-            if (algOID.Equals(BCObjectIdentifiers.kyber512)
-                || algOID.Equals(BCObjectIdentifiers.kyber512_aes)
-                || algOID.Equals(BCObjectIdentifiers.kyber768)
-                || algOID.Equals(BCObjectIdentifiers.kyber768_aes)
-                || algOID.Equals(BCObjectIdentifiers.kyber1024)
-                || algOID.Equals(BCObjectIdentifiers.kyber1024_aes))
+            if (algOID.On(BCObjectIdentifiers.pqc_kem_kyber))
             {
-                Asn1Sequence keyEnc = Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey());
-
-                KyberParameters spParams = PqcUtilities.KyberParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
+                KyberPrivateKey kyberKey = KyberPrivateKey.GetInstance(keyInfo.ParsePrivateKey());
+                KyberParameters kyberParams = PqcUtilities.KyberParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
 
-                int version = DerInteger.GetInstance(keyEnc[0]).Value.IntValue;
-                if (version != 0)
-                {
-                    throw new IOException("unknown private key version: " + version);
-                }
- 
-                if (keyInfo.PublicKeyData != null)
-                {
-                    Asn1Sequence pubKey = Asn1Sequence.GetInstance(keyInfo.PublicKeyData.GetOctets());
-                    return new KyberPrivateKeyParameters(spParams,
-                        Asn1OctetString.GetInstance(keyEnc[1]).GetDerEncoded(), 
-                        Asn1OctetString.GetInstance(keyEnc[2]).GetOctets(), 
-                        Asn1OctetString.GetInstance(keyEnc[3]).GetOctets(),
-                        Asn1OctetString.GetInstance(pubKey[0]).GetOctets(), // t
-                        Asn1OctetString.GetInstance(pubKey[1]).GetOctets()); // rho
-                }
-                else
+#pragma warning disable CS0618 // Type or member is obsolete
+                KyberPublicKey pubKey = kyberKey.PublicKey;
+#pragma warning restore CS0618 // Type or member is obsolete
+                if (pubKey != null)
                 {
-                    return new KyberPrivateKeyParameters(spParams,
-                        Asn1OctetString.GetInstance(keyEnc[1]).GetOctets(),
-                        Asn1OctetString.GetInstance(keyEnc[2]).GetOctets(),
-                        Asn1OctetString.GetInstance(keyEnc[3]).GetOctets(),
-                        null,
-                        null);
+                    return new KyberPrivateKeyParameters(kyberParams, kyberKey.GetS(), kyberKey.GetHpk(),
+                        kyberKey.GetNonce(), pubKey.T, pubKey.Rho);
                 }
+                return new KyberPrivateKeyParameters(kyberParams, kyberKey.GetS(), kyberKey.GetHpk(),
+                    kyberKey.GetNonce(), null, null);
             }
-            if (algOID.Equals(BCObjectIdentifiers.dilithium2)
-                || algOID.Equals(BCObjectIdentifiers.dilithium3)
-                || algOID.Equals(BCObjectIdentifiers.dilithium5)
-                || algOID.Equals(BCObjectIdentifiers.dilithium2_aes)
-                || algOID.Equals(BCObjectIdentifiers.dilithium3_aes)
-                || algOID.Equals(BCObjectIdentifiers.dilithium5_aes))
+            if (algOID.Equals(BCObjectIdentifiers.dilithium2) ||
+                algOID.Equals(BCObjectIdentifiers.dilithium3) ||
+                algOID.Equals(BCObjectIdentifiers.dilithium5) ||
+                algOID.Equals(BCObjectIdentifiers.dilithium2_aes) ||
+                algOID.Equals(BCObjectIdentifiers.dilithium3_aes) ||
+                algOID.Equals(BCObjectIdentifiers.dilithium5_aes))
             {
                 Asn1Sequence keyEnc = Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey());
 
-                DilithiumParameters spParams = PqcUtilities.DilithiumParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
+                DilithiumParameters spParams = PqcUtilities.DilithiumParamsLookup(
+                    keyInfo.PrivateKeyAlgorithm.Algorithm);
 
-                int version = DerInteger.GetInstance(keyEnc[0]).Value.IntValue;
+                int version = DerInteger.GetInstance(keyEnc[0]).IntValueExact;
                 if (version != 0)
                     throw new IOException("unknown private key version: " + version);
 
@@ -216,7 +196,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
                 FalconParameters spParams = PqcUtilities.FalconParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
                     
                 DerBitString publicKeyData = keyInfo.PublicKeyData;
-                int version = DerInteger.GetInstance(keyEnc[0]).Value.IntValue;
+                int version = DerInteger.GetInstance(keyEnc[0]).IntValueExact;
                 if (version != 1)
                     throw new IOException("unknown private key version: " + version);
 
diff --git a/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
index 6f7bed2ca..3e2832713 100644
--- a/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcPrivateKeyInfoFactory.cs
@@ -129,21 +129,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             }
             if (privateKey is KyberPrivateKeyParameters kyberPrivateKeyParameters)
             {
-                Asn1EncodableVector v = new Asn1EncodableVector(4);
-                v.Add(new DerInteger(0));
-                v.Add(new DerOctetString(kyberPrivateKeyParameters.S));
-                v.Add(new DerOctetString(kyberPrivateKeyParameters.Hpk));
-                v.Add(new DerOctetString(kyberPrivateKeyParameters.Nonce));
-
                 AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
                     PqcUtilities.KyberOidLookup(kyberPrivateKeyParameters.Parameters));
 
-                Asn1EncodableVector vPub = new Asn1EncodableVector(2);
-                vPub.Add(new DerOctetString(kyberPrivateKeyParameters.T));
-                vPub.Add(new DerOctetString(kyberPrivateKeyParameters.Rho));
+#pragma warning disable CS0618 // Type or member is obsolete
+                KyberPublicKey kyberPub = new KyberPublicKey(kyberPrivateKeyParameters.GetT(),
+                    kyberPrivateKeyParameters.GetRho());
+#pragma warning restore CS0618 // Type or member is obsolete
+                KyberPrivateKey kyberPriv = new KyberPrivateKey(0, kyberPrivateKeyParameters.GetS(),
+                    kyberPrivateKeyParameters.GetHpk(), kyberPrivateKeyParameters.GetNonce(), kyberPub);
 
-                return new PrivateKeyInfo(algorithmIdentifier, new DerSequence(v), attributes,
-                    new DerSequence(vPub).GetEncoded());
+                return new PrivateKeyInfo(algorithmIdentifier, kyberPriv, attributes);
             }
             if (privateKey is DilithiumPrivateKeyParameters dilithiumPrivateKeyParameters)
             {
diff --git a/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
index 1bdf031f6..946aca963 100644
--- a/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PqcSubjectPublicKeyInfoFactory.cs
@@ -132,8 +132,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             {
                 AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
                     PqcUtilities.DilithiumOidLookup(dilithiumPublicKeyParameters.Parameters));
-            
-                return new SubjectPublicKeyInfo(algorithmIdentifier, Arrays.Concatenate(dilithiumPublicKeyParameters.Rho, dilithiumPublicKeyParameters.T1));
+
+                return new SubjectPublicKeyInfo(algorithmIdentifier, dilithiumPublicKeyParameters.GetEncoded());
             }
             if (publicKey is BikePublicKeyParameters bikePublicKeyParameters)
             { 
diff --git a/crypto/test/src/pqc/crypto/test/CrystalsDilithiumTest.cs b/crypto/test/src/pqc/crypto/test/CrystalsDilithiumTest.cs
index 10ac3db5c..bb6da3ffb 100644
--- a/crypto/test/src/pqc/crypto/test/CrystalsDilithiumTest.cs
+++ b/crypto/test/src/pqc/crypto/test/CrystalsDilithiumTest.cs
@@ -67,13 +67,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
             DilithiumKeyGenerationParameters kparam = new DilithiumKeyGenerationParameters(random, DilithiumParameters.Dilithium2);
             DilithiumKeyPairGenerator kpg = new DilithiumKeyPairGenerator();
             kpg.Init(kparam);
-            AsymmetricCipherKeyPair ackp = kpg.GenerateKeyPair();
+            AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
 
-            AsymmetricKeyParameter pub = ackp.Public;
-            AsymmetricKeyParameter priv = ackp.Private;
+            AsymmetricKeyParameter pub = kp.Public;
+            AsymmetricKeyParameter priv = kp.Private;
 
-            AsymmetricKeyParameter pubDec = PqcPublicKeyFactory.CreateKey(PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub));
-            AsymmetricKeyParameter privDec = PqcPrivateKeyFactory.CreateKey(PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo(priv));
+            AsymmetricKeyParameter pubDec = PqcPublicKeyFactory.CreateKey(
+                PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub));
+            AsymmetricKeyParameter privDec = PqcPrivateKeyFactory.CreateKey(
+                PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo(priv));
 
             Assert.AreEqual(((DilithiumPublicKeyParameters)pub).GetEncoded(), ((DilithiumPublicKeyParameters)pubDec).GetEncoded());
             Assert.AreEqual(((DilithiumPrivateKeyParameters)priv).GetEncoded(), ((DilithiumPrivateKeyParameters)privDec).GetEncoded());
@@ -126,17 +128,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
             // Generate keys and test.
             //
             kpGen.Init(genParams);
-            AsymmetricCipherKeyPair ackp = kpGen.GenerateKeyPair();
-
-
-            DilithiumPublicKeyParameters pubParams = (DilithiumPublicKeyParameters)ackp.Public;
-            DilithiumPrivateKeyParameters privParams = (DilithiumPrivateKeyParameters)ackp.Private;
-
-            //Console.WriteLine(string.Format("{0} Expected pk       = {1}", pk.Length, Convert.ToHexString(pk)));
-            //Console.WriteLine(String.Format("{0} Actual Public key = {1}", pubParams.GetEncoded().Length, Convert.ToHexString(pubParams.GetEncoded())));
+            AsymmetricCipherKeyPair kp = kpGen.GenerateKeyPair();
 
-            pubParams = (DilithiumPublicKeyParameters)PqcPublicKeyFactory.CreateKey(PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(ackp.Public));
-            privParams = (DilithiumPrivateKeyParameters)PqcPrivateKeyFactory.CreateKey(PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo(ackp.Private));
+            DilithiumPublicKeyParameters pubParams = (DilithiumPublicKeyParameters)PqcPublicKeyFactory.CreateKey(
+                PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo((DilithiumPublicKeyParameters)kp.Public));
+            DilithiumPrivateKeyParameters privParams = (DilithiumPrivateKeyParameters)PqcPrivateKeyFactory.CreateKey(
+                PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo((DilithiumPrivateKeyParameters)kp.Private));
 
             Assert.True(Arrays.AreEqual(pk, pubParams.GetEncoded()), name + " " + count + ": public key");
             Assert.True(Arrays.AreEqual(sk, privParams.GetEncoded()), name + " " + count + ": secret key");
@@ -145,7 +142,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
             // Signature test
             //
             DilithiumSigner signer = new DilithiumSigner();
-            DilithiumPrivateKeyParameters skparam = (DilithiumPrivateKeyParameters)ackp.Private;
+            DilithiumPrivateKeyParameters skparam = (DilithiumPrivateKeyParameters)kp.Private;
 
             signer.Init(true, skparam);
             byte[] sigGenerated = signer.GenerateSignature(msg);
diff --git a/crypto/test/src/pqc/crypto/test/CrystalsKyberTest.cs b/crypto/test/src/pqc/crypto/test/CrystalsKyberTest.cs
index 44ad1cbe9..0c4a78022 100644
--- a/crypto/test/src/pqc/crypto/test/CrystalsKyberTest.cs
+++ b/crypto/test/src/pqc/crypto/test/CrystalsKyberTest.cs
@@ -3,8 +3,13 @@ using System.IO;
 
 using NUnit.Framework;
 
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
+using Org.BouncyCastle.Pqc.Crypto.Utilities;
+using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
 using Org.BouncyCastle.Utilities.Test;
@@ -38,6 +43,120 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
             "kyber1024aes.rsp",
         };
 
+        [Test]
+        public void TestKyber()
+        {
+            /*
+            count = 0
+            seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1
+            pk = D22302CBD3399FACC630991FC8F28BDB4354762541527678BCF61F65C241146C426D23B9BFAA6B7DF18C97F20C1B6125BF874B1D89475852C448215DB0EB7737F91480E8CEBD9A0871574F5AB62D9020175EC6927CA0B54C09818E42CF92A383172422C7DC1831D63B0C295DE75159DB8034E9E07F7B0B910C3C1E5FB66B3DC523F1FA6EB4910CB89A6C17562C83AB4C18D0CD7E0796592A372AA409B1C557347CCACDC4644A119064D06DD474929D1C6FB4D686E5491CE4BC89A30BB4B8C41BCE5157DFC1360823B1AB618C14B10F98C25067398EA7018C278A4B3DF31334D603B2044EF187CD9BC6CE42725BD962C264983E9E18155A8B9C47143D70460A26A56FE7658C1F150348C6087EF758AD167887860A007A5FC37358D43B5EBEE820ACEA474F0AC07B76802866199C61231D5C747C93774D2C1E0C1C67E6C81B82752173E125BAF39B4FD19A4F453DC57976B1D97FE6996992BBB65B7CB25D077BBAA6A13322899AF659CF1B3558C1B5001154B625809ED89AEEBB89E6EA7D67F723D045AB05715C42355DA6A5C8DD39C8ABE3037751A01ED1C7374919F3121B5A52C53D1487316769F80721DEEAAAD3C90F76E7AE9E12BA92B32B5FD457E3C752C2650DFB885771CB77AC3C785A8C562E6A1C63C2A55EA47CF8B90EB8225C123C346452566235B2F31823A33521E087937A345D8D663EEAA05658917BBAA008C2E335F8850A90A326D0E66432F44CEB8289E4ECB2D12958E984072ECACB88E1348FF0B55654ACBA5B54971CBAEBA88EC4B91A94C37192FA982BECB9F3DA421603B61A51BC8E36CBD053851C77B1B926B17A272AA9023246B02B3ED47F66A00BD5684823634E7CE58CF8F306E35B1E5322824D904801F0A2FA7C2BC9C252B0A56B7BA2AB0F636021745A70A9A43E2B0A8D615970B65309624B5184BCC30B911679AEDD76025FE3908FD67897B0CF4BE5A6F5413D7DD98564B23E42A93E4AA8821CD45054C643EDC1158DB6B3DEB13FB5A51EBD1A8A78B87225A7338E101104C4A220D9BDEDD48C85A1C2DAE781A80C40E13B87EAC73A764201C9B760CCFB1AE392699C7039D27C39362B27B8FC6F07A8A3D4410F1547C48A9997F62C61074452EF1515F8A649EBCA9437205A4E8A61606B41DAF6834D671F4D852C0C9C4096611648C6A3170678B1537CC1828D93580C9E5849A9653175ACB753F2BE7437BE45F6C603E485F2EC301BB42B6C37C225D7495A584AE231890AB5C8C35C268CF4BBB0213C096019319561A8A6947637AA40D006B415BB2CFA2237E0890B6A3BC134ABF8F6585E108D15940F91F4BF5B0C818055B21DEA6E63B553988C47F4B94E7CF800A493B4734705EDC56A4B6021C629500675876804CF0B951F038A5C7FE58E89774EF2992FD7C63099D352A7D21560B788B405709861817E59A96B3A3A83CBA803B16934331071905BBEC6532900155D8AC88CB32E4E21A3BD3A03FDEC325A51CD2773964E6784FCF1853737AA64EB67564727272661ABF84313A57A44B123C65509CFB7A6F6641CDCC3B57FE628C7B8192DB44FFBF5796A8613B1FA126F6076883C783DC24E2A4464C40B3A41CA70AE87620866CF4FCB2BD204BF5C283812BA056AC0C345E379C4BA24D750901279BB2F3A16F612BFADB35703332C7C136F68EAB6755C66B6A4AD1AABA7B768A58ACAACC10A459A1CC8EF29377BC200E4D315A30A6BCC3256F9734D06E9779CAA5442A9A16069081377C76E75154368072DC446ED6C8B8E622A21E383CF9BA1FB434E2ECC81E7B78CEE986B8FF798AB18CF9634543546284EDA2A26B47F05B735BCDB1202220076DC8B4E4B9F853533C8F6C7FF38817BA49712835785F17F14CA01D0C1C1E98810FE0B36E5B427157B9418449CEDD641A4293C85C32700102ACEC22EBAD98ED160A5F027BD4CDA57F1F3720A12C134654DD5E73F829676495390D0E7929D6034E9C55F7D55BA658BC587988E8AF94960F6CFB8D5AF7A0021535A6E25E437D49A780698BE22AC9953949F571B85A685725F8207A2B0AE849B601AB91B159B3DF4A154C2041E776070AFC42969322380917C97510799F3149131477E16663D3174C7C1CAEA788535C6C005A64F2868631B31B66E205FD38C1D84542D0F1B578F58C9BF5A0FAEAB6AB6494893053165EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922
+            sk = 07638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405D85A4C1A1AB9B6AEB49CCE1C2F8A97C3516C72A00A46263BAA696BF25727719C3216423618FF33380934A6C10545C4C5C5155B12486181FC7A2319873978B6A2A67490F8256BD2196FE1792A4C00077B812EAE8BED3572499684AB3371876761E450C9F9D2768A36806D7AB2046C91F17599E9AC592990808DCD7B4D0919072F14EC361773B7252444C323C308326F4A30F8680D2F748F56A132B82674ED0184620B82AD2CB182C97B481626647491290A011CC73828685A8C367A5B9CF8D621B0D5C1EFF03172758BD004978C251CD51342228989CAE6332AC486437CB5C57D4307462865253BE217B3515C73DF405B7F28217AD0B8CF60C2FFFAA0A0048B1FB4ACDCDC38B5250CFEC356A6DE26CFA7A588FDC86F98C854AC64C7BFAA96F5A32CC0610934BAA6A586B9A2054F13BA274174AA0D2B3A81B96A940666F789B5A6BCDC0A6A0178A0C9A02578A493F6EEA0D2E6C13951C9F249A5E8DD71DD49A742D451F1ABBA19AF8C547855E0AFC728E90ABB499C9BEEB766F4729CDA22263E324D22302CBD3399FACC630991FC8F28BDB4354762541527678BCF61F65C241146C426D23B9BFAA6B7DF18C97F20C1B6125BF874B1D89475852C448215DB0EB7737F91480E8CEBD9A0871574F5AB62D9020175EC6927CA0B54C09818E42CF92A383172422C7DC1831D63B0C295DE75159DB8034E9E07F7B0B910C3C1E5FB66B3DC523F1FA6EB4910CB89A6C17562C83AB4C18D0CD7E0796592A372AA409B1C557347CCACDC4644A119064D06DD474929D1C6FB4D686E5491CE4BC89A30BB4B8C41BCE5157DFC1360823B1AB618C14B10F98C25067398EA7018C278A4B3DF31334D603B2044EF187CD9BC6CE42725BD962C264983E9E18155A8B9C47143D70460A26A56FE7658C1F150348C6087EF758AD167887860A007A5FC37358D43B5EBEE820ACEA474F0AC07B76802866199C61231D5C747C93774D2C1E0C1C67E6C81B82752173E125BAF39B4FD19A4F453DC57976B1D97FE6996992BBB65B7CB25D077BBAA6A13322899AF659CF1B3558C1B5001154B625809ED89AEEBB89E6EA7D67F723D045AB05715C42355DA6A5C8DD39C8ABE3037751A01ED1C7374919F3121B5A52C53D1487316769F80721DEEAAAD3C90F76E7AE9E12BA92B32B5FD457E3C752C2650DFB885771CB77AC3C785A8C562E6A1C63C2A55EA47CF8B90EB8225C123C346452566235B2F31823A33521E087937A345D8D663EEAA05658917BBAA008C2E335F8850A90A326D0E66432F44CEB8289E4ECB2D12958E984072ECACB88E1348FF0B55654ACBA5B54971CBAEBA88EC4B91A94C37192FA982BECB9F3DA421603B61A51BC8E36CBD053851C77B1B926B17A272AA9023246B02B3ED47F66A00BD5684823634E7CE58CF8F306E35B1E5322824D904801F0A2FA7C2BC9C252B0A56B7BA2AB0F636021745A70A9A43E2B0A8D615970B65309624B5184BCC30B911679AEDD76025FE3908FD67897B0CF4BE5A6F5413D7DD98564B23E42A93E4AA8821CD45054C643EDC1158DB6B3DEB13FB5A51EBD1A8A78B87225A7338E101104C4A220D9BDEDD48C85A1C2DAE781A80C40E13B87EAC73A764201C9B760CCFB1AE392699C7039D27C39362B27B8FC6F07A8A3D4410F1547C48A9997F62C61074452EF1515F8A649EBCA9437205A4E8A61606B41DAF6834D671F4D852C0C9C4096611648C6A3170678B1537CC1828D93580C9E5849A9653175ACB753F2BE7437BE45F6C603E485F2EC301BB42B6C37C225D7495A584AE231890AB5C8C35C268CF4BBB0213C096019319561A8A6947637AA40D006B415BB2CFA2237E0890B6A3BC134ABF8F6585E108D15940F91F4BF5B0C818055B21DEA6E63B553988C47F4B94E7CF800A493B4734705EDC56A4B6021C629500675876804CF0B951F038A5C7FE58E89774EF2992FD7C63099D352A7D21560B788B405709861817E59A96B3A3A83CBA803B16934331071905BBEC6532900155D8AC88CB32E4E21A3BD3A03FDEC325A51CD2773964E6784FCF1853737AA64EB67564727272661ABF84313A57A44B123C65509CFB7A6F6641CDCC3B57FE628C7B8192DB44FFBF5796A8613B1FA126F6076883C783DC24E2A4464C40B3A41CA70AE87620866CF4FCB2BD204BF5C283812BA056AC0C345E379C4BA24D750901279BB2F3A16F612BFADB35703332C7C136F68EAB6755C66B6A4AD1AABA7B768A58ACAACC10A459A1CC8EF29377BC200E4D315A30A6BCC3256F9734D06E9779CAA5442A9A16069081377C76E75154368072DC446ED6C8B8E622A21E383CF9BA1FB434E2ECC81E7B78CEE986B8FF798AB18CF9634543546284EDA2A26B47F05B735BCDB1202220076DC8B4E4B9F853533C8F6C7FF38817BA49712835785F17F14CA01D0C1C1E98810FE0B36E5B427157B9418449CEDD641A4293C85C32700102ACEC22EBAD98ED160A5F027BD4CDA57F1F3720A12C134654DD5E73F829676495390D0E7929D6034E9C55F7D55BA658BC587988E8AF94960F6CFB8D5AF7A0021535A6E25E437D49A780698BE22AC9953949F571B85A685725F8207A2B0AE849B601AB91B159B3DF4A154C2041E776070AFC42969322380917C97510799F3149131477E16663D3174C7C1CAEA788535C6C005A64F2868631B31B66E205FD38C1D84542D0F1B578F58C9BF5A0FAEAB6AB6494893053165EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B539228A39E87D531F3527C207EDCC1DB7FADDCF9628391879B335C707839A0DB051A88626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F
+            ct = A6AF29D5F5B80BD130F518BADDD6C8F17545413D860FB3DE451979EBFA5E4E3112C7C0ADF99824BB526F2C3550748ED0E134F0457A7C61F9F526F002BAADC03FC13E38131219513C3EDE061661E74F603C4FCF7951C8E52C9C213B0D22D9293663D669A6B58ED8FCEFCF8249D7BB5298F55761445B2B83CE7F005CB04248AEC8BDA22FD2D42AA766322014EA038CC32C55C8E4B9E28EC9119F527341E4F66A035121073B85DE6706DA19E0838A9F33B719A68F039B664DC002659EABFC398679AA7009CE0CD01CDAFB6CD2A26FE4101672C98FF58F7C47D5BDA2906653B3A6F9651F7A121EA77EA74723FAE5B873F9BB7B664F0C8A93831EF9D51C7CC1EF44AC0E55A55CA76D137FE9B75F40509CEF156E5AD18F9FB999680008E547D55EECD5B4D1CB1D9F076CEC21501C7402509ECB77AFB2CB9A61340A8BD1514C6E71B4AA45E47EC37512271B911F8FB46C9082C9DF07204ABB5A50E6E3647A8AD4D8D5D7BFF19C8A509308BCFB895536D045CA2B97CB16A29BB7181CAD0509DDB91735028EBA8C31D74BD275EAA65B5340B3A43FBFE0B3061D6BAE7E75B7098CDABE91D4B31E36C9AA7A8298862AD63C8FD282E03B460B3AB464CE0F27B1C3D11155ACAA011EB9E2AE3E6DDA07D6F491737CBCE9B05F9BC56BE20E8D326BA132C57FB235161144519CDF40560FBE279BDE411E112531F826D6AB10D4547350ADD2A9DE8D62C2AC82CABE6815646F4DC9742BB0C2A3F77EC7B46C6B537605FA31798CD89281221A33DFB9796E644305630332C2CB931408AB481A16D953F6BEAE3891D6D9AC1FAB38222D9271872D9D0CADB91ABE9B4E265F75C6E5E829E146C3D8CE1E9D12E0D129801957F46B0D2DBE1F749B1D08E2345F6239A731342EB75B0CF1BF411749BC2CAF2810B788C6B7238B4D3DA2D6315CE9542E24404F145755A30AB851E4445841BD33F716A586884888ECC6BC6498AA32919AE81D20C26973C2BD54582A0F6AD98ABFD2627E15690A727E69F581DD2A7127982A90E33E2D4A03FE339142C7E44C326AC46ED395A225D3033389917328B45316B1585A01B2C304B2944E903ABBB3EC5619441CFC8965A446DF75DEFA80C6E15ADBD506B7AB2DE12DDA9BC81441CFC89052E2E5808F7126C6FD3AC6AC8081258A84A09AE50F6CD7CC0F4AF336FD1D643E99079996268C2D32D909F22E3504F07FBB563196D4312FDDB9335D5C1D36E8C5EEA2278DBA23B94D193C947CC41CA993DC7DB1396340AD9C4FE687DD7B8D0C7A5120AE0204F2C665BD5F473D644C7FF26BFFBA7A36980830702128A7E661D677A092A36E7428A4139FB29B0095CC11086F447D2A9EF6C9B161F189C6299E084CB7AA00FAF787797BFB069FBC087FDE26252A1664F19C5A8A22EC5EE1AEB076357B7DC37E6B0F1520F958F7851BACB92C89FD114A72FEAC54652D45B09E1AE7651ABD164BCD537D58FA39D3EC8ACDCDF98425005862FA59692DE162B77E6297C66233348408A8AB695CE2F2728DB9FBE27E958967EC5974767C5A66023074B4A71AFD264AD2890E970A1F31D6E3311B736F9F9488793DDC88F23458064254C82A1D9E59EAD2FCEC40B430687C4B7E28960926AFCACC9BD756A71088C78450E20A2E980AEDE9EBEDFE7FABD6ABFE96F934C4B02C01CA194D01B73C25D5997039D3FCD0F099521F70CAEE69110AC1FC5A99917AD752FC96ADFAD7186D0A7C9CFE5601C07514EA6448D661C57AA20242103C4276A070A489A4CB6BCA0F9ECC4379FB220215FD91F81019D5B0AE619358B52468F272C178E3A74CF6775AA924FE329C3175D9E4C3E21AB9EC836EDC3ACAB2E3891EE8DEDA515D39AF9B8DDD0EE7B0164F805C3835F6D2BABDB30EAB4756E7EC7F829ECE01E8EADFBBED12FC283B3D4C69F575E7F80417689FDFCFC7BE27EE3B8CDF57AAEBEC4A95B7E5BB585B85227F7C32BE30DB3E65E42E30DCF5A5FA073DBA399D942F2222ADB9B9898102AFE5432EDC7F04AE34A8FEC2D81CB49A9A9B43814CE71D97F726E2B1E8F64B50E65DFB4816E12E82A3197484A4E9BBA4D2D69E3F19D0B75C21E2BFFE9FC0C98CF48A3AAF08D467F72687DF0178174B7897F734349B181ECA86A598A0C5E8C25946F24DC5572BD324A40458A788E5137F3C7A7C97FC9F12A3C463A8FE9449101CCE966D7C009323932998D56EF430C73BC24F5D95F737858DDC4F32C013
+            ss = B10F7394926AD3B49C5D62D5AEB531D5757538BCC0DA9E550D438F1B61BD7419
+            */
+            string temp = "061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1";
+            string expectedPubKey = "D22302CBD3399FACC630991FC8F28BDB4354762541527678BCF61F65C241146C426D23B9BFAA6B7DF18C97F20C1B6125BF874B1D89475852C448215DB0EB7737F91480E8CEBD9A0871574F5AB62D9020175EC6927CA0B54C09818E42CF92A383172422C7DC1831D63B0C295DE75159DB8034E9E07F7B0B910C3C1E5FB66B3DC523F1FA6EB4910CB89A6C17562C83AB4C18D0CD7E0796592A372AA409B1C557347CCACDC4644A119064D06DD474929D1C6FB4D686E5491CE4BC89A30BB4B8C41BCE5157DFC1360823B1AB618C14B10F98C25067398EA7018C278A4B3DF31334D603B2044EF187CD9BC6CE42725BD962C264983E9E18155A8B9C47143D70460A26A56FE7658C1F150348C6087EF758AD167887860A007A5FC37358D43B5EBEE820ACEA474F0AC07B76802866199C61231D5C747C93774D2C1E0C1C67E6C81B82752173E125BAF39B4FD19A4F453DC57976B1D97FE6996992BBB65B7CB25D077BBAA6A13322899AF659CF1B3558C1B5001154B625809ED89AEEBB89E6EA7D67F723D045AB05715C42355DA6A5C8DD39C8ABE3037751A01ED1C7374919F3121B5A52C53D1487316769F80721DEEAAAD3C90F76E7AE9E12BA92B32B5FD457E3C752C2650DFB885771CB77AC3C785A8C562E6A1C63C2A55EA47CF8B90EB8225C123C346452566235B2F31823A33521E087937A345D8D663EEAA05658917BBAA008C2E335F8850A90A326D0E66432F44CEB8289E4ECB2D12958E984072ECACB88E1348FF0B55654ACBA5B54971CBAEBA88EC4B91A94C37192FA982BECB9F3DA421603B61A51BC8E36CBD053851C77B1B926B17A272AA9023246B02B3ED47F66A00BD5684823634E7CE58CF8F306E35B1E5322824D904801F0A2FA7C2BC9C252B0A56B7BA2AB0F636021745A70A9A43E2B0A8D615970B65309624B5184BCC30B911679AEDD76025FE3908FD67897B0CF4BE5A6F5413D7DD98564B23E42A93E4AA8821CD45054C643EDC1158DB6B3DEB13FB5A51EBD1A8A78B87225A7338E101104C4A220D9BDEDD48C85A1C2DAE781A80C40E13B87EAC73A764201C9B760CCFB1AE392699C7039D27C39362B27B8FC6F07A8A3D4410F1547C48A9997F62C61074452EF1515F8A649EBCA9437205A4E8A61606B41DAF6834D671F4D852C0C9C4096611648C6A3170678B1537CC1828D93580C9E5849A9653175ACB753F2BE7437BE45F6C603E485F2EC301BB42B6C37C225D7495A584AE231890AB5C8C35C268CF4BBB0213C096019319561A8A6947637AA40D006B415BB2CFA2237E0890B6A3BC134ABF8F6585E108D15940F91F4BF5B0C818055B21DEA6E63B553988C47F4B94E7CF800A493B4734705EDC56A4B6021C629500675876804CF0B951F038A5C7FE58E89774EF2992FD7C63099D352A7D21560B788B405709861817E59A96B3A3A83CBA803B16934331071905BBEC6532900155D8AC88CB32E4E21A3BD3A03FDEC325A51CD2773964E6784FCF1853737AA64EB67564727272661ABF84313A57A44B123C65509CFB7A6F6641CDCC3B57FE628C7B8192DB44FFBF5796A8613B1FA126F6076883C783DC24E2A4464C40B3A41CA70AE87620866CF4FCB2BD204BF5C283812BA056AC0C345E379C4BA24D750901279BB2F3A16F612BFADB35703332C7C136F68EAB6755C66B6A4AD1AABA7B768A58ACAACC10A459A1CC8EF29377BC200E4D315A30A6BCC3256F9734D06E9779CAA5442A9A16069081377C76E75154368072DC446ED6C8B8E622A21E383CF9BA1FB434E2ECC81E7B78CEE986B8FF798AB18CF9634543546284EDA2A26B47F05B735BCDB1202220076DC8B4E4B9F853533C8F6C7FF38817BA49712835785F17F14CA01D0C1C1E98810FE0B36E5B427157B9418449CEDD641A4293C85C32700102ACEC22EBAD98ED160A5F027BD4CDA57F1F3720A12C134654DD5E73F829676495390D0E7929D6034E9C55F7D55BA658BC587988E8AF94960F6CFB8D5AF7A0021535A6E25E437D49A780698BE22AC9953949F571B85A685725F8207A2B0AE849B601AB91B159B3DF4A154C2041E776070AFC42969322380917C97510799F3149131477E16663D3174C7C1CAEA788535C6C005A64F2868631B31B66E205FD38C1D84542D0F1B578F58C9BF5A0FAEAB6AB6494893053165EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922";
+            string expectedPrivKey = "07638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405D85A4C1A1AB9B6AEB49CCE1C2F8A97C3516C72A00A46263BAA696BF25727719C3216423618FF33380934A6C10545C4C5C5155B12486181FC7A2319873978B6A2A67490F8256BD2196FE1792A4C00077B812EAE8BED3572499684AB3371876761E450C9F9D2768A36806D7AB2046C91F17599E9AC592990808DCD7B4D0919072F14EC361773B7252444C323C308326F4A30F8680D2F748F56A132B82674ED0184620B82AD2CB182C97B481626647491290A011CC73828685A8C367A5B9CF8D621B0D5C1EFF03172758BD004978C251CD51342228989CAE6332AC486437CB5C57D4307462865253BE217B3515C73DF405B7F28217AD0B8CF60C2FFFAA0A0048B1FB4ACDCDC38B5250CFEC356A6DE26CFA7A588FDC86F98C854AC64C7BFAA96F5A32CC0610934BAA6A586B9A2054F13BA274174AA0D2B3A81B96A940666F789B5A6BCDC0A6A0178A0C9A02578A493F6EEA0D2E6C13951C9F249A5E8DD71DD49A742D451F1ABBA19AF8C547855E0AFC728E90ABB499C9BEEB766F4729CDA22263E324D22302CBD3399FACC630991FC8F28BDB4354762541527678BCF61F65C241146C426D23B9BFAA6B7DF18C97F20C1B6125BF874B1D89475852C448215DB0EB7737F91480E8CEBD9A0871574F5AB62D9020175EC6927CA0B54C09818E42CF92A383172422C7DC1831D63B0C295DE75159DB8034E9E07F7B0B910C3C1E5FB66B3DC523F1FA6EB4910CB89A6C17562C83AB4C18D0CD7E0796592A372AA409B1C557347CCACDC4644A119064D06DD474929D1C6FB4D686E5491CE4BC89A30BB4B8C41BCE5157DFC1360823B1AB618C14B10F98C25067398EA7018C278A4B3DF31334D603B2044EF187CD9BC6CE42725BD962C264983E9E18155A8B9C47143D70460A26A56FE7658C1F150348C6087EF758AD167887860A007A5FC37358D43B5EBEE820ACEA474F0AC07B76802866199C61231D5C747C93774D2C1E0C1C67E6C81B82752173E125BAF39B4FD19A4F453DC57976B1D97FE6996992BBB65B7CB25D077BBAA6A13322899AF659CF1B3558C1B5001154B625809ED89AEEBB89E6EA7D67F723D045AB05715C42355DA6A5C8DD39C8ABE3037751A01ED1C7374919F3121B5A52C53D1487316769F80721DEEAAAD3C90F76E7AE9E12BA92B32B5FD457E3C752C2650DFB885771CB77AC3C785A8C562E6A1C63C2A55EA47CF8B90EB8225C123C346452566235B2F31823A33521E087937A345D8D663EEAA05658917BBAA008C2E335F8850A90A326D0E66432F44CEB8289E4ECB2D12958E984072ECACB88E1348FF0B55654ACBA5B54971CBAEBA88EC4B91A94C37192FA982BECB9F3DA421603B61A51BC8E36CBD053851C77B1B926B17A272AA9023246B02B3ED47F66A00BD5684823634E7CE58CF8F306E35B1E5322824D904801F0A2FA7C2BC9C252B0A56B7BA2AB0F636021745A70A9A43E2B0A8D615970B65309624B5184BCC30B911679AEDD76025FE3908FD67897B0CF4BE5A6F5413D7DD98564B23E42A93E4AA8821CD45054C643EDC1158DB6B3DEB13FB5A51EBD1A8A78B87225A7338E101104C4A220D9BDEDD48C85A1C2DAE781A80C40E13B87EAC73A764201C9B760CCFB1AE392699C7039D27C39362B27B8FC6F07A8A3D4410F1547C48A9997F62C61074452EF1515F8A649EBCA9437205A4E8A61606B41DAF6834D671F4D852C0C9C4096611648C6A3170678B1537CC1828D93580C9E5849A9653175ACB753F2BE7437BE45F6C603E485F2EC301BB42B6C37C225D7495A584AE231890AB5C8C35C268CF4BBB0213C096019319561A8A6947637AA40D006B415BB2CFA2237E0890B6A3BC134ABF8F6585E108D15940F91F4BF5B0C818055B21DEA6E63B553988C47F4B94E7CF800A493B4734705EDC56A4B6021C629500675876804CF0B951F038A5C7FE58E89774EF2992FD7C63099D352A7D21560B788B405709861817E59A96B3A3A83CBA803B16934331071905BBEC6532900155D8AC88CB32E4E21A3BD3A03FDEC325A51CD2773964E6784FCF1853737AA64EB67564727272661ABF84313A57A44B123C65509CFB7A6F6641CDCC3B57FE628C7B8192DB44FFBF5796A8613B1FA126F6076883C783DC24E2A4464C40B3A41CA70AE87620866CF4FCB2BD204BF5C283812BA056AC0C345E379C4BA24D750901279BB2F3A16F612BFADB35703332C7C136F68EAB6755C66B6A4AD1AABA7B768A58ACAACC10A459A1CC8EF29377BC200E4D315A30A6BCC3256F9734D06E9779CAA5442A9A16069081377C76E75154368072DC446ED6C8B8E622A21E383CF9BA1FB434E2ECC81E7B78CEE986B8FF798AB18CF9634543546284EDA2A26B47F05B735BCDB1202220076DC8B4E4B9F853533C8F6C7FF38817BA49712835785F17F14CA01D0C1C1E98810FE0B36E5B427157B9418449CEDD641A4293C85C32700102ACEC22EBAD98ED160A5F027BD4CDA57F1F3720A12C134654DD5E73F829676495390D0E7929D6034E9C55F7D55BA658BC587988E8AF94960F6CFB8D5AF7A0021535A6E25E437D49A780698BE22AC9953949F571B85A685725F8207A2B0AE849B601AB91B159B3DF4A154C2041E776070AFC42969322380917C97510799F3149131477E16663D3174C7C1CAEA788535C6C005A64F2868631B31B66E205FD38C1D84542D0F1B578F58C9BF5A0FAEAB6AB6494893053165EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B539228A39E87D531F3527C207EDCC1DB7FADDCF9628391879B335C707839A0DB051A88626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F";
+
+            byte[] seed = Hex.Decode(temp);
+
+            NistSecureRandom random = new NistSecureRandom(seed, null);
+
+            KyberKeyPairGenerator keyGen = new KyberKeyPairGenerator();
+            keyGen.Init(new KyberKeyGenerationParameters(random, KyberParameters.kyber1024));
+
+            AsymmetricCipherKeyPair keyPair = keyGen.GenerateKeyPair();
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode(expectedPubKey), ((KyberPublicKeyParameters)keyPair.Public).GetEncoded()));
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode(expectedPrivKey), ((KyberPrivateKeyParameters)keyPair.Private).GetEncoded()));
+
+            KyberKemGenerator kemGen = new KyberKemGenerator(random);
+
+            ISecretWithEncapsulation secretEncap = kemGen.GenerateEncapsulated(keyPair.Public);
+
+            string expectedSharedSecret = "B10F7394926AD3B49C5D62D5AEB531D5757538BCC0DA9E550D438F1B61BD7419";
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode(expectedSharedSecret), secretEncap.GetSecret()));
+
+            string expectedCipherText = "A6AF29D5F5B80BD130F518BADDD6C8F17545413D860FB3DE451979EBFA5E4E3112C7C0ADF99824BB526F2C3550748ED0E134F0457A7C61F9F526F002BAADC03FC13E38131219513C3EDE061661E74F603C4FCF7951C8E52C9C213B0D22D9293663D669A6B58ED8FCEFCF8249D7BB5298F55761445B2B83CE7F005CB04248AEC8BDA22FD2D42AA766322014EA038CC32C55C8E4B9E28EC9119F527341E4F66A035121073B85DE6706DA19E0838A9F33B719A68F039B664DC002659EABFC398679AA7009CE0CD01CDAFB6CD2A26FE4101672C98FF58F7C47D5BDA2906653B3A6F9651F7A121EA77EA74723FAE5B873F9BB7B664F0C8A93831EF9D51C7CC1EF44AC0E55A55CA76D137FE9B75F40509CEF156E5AD18F9FB999680008E547D55EECD5B4D1CB1D9F076CEC21501C7402509ECB77AFB2CB9A61340A8BD1514C6E71B4AA45E47EC37512271B911F8FB46C9082C9DF07204ABB5A50E6E3647A8AD4D8D5D7BFF19C8A509308BCFB895536D045CA2B97CB16A29BB7181CAD0509DDB91735028EBA8C31D74BD275EAA65B5340B3A43FBFE0B3061D6BAE7E75B7098CDABE91D4B31E36C9AA7A8298862AD63C8FD282E03B460B3AB464CE0F27B1C3D11155ACAA011EB9E2AE3E6DDA07D6F491737CBCE9B05F9BC56BE20E8D326BA132C57FB235161144519CDF40560FBE279BDE411E112531F826D6AB10D4547350ADD2A9DE8D62C2AC82CABE6815646F4DC9742BB0C2A3F77EC7B46C6B537605FA31798CD89281221A33DFB9796E644305630332C2CB931408AB481A16D953F6BEAE3891D6D9AC1FAB38222D9271872D9D0CADB91ABE9B4E265F75C6E5E829E146C3D8CE1E9D12E0D129801957F46B0D2DBE1F749B1D08E2345F6239A731342EB75B0CF1BF411749BC2CAF2810B788C6B7238B4D3DA2D6315CE9542E24404F145755A30AB851E4445841BD33F716A586884888ECC6BC6498AA32919AE81D20C26973C2BD54582A0F6AD98ABFD2627E15690A727E69F581DD2A7127982A90E33E2D4A03FE339142C7E44C326AC46ED395A225D3033389917328B45316B1585A01B2C304B2944E903ABBB3EC5619441CFC8965A446DF75DEFA80C6E15ADBD506B7AB2DE12DDA9BC81441CFC89052E2E5808F7126C6FD3AC6AC8081258A84A09AE50F6CD7CC0F4AF336FD1D643E99079996268C2D32D909F22E3504F07FBB563196D4312FDDB9335D5C1D36E8C5EEA2278DBA23B94D193C947CC41CA993DC7DB1396340AD9C4FE687DD7B8D0C7A5120AE0204F2C665BD5F473D644C7FF26BFFBA7A36980830702128A7E661D677A092A36E7428A4139FB29B0095CC11086F447D2A9EF6C9B161F189C6299E084CB7AA00FAF787797BFB069FBC087FDE26252A1664F19C5A8A22EC5EE1AEB076357B7DC37E6B0F1520F958F7851BACB92C89FD114A72FEAC54652D45B09E1AE7651ABD164BCD537D58FA39D3EC8ACDCDF98425005862FA59692DE162B77E6297C66233348408A8AB695CE2F2728DB9FBE27E958967EC5974767C5A66023074B4A71AFD264AD2890E970A1F31D6E3311B736F9F9488793DDC88F23458064254C82A1D9E59EAD2FCEC40B430687C4B7E28960926AFCACC9BD756A71088C78450E20A2E980AEDE9EBEDFE7FABD6ABFE96F934C4B02C01CA194D01B73C25D5997039D3FCD0F099521F70CAEE69110AC1FC5A99917AD752FC96ADFAD7186D0A7C9CFE5601C07514EA6448D661C57AA20242103C4276A070A489A4CB6BCA0F9ECC4379FB220215FD91F81019D5B0AE619358B52468F272C178E3A74CF6775AA924FE329C3175D9E4C3E21AB9EC836EDC3ACAB2E3891EE8DEDA515D39AF9B8DDD0EE7B0164F805C3835F6D2BABDB30EAB4756E7EC7F829ECE01E8EADFBBED12FC283B3D4C69F575E7F80417689FDFCFC7BE27EE3B8CDF57AAEBEC4A95B7E5BB585B85227F7C32BE30DB3E65E42E30DCF5A5FA073DBA399D942F2222ADB9B9898102AFE5432EDC7F04AE34A8FEC2D81CB49A9A9B43814CE71D97F726E2B1E8F64B50E65DFB4816E12E82A3197484A4E9BBA4D2D69E3F19D0B75C21E2BFFE9FC0C98CF48A3AAF08D467F72687DF0178174B7897F734349B181ECA86A598A0C5E8C25946F24DC5572BD324A40458A788E5137F3C7A7C97FC9F12A3C463A8FE9449101CCE966D7C009323932998D56EF430C73BC24F5D95F737858DDC4F32C013";
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode(expectedCipherText), secretEncap.GetEncapsulation()));
+
+            KyberKemExtractor kemExtract = new KyberKemExtractor((KyberPrivateKeyParameters)keyPair.Private);
+
+            byte[] decryptedSharedSecret = kemExtract.ExtractSecret(secretEncap.GetEncapsulation());
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode(expectedSharedSecret), decryptedSharedSecret));
+        }
+
+        [Test]
+        public void TestKyberRandom()
+        {
+            SecureRandom random = new SecureRandom();
+            KyberKeyPairGenerator keyGen = new KyberKeyPairGenerator();
+
+            keyGen.Init(new KyberKeyGenerationParameters(random, KyberParameters.kyber1024));
+
+            for (int i = 0; i != 1000; i++)
+            {
+                AsymmetricCipherKeyPair keyPair = keyGen.GenerateKeyPair();
+
+                KyberKemGenerator kemGen = new KyberKemGenerator(random);
+
+                ISecretWithEncapsulation secretEncap = kemGen.GenerateEncapsulated(keyPair.Public);
+
+                KyberKemExtractor kemExtract = new KyberKemExtractor((KyberPrivateKeyParameters)keyPair.Private);
+
+                byte[] decryptedSharedSecret = kemExtract.ExtractSecret(secretEncap.GetEncapsulation());
+
+                Assert.IsTrue(Arrays.AreEqual(secretEncap.GetSecret(), decryptedSharedSecret));
+            }
+        }
+
+        [Test]
+        public void TestParameters()
+        {
+            Assert.AreEqual(128, KyberParameters.kyber512.SessionKeySize);
+            Assert.AreEqual(192, KyberParameters.kyber768.SessionKeySize);
+            Assert.AreEqual(256, KyberParameters.kyber1024.SessionKeySize);
+        }
+
+        [Test]
+        public void TestPrivInfoGeneration()
+        {
+            SecureRandom random = new SecureRandom();
+            PqcOtherInfoGenerator.PartyU partyU = new PqcOtherInfoGenerator.PartyU(KyberParameters.kyber512,
+                new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), Hex.Decode("beef"), Hex.Decode("cafe"), random);
+
+            byte[] partA = partyU.GetSuppPrivInfoPartA();
+
+            PqcOtherInfoGenerator.PartyV partyV = new PqcOtherInfoGenerator.PartyV(KyberParameters.kyber512,
+                new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), Hex.Decode("beef"), Hex.Decode("cafe"), random);
+
+            byte[] partB = partyV.GetSuppPrivInfoPartB(partA);
+
+            DerOtherInfo otherInfoU = partyU.Generate(partB);
+
+            DerOtherInfo otherInfoV = partyV.Generate();
+
+            Assert.IsTrue(Arrays.AreEqual(otherInfoU.GetEncoded(), otherInfoV.GetEncoded()));
+        }
+
+        [Test]
+        public void TestRng()
+        {
+            string temp = "061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1";
+            byte[] seed = Hex.Decode(temp);
+            NistSecureRandom r = new NistSecureRandom(seed, null);
+            byte[] testBytes = new byte[48];
+            r.NextBytes(testBytes);
+
+            string randBytesString = "7C9935A0B07694AA0C6D10E4DB6B1ADD2FD81A25CCB148032DCD739936737F2DB505D7CFAD1B497499323C8686325E47";
+            byte[] randBytes = Hex.Decode(randBytesString);
+
+            Assert.IsTrue(Arrays.AreEqual(randBytes, testBytes));
+        }
+
         [TestCaseSource(nameof(TestVectorFiles))]
         [Parallelizable(ParallelScope.All)]
         public void TV(string testVectorFile)
@@ -71,11 +190,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
             // Generate keys and test.
             //
             kpGen.Init(genParam);
-            AsymmetricCipherKeyPair ackp = kpGen.GenerateKeyPair();
-
+            AsymmetricCipherKeyPair kp = kpGen.GenerateKeyPair();
 
-            KyberPublicKeyParameters pubParams = (KyberPublicKeyParameters)ackp.Public;
-            KyberPrivateKeyParameters privParams = (KyberPrivateKeyParameters)ackp.Private;
+            KyberPublicKeyParameters pubParams = (KyberPublicKeyParameters)PqcPublicKeyFactory.CreateKey(
+                PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo((KyberPublicKeyParameters)kp.Public));
+            KyberPrivateKeyParameters privParams = (KyberPrivateKeyParameters)PqcPrivateKeyFactory.CreateKey(
+                PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo((KyberPrivateKeyParameters)kp.Private));
 
             Assert.True(Arrays.AreEqual(pk, pubParams.GetEncoded()), name + " " + count + ": public key");
             Assert.True(Arrays.AreEqual(sk, privParams.GetEncoded()), name + " " + count + ": secret key");
diff --git a/crypto/test/src/pqc/crypto/test/FalconTest.cs b/crypto/test/src/pqc/crypto/test/FalconTest.cs
index be2d0d352..c8424b37a 100644
--- a/crypto/test/src/pqc/crypto/test/FalconTest.cs
+++ b/crypto/test/src/pqc/crypto/test/FalconTest.cs
@@ -108,17 +108,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
             FalconKeyGenerationParameters kparam = new FalconKeyGenerationParameters(random, falconParameters);
             FalconKeyPairGenerator kpg = new FalconKeyPairGenerator();
             kpg.Init(kparam);
-            AsymmetricCipherKeyPair ackp = kpg.GenerateKeyPair();
-            byte[] respk = ((FalconPublicKeyParameters)ackp.Public).GetEncoded();
-            byte[] ressk = ((FalconPrivateKeyParameters)ackp.Private).GetEncoded();
-                            
-            //keygen
+            AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
+
+            FalconPublicKeyParameters pubParams = (FalconPublicKeyParameters)PqcPublicKeyFactory.CreateKey(
+                PqcSubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo((FalconPublicKeyParameters)kp.Public));
+            FalconPrivateKeyParameters privParams = (FalconPrivateKeyParameters)PqcPrivateKeyFactory.CreateKey(
+                PqcPrivateKeyInfoFactory.CreatePrivateKeyInfo((FalconPrivateKeyParameters)kp.Private));
+
+            byte[] respk = pubParams.GetEncoded();
+            byte[] ressk = privParams.GetEncoded();
+
             Assert.True(Arrays.AreEqual(respk, 0, respk.Length, pk, 1, pk.Length), name + " " + count + " public key");
             Assert.True(Arrays.AreEqual(ressk, 0, ressk.Length, sk, 1, sk.Length), name + " " + count + " private key");
 
             // sign
             FalconSigner signer = new FalconSigner();
-            ParametersWithRandom skwrand = new ParametersWithRandom(ackp.Private, random);
+            ParametersWithRandom skwrand = new ParametersWithRandom(kp.Private, random);
             signer.Init(true, skwrand);
             byte[] sig = signer.GenerateSignature(msg);
             byte[] ressm = new byte[2 + msg.Length + sig.Length];
@@ -131,7 +136,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Tests
          
             // verify
             FalconSigner verifier = new FalconSigner();
-            FalconPublicKeyParameters pkparam = (FalconPublicKeyParameters)ackp.Public;
+            FalconPublicKeyParameters pkparam = (FalconPublicKeyParameters)kp.Public;
             verifier.Init(false, pkparam);
             bool vrfyrespass = verifier.VerifySignature(msg, sig);
             sig[42]++; // changing the signature by 1 byte should cause it to fail