Skip to content

Commit 05c8866

Browse files
committed
Merge branch 'main' of gitlab.cryptoworkshop.com:root/bc-java
2 parents 611dc08 + ca2806b commit 05c8866

File tree

8 files changed

+72
-56
lines changed

8 files changed

+72
-56
lines changed

core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMEngine.java

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ public void init(SecureRandom random)
188188
this.random = random;
189189
}
190190

191+
boolean checkModulus(byte[] t)
192+
{
193+
return PolyVec.checkModulus(this, t) < 0;
194+
}
195+
191196
public byte[][] generateKemKeyPair()
192197
{
193198
byte[] d = new byte[KyberSymBytes];
@@ -224,9 +229,9 @@ public byte[][] generateKemKeyPairInternal(byte[] d, byte[] z)
224229
};
225230
}
226231

227-
public byte[][] kemEncryptInternal(byte[] publicKeyInput, byte[] randBytes)
232+
byte[][] kemEncrypt(MLKEMPublicKeyParameters publicKey, byte[] randBytes)
228233
{
229-
byte[] outputCipherText;
234+
byte[] publicKeyInput = publicKey.getEncoded();
230235

231236
byte[] buf = new byte[2 * KyberSymBytes];
232237
byte[] kr = new byte[2 * KyberSymBytes];
@@ -240,7 +245,8 @@ public byte[][] kemEncryptInternal(byte[] publicKeyInput, byte[] randBytes)
240245
symmetric.hash_g(kr, buf);
241246

242247
// IndCpa Encryption
243-
outputCipherText = indCpa.encrypt(publicKeyInput, Arrays.copyOfRange(buf, 0, KyberSymBytes), Arrays.copyOfRange(kr, 32, kr.length));
248+
byte[] outputCipherText = indCpa.encrypt(publicKeyInput, Arrays.copyOfRange(buf, 0, KyberSymBytes),
249+
Arrays.copyOfRange(kr, 32, kr.length));
244250

245251
byte[] outputSharedSecret = new byte[sessionKeyLength];
246252

@@ -252,8 +258,10 @@ public byte[][] kemEncryptInternal(byte[] publicKeyInput, byte[] randBytes)
252258
return outBuf;
253259
}
254260

255-
public byte[] kemDecryptInternal(byte[] secretKey, byte[] cipherText)
261+
byte[] kemDecrypt(MLKEMPrivateKeyParameters privateKey, byte[] cipherText)
256262
{
263+
byte[] secretKey = privateKey.getEncoded();
264+
257265
byte[] buf = new byte[2 * KyberSymBytes],
258266
kr = new byte[2 * KyberSymBytes];
259267

@@ -282,21 +290,6 @@ public byte[] kemDecryptInternal(byte[] secretKey, byte[] cipherText)
282290
return Arrays.copyOfRange(kr, 0, sessionKeyLength);
283291
}
284292

285-
MLKEMIndCpa getIndCpa()
286-
{
287-
return indCpa;
288-
}
289-
290-
byte[][] kemEncrypt(byte[] publicKeyInput, byte[] randBytes)
291-
{
292-
return kemEncryptInternal(publicKeyInput, randBytes);
293-
}
294-
295-
byte[] kemDecrypt(byte[] secretKey, byte[] cipherText)
296-
{
297-
return kemDecryptInternal(secretKey, cipherText);
298-
}
299-
300293
private void cmov(byte[] r, byte[] x, int xlen, boolean b)
301294
{
302295
if (b)
@@ -308,9 +301,4 @@ private void cmov(byte[] r, byte[] x, int xlen, boolean b)
308301
System.arraycopy(r, 0, r, 0, xlen);
309302
}
310303
}
311-
312-
public void getRandomBytes(byte[] buf)
313-
{
314-
this.random.nextBytes(buf);
315-
}
316304
}

core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMExtractor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public MLKEMExtractor(MLKEMPrivateKeyParameters privateKey)
2121

2222
public byte[] extractSecret(byte[] encapsulation)
2323
{
24-
return engine.kemDecrypt(privateKey.getEncoded(), encapsulation);
24+
return engine.kemDecrypt(privateKey, encapsulation);
2525
}
2626

2727
public int getEncapsulationLength()

core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMGenerator.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,19 @@ public MLKEMGenerator(SecureRandom random)
2020

2121
public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey)
2222
{
23-
MLKEMPublicKeyParameters key = (MLKEMPublicKeyParameters)recipientKey;
24-
MLKEMEngine engine = key.getParameters().getEngine();
25-
engine.init(sr);
26-
2723
byte[] randBytes = new byte[32];
28-
engine.getRandomBytes(randBytes);
24+
sr.nextBytes(randBytes);
2925

30-
byte[][] kemEncrypt = engine.kemEncrypt(key.getEncoded(), randBytes);
31-
return new SecretWithEncapsulationImpl(kemEncrypt[0], kemEncrypt[1]);
26+
return internalGenerateEncapsulated(recipientKey, randBytes);
3227
}
28+
3329
public SecretWithEncapsulation internalGenerateEncapsulated(AsymmetricKeyParameter recipientKey, byte[] randBytes)
3430
{
3531
MLKEMPublicKeyParameters key = (MLKEMPublicKeyParameters)recipientKey;
3632
MLKEMEngine engine = key.getParameters().getEngine();
3733
engine.init(sr);
3834

39-
byte[][] kemEncrypt = engine.kemEncryptInternal(key.getEncoded(), randBytes);
35+
byte[][] kemEncrypt = engine.kemEncrypt(key, randBytes);
4036
return new SecretWithEncapsulationImpl(kemEncrypt[0], kemEncrypt[1]);
4137
}
4238
}

core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPublicKeyParameters.java

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,43 @@ public MLKEMPublicKeyParameters(MLKEMParameters params, byte[] t, byte[] rho)
1717
{
1818
super(false, params);
1919

20-
validatePublicKey(params.getEngine(), getEncoded(t, rho));
20+
MLKEMEngine engine = params.getEngine();
21+
22+
if (t.length != engine.getKyberPolyVecBytes())
23+
{
24+
throw new IllegalArgumentException("'t' has invalid length");
25+
}
26+
if (rho.length != MLKEMEngine.KyberSymBytes)
27+
{
28+
throw new IllegalArgumentException("'rho' has invalid length");
29+
}
2130

2231
this.t = Arrays.clone(t);
2332
this.rho = Arrays.clone(rho);
33+
34+
if (!engine.checkModulus(this.t))
35+
{
36+
throw new IllegalArgumentException("Modulus check failed for ML-KEM public key");
37+
}
2438
}
2539

2640
public MLKEMPublicKeyParameters(MLKEMParameters params, byte[] encoding)
2741
{
2842
super(false, params);
2943

30-
validatePublicKey(params.getEngine(), encoding);
44+
MLKEMEngine engine = params.getEngine();
3145

32-
this.t = Arrays.copyOfRange(encoding, 0, encoding.length - MLKEMEngine.KyberSymBytes);
33-
this.rho = Arrays.copyOfRange(encoding, encoding.length - MLKEMEngine.KyberSymBytes, encoding.length);
34-
}
35-
36-
private static void validatePublicKey(MLKEMEngine engine, byte[] publicKeyInput)
37-
{
38-
// Input validation (6.2 ML-KEM Encaps)
39-
// length Check
40-
if (publicKeyInput.length != engine.getKyberIndCpaPublicKeyBytes())
46+
if (encoding.length != engine.getKyberIndCpaPublicKeyBytes())
4147
{
42-
throw new IllegalArgumentException("length check failed for ml-kem public key construction");
48+
throw new IllegalArgumentException("'encoding' has invalid length");
4349
}
4450

45-
// Modulus Check
46-
PolyVec polyVec = new PolyVec(engine);
47-
MLKEMIndCpa indCpa = engine.getIndCpa();
51+
this.t = Arrays.copyOfRange(encoding, 0, encoding.length - MLKEMEngine.KyberSymBytes);
52+
this.rho = Arrays.copyOfRange(encoding, encoding.length - MLKEMEngine.KyberSymBytes, encoding.length);
4853

49-
byte[] seed = indCpa.unpackPublicKey(polyVec, publicKeyInput);
50-
byte[] ek = indCpa.packPublicKey(polyVec, seed);
51-
if (!Arrays.areEqual(ek, publicKeyInput))
54+
if (!engine.checkModulus(this.t))
5255
{
53-
throw new IllegalArgumentException("modulus check failed for ml-kem public key construction");
56+
throw new IllegalArgumentException("Modulus check failed for ML-KEM public key");
5457
}
5558
}
5659

core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Poly.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,5 +340,20 @@ public String toString()
340340
out.append("]");
341341
return out.toString();
342342
}
343-
}
344343

344+
static int checkModulus(byte[] a, int off)
345+
{
346+
int result = -1;
347+
for (int i = 0; i < MLKEMEngine.KyberN / 2; ++i)
348+
{
349+
int a0 = a[off + 3 * i + 0] & 0xFF;
350+
int a1 = a[off + 3 * i + 1] & 0xFF;
351+
int a2 = a[off + 3 * i + 2] & 0xFF;
352+
short c0 = (short)(((a0 >> 0) | (a1 << 8)) & 0xFFF);
353+
short c1 = (short)(((a1 >> 4) | (a2 << 4)) & 0xFFF);
354+
result &= Reduce.checkModulus(c0);
355+
result &= Reduce.checkModulus(c1);
356+
}
357+
return result;
358+
}
359+
}

core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/PolyVec.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,14 @@ public String toString()
269269
out.append("]");
270270
return out.toString();
271271
}
272+
273+
static int checkModulus(MLKEMEngine engine, byte[] inputBytes)
274+
{
275+
int result = -1;
276+
for (int i = 0, k = engine.getKyberK(); i < k; i++)
277+
{
278+
result &= Poly.checkModulus(inputBytes, i * MLKEMEngine.KyberPolyBytes);
279+
}
280+
return result;
281+
}
272282
}

core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Reduce.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,9 @@ public static short conditionalSubQ(short a)
3232
return a;
3333
}
3434

35+
// NB: We only care about the sign bit of the result: it will be 1 iff the argument was in range
36+
static int checkModulus(short a)
37+
{
38+
return a - MLKEMEngine.KyberQ;
39+
}
3540
}

core/src/test/java/org/bouncycastle/pqc/crypto/test/MLKEMTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,12 @@ public void testModulus() throws IOException
416416

417417
try
418418
{
419-
MLKEMPublicKeyParameters pubParams = (MLKEMPublicKeyParameters)PublicKeyFactory.createKey(
420-
SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(new MLKEMPublicKeyParameters(parameters, key)));
419+
new MLKEMPublicKeyParameters(parameters, key);
421420
fail();
422421
}
423422
catch (IllegalArgumentException e)
424423
{
425-
assertEquals("modulus check failed for ml-kem public key construction", e.getMessage());
424+
assertEquals("Modulus check failed for ML-KEM public key", e.getMessage());
426425
}
427426
}
428427
}

0 commit comments

Comments
 (0)