summary refs log tree commit diff
path: root/crypto/src/pqc
diff options
context:
space:
mode:
authorroyb <roy.basmacier@primekey.com>2022-10-24 15:57:57 -0400
committerroyb <roy.basmacier@primekey.com>2022-10-24 15:57:57 -0400
commitf506a6ad1ee03b2c950c76ba8e9d3e47f3a44d67 (patch)
treef9f79c9f5504dde6a8d4bf51ba724d26d20eea17 /crypto/src/pqc
parentfixed refactored class names in pqc/utils (diff)
downloadBouncyCastle.NET-ed25519-f506a6ad1ee03b2c950c76ba8e9d3e47f3a44d67.tar.xz
Added Aes and Uniform variant to Saber
Diffstat (limited to 'crypto/src/pqc')
-rw-r--r--crypto/src/pqc/crypto/saber/Poly.cs25
-rw-r--r--crypto/src/pqc/crypto/saber/SABEREngine.cs82
-rw-r--r--crypto/src/pqc/crypto/saber/SABERParameters.cs35
-rw-r--r--crypto/src/pqc/crypto/saber/SaberUtilities.cs122
-rw-r--r--crypto/src/pqc/crypto/saber/Symmetric.cs96
-rw-r--r--crypto/src/pqc/crypto/utils/PqcUtilities.cs21
-rw-r--r--crypto/src/pqc/crypto/utils/PublicKeyFactory.cs9
7 files changed, 289 insertions, 101 deletions
diff --git a/crypto/src/pqc/crypto/saber/Poly.cs b/crypto/src/pqc/crypto/saber/Poly.cs
index eaae6c9a5..1a7312201 100644
--- a/crypto/src/pqc/crypto/saber/Poly.cs
+++ b/crypto/src/pqc/crypto/saber/Poly.cs
@@ -32,9 +32,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             byte[] buf = new byte[SABER_L * engine.PolyVecBytes];
             int i;
 
-            IXof digest = new ShakeDigest(128);
-            digest.BlockUpdate(seed, 0, engine.SeedBytes);
-            digest.OutputFinal(buf, 0, buf.Length);
+            engine.Symmetric.Prf(buf, seed, engine.SeedBytes, buf.Length);
+
 
             for (i = 0; i < SABER_L; i++)
             {
@@ -46,13 +45,25 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         {
             byte[] buf = new byte[SABER_L * engine.PolyCoinBytes];
 
-            IXof digest = new ShakeDigest(128);
-            digest.BlockUpdate(seed, 0, engine.NoiseSeedBytes);
-            digest.OutputFinal(buf, 0, buf.Length);
+            engine.Symmetric.Prf(buf, seed, engine.NoiseSeedBytes, buf.Length);
+
 
             for (int i = 0; i < SABER_L; i++)
             {
-                Cbd(s[i], buf, i * engine.PolyCoinBytes);
+                if (!engine.UsingEffectiveMasking)
+                {
+                    Cbd(s[i], buf, i * engine.PolyCoinBytes);
+                }
+                else
+                {
+                    for(int j = 0; j<SABER_N/4; j++)
+                    {
+                        s[i][4*j] = (short) ((((buf[j + i * engine.PolyCoinBytes]) & 0x03) ^ 2) - 2);
+                        s[i][4*j+1] = (short) ((((buf[j + i * engine.PolyCoinBytes] >> 2) & 0x03)  ^ 2) - 2);
+                        s[i][4*j+2] = (short) ((((buf[j + i * engine.PolyCoinBytes] >> 4) & 0x03)  ^ 2) - 2);
+                        s[i][4*j+3] = (short) ((((buf[j + i * engine.PolyCoinBytes] >> 6) & 0x03)  ^ 2) - 2);
+                    }
+                }
             }
         }
 
diff --git a/crypto/src/pqc/crypto/saber/SABEREngine.cs b/crypto/src/pqc/crypto/saber/SABEREngine.cs
index c17efb123..e57c0a23f 100644
--- a/crypto/src/pqc/crypto/saber/SABEREngine.cs
+++ b/crypto/src/pqc/crypto/saber/SABEREngine.cs
@@ -10,7 +10,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
     internal sealed class SaberEngine
     {
         // constant parameters
-        internal const int SABER_EQ = 13;
         internal const int SABER_EP = 10;
         internal const int SABER_N = 256;
 
@@ -25,6 +24,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         private readonly int SABER_ET;
 
         private readonly int SABER_POLYCOINBYTES;
+        private readonly int SABER_EQ;
         private readonly int SABER_POLYBYTES;
         private readonly int SABER_POLYVECBYTES;
         private readonly int SABER_POLYCOMPRESSEDBYTES;
@@ -41,9 +41,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         private int h1;
         private int h2;
 
+        private Symmetric symmetric;
         private SaberUtilities utils;
         private Poly poly;
 
+        private readonly bool usingAes;
+        private readonly bool usingEffectiveMasking;
+
+        public bool UsingAes => usingAes;
+        public bool UsingEffectiveMasking => usingEffectiveMasking;
+        public Symmetric Symmetric => symmetric;
+        
+        public int EQ => SABER_EQ;
         public int N => SABER_N;
 
         public int EP => SABER_EP;
@@ -89,10 +98,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             return SABER_SECRETKEYBYTES;
         }
 
-        internal SaberEngine(int l, int defaultKeySize)
+        internal SaberEngine(int l, int defaultKeySize, bool usingAes, bool usingEffectiveMasking)
         {
             this.defaultKeySize = defaultKeySize;
-
+            this.usingAes = usingAes;
+            this.usingEffectiveMasking = usingEffectiveMasking;
             this.SABER_L = l;
             if (l == 2)
             {
@@ -109,8 +119,25 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
                 this.SABER_MU = 6;
                 this.SABER_ET = 6;
             }
+            if(usingAes)
+            {
+                symmetric = new Symmetric.AesSymmetric();
+            }
+            else
+            {
+                symmetric = new Symmetric.ShakeSymmetric();
+            }
 
-            this.SABER_POLYCOINBYTES = (SABER_MU * SABER_N / 8);
+            if(usingEffectiveMasking)
+            {
+                this.SABER_EQ = 12;
+                this.SABER_POLYCOINBYTES = (2 * SABER_N / 8);
+            }
+            else
+            {
+                this.SABER_EQ = 13;
+                this.SABER_POLYCOINBYTES = (SABER_MU * SABER_N / 8);
+            }
             this.SABER_POLYBYTES = (SABER_EQ * SABER_N / 8);
             this.SABER_POLYVECBYTES = (SABER_L * SABER_POLYBYTES);
             this.SABER_POLYCOMPRESSEDBYTES = (SABER_EP * SABER_N / 8);
@@ -165,9 +192,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
             random.NextBytes(seed_A);
 
-            IXof digest = new ShakeDigest(128);
-            digest.BlockUpdate(seed_A, 0, SABER_SEEDBYTES);
-            digest.OutputFinal(seed_A, 0, SABER_SEEDBYTES);
+            symmetric.Prf(seed_A, seed_A, SABER_SEEDBYTES, SABER_SEEDBYTES);
 
             random.NextBytes(seed_s);
 
@@ -196,13 +221,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             int i;
             indcpa_kem_keypair(pk, sk, random); // sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk
             for (i = 0; i < SABER_INDCPA_PUBLICKEYBYTES; i++)
+            {
                 sk[i + SABER_INDCPA_SECRETKEYBYTES] =
                     pk[i]; // sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk
-
+            }
             // Then hash(pk) is appended.
-            Sha3Digest digest = new Sha3Digest(256);
-            digest.BlockUpdate(pk, 0, SABER_INDCPA_PUBLICKEYBYTES);
-            digest.DoFinal(sk, SABER_SECRETKEYBYTES - 64);
+            symmetric.Hash_h(sk, pk, SABER_SECRETKEYBYTES - 64);
 
             // Remaining part of sk contains a pseudo-random number.
             byte[] nonce = new byte[SABER_KEYBYTES];
@@ -252,7 +276,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             }
 
             short[] mp = new short[SABER_N];
-            ;
             short[] vp = new short[SABER_N];
             byte[] seed_A = Arrays.CopyOfRange(pk, SABER_POLYVECCOMPRESSEDBYTES, pk.Length);
 
@@ -290,35 +313,30 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             byte[] nonce = new byte[32];
             random.NextBytes(nonce);
 
-            Sha3Digest digest_256 = new Sha3Digest(256);
-            Sha3Digest digest_512 = new Sha3Digest(512);
+           
 
             // BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output
-            digest_256.BlockUpdate(nonce, 0, 32);
-            digest_256.DoFinal(nonce, 0);
+            symmetric.Hash_h(nonce, nonce, 0);
+
             Array.Copy(nonce, 0, buf, 0, 32);
 
             // BUF[32:63] <-- Hash(public key);  Multitarget countermeasure for coins + contributory KEM
-            digest_256.BlockUpdate(pk, 0, SABER_INDCPA_PUBLICKEYBYTES);
-            digest_256.DoFinal(buf, 32);
+            symmetric.Hash_h(buf, pk, 32);
 
             // kr[0:63] <-- Hash(buf[0:63]);
-            digest_512.BlockUpdate(buf, 0, 64);
-            digest_512.DoFinal(kr, 0);
+            symmetric.Hash_g(kr, buf);
 
             // K^ <-- kr[0:31]
             // noiseseed (r) <-- kr[32:63];
             // buf[0:31] contains message; kr[32:63] contains randomness r;
             indcpa_kem_enc(buf, Arrays.CopyOfRange(kr, 32, kr.Length), pk, c);
 
-            digest_256.BlockUpdate(c, 0, SABER_BYTES_CCA_DEC);
-            digest_256.DoFinal(kr, 32);
+            symmetric.Hash_h(kr, c, 32);
 
             // hash concatenation of pre-k and h(c) to k
             //todo support 128 and 192 bit keys
             byte[] temp_k = new byte[32];
-            digest_256.BlockUpdate(kr, 0, 64);
-            digest_256.DoFinal(temp_k, 0);
+            symmetric.Hash_h(temp_k, kr, 0);
 
             Array.Copy(temp_k, 0, k, 0, defaultKeySize / 8);
 
@@ -370,14 +388,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
             // Multitarget countermeasure for coins + contributory KEM
             for (i = 0; i < 32; i++) // Save hash by storing h(pk) in sk
+            {
                 buf[32 + i] = sk[SABER_SECRETKEYBYTES - 64 + i];
+            }
 
 
-            Sha3Digest digest_256 = new Sha3Digest(256);
-            Sha3Digest digest_512 = new Sha3Digest(512);
-
-            digest_512.BlockUpdate(buf, 0, 64);
-            digest_512.DoFinal(kr, 0);
+            symmetric.Hash_g(kr, buf);
 
             indcpa_kem_enc(buf, Arrays.CopyOfRange(kr, 32, kr.Length), pk, cmp);
 
@@ -385,16 +401,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
             // overwrite coins in kr with h(c)
 
-            digest_256.BlockUpdate(c, 0, SABER_BYTES_CCA_DEC);
-            digest_256.DoFinal(kr, 32);
-
+            symmetric.Hash_h(kr, c, 32);
+            
             cmov(kr, sk, SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES, (byte) fail);
 
             // hash concatenation of pre-k and h(c) to k
             //todo support 128 and 192 bit keys
             byte[] temp_k = new byte[32];
-            digest_256.BlockUpdate(kr, 0, 64);
-            digest_256.DoFinal(temp_k, 0);
+            symmetric.Hash_h(temp_k, kr, 0);
 
             Array.Copy(temp_k, 0, k, 0, defaultKeySize / 8);
             return 0;
diff --git a/crypto/src/pqc/crypto/saber/SABERParameters.cs b/crypto/src/pqc/crypto/saber/SABERParameters.cs
index 8cc9b468c..e2992d4c4 100644
--- a/crypto/src/pqc/crypto/saber/SABERParameters.cs
+++ b/crypto/src/pqc/crypto/saber/SABERParameters.cs
@@ -5,29 +5,42 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
     public sealed class SaberParameters
         : ICipherParameters
     {
-        public static SaberParameters lightsaberkem128r3 = new SaberParameters("lightsaberkem128r3", 2, 128);
-        public static SaberParameters saberkem128r3 = new SaberParameters("saberkem128r3", 3, 128);
-        public static SaberParameters firesaberkem128r3 = new SaberParameters("firesaberkem128r3", 4, 128);
+        public static SaberParameters lightsaberkem128r3 = new SaberParameters("lightsaberkem128r3", 2, 128, false, false);
+        public static SaberParameters saberkem128r3 = new SaberParameters("saberkem128r3", 3, 128, false, false);
+        public static SaberParameters firesaberkem128r3 = new SaberParameters("firesaberkem128r3", 4, 128, false, false);
 
-        public static SaberParameters lightsaberkem192r3 = new SaberParameters("lightsaberkem192r3", 2, 192);
-        public static SaberParameters saberkem192r3 = new SaberParameters("saberkem192r3", 3, 192);
-        public static SaberParameters firesaberkem192r3 = new SaberParameters("firesaberkem192r3", 4, 192);
+        public static SaberParameters lightsaberkem192r3 = new SaberParameters("lightsaberkem192r3", 2, 192, false, false);
+        public static SaberParameters saberkem192r3 = new SaberParameters("saberkem192r3", 3, 192, false, false);
+        public static SaberParameters firesaberkem192r3 = new SaberParameters("firesaberkem192r3", 4, 192, false, false);
+
+        public static SaberParameters lightsaberkem256r3 = new SaberParameters("lightsaberkem256r3", 2, 256, false, false);
+        public static SaberParameters saberkem256r3 = new SaberParameters("saberkem256r3", 3, 256, false, false);
+        public static SaberParameters firesaberkem256r3 = new SaberParameters("firesaberkem256r3", 4, 256, false, false);
+        
+        public static SaberParameters lightsaberkem90sr3 = new SaberParameters("lightsaberkem90sr3", 2, 256, true, false);
+        public static SaberParameters saberkem90sr3 = new SaberParameters("saberkem90sr3", 3, 256, true, false);
+        public static SaberParameters firesaberkem90sr3 = new SaberParameters("firesaberkem90sr3", 4, 256, true, false);
+
+        public static SaberParameters ulightsaberkemr3 = new SaberParameters("ulightsaberkemr3", 2, 256, false, true);
+        public static SaberParameters usaberkemr3 = new SaberParameters("usaberkemr3", 3, 256, false, true);
+        public static SaberParameters ufiresaberkemr3 = new SaberParameters("ufiresaberkemr3", 4, 256, false, true);
+
+        public static SaberParameters ulightsaberkem90sr3 = new SaberParameters("ulightsaberkem90sr3", 2, 256, true, true);
+        public static SaberParameters usaberkem90sr3 = new SaberParameters("usaberkem90sr3", 3, 256, true, true);
+        public static SaberParameters ufiresaberkem90sr3 = new SaberParameters("ufiresaberkem90sr3", 4, 256, true, true);
 
-        public static SaberParameters lightsaberkem256r3 = new SaberParameters("lightsaberkem256r3", 2, 256);
-        public static SaberParameters saberkem256r3 = new SaberParameters("saberkem256r3", 3, 256);
-        public static SaberParameters firesaberkem256r3 = new SaberParameters("firesaberkem256r3", 4, 256);
 
         private readonly string name;
         private readonly int l;
         private readonly int defaultKeySize;
         private readonly SaberEngine engine;
 
-        private SaberParameters(string name, int l, int defaultKeySize)
+        private SaberParameters(string name, int l, int defaultKeySize, bool usingAes, bool usingEffectiveMasking)
         {
             this.name = name;
             this.l = l;
             this.defaultKeySize = defaultKeySize;
-            this.engine = new SaberEngine(l, defaultKeySize);
+            this.engine = new SaberEngine(l, defaultKeySize, usingAes, usingEffectiveMasking);
         }
 
         public string Name => name;
diff --git a/crypto/src/pqc/crypto/saber/SaberUtilities.cs b/crypto/src/pqc/crypto/saber/SaberUtilities.cs
index d25eb8d2d..90c2b4ea4 100644
--- a/crypto/src/pqc/crypto/saber/SaberUtilities.cs
+++ b/crypto/src/pqc/crypto/saber/SaberUtilities.cs
@@ -8,7 +8,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         private readonly int SABER_POLYBYTES;
         private readonly int SABER_EP;
         private readonly int SABER_KEYBYTES;
-
+        private readonly bool usingEffectiveMasking;
         internal SaberUtilities(SaberEngine engine)
         {
             this.SABER_N = engine.N;
@@ -17,6 +17,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             this.SABER_POLYBYTES = engine.PolyBytes;
             this.SABER_EP = engine.EP;
             this.SABER_KEYBYTES = engine.KeyBytes;
+            this.usingEffectiveMasking = engine.UsingEffectiveMasking;
         }
 
         public void POLT2BS(byte[] bytes, int byteIndex, short[] data)
@@ -117,60 +118,87 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         private void POLq2BS(byte[] bytes, int byteIndex, short[] data)
         {
             short j, offset_byte, offset_data;
-            for (j = 0; j < SABER_N / 8; j++)
+            if (!usingEffectiveMasking)
             {
-                offset_byte = (short) (13 * j);
-                offset_data = (short) (8 * j);
-                bytes[byteIndex + offset_byte + 0] = (byte) (data[offset_data + 0] & (0xff));
-                bytes[byteIndex + offset_byte + 1] =
-                    (byte) (((data[offset_data + 0] >> 8) & 0x1f) | ((data[offset_data + 1] & 0x07) << 5));
-                bytes[byteIndex + offset_byte + 2] = (byte) ((data[offset_data + 1] >> 3) & 0xff);
-                bytes[byteIndex + offset_byte + 3] =
-                    (byte) (((data[offset_data + 1] >> 11) & 0x03) | ((data[offset_data + 2] & 0x3f) << 2));
-                bytes[byteIndex + offset_byte + 4] =
-                    (byte) (((data[offset_data + 2] >> 6) & 0x7f) | ((data[offset_data + 3] & 0x01) << 7));
-                bytes[byteIndex + offset_byte + 5] = (byte) ((data[offset_data + 3] >> 1) & 0xff);
-                bytes[byteIndex + offset_byte + 6] =
-                    (byte) (((data[offset_data + 3] >> 9) & 0x0f) | ((data[offset_data + 4] & 0x0f) << 4));
-                bytes[byteIndex + offset_byte + 7] = (byte) ((data[offset_data + 4] >> 4) & 0xff);
-                bytes[byteIndex + offset_byte + 8] =
-                    (byte) (((data[offset_data + 4] >> 12) & 0x01) | ((data[offset_data + 5] & 0x7f) << 1));
-                bytes[byteIndex + offset_byte + 9] =
-                    (byte) (((data[offset_data + 5] >> 7) & 0x3f) | ((data[offset_data + 6] & 0x03) << 6));
-                bytes[byteIndex + offset_byte + 10] = (byte) ((data[offset_data + 6] >> 2) & 0xff);
-                bytes[byteIndex + offset_byte + 11] =
-                    (byte) (((data[offset_data + 6] >> 10) & 0x07) | ((data[offset_data + 7] & 0x1f) << 3));
-                bytes[byteIndex + offset_byte + 12] = (byte) ((data[offset_data + 7] >> 5) & 0xff);
+                for (j = 0; j < SABER_N / 8; j++)
+                {
+                    offset_byte = (short)(13 * j);
+                    offset_data = (short)(8 * j);
+                    bytes[byteIndex + offset_byte + 0] = (byte)(data[offset_data + 0] & (0xff));
+                    bytes[byteIndex + offset_byte + 1] =
+                        (byte)(((data[offset_data + 0] >> 8) & 0x1f) | ((data[offset_data + 1] & 0x07) << 5));
+                    bytes[byteIndex + offset_byte + 2] = (byte)((data[offset_data + 1] >> 3) & 0xff);
+                    bytes[byteIndex + offset_byte + 3] =
+                        (byte)(((data[offset_data + 1] >> 11) & 0x03) | ((data[offset_data + 2] & 0x3f) << 2));
+                    bytes[byteIndex + offset_byte + 4] =
+                        (byte)(((data[offset_data + 2] >> 6) & 0x7f) | ((data[offset_data + 3] & 0x01) << 7));
+                    bytes[byteIndex + offset_byte + 5] = (byte)((data[offset_data + 3] >> 1) & 0xff);
+                    bytes[byteIndex + offset_byte + 6] =
+                        (byte)(((data[offset_data + 3] >> 9) & 0x0f) | ((data[offset_data + 4] & 0x0f) << 4));
+                    bytes[byteIndex + offset_byte + 7] = (byte)((data[offset_data + 4] >> 4) & 0xff);
+                    bytes[byteIndex + offset_byte + 8] =
+                        (byte)(((data[offset_data + 4] >> 12) & 0x01) | ((data[offset_data + 5] & 0x7f) << 1));
+                    bytes[byteIndex + offset_byte + 9] =
+                        (byte)(((data[offset_data + 5] >> 7) & 0x3f) | ((data[offset_data + 6] & 0x03) << 6));
+                    bytes[byteIndex + offset_byte + 10] = (byte)((data[offset_data + 6] >> 2) & 0xff);
+                    bytes[byteIndex + offset_byte + 11] =
+                        (byte)(((data[offset_data + 6] >> 10) & 0x07) | ((data[offset_data + 7] & 0x1f) << 3));
+                    bytes[byteIndex + offset_byte + 12] = (byte)((data[offset_data + 7] >> 5) & 0xff);
+                }
+            }
+            else
+            {
+                for (j = 0; j < SABER_N / 2; j++)
+                {
+                    offset_byte = (short) (3 * j);
+                    offset_data = (short) (2 * j);
+                    bytes[byteIndex + offset_byte + 0] = (byte) (data[offset_data + 0] & (0xff));
+                    bytes[byteIndex + offset_byte + 1] = (byte) (((data[offset_data + 0] >> 8) & 0xf) | ((data[offset_data + 1] & 0xf) << 4));
+                    bytes[byteIndex + offset_byte + 2] = (byte) ((data[offset_data + 1] >> 4) & 0xff);
+                }
             }
         }
 
         private void BS2POLq(byte[] bytes, int byteIndex, short[] data)
         {
             short j, offset_byte, offset_data;
-            for (j = 0; j < SABER_N / 8; j++)
+            if (!usingEffectiveMasking)
             {
-                offset_byte = (short) (13 * j);
-                offset_data = (short) (8 * j);
-                data[offset_data + 0] = (short) ((bytes[byteIndex + offset_byte + 0] & (0xff)) |
-                                                 ((bytes[byteIndex + offset_byte + 1] & 0x1f) << 8));
-                data[offset_data + 1] = (short) ((bytes[byteIndex + offset_byte + 1] >> 5 & (0x07)) |
-                                                 ((bytes[byteIndex + offset_byte + 2] & 0xff) << 3) |
-                                                 ((bytes[byteIndex + offset_byte + 3] & 0x03) << 11));
-                data[offset_data + 2] = (short) ((bytes[byteIndex + offset_byte + 3] >> 2 & (0x3f)) |
-                                                 ((bytes[byteIndex + offset_byte + 4] & 0x7f) << 6));
-                data[offset_data + 3] = (short) ((bytes[byteIndex + offset_byte + 4] >> 7 & (0x01)) |
-                                                 ((bytes[byteIndex + offset_byte + 5] & 0xff) << 1) |
-                                                 ((bytes[byteIndex + offset_byte + 6] & 0x0f) << 9));
-                data[offset_data + 4] = (short) ((bytes[byteIndex + offset_byte + 6] >> 4 & (0x0f)) |
-                                                 ((bytes[byteIndex + offset_byte + 7] & 0xff) << 4) |
-                                                 ((bytes[byteIndex + offset_byte + 8] & 0x01) << 12));
-                data[offset_data + 5] = (short) ((bytes[byteIndex + offset_byte + 8] >> 1 & (0x7f)) |
-                                                 ((bytes[byteIndex + offset_byte + 9] & 0x3f) << 7));
-                data[offset_data + 6] = (short) ((bytes[byteIndex + offset_byte + 9] >> 6 & (0x03)) |
-                                                 ((bytes[byteIndex + offset_byte + 10] & 0xff) << 2) |
-                                                 ((bytes[byteIndex + offset_byte + 11] & 0x07) << 10));
-                data[offset_data + 7] = (short) ((bytes[byteIndex + offset_byte + 11] >> 3 & (0x1f)) |
-                                                 ((bytes[byteIndex + offset_byte + 12] & 0xff) << 5));
+                for (j = 0; j < SABER_N / 8; j++)
+                {
+                    offset_byte = (short)(13 * j);
+                    offset_data = (short)(8 * j);
+                    data[offset_data + 0] = (short)((bytes[byteIndex + offset_byte + 0] & (0xff)) |
+                                                    ((bytes[byteIndex + offset_byte + 1] & 0x1f) << 8));
+                    data[offset_data + 1] = (short)((bytes[byteIndex + offset_byte + 1] >> 5 & (0x07)) |
+                                                    ((bytes[byteIndex + offset_byte + 2] & 0xff) << 3) |
+                                                    ((bytes[byteIndex + offset_byte + 3] & 0x03) << 11));
+                    data[offset_data + 2] = (short)((bytes[byteIndex + offset_byte + 3] >> 2 & (0x3f)) |
+                                                    ((bytes[byteIndex + offset_byte + 4] & 0x7f) << 6));
+                    data[offset_data + 3] = (short)((bytes[byteIndex + offset_byte + 4] >> 7 & (0x01)) |
+                                                    ((bytes[byteIndex + offset_byte + 5] & 0xff) << 1) |
+                                                    ((bytes[byteIndex + offset_byte + 6] & 0x0f) << 9));
+                    data[offset_data + 4] = (short)((bytes[byteIndex + offset_byte + 6] >> 4 & (0x0f)) |
+                                                    ((bytes[byteIndex + offset_byte + 7] & 0xff) << 4) |
+                                                    ((bytes[byteIndex + offset_byte + 8] & 0x01) << 12));
+                    data[offset_data + 5] = (short)((bytes[byteIndex + offset_byte + 8] >> 1 & (0x7f)) |
+                                                    ((bytes[byteIndex + offset_byte + 9] & 0x3f) << 7));
+                    data[offset_data + 6] = (short)((bytes[byteIndex + offset_byte + 9] >> 6 & (0x03)) |
+                                                    ((bytes[byteIndex + offset_byte + 10] & 0xff) << 2) |
+                                                    ((bytes[byteIndex + offset_byte + 11] & 0x07) << 10));
+                    data[offset_data + 7] = (short)((bytes[byteIndex + offset_byte + 11] >> 3 & (0x1f)) |
+                                                    ((bytes[byteIndex + offset_byte + 12] & 0xff) << 5));
+                }
+            }
+            else
+            {
+                for (j = 0; j < SABER_N / 2; j++)
+                {
+                    offset_byte = (short) (3 * j);
+                    offset_data = (short) (2 * j);
+                    data[offset_data + 0] = (short) ((bytes[byteIndex + offset_byte + 0] & (0xff)) | ((bytes[byteIndex + offset_byte + 1] & 0xf) << 8));
+                    data[offset_data + 1] = (short) ((bytes[byteIndex + offset_byte + 1] >> 4 & (0xf)) | ((bytes[byteIndex + offset_byte + 2] & 0xff) << 4));
+                }
             }
         }
 
diff --git a/crypto/src/pqc/crypto/saber/Symmetric.cs b/crypto/src/pqc/crypto/saber/Symmetric.cs
new file mode 100644
index 000000000..dc47b87bb
--- /dev/null
+++ b/crypto/src/pqc/crypto/saber/Symmetric.cs
@@ -0,0 +1,96 @@
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Saber;
+
+public abstract class Symmetric
+{
+
+    internal abstract void Hash_h(byte[] output, byte[] input, int outputOffset);
+
+    internal abstract void Hash_g(byte[] output, byte[] input);
+
+    internal abstract void Prf(byte[] output, byte[] input, int inLen, int outputLen);
+
+    protected internal class ShakeSymmetric
+        : Symmetric
+    {
+
+        private readonly Sha3Digest sha3Digest256;
+        private readonly Sha3Digest sha3Digest512;
+        private readonly IXof shakeDigest;
+
+        internal ShakeSymmetric()
+        {
+            shakeDigest = new ShakeDigest(128);
+            sha3Digest256 = new Sha3Digest(256);
+            sha3Digest512 = new Sha3Digest(512);
+        }
+
+        internal override void Hash_h(byte[] output, byte[] input, int outputOffset)
+        {
+            sha3Digest256.BlockUpdate(input, 0, input.Length);
+            sha3Digest256.DoFinal(output, outputOffset);
+        }
+
+        internal override void Hash_g(byte[] output, byte[] input)
+        {
+            sha3Digest512.BlockUpdate(input, 0, input.Length);
+            sha3Digest512.DoFinal(output, 0);
+        }
+
+        internal override void Prf(byte[] output, byte[] input, int inLen, int outputLen)
+        {
+            shakeDigest.Reset();
+            shakeDigest.BlockUpdate(input, 0, inLen);
+            shakeDigest.OutputFinal(output, 0, outputLen);
+        }
+
+
+    }
+    internal class AesSymmetric
+        : Symmetric
+    {
+
+        private readonly Sha256Digest sha256Digest;
+        private readonly Sha512Digest sha512Digest;
+
+        private readonly SicBlockCipher cipher;
+
+
+        protected internal AesSymmetric()
+        {
+            sha256Digest = new Sha256Digest();
+            sha512Digest = new Sha512Digest();
+            cipher = new SicBlockCipher(AesUtilities.CreateEngine());
+        }
+        
+        internal override void Hash_h(byte[] output, byte[] input, int outputOffset)
+        {
+            sha256Digest.BlockUpdate(input, 0, input.Length);
+            sha256Digest.DoFinal(output, outputOffset);
+        }
+
+        internal override void Hash_g(byte[] output, byte[] input)
+        {
+            sha512Digest.BlockUpdate(input, 0, input.Length);
+            sha512Digest.DoFinal(output, 0);
+        }
+
+        internal override void Prf(byte[] output, byte[] input, int inLen, int outputLen)
+        {
+            ParametersWithIV kp = new ParametersWithIV(new KeyParameter(input, 0, inLen), new byte[16]);
+            cipher.Init(true, kp);
+            byte[] buf = new byte[outputLen];   // TODO: there might be a more efficient way of doing this...
+            for (int i = 0; i < outputLen; i+= 16)
+            {
+                cipher.ProcessBlock(buf, i, output, i);
+            }
+        }
+
+
+    }
+
+}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/utils/PqcUtilities.cs b/crypto/src/pqc/crypto/utils/PqcUtilities.cs
index ac9415b06..1f1da5e74 100644
--- a/crypto/src/pqc/crypto/utils/PqcUtilities.cs
+++ b/crypto/src/pqc/crypto/utils/PqcUtilities.cs
@@ -78,7 +78,16 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             saberOids[SaberParameters.lightsaberkem256r3] = BCObjectIdentifiers.lightsaberkem256r3;
             saberOids[SaberParameters.saberkem256r3] = BCObjectIdentifiers.saberkem256r3;
             saberOids[SaberParameters.firesaberkem256r3] = BCObjectIdentifiers.firesaberkem256r3;
-            
+            saberOids[SaberParameters.ulightsaberkemr3] = BCObjectIdentifiers.ulightsaberkemr3;
+            saberOids[SaberParameters.usaberkemr3] = BCObjectIdentifiers.usaberkemr3;
+            saberOids[SaberParameters.ufiresaberkemr3] = BCObjectIdentifiers.ufiresaberkemr3;
+            saberOids[SaberParameters.lightsaberkem90sr3] = BCObjectIdentifiers.lightsaberkem90sr3;
+            saberOids[SaberParameters.saberkem90sr3] = BCObjectIdentifiers.saberkem90sr3;
+            saberOids[SaberParameters.firesaberkem90sr3] = BCObjectIdentifiers.firesaberkem90sr3;
+            saberOids[SaberParameters.ulightsaberkem90sr3] = BCObjectIdentifiers.ulightsaberkem90sr3;
+            saberOids[SaberParameters.usaberkem90sr3] = BCObjectIdentifiers.usaberkem90sr3;
+            saberOids[SaberParameters.ufiresaberkem90sr3] = BCObjectIdentifiers.ufiresaberkem90sr3;
+
             saberParams[BCObjectIdentifiers.lightsaberkem128r3] = SaberParameters.lightsaberkem128r3;
             saberParams[BCObjectIdentifiers.saberkem128r3] = SaberParameters.saberkem128r3;
             saberParams[BCObjectIdentifiers.firesaberkem128r3] = SaberParameters.firesaberkem128r3;
@@ -88,7 +97,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             saberParams[BCObjectIdentifiers.lightsaberkem256r3] = SaberParameters.lightsaberkem256r3;
             saberParams[BCObjectIdentifiers.saberkem256r3] = SaberParameters.saberkem256r3;
             saberParams[BCObjectIdentifiers.firesaberkem256r3] = SaberParameters.firesaberkem256r3;
-
+            saberParams[BCObjectIdentifiers.ulightsaberkemr3] = SaberParameters.ulightsaberkemr3;
+            saberParams[BCObjectIdentifiers.usaberkemr3] = SaberParameters.usaberkemr3;
+            saberParams[BCObjectIdentifiers.ufiresaberkemr3] = SaberParameters.ufiresaberkemr3;
+            saberParams[BCObjectIdentifiers.lightsaberkem90sr3] = SaberParameters.lightsaberkem90sr3;
+            saberParams[BCObjectIdentifiers.saberkem90sr3] = SaberParameters.saberkem90sr3;
+            saberParams[BCObjectIdentifiers.firesaberkem90sr3] = SaberParameters.firesaberkem90sr3;
+            saberParams[BCObjectIdentifiers.ulightsaberkem90sr3] = SaberParameters.ulightsaberkem90sr3;
+            saberParams[BCObjectIdentifiers.usaberkem90sr3] = SaberParameters.usaberkem90sr3;
+            saberParams[BCObjectIdentifiers.ufiresaberkem90sr3] = SaberParameters.ufiresaberkem90sr3;
             
             picnicOids[PicnicParameters.picnicl1fs] = BCObjectIdentifiers.picnicl1fs;
             picnicOids[PicnicParameters.picnicl1ur] = BCObjectIdentifiers.picnicl1ur;
diff --git a/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs b/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs
index 07df84ca1..bb33a3aa3 100644
--- a/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs
@@ -53,6 +53,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             converters[BCObjectIdentifiers.lightsaberkem256r3] = new SaberConverter();
             converters[BCObjectIdentifiers.saberkem256r3] = new SaberConverter();
             converters[BCObjectIdentifiers.firesaberkem256r3] = new SaberConverter();
+            converters[BCObjectIdentifiers.ulightsaberkemr3] = new SaberConverter();
+            converters[BCObjectIdentifiers.usaberkemr3] = new SaberConverter();
+            converters[BCObjectIdentifiers.ufiresaberkemr3] = new SaberConverter();
+            converters[BCObjectIdentifiers.lightsaberkem90sr3] = new SaberConverter();
+            converters[BCObjectIdentifiers.saberkem90sr3] = new SaberConverter();
+            converters[BCObjectIdentifiers.firesaberkem90sr3] = new SaberConverter();
+            converters[BCObjectIdentifiers.ulightsaberkem90sr3] = new SaberConverter();
+            converters[BCObjectIdentifiers.usaberkem90sr3] = new SaberConverter();
+            converters[BCObjectIdentifiers.ufiresaberkem90sr3] = new SaberConverter();
             
             converters[BCObjectIdentifiers.picnic] = new PicnicConverter();
             converters[BCObjectIdentifiers.picnicl1fs] = new PicnicConverter();