Skip to content

Commit 98409a8

Browse files
author
gefeili
committed
Refactor on Snova
1 parent e23335e commit 98409a8

File tree

6 files changed

+1226
-69
lines changed

6 files changed

+1226
-69
lines changed

core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,4 +451,53 @@ public interface BCObjectIdentifiers
451451
ASN1ObjectIdentifier mayo2 = mayo.branch("2");
452452
ASN1ObjectIdentifier mayo3 = mayo.branch("3");
453453
ASN1ObjectIdentifier mayo5 = mayo.branch("4");
454+
455+
/**
456+
* Snova
457+
*/
458+
ASN1ObjectIdentifier snova = bc_sig.branch("11");
459+
ASN1ObjectIdentifier snova_24_5_4_ssk = snova.branch("1");
460+
ASN1ObjectIdentifier snova_24_5_4_esk = snova.branch("2");
461+
ASN1ObjectIdentifier snova_24_5_4_shake_ssk = snova.branch("3");
462+
ASN1ObjectIdentifier snova_24_5_4_shake_esk = snova.branch("4");
463+
ASN1ObjectIdentifier snova_24_5_5_ssk = snova.branch("5");
464+
ASN1ObjectIdentifier snova_24_5_5_esk = snova.branch("6");
465+
ASN1ObjectIdentifier snova_24_5_5_shake_ssk = snova.branch("7");
466+
ASN1ObjectIdentifier snova_24_5_5_shake_esk = snova.branch("8");
467+
ASN1ObjectIdentifier snova_25_8_3_ssk = snova.branch("9");
468+
ASN1ObjectIdentifier snova_25_8_3_esk = snova.branch("10");
469+
ASN1ObjectIdentifier snova_25_8_3_shake_ssk = snova.branch("11");
470+
ASN1ObjectIdentifier snova_25_8_3_shake_esk = snova.branch("12");
471+
ASN1ObjectIdentifier snova_29_6_5_ssk = snova.branch("13");
472+
ASN1ObjectIdentifier snova_29_6_5_esk = snova.branch("14");
473+
ASN1ObjectIdentifier snova_29_6_5_shake_ssk = snova.branch("15");
474+
ASN1ObjectIdentifier snova_29_6_5_shake_esk = snova.branch("16");
475+
ASN1ObjectIdentifier snova_37_8_4_ssk = snova.branch("17");
476+
ASN1ObjectIdentifier snova_37_8_4_esk = snova.branch("18");
477+
ASN1ObjectIdentifier snova_37_8_4_shake_ssk = snova.branch("19");
478+
ASN1ObjectIdentifier snova_37_8_4_shake_esk = snova.branch("20");
479+
ASN1ObjectIdentifier snova_37_17_2_ssk = snova.branch("21");
480+
ASN1ObjectIdentifier snova_37_17_2_esk = snova.branch("22");
481+
ASN1ObjectIdentifier snova_37_17_2_shake_ssk = snova.branch("23");
482+
ASN1ObjectIdentifier snova_37_17_2_shake_esk = snova.branch("24");
483+
ASN1ObjectIdentifier snova_49_11_3_ssk = snova.branch("25");
484+
ASN1ObjectIdentifier snova_49_11_3_esk = snova.branch("26");
485+
ASN1ObjectIdentifier snova_49_11_3_shake_ssk = snova.branch("27");
486+
ASN1ObjectIdentifier snova_49_11_3_shake_esk = snova.branch("28");
487+
ASN1ObjectIdentifier snova_56_25_2_ssk = snova.branch("29");
488+
ASN1ObjectIdentifier snova_56_25_2_esk = snova.branch("30");
489+
ASN1ObjectIdentifier snova_56_25_2_shake_ssk = snova.branch("31");
490+
ASN1ObjectIdentifier snova_56_25_2_shake_esk = snova.branch("32");
491+
ASN1ObjectIdentifier snova_60_10_4_ssk = snova.branch("33");
492+
ASN1ObjectIdentifier snova_60_10_4_esk = snova.branch("34");
493+
ASN1ObjectIdentifier snova_60_10_4_shake_ssk = snova.branch("35");
494+
ASN1ObjectIdentifier snova_60_10_4_shake_esk = snova.branch("36");
495+
ASN1ObjectIdentifier snova_66_15_3_ssk = snova.branch("37");
496+
ASN1ObjectIdentifier snova_66_15_3_esk = snova.branch("38");
497+
ASN1ObjectIdentifier snova_66_15_3_shake_ssk = snova.branch("39");
498+
ASN1ObjectIdentifier snova_66_15_3_shake_esk = snova.branch("40");
499+
ASN1ObjectIdentifier snova_75_33_2_ssk = snova.branch("41");
500+
ASN1ObjectIdentifier snova_75_33_2_esk = snova.branch("42");
501+
ASN1ObjectIdentifier snova_75_33_2_shake_ssk = snova.branch("43");
502+
ASN1ObjectIdentifier snova_75_33_2_shake_esk = snova.branch("44");
454503
}

core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
class GF16Utils
66
{
7-
public static void encodeMergeInHalf(byte[] m, int mlen, byte[] menc)
7+
static void encodeMergeInHalf(byte[] m, int mlen, byte[] menc)
88
{
99
int i, half = (mlen + 1) >>> 1;
1010
// Process pairs of 4-bit values
@@ -19,7 +19,7 @@ public static void encodeMergeInHalf(byte[] m, int mlen, byte[] menc)
1919
}
2020
}
2121

22-
public static void decodeMergeInHalf(byte[] byteArray, byte[] gf16Array, int nGf16)
22+
static void decodeMergeInHalf(byte[] byteArray, byte[] gf16Array, int nGf16)
2323
{
2424
int i, half = (nGf16 + 1) >>> 1;
2525
// Process pairs of 4-bit values
@@ -30,15 +30,15 @@ public static void decodeMergeInHalf(byte[] byteArray, byte[] gf16Array, int nGf
3030
}
3131
}
3232

33-
public static void gf16mTranMulMul(byte[] sign, byte[] a, byte[] b, byte[] q1, byte[] q2, byte[] tmp,
34-
byte[] left, byte[] right, int rank)
33+
static void gf16mTranMulMul(byte[] sign, int signOff, byte[] a, byte[] b, byte[] q1, byte[] q2, byte[] tmp,
34+
byte[] left, byte[] right, int rank)
3535
{
3636
for (int i = 0, leftOff = 0, dOff = 0; i < rank; i++, leftOff += rank)
3737
{
3838
for (int j = 0; j < rank; j++)
3939
{
4040
byte result = 0;
41-
for (int k = 0, aOff = j, bOff = i; k < rank; ++k, aOff += rank, bOff += rank)
41+
for (int k = 0, aOff = signOff + j, bOff = i; k < rank; ++k, aOff += rank, bOff += rank)
4242
{
4343
result ^= GF16.mul(sign[aOff], q1[bOff]);
4444
}
@@ -56,7 +56,7 @@ public static void gf16mTranMulMul(byte[] sign, byte[] a, byte[] b, byte[] q1, b
5656
}
5757
for (int j = 0; j < rank; j++)
5858
{
59-
tmp[j] = GF16.innerProduct(q2, leftOff, sign, j, rank);
59+
tmp[j] = GF16.innerProduct(q2, leftOff, sign, signOff + j, rank);
6060
}
6161

6262
for (int j = 0; j < rank; j++)
@@ -67,7 +67,7 @@ public static void gf16mTranMulMul(byte[] sign, byte[] a, byte[] b, byte[] q1, b
6767
}
6868

6969
// tmp = a * b, d = tmp * c -> d = (a * b) * c
70-
public static void gf16mMulMul(byte[] a, byte[] b, byte[] c, byte[] tmp, byte[] d, int rank)
70+
static void gf16mMulMul(byte[] a, byte[] b, byte[] c, byte[] tmp, byte[] d, int rank)
7171
{
7272
for (int i = 0, leftOff = 0, dOff = 0; i < rank; i++, leftOff += rank)
7373
{
@@ -83,7 +83,7 @@ public static void gf16mMulMul(byte[] a, byte[] b, byte[] c, byte[] tmp, byte[]
8383
}
8484
}
8585

86-
public static void gf16mMul(byte[] a, byte[] b, byte[] c, int rank)
86+
static void gf16mMul(byte[] a, byte[] b, byte[] c, int rank)
8787
{
8888
for (int i = 0, aOff = 0, cOff = 0; i < rank; i++, aOff += rank)
8989
{
@@ -94,7 +94,7 @@ public static void gf16mMul(byte[] a, byte[] b, byte[] c, int rank)
9494
}
9595
}
9696

97-
public static void gf16mMulMulTo(byte[] a, byte[] b, byte[] c, byte[] tmp, byte[] d, int rank)
97+
static void gf16mMulMulTo(byte[] a, byte[] b, byte[] c, byte[] tmp, byte[] d, int rank)
9898
{
9999
for (int i = 0, leftOff = 0, dOff = 0; i < rank; i++, leftOff += rank)
100100
{
@@ -110,7 +110,7 @@ public static void gf16mMulMulTo(byte[] a, byte[] b, byte[] c, byte[] tmp, byte[
110110
}
111111
}
112112

113-
public static void gf16mMulTo(byte[] a, byte[] b, byte[] c, int rank)
113+
static void gf16mMulTo(byte[] a, byte[] b, byte[] c, int rank)
114114
{
115115
for (int i = 0, aOff = 0, cOff = 0; i < rank; i++, aOff += rank)
116116
{
@@ -122,7 +122,7 @@ public static void gf16mMulTo(byte[] a, byte[] b, byte[] c, int rank)
122122
}
123123

124124
// d = a * b, e = b * c
125-
public static void gf16mMulToTo(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e, int rank)
125+
static void gf16mMulToTo(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e, int rank)
126126
{
127127
for (int i = 0, leftOff = 0, outOff = 0; i < rank; i++, leftOff += rank)
128128
{
@@ -134,7 +134,7 @@ public static void gf16mMulToTo(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e
134134
}
135135
}
136136

137-
public static void gf16mMulTo(byte[] a, byte[] b, byte[] c, int cOff, int rank)
137+
static void gf16mMulTo(byte[] a, byte[] b, byte[] c, int cOff, int rank)
138138
{
139139
for (int i = 0, aOff = 0; i < rank; i++, aOff += rank)
140140
{
@@ -146,7 +146,7 @@ public static void gf16mMulTo(byte[] a, byte[] b, byte[] c, int cOff, int rank)
146146
}
147147

148148
// d ^= a * b + c * d
149-
public static void gf16mMulTo(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e, int eOff, int rank)
149+
static void gf16mMulTo(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e, int eOff, int rank)
150150
{
151151
for (int i = 0, leftOff = 0; i < rank; i++, leftOff += rank)
152152
{
@@ -157,7 +157,7 @@ public static void gf16mMulTo(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e,
157157
}
158158
}
159159

160-
public static void gf16mMulTo(byte[] a, byte[] b, int bOff, byte[] c, int cOff, int rank)
160+
static void gf16mMulTo(byte[] a, byte[] b, int bOff, byte[] c, int cOff, int rank)
161161
{
162162
for (int i = 0, aOff = 0; i < rank; i++, aOff += rank)
163163
{
@@ -171,7 +171,7 @@ public static void gf16mMulTo(byte[] a, byte[] b, int bOff, byte[] c, int cOff,
171171
/**
172172
* Conversion 4 bit -> 32 bit representation
173173
*/
174-
public static int gf16FromNibble(int idx)
174+
static int gf16FromNibble(int idx)
175175
{
176176
int middle = idx | (idx << 4);
177177
return ((middle & 0x41) | ((middle << 2) & 0x208));

core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -563,11 +563,12 @@ public void genABQP(MapGroup1 map1, byte[] pkSeed)
563563
}
564564
else
565565
{
566+
int oxalphaxlsq = o * alpha * lsq;
566567
byte[] fixedAbq = fixedAbqSet.get(o);
567-
MapGroup1.fillAlpha(fixedAbq, 0, map1.aAlpha, m * o * alpha * lsq);
568-
MapGroup1.fillAlpha(fixedAbq, o * alpha * lsq, map1.bAlpha, (m - 1) * o * alpha * lsq);
569-
MapGroup1.fillAlpha(fixedAbq, o * alpha * lsq * 2, map1.qAlpha1, (m - 2) * o * alpha * lsq);
570-
MapGroup1.fillAlpha(fixedAbq, o * alpha * lsq * 3, map1.qAlpha2, (m - 3) * o * alpha * lsq);
568+
MapGroup1.fillAlpha(fixedAbq, 0, map1.aAlpha, m * oxalphaxlsq);
569+
MapGroup1.fillAlpha(fixedAbq, oxalphaxlsq, map1.bAlpha, (m - 1) * oxalphaxlsq);
570+
MapGroup1.fillAlpha(fixedAbq, oxalphaxlsq * 2, map1.qAlpha1, (m - 2) * oxalphaxlsq);
571+
MapGroup1.fillAlpha(fixedAbq, oxalphaxlsq * 3, map1.qAlpha2, (m - 3) * oxalphaxlsq);
571572
}
572573
}
573574

core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaSigner.java

Lines changed: 36 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ void signDigestCore(byte[] ptSignature, byte[] digest, byte[] arraySalt,
149149
final int n = params.getN();
150150
final int mxlsq = m * lsq;
151151
final int oxlsq = o * lsq;
152+
final int vxlsq = v * lsq;
152153
final int bytesHash = (oxlsq + 1) >>> 1;
153154
final int bytesSalt = 16;
154155

@@ -161,12 +162,11 @@ void signDigestCore(byte[] ptSignature, byte[] digest, byte[] arraySalt,
161162
byte[][][] Right = new byte[alpha][v][lsq];
162163
byte[] leftXTmp = new byte[lsq];
163164
byte[] rightXtmp = new byte[lsq];
164-
byte[][] XInGF16Matrix = new byte[v][lsq];
165165
byte[] FvvGF16Matrix = new byte[lsq];
166166
byte[] hashInGF16 = new byte[mxlsq];
167167
byte[] vinegarGf16 = new byte[n * lsq];
168168
byte[] signedHash = new byte[bytesHash];
169-
byte[] vinegarBytes = new byte[(v * lsq + 1) >>> 1];
169+
byte[] vinegarBytes = new byte[(vxlsq + 1) >>> 1];
170170

171171
// Temporary matrices
172172
byte[] gf16mTemp0 = new byte[l];
@@ -202,18 +202,20 @@ void signDigestCore(byte[] ptSignature, byte[] digest, byte[] arraySalt,
202202
shake.doFinal(vinegarBytes, 0, vinegarBytes.length);
203203

204204
GF16.decode(vinegarBytes, vinegarGf16, vinegarBytes.length << 1);
205-
fill(vinegarGf16, XInGF16Matrix, vinegarBytes.length << 1);
206205

207206
for (int i = 0, ixlsq = 0; i < m; i++, ixlsq += lsq)
208207
{
209208
Arrays.fill(FvvGF16Matrix, (byte)0);
210209
// Evaluate vinegar part of central map
211-
for (int a = 0; a < alpha; a++)
210+
for (int a = 0, miPrime = i; a < alpha; a++, miPrime++)
212211
{
213-
int miPrime = iPrime(i, a);
214-
for (int j = 0; j < v; j++)
212+
if (miPrime >= o)
213+
{
214+
miPrime -= o;
215+
}
216+
for (int j = 0, jxlsq = 0; j < v; j++, jxlsq += lsq)
215217
{
216-
GF16Utils.gf16mTranMulMul(XInGF16Matrix[j], Aalpha[i][a], Balpha[i][a], Qalpha1[i][a],
218+
GF16Utils.gf16mTranMulMul(vinegarGf16, jxlsq, Aalpha[i][a], Balpha[i][a], Qalpha1[i][a],
217219
Qalpha2[i][a], gf16mTemp0, Left[a][j], Right[a][j], l);
218220
}
219221

@@ -235,15 +237,18 @@ void signDigestCore(byte[] ptSignature, byte[] digest, byte[] arraySalt,
235237
}
236238
}
237239
// }
238-
// // TODO: think about how this two loops can merge together?
240+
// // TODO: think about why this two loops can merge together?
239241
// // Compute the coefficients of Xo and put into Gauss matrix and compute the coefficients of Xo^t and add into Gauss matrix
240242
// for (int i = 0, ixlsq = 0; i < m; ++i, ixlsq += lsq)
241243
// {
242244
for (int index = 0, idxlsq = 0; index < o; ++index, idxlsq += lsq)
243245
{
244-
for (int a = 0; a < alpha; ++a)
246+
for (int a = 0, mi_prime = i; a < alpha; ++a, ++mi_prime)
245247
{
246-
int mi_prime = iPrime(i, a);
248+
if (mi_prime >= o)
249+
{
250+
mi_prime -= o;
251+
}
247252
// Initialize Temp to zero
248253
for (int ti = 0; ti < lsq; ++ti)
249254
{
@@ -311,49 +316,43 @@ void signDigestCore(byte[] ptSignature, byte[] digest, byte[] arraySalt,
311316
}
312317

313318
// Copy remaining oil variables
314-
System.arraycopy(solution, 0, vinegarGf16, v * lsq, oxlsq);
319+
System.arraycopy(solution, 0, vinegarGf16, vxlsq, oxlsq);
315320
GF16.encode(vinegarGf16, ptSignature, vinegarGf16.length);
316321

317322
System.arraycopy(arraySalt, 0, ptSignature, ptSignature.length - bytesSalt, bytesSalt);
318323
}
319324

320325
boolean verifySignatureCore(byte[] digest, byte[] signature, byte[] publicKeySeed, MapGroup1 map1, byte[][][][] p22)
321326
{
322-
final int bytesHash = (params.getO() * params.getLsq() + 1) >>> 1;
323-
final int bytesSalt = params.getSaltLength();
324327
final int lsq = params.getLsq();
328+
final int o = params.getO();
329+
final int oxlsq = o * lsq;
330+
final int bytesHash = (oxlsq + 1) >>> 1;
331+
final int bytesSalt = params.getSaltLength();
325332
final int m = params.getM();
326333
final int n = params.getN();
327-
final int o = params.getO();
328-
int bytesSignature = ((n * lsq) + 1) >>> 1;
334+
final int nxlsq = n * lsq;
335+
336+
int bytesSignature = ((nxlsq) + 1) >>> 1;
329337

330338
// Step 1: Regenerate signed hash using public key seed, digest and salt
331339
byte[] signedHash = new byte[bytesHash];
332340
createSignedHash(publicKeySeed, publicKeySeed.length, digest, digest.length,
333341
signature, bytesSignature, bytesSalt, signedHash, bytesHash);
334342

335343
// Handle odd-length adjustment (if needed)
336-
if (((o * lsq) & 1) != 0)
344+
if (((oxlsq) & 1) != 0)
337345
{
338346
signedHash[bytesHash - 1] &= 0x0F;
339347
}
340348

341349
// Step 2: Convert signature to GF16 matrices
342-
byte[][] signatureGF16Matrix = new byte[n][lsq];
343-
if ((lsq & 1) == 1)
344-
{
345-
byte[] decodedSig = new byte[n * lsq];
346-
GF16.decode(signature, 0, decodedSig, 0, decodedSig.length);
347-
fill(decodedSig, signatureGF16Matrix, decodedSig.length);
348-
}
349-
else
350-
{
351-
MapGroup1.decodeArray(signature, 0, signatureGF16Matrix, signature.length);
352-
}
350+
byte[] decodedSig = new byte[nxlsq];
351+
GF16.decode(signature, 0, decodedSig, 0, decodedSig.length);
353352

354353
// Step 3: Evaluate signature using public key
355354
byte[] computedHashBytes = new byte[m * lsq];
356-
evaluation(computedHashBytes, map1, p22, signatureGF16Matrix);
355+
evaluation(computedHashBytes, map1, p22, decodedSig);//signatureGF16Matrix);
357356

358357
// Convert computed hash matrix to bytes
359358
byte[] encodedHash = new byte[bytesHash];
@@ -363,13 +362,14 @@ boolean verifySignatureCore(byte[] digest, byte[] signature, byte[] publicKeySee
363362
return Arrays.areEqual(signedHash, encodedHash);
364363
}
365364

366-
private void evaluation(byte[] hashMatrix, MapGroup1 map1, byte[][][][] p22, byte[][] signature)
365+
private void evaluation(byte[] hashMatrix, MapGroup1 map1, byte[][][][] p22, byte[] signature)
367366
{
368367
final int m = params.getM();
369368
final int alpha = params.getAlpha();
370369
final int n = params.getN();
371370
final int l = params.getL();
372371
final int lsq = params.getLsq();
372+
final int o = params.getO();
373373

374374
byte[][][] Left = new byte[alpha][n][lsq];
375375
byte[][][] Right = new byte[alpha][n][lsq];
@@ -378,21 +378,24 @@ private void evaluation(byte[] hashMatrix, MapGroup1 map1, byte[][][][] p22, byt
378378
// Evaluate Left and Right matrices
379379
for (int mi = 0, mixlsq = 0; mi < m; mi++, mixlsq += lsq)
380380
{
381-
for (int si = 0; si < n; si++)
381+
for (int si = 0, sixlsq = 0; si < n; si++, sixlsq += lsq)
382382
{
383383
for (int a = 0; a < alpha; a++)
384384
{
385385
// Left[mi][a][si] = Aalpha * (sig^T * Qalpha1)
386386
// Right[mi][a][si] = (Qalpha2 * sig) * Balpha
387-
GF16Utils.gf16mTranMulMul(signature[si], map1.aAlpha[mi][a], map1.bAlpha[mi][a], map1.qAlpha1[mi][a],
387+
GF16Utils.gf16mTranMulMul(signature, sixlsq, map1.aAlpha[mi][a], map1.bAlpha[mi][a], map1.qAlpha1[mi][a],
388388
map1.qAlpha2[mi][a], temp, Left[a][si], Right[a][si], l);
389389
}
390390
}
391391

392392
// Process P matrices and accumulate results
393-
for (int a = 0; a < alpha; a++)
393+
for (int a = 0, miPrime = mi; a < alpha; a++, miPrime++)
394394
{
395-
int miPrime = iPrime(mi, a);
395+
if (miPrime >= o)
396+
{
397+
miPrime -= o;
398+
}
396399
for (int ni = 0; ni < n; ni++)
397400
{
398401
// sum_t0 = sum(P[miPrime][ni][nj] * Right[mi][a][nj])
@@ -499,23 +502,6 @@ private int performGaussianElimination(byte[][] Gauss, byte[] solution, int size
499502
return 0;
500503
}
501504

502-
private int iPrime(int mi, int alpha)
503-
{
504-
// Implement index calculation based on SNOVA specification
505-
return (mi + alpha) % params.getO();
506-
}
507-
508-
static void fill(byte[] input, byte[][] output, int len)
509-
{
510-
int rlt = 0;
511-
for (int i = 0; i < output.length; ++i)
512-
{
513-
int tmp = Math.min(output[i].length, len - rlt);
514-
System.arraycopy(input, rlt, output[i], 0, tmp);
515-
rlt += tmp;
516-
}
517-
}
518-
519505
private byte[] getMessageHash(byte[] message)
520506
{
521507
byte[] hash = new byte[shake.getDigestSize()];

0 commit comments

Comments
 (0)