Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,20 @@ KEM Details:
Length secret key (bytes): 1632
Length ciphertext (bytes): 768
Length shared secret (bytes): 32
Length keypair seed (bytes): 64

Client public key:
A8 37 25 CA 79 A5 55 42 ... AF 43 3A 54 6C 3C 34 30
A4 E7 5D DB AB 9D FA 13 ... 32 9C 08 3F 71 D6 BA 41

It took 1 millisecs to generate the key pair.
It took 0 millisecs to encapsulate the secret.
It took 0 millisecs to decapsulate the secret.

Client shared secret:
7D 3B BB C7 29 45 4B 2F ... 58 87 1D BB BD 35 9C 79
5C BE 27 50 C8 7E 61 36 ... 07 60 EA 4C 3E 25 90 3F

Server shared secret:
7D 3B BB C7 29 45 4B 2F ... 58 87 1D BB BD 35 9C 79
5C BE 27 50 C8 7E 61 36 ... 07 60 EA 4C 3E 25 90 3F

Shared secrets coincide? true
```
Expand All @@ -173,10 +174,10 @@ java -cp target/liboqs-java.jar:examples/ SigExample

```
Supported signatures:
Dilithium2 Dilithium3 Dilithium5 ML-DSA-44 ML-DSA-65 ML-DSA-87 Falcon-512 Falcon-1024 Falcon-padded-512 Falcon-padded-1024 SPHINCS+-SHA2-128f-simple SPHINCS+-SHA2-128s-simple SPHINCS+-SHA2-192f-simple SPHINCS+-SHA2-192s-simple SPHINCS+-SHA2-256f-simple SPHINCS+-SHA2-256s-simple SPHINCS+-SHAKE-128f-simple SPHINCS+-SHAKE-128s-simple SPHINCS+-SHAKE-192f-simple SPHINCS+-SHAKE-192s-simple SPHINCS+-SHAKE-256f-simple SPHINCS+-SHAKE-256s-simple MAYO-1 MAYO-2 MAYO-3 MAYO-5 cross-rsdp-128-balanced cross-rsdp-128-fast cross-rsdp-128-small cross-rsdp-192-balanced cross-rsdp-192-fast cross-rsdp-192-small cross-rsdp-256-balanced cross-rsdp-256-fast cross-rsdp-256-small cross-rsdpg-128-balanced cross-rsdpg-128-fast cross-rsdpg-128-small cross-rsdpg-192-balanced cross-rsdpg-192-fast cross-rsdpg-192-small cross-rsdpg-256-balanced cross-rsdpg-256-fast cross-rsdpg-256-small
Dilithium2 Dilithium3 Dilithium5 ML-DSA-44 ML-DSA-65 ML-DSA-87 Falcon-512 Falcon-1024 Falcon-padded-512 Falcon-padded-1024 SPHINCS+-SHA2-128f-simple SPHINCS+-SHA2-128s-simple SPHINCS+-SHA2-192f-simple SPHINCS+-SHA2-192s-simple SPHINCS+-SHA2-256f-simple SPHINCS+-SHA2-256s-simple SPHINCS+-SHAKE-128f-simple SPHINCS+-SHAKE-128s-simple SPHINCS+-SHAKE-192f-simple SPHINCS+-SHAKE-192s-simple SPHINCS+-SHAKE-256f-simple SPHINCS+-SHAKE-256s-simple MAYO-1 MAYO-2 MAYO-3 MAYO-5 cross-rsdp-128-balanced cross-rsdp-128-fast cross-rsdp-128-small cross-rsdp-192-balanced cross-rsdp-192-fast cross-rsdp-192-small cross-rsdp-256-balanced cross-rsdp-256-fast cross-rsdp-256-small cross-rsdpg-128-balanced cross-rsdpg-128-fast cross-rsdpg-128-small cross-rsdpg-192-balanced cross-rsdpg-192-fast cross-rsdpg-192-small cross-rsdpg-256-balanced cross-rsdpg-256-fast cross-rsdpg-256-small OV-Is OV-Ip OV-III OV-V OV-Is-pkc OV-Ip-pkc OV-III-pkc OV-V-pkc OV-Is-pkc-skc OV-Ip-pkc-skc OV-III-pkc-skc OV-V-pkc-skc

Enabled signatures:
Dilithium2 Dilithium3 Dilithium5 ML-DSA-44 ML-DSA-65 ML-DSA-87 Falcon-512 Falcon-1024 Falcon-padded-512 Falcon-padded-1024 SPHINCS+-SHA2-128f-simple SPHINCS+-SHA2-128s-simple SPHINCS+-SHA2-192f-simple SPHINCS+-SHA2-192s-simple SPHINCS+-SHA2-256f-simple SPHINCS+-SHA2-256s-simple SPHINCS+-SHAKE-128f-simple SPHINCS+-SHAKE-128s-simple SPHINCS+-SHAKE-192f-simple SPHINCS+-SHAKE-192s-simple SPHINCS+-SHAKE-256f-simple SPHINCS+-SHAKE-256s-simple MAYO-1 MAYO-2 MAYO-3 MAYO-5 cross-rsdp-128-balanced cross-rsdp-128-fast cross-rsdp-128-small cross-rsdp-192-balanced cross-rsdp-192-fast cross-rsdp-192-small cross-rsdp-256-balanced cross-rsdp-256-fast cross-rsdp-256-small cross-rsdpg-128-balanced cross-rsdpg-128-fast cross-rsdpg-128-small cross-rsdpg-192-balanced cross-rsdpg-192-fast cross-rsdpg-192-small cross-rsdpg-256-balanced cross-rsdpg-256-fast cross-rsdpg-256-small
Dilithium2 Dilithium3 Dilithium5 ML-DSA-44 ML-DSA-65 ML-DSA-87 Falcon-512 Falcon-1024 Falcon-padded-512 Falcon-padded-1024 SPHINCS+-SHA2-128f-simple SPHINCS+-SHA2-128s-simple SPHINCS+-SHA2-192f-simple SPHINCS+-SHA2-192s-simple SPHINCS+-SHA2-256f-simple SPHINCS+-SHA2-256s-simple SPHINCS+-SHAKE-128f-simple SPHINCS+-SHAKE-128s-simple SPHINCS+-SHAKE-192f-simple SPHINCS+-SHAKE-192s-simple SPHINCS+-SHAKE-256f-simple SPHINCS+-SHAKE-256s-simple MAYO-1 MAYO-2 MAYO-3 MAYO-5 cross-rsdp-128-balanced cross-rsdp-128-fast cross-rsdp-128-small cross-rsdp-192-balanced cross-rsdp-192-fast cross-rsdp-192-small cross-rsdp-256-balanced cross-rsdp-256-fast cross-rsdp-256-small cross-rsdpg-128-balanced cross-rsdpg-128-fast cross-rsdpg-128-small cross-rsdpg-192-balanced cross-rsdpg-192-fast cross-rsdpg-192-small cross-rsdpg-256-balanced cross-rsdpg-256-fast cross-rsdpg-256-small OV-Is OV-Ip OV-III OV-V OV-Is-pkc OV-Ip-pkc OV-III-pkc OV-V-pkc OV-Is-pkc-skc OV-Ip-pkc-skc OV-III-pkc-skc OV-V-pkc-skc

Signature Details:
Name: ML-DSA-44
Expand All @@ -188,14 +189,14 @@ Signature Details:
Maximum length signature (bytes): 2420

Signer public key:
CB CB 70 FF 1E B3 BA 26 ... A7 CF 7C 70 89 A1 1A 40
2F F1 7A 8F FF EA 04 AA ... FD 51 A2 A0 80 5C 61 2B

It took 1 millisecs to generate the key pair.
It took 1 millisecs to sign the message.
It took 0 millisecs to sign the message.
It took 0 millisecs to verify the signature.

Signature:
ED 6F 67 B6 2E C9 31 FC ... 00 00 00 00 0F 21 2A 38
C0 41 9D 4D A9 B1 5F 4C ... 00 00 00 00 0A 20 2E 41

Valid signature? true
```
Expand Down
28 changes: 28 additions & 0 deletions src/main/c/KeyEncapsulation.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ JNIEXPORT jobject JNICALL Java_org_openquantumsafe_KeyEncapsulation_get_1KEM_1de
jfieldID _length_shared_secret = (*env)->GetFieldID(env, cls, "length_shared_secret", "J");
(*env)->SetLongField(env, _nativeKED, _length_shared_secret, (jlong) kem->length_shared_secret);

// long length_keypair_seed;
jfieldID _length_keypair_seed = (*env)->GetFieldID(env, cls, "length_keypair_seed", "J");
(*env)->SetLongField(env, _nativeKED, _length_keypair_seed, (jlong) kem->length_keypair_seed);

return _nativeKED;
}

Expand All @@ -110,6 +114,30 @@ JNIEXPORT jint JNICALL Java_org_openquantumsafe_KeyEncapsulation_generate_1keypa
return (rv_ == OQS_SUCCESS) ? 0 : -1;
}

/*
* Class: org_openquantumsafe_KeyEncapsulation
* Method: generate_keypair
* Signature: ([B[B)I
*/
JNIEXPORT jint JNICALL Java_org_openquantumsafe_KeyEncapsulation_generate_1keypair_1derand
(JNIEnv *env, jobject obj, jbyteArray jpublic_key, jbyteArray jsecret_key, jbyteArray jseed)
{
jbyte *public_key_native = (*env)->GetByteArrayElements(env, jpublic_key, 0);
jbyte *secret_key_native = (*env)->GetByteArrayElements(env, jsecret_key, 0);
jbyte *seed_native = (*env)->GetByteArrayElements(env, jseed, 0);

// Get pointer to KEM
OQS_KEM *kem = (OQS_KEM *) getHandle(env, obj, "native_kem_handle_");

// Invoke liboqs KEM keypair generation function
OQS_STATUS rv_ = OQS_KEM_keypair_derand(kem, (uint8_t*) public_key_native, (uint8_t*) secret_key_native, (uint8_t*) seed_native);

(*env)->ReleaseByteArrayElements(env, jpublic_key, public_key_native, 0);
(*env)->ReleaseByteArrayElements(env, jsecret_key, secret_key_native, 0);
(*env)->ReleaseByteArrayElements(env, jseed, seed_native, JNI_ABORT);
return (rv_ == OQS_SUCCESS) ? 0 : -1;
}

/*
* Class: org_openquantumsafe_KeyEncapsulation
* Method: encap_secret
Expand Down
38 changes: 37 additions & 1 deletion src/main/java/org/openquantumsafe/KeyEncapsulation.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class KeyEncapsulationDetails {
long length_secret_key;
long length_ciphertext;
long length_shared_secret;
long length_keypair_seed;

/**
* \brief Print KEM algorithm details
Expand All @@ -33,7 +34,9 @@ void printKeyEncapsulation() {
"\n Length public key (bytes): " + this.length_public_key +
"\n Length secret key (bytes): " + this.length_secret_key +
"\n Length ciphertext (bytes): " + this.length_ciphertext +
"\n Length shared secret (bytes): " + this.length_shared_secret
"\n Length shared secret (bytes): " + this.length_shared_secret +
"\n Length keypair seed (bytes): "
+ ((this.length_keypair_seed > 0) ? this.length_keypair_seed : "N/A")
);
}

Expand Down Expand Up @@ -114,6 +117,18 @@ public KeyEncapsulation(String alg_name, byte[] secret_key)
*/
private native int generate_keypair(byte[] public_key, byte[] secret_key);

/**
* \brief Wrapper for OQS_API OQS_STATUS OQS_KEM_keypair_derand(const OQS_KEM *kem,
* uint8_t *public_key, uint8_t *secret_key,
* const uint8_t *seed);
* \param Public key
* \param Secret key
* \param Seed
* \return Status
*/
private native int generate_keypair_derand(byte[] public_key,
byte[] secret_key, byte[] seed);

/**
* \brief Wrapper for OQS_API OQS_STATUS OQS_KEM_encaps(const OQS_KEM *kem,
* uint8_t *ciphertext,
Expand Down Expand Up @@ -159,6 +174,27 @@ public byte[] generate_keypair() throws RuntimeException {
return this.public_key_;
}

/**
* \brief Invoke native generate_keypair_derand method using the PK and SK lengths
* from alg_details_. Check return value and if != 0 throw Exception.
*/
public byte[] generate_keypair(byte[] seed) throws RuntimeException {
if (seed.length != alg_details_.length_keypair_seed) {
throw new RuntimeException("Incorrect seed length");
}

int rv_ = generate_keypair_derand(this.public_key_, this.secret_key_, seed);
if (rv_ != 0) throw new RuntimeException("Cannot generate keypair from seed");
return this.public_key_;
}

/**
* \brief Return seed length
*/
public long get_keypair_seed_length() {
return alg_details_.length_keypair_seed;
}

/**
* \brief Return public key
*/
Expand Down
46 changes: 46 additions & 0 deletions src/test/java/org/openquantumsafe/KEMTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static org.junit.jupiter.api.Assertions.assertArrayEquals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.Stream;

public class KEMTest {
Expand Down Expand Up @@ -56,6 +57,43 @@ public void testAllKEMs(String kem_name) {
System.out.println(sb.toString());
}

/**
* Test KEMs with derandomized keypair generation.
*/
@ParameterizedTest(name = "Testing {arguments}")
@MethodSource("getDerandSupportedKEMsAsStream")
public void testKEMsWithDerand(String kem_name) {
StringBuilder sb = new StringBuilder();
sb.append(kem_name);
sb.append(" (derand)");
sb.append(String.format("%1$" + (40 - kem_name.length() - 9) + "s", ""));

// Create client and server
KeyEncapsulation client = new KeyEncapsulation(kem_name);
KeyEncapsulation server = new KeyEncapsulation(kem_name);

// Generate seed
byte[] seed = Rand.randombytes(client.get_keypair_seed_length());

// Generate client key pair
byte[] client_public_key = client.generate_keypair(seed);

// Server: encapsulate secret with client's public key
Pair<byte[], byte[]> server_pair = server.encap_secret(client_public_key);
byte[] ciphertext = server_pair.getLeft();
byte[] shared_secret_server = server_pair.getRight();

// Client: decapsulate
byte[] shared_secret_client = client.decap_secret(ciphertext);

// Check if equal
assertArrayEquals(shared_secret_client, shared_secret_server, kem_name);

// If successful print KEM name, otherwise an exception will be thrown
sb.append("\033[0;32m").append("PASSED").append("\033[0m");
System.out.println(sb.toString());
}

/**
* Test the MechanismNotSupported Exception
*/
Expand All @@ -71,4 +109,12 @@ private static Stream<String> getEnabledKEMsAsStream() {
return enabled_kems.parallelStream();
}

/**
* Method to convert the list of derand-supported KEMs to a stream for input to testAllSigs
*/
private static Stream<String> getDerandSupportedKEMsAsStream() {
return Arrays.asList(
"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"
).parallelStream();
}
}
Loading