Skip to content

Commit

Permalink
[PQ] Add experimental support for PQ/T hybrid KEMs (#1741)
Browse files Browse the repository at this point in the history
Add an experimental implementation of PQ/T Hybrid KEMs.
  • Loading branch information
sgmenda-aws authored Aug 13, 2024
1 parent 0574778 commit 1d0fb39
Show file tree
Hide file tree
Showing 14 changed files with 905 additions and 5 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# EXPERIMENTAL BRANCH

This branch includes an experimental implementation of [PQ/T Hybrid KEMs](./crypto/pqt/README.md).

---

# AWS libcrypto (AWS-LC)

AWS-LC is a general-purpose cryptographic library maintained by the AWS Cryptography
Expand Down
1 change: 1 addition & 0 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ add_library(
poly1305/poly1305_arm.c
poly1305/poly1305_vec.c
pool/pool.c
pqt/pqt_kem.c
rand_extra/deterministic.c
rand_extra/entropy_passive.c
rand_extra/forkunsafe.c
Expand Down
14 changes: 14 additions & 0 deletions crypto/evp_extra/evp_extra_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <openssl/err.h>
#include <openssl/experimental/kem_deterministic_api.h>
#include <openssl/pkcs8.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>

#include "../test/file_test.h"
Expand Down Expand Up @@ -2075,6 +2076,9 @@ static const struct KnownKEM kKEMs[] = {
{"MLKEM512IPD", NID_MLKEM512IPD, 800, 1632, 768, 32, 64, 32, "ml_kem/kat/mlkem512ipd.txt"},
{"MLKEM768IPD", NID_MLKEM768IPD, 1184, 2400, 1088, 32, 64, 32, "ml_kem/kat/mlkem768ipd.txt"},
{"MLKEM1024IPD", NID_MLKEM1024IPD, 1568, 3168, 1568, 32, 64, 32, "ml_kem/kat/mlkem1024ipd.txt"},
{"PQT25519", NID_PQT25519, 1216, 2464, 1120, 32, 96, 64, "pqt/kat/pqt25519.txt"},
{"PQT256", NID_PQT256, 1249, 2497, 1153, 32, 112, 80, "pqt/kat/pqt256.txt"},
{"PQT384", NID_PQT384, 1665, 3313, 1665, 32, 128, 96, "pqt/kat/pqt384.txt"},
};

class PerKEMTest : public testing::TestWithParam<KnownKEM> {};
Expand Down Expand Up @@ -2648,6 +2652,13 @@ TEST_P(PerKEMTest, RawKeyOperations) {
// The "coins" provided to key generation are "keypair_coins".
// The "coins" provided to key encapsulation are "encap_coins".
TEST_P(PerKEMTest, KAT) {
// FIXME(sanketh): generate KATs for PQ/T KEMs.
if ((strcmp(GetParam().name, "PQT25519") == 0) ||
(strcmp(GetParam().name, "PQT256") == 0) ||
(strcmp(GetParam().name, "PQT384") == 0)) {
return;
}

std::string kat_filepath = "crypto/";
kat_filepath += GetParam().kat_filename;

Expand Down Expand Up @@ -2769,6 +2780,9 @@ TEST_P(PerKEMTest, EncapsSeedTest) {
std::vector<uint8_t> ss(ss_len);
std::vector<uint8_t> es(es_len);

// Randomize the seed
RAND_bytes(es.data(), es_len);

// ---- 3. Test calling encapsulate with different lengths ----
// Set ct length to be less than expected -- should fail.
ct_len = GetParam().ciphertext_len - 1;
Expand Down
7 changes: 5 additions & 2 deletions crypto/kem/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ extern "C" {

// KEM_METHOD structure and helper functions.
typedef struct {
int (*keygen_deterministic)(uint8_t *ctx,
uint8_t *pkey,
int (*keygen_deterministic)(uint8_t *public_key,
uint8_t *secret_key,
const uint8_t *seed);

int (*keygen)(uint8_t *public_key,
Expand All @@ -40,6 +40,9 @@ extern const KEM_METHOD kem_kyber1024r3_method;
extern const KEM_METHOD kem_ml_kem_512_ipd_method;
extern const KEM_METHOD kem_ml_kem_768_ipd_method;
extern const KEM_METHOD kem_ml_kem_1024_ipd_method;
extern const KEM_METHOD kem_pqt25519_method;
extern const KEM_METHOD kem_pqt256_method;
extern const KEM_METHOD kem_pqt384_method;

// KEM structure and helper functions.
typedef struct {
Expand Down
45 changes: 44 additions & 1 deletion crypto/kem/kem.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "internal.h"
#include "../kyber/kem_kyber.h"
#include "../ml_kem/ml_kem.h"
#include "../pqt/pqt_kem.h"


// The KEM parameters listed below are taken from corresponding specifications.
Expand All @@ -19,7 +20,7 @@
// - Kyber is not standardized yet, so we use the latest specification
// from Round 3 of NIST PQC project.

#define AWSLC_NUM_BUILT_IN_KEMS 6
#define AWSLC_NUM_BUILT_IN_KEMS 9

// TODO(awslc): placeholder OIDs, replace with the real ones when available.
static const uint8_t kOIDKyber512r3[] = {0xff, 0xff, 0xff, 0xff};
Expand All @@ -28,6 +29,9 @@ static const uint8_t kOIDKyber1024r3[] = {0xff, 0xff, 0xff, 0xff};
static const uint8_t kOIDMLKEM512IPD[] = {0xff, 0xff, 0xff, 0xff};
static const uint8_t kOIDMLKEM768IPD[] = {0xff, 0xff, 0xff, 0xff};
static const uint8_t kOIDMLKEM1024IPD[] = {0xff, 0xff, 0xff, 0xff};
static const uint8_t kOIDPQT25519[] = {0xff, 0xff, 0xff, 0xff};
static const uint8_t kOIDPQT256[] = {0xff, 0xff, 0xff, 0xff};
static const uint8_t kOIDPQT384[] = {0xff, 0xff, 0xff, 0xff};

static const KEM built_in_kems[AWSLC_NUM_BUILT_IN_KEMS] = {
{
Expand Down Expand Up @@ -110,6 +114,45 @@ static const KEM built_in_kems[AWSLC_NUM_BUILT_IN_KEMS] = {
MLKEM1024IPD_ENCAPS_SEED_LEN, // kem.encaps_seed_len
&kem_ml_kem_1024_ipd_method, // kem.method
},
{
NID_PQT25519, // kem.nid
kOIDPQT25519, // kem.oid
sizeof(kOIDPQT25519), // kem.oid_len
"PQT25519", // kem.comment
PQT25519_PUBLIC_KEY_BYTES, // kem.public_key_len
PQT25519_SECRET_KEY_BYTES, // kem.secret_key_len
PQT25519_CIPHERTEXT_BYTES, // kem.ciphertext_len
PQT25519_SHARED_SECRET_LEN, // kem.shared_secret_len
PQT25519_KEYGEN_SEED_LEN, // kem.keygen_seed_len
PQT25519_ENCAPS_SEED_LEN, // kem.encaps_seed_len
&kem_pqt25519_method, // kem.method
},
{
NID_PQT256, // kem.nid
kOIDPQT256, // kem.oid
sizeof(kOIDPQT256), // kem.oid_len
"PQT256", // kem.comment
PQT256_PUBLIC_KEY_BYTES, // kem.public_key_len
PQT256_SECRET_KEY_BYTES, // kem.secret_key_len
PQT256_CIPHERTEXT_BYTES, // kem.ciphertext_len
PQT256_SHARED_SECRET_LEN, // kem.shared_secret_len
PQT256_KEYGEN_SEED_LEN, // kem.keygen_seed_len
PQT256_ENCAPS_SEED_LEN, // kem.encaps_seed_len
&kem_pqt256_method, // kem.method
},
{
NID_PQT384, // kem.nid
kOIDPQT384, // kem.oid
sizeof(kOIDPQT384), // kem.oid_len
"PQT384", // kem.comment
PQT384_PUBLIC_KEY_BYTES, // kem.public_key_len
PQT384_SECRET_KEY_BYTES, // kem.secret_key_len
PQT384_CIPHERTEXT_BYTES, // kem.ciphertext_len
PQT384_SHARED_SECRET_LEN, // kem.shared_secret_len
PQT384_KEYGEN_SEED_LEN, // kem.keygen_seed_len
PQT384_ENCAPS_SEED_LEN, // kem.encaps_seed_len
&kem_pqt384_method, // kem.method
},
};

const KEM *KEM_find_kem_by_nid(int nid) {
Expand Down
25 changes: 25 additions & 0 deletions crypto/kem/kem_methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "../kyber/kem_kyber.h"
#include "../ml_kem/ml_kem.h"
#include "../pqt/pqt_kem.h"

static int kyber512r3_keygen_deterministic(uint8_t *public_key,
uint8_t *secret_key,
Expand Down Expand Up @@ -237,3 +238,27 @@ const KEM_METHOD kem_ml_kem_1024_ipd_method = {
ml_kem_1024_ipd_encaps,
ml_kem_1024_ipd_decaps,
};

const KEM_METHOD kem_pqt25519_method = {
pqt25519_keygen_deterministic,
pqt25519_keygen,
pqt25519_encaps_deterministic,
pqt25519_encaps,
pqt25519_decaps,
};

const KEM_METHOD kem_pqt256_method = {
pqt256_keygen_deterministic,
pqt256_keygen,
pqt256_encaps_deterministic,
pqt256_encaps,
pqt256_decaps,
};

const KEM_METHOD kem_pqt384_method = {
pqt384_keygen_deterministic,
pqt384_keygen,
pqt384_encaps_deterministic,
pqt384_encaps,
pqt384_decaps,
};
11 changes: 10 additions & 1 deletion crypto/obj/obj_dat.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@

/* This file is generated by crypto/obj/objects.go. */

#define NUM_NID 988
#define NUM_NID 991

static const uint8_t kObjectData[] = {
/* NID_rsadsi */
Expand Down Expand Up @@ -8891,6 +8891,9 @@ static const ASN1_OBJECT kObjects[NUM_NID] = {
{"MLKEM512IPD", "MLKEM512IPD", NID_MLKEM512IPD, 0, NULL, 0},
{"MLKEM768IPD", "MLKEM768IPD", NID_MLKEM768IPD, 0, NULL, 0},
{"MLKEM1024IPD", "MLKEM1024IPD", NID_MLKEM1024IPD, 0, NULL, 0},
{"PQT25519", "PQT25519", NID_PQT25519, 0, NULL, 0},
{"PQT256", "PQT256", NID_PQT256, 0, NULL, 0},
{"PQT384", "PQT384", NID_PQT384, 0, NULL, 0},
};

static const uint16_t kNIDsInShortNameOrder[] = {
Expand Down Expand Up @@ -9050,6 +9053,9 @@ static const uint16_t kNIDsInShortNameOrder[] = {
69 /* PBKDF2 */,
162 /* PBMAC1 */,
127 /* PKIX */,
988 /* PQT25519 */,
989 /* PQT256 */,
990 /* PQT384 */,
935 /* PSPECIFIED */,
98 /* RC2-40-CBC */,
166 /* RC2-64-CBC */,
Expand Down Expand Up @@ -9970,6 +9976,9 @@ static const uint16_t kNIDsInLongNameOrder[] = {
69 /* PBKDF2 */,
162 /* PBMAC1 */,
127 /* PKIX */,
988 /* PQT25519 */,
989 /* PQT256 */,
990 /* PQT384 */,
858 /* Permanent Identifier */,
164 /* Policy Qualifier CPS */,
165 /* Policy Qualifier User Notice */,
Expand Down
3 changes: 3 additions & 0 deletions crypto/obj/obj_mac.num
Original file line number Diff line number Diff line change
Expand Up @@ -975,3 +975,6 @@ ffdhe8192 984
MLKEM512IPD 985
MLKEM768IPD 986
MLKEM1024IPD 987
PQT25519 988
PQT256 989
PQT384 990
3 changes: 3 additions & 0 deletions crypto/obj/objects.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,9 @@ nist_sha3hashalgs 12 : SHAKE256 : shake256
: MLKEM512IPD
: MLKEM768IPD
: MLKEM1024IPD
: PQT25519
: PQT256
: PQT384

# OID for DILITHIUM3 SIG Round-3. These are temp values from
# https://github.com/IETF-Hackathon/pqc-certificates/blob/master/docs/oid_mapping.md
Expand Down
11 changes: 11 additions & 0 deletions crypto/pqt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# PQ/T Hybrid KEMs

The source code in this folder implements post-quantum/traditional hybrid KEMs as defined in [LINK TO DESIGN DOCUMENT].

## Usage

These KEMs implement the standard KEM API, see [crypto/kem/README.md](../kem/README.md).

## KATs and Testing

FIXME(sanketh): add KATs.
Loading

0 comments on commit 1d0fb39

Please sign in to comment.