22
33import org .bouncycastle .util .Arrays ;
44import org .bouncycastle .util .Pack ;
5+ import org .bouncycastle .util .encoders .Hex ;
56
67class HQCEngine
78{
@@ -20,8 +21,7 @@ class HQCEngine
2021
2122 private int SEED_SIZE = 40 ;
2223 private byte G_FCT_DOMAIN = 3 ;
23- private byte H_FCT_DOMAIN = 4 ;
24- private byte K_FCT_DOMAIN = 5 ;
24+ private byte K_FCT_DOMAIN = 4 ;
2525
2626 private int N_BYTE ;
2727 private int n1n2 ;
@@ -87,10 +87,12 @@ public void genKeyPair(byte[] pk, byte[] sk, byte[] seed)
8787 {
8888 // Randomly generate seeds for secret keys and public keys
8989 byte [] secretKeySeed = new byte [SEED_SIZE ];
90+ byte [] sigma = new byte [K_BYTE ];
9091
9192 KeccakRandomGenerator randomGenerator = new KeccakRandomGenerator (256 );
9293 randomGenerator .randomGeneratorInit (seed , null , seed .length , 0 );
9394 randomGenerator .squeeze (secretKeySeed , 40 );
95+ randomGenerator .squeeze (sigma , K_BYTE );
9496
9597 // 1. Randomly generate secret keys x, y
9698 KeccakRandomGenerator secretKeySeedExpander = new KeccakRandomGenerator (256 );
@@ -99,8 +101,8 @@ public void genKeyPair(byte[] pk, byte[] sk, byte[] seed)
99101 long [] xLongBytes = new long [N_BYTE_64 ];
100102 long [] yLongBytes = new long [N_BYTE_64 ];
101103
102- generateRandomFixedWeight (xLongBytes , secretKeySeedExpander , w );
103104 generateRandomFixedWeight (yLongBytes , secretKeySeedExpander , w );
105+ generateRandomFixedWeight (xLongBytes , secretKeySeedExpander , w );
104106
105107 // 2. Randomly generate h
106108 byte [] publicKeySeed = new byte [SEED_SIZE ];
@@ -120,7 +122,7 @@ public void genKeyPair(byte[] pk, byte[] sk, byte[] seed)
120122 Utils .fromLongArrayToByteArray (sBytes , s );
121123
122124 byte [] tmpPk = Arrays .concatenate (publicKeySeed , sBytes );
123- byte [] tmpSk = Arrays .concatenate (secretKeySeed , tmpPk );
125+ byte [] tmpSk = Arrays .concatenate (secretKeySeed , sigma , tmpPk );
124126
125127 System .arraycopy (tmpPk , 0 , pk , 0 , tmpPk .length );
126128 System .arraycopy (tmpSk , 0 , sk , 0 , tmpSk .length );
@@ -133,12 +135,11 @@ public void genKeyPair(byte[] pk, byte[] sk, byte[] seed)
133135 *
134136 * @param u u
135137 * @param v v
136- * @param d d
137138 * @param K session key
138139 * @param pk public key
139140 * @param seed seed
140141 **/
141- public void encaps (byte [] u , byte [] v , byte [] K , byte [] d , byte [] pk , byte [] seed , byte [] salt )
142+ public void encaps (byte [] u , byte [] v , byte [] K , byte [] pk , byte [] seed , byte [] salt )
142143 {
143144 // 1. Randomly generate m
144145 byte [] m = new byte [K_BYTE ];
@@ -148,6 +149,9 @@ public void encaps(byte[] u, byte[] v, byte[] K, byte[] d, byte[] pk, byte[] see
148149 randomGenerator .randomGeneratorInit (seed , null , seed .length , 0 );
149150 randomGenerator .squeeze (secretKeySeed , 40 );
150151
152+ byte [] sigma = new byte [K_BYTE ];
153+ randomGenerator .squeeze (sigma , K_BYTE );
154+
151155 byte [] publicKeySeed = new byte [SEED_SIZE ];
152156 randomGenerator .squeeze (publicKeySeed , 40 );
153157
@@ -156,12 +160,12 @@ public void encaps(byte[] u, byte[] v, byte[] K, byte[] d, byte[] pk, byte[] see
156160
157161 // 2. Generate theta
158162 byte [] theta = new byte [SHA512_BYTES ];
159- byte [] tmp = new byte [K_BYTE + SEED_SIZE + SALT_SIZE_BYTES ];
163+ byte [] tmp = new byte [K_BYTE + ( SALT_SIZE_BYTES * 2 ) + SALT_SIZE_BYTES ];
160164 randomGenerator .squeeze (salt , SALT_SIZE_BYTES );
161165
162166 System .arraycopy (m , 0 , tmp , 0 , m .length );
163- System .arraycopy (pk , 0 , tmp , K_BYTE , SEED_SIZE );
164- System .arraycopy (salt , 0 , tmp , K_BYTE + SEED_SIZE , SALT_SIZE_BYTES );
167+ System .arraycopy (pk , 0 , tmp , K_BYTE , SALT_SIZE_BYTES * 2 );
168+ System .arraycopy (salt , 0 , tmp , K_BYTE + ( SALT_SIZE_BYTES * 2 ) , SALT_SIZE_BYTES );
165169 KeccakRandomGenerator shakeDigest = new KeccakRandomGenerator (256 );
166170 shakeDigest .SHAKE256_512_ds (theta , tmp , tmp .length , new byte []{G_FCT_DOMAIN });
167171
@@ -176,13 +180,8 @@ public void encaps(byte[] u, byte[] v, byte[] K, byte[] d, byte[] pk, byte[] see
176180
177181 Utils .fromLongArrayToByteArray (v , vTmp );
178182
179- // 4. Compute d
180- shakeDigest .SHAKE256_512_ds (d , m , m .length , new byte []{H_FCT_DOMAIN });
181-
182183 // 5. Compute session key K
183- byte [] hashInputK = new byte [K_BYTE + N_BYTE + N1N2_BYTE ];
184- hashInputK = Arrays .concatenate (m , u );
185- hashInputK = Arrays .concatenate (hashInputK , v );
184+ byte [] hashInputK = Arrays .concatenate (m , u , v );
186185 shakeDigest .SHAKE256_512_ds (K , hashInputK , hashInputK .length , new byte []{K_FCT_DOMAIN });
187186 }
188187
@@ -194,32 +193,32 @@ public void encaps(byte[] u, byte[] v, byte[] K, byte[] d, byte[] pk, byte[] see
194193 * @param ss session key
195194 * @param ct ciphertext
196195 * @param sk secret key
196+ * @return 0 if decapsulation is successful, -1 otherwise
197197 **/
198- public void decaps (byte [] ss , byte [] ct , byte [] sk )
198+ public int decaps (byte [] ss , byte [] ct , byte [] sk )
199199 {
200200 //Extract Y and Public Keys from sk
201- long [] x = new long [N_BYTE_64 ];
202201 long [] y = new long [N_BYTE_64 ];
203202 byte [] pk = new byte [40 + N_BYTE ];
204- extractKeysFromSecretKeys (x , y , pk , sk );
203+ byte [] sigma = new byte [K_BYTE ];
204+ extractKeysFromSecretKeys (y , sigma , pk , sk );
205205
206206 // Extract u, v, d from ciphertext
207207 byte [] u = new byte [N_BYTE ];
208208 byte [] v = new byte [N1N2_BYTE ];
209- byte [] d = new byte [SHA512_BYTES ];
210209 byte [] salt = new byte [SALT_SIZE_BYTES ];
211- extractCiphertexts (u , v , d , salt , ct );
210+ extractCiphertexts (u , v , salt , ct );
212211
213212 // 1. Decrypt -> m'
214213 byte [] mPrimeBytes = new byte [k ];
215- decrypt (mPrimeBytes , mPrimeBytes , u , v , y );
214+ int result = decrypt (mPrimeBytes , mPrimeBytes , sigma , u , v , y );
216215
217216 // 2. Compute theta'
218217 byte [] theta = new byte [SHA512_BYTES ];
219- byte [] tmp = new byte [K_BYTE + SALT_SIZE_BYTES + SEED_SIZE ];
218+ byte [] tmp = new byte [K_BYTE + ( SALT_SIZE_BYTES * 2 ) + SALT_SIZE_BYTES ];
220219 System .arraycopy (mPrimeBytes , 0 , tmp , 0 , mPrimeBytes .length );
221- System .arraycopy (pk , 0 , tmp , K_BYTE , SEED_SIZE );
222- System .arraycopy (salt , 0 , tmp , K_BYTE + SEED_SIZE , SALT_SIZE_BYTES );
220+ System .arraycopy (pk , 0 , tmp , K_BYTE , SALT_SIZE_BYTES * 2 );
221+ System .arraycopy (salt , 0 , tmp , K_BYTE + ( SALT_SIZE_BYTES * 2 ) , SALT_SIZE_BYTES );
223222
224223 KeccakRandomGenerator shakeDigest = new KeccakRandomGenerator (256 );
225224 shakeDigest .SHAKE256_512_ds (theta , tmp , tmp .length , new byte []{G_FCT_DOMAIN });
@@ -236,40 +235,32 @@ public void decaps(byte[] ss, byte[] ct, byte[] sk)
236235 encrypt (u2Bytes , vTmp , h , s , mPrimeBytes , theta );
237236 Utils .fromLongArrayToByteArray (v2Bytes , vTmp );
238237
239- // 4. Compute d' = H(m')
240- byte [] dPrime = new byte [SHA512_BYTES ];
241- shakeDigest .SHAKE256_512_ds (dPrime , mPrimeBytes , mPrimeBytes .length , new byte []{H_FCT_DOMAIN });
242-
243238 // 5. Compute session key KPrime
244239 byte [] hashInputK = new byte [K_BYTE + N_BYTE + N1N2_BYTE ];
245- hashInputK = Arrays .concatenate (mPrimeBytes , u );
246- hashInputK = Arrays .concatenate (hashInputK , v );
247- shakeDigest .SHAKE256_512_ds (ss , hashInputK , hashInputK .length , new byte []{K_FCT_DOMAIN });
248240
249- int result = 1 ;
250241 // Compare u, v, d
251242 if (!Arrays .constantTimeAreEqual (u , u2Bytes ))
252243 {
253- result = 0 ;
244+ result = 1 ;
254245 }
255246
256247 if (!Arrays .constantTimeAreEqual (v , v2Bytes ))
257248 {
258- result = 0 ;
249+ result = 1 ;
259250 }
260251
261- if (!Arrays .constantTimeAreEqual (d , dPrime ))
252+ result -= 1 ;
253+
254+ for (int i = 0 ; i < K_BYTE ; i ++)
262255 {
263- result = 0 ;
256+ hashInputK [ i ] = ( byte )((( mPrimeBytes [ i ] & result ) ^ ( sigma [ i ] & ~ result )) & 0xff ) ;
264257 }
258+ System .arraycopy (u , 0 , hashInputK , K_BYTE , N_BYTE );
259+ System .arraycopy (v , 0 , hashInputK , K_BYTE + N_BYTE , N1N2_BYTE );
265260
266- if (result == 0 )
267- { //abort
268- for (int i = 0 ; i < getSessionKeySize (); i ++)
269- {
270- ss [i ] = 0 ;
271- }
272- }
261+ shakeDigest .SHAKE256_512_ds (ss , hashInputK , hashInputK .length , new byte []{K_FCT_DOMAIN });
262+
263+ return -result ;
273264 }
274265
275266 int getSessionKeySize ()
@@ -296,9 +287,9 @@ private void encrypt(byte[] u, long[] v, long[] h, byte[] s, byte[] m, byte[] th
296287 long [] e = new long [N_BYTE_64 ];
297288 long [] r1 = new long [N_BYTE_64 ];
298289 long [] r2 = new long [N_BYTE_64 ];
299- generateRandomFixedWeight (r1 , randomGenerator , wr );
300290 generateRandomFixedWeight (r2 , randomGenerator , wr );
301291 generateRandomFixedWeight (e , randomGenerator , we );
292+ generateRandomFixedWeight (r1 , randomGenerator , wr );
302293
303294 // Calculate u
304295 long [] uLong = new long [N_BYTE_64 ];
@@ -327,7 +318,7 @@ private void encrypt(byte[] u, long[] v, long[] h, byte[] s, byte[] m, byte[] th
327318 Utils .resizeArray (v , n1n2 , tmpLong , n , N1N2_BYTE_64 , N1N2_BYTE_64 );
328319 }
329320
330- private void decrypt (byte [] output , byte [] m , byte [] u , byte [] v , long [] y )
321+ private int decrypt (byte [] output , byte [] m , byte [] sigma , byte [] u , byte [] v , long [] y )
331322 {
332323 long [] uLongs = new long [N_BYTE_64 ];
333324 Utils .fromByteArrayToLongArray (uLongs , u );
@@ -348,6 +339,7 @@ private void decrypt(byte[] output, byte[] m, byte[] u, byte[] v, long[] y)
348339 ReedSolomon .decode (m , tmp , n1 , fft , delta , k , g );
349340
350341 System .arraycopy (m , 0 , output , 0 , output .length );
342+ return 0 ;
351343 }
352344
353345 private void generateRandomFixedWeight (long [] output , KeccakRandomGenerator random , int weight )
@@ -427,26 +419,25 @@ private void extractPublicKeys(long[] h, byte[] s, byte[] pk)
427419 System .arraycopy (pk , 40 , s , 0 , s .length );
428420 }
429421
430- private void extractKeysFromSecretKeys (long [] x , long [] y , byte [] pk , byte [] sk )
422+ private void extractKeysFromSecretKeys (long [] y , byte [] sigma , byte [] pk , byte [] sk )
431423 {
432424 byte [] secretKeySeed = new byte [SEED_SIZE ];
433425 System .arraycopy (sk , 0 , secretKeySeed , 0 , secretKeySeed .length );
426+ System .arraycopy (sk , SEED_SIZE , sigma , 0 , K_BYTE );
434427
435428 // Randomly generate secret keys x, y
436429 KeccakRandomGenerator secretKeySeedExpander = new KeccakRandomGenerator (256 );
437430 secretKeySeedExpander .seedExpanderInit (secretKeySeed , secretKeySeed .length );
438431
439- generateRandomFixedWeight (x , secretKeySeedExpander , w );
440432 generateRandomFixedWeight (y , secretKeySeedExpander , w );
441433
442- System .arraycopy (sk , SEED_SIZE , pk , 0 , pk .length );
434+ System .arraycopy (sk , SEED_SIZE + K_BYTE , pk , 0 , pk .length );
443435 }
444436
445- private void extractCiphertexts (byte [] u , byte [] v , byte [] d , byte [] salt , byte [] ct )
437+ private void extractCiphertexts (byte [] u , byte [] v , byte [] salt , byte [] ct )
446438 {
447439 System .arraycopy (ct , 0 , u , 0 , u .length );
448440 System .arraycopy (ct , u .length , v , 0 , v .length );
449- System .arraycopy (ct , u .length + v .length , d , 0 , d .length );
450- System .arraycopy (ct , u .length + v .length + d .length , salt , 0 , salt .length );
441+ System .arraycopy (ct , u .length + v .length , salt , 0 , salt .length );
451442 }
452443}
0 commit comments