summary refs log tree commit diff
path: root/crypto/src/pqc
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/pqc')
-rw-r--r--crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs266
-rw-r--r--crypto/src/pqc/crypto/hqc/GFCalculator.cs4
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcEngine.cs258
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs13
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs2
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs13
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs18
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcParameters.cs7
-rw-r--r--crypto/src/pqc/crypto/hqc/ReedMuller.cs15
-rw-r--r--crypto/src/pqc/crypto/hqc/ReedSolomon.cs1
-rw-r--r--crypto/src/pqc/crypto/hqc/Utils.cs25
11 files changed, 364 insertions, 258 deletions
diff --git a/crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs b/crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs
index 0c01ade96..48774cde3 100644
--- a/crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs
+++ b/crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs
@@ -1,129 +1,223 @@
-using System;
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-using System.Buffers.Binary;
-using System.Runtime.InteropServices;
-#endif
-
-using Org.BouncyCastle.Math.Raw;
-
-namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
 {
     internal class GF2PolynomialCalculator
     {
-        private const int TABLE = 16;
+        private readonly int _vecNSize64;
+        private readonly int _paramN;
+        private readonly long _redMask;
 
-        static void Mod(ulong[] res, ulong[] a, int n, int nByte64)
+        public GF2PolynomialCalculator(int vecNSize64, int paramN, ulong redMask)
         {
-            for (int i = 0; i < nByte64; i++)
-            {
-                ulong r = a[i + nByte64 - 1] >> (n & 0x3F);
-                ulong carry = a[i + nByte64] << (64 - (n & 0x3F));
-                res[i] = a[i] ^ r ^ carry;
-            }
-            res[nByte64 - 1] &= Utils.BitMask((ulong)n, 64);
+            _vecNSize64 = vecNSize64;
+            _paramN = paramN;
+            _redMask = (long)redMask;
         }
 
-        static void Swap(int[] table, int firstIndex, int secondIndex)
+        internal void MultLongs(long[] res, long[] a, long[] b)
         {
-            int tmp = table[firstIndex];
-            table[firstIndex] = table[secondIndex];
-            table[secondIndex] = tmp;
+            long[] stack = new long[_vecNSize64 << 3];
+            long[] oKarat = new long[(_vecNSize64 << 1) + 1];
+
+            karatsuba(oKarat, 0, a, 0,  b, 0, _vecNSize64, stack, 0);
+            reduce(res, oKarat);
         }
 
-        static void FastConvolutionMult(ulong[] res, int[] a, ulong[] b, int weight, int nByte64, int we,
-            HqcKeccakRandomGenerator random)
+
+        private void base_mul(long[] c, int cOffset, long a, long b)
         {
-            int[] permutedTable = new int[TABLE];
-            for (int i = 0; i < 16; i++)
+            long h = 0;
+            long l = 0;
+            long g;
+            long[] u = new long[16];
+            long[] maskTab = new long[4];
+
+            // Step 1
+            u[0] = 0;
+            u[1] = b & ((1L << (64 - 4)) - 1L);
+            u[2] = u[1] << 1;
+            u[3] = u[2] ^ u[1];
+            u[4] = u[2] << 1;
+            u[5] = u[4] ^ u[1];
+            u[6] = u[3] << 1;
+            u[7] = u[6] ^ u[1];
+            u[8] = u[4] << 1;
+            u[9] = u[8] ^ u[1];
+            u[10] = u[5] << 1;
+            u[11] = u[10] ^ u[1];
+            u[12] = u[6] << 1;
+            u[13] = u[12] ^ u[1];
+            u[14] = u[7] << 1;
+            u[15] = u[14] ^ u[1];
+
+            g=0;
+            long tmp1 = a & 15;
+
+            for(int i = 0; i < 16; i++)
             {
-                permutedTable[i] = i;
+                long tmp2 = tmp1 - i;
+                g ^= (u[i] & -(1 - (long)((ulong)(tmp2 | -tmp2) >> 63)));
             }
+            l = g;
+            h = 0;
 
-            byte[] permutationTableByte = new byte[TABLE*2];
-            random.ExpandSeed(permutationTableByte, TABLE << 1);
-
-            int[] permutationTable = new int[TABLE];
-            Utils.FromByteArrayToByte16Array(permutationTable, permutationTableByte);
-
-            for (int i = 0; i < TABLE - 1; i++)
+            // Step 2
+            for (byte i = 4; i < 64; i += 4)
             {
-                Swap(permutedTable, i, i + permutationTable[i] % (TABLE - i));
+                g = 0;
+                long temp1 = (a >> i) & 15;
+                for (int j = 0; j < 16; ++j)
+                {
+                    long tmp2 = temp1 - j;
+                    g ^= (u[j] & -(1 - (long)((ulong)(tmp2 | -tmp2) >> 63)));
+                }
+
+                l ^= g << i;
+                h ^= (long)((ulong)g) >> (64 - i);
             }
 
-            ulong[] table = new ulong[TABLE * (nByte64 + 1)];
-            int idx = permutedTable[0] * (nByte64 + 1);
-            Array.Copy(b, 0, table, idx, nByte64);
-            table[idx + nByte64] = 0UL;
+            // Step 3
+            maskTab [0] = -((b >> 60) & 1);
+            maskTab [1] = -((b >> 61) & 1);
+            maskTab [2] = -((b >> 62) & 1);
+            maskTab [3] = -((b >> 63) & 1);
+
+            l ^= ((a << 60) & maskTab[0]);
+            h ^= ((long)((ulong)a >> 4) & maskTab[0]);
+
+            l ^= ((a << 61) & maskTab[1]);
+            h ^= ((long)((ulong)a >> 3) & maskTab[1]);
 
-            for (int i = 1; i < TABLE; i++)
+            l ^= ((a << 62) & maskTab[2]);
+            h ^= ((long)((ulong)a >> 2) & maskTab[2]);
+
+            l ^= ((a << 63) & maskTab[3]);
+            h ^= ((long)((ulong)a >> 1) & maskTab[3]);
+
+            c[0 + cOffset] = l;
+            c[1 + cOffset] = h;
+        }
+
+
+
+
+        private void karatsuba_add1(long[] alh, int alhOffset,
+                            long[] blh, int blhOffset,
+                            long[] a, int aOffset,
+                            long[] b, int bOffset,
+                            int size_l, int size_h)
+        {
+            for (int i = 0; i < size_h; i++)
             {
-                idx = permutedTable[i] * (nByte64 + 1);
-                table[idx + nByte64] = Nat.ShiftUpBits64(nByte64, b, 0, i, 0UL, table, idx);
+                alh[i + alhOffset] = a[i+ aOffset] ^ a[i + size_l + aOffset];
+                blh[i + blhOffset] = b[i+ bOffset] ^ b[i + size_l + bOffset];
             }
 
-            int[] permutedSparseVect = new int[we];
-            for (int i = 0; i < weight; i++)
+            if (size_h < size_l)
             {
-                permutedSparseVect[i] = i;
+                alh[size_h + alhOffset] = a[size_h + aOffset];
+                blh[size_h + blhOffset] = b[size_h + bOffset];
             }
+        }
 
-            byte[] permutationSparseVectBytes = new byte[we * 2];
-            random.ExpandSeed(permutationSparseVectBytes, weight << 1);
 
-            int[] permutationSparseVect = new int[we];
-            Utils.FromByteArrayToByte16Array(permutationSparseVect, permutationSparseVectBytes);
 
-            for (int i = 0; i < (weight - 1); i++)
+        private void karatsuba_add2(long[] o, int oOffset,
+                           long[] tmp1, int tmp1Offset,
+                           long[] tmp2, int tmp2Offset,
+                            int size_l, int size_h)
+        {
+            for (int i = 0; i < (2 * size_l) ; i++)
             {
-                Swap(permutedSparseVect, i, i + permutationSparseVect[i] % (weight - i));
+                tmp1[i + tmp1Offset] = tmp1[i + tmp1Offset] ^ o[i + oOffset];
             }
 
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-            Span<byte> resBytes = MemoryMarshal.AsBytes(res.AsSpan());
-            for (int i = 0; i < weight; i++)
+            for (int i = 0; i < ( 2 * size_h); i++)
             {
-                int dec = a[permutedSparseVect[i]] & 0xf;
-                int s = a[permutedSparseVect[i]] >> 4;
-
-                idx = permutedTable[dec] * (nByte64 + 1);
-
-                int count = s * 2 + nByte64 * 8;
-                for (int j = nByte64; j >= 0; --j)
-                {
-                    ulong tmp = BinaryPrimitives.ReadUInt64LittleEndian(resBytes[count..]);
-                    BinaryPrimitives.WriteUInt64LittleEndian(resBytes[count..], tmp ^ table[idx + j]);
-                    count -= 8;
-                }
+                tmp1[i + tmp1Offset] = tmp1[i + tmp1Offset] ^ tmp2[i + tmp2Offset];
             }
-#else
-            ushort[] resByte16 = new ushort[res.Length * 4];
-            for (int i = 0; i < weight; i++)
+
+            for (int i = 0; i < (2 * size_l); i++)
             {
-                int dec = a[permutedSparseVect[i]] & 0xf;
-                int s = a[permutedSparseVect[i]] >> 4;
+                o[i + size_l + oOffset] = o[i + size_l + oOffset] ^ tmp1[i + tmp1Offset];
+            }
+        }
 
-                idx = permutedTable[dec] * (nByte64 + 1);
 
-                int count = s;
-                for (int j = 0; j <= nByte64; j++)
-                {
-                    Utils.XorULongToByte16Array(resByte16, count, table[idx + j]);
-                    count += 4;
-                }
+
+        /**
+         * Karatsuba multiplication of a and b, Implementation inspired from the NTL library.
+         *
+         * \param[out] o Polynomial
+         * \param[in] a Polynomial
+         * \param[in] b Polynomial
+         * \param[in] size Length of polynomial
+         * \param[in] stack Length of polynomial
+         */
+        private void karatsuba(long[] o, int oOffset, long[] a, int aOffset, long[] b, int bOffset, int size, long[] stack, int stackOffset)
+        {
+            int size_l, size_h;
+            int ahOffset, bhOffset;
+
+            if (size == 1)
+            {
+                base_mul(o, oOffset, a[0 + aOffset], b[0 + bOffset]);
+                return;
             }
-            Utils.FromByte16ArrayToULongArray(res, resByte16);
-#endif
+
+            size_h = size / 2;
+            size_l = (size + 1) / 2;
+
+            // alh = stack
+            int alhOffset = stackOffset;
+            // blh = stack with size_l offset
+            int blhOffset = alhOffset + size_l;
+            // tmp1 = stack with size_l * 2 offset;
+            int tmp1Offset = blhOffset + size_l;
+            // tmp2 = o with size_l * 2 offset;
+            int tmp2Offset = oOffset + size_l*2;
+
+            stackOffset += 4 * size_l;
+
+            ahOffset = aOffset + size_l;
+            bhOffset = bOffset + size_l;
+
+            karatsuba(o, oOffset, a, aOffset, b, bOffset, size_l, stack, stackOffset);
+
+            karatsuba(o, tmp2Offset, a, ahOffset, b, bhOffset, size_h, stack, stackOffset);
+
+            karatsuba_add1(stack, alhOffset, stack, blhOffset, a, aOffset, b, bOffset, size_l, size_h);
+
+            karatsuba(stack, tmp1Offset, stack, alhOffset, stack, blhOffset, size_l, stack, stackOffset);
+
+            karatsuba_add2(o, oOffset, stack, tmp1Offset, o, tmp2Offset, size_l, size_h);
         }
 
-        internal static void ModMult(ulong[] res, int[] a, ulong[] b, int weight,int n,  int nByte64, int we,
-            HqcKeccakRandomGenerator random)
+
+
+        /**
+         * @brief Compute o(x) = a(x) mod \f$ X^n - 1\f$
+         *
+         * This function computes the modular reduction of the polynomial a(x)
+         *
+         * @param[in] a Pointer to the polynomial a(x)
+         * @param[out] o Pointer to the result
+         */
+        private void reduce(long[] o, long[] a)
         {
-            ulong[] tmp = new ulong[(nByte64 << 1) + 1];
-            FastConvolutionMult(tmp, a, b, weight, nByte64, we, random);
-            Mod(res, tmp, n, nByte64);
+            int i;
+            long r;
+            long carry;
+
+            for (i = 0; i < _vecNSize64; i++)
+            {
+                r = (long)((ulong)a[i + _vecNSize64 - 1] >> (_paramN & 0x3F));
+                carry = a[i + _vecNSize64 ] << (int)(64 - (_paramN & 0x3FL));
+                o[i] = a[i] ^ r ^ carry;
+            }
+            o[_vecNSize64 - 1] &= _redMask;
         }
 
-        internal static void AddULongs(ulong[] res, ulong[] a, ulong[] b)
+        internal static void AddLongs(long[] res, long[] a, long[] b)
         {
             for (int i = 0; i < a.Length; i++)
             {
diff --git a/crypto/src/pqc/crypto/hqc/GFCalculator.cs b/crypto/src/pqc/crypto/hqc/GFCalculator.cs
index d63e70513..ab0359b3b 100644
--- a/crypto/src/pqc/crypto/hqc/GFCalculator.cs
+++ b/crypto/src/pqc/crypto/hqc/GFCalculator.cs
@@ -2,8 +2,8 @@
 {
     internal class GFCalculator
     {
-        static int[] exp = new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4 };
-        static int[] log = new int[] { 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 };
+        static int[] exp = { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4 };
+        static int[] log = { 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 };
 
         internal static int mult(int a, int b)
         {
diff --git a/crypto/src/pqc/crypto/hqc/HqcEngine.cs b/crypto/src/pqc/crypto/hqc/HqcEngine.cs
index ac1a96f00..ee628e843 100644
--- a/crypto/src/pqc/crypto/hqc/HqcEngine.cs
+++ b/crypto/src/pqc/crypto/hqc/HqcEngine.cs
@@ -1,5 +1,5 @@
 using System;
-
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Hqc
@@ -33,10 +33,18 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
         private int N1N2_BYTE_64;
         private int N1N2_BYTE;
         private int N1_BYTE;
+        
+        private int GF_POLY_WT  = 5;
+        private int GF_POLY_M2 = 4;
+        private int SALT_SIZE_BYTES = 16;
+        private int SALT_SIZE_64 = 2;
 
         private int[] generatorPoly;
         private int SHA512_BYTES = 512 / 8;
 
+        private ulong RED_MASK;
+        private GF2PolynomialCalculator gfCalculator;
+
         public HqcEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr, int we, int rejectionThreshold, int fft, int[] generatorPoly)
         {
             this.n = n;
@@ -47,21 +55,25 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             this.we = we;
             this.n1 = n1;
             this.n2 = n2;
-            this.n1n2 = n1 * n2;
+            n1n2 = n1 * n2;
             this.generatorPoly = generatorPoly;
             this.g = g;
             this.rejectionThreshold = rejectionThreshold;
             this.fft = fft;
 
-            this.mulParam = (n2 + 127) / 128;
-            this.N_BYTE = Utils.GetByteSizeFromBitSize(n);
-            this.K_BYTE = k;
-            this.N_BYTE_64 = Utils.GetByte64SizeFromBitSize(n);
-            this.K_BYTE_64 = Utils.GetByteSizeFromBitSize(k);
-            this.N1_BYTE_64 = Utils.GetByteSizeFromBitSize(n1);
-            this.N1N2_BYTE_64 = Utils.GetByte64SizeFromBitSize(n1 * n2);
-            this.N1N2_BYTE = Utils.GetByteSizeFromBitSize(n1 * n2);
-            this.N1_BYTE = Utils.GetByteSizeFromBitSize(n1);
+            mulParam = (n2 + 127) / 128;
+            N_BYTE = Utils.GetByteSizeFromBitSize(n);
+            K_BYTE = k;
+            N_BYTE_64 = Utils.GetByte64SizeFromBitSize(n);
+            K_BYTE_64 = Utils.GetByteSizeFromBitSize(k);
+            N1_BYTE_64 = Utils.GetByteSizeFromBitSize(n1);
+            N1N2_BYTE_64 = Utils.GetByte64SizeFromBitSize(n1 * n2);
+            N1N2_BYTE = Utils.GetByteSizeFromBitSize(n1 * n2);
+            N1_BYTE = Utils.GetByteSizeFromBitSize(n1);
+            
+            RED_MASK = ((1UL << (n % 64)) - 1);
+
+            gfCalculator = new GF2PolynomialCalculator(N_BYTE_64, n, RED_MASK);
         }
 
         /**
@@ -84,11 +96,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             HqcKeccakRandomGenerator secretKeySeedExpander = new HqcKeccakRandomGenerator(256);
             secretKeySeedExpander.SeedExpanderInit(secretKeySeed, secretKeySeed.Length);
 
-            ulong[] xLongBytes = new ulong[N_BYTE_64];
-            int[] yPos = new int[this.w];
+            long[] xLongBytes = new long[N_BYTE_64];
+            long[] yLongBytes = new long[N_BYTE_64];
 
-            GenerateSecretKey(xLongBytes, secretKeySeedExpander, w);
-            GenerateSecretKeyByCoordinates(yPos, secretKeySeedExpander, w);
+            GenerateRandomFixedWeight(xLongBytes, secretKeySeedExpander, w);
+            GenerateRandomFixedWeight(yLongBytes, secretKeySeedExpander, w);
 
             // 2. Randomly generate h
             byte[] publicKeySeed = new byte[SEED_SIZE];
@@ -97,15 +109,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             HqcKeccakRandomGenerator randomPublic = new HqcKeccakRandomGenerator(256);
             randomPublic.SeedExpanderInit(publicKeySeed, publicKeySeed.Length);
 
-            ulong[] hLongBytes = new ulong[N_BYTE_64];
+            long[] hLongBytes = new long[N_BYTE_64];
             GeneratePublicKeyH(hLongBytes, randomPublic);
 
             // 3. Compute s
-            ulong[] s = new ulong[N_BYTE_64];
-            GF2PolynomialCalculator.ModMult(s, yPos, hLongBytes, w, n, N_BYTE_64, we, secretKeySeedExpander);
-            GF2PolynomialCalculator.AddULongs(s, s, xLongBytes);
+            long[] s = new long[N_BYTE_64];
+            gfCalculator.MultLongs(s, yLongBytes, hLongBytes);
+            GF2PolynomialCalculator.AddLongs(s, s, xLongBytes);
             byte[] sBytes = new byte[N_BYTE];
-            Utils.FromULongArrayToByteArray(sBytes, s);
+            Utils.FromLongArrayToByteArray(sBytes, s);
 
             byte[] tmpPk = Arrays.Concatenate(publicKeySeed, sBytes);
             byte[] tmpSk = Arrays.Concatenate(secretKeySeed, tmpPk);
@@ -126,7 +138,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
          * @param pk   public key
          * @param seed seed
          **/
-        public void Encaps(byte[] u, byte[] v, byte[] K, byte[] d, byte[] pk, byte[] seed)
+        public void Encaps(byte[] u, byte[] v, byte[] K, byte[] d, byte[] pk, byte[] seed, byte[] salt)
         {
             // 1. Randomly generate m
             byte[] m = new byte[K_BYTE];
@@ -145,27 +157,33 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
 
             // 2. Generate theta
             byte[] theta = new byte[SHA512_BYTES];
+            byte[] tmp = new byte[K_BYTE + SEED_SIZE + SALT_SIZE_BYTES];
+            randomGenerator.Squeeze(salt, SALT_SIZE_BYTES);
+
+            Array.Copy(m, 0, tmp, 0, m.Length);
+            Array.Copy(pk, 0, tmp, K_BYTE, SEED_SIZE);
+            Array.Copy(salt, 0, tmp, K_BYTE + SEED_SIZE, SALT_SIZE_BYTES);
             HqcKeccakRandomGenerator shakeDigest = new HqcKeccakRandomGenerator(256);
-            shakeDigest.SHAKE256_512_ds(theta, m, m.Length, new byte[] { G_FCT_DOMAIN });
+            shakeDigest.SHAKE256_512_ds(theta, tmp, tmp.Length, new[] { G_FCT_DOMAIN });
 
             // 3. Generate ciphertext c = (u,v)
             // Extract public keys
-            ulong[] h = new ulong[N_BYTE_64];
+            long[] h = new long[N_BYTE_64];
             byte[] s = new byte[N_BYTE];
             ExtractPublicKeys(h, s, pk);
 
-            ulong[] vTmp = new ulong[N1N2_BYTE_64];
+            long[] vTmp = new long[N1N2_BYTE_64];
             Encrypt(u, vTmp, h, s, m, theta);
-            Utils.FromULongArrayToByteArray(v, vTmp);
+            Utils.FromLongArrayToByteArray(v, vTmp);
 
             // 4. Compute d
-            shakeDigest.SHAKE256_512_ds(d, m, m.Length, new byte[] { H_FCT_DOMAIN });
+            shakeDigest.SHAKE256_512_ds(d, m, m.Length, new[] { H_FCT_DOMAIN });
 
             // 5. Compute session key K
             byte[] hashInputK = new byte[K_BYTE + N_BYTE + N1N2_BYTE];
             hashInputK = Arrays.Concatenate(m, u);
             hashInputK = Arrays.Concatenate(hashInputK, v);
-            shakeDigest.SHAKE256_512_ds(K, hashInputK, hashInputK.Length, new byte[] { K_FCT_DOMAIN });
+            shakeDigest.SHAKE256_512_ds(K, hashInputK, hashInputK.Length, new[] { K_FCT_DOMAIN });
         }
 
         /**
@@ -180,46 +198,52 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
         public void Decaps(byte[] ss, byte[] ct, byte[] sk)
         {
             //Extract Y and Public Keys from sk
-            int[] yPos = new int[this.w];
+            long[] x = new long[N_BYTE_64];
+            long[] y = new long[N_BYTE_64];
             byte[] pk = new byte[40 + N_BYTE];
-            ExtractKeysFromSecretKeys(yPos, pk, sk);
+            ExtractKeysFromSecretKeys(x, y, pk, sk);
 
             // Extract u, v, d from ciphertext
             byte[] u = new byte[N_BYTE];
             byte[] v = new byte[N1N2_BYTE];
             byte[] d = new byte[SHA512_BYTES];
-            HqcEngine.ExtractCiphertexts(u, v, d, ct);
+            byte[] salt = new byte[SALT_SIZE_BYTES];
+            ExtractCiphertexts(u, v, d, salt, ct);
 
             // 1. Decrypt -> m'
             byte[] mPrimeBytes = new byte[k];
-            Decrypt(mPrimeBytes, mPrimeBytes, u, v, yPos);
+            Decrypt(mPrimeBytes, mPrimeBytes, u, v, y);
 
             // 2. Compute theta'
             byte[] theta = new byte[SHA512_BYTES];
+            byte[] tmp = new byte[K_BYTE + SALT_SIZE_BYTES + SEED_SIZE];
+            Array.Copy(mPrimeBytes, 0, tmp, 0, mPrimeBytes.Length);
+            Array.Copy(pk, 0, tmp, K_BYTE, SEED_SIZE);
+            Array.Copy(salt, 0, tmp, K_BYTE + SEED_SIZE, SALT_SIZE_BYTES);
             HqcKeccakRandomGenerator shakeDigest = new HqcKeccakRandomGenerator(256);
-            shakeDigest.SHAKE256_512_ds(theta, mPrimeBytes, mPrimeBytes.Length, new byte[] { G_FCT_DOMAIN });
+            shakeDigest.SHAKE256_512_ds(theta, tmp, tmp.Length, new[] { G_FCT_DOMAIN });
 
             // 3. Compute c' = Enc(pk, m', theta')
             // Extract public keys
-            ulong[] h = new ulong[N_BYTE_64];
+            long[] h = new long[N_BYTE_64];
             byte[] s = new byte[N_BYTE];
             ExtractPublicKeys(h, s, pk);
 
             byte[] u2Bytes = new byte[N_BYTE];
             byte[] v2Bytes = new byte[N1N2_BYTE];
-            ulong[] vTmp = new ulong[N1N2_BYTE_64];
+            long[] vTmp = new long[N1N2_BYTE_64];
             Encrypt(u2Bytes, vTmp, h, s, mPrimeBytes, theta);
-            Utils.FromULongArrayToByteArray(v2Bytes, vTmp);
+            Utils.FromLongArrayToByteArray(v2Bytes, vTmp);
 
             // 4. Compute d' = H(m')
             byte[] dPrime = new byte[SHA512_BYTES];
-            shakeDigest.SHAKE256_512_ds(dPrime, mPrimeBytes, mPrimeBytes.Length, new byte[] { H_FCT_DOMAIN });
+            shakeDigest.SHAKE256_512_ds(dPrime, mPrimeBytes, mPrimeBytes.Length, new[] { H_FCT_DOMAIN });
 
             // 5. Compute session key KPrime
             byte[] hashInputK = new byte[K_BYTE + N_BYTE + N1N2_BYTE];
             hashInputK = Arrays.Concatenate(mPrimeBytes, u);
             hashInputK = Arrays.Concatenate(hashInputK, v);
-            shakeDigest.SHAKE256_512_ds(ss, hashInputK, hashInputK.Length, new byte[] { K_FCT_DOMAIN });
+            shakeDigest.SHAKE256_512_ds(ss, hashInputK, hashInputK.Length, new[] { K_FCT_DOMAIN });
 
             int result = 1;
             // Compare u, v, d
@@ -263,63 +287,59 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
          * @param u ciphertext
          * @param v ciphertext
          **/
-        private void Encrypt(byte[] u, ulong[] v, ulong[] h, byte[] s, byte[] m, byte[] theta)
+        private void Encrypt(byte[] u, long[] v, long[] h, byte[] s, byte[] m, byte[] theta)
         {
             // Randomly generate e, r1, r2
             HqcKeccakRandomGenerator randomGenerator = new HqcKeccakRandomGenerator(256);
             randomGenerator.SeedExpanderInit(theta, SEED_SIZE);
-            ulong[] e = new ulong[N_BYTE_64];
-            ulong[] r1 = new ulong[N_BYTE_64];
-            int[] r2 = new int[wr];
-            GenerateSecretKey(r1, randomGenerator, wr);
-            GenerateSecretKeyByCoordinates(r2, randomGenerator, wr);
-            GenerateSecretKey(e, randomGenerator, we);
+            long[] e = new long[N_BYTE_64];
+            long[] r1 = new long[N_BYTE_64];
+            long[] r2 = new long[N_BYTE_64];
+            GenerateRandomFixedWeight(r1, randomGenerator, wr);
+            GenerateRandomFixedWeight(r2, randomGenerator, wr);
+            GenerateRandomFixedWeight(e, randomGenerator, we);
 
             // Calculate u
-            ulong[] uLong = new ulong[N_BYTE_64];
-            GF2PolynomialCalculator.ModMult(uLong, r2, h, wr, n, N_BYTE_64, we, randomGenerator);
-            GF2PolynomialCalculator.AddULongs(uLong, uLong, r1);
-            Utils.FromULongArrayToByteArray(u, uLong);
+            long[] uLong = new long[N_BYTE_64];
+            gfCalculator.MultLongs(uLong, r2, h);
+            GF2PolynomialCalculator.AddLongs(uLong, uLong, r1);
+            Utils.FromLongArrayToByteArray(u, uLong);
 
             // Calculate v
             // encode m
             byte[] res = new byte[n1];
-            ulong[] vLong = new ulong[N1N2_BYTE_64];
-            ulong[] tmpVLong = new ulong[N_BYTE_64];
+            long[] vLong = new long[N1N2_BYTE_64];
+            long[] tmpVLong = new long[N_BYTE_64];
             ReedSolomon.Encode(res, m, K_BYTE * 8, n1, k, g, generatorPoly);
             ReedMuller.Encode(vLong, res, n1, mulParam);
             Array.Copy(vLong, 0, tmpVLong, 0, vLong.Length);
 
             //Compute v
-            ulong[] sLong = new ulong[N_BYTE_64];
-            Utils.FromByteArrayToULongArray(sLong, s);
+            long[] sLong = new long[N_BYTE_64];
+            Utils.FromByteArrayToLongArray(sLong, s);
 
-            ulong[] tmpLong = new ulong[N_BYTE_64];
-            GF2PolynomialCalculator.ModMult(tmpLong, r2, sLong, wr, n, N_BYTE_64, we, randomGenerator);
-            GF2PolynomialCalculator.AddULongs(tmpLong, tmpLong, tmpVLong);
-            GF2PolynomialCalculator.AddULongs(tmpLong, tmpLong, e);
+            long[] tmpLong = new long[N_BYTE_64];
+            gfCalculator.MultLongs(tmpLong, r2, sLong);
+            GF2PolynomialCalculator.AddLongs(tmpLong, tmpLong, tmpVLong);
+            GF2PolynomialCalculator.AddLongs(tmpLong, tmpLong, e);
 
             Utils.ResizeArray(v, n1n2, tmpLong, n, N1N2_BYTE_64, N1N2_BYTE_64);
         }
 
-        private void Decrypt(byte[] output, byte[] m, byte[] u, byte[] v, int[] y)
+        private void Decrypt(byte[] output, byte[] m, byte[] u, byte[] v, long[] y)
         {
-            byte[] tmpSeed = new byte[SEED_SIZE];
-            HqcKeccakRandomGenerator randomGenerator = new HqcKeccakRandomGenerator(256);
-            randomGenerator.SeedExpanderInit(tmpSeed, SEED_SIZE);
-
-            ulong[] uLongs = new ulong[N_BYTE_64];
-            Utils.FromByteArrayToULongArray(uLongs, u);
+            long[] uLongs = new long[N_BYTE_64];
+            Utils.FromByteArrayToLongArray(uLongs, u);
 
-            ulong[] vLongs = new ulong[N1N2_BYTE_64];
-            Utils.FromByteArrayToULongArray(vLongs, v);
+            long[] vLongs = new long[N1N2_BYTE_64];
+            Utils.FromByteArrayToLongArray(vLongs, v);
 
-            ulong[] tmpV = new ulong[N_BYTE_64];
+            long[] tmpV = new long[N_BYTE_64];
             Array.Copy(vLongs, 0, tmpV, 0, vLongs.Length);
 
-            ulong[] tmpLong = new ulong[N_BYTE_64];
-            GF2PolynomialCalculator.ModMult(tmpLong, y, uLongs, w, n, N_BYTE_64, we, randomGenerator);
-            GF2PolynomialCalculator.AddULongs(tmpLong, tmpLong, tmpV);
+            long[] tmpLong = new long[N_BYTE_64];
+            gfCalculator.MultLongs(tmpLong, y, uLongs);
+            GF2PolynomialCalculator.AddLongs(tmpLong, tmpLong, tmpV);
 
             // Decode res
             byte[] tmp = new byte[n1];
@@ -329,70 +349,69 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             Array.Copy(m, 0, output, 0, output.Length);
         }
 
-        private void GenerateSecretKey(ulong[] output, HqcKeccakRandomGenerator random, int w)
+        private void GenerateRandomFixedWeight(long[] output, HqcKeccakRandomGenerator random, int weight)
         {
-            int[] tmp = new int[w];
-            GenerateSecretKeyByCoordinates(tmp, random, w);
+            uint[] rand_u32 = new uint[wr];
+            byte[] rand_bytes = new byte[wr * 4];
+            int[] support = new int[wr];
+            int[] index_tab = new int[wr];
+            long[] bit_tab = new long[wr];
+
+            random.ExpandSeed(rand_bytes, 4 * weight);
+            Pack.LE_To_UInt32(rand_bytes, 0, rand_u32, 0, rand_u32.Length);
 
-            for (int i = 0; i < w; ++i)
+            for (int i = 0; i < weight; i++)
             {
-                int index = tmp[i] / 64;
-                int pos = tmp[i] % 64;
-                ulong t = 1UL << pos;
-                output[index] |= t;
+                support[i] = (int) (i + ((rand_u32[i]&0xFFFFFFFFL) % (n - i)));
             }
-        }
-
-        private void GenerateSecretKeyByCoordinates(int[] output, HqcKeccakRandomGenerator random, int w)
-        {
-            int randomByteSize = 3 * w;
-            byte[] randomBytes = new byte[3 * this.wr];
-            int inc;
 
-            int i = 0;
-            int j = randomByteSize;
-            while (i < w)
+            for (int i = (weight - 1); i >= 0; i--)
             {
-                do
+                int found = 0;
+                for (int j = i + 1; j < weight; j++)
                 {
-                    if (j == randomByteSize)
+                    if (support[j] == support[i])
                     {
-                        random.ExpandSeed(randomBytes, randomByteSize);
-
-                        j = 0;
+                        found |= 1;
                     }
-
-                    output[i] = (randomBytes[j++] & 0xff) << 16;
-                    output[i] |= (randomBytes[j++] & 0xff) << 8;
-                    output[i] |= (randomBytes[j++] & 0xff);
-
                 }
-                while (output[i] >= this.rejectionThreshold);
 
-                output[i] = output[i] % this.n;
-                inc = 1;
-                for (int k = 0; k < i; k++)
+                int mask = -found;
+                support[i] = (mask & i) ^ (~mask & support[i]);
+            }
+
+            for (int i = 0; i < weight; i++)
+            {
+                index_tab[i] = (int)((uint)support[i] >> 6);
+                int pos = support[i] & 0x3f;
+                bit_tab[i] = (1L) << pos;
+            }
+            long val = 0;
+            for (int i = 0; i < N_BYTE_64; i++)
+            {
+                val = 0;
+                for (int j = 0; j < weight; j++)
                 {
-                    if (output[k] == output[i])
-                    {
-                        inc = 0;
-                    }
+                    int tmp = i - index_tab[j];
+                    int val1 = 1 ^ ((int)((uint)(tmp | -tmp) >> 31));
+                    long mask = -val1;
+                    val |= (bit_tab[j] & mask);
                 }
-                i += inc;
+                output[i] |= val;
             }
         }
-
-        void GeneratePublicKeyH(ulong[] output, HqcKeccakRandomGenerator random)
+        
+        void GeneratePublicKeyH(long[] output, HqcKeccakRandomGenerator random)
         {
             byte[] randBytes = new byte[N_BYTE];
             random.ExpandSeed(randBytes, N_BYTE);
-            ulong[] tmp = new ulong[N_BYTE_64];
-            Utils.FromByteArrayToULongArray(tmp, randBytes);
+            long[] tmp = new long[N_BYTE_64];
+            Utils.FromByteArrayToLongArray(tmp, randBytes);
             tmp[N_BYTE_64 - 1] &= Utils.BitMask((ulong)n, 64);
             Array.Copy(tmp, 0, output, 0, output.Length);
         }
 
-        private void ExtractPublicKeys(ulong[] h, byte[] s, byte[] pk)
+        private void ExtractPublicKeys(long[] h, byte[] s, byte[] pk)
         {
             byte[] publicKeySeed = new byte[SEED_SIZE];
             Array.Copy(pk, 0, publicKeySeed, 0, publicKeySeed.Length);
@@ -400,14 +419,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             HqcKeccakRandomGenerator randomPublic = new HqcKeccakRandomGenerator(256);
             randomPublic.SeedExpanderInit(publicKeySeed, publicKeySeed.Length);
 
-            ulong[] hLongBytes = new ulong[N_BYTE_64];
+            long[] hLongBytes = new long[N_BYTE_64];
             GeneratePublicKeyH(hLongBytes, randomPublic);
 
             Array.Copy(hLongBytes, 0, h, 0, h.Length);
             Array.Copy(pk, 40, s, 0, s.Length);
         }
 
-        private void ExtractKeysFromSecretKeys(int[] y, byte[] pk, byte[] sk)
+        private void ExtractKeysFromSecretKeys(long[] x, long[] y, byte[] pk, byte[] sk)
         {
             byte[] secretKeySeed = new byte[SEED_SIZE];
             Array.Copy(sk, 0, secretKeySeed, 0, secretKeySeed.Length);
@@ -415,22 +434,19 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             // Randomly generate secret keys x, y
             HqcKeccakRandomGenerator secretKeySeedExpander = new HqcKeccakRandomGenerator(256);
             secretKeySeedExpander.SeedExpanderInit(secretKeySeed, secretKeySeed.Length);
+            
+            GenerateRandomFixedWeight(x, secretKeySeedExpander, w);
+            GenerateRandomFixedWeight(y, secretKeySeedExpander, w);
 
-            ulong[] xLongBytes = new ulong[N_BYTE_64];
-            int[] yPos = new int[this.w];
-
-            GenerateSecretKey(xLongBytes, secretKeySeedExpander, w);
-            GenerateSecretKeyByCoordinates(yPos, secretKeySeedExpander, w);
-
-            Array.Copy(yPos, 0, y, 0, yPos.Length);
             Array.Copy(sk, SEED_SIZE, pk, 0, pk.Length);
         }
 
-        private static void ExtractCiphertexts(byte[] u, byte[] v, byte[] d, byte[] ct)
+        private static void ExtractCiphertexts(byte[] u, byte[] v, byte[] d, byte[] salt, byte[] ct)
         {
             Array.Copy(ct, 0, u, 0, u.Length);
             Array.Copy(ct, u.Length, v, 0, v.Length);
             Array.Copy(ct, u.Length + v.Length, d, 0, d.Length);
+            Array.Copy(ct, u.Length + v.Length + d.Length, salt, 0, salt.Length);
         }
     }
 }
diff --git a/crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs b/crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs
index 090f5a9c0..3ecbef633 100644
--- a/crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs
+++ b/crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs
@@ -1,5 +1,4 @@
 using System;
-
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Hqc
@@ -60,10 +59,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             {
                 state[i] = 0L;
             }
-            Arrays.Fill(this.dataQueue, 0);
-            this.bitsInQueue = 0;
-            this.squeezing = false;
-            this.fixedOutputLength = (1600 - rate) / 2;
+            Arrays.Fill(dataQueue, 0);
+            bitsInQueue = 0;
+            squeezing = false;
+            fixedOutputLength = (1600 - rate) / 2;
         }
 
         private void KeccakPermutation()
@@ -273,7 +272,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
 
         public void RandomGeneratorInit(byte[] entropyInput, byte[] personalizationString, int entropyLen, int perLen)
         {
-            byte[] domain = new byte[] { 1 };
+            byte[] domain = { 1 };
             KeccakIncAbsorb(entropyInput, entropyLen);
             KeccakIncAbsorb(personalizationString, perLen);
             KeccakIncAbsorb(domain, domain.Length);
@@ -282,7 +281,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
 
         public void SeedExpanderInit(byte[] seed, int seedLen)
         {
-            byte[] domain = new byte[] { 2 };
+            byte[] domain = { 2 };
             KeccakIncAbsorb(seed, seedLen);
             KeccakIncAbsorb(domain, 1);
             KeccakIncFinalize(0x1F);
diff --git a/crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs b/crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs
index 32890f80b..b18c532fa 100644
--- a/crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs
+++ b/crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
 
         public HqcKemExtractor(HqcPrivateKeyParameters privParams)
         {
-            this.key = privParams;
+            key = privParams;
             InitCipher(key.Parameters);
         }
 
diff --git a/crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs b/crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs
index 918dadd38..53f59be16 100644
--- a/crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs
+++ b/crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs
@@ -1,5 +1,4 @@
 using System;
-
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
@@ -11,7 +10,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
         private SecureRandom sr;
         public HqcKemGenerator(SecureRandom random)
         {
-            this.sr = random;
+            sr = random;
         }
 
         public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey)
@@ -23,22 +22,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             byte[] u = new byte[key.Parameters.NBytes];
             byte[] v = new byte[key.Parameters.N1n2Bytes];
             byte[] d = new byte[key.Parameters.Sha512Bytes];
+            byte[] salt = new byte[key.Parameters.SaltSizeBytes];
             byte[] pk = key.PublicKey;
             byte[] seed = new byte[48];
 
             sr.NextBytes(seed);
 
-            engine.Encaps(u, v, K, d, pk, seed);
+            engine.Encaps(u, v, K, d, pk, seed, salt);
 
-            byte[] cipherText = Arrays.Concatenate(u, v);
-            cipherText = Arrays.Concatenate(cipherText, d);
+            byte[] cipherText = Arrays.ConcatenateAll(u, v, d, salt);
 
-            return new HqcKemGenerator.SecretWithEncapsulationImpl(K, cipherText);
+            return new SecretWithEncapsulationImpl(K, cipherText);
         }
 
         private class SecretWithEncapsulationImpl : ISecretWithEncapsulation
         {
-            private volatile bool hasBeenDestroyed = false;
+            private volatile bool hasBeenDestroyed;
 
             private byte[] sessionKey;
             private byte[] cipher_text;
diff --git a/crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs b/crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs
index 243b0d850..50882f432 100644
--- a/crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs
@@ -36,17 +36,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
 
         public void Init(KeyGenerationParameters parameters)
         {
-            this.hqcKeyGenerationParameters = (HqcKeyGenerationParameters)parameters;
-            this.random = parameters.Random;
+            hqcKeyGenerationParameters = (HqcKeyGenerationParameters)parameters;
+            random = parameters.Random;
 
             // get parameters
-            this.n = this.hqcKeyGenerationParameters.Parameters.N;
-            this.k = this.hqcKeyGenerationParameters.Parameters.K;
-            this.delta = this.hqcKeyGenerationParameters.Parameters.Delta;
-            this.w = this.hqcKeyGenerationParameters.Parameters.W;
-            this.wr = this.hqcKeyGenerationParameters.Parameters.Wr;
-            this.we = this.hqcKeyGenerationParameters.Parameters.We;
-            this.N_BYTE = (n + 7) / 8;
+            n = hqcKeyGenerationParameters.Parameters.N;
+            k = hqcKeyGenerationParameters.Parameters.K;
+            delta = hqcKeyGenerationParameters.Parameters.Delta;
+            w = hqcKeyGenerationParameters.Parameters.W;
+            wr = hqcKeyGenerationParameters.Parameters.Wr;
+            we = hqcKeyGenerationParameters.Parameters.We;
+            N_BYTE = (n + 7) / 8;
         }
         private AsymmetricCipherKeyPair GenKeyPair(byte[] seed)
         {
diff --git a/crypto/src/pqc/crypto/hqc/HqcParameters.cs b/crypto/src/pqc/crypto/hqc/HqcParameters.cs
index c397f65b1..d01c6fe9f 100644
--- a/crypto/src/pqc/crypto/hqc/HqcParameters.cs
+++ b/crypto/src/pqc/crypto/hqc/HqcParameters.cs
@@ -6,13 +6,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
         : ICipherParameters
     {
         // 128 bits security
-        public static HqcParameters hqc128 = new HqcParameters("hqc128", 17669, 46, 384, 16, 31, 15, 66, 75, 75, 16767881, 4, new int[] { 89, 69, 153, 116, 176, 117, 111, 75, 73, 233, 242, 233, 65, 210, 21, 139, 103, 173, 67, 118, 105, 210, 174, 110, 74, 69, 228, 82, 255, 181, 1 }, 128);
+        public static HqcParameters hqc128 = new HqcParameters("hqc128", 17669, 46, 384, 16, 31, 15, 66, 75, 75, 16767881, 4, new[] { 89, 69, 153, 116, 176, 117, 111, 75, 73, 233, 242, 233, 65, 210, 21, 139, 103, 173, 67, 118, 105, 210, 174, 110, 74, 69, 228, 82, 255, 181, 1 }, 128);
 
         // 192 bits security
-        public static HqcParameters hqc192 = new HqcParameters("hqc192", 35851, 56, 640, 24, 33, 16, 100, 114, 114, 16742417, 5, new int[] { 45, 216, 239, 24, 253, 104, 27, 40, 107, 50, 163, 210, 227, 134, 224, 158, 119, 13, 158, 1, 238, 164, 82, 43, 15, 232, 246, 142, 50, 189, 29, 232, 1 }, 192);
+        public static HqcParameters hqc192 = new HqcParameters("hqc192", 35851, 56, 640, 24, 33, 16, 100, 114, 114, 16742417, 5, new[] { 45, 216, 239, 24, 253, 104, 27, 40, 107, 50, 163, 210, 227, 134, 224, 158, 119, 13, 158, 1, 238, 164, 82, 43, 15, 232, 246, 142, 50, 189, 29, 232, 1 }, 192);
 
         // 256 bits security
-        public static HqcParameters hqc256 = new HqcParameters("hqc256", 57637, 90, 640, 32, 59, 29, 131, 149, 149, 16772367, 5, new int[] { 49, 167, 49, 39, 200, 121, 124, 91, 240, 63, 148, 71, 150, 123, 87, 101, 32, 215, 159, 71, 201, 115, 97, 210, 186, 183, 141, 217, 123, 12, 31, 243, 180, 219, 152, 239, 99, 141, 4, 246, 191, 144, 8, 232, 47, 27, 141, 178, 130, 64, 124, 47, 39, 188, 216, 48, 199, 187, 1 }, 256);
+        public static HqcParameters hqc256 = new HqcParameters("hqc256", 57637, 90, 640, 32, 59, 29, 131, 149, 149, 16772367, 5, new[] { 49, 167, 49, 39, 200, 121, 124, 91, 240, 63, 148, 71, 150, 123, 87, 101, 32, 215, 159, 71, 201, 115, 97, 210, 186, 183, 141, 217, 123, 12, 31, 243, 180, 219, 152, 239, 99, 141, 4, 246, 191, 144, 8, 232, 47, 27, 141, 178, 130, 64, 124, 47, 39, 188, 216, 48, 199, 187, 1 }, 256);
 
         private string name;
         private int n;
@@ -66,6 +66,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
         public int NBytes => (n + 7) / 8;
         public int N1n2Bytes => (n1 * n2 + 7) / 8;
         public int DefaultKeySize => defaultKeySize;
+        public int SaltSizeBytes => 16;
         internal HqcEngine Engine => hqcEngine;
     }
 }
diff --git a/crypto/src/pqc/crypto/hqc/ReedMuller.cs b/crypto/src/pqc/crypto/hqc/ReedMuller.cs
index 5f1f8e2bf..a39f403e6 100644
--- a/crypto/src/pqc/crypto/hqc/ReedMuller.cs
+++ b/crypto/src/pqc/crypto/hqc/ReedMuller.cs
@@ -1,5 +1,4 @@
 using System;
-
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Hqc
@@ -13,8 +12,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
 
             public Codeword()
             {
-                this.type32 = new int[4];
-                this.type8 = new int[16];
+                type32 = new int[4];
+                type8 = new int[16];
             }
         }
 
@@ -117,7 +116,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             return (int) ((-(b & 1)) & 0xffffffff);
         }
 
-        public static void Encode(ulong[] codeword, byte[] m, int n1, int mulParam)
+        public static void Encode(long[] codeword, byte[] m, int n1, int mulParam)
         {
             byte[] mBytes = Arrays.Clone(m);
 
@@ -147,16 +146,16 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
                 off += 4;
             }
 
-            Utils.FromByte32ArrayToULongArray(codeword, cwd64);
+            Utils.FromByte32ArrayToLongArray(codeword, cwd64);
         }
 
-        public static void Decode(byte[] m, ulong[] codeword, int n1, int mulParam)
+        public static void Decode(byte[] m, long[] codeword, int n1, int mulParam)
         {
             byte[] mBytes = Arrays.Clone(m);
 
             Codeword[] codewordCopy = new Codeword[codeword.Length / 2]; // because each codewordCopy has a 32 bit array size 4
             int[] byteCodeWords = new int[codeword.Length * 2];
-            Utils.FromULongArrayToByte32Array(byteCodeWords, codeword);
+            Utils.FromLongArrayToByte32Array(byteCodeWords, codeword);
 
             for (int i = 0; i < codewordCopy.Length; i++)
             {
@@ -189,7 +188,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
                 Array.Copy(codewordCopy[i].type32, 0, cwd64, off, codewordCopy[i].type32.Length);
                 off += 4;
             }
-            Utils.FromByte32ArrayToULongArray(codeword, cwd64);
+            Utils.FromByte32ArrayToLongArray(codeword, cwd64);
             Array.Copy(mBytes, 0, m, 0, m.Length);
         }
     }
diff --git a/crypto/src/pqc/crypto/hqc/ReedSolomon.cs b/crypto/src/pqc/crypto/hqc/ReedSolomon.cs
index 25a8c7997..4024b0a38 100644
--- a/crypto/src/pqc/crypto/hqc/ReedSolomon.cs
+++ b/crypto/src/pqc/crypto/hqc/ReedSolomon.cs
@@ -1,5 +1,4 @@
 using System;
-
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Hqc
diff --git a/crypto/src/pqc/crypto/hqc/Utils.cs b/crypto/src/pqc/crypto/hqc/Utils.cs
index 4d44db07c..993def057 100644
--- a/crypto/src/pqc/crypto/hqc/Utils.cs
+++ b/crypto/src/pqc/crypto/hqc/Utils.cs
@@ -1,15 +1,14 @@
 using System;
-
 using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Hqc
 {
     internal class Utils
     {
-        internal static void ResizeArray(ulong[] output, int sizeOutBits, ulong[] input, int sizeInBits,
+        internal static void ResizeArray(long[] output, int sizeOutBits, long[] input, int sizeInBits,
             int n1n2ByteSize, int n1n2Byte64Size)
         {
-            ulong mask = 0x7FFFFFFFFFFFFFFFUL;
+            long mask = 0x7FFFFFFFFFFFFFFFL;
             int val = 0;
             if (sizeOutBits < sizeInBits)
             {
@@ -31,12 +30,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             }
         }
 
-        internal static void FromULongArrayToByteArray(byte[] output, ulong[] input)
+        internal static void FromLongArrayToByteArray(byte[] output, long[] input)
         {
             int max = output.Length / 8;
             for (int i = 0; i != max; i++)
             {
-                Pack.UInt64_To_LE(input[i], output, i * 8);
+                Pack.UInt64_To_LE((ulong)input[i], output, i * 8);
             }
 
             if (output.Length % 8 != 0)
@@ -50,13 +49,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             }
         }
 
-        internal static ulong BitMask(ulong a, ulong b)
+        internal static long BitMask(ulong a, ulong b)
         {
             uint tmp = (uint)(a % b);
-            return ((1UL << (int)tmp) - 1);
+            return ((1L << (int)tmp) - 1);
         }
 
-        internal static void FromByteArrayToULongArray(ulong[] output, byte[] input)
+        internal static void FromByteArrayToLongArray(long[] output, byte[] input)
         {
             byte[] tmp = input;
             if (input.Length % 8 != 0)
@@ -68,7 +67,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             int off = 0;
             for (int i = 0; i < output.Length; i++)
             {
-                output[i] = Pack.LE_To_UInt64(tmp, off);
+                output[i] = (long)Pack.LE_To_UInt64(tmp, off);
                 off += 8;
             }
         }
@@ -85,17 +84,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             int off = 0;
             for (int i = 0; i < output.Length; i++)
             {
-                output[i] = (int)Pack.LE_To_UInt16(tmp, off);
+                output[i] = Pack.LE_To_UInt16(tmp, off);
                 off += 2;
             }
         }
 
-        internal static void FromByte32ArrayToULongArray(ulong[] output, int[] input)
+        internal static void FromByte32ArrayToLongArray(long[] output, int[] input)
         {
             for (int i = 0; i != input.Length; i += 2)
             {
                 output[i / 2] = (uint)input[i];
-                output[i / 2] |= (ulong)input[i + 1] << 32;
+                output[i / 2] |= (long)input[i + 1] << 32;
             }
         }
 
@@ -110,7 +109,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
             }
         }
 
-        internal static void FromULongArrayToByte32Array(int[] output, ulong[] input)
+        internal static void FromLongArrayToByte32Array(int[] output, long[] input)
         {
             for (int i = 0; i != input.Length; i++)
             {