Merge pull request 'PQ MLKEM hybrid ratchet only' (#517) from zzz/i2p.i2p:pq-ratchet into master

Reviewed-on: http://git.idk.i2p/I2P_Developers/i2p.i2p/pulls/517
Reviewed-by: idk <idki2p@mail.i2p>
This commit is contained in:
zzz
2025-06-24 08:31:49 -04:00
76 changed files with 5944 additions and 73 deletions
+8 -1
View File
@@ -11,7 +11,14 @@ public enum EncAlgo {
EC("EC"),
/** @since 0.9.38 */
ECIES("ECIES");
ECIES("ECIES"),
/** @since 0.9.67 */
ECIES_MLKEM("ECIES-MLKEM"),
/** @since 0.9.67 */
ECIES_MLKEM_INT("ECIES-MLKEM-Internal");
private final String name;
+91 -8
View File
@@ -52,14 +52,83 @@ public enum EncType {
* Pubkey 32 bytes; privkey 32 bytes
* @since 0.9.38
*/
ECIES_X25519(4, 32, 32, EncAlgo.ECIES, "EC/None/NoPadding", X25519_SPEC, "0.9.38");
ECIES_X25519(4, 32, 32, EncAlgo.ECIES, "EC/None/NoPadding", X25519_SPEC, "0.9.38"),
/**
* Proposal 169.
* Pubkey 32 bytes; privkey 32 bytes
* @since 0.9.67
*/
MLKEM512_X25519(5, 32, 32, EncAlgo.ECIES_MLKEM, "EC/None/NoPadding", X25519_SPEC, "0.9.67"),
/**
* Proposal 169.
* Pubkey 32 bytes; privkey 32 bytes
* @since 0.9.67
*/
MLKEM768_X25519(6, 32, 32, EncAlgo.ECIES_MLKEM, "EC/None/NoPadding", X25519_SPEC, "0.9.67"),
/**
* Proposal 169.
* Pubkey 32 bytes; privkey 32 bytes
* @since 0.9.67
*/
MLKEM1024_X25519(7, 32, 32, EncAlgo.ECIES_MLKEM, "EC/None/NoPadding", X25519_SPEC, "0.9.67"),
/**
* For internal use only (Alice side)
* Proposal 169.
* Pubkey 800 bytes; privkey 1632 bytes
* @since 0.9.67
*/
MLKEM512_X25519_INT(100005, 800, 1632, EncAlgo.ECIES_MLKEM_INT, "EC/None/NoPadding", X25519_SPEC, "0.9.67"),
/**
* For internal use only (Alice side)
* Proposal 169.
* Pubkey 1184 bytes; privkey 2400 bytes
* @since 0.9.67
*/
MLKEM768_X25519_INT(100006, 1184, 2400, EncAlgo.ECIES_MLKEM_INT, "EC/None/NoPadding", X25519_SPEC, "0.9.67"),
/**
* For internal use only (Alice side)
* Proposal 169.
* Pubkey 1568 bytes; privkey 3168 bytes
* @since 0.9.67
*/
MLKEM1024_X25519_INT(100007, 1568, 3168, EncAlgo.ECIES_MLKEM_INT, "EC/None/NoPadding", X25519_SPEC, "0.9.67"),
/**
* For internal use only (Bob side ciphertext)
* Proposal 169.
* Pubkey 768 bytes; privkey 0
* @since 0.9.67
*/
MLKEM512_X25519_CT(100008, 768, 0, EncAlgo.ECIES_MLKEM_INT, "EC/None/NoPadding", X25519_SPEC, "0.9.67"),
/**
* For internal use only (Bob side ciphertext)
* Proposal 169.
* Pubkey 1088 bytes; privkey 0
* @since 0.9.67
*/
MLKEM768_X25519_CT(100009, 1088, 0, EncAlgo.ECIES_MLKEM_INT, "EC/None/NoPadding", X25519_SPEC, "0.9.67"),
/**
* For internal use only (Bob side ciphertext)
* Proposal 169.
* Pubkey 1568 bytes; privkey 0
* @since 0.9.67
*/
MLKEM1024_X25519_CT(100010, 1568, 0, EncAlgo.ECIES_MLKEM_INT, "EC/None/NoPadding", X25519_SPEC, "0.9.67");
private final int code, pubkeyLen, privkeyLen;
private final EncAlgo base;
private final String algoName, since;
private final AlgorithmParameterSpec params;
private final boolean isAvail;
private final boolean isAvail, isPQ;
/**
*
@@ -68,7 +137,7 @@ public enum EncType {
*/
EncType(int cod, int pubLen, int privLen, EncAlgo baseAlgo,
String transformation, AlgorithmParameterSpec pSpec, String supportedSince) {
if (pubLen > 256)
if (pubLen > 256 && baseAlgo != EncAlgo.ECIES_MLKEM_INT)
throw new IllegalArgumentException("fixup PublicKey for longer keys");
code = cod;
pubkeyLen = pubLen;
@@ -78,6 +147,7 @@ public enum EncType {
params = pSpec;
since = supportedSince;
isAvail = x_isAvailable();
isPQ = base == EncAlgo.ECIES_MLKEM;
}
/** the unique identifier for this type */
@@ -120,11 +190,16 @@ public enum EncType {
}
private boolean x_isAvailable() {
if (ELGAMAL_2048 == this)
return true;
// EC types are placeholders for now
if (base == EncAlgo.EC)
return false;
switch (base) {
case ELGAMAL:
return true;
// EC types are placeholders for now
case EC:
// internal types
case ECIES_MLKEM_INT:
return false;
}
try {
getParams();
} catch (InvalidParameterSpecException e) {
@@ -154,6 +229,14 @@ public enum EncType {
return type.isAvailable();
}
/**
* @since 0.9.67
* @return true if this is a PQ type
*/
public boolean isPQ() {
return isPQ;
}
private static final EncType[] BY_CODE;
static {
@@ -196,6 +196,9 @@ public final class KeyGenerator {
break;
case ECIES_X25519:
case MLKEM512_X25519:
case MLKEM768_X25519:
case MLKEM1024_X25519:
byte[] bpriv = new byte[32];
do {
_context.random().nextBytes(bpriv);
@@ -238,6 +241,9 @@ public final class KeyGenerator {
break;
case ECIES_X25519:
case MLKEM512_X25519:
case MLKEM768_X25519:
case MLKEM1024_X25519:
data = new byte[32];
Curve25519.eval(data, 0, priv.getData(), null);
break;
@@ -342,6 +348,7 @@ public final class KeyGenerator {
}
java.security.PublicKey pubkey = kp.getPublic();
java.security.PrivateKey privkey = kp.getPrivate();
SimpleDataStructure[] keys = new SimpleDataStructure[2];
keys[0] = SigUtil.fromJavaKey(pubkey, type);
keys[1] = SigUtil.fromJavaKey(privkey, type);
@@ -476,6 +483,7 @@ public final class KeyGenerator {
System.out.println(type + " private-to-public test PASSED");
else
System.out.println(type + " private-to-public test FAILED");
//System.out.println("privkey " + keys[1]);
MessageDigest md = type.getDigestInstance();
for (int i = 0; i < runs; i++) {