Skip to content

Commit 7a324ba

Browse files
committed
HQC perf. opts., refactoring
1 parent 342b20f commit 7a324ba

4 files changed

Lines changed: 76 additions & 78 deletions

File tree

core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GF2PolynomialCalculator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ void addTo(long[] x, long[] z)
2525
Nat.xorTo64(size, x, z);
2626
}
2727

28+
void clear(long[] z)
29+
{
30+
Nat.zero64(size, z);
31+
}
32+
2833
long[] create()
2934
{
3035
return new long[size];

core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCEngine.java

Lines changed: 60 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,16 @@ class HQCEngine
2222
private final int fft;
2323
private final int mulParam;
2424
private final int N_BYTE;
25-
private final int K_BYTE;
2625
private final int N1N2_BYTE_64;
2726
private final int N1N2_BYTE;
2827
private final int[] generatorPoly;
29-
private final int N_MU;
28+
private final int nMu;
3029
private final int pkSize;
3130
private final GF2PolynomialCalculator gf;
3231
private final int rejectionThreshold;
3332
private final int cipherTextBytes;
3433

35-
HQCEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr, int fft, int nmu, int pkSize,
34+
HQCEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr, int fft, int nMu, int pkSize,
3635
int[] generatorPoly)
3736
{
3837
this.n = n;
@@ -44,11 +43,10 @@ class HQCEngine
4443
this.generatorPoly = generatorPoly;
4544
this.g = g;
4645
this.fft = fft;
47-
this.N_MU = nmu;
46+
this.nMu = nMu;
4847
this.pkSize = pkSize;
4948
this.mulParam = n2 >> 7;
5049
this.N_BYTE = Utils.getByteSizeFromBitSize(n);
51-
this.K_BYTE = k;
5250
this.N1N2_BYTE_64 = Utils.getByte64SizeFromBitSize(n1 * n2);
5351
this.N1N2_BYTE = Utils.getByteSizeFromBitSize(n1 * n2);
5452
this.gf = new GF2PolynomialCalculator(n);
@@ -77,10 +75,10 @@ void genKeyPair(byte[] pk, byte[] sk, SecureRandom secureRandom)
7775

7876
secureRandom.nextBytes(seedKem);
7977
Shake256RandomGenerator ctxKem = new Shake256RandomGenerator(seedKem, (byte)1);
80-
System.arraycopy(seedKem, 0, sk, pkSize + SEED_BYTES + K_BYTE, SEED_BYTES);
78+
System.arraycopy(seedKem, 0, sk, pkSize + SEED_BYTES + k, SEED_BYTES);
8179

8280
ctxKem.nextBytes(seedKem);
83-
ctxKem.nextBytes(sk, pkSize + SEED_BYTES, K_BYTE);
81+
ctxKem.nextBytes(sk, pkSize + SEED_BYTES, k);
8482

8583
hashHI(keypairSeed, 512, seedKem, seedKem.length, (byte)2);
8684
ctxKem.init(keypairSeed, 0, SEED_BYTES, (byte)1);
@@ -96,9 +94,9 @@ void genKeyPair(byte[] pk, byte[] sk, SecureRandom secureRandom)
9694
System.arraycopy(keypairSeed, 0, sk, pkSize, SEED_BYTES);
9795
System.arraycopy(pk, 0, sk, 0, pkSize);
9896
Arrays.clear(keypairSeed);
99-
Arrays.clear(xLongBytes);
100-
Arrays.clear(yLongBytes);
101-
Arrays.clear(h);
97+
gf.clear(xLongBytes);
98+
gf.clear(yLongBytes);
99+
gf.clear(h);
102100
}
103101

104102
/**
@@ -112,7 +110,7 @@ void genKeyPair(byte[] pk, byte[] sk, SecureRandom secureRandom)
112110
void encaps(byte[] u, byte[] v, byte[] kTheta, byte[] pk, byte[] salt, SecureRandom secureRandom)
113111
{
114112
// 1. Randomly generate m
115-
byte[] m = new byte[K_BYTE];
113+
byte[] m = new byte[k];
116114
byte[] hashEkKem = new byte[SEED_BYTES];
117115
long[] u64 = gf.create();
118116
long[] v64 = new long[N1N2_BYTE_64];
@@ -125,7 +123,7 @@ void encaps(byte[] u, byte[] v, byte[] kTheta, byte[] pk, byte[] salt, SecureRan
125123
pkeEncrypt(u64, v64, pk, m, kTheta, SEED_BYTES);
126124
Utils.fromLongArrayToByteArray(u, 0, u.length, u64);
127125
Utils.fromLongArrayToByteArray(v, 0, v.length, v64);
128-
Arrays.clear(u64);
126+
gf.clear(u64);
129127
Arrays.clear(v64);
130128
Arrays.clear(m);
131129
Arrays.clear(hashEkKem);
@@ -173,19 +171,19 @@ int decaps(byte[] ss, byte[] ct, byte[] sk)
173171
System.arraycopy(kThetaPrime, 0, ss, 0, 32);
174172
Arrays.fill(cKemPrimeV64, 0L);
175173
pkeEncrypt(cKemPrimeU64, cKemPrimeV64, sk, mPrime, kThetaPrime, 32);
176-
hashGJ(kBar, 256, hashEkKem, sk, pkSize + SEED_BYTES, K_BYTE, ct, 0, ct.length, (byte)3);
174+
hashGJ(kBar, 256, hashEkKem, sk, pkSize + SEED_BYTES, k, ct, 0, ct.length, (byte)3);
177175

178176
int result = (int)(gf.equalTo(u64, cKemPrimeU64) & gf.equalTo(v64, cKemPrimeV64));
179177

180-
for (int i = 0; i < K_BYTE; i++)
178+
for (int i = 0; i < k; i++)
181179
{
182180
ss[i] = (byte)(((ss[i] & result) ^ (kBar[i] & ~result)) & 0xff);
183181
}
184182

185-
Arrays.clear(u64);
186-
Arrays.clear(v64);
187-
Arrays.clear(cKemPrimeU64);
188-
Arrays.clear(cKemPrimeV64);
183+
gf.clear(u64);
184+
gf.clear(v64);
185+
gf.clear(cKemPrimeU64);
186+
gf.clear(cKemPrimeV64);
189187
Arrays.clear(hashEkKem);
190188
Arrays.clear(kThetaPrime);
191189
Arrays.clear(mPrime);
@@ -218,17 +216,16 @@ private void pkeEncrypt(long[] u, long[] v, byte[] ekPke, byte[] m, byte[] theta
218216

219217
vectSampleFixedWeights2(randomGenerator, tmp, wr);// tmp is r1
220218
gf.addTo(tmp, u);
221-
Arrays.clear(e);
222-
Arrays.clear(tmp);
219+
gf.clear(e);
220+
gf.clear(tmp);
223221
Arrays.clear(res);
224222
}
225223

226224
private int barrettReduce(int x)
227225
{
228-
long q = ((long) x * N_MU) >>> 32;
229-
int r = x - (int) (q * n);
230-
r -= (-(((r - n) >>> 31) ^ 1)) & n;
231-
return r;
226+
int q = (int)(((long)x * nMu) >>> 32);
227+
int r = x - n - q * n;
228+
return r + ((r >> 31) & n);
232229
}
233230

234231
private void generateRandomSupport(int[] support, int weight, Shake256RandomGenerator random)
@@ -250,9 +247,9 @@ private void generateRandomSupport(int[] support, int weight, Shake256RandomGene
250247
{
251248
continue;
252249
}
250+
253251
candidate = barrettReduce(candidate);
254252
boolean duplicate = false;
255-
256253
for (int k = 0; k < count; k++)
257254
{
258255
if (support[k] == candidate)
@@ -261,11 +258,12 @@ private void generateRandomSupport(int[] support, int weight, Shake256RandomGene
261258
break;
262259
}
263260
}
264-
265-
if (!duplicate)
261+
if (duplicate)
266262
{
267-
support[count++] = candidate;
263+
continue;
268264
}
265+
266+
support[count++] = candidate;
269267
}
270268
}
271269

@@ -284,69 +282,68 @@ private void writeSupportToVector(long[] v, int[] support, int weight)
284282
for (int j = 0; j < weight; j++)
285283
{
286284
int tmp = i - indexTab[j];
287-
val |= (bitTab[j] & -(1 ^ ((tmp | -tmp) >>> 31)));
285+
val |= bitTab[j] & ~((tmp | -tmp) >> 31);
288286
}
289287
v[i] = val;
290288
}
291289
}
292290

293-
public void vectSampleFixedWeight1(long[] output, Shake256RandomGenerator random, int weight)
291+
private void vectSampleFixedWeight1(long[] output, Shake256RandomGenerator random, int weight)
294292
{
295293
int[] support = new int[wr];
296294
generateRandomSupport(support, weight, random);
297295
writeSupportToVector(output, support, weight);
298296
}
299297

300-
private static void hashHI(byte[] output, int bitLength, byte[] in, int inLen, byte domain)
301-
{
302-
SHA3Digest digest = new SHA3Digest(bitLength);
303-
digest.update(in, 0, inLen);
304-
digest.update(domain);
305-
digest.doFinal(output, 0);
306-
}
307-
308-
private void hashGJ(byte[] output, int bitLength, byte[] hashEkKem, byte[] mOrSigma, int mOrSigmaOff,
309-
int mOrSigmaLen, byte[] saltOrCt, int saltOrCtOff, int saltOrCtOffLen, byte domain)
310-
{
311-
SHA3Digest digest = new SHA3Digest(bitLength);
312-
digest.update(hashEkKem, 0, hashEkKem.length);
313-
digest.update(mOrSigma, mOrSigmaOff, mOrSigmaLen);
314-
digest.update(saltOrCt, saltOrCtOff, saltOrCtOffLen);
315-
digest.update(domain);
316-
digest.doFinal(output, 0);
317-
}
318-
319298
private void vectSampleFixedWeights2(Shake256RandomGenerator generator, long[] v, int weight)
320299
{
321-
int[] support = new int[wr];
322300
byte[] rand = new byte[wr << 2];
323301
generator.xofGetBytes(rand, rand.length);
302+
303+
int[] support = new int[wr];
324304
Pack.littleEndianToInt(rand, 0, support);
325-
for (int i = 0; i < weight; ++i)
326-
{
327-
support[i] = i + (int) (((support[i] & 0xFFFFFFFFL) * (n - i)) >> 32);
328-
}
329305

330-
for (int i = weight - 1; i-- > 0;)
306+
int i = weight;
307+
while (--i >= 0)
331308
{
332-
int found = 0;
309+
int support_i = i + (int)(((support[i] & 0xFFFFFFFFL) * (n - i)) >> 32);
310+
int notFound = -1;
333311
for (int j = i + 1; j < weight; ++j)
334312
{
335-
found |= compareU32(support[j], support[i]);
313+
notFound &= cdiff(support_i, support[j]);
336314
}
337-
found = -found;
338-
support[i] = (found & i) ^ (~found & support[i]);
315+
support[i] = (~notFound & i) ^ (notFound & support_i);
339316
}
317+
340318
writeSupportToVector(v, support, weight);
341319
}
342320

343-
private static int compareU32(int v1, int v2)
321+
private void vectTruncate(long[] v)
344322
{
345-
return 1 ^ (((v1 - v2) | (v2 - v1)) >>> 31);
323+
Arrays.fill(v, N1N2_BYTE_64, (n + 63) >> 6, 0L);
346324
}
347325

348-
private void vectTruncate(long[] v)
326+
private static int cdiff(int v1, int v2)
349327
{
350-
Arrays.fill(v, N1N2_BYTE_64, (n + 63) >> 6, 0L);
328+
return ((v1 - v2) | (v2 - v1)) >> 31;
329+
}
330+
331+
private static void hashGJ(byte[] output, int bitLength, byte[] hashEkKem, byte[] mOrSigma, int mOrSigmaOff,
332+
int mOrSigmaLen, byte[] saltOrCt, int saltOrCtOff, int saltOrCtOffLen, byte domain)
333+
{
334+
SHA3Digest digest = new SHA3Digest(bitLength);
335+
digest.update(hashEkKem, 0, hashEkKem.length);
336+
digest.update(mOrSigma, mOrSigmaOff, mOrSigmaLen);
337+
digest.update(saltOrCt, saltOrCtOff, saltOrCtOffLen);
338+
digest.update(domain);
339+
digest.doFinal(output, 0);
340+
}
341+
342+
private static void hashHI(byte[] output, int bitLength, byte[] in, int inLen, byte domain)
343+
{
344+
SHA3Digest digest = new SHA3Digest(bitLength);
345+
digest.update(in, 0, inLen);
346+
digest.update(domain);
347+
digest.doFinal(output, 0);
351348
}
352349
}

core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedMuller.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,15 @@ private static void expandThenSum(int[] desCode, Codeword[] srcCode, int off, in
6262

6363
for (int i = 1; i < mulParam; i++)
6464
{
65+
int[] type32 = srcCode[off + i].type32;
6566
for (int j = 0; j < 4; j++)
6667
{
6768
for (int k = 0; k < 32; k++)
6869
{
69-
desCode[j * 32 + k] += srcCode[i + off].type32[j] >> k & 1;
70-
70+
desCode[j * 32 + k] += type32[j] >> k & 1;
7171
}
7272
}
7373
}
74-
7574
}
7675

7776
private static int findPeaks(int[] input)
@@ -95,10 +94,9 @@ private static int findPeaks(int[] input)
9594
return peakPos;
9695
}
9796

98-
9997
private static int Bit0Mask(int b)
10098
{
101-
return (-(b & 1));
99+
return -(b & 1);
102100
}
103101

104102
public static void encode(long[] codeword, byte[] m, int n1, int mulParam)

core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedSolomon.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ private static int computeELP(int[] sigma, int[] syndromes, int delta)
111111
int degSigmaP = 0;
112112
int[] sigmaDup = new int[delta + 1];
113113
int[] sigmaP = new int[delta + 1];
114-
int degSigmaDup;
115114
int pp = Utils.toUnsigned16Bits(-1);
116115
int dp = 1;
117116
int d = syndromes[0];
@@ -121,7 +120,7 @@ private static int computeELP(int[] sigma, int[] syndromes, int delta)
121120
for (int i = 0; i < 2 * delta; i++)
122121
{
123122
System.arraycopy(sigma, 0, sigmaDup, 0, delta + 1);
124-
degSigmaDup = degSigma;
123+
int degSigmaDup = degSigma;
125124
int dd = GFCalculator.div(d, dp);
126125

127126
for (int j = 1; j <= i + 1 && j <= delta; j++)
@@ -190,20 +189,19 @@ private static void computeErrors(int[] res, int[] zx, byte[] errorCompactSet, i
190189
int[] betaSet = new int[delta];
191190
int[] eSet = new int[delta];
192191

193-
int deltaCount = 0, deltaVal, mask1;
192+
int deltaCount1 = 0;
194193
for (int i = 0; i < n1; i++)
195194
{
196195
int mark = 0;
197196
int mask = errorCompactSet[i] != 0 ? 0xffff : 0;
198197
for (int j = 0; j < delta; j++)
199198
{
200-
int iMask = j == deltaCount ? 0xffff : 0;
199+
int iMask = j == deltaCount1 ? 0xffff : 0;
201200
betaSet[j] += iMask & mask & expArrays[i];
202201
mark += iMask & mask & 1;
203202
}
204-
deltaCount += mark;
203+
deltaCount1 += mark;
205204
}
206-
deltaVal = deltaCount;
207205

208206
for (int i = 0; i < delta; i++)
209207
{
@@ -223,23 +221,23 @@ private static void computeErrors(int[] res, int[] zx, byte[] errorCompactSet, i
223221
temp2 = GFCalculator.mul(temp2, 1 ^ GFCalculator.mul(inv, betaSet[(i + j) % delta]));
224222
}
225223

226-
mask1 = i < deltaVal ? 0xffff : 0;
224+
int mask1 = i < deltaCount1 ? 0xffff : 0;
227225
eSet[i] = mask1 & GFCalculator.div(temp1, temp2);
228226
}
229227

230-
deltaCount = 0;
228+
int deltaCount2 = 0;
231229
for (int i = 0; i < n1; i++)
232230
{
233231
int mark = 0;
234232
int mask = errorCompactSet[i] != 0 ? 0xffff : 0;
235233

236234
for (int j = 0; j < delta; j++)
237235
{
238-
int iMask = j == deltaCount ? 0xffff : 0;
236+
int iMask = j == deltaCount2 ? 0xffff : 0;
239237
res[i] += iMask & mask & eSet[j];
240238
mark += iMask & mask & 1;
241239
}
242-
deltaCount += mark;
240+
deltaCount2 += mark;
243241
}
244242
}
245243
}

0 commit comments

Comments
 (0)