├── .gitignore ├── README.md ├── firefox.patch └── nss.patch /.gitignore: -------------------------------------------------------------------------------- 1 | bootstrap.py 2 | cf-go 3 | mozilla-unified 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TLS 1.3 With X25519+Kyber512 in Firefox 2 | 3 | (For the KEMTLS demo, switch to the `kemtls` branch.) 4 | 5 | 1. Run `build.sh`. Keep the default `mozilla-unified` as the source directory, and when asked to choose which version of Firefox to build, choose option 2: `Firefox for Desktop`. 6 | 7 | 2. Start Firefox by running `./mozilla-unified/mach run` 8 | 9 | 3. In Firefox, load `https://pq.cloudflareresearch.com`. 10 | -------------------------------------------------------------------------------- /firefox.patch: -------------------------------------------------------------------------------- 1 | diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp 2 | --- a/netwerk/protocol/http/Http2Session.cpp 3 | +++ b/netwerk/protocol/http/Http2Session.cpp 4 | @@ -4229,7 +4229,7 @@ nsresult Http2Session::ConfirmTLSProfile 5 | } 6 | 7 | uint16_t kea = ssl->GetKEAUsed(); 8 | - if (kea != ssl_kea_dh && kea != ssl_kea_ecdh) { 9 | + if (kea != ssl_kea_dh && kea != ssl_kea_ecdh && kea != ssl_kea_x25519Kyber512Draft00) { 10 | LOG3(("Http2Session::ConfirmTLSProfile %p FAILED due to invalid KEA %d\n", 11 | this, kea)); 12 | return SessionError(INADEQUATE_SECURITY); 13 | diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp 14 | --- a/security/manager/ssl/nsNSSCallbacks.cpp 15 | +++ b/security/manager/ssl/nsNSSCallbacks.cpp 16 | @@ -612,6 +612,9 @@ char* PK11PasswordPrompt(PK11SlotInfo* s 17 | nsCString getKeaGroupName(uint32_t aKeaGroup) { 18 | nsCString groupName; 19 | switch (aKeaGroup) { 20 | + case ssl_grp_x25519Kyber512Draft00: 21 | + groupName = "X25519Kyber512Draft00"_ns; 22 | + break; 23 | case ssl_grp_ec_secp256r1: 24 | groupName = "P256"_ns; 25 | break; 26 | @@ -1194,6 +1197,8 @@ void HandshakeCallback(PRFileDesc* fd, v 27 | AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL, 28 | channelInfo.keaKeyBits); 29 | break; 30 | + case ssl_kea_x25519Kyber512Draft00: 31 | + break; 32 | default: 33 | MOZ_CRASH("impossible KEA"); 34 | break; 35 | diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp 36 | --- a/security/manager/ssl/nsNSSIOLayer.cpp 37 | +++ b/security/manager/ssl/nsNSSIOLayer.cpp 38 | @@ -2008,9 +2008,7 @@ static nsresult nsSSLIOLayerSetOptions(P 39 | // Include a modest set of named groups. 40 | // Please change getKeaGroupName in nsNSSCallbacks.cpp when changing the list 41 | // here. 42 | - const SSLNamedGroup namedGroups[] = { 43 | - ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, 44 | - ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072}; 45 | + const SSLNamedGroup namedGroups[] = { ssl_grp_x25519Kyber512Draft00 }; 46 | if (SECSuccess != SSL_NamedGroupConfig(fd, namedGroups, 47 | mozilla::ArrayLength(namedGroups))) { 48 | return NS_ERROR_FAILURE; 49 | -------------------------------------------------------------------------------- /nss.patch: -------------------------------------------------------------------------------- 1 | diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c 2 | index d9270ed92..d11f49ef0 100644 3 | --- a/cmd/lib/secutil.c 4 | +++ b/cmd/lib/secutil.c 5 | @@ -4205,6 +4205,9 @@ groupNameToNamedGroup(char *name) 6 | return ssl_grp_ffdhe_8192; 7 | } 8 | } 9 | + if (!strncmp(name, "X25519Kyber512Draft00", 21)) { 10 | + return ssl_grp_x25519Kyber512Draft00; 11 | + } 12 | 13 | return ssl_grp_none; 14 | } 15 | diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c 16 | index d26851d98..4c30c52e5 100644 17 | --- a/cmd/selfserv/selfserv.c 18 | +++ b/cmd/selfserv/selfserv.c 19 | @@ -229,7 +229,7 @@ PrintParameterUsage() 20 | "-Q enables ALPN for HTTP/1.1 [RFC7301]\n" 21 | "-I comma separated list of enabled groups for TLS key exchange.\n" 22 | " The following values are valid:\n" 23 | - " P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n" 24 | + " X25519Kyber512Draft00, P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n" 25 | "-J comma separated list of enabled signature schemes in preference order.\n" 26 | " The following values are valid:\n" 27 | " rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n" 28 | diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c 29 | index cbf824ec1..596dc2e2c 100644 30 | --- a/cmd/tstclnt/tstclnt.c 31 | +++ b/cmd/tstclnt/tstclnt.c 32 | @@ -304,7 +304,7 @@ PrintParameterUsage() 33 | fprintf(stderr, "%-20s Disconnect and reconnect up to N times total\n", "-L"); 34 | fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n" 35 | "%-20s The following values are valid:\n" 36 | - "%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n", 37 | + "%-20s X25519Kyber512Draft00, P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n", 38 | "-I", "", ""); 39 | fprintf(stderr, "%-20s Comma separated list of signature schemes in preference order.\n" 40 | "%-20s The following values are valid:\n" 41 | diff --git a/gtests/pk11_gtest/pk11_import_unittest.cc b/gtests/pk11_gtest/pk11_import_unittest.cc 42 | index 3dc7983f8..56197e09a 100644 43 | --- a/gtests/pk11_gtest/pk11_import_unittest.cc 44 | +++ b/gtests/pk11_gtest/pk11_import_unittest.cc 45 | @@ -91,6 +91,7 @@ class Pk11KeyImportTestBase : public ::testing::Test { 46 | return pub_key->u.ec.publicValue; 47 | case fortezzaKey: /* depricated */ 48 | case nullKey: 49 | + case x25519Kyber512Draft00Key: 50 | /* didn't use default here so we can catch new key types at compile time 51 | */ 52 | break; 53 | diff --git a/lib/cryptohi/keythi.h b/lib/cryptohi/keythi.h 54 | index f6170bb78..213c17c46 100644 55 | --- a/lib/cryptohi/keythi.h 56 | +++ b/lib/cryptohi/keythi.h 57 | @@ -33,7 +33,8 @@ typedef enum { 58 | keaKey = 5, /* deprecated */ 59 | ecKey = 6, 60 | rsaPssKey = 7, 61 | - rsaOaepKey = 8 62 | + rsaOaepKey = 8, 63 | + x25519Kyber512Draft00Key = 9 64 | } KeyType; 65 | 66 | /* 67 | diff --git a/lib/freebl/blapi.h b/lib/freebl/blapi.h 68 | index 94fd80222..e0501c563 100644 69 | --- a/lib/freebl/blapi.h 70 | +++ b/lib/freebl/blapi.h 71 | @@ -1791,6 +1791,14 @@ extern SECStatus EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, 72 | */ 73 | extern int EC_GetPointSize(const ECParams *params); 74 | 75 | +/****************************************************** 76 | +** X25519Kyber512Draft00 algorithms 77 | +*/ 78 | + 79 | +extern SECStatus X25519Kyber512Draft00_Generate(SECItem **publicKey, SECItem **secretKey); 80 | +extern SECStatus X25519Kyber512Draft00_Encapsulate(SECItem **ciphertext, SECItem **sharedSecret, SECItem *publicKey); 81 | +extern SECStatus X25519Kyber512Draft00_Decapsulate(SECItem **sharedSecret, SECItem *ciphertext, SECItem *secretKey); 82 | + 83 | SEC_END_PROTOS 84 | 85 | #endif /* _BLAPI_H_ */ 86 | diff --git a/lib/freebl/blapit.h b/lib/freebl/blapit.h 87 | index 0054e17b8..4e8a55632 100644 88 | --- a/lib/freebl/blapit.h 89 | +++ b/lib/freebl/blapit.h 90 | @@ -228,6 +228,8 @@ typedef int __BLAPI_DEPRECATED __attribute__((deprecated)); 91 | * to use a random value for the nonce in TLS. */ 92 | #define GCMIV_RANDOM_BIRTHDAY_BITS 64 93 | 94 | +#define X25519KYBER512DRAFT00_PUBLICKEYBYTES 800 95 | + 96 | /*************************************************************************** 97 | ** Opaque objects 98 | */ 99 | diff --git a/lib/freebl/freebl.gyp b/lib/freebl/freebl.gyp 100 | index 72e1b9b73..eb41f4afa 100644 101 | --- a/lib/freebl/freebl.gyp 102 | +++ b/lib/freebl/freebl.gyp 103 | @@ -760,6 +760,7 @@ 104 | 'include_dirs': [ 105 | 'mpi', 106 | 'ecl', 107 | + 'kyber512', 108 | 'verified', 109 | 'verified/kremlin/include', 110 | 'verified/kremlin/kremlib/dist/minimal', 111 | diff --git a/lib/freebl/freebl_base.gypi b/lib/freebl/freebl_base.gypi 112 | index 34b6b3c81..7bf3d341e 100644 113 | --- a/lib/freebl/freebl_base.gypi 114 | +++ b/lib/freebl/freebl_base.gypi 115 | @@ -61,6 +61,18 @@ 116 | 'sysrand.c', 117 | 'tlsprfalg.c', 118 | 'secmpi.c', 119 | + 'kyber512/cbd.c', 120 | + 'kyber512/indcpa.c', 121 | + 'kyber512/kem.c', 122 | + 'kyber512/ntt.c', 123 | + 'kyber512/poly.c', 124 | + 'kyber512/polyvec.c', 125 | + 'kyber512/reduce.c', 126 | + 'kyber512/symmetric-shake.c', 127 | + 'kyber512/verify.c', 128 | + 'kyber512/fips202.c', 129 | + 'kyber512/randombytes.c', 130 | + 'x25519Kyber512.c', 131 | ], 132 | 'conditions': [ 133 | [ 'OS=="linux" or OS=="android"', { 134 | diff --git a/lib/freebl/kyber512/LICENSE b/lib/freebl/kyber512/LICENSE 135 | new file mode 100644 136 | index 000000000..08473af75 137 | --- /dev/null 138 | +++ b/lib/freebl/kyber512/LICENSE 139 | @@ -0,0 +1,5 @@ 140 | +Public Domain (https://creativecommons.org/share-your-work/public-domain/cc0/) 141 | + 142 | +For Keccak and AES we are using public-domain 143 | +code from sources and by authors listed in 144 | +comments on top of the respective files. 145 | diff --git a/lib/freebl/kyber512/api.h b/lib/freebl/kyber512/api.h 146 | new file mode 100644 147 | index 000000000..29817fe3c 148 | --- /dev/null 149 | +++ b/lib/freebl/kyber512/api.h 150 | @@ -0,0 +1,18 @@ 151 | +#ifndef PQCLEAN_KYBER512_CLEAN_API_H 152 | +#define PQCLEAN_KYBER512_CLEAN_API_H 153 | + 154 | +#include 155 | + 156 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_SECRETKEYBYTES 1632 157 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_PUBLICKEYBYTES 800 158 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_CIPHERTEXTBYTES 768 159 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_BYTES 32 160 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_ALGNAME "Kyber512" 161 | + 162 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); 163 | + 164 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); 165 | + 166 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); 167 | + 168 | +#endif 169 | diff --git a/lib/freebl/kyber512/cbd.c b/lib/freebl/kyber512/cbd.c 170 | new file mode 100644 171 | index 000000000..ff6613209 172 | --- /dev/null 173 | +++ b/lib/freebl/kyber512/cbd.c 174 | @@ -0,0 +1,108 @@ 175 | +#include "cbd.h" 176 | +#include "params.h" 177 | +#include 178 | + 179 | +/************************************************* 180 | +* Name: load32_littleendian 181 | +* 182 | +* Description: load 4 bytes into a 32-bit integer 183 | +* in little-endian order 184 | +* 185 | +* Arguments: - const uint8_t *x: pointer to input byte array 186 | +* 187 | +* Returns 32-bit unsigned integer loaded from x 188 | +**************************************************/ 189 | +static uint32_t load32_littleendian(const uint8_t x[4]) { 190 | + uint32_t r; 191 | + r = (uint32_t)x[0]; 192 | + r |= (uint32_t)x[1] << 8; 193 | + r |= (uint32_t)x[2] << 16; 194 | + r |= (uint32_t)x[3] << 24; 195 | + return r; 196 | +} 197 | + 198 | +/************************************************* 199 | +* Name: load24_littleendian 200 | +* 201 | +* Description: load 3 bytes into a 32-bit integer 202 | +* in little-endian order. 203 | +* This function is only needed for Kyber-512 204 | +* 205 | +* Arguments: - const uint8_t *x: pointer to input byte array 206 | +* 207 | +* Returns 32-bit unsigned integer loaded from x (most significant byte is zero) 208 | +**************************************************/ 209 | +static uint32_t load24_littleendian(const uint8_t x[3]) { 210 | + uint32_t r; 211 | + r = (uint32_t)x[0]; 212 | + r |= (uint32_t)x[1] << 8; 213 | + r |= (uint32_t)x[2] << 16; 214 | + return r; 215 | +} 216 | + 217 | + 218 | +/************************************************* 219 | +* Name: cbd2 220 | +* 221 | +* Description: Given an array of uniformly random bytes, compute 222 | +* polynomial with coefficients distributed according to 223 | +* a centered binomial distribution with parameter eta=2 224 | +* 225 | +* Arguments: - poly *r: pointer to output polynomial 226 | +* - const uint8_t *buf: pointer to input byte array 227 | +**************************************************/ 228 | +static void cbd2(poly *r, const uint8_t buf[2 * KYBER_N / 4]) { 229 | + unsigned int i, j; 230 | + uint32_t t, d; 231 | + int16_t a, b; 232 | + 233 | + for (i = 0; i < KYBER_N / 8; i++) { 234 | + t = load32_littleendian(buf + 4 * i); 235 | + d = t & 0x55555555; 236 | + d += (t >> 1) & 0x55555555; 237 | + 238 | + for (j = 0; j < 8; j++) { 239 | + a = (d >> (4 * j + 0)) & 0x3; 240 | + b = (d >> (4 * j + 2)) & 0x3; 241 | + r->coeffs[8 * i + j] = a - b; 242 | + } 243 | + } 244 | +} 245 | + 246 | +/************************************************* 247 | +* Name: cbd3 248 | +* 249 | +* Description: Given an array of uniformly random bytes, compute 250 | +* polynomial with coefficients distributed according to 251 | +* a centered binomial distribution with parameter eta=3. 252 | +* This function is only needed for Kyber-512 253 | +* 254 | +* Arguments: - poly *r: pointer to output polynomial 255 | +* - const uint8_t *buf: pointer to input byte array 256 | +**************************************************/ 257 | +static void cbd3(poly *r, const uint8_t buf[3 * KYBER_N / 4]) { 258 | + unsigned int i, j; 259 | + uint32_t t, d; 260 | + int16_t a, b; 261 | + 262 | + for (i = 0; i < KYBER_N / 4; i++) { 263 | + t = load24_littleendian(buf + 3 * i); 264 | + d = t & 0x00249249; 265 | + d += (t >> 1) & 0x00249249; 266 | + d += (t >> 2) & 0x00249249; 267 | + 268 | + for (j = 0; j < 4; j++) { 269 | + a = (d >> (6 * j + 0)) & 0x7; 270 | + b = (d >> (6 * j + 3)) & 0x7; 271 | + r->coeffs[4 * i + j] = a - b; 272 | + } 273 | + } 274 | +} 275 | + 276 | +void PQCLEAN_KYBER512_CLEAN_poly_cbd_eta1(poly *r, const uint8_t buf[KYBER_ETA1 * KYBER_N / 4]) { 277 | + cbd3(r, buf); 278 | +} 279 | + 280 | +void PQCLEAN_KYBER512_CLEAN_poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2 * KYBER_N / 4]) { 281 | + cbd2(r, buf); 282 | +} 283 | diff --git a/lib/freebl/kyber512/cbd.h b/lib/freebl/kyber512/cbd.h 284 | new file mode 100644 285 | index 000000000..fc8788b33 286 | --- /dev/null 287 | +++ b/lib/freebl/kyber512/cbd.h 288 | @@ -0,0 +1,11 @@ 289 | +#ifndef PQCLEAN_KYBER512_CLEAN_CBD_H 290 | +#define PQCLEAN_KYBER512_CLEAN_CBD_H 291 | +#include "params.h" 292 | +#include "poly.h" 293 | +#include 294 | + 295 | +void PQCLEAN_KYBER512_CLEAN_poly_cbd_eta1(poly *r, const uint8_t buf[KYBER_ETA1 * KYBER_N / 4]); 296 | + 297 | +void PQCLEAN_KYBER512_CLEAN_poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2 * KYBER_N / 4]); 298 | + 299 | +#endif 300 | diff --git a/lib/freebl/kyber512/fips202.c b/lib/freebl/kyber512/fips202.c 301 | new file mode 100644 302 | index 000000000..6a13446b0 303 | --- /dev/null 304 | +++ b/lib/freebl/kyber512/fips202.c 305 | @@ -0,0 +1,929 @@ 306 | +/* Based on the public domain implementation in 307 | + * crypto_hash/keccakc512/simple/ from http://bench.cr.yp.to/supercop.html 308 | + * by Ronny Van Keer 309 | + * and the public domain "TweetFips202" implementation 310 | + * from https://twitter.com/tweetfips202 311 | + * by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe */ 312 | + 313 | +#include 314 | +#include 315 | +#include 316 | +#include 317 | + 318 | +#include "fips202.h" 319 | + 320 | +#define NROUNDS 24 321 | +#define ROL(a, offset) (((a) << (offset)) ^ ((a) >> (64 - (offset)))) 322 | + 323 | +/************************************************* 324 | + * Name: load64 325 | + * 326 | + * Description: Load 8 bytes into uint64_t in little-endian order 327 | + * 328 | + * Arguments: - const uint8_t *x: pointer to input byte array 329 | + * 330 | + * Returns the loaded 64-bit unsigned integer 331 | + **************************************************/ 332 | +static uint64_t load64(const uint8_t *x) { 333 | + uint64_t r = 0; 334 | + for (size_t i = 0; i < 8; ++i) { 335 | + r |= (uint64_t)x[i] << 8 * i; 336 | + } 337 | + 338 | + return r; 339 | +} 340 | + 341 | +/************************************************* 342 | + * Name: store64 343 | + * 344 | + * Description: Store a 64-bit integer to a byte array in little-endian order 345 | + * 346 | + * Arguments: - uint8_t *x: pointer to the output byte array 347 | + * - uint64_t u: input 64-bit unsigned integer 348 | + **************************************************/ 349 | +static void store64(uint8_t *x, uint64_t u) { 350 | + for (size_t i = 0; i < 8; ++i) { 351 | + x[i] = (uint8_t) (u >> 8 * i); 352 | + } 353 | +} 354 | + 355 | +/* Keccak round constants */ 356 | +static const uint64_t KeccakF_RoundConstants[NROUNDS] = { 357 | + 0x0000000000000001ULL, 0x0000000000008082ULL, 358 | + 0x800000000000808aULL, 0x8000000080008000ULL, 359 | + 0x000000000000808bULL, 0x0000000080000001ULL, 360 | + 0x8000000080008081ULL, 0x8000000000008009ULL, 361 | + 0x000000000000008aULL, 0x0000000000000088ULL, 362 | + 0x0000000080008009ULL, 0x000000008000000aULL, 363 | + 0x000000008000808bULL, 0x800000000000008bULL, 364 | + 0x8000000000008089ULL, 0x8000000000008003ULL, 365 | + 0x8000000000008002ULL, 0x8000000000000080ULL, 366 | + 0x000000000000800aULL, 0x800000008000000aULL, 367 | + 0x8000000080008081ULL, 0x8000000000008080ULL, 368 | + 0x0000000080000001ULL, 0x8000000080008008ULL 369 | +}; 370 | + 371 | +/************************************************* 372 | + * Name: KeccakF1600_StatePermute 373 | + * 374 | + * Description: The Keccak F1600 Permutation 375 | + * 376 | + * Arguments: - uint64_t *state: pointer to input/output Keccak state 377 | + **************************************************/ 378 | +static void KeccakF1600_StatePermute(uint64_t *state) { 379 | + int round; 380 | + 381 | + uint64_t Aba, Abe, Abi, Abo, Abu; 382 | + uint64_t Aga, Age, Agi, Ago, Agu; 383 | + uint64_t Aka, Ake, Aki, Ako, Aku; 384 | + uint64_t Ama, Ame, Ami, Amo, Amu; 385 | + uint64_t Asa, Ase, Asi, Aso, Asu; 386 | + uint64_t BCa, BCe, BCi, BCo, BCu; 387 | + uint64_t Da, De, Di, Do, Du; 388 | + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; 389 | + uint64_t Ega, Ege, Egi, Ego, Egu; 390 | + uint64_t Eka, Eke, Eki, Eko, Eku; 391 | + uint64_t Ema, Eme, Emi, Emo, Emu; 392 | + uint64_t Esa, Ese, Esi, Eso, Esu; 393 | + 394 | + // copyFromState(A, state) 395 | + Aba = state[0]; 396 | + Abe = state[1]; 397 | + Abi = state[2]; 398 | + Abo = state[3]; 399 | + Abu = state[4]; 400 | + Aga = state[5]; 401 | + Age = state[6]; 402 | + Agi = state[7]; 403 | + Ago = state[8]; 404 | + Agu = state[9]; 405 | + Aka = state[10]; 406 | + Ake = state[11]; 407 | + Aki = state[12]; 408 | + Ako = state[13]; 409 | + Aku = state[14]; 410 | + Ama = state[15]; 411 | + Ame = state[16]; 412 | + Ami = state[17]; 413 | + Amo = state[18]; 414 | + Amu = state[19]; 415 | + Asa = state[20]; 416 | + Ase = state[21]; 417 | + Asi = state[22]; 418 | + Aso = state[23]; 419 | + Asu = state[24]; 420 | + 421 | + for (round = 0; round < NROUNDS; round += 2) { 422 | + // prepareTheta 423 | + BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; 424 | + BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; 425 | + BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; 426 | + BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; 427 | + BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; 428 | + 429 | + // thetaRhoPiChiIotaPrepareTheta(round , A, E) 430 | + Da = BCu ^ ROL(BCe, 1); 431 | + De = BCa ^ ROL(BCi, 1); 432 | + Di = BCe ^ ROL(BCo, 1); 433 | + Do = BCi ^ ROL(BCu, 1); 434 | + Du = BCo ^ ROL(BCa, 1); 435 | + 436 | + Aba ^= Da; 437 | + BCa = Aba; 438 | + Age ^= De; 439 | + BCe = ROL(Age, 44); 440 | + Aki ^= Di; 441 | + BCi = ROL(Aki, 43); 442 | + Amo ^= Do; 443 | + BCo = ROL(Amo, 21); 444 | + Asu ^= Du; 445 | + BCu = ROL(Asu, 14); 446 | + Eba = BCa ^ ((~BCe) & BCi); 447 | + Eba ^= KeccakF_RoundConstants[round]; 448 | + Ebe = BCe ^ ((~BCi) & BCo); 449 | + Ebi = BCi ^ ((~BCo) & BCu); 450 | + Ebo = BCo ^ ((~BCu) & BCa); 451 | + Ebu = BCu ^ ((~BCa) & BCe); 452 | + 453 | + Abo ^= Do; 454 | + BCa = ROL(Abo, 28); 455 | + Agu ^= Du; 456 | + BCe = ROL(Agu, 20); 457 | + Aka ^= Da; 458 | + BCi = ROL(Aka, 3); 459 | + Ame ^= De; 460 | + BCo = ROL(Ame, 45); 461 | + Asi ^= Di; 462 | + BCu = ROL(Asi, 61); 463 | + Ega = BCa ^ ((~BCe) & BCi); 464 | + Ege = BCe ^ ((~BCi) & BCo); 465 | + Egi = BCi ^ ((~BCo) & BCu); 466 | + Ego = BCo ^ ((~BCu) & BCa); 467 | + Egu = BCu ^ ((~BCa) & BCe); 468 | + 469 | + Abe ^= De; 470 | + BCa = ROL(Abe, 1); 471 | + Agi ^= Di; 472 | + BCe = ROL(Agi, 6); 473 | + Ako ^= Do; 474 | + BCi = ROL(Ako, 25); 475 | + Amu ^= Du; 476 | + BCo = ROL(Amu, 8); 477 | + Asa ^= Da; 478 | + BCu = ROL(Asa, 18); 479 | + Eka = BCa ^ ((~BCe) & BCi); 480 | + Eke = BCe ^ ((~BCi) & BCo); 481 | + Eki = BCi ^ ((~BCo) & BCu); 482 | + Eko = BCo ^ ((~BCu) & BCa); 483 | + Eku = BCu ^ ((~BCa) & BCe); 484 | + 485 | + Abu ^= Du; 486 | + BCa = ROL(Abu, 27); 487 | + Aga ^= Da; 488 | + BCe = ROL(Aga, 36); 489 | + Ake ^= De; 490 | + BCi = ROL(Ake, 10); 491 | + Ami ^= Di; 492 | + BCo = ROL(Ami, 15); 493 | + Aso ^= Do; 494 | + BCu = ROL(Aso, 56); 495 | + Ema = BCa ^ ((~BCe) & BCi); 496 | + Eme = BCe ^ ((~BCi) & BCo); 497 | + Emi = BCi ^ ((~BCo) & BCu); 498 | + Emo = BCo ^ ((~BCu) & BCa); 499 | + Emu = BCu ^ ((~BCa) & BCe); 500 | + 501 | + Abi ^= Di; 502 | + BCa = ROL(Abi, 62); 503 | + Ago ^= Do; 504 | + BCe = ROL(Ago, 55); 505 | + Aku ^= Du; 506 | + BCi = ROL(Aku, 39); 507 | + Ama ^= Da; 508 | + BCo = ROL(Ama, 41); 509 | + Ase ^= De; 510 | + BCu = ROL(Ase, 2); 511 | + Esa = BCa ^ ((~BCe) & BCi); 512 | + Ese = BCe ^ ((~BCi) & BCo); 513 | + Esi = BCi ^ ((~BCo) & BCu); 514 | + Eso = BCo ^ ((~BCu) & BCa); 515 | + Esu = BCu ^ ((~BCa) & BCe); 516 | + 517 | + // prepareTheta 518 | + BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa; 519 | + BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; 520 | + BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; 521 | + BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; 522 | + BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; 523 | + 524 | + // thetaRhoPiChiIotaPrepareTheta(round+1, E, A) 525 | + Da = BCu ^ ROL(BCe, 1); 526 | + De = BCa ^ ROL(BCi, 1); 527 | + Di = BCe ^ ROL(BCo, 1); 528 | + Do = BCi ^ ROL(BCu, 1); 529 | + Du = BCo ^ ROL(BCa, 1); 530 | + 531 | + Eba ^= Da; 532 | + BCa = Eba; 533 | + Ege ^= De; 534 | + BCe = ROL(Ege, 44); 535 | + Eki ^= Di; 536 | + BCi = ROL(Eki, 43); 537 | + Emo ^= Do; 538 | + BCo = ROL(Emo, 21); 539 | + Esu ^= Du; 540 | + BCu = ROL(Esu, 14); 541 | + Aba = BCa ^ ((~BCe) & BCi); 542 | + Aba ^= KeccakF_RoundConstants[round + 1]; 543 | + Abe = BCe ^ ((~BCi) & BCo); 544 | + Abi = BCi ^ ((~BCo) & BCu); 545 | + Abo = BCo ^ ((~BCu) & BCa); 546 | + Abu = BCu ^ ((~BCa) & BCe); 547 | + 548 | + Ebo ^= Do; 549 | + BCa = ROL(Ebo, 28); 550 | + Egu ^= Du; 551 | + BCe = ROL(Egu, 20); 552 | + Eka ^= Da; 553 | + BCi = ROL(Eka, 3); 554 | + Eme ^= De; 555 | + BCo = ROL(Eme, 45); 556 | + Esi ^= Di; 557 | + BCu = ROL(Esi, 61); 558 | + Aga = BCa ^ ((~BCe) & BCi); 559 | + Age = BCe ^ ((~BCi) & BCo); 560 | + Agi = BCi ^ ((~BCo) & BCu); 561 | + Ago = BCo ^ ((~BCu) & BCa); 562 | + Agu = BCu ^ ((~BCa) & BCe); 563 | + 564 | + Ebe ^= De; 565 | + BCa = ROL(Ebe, 1); 566 | + Egi ^= Di; 567 | + BCe = ROL(Egi, 6); 568 | + Eko ^= Do; 569 | + BCi = ROL(Eko, 25); 570 | + Emu ^= Du; 571 | + BCo = ROL(Emu, 8); 572 | + Esa ^= Da; 573 | + BCu = ROL(Esa, 18); 574 | + Aka = BCa ^ ((~BCe) & BCi); 575 | + Ake = BCe ^ ((~BCi) & BCo); 576 | + Aki = BCi ^ ((~BCo) & BCu); 577 | + Ako = BCo ^ ((~BCu) & BCa); 578 | + Aku = BCu ^ ((~BCa) & BCe); 579 | + 580 | + Ebu ^= Du; 581 | + BCa = ROL(Ebu, 27); 582 | + Ega ^= Da; 583 | + BCe = ROL(Ega, 36); 584 | + Eke ^= De; 585 | + BCi = ROL(Eke, 10); 586 | + Emi ^= Di; 587 | + BCo = ROL(Emi, 15); 588 | + Eso ^= Do; 589 | + BCu = ROL(Eso, 56); 590 | + Ama = BCa ^ ((~BCe) & BCi); 591 | + Ame = BCe ^ ((~BCi) & BCo); 592 | + Ami = BCi ^ ((~BCo) & BCu); 593 | + Amo = BCo ^ ((~BCu) & BCa); 594 | + Amu = BCu ^ ((~BCa) & BCe); 595 | + 596 | + Ebi ^= Di; 597 | + BCa = ROL(Ebi, 62); 598 | + Ego ^= Do; 599 | + BCe = ROL(Ego, 55); 600 | + Eku ^= Du; 601 | + BCi = ROL(Eku, 39); 602 | + Ema ^= Da; 603 | + BCo = ROL(Ema, 41); 604 | + Ese ^= De; 605 | + BCu = ROL(Ese, 2); 606 | + Asa = BCa ^ ((~BCe) & BCi); 607 | + Ase = BCe ^ ((~BCi) & BCo); 608 | + Asi = BCi ^ ((~BCo) & BCu); 609 | + Aso = BCo ^ ((~BCu) & BCa); 610 | + Asu = BCu ^ ((~BCa) & BCe); 611 | + } 612 | + 613 | + // copyToState(state, A) 614 | + state[0] = Aba; 615 | + state[1] = Abe; 616 | + state[2] = Abi; 617 | + state[3] = Abo; 618 | + state[4] = Abu; 619 | + state[5] = Aga; 620 | + state[6] = Age; 621 | + state[7] = Agi; 622 | + state[8] = Ago; 623 | + state[9] = Agu; 624 | + state[10] = Aka; 625 | + state[11] = Ake; 626 | + state[12] = Aki; 627 | + state[13] = Ako; 628 | + state[14] = Aku; 629 | + state[15] = Ama; 630 | + state[16] = Ame; 631 | + state[17] = Ami; 632 | + state[18] = Amo; 633 | + state[19] = Amu; 634 | + state[20] = Asa; 635 | + state[21] = Ase; 636 | + state[22] = Asi; 637 | + state[23] = Aso; 638 | + state[24] = Asu; 639 | +} 640 | + 641 | +/************************************************* 642 | + * Name: keccak_absorb 643 | + * 644 | + * Description: Absorb step of Keccak; 645 | + * non-incremental, starts by zeroeing the state. 646 | + * 647 | + * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state 648 | + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) 649 | + * - const uint8_t *m: pointer to input to be absorbed into s 650 | + * - size_t mlen: length of input in bytes 651 | + * - uint8_t p: domain-separation byte for different 652 | + * Keccak-derived functions 653 | + **************************************************/ 654 | +static void keccak_absorb(uint64_t *s, uint32_t r, const uint8_t *m, 655 | + size_t mlen, uint8_t p) { 656 | + size_t i; 657 | + uint8_t t[200]; 658 | + 659 | + /* Zero state */ 660 | + for (i = 0; i < 25; ++i) { 661 | + s[i] = 0; 662 | + } 663 | + 664 | + while (mlen >= r) { 665 | + for (i = 0; i < r / 8; ++i) { 666 | + s[i] ^= load64(m + 8 * i); 667 | + } 668 | + 669 | + KeccakF1600_StatePermute(s); 670 | + mlen -= r; 671 | + m += r; 672 | + } 673 | + 674 | + for (i = 0; i < r; ++i) { 675 | + t[i] = 0; 676 | + } 677 | + for (i = 0; i < mlen; ++i) { 678 | + t[i] = m[i]; 679 | + } 680 | + t[i] = p; 681 | + t[r - 1] |= 128; 682 | + for (i = 0; i < r / 8; ++i) { 683 | + s[i] ^= load64(t + 8 * i); 684 | + } 685 | +} 686 | + 687 | +/************************************************* 688 | + * Name: keccak_squeezeblocks 689 | + * 690 | + * Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each. 691 | + * Modifies the state. Can be called multiple times to keep 692 | + * squeezing, i.e., is incremental. 693 | + * 694 | + * Arguments: - uint8_t *h: pointer to output blocks 695 | + * - size_t nblocks: number of blocks to be 696 | + * squeezed (written to h) 697 | + * - uint64_t *s: pointer to input/output Keccak state 698 | + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) 699 | + **************************************************/ 700 | +static void keccak_squeezeblocks(uint8_t *h, size_t nblocks, 701 | + uint64_t *s, uint32_t r) { 702 | + while (nblocks > 0) { 703 | + KeccakF1600_StatePermute(s); 704 | + for (size_t i = 0; i < (r >> 3); i++) { 705 | + store64(h + 8 * i, s[i]); 706 | + } 707 | + h += r; 708 | + nblocks--; 709 | + } 710 | +} 711 | + 712 | +/************************************************* 713 | + * Name: keccak_inc_init 714 | + * 715 | + * Description: Initializes the incremental Keccak state to zero. 716 | + * 717 | + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state 718 | + * First 25 values represent Keccak state. 719 | + * 26th value represents either the number of absorbed bytes 720 | + * that have not been permuted, or not-yet-squeezed bytes. 721 | + **************************************************/ 722 | +static void keccak_inc_init(uint64_t *s_inc) { 723 | + size_t i; 724 | + 725 | + for (i = 0; i < 25; ++i) { 726 | + s_inc[i] = 0; 727 | + } 728 | + s_inc[25] = 0; 729 | +} 730 | + 731 | +/************************************************* 732 | + * Name: keccak_inc_absorb 733 | + * 734 | + * Description: Incremental keccak absorb 735 | + * Preceded by keccak_inc_init, succeeded by keccak_inc_finalize 736 | + * 737 | + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state 738 | + * First 25 values represent Keccak state. 739 | + * 26th value represents either the number of absorbed bytes 740 | + * that have not been permuted, or not-yet-squeezed bytes. 741 | + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) 742 | + * - const uint8_t *m: pointer to input to be absorbed into s 743 | + * - size_t mlen: length of input in bytes 744 | + **************************************************/ 745 | +static void keccak_inc_absorb(uint64_t *s_inc, uint32_t r, const uint8_t *m, 746 | + size_t mlen) { 747 | + size_t i; 748 | + 749 | + /* Recall that s_inc[25] is the non-absorbed bytes xored into the state */ 750 | + while (mlen + s_inc[25] >= r) { 751 | + for (i = 0; i < r - (uint32_t)s_inc[25]; i++) { 752 | + /* Take the i'th byte from message 753 | + xor with the s_inc[25] + i'th byte of the state; little-endian */ 754 | + s_inc[(s_inc[25] + i) >> 3] ^= (uint64_t)m[i] << (8 * ((s_inc[25] + i) & 0x07)); 755 | + } 756 | + mlen -= (size_t)(r - s_inc[25]); 757 | + m += r - s_inc[25]; 758 | + s_inc[25] = 0; 759 | + 760 | + KeccakF1600_StatePermute(s_inc); 761 | + } 762 | + 763 | + for (i = 0; i < mlen; i++) { 764 | + s_inc[(s_inc[25] + i) >> 3] ^= (uint64_t)m[i] << (8 * ((s_inc[25] + i) & 0x07)); 765 | + } 766 | + s_inc[25] += mlen; 767 | +} 768 | + 769 | +/************************************************* 770 | + * Name: keccak_inc_finalize 771 | + * 772 | + * Description: Finalizes Keccak absorb phase, prepares for squeezing 773 | + * 774 | + * Arguments: - uint64_t *s_inc: pointer to input/output incremental state 775 | + * First 25 values represent Keccak state. 776 | + * 26th value represents either the number of absorbed bytes 777 | + * that have not been permuted, or not-yet-squeezed bytes. 778 | + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) 779 | + * - uint8_t p: domain-separation byte for different 780 | + * Keccak-derived functions 781 | + **************************************************/ 782 | +static void keccak_inc_finalize(uint64_t *s_inc, uint32_t r, uint8_t p) { 783 | + /* After keccak_inc_absorb, we are guaranteed that s_inc[25] < r, 784 | + so we can always use one more byte for p in the current state. */ 785 | + s_inc[s_inc[25] >> 3] ^= (uint64_t)p << (8 * (s_inc[25] & 0x07)); 786 | + s_inc[(r - 1) >> 3] ^= (uint64_t)128 << (8 * ((r - 1) & 0x07)); 787 | + s_inc[25] = 0; 788 | +} 789 | + 790 | +/************************************************* 791 | + * Name: keccak_inc_squeeze 792 | + * 793 | + * Description: Incremental Keccak squeeze; can be called on byte-level 794 | + * 795 | + * Arguments: - uint8_t *h: pointer to output bytes 796 | + * - size_t outlen: number of bytes to be squeezed 797 | + * - uint64_t *s_inc: pointer to input/output incremental state 798 | + * First 25 values represent Keccak state. 799 | + * 26th value represents either the number of absorbed bytes 800 | + * that have not been permuted, or not-yet-squeezed bytes. 801 | + * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) 802 | + **************************************************/ 803 | +static void keccak_inc_squeeze(uint8_t *h, size_t outlen, 804 | + uint64_t *s_inc, uint32_t r) { 805 | + size_t i; 806 | + 807 | + /* First consume any bytes we still have sitting around */ 808 | + for (i = 0; i < outlen && i < s_inc[25]; i++) { 809 | + /* There are s_inc[25] bytes left, so r - s_inc[25] is the first 810 | + available byte. We consume from there, i.e., up to r. */ 811 | + h[i] = (uint8_t)(s_inc[(r - s_inc[25] + i) >> 3] >> (8 * ((r - s_inc[25] + i) & 0x07))); 812 | + } 813 | + h += i; 814 | + outlen -= i; 815 | + s_inc[25] -= i; 816 | + 817 | + /* Then squeeze the remaining necessary blocks */ 818 | + while (outlen > 0) { 819 | + KeccakF1600_StatePermute(s_inc); 820 | + 821 | + for (i = 0; i < outlen && i < r; i++) { 822 | + h[i] = (uint8_t)(s_inc[i >> 3] >> (8 * (i & 0x07))); 823 | + } 824 | + h += i; 825 | + outlen -= i; 826 | + s_inc[25] = r - i; 827 | + } 828 | +} 829 | + 830 | +void shake128_inc_init(shake128incctx *state) { 831 | + state->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 832 | + if (state->ctx == NULL) { 833 | + exit(111); 834 | + } 835 | + keccak_inc_init(state->ctx); 836 | +} 837 | + 838 | +void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen) { 839 | + keccak_inc_absorb(state->ctx, SHAKE128_RATE, input, inlen); 840 | +} 841 | + 842 | +void shake128_inc_finalize(shake128incctx *state) { 843 | + keccak_inc_finalize(state->ctx, SHAKE128_RATE, 0x1F); 844 | +} 845 | + 846 | +void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state) { 847 | + keccak_inc_squeeze(output, outlen, state->ctx, SHAKE128_RATE); 848 | +} 849 | + 850 | +void shake128_inc_ctx_clone(shake128incctx *dest, const shake128incctx *src) { 851 | + dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 852 | + if (dest->ctx == NULL) { 853 | + exit(111); 854 | + } 855 | + memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES); 856 | +} 857 | + 858 | +void shake128_inc_ctx_release(shake128incctx *state) { 859 | + free(state->ctx); 860 | +} 861 | + 862 | +void shake256_inc_init(shake256incctx *state) { 863 | + state->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 864 | + if (state->ctx == NULL) { 865 | + exit(111); 866 | + } 867 | + keccak_inc_init(state->ctx); 868 | +} 869 | + 870 | +void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen) { 871 | + keccak_inc_absorb(state->ctx, SHAKE256_RATE, input, inlen); 872 | +} 873 | + 874 | +void shake256_inc_finalize(shake256incctx *state) { 875 | + keccak_inc_finalize(state->ctx, SHAKE256_RATE, 0x1F); 876 | +} 877 | + 878 | +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state) { 879 | + keccak_inc_squeeze(output, outlen, state->ctx, SHAKE256_RATE); 880 | +} 881 | + 882 | +void shake256_inc_ctx_clone(shake256incctx *dest, const shake256incctx *src) { 883 | + dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 884 | + if (dest->ctx == NULL) { 885 | + exit(111); 886 | + } 887 | + memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES); 888 | +} 889 | + 890 | +void shake256_inc_ctx_release(shake256incctx *state) { 891 | + free(state->ctx); 892 | +} 893 | + 894 | + 895 | +/************************************************* 896 | + * Name: shake128_absorb 897 | + * 898 | + * Description: Absorb step of the SHAKE128 XOF. 899 | + * non-incremental, starts by zeroeing the state. 900 | + * 901 | + * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state 902 | + * - const uint8_t *input: pointer to input to be absorbed 903 | + * into s 904 | + * - size_t inlen: length of input in bytes 905 | + **************************************************/ 906 | +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) { 907 | + state->ctx = malloc(PQC_SHAKECTX_BYTES); 908 | + if (state->ctx == NULL) { 909 | + exit(111); 910 | + } 911 | + keccak_absorb(state->ctx, SHAKE128_RATE, input, inlen, 0x1F); 912 | +} 913 | + 914 | +/************************************************* 915 | + * Name: shake128_squeezeblocks 916 | + * 917 | + * Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of 918 | + * SHAKE128_RATE bytes each. Modifies the state. Can be called 919 | + * multiple times to keep squeezing, i.e., is incremental. 920 | + * 921 | + * Arguments: - uint8_t *output: pointer to output blocks 922 | + * - size_t nblocks: number of blocks to be squeezed 923 | + * (written to output) 924 | + * - shake128ctx *state: pointer to input/output Keccak state 925 | + **************************************************/ 926 | +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state) { 927 | + keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE128_RATE); 928 | +} 929 | + 930 | +void shake128_ctx_clone(shake128ctx *dest, const shake128ctx *src) { 931 | + dest->ctx = malloc(PQC_SHAKECTX_BYTES); 932 | + if (dest->ctx == NULL) { 933 | + exit(111); 934 | + } 935 | + memcpy(dest->ctx, src->ctx, PQC_SHAKECTX_BYTES); 936 | +} 937 | + 938 | +/** Release the allocated state. Call only once. */ 939 | +void shake128_ctx_release(shake128ctx *state) { 940 | + free(state->ctx); 941 | +} 942 | + 943 | +/************************************************* 944 | + * Name: shake256_absorb 945 | + * 946 | + * Description: Absorb step of the SHAKE256 XOF. 947 | + * non-incremental, starts by zeroeing the state. 948 | + * 949 | + * Arguments: - shake256ctx *state: pointer to (uninitialized) output Keccak state 950 | + * - const uint8_t *input: pointer to input to be absorbed 951 | + * into s 952 | + * - size_t inlen: length of input in bytes 953 | + **************************************************/ 954 | +void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen) { 955 | + state->ctx = malloc(PQC_SHAKECTX_BYTES); 956 | + if (state->ctx == NULL) { 957 | + exit(111); 958 | + } 959 | + keccak_absorb(state->ctx, SHAKE256_RATE, input, inlen, 0x1F); 960 | +} 961 | + 962 | +/************************************************* 963 | + * Name: shake256_squeezeblocks 964 | + * 965 | + * Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of 966 | + * SHAKE256_RATE bytes each. Modifies the state. Can be called 967 | + * multiple times to keep squeezing, i.e., is incremental. 968 | + * 969 | + * Arguments: - uint8_t *output: pointer to output blocks 970 | + * - size_t nblocks: number of blocks to be squeezed 971 | + * (written to output) 972 | + * - shake256ctx *state: pointer to input/output Keccak state 973 | + **************************************************/ 974 | +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state) { 975 | + keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE256_RATE); 976 | +} 977 | + 978 | +void shake256_ctx_clone(shake256ctx *dest, const shake256ctx *src) { 979 | + dest->ctx = malloc(PQC_SHAKECTX_BYTES); 980 | + if (dest->ctx == NULL) { 981 | + exit(111); 982 | + } 983 | + memcpy(dest->ctx, src->ctx, PQC_SHAKECTX_BYTES); 984 | +} 985 | + 986 | +/** Release the allocated state. Call only once. */ 987 | +void shake256_ctx_release(shake256ctx *state) { 988 | + free(state->ctx); 989 | +} 990 | + 991 | +/************************************************* 992 | + * Name: shake128 993 | + * 994 | + * Description: SHAKE128 XOF with non-incremental API 995 | + * 996 | + * Arguments: - uint8_t *output: pointer to output 997 | + * - size_t outlen: requested output length in bytes 998 | + * - const uint8_t *input: pointer to input 999 | + * - size_t inlen: length of input in bytes 1000 | + **************************************************/ 1001 | +void shake128(uint8_t *output, size_t outlen, 1002 | + const uint8_t *input, size_t inlen) { 1003 | + size_t nblocks = outlen / SHAKE128_RATE; 1004 | + uint8_t t[SHAKE128_RATE]; 1005 | + shake128ctx s; 1006 | + 1007 | + shake128_absorb(&s, input, inlen); 1008 | + shake128_squeezeblocks(output, nblocks, &s); 1009 | + 1010 | + output += nblocks * SHAKE128_RATE; 1011 | + outlen -= nblocks * SHAKE128_RATE; 1012 | + 1013 | + if (outlen) { 1014 | + shake128_squeezeblocks(t, 1, &s); 1015 | + for (size_t i = 0; i < outlen; ++i) { 1016 | + output[i] = t[i]; 1017 | + } 1018 | + } 1019 | + shake128_ctx_release(&s); 1020 | +} 1021 | + 1022 | +/************************************************* 1023 | + * Name: shake256 1024 | + * 1025 | + * Description: SHAKE256 XOF with non-incremental API 1026 | + * 1027 | + * Arguments: - uint8_t *output: pointer to output 1028 | + * - size_t outlen: requested output length in bytes 1029 | + * - const uint8_t *input: pointer to input 1030 | + * - size_t inlen: length of input in bytes 1031 | + **************************************************/ 1032 | +void shake256(uint8_t *output, size_t outlen, 1033 | + const uint8_t *input, size_t inlen) { 1034 | + size_t nblocks = outlen / SHAKE256_RATE; 1035 | + uint8_t t[SHAKE256_RATE]; 1036 | + shake256ctx s; 1037 | + 1038 | + shake256_absorb(&s, input, inlen); 1039 | + shake256_squeezeblocks(output, nblocks, &s); 1040 | + 1041 | + output += nblocks * SHAKE256_RATE; 1042 | + outlen -= nblocks * SHAKE256_RATE; 1043 | + 1044 | + if (outlen) { 1045 | + shake256_squeezeblocks(t, 1, &s); 1046 | + for (size_t i = 0; i < outlen; ++i) { 1047 | + output[i] = t[i]; 1048 | + } 1049 | + } 1050 | + shake256_ctx_release(&s); 1051 | +} 1052 | + 1053 | +void sha3_256_inc_init(sha3_256incctx *state) { 1054 | + state->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 1055 | + if (state->ctx == NULL) { 1056 | + exit(111); 1057 | + } 1058 | + keccak_inc_init(state->ctx); 1059 | +} 1060 | + 1061 | +void sha3_256_inc_ctx_clone(sha3_256incctx *dest, const sha3_256incctx *src) { 1062 | + dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 1063 | + if (dest->ctx == NULL) { 1064 | + exit(111); 1065 | + } 1066 | + memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES); 1067 | +} 1068 | + 1069 | +void sha3_256_inc_ctx_release(sha3_256incctx *state) { 1070 | + free(state->ctx); 1071 | +} 1072 | + 1073 | +void sha3_256_inc_absorb(sha3_256incctx *state, const uint8_t *input, size_t inlen) { 1074 | + keccak_inc_absorb(state->ctx, SHA3_256_RATE, input, inlen); 1075 | +} 1076 | + 1077 | +void sha3_256_inc_finalize(uint8_t *output, sha3_256incctx *state) { 1078 | + uint8_t t[SHA3_256_RATE]; 1079 | + keccak_inc_finalize(state->ctx, SHA3_256_RATE, 0x06); 1080 | + 1081 | + keccak_squeezeblocks(t, 1, state->ctx, SHA3_256_RATE); 1082 | + 1083 | + sha3_256_inc_ctx_release(state); 1084 | + 1085 | + for (size_t i = 0; i < 32; i++) { 1086 | + output[i] = t[i]; 1087 | + } 1088 | +} 1089 | + 1090 | +/************************************************* 1091 | + * Name: sha3_256 1092 | + * 1093 | + * Description: SHA3-256 with non-incremental API 1094 | + * 1095 | + * Arguments: - uint8_t *output: pointer to output 1096 | + * - const uint8_t *input: pointer to input 1097 | + * - size_t inlen: length of input in bytes 1098 | + **************************************************/ 1099 | +void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) { 1100 | + uint64_t s[25]; 1101 | + uint8_t t[SHA3_256_RATE]; 1102 | + 1103 | + /* Absorb input */ 1104 | + keccak_absorb(s, SHA3_256_RATE, input, inlen, 0x06); 1105 | + 1106 | + /* Squeeze output */ 1107 | + keccak_squeezeblocks(t, 1, s, SHA3_256_RATE); 1108 | + 1109 | + for (size_t i = 0; i < 32; i++) { 1110 | + output[i] = t[i]; 1111 | + } 1112 | +} 1113 | + 1114 | +void sha3_384_inc_init(sha3_384incctx *state) { 1115 | + state->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 1116 | + if (state->ctx == NULL) { 1117 | + exit(111); 1118 | + } 1119 | + keccak_inc_init(state->ctx); 1120 | +} 1121 | + 1122 | +void sha3_384_inc_ctx_clone(sha3_384incctx *dest, const sha3_384incctx *src) { 1123 | + dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 1124 | + if (dest->ctx == NULL) { 1125 | + exit(111); 1126 | + } 1127 | + memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES); 1128 | +} 1129 | + 1130 | +void sha3_384_inc_absorb(sha3_384incctx *state, const uint8_t *input, size_t inlen) { 1131 | + keccak_inc_absorb(state->ctx, SHA3_384_RATE, input, inlen); 1132 | +} 1133 | + 1134 | +void sha3_384_inc_ctx_release(sha3_384incctx *state) { 1135 | + free(state->ctx); 1136 | +} 1137 | + 1138 | +void sha3_384_inc_finalize(uint8_t *output, sha3_384incctx *state) { 1139 | + uint8_t t[SHA3_384_RATE]; 1140 | + keccak_inc_finalize(state->ctx, SHA3_384_RATE, 0x06); 1141 | + 1142 | + keccak_squeezeblocks(t, 1, state->ctx, SHA3_384_RATE); 1143 | + 1144 | + sha3_384_inc_ctx_release(state); 1145 | + 1146 | + for (size_t i = 0; i < 48; i++) { 1147 | + output[i] = t[i]; 1148 | + } 1149 | +} 1150 | + 1151 | +/************************************************* 1152 | + * Name: sha3_384 1153 | + * 1154 | + * Description: SHA3-256 with non-incremental API 1155 | + * 1156 | + * Arguments: - uint8_t *output: pointer to output 1157 | + * - const uint8_t *input: pointer to input 1158 | + * - size_t inlen: length of input in bytes 1159 | + **************************************************/ 1160 | +void sha3_384(uint8_t *output, const uint8_t *input, size_t inlen) { 1161 | + uint64_t s[25]; 1162 | + uint8_t t[SHA3_384_RATE]; 1163 | + 1164 | + /* Absorb input */ 1165 | + keccak_absorb(s, SHA3_384_RATE, input, inlen, 0x06); 1166 | + 1167 | + /* Squeeze output */ 1168 | + keccak_squeezeblocks(t, 1, s, SHA3_384_RATE); 1169 | + 1170 | + for (size_t i = 0; i < 48; i++) { 1171 | + output[i] = t[i]; 1172 | + } 1173 | +} 1174 | + 1175 | +void sha3_512_inc_init(sha3_512incctx *state) { 1176 | + state->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 1177 | + if (state->ctx == NULL) { 1178 | + exit(111); 1179 | + } 1180 | + keccak_inc_init(state->ctx); 1181 | +} 1182 | + 1183 | +void sha3_512_inc_ctx_clone(sha3_512incctx *dest, const sha3_512incctx *src) { 1184 | + dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES); 1185 | + if (dest->ctx == NULL) { 1186 | + exit(111); 1187 | + } 1188 | + memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES); 1189 | +} 1190 | + 1191 | +void sha3_512_inc_absorb(sha3_512incctx *state, const uint8_t *input, size_t inlen) { 1192 | + keccak_inc_absorb(state->ctx, SHA3_512_RATE, input, inlen); 1193 | +} 1194 | + 1195 | +void sha3_512_inc_ctx_release(sha3_512incctx *state) { 1196 | + free(state->ctx); 1197 | +} 1198 | + 1199 | +void sha3_512_inc_finalize(uint8_t *output, sha3_512incctx *state) { 1200 | + uint8_t t[SHA3_512_RATE]; 1201 | + keccak_inc_finalize(state->ctx, SHA3_512_RATE, 0x06); 1202 | + 1203 | + keccak_squeezeblocks(t, 1, state->ctx, SHA3_512_RATE); 1204 | + 1205 | + sha3_512_inc_ctx_release(state); 1206 | + 1207 | + for (size_t i = 0; i < 64; i++) { 1208 | + output[i] = t[i]; 1209 | + } 1210 | +} 1211 | + 1212 | +/************************************************* 1213 | + * Name: sha3_512 1214 | + * 1215 | + * Description: SHA3-512 with non-incremental API 1216 | + * 1217 | + * Arguments: - uint8_t *output: pointer to output 1218 | + * - const uint8_t *input: pointer to input 1219 | + * - size_t inlen: length of input in bytes 1220 | + **************************************************/ 1221 | +void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen) { 1222 | + uint64_t s[25]; 1223 | + uint8_t t[SHA3_512_RATE]; 1224 | + 1225 | + /* Absorb input */ 1226 | + keccak_absorb(s, SHA3_512_RATE, input, inlen, 0x06); 1227 | + 1228 | + /* Squeeze output */ 1229 | + keccak_squeezeblocks(t, 1, s, SHA3_512_RATE); 1230 | + 1231 | + for (size_t i = 0; i < 64; i++) { 1232 | + output[i] = t[i]; 1233 | + } 1234 | +} 1235 | diff --git a/lib/freebl/kyber512/fips202.h b/lib/freebl/kyber512/fips202.h 1236 | new file mode 100644 1237 | index 000000000..d3fda8119 1238 | --- /dev/null 1239 | +++ b/lib/freebl/kyber512/fips202.h 1240 | @@ -0,0 +1,167 @@ 1241 | +#ifndef FIPS202_H 1242 | +#define FIPS202_H 1243 | + 1244 | +#include 1245 | +#include 1246 | + 1247 | +#define SHAKE128_RATE 168 1248 | +#define SHAKE256_RATE 136 1249 | +#define SHA3_256_RATE 136 1250 | +#define SHA3_384_RATE 104 1251 | +#define SHA3_512_RATE 72 1252 | + 1253 | + 1254 | +#define PQC_SHAKEINCCTX_BYTES (sizeof(uint64_t)*26) 1255 | +#define PQC_SHAKECTX_BYTES (sizeof(uint64_t)*25) 1256 | + 1257 | +// Context for incremental API 1258 | +typedef struct { 1259 | + uint64_t* ctx; 1260 | +} shake128incctx; 1261 | + 1262 | +// Context for non-incremental API 1263 | +typedef struct { 1264 | + uint64_t* ctx; 1265 | +} shake128ctx; 1266 | + 1267 | +// Context for incremental API 1268 | +typedef struct { 1269 | + uint64_t* ctx; 1270 | +} shake256incctx; 1271 | + 1272 | +// Context for non-incremental API 1273 | +typedef struct { 1274 | + uint64_t* ctx; 1275 | +} shake256ctx; 1276 | + 1277 | +// Context for incremental API 1278 | +typedef struct { 1279 | + uint64_t* ctx; 1280 | +} sha3_256incctx; 1281 | + 1282 | +// Context for incremental API 1283 | +typedef struct { 1284 | + uint64_t* ctx; 1285 | +} sha3_384incctx; 1286 | + 1287 | +// Context for incremental API 1288 | +typedef struct { 1289 | + uint64_t* ctx; 1290 | +} sha3_512incctx; 1291 | + 1292 | +/* Initialize the state and absorb the provided input. 1293 | + * 1294 | + * This function does not support being called multiple times 1295 | + * with the same state. 1296 | + */ 1297 | +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen); 1298 | +/* Squeeze output out of the sponge. 1299 | + * 1300 | + * Supports being called multiple times 1301 | + */ 1302 | +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state); 1303 | +/* Free the state */ 1304 | +void shake128_ctx_release(shake128ctx *state); 1305 | +/* Copy the state. */ 1306 | +void shake128_ctx_clone(shake128ctx *dest, const shake128ctx *src); 1307 | + 1308 | +/* Initialize incremental hashing API */ 1309 | +void shake128_inc_init(shake128incctx *state); 1310 | +/* Absorb more information into the XOF. 1311 | + * 1312 | + * Can be called multiple times. 1313 | + */ 1314 | +void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen); 1315 | +/* Finalize the XOF for squeezing */ 1316 | +void shake128_inc_finalize(shake128incctx *state); 1317 | +/* Squeeze output out of the sponge. 1318 | + * 1319 | + * Supports being called multiple times 1320 | + */ 1321 | +void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state); 1322 | +/* Copy the context of the SHAKE128 XOF */ 1323 | +void shake128_inc_ctx_clone(shake128incctx* dest, const shake128incctx *src); 1324 | +/* Free the context of the SHAKE128 XOF */ 1325 | +void shake128_inc_ctx_release(shake128incctx *state); 1326 | + 1327 | +/* Initialize the state and absorb the provided input. 1328 | + * 1329 | + * This function does not support being called multiple times 1330 | + * with the same state. 1331 | + */ 1332 | +void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen); 1333 | +/* Squeeze output out of the sponge. 1334 | + * 1335 | + * Supports being called multiple times 1336 | + */ 1337 | +void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state); 1338 | +/* Free the context held by this XOF */ 1339 | +void shake256_ctx_release(shake256ctx *state); 1340 | +/* Copy the context held by this XOF */ 1341 | +void shake256_ctx_clone(shake256ctx *dest, const shake256ctx *src); 1342 | + 1343 | +/* Initialize incremental hashing API */ 1344 | +void shake256_inc_init(shake256incctx *state); 1345 | +void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen); 1346 | +/* Prepares for squeeze phase */ 1347 | +void shake256_inc_finalize(shake256incctx *state); 1348 | +/* Squeeze output out of the sponge. 1349 | + * 1350 | + * Supports being called multiple times 1351 | + */ 1352 | +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state); 1353 | +/* Copy the state */ 1354 | +void shake256_inc_ctx_clone(shake256incctx* dest, const shake256incctx *src); 1355 | +/* Free the state */ 1356 | +void shake256_inc_ctx_release(shake256incctx *state); 1357 | + 1358 | +/* One-stop SHAKE128 call */ 1359 | +void shake128(uint8_t *output, size_t outlen, 1360 | + const uint8_t *input, size_t inlen); 1361 | + 1362 | +/* One-stop SHAKE256 call */ 1363 | +void shake256(uint8_t *output, size_t outlen, 1364 | + const uint8_t *input, size_t inlen); 1365 | + 1366 | +/* Initialize the incremental hashing state */ 1367 | +void sha3_256_inc_init(sha3_256incctx *state); 1368 | +/* Absorb blocks into SHA3 */ 1369 | +void sha3_256_inc_absorb(sha3_256incctx *state, const uint8_t *input, size_t inlen); 1370 | +/* Obtain the output of the function and free `state` */ 1371 | +void sha3_256_inc_finalize(uint8_t *output, sha3_256incctx *state); 1372 | +/* Copy the context */ 1373 | +void sha3_256_inc_ctx_clone(sha3_256incctx *dest, const sha3_256incctx *src); 1374 | +/* Release the state, don't use if `_finalize` has been used */ 1375 | +void sha3_256_inc_ctx_release(sha3_256incctx *state); 1376 | + 1377 | +void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen); 1378 | + 1379 | +/* Initialize the incremental hashing state */ 1380 | +void sha3_384_inc_init(sha3_384incctx *state); 1381 | +/* Absorb blocks into SHA3 */ 1382 | +void sha3_384_inc_absorb(sha3_384incctx *state, const uint8_t *input, size_t inlen); 1383 | +/* Obtain the output of the function and free `state` */ 1384 | +void sha3_384_inc_finalize(uint8_t *output, sha3_384incctx *state); 1385 | +/* Copy the context */ 1386 | +void sha3_384_inc_ctx_clone(sha3_384incctx *dest, const sha3_384incctx *src); 1387 | +/* Release the state, don't use if `_finalize` has been used */ 1388 | +void sha3_384_inc_ctx_release(sha3_384incctx *state); 1389 | + 1390 | +/* One-stop SHA3-384 shop */ 1391 | +void sha3_384(uint8_t *output, const uint8_t *input, size_t inlen); 1392 | + 1393 | +/* Initialize the incremental hashing state */ 1394 | +void sha3_512_inc_init(sha3_512incctx *state); 1395 | +/* Absorb blocks into SHA3 */ 1396 | +void sha3_512_inc_absorb(sha3_512incctx *state, const uint8_t *input, size_t inlen); 1397 | +/* Obtain the output of the function and free `state` */ 1398 | +void sha3_512_inc_finalize(uint8_t *output, sha3_512incctx *state); 1399 | +/* Copy the context */ 1400 | +void sha3_512_inc_ctx_clone(sha3_512incctx *dest, const sha3_512incctx *src); 1401 | +/* Release the state, don't use if `_finalize` has been used */ 1402 | +void sha3_512_inc_ctx_release(sha3_512incctx *state); 1403 | + 1404 | +/* One-stop SHA3-512 shop */ 1405 | +void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen); 1406 | + 1407 | +#endif 1408 | diff --git a/lib/freebl/kyber512/indcpa.c b/lib/freebl/kyber512/indcpa.c 1409 | new file mode 100644 1410 | index 000000000..e90dccd8a 1411 | --- /dev/null 1412 | +++ b/lib/freebl/kyber512/indcpa.c 1413 | @@ -0,0 +1,330 @@ 1414 | +#include "indcpa.h" 1415 | +#include "ntt.h" 1416 | +#include "params.h" 1417 | +#include "poly.h" 1418 | +#include "polyvec.h" 1419 | +#include "randombytes.h" 1420 | +#include "symmetric.h" 1421 | +#include 1422 | +#include 1423 | + 1424 | +/************************************************* 1425 | +* Name: pack_pk 1426 | +* 1427 | +* Description: Serialize the public key as concatenation of the 1428 | +* serialized vector of polynomials pk 1429 | +* and the public seed used to generate the matrix A. 1430 | +* 1431 | +* Arguments: uint8_t *r: pointer to the output serialized public key 1432 | +* polyvec *pk: pointer to the input public-key polyvec 1433 | +* const uint8_t *seed: pointer to the input public seed 1434 | +**************************************************/ 1435 | +static void pack_pk(uint8_t r[KYBER_INDCPA_PUBLICKEYBYTES], 1436 | + polyvec *pk, 1437 | + const uint8_t seed[KYBER_SYMBYTES]) { 1438 | + size_t i; 1439 | + PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(r, pk); 1440 | + for (i = 0; i < KYBER_SYMBYTES; i++) { 1441 | + r[i + KYBER_POLYVECBYTES] = seed[i]; 1442 | + } 1443 | +} 1444 | + 1445 | +/************************************************* 1446 | +* Name: unpack_pk 1447 | +* 1448 | +* Description: De-serialize public key from a byte array; 1449 | +* approximate inverse of pack_pk 1450 | +* 1451 | +* Arguments: - polyvec *pk: pointer to output public-key polynomial vector 1452 | +* - uint8_t *seed: pointer to output seed to generate matrix A 1453 | +* - const uint8_t *packedpk: pointer to input serialized public key 1454 | +**************************************************/ 1455 | +static void unpack_pk(polyvec *pk, 1456 | + uint8_t seed[KYBER_SYMBYTES], 1457 | + const uint8_t packedpk[KYBER_INDCPA_PUBLICKEYBYTES]) { 1458 | + size_t i; 1459 | + PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(pk, packedpk); 1460 | + for (i = 0; i < KYBER_SYMBYTES; i++) { 1461 | + seed[i] = packedpk[i + KYBER_POLYVECBYTES]; 1462 | + } 1463 | +} 1464 | + 1465 | +/************************************************* 1466 | +* Name: pack_sk 1467 | +* 1468 | +* Description: Serialize the secret key 1469 | +* 1470 | +* Arguments: - uint8_t *r: pointer to output serialized secret key 1471 | +* - polyvec *sk: pointer to input vector of polynomials (secret key) 1472 | +**************************************************/ 1473 | +static void pack_sk(uint8_t r[KYBER_INDCPA_SECRETKEYBYTES], polyvec *sk) { 1474 | + PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(r, sk); 1475 | +} 1476 | + 1477 | +/************************************************* 1478 | +* Name: unpack_sk 1479 | +* 1480 | +* Description: De-serialize the secret key; inverse of pack_sk 1481 | +* 1482 | +* Arguments: - polyvec *sk: pointer to output vector of polynomials (secret key) 1483 | +* - const uint8_t *packedsk: pointer to input serialized secret key 1484 | +**************************************************/ 1485 | +static void unpack_sk(polyvec *sk, const uint8_t packedsk[KYBER_INDCPA_SECRETKEYBYTES]) { 1486 | + PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(sk, packedsk); 1487 | +} 1488 | + 1489 | +/************************************************* 1490 | +* Name: pack_ciphertext 1491 | +* 1492 | +* Description: Serialize the ciphertext as concatenation of the 1493 | +* compressed and serialized vector of polynomials b 1494 | +* and the compressed and serialized polynomial v 1495 | +* 1496 | +* Arguments: uint8_t *r: pointer to the output serialized ciphertext 1497 | +* poly *pk: pointer to the input vector of polynomials b 1498 | +* poly *v: pointer to the input polynomial v 1499 | +**************************************************/ 1500 | +static void pack_ciphertext(uint8_t r[KYBER_INDCPA_BYTES], polyvec *b, poly *v) { 1501 | + PQCLEAN_KYBER512_CLEAN_polyvec_compress(r, b); 1502 | + PQCLEAN_KYBER512_CLEAN_poly_compress(r + KYBER_POLYVECCOMPRESSEDBYTES, v); 1503 | +} 1504 | + 1505 | +/************************************************* 1506 | +* Name: unpack_ciphertext 1507 | +* 1508 | +* Description: De-serialize and decompress ciphertext from a byte array; 1509 | +* approximate inverse of pack_ciphertext 1510 | +* 1511 | +* Arguments: - polyvec *b: pointer to the output vector of polynomials b 1512 | +* - poly *v: pointer to the output polynomial v 1513 | +* - const uint8_t *c: pointer to the input serialized ciphertext 1514 | +**************************************************/ 1515 | +static void unpack_ciphertext(polyvec *b, poly *v, const uint8_t c[KYBER_INDCPA_BYTES]) { 1516 | + PQCLEAN_KYBER512_CLEAN_polyvec_decompress(b, c); 1517 | + PQCLEAN_KYBER512_CLEAN_poly_decompress(v, c + KYBER_POLYVECCOMPRESSEDBYTES); 1518 | +} 1519 | + 1520 | +/************************************************* 1521 | +* Name: rej_uniform 1522 | +* 1523 | +* Description: Run rejection sampling on uniform random bytes to generate 1524 | +* uniform random integers mod q 1525 | +* 1526 | +* Arguments: - int16_t *r: pointer to output buffer 1527 | +* - unsigned int len: requested number of 16-bit integers (uniform mod q) 1528 | +* - const uint8_t *buf: pointer to input buffer (assumed to be uniformly random bytes) 1529 | +* - unsigned int buflen: length of input buffer in bytes 1530 | +* 1531 | +* Returns number of sampled 16-bit integers (at most len) 1532 | +**************************************************/ 1533 | +static unsigned int rej_uniform(int16_t *r, 1534 | + unsigned int len, 1535 | + const uint8_t *buf, 1536 | + unsigned int buflen) { 1537 | + unsigned int ctr, pos; 1538 | + uint16_t val0, val1; 1539 | + 1540 | + ctr = pos = 0; 1541 | + while (ctr < len && pos + 3 <= buflen) { 1542 | + val0 = ((buf[pos + 0] >> 0) | ((uint16_t)buf[pos + 1] << 8)) & 0xFFF; 1543 | + val1 = ((buf[pos + 1] >> 4) | ((uint16_t)buf[pos + 2] << 4)) & 0xFFF; 1544 | + pos += 3; 1545 | + 1546 | + if (val0 < KYBER_Q) { 1547 | + r[ctr++] = val0; 1548 | + } 1549 | + if (ctr < len && val1 < KYBER_Q) { 1550 | + r[ctr++] = val1; 1551 | + } 1552 | + } 1553 | + 1554 | + return ctr; 1555 | +} 1556 | + 1557 | +#define gen_a(A,B) PQCLEAN_KYBER512_CLEAN_gen_matrix(A,B,0) 1558 | +#define gen_at(A,B) PQCLEAN_KYBER512_CLEAN_gen_matrix(A,B,1) 1559 | + 1560 | +/************************************************* 1561 | +* Name: PQCLEAN_KYBER512_CLEAN_gen_matrix 1562 | +* 1563 | +* Description: Deterministically generate matrix A (or the transpose of A) 1564 | +* from a seed. Entries of the matrix are polynomials that look 1565 | +* uniformly random. Performs rejection sampling on output of 1566 | +* a XOF 1567 | +* 1568 | +* Arguments: - polyvec *a: pointer to ouptput matrix A 1569 | +* - const uint8_t *seed: pointer to input seed 1570 | +* - int transposed: boolean deciding whether A or A^T is generated 1571 | +**************************************************/ 1572 | +#define GEN_MATRIX_NBLOCKS ((12*KYBER_N/8*(1 << 12)/KYBER_Q + XOF_BLOCKBYTES)/XOF_BLOCKBYTES) 1573 | +// Not static for benchmarking 1574 | +void PQCLEAN_KYBER512_CLEAN_gen_matrix(polyvec *a, const uint8_t seed[KYBER_SYMBYTES], int transposed) { 1575 | + unsigned int ctr, i, j, k; 1576 | + unsigned int buflen, off; 1577 | + uint8_t buf[GEN_MATRIX_NBLOCKS * XOF_BLOCKBYTES + 2]; 1578 | + xof_state state; 1579 | + 1580 | + for (i = 0; i < KYBER_K; i++) { 1581 | + for (j = 0; j < KYBER_K; j++) { 1582 | + if (transposed) { 1583 | + xof_absorb(&state, seed, (uint8_t)i, (uint8_t)j); 1584 | + } else { 1585 | + xof_absorb(&state, seed, (uint8_t)j, (uint8_t)i); 1586 | + } 1587 | + 1588 | + xof_squeezeblocks(buf, GEN_MATRIX_NBLOCKS, &state); 1589 | + buflen = GEN_MATRIX_NBLOCKS * XOF_BLOCKBYTES; 1590 | + ctr = rej_uniform(a[i].vec[j].coeffs, KYBER_N, buf, buflen); 1591 | + 1592 | + while (ctr < KYBER_N) { 1593 | + off = buflen % 3; 1594 | + for (k = 0; k < off; k++) { 1595 | + buf[k] = buf[buflen - off + k]; 1596 | + } 1597 | + xof_squeezeblocks(buf + off, 1, &state); 1598 | + buflen = off + XOF_BLOCKBYTES; 1599 | + ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf, buflen); 1600 | + } 1601 | + xof_ctx_release(&state); 1602 | + } 1603 | + } 1604 | +} 1605 | + 1606 | +/************************************************* 1607 | +* Name: PQCLEAN_KYBER512_CLEAN_indcpa_keypair 1608 | +* 1609 | +* Description: Generates public and private key for the CPA-secure 1610 | +* public-key encryption scheme underlying Kyber 1611 | +* 1612 | +* Arguments: - uint8_t *pk: pointer to output public key 1613 | +* (of length KYBER_INDCPA_PUBLICKEYBYTES bytes) 1614 | +* - uint8_t *sk: pointer to output private key 1615 | + (of length KYBER_INDCPA_SECRETKEYBYTES bytes) 1616 | +**************************************************/ 1617 | +void PQCLEAN_KYBER512_CLEAN_indcpa_keypair(uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES], 1618 | + uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES]) { 1619 | + unsigned int i; 1620 | + uint8_t buf[2 * KYBER_SYMBYTES]; 1621 | + const uint8_t *publicseed = buf; 1622 | + const uint8_t *noiseseed = buf + KYBER_SYMBYTES; 1623 | + uint8_t nonce = 0; 1624 | + polyvec a[KYBER_K], e, pkpv, skpv; 1625 | + 1626 | + randombytes(buf, KYBER_SYMBYTES); 1627 | + hash_g(buf, buf, KYBER_SYMBYTES); 1628 | + 1629 | + gen_a(a, publicseed); 1630 | + 1631 | + for (i = 0; i < KYBER_K; i++) { 1632 | + PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta1(&skpv.vec[i], noiseseed, nonce++); 1633 | + } 1634 | + for (i = 0; i < KYBER_K; i++) { 1635 | + PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta1(&e.vec[i], noiseseed, nonce++); 1636 | + } 1637 | + 1638 | + PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&skpv); 1639 | + PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&e); 1640 | + 1641 | + // matrix-vector multiplication 1642 | + for (i = 0; i < KYBER_K; i++) { 1643 | + PQCLEAN_KYBER512_CLEAN_polyvec_basemul_acc_montgomery(&pkpv.vec[i], &a[i], &skpv); 1644 | + PQCLEAN_KYBER512_CLEAN_poly_tomont(&pkpv.vec[i]); 1645 | + } 1646 | + 1647 | + PQCLEAN_KYBER512_CLEAN_polyvec_add(&pkpv, &pkpv, &e); 1648 | + PQCLEAN_KYBER512_CLEAN_polyvec_reduce(&pkpv); 1649 | + 1650 | + pack_sk(sk, &skpv); 1651 | + pack_pk(pk, &pkpv, publicseed); 1652 | +} 1653 | + 1654 | +/************************************************* 1655 | +* Name: PQCLEAN_KYBER512_CLEAN_indcpa_enc 1656 | +* 1657 | +* Description: Encryption function of the CPA-secure 1658 | +* public-key encryption scheme underlying Kyber. 1659 | +* 1660 | +* Arguments: - uint8_t *c: pointer to output ciphertext 1661 | +* (of length KYBER_INDCPA_BYTES bytes) 1662 | +* - const uint8_t *m: pointer to input message 1663 | +* (of length KYBER_INDCPA_MSGBYTES bytes) 1664 | +* - const uint8_t *pk: pointer to input public key 1665 | +* (of length KYBER_INDCPA_PUBLICKEYBYTES) 1666 | +* - const uint8_t *coins: pointer to input random coins used as seed 1667 | +* (of length KYBER_SYMBYTES) to deterministically 1668 | +* generate all randomness 1669 | +**************************************************/ 1670 | +void PQCLEAN_KYBER512_CLEAN_indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES], 1671 | + const uint8_t m[KYBER_INDCPA_MSGBYTES], 1672 | + const uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES], 1673 | + const uint8_t coins[KYBER_SYMBYTES]) { 1674 | + unsigned int i; 1675 | + uint8_t seed[KYBER_SYMBYTES]; 1676 | + uint8_t nonce = 0; 1677 | + polyvec sp, pkpv, ep, at[KYBER_K], b; 1678 | + poly v, k, epp; 1679 | + 1680 | + unpack_pk(&pkpv, seed, pk); 1681 | + PQCLEAN_KYBER512_CLEAN_poly_frommsg(&k, m); 1682 | + gen_at(at, seed); 1683 | + 1684 | + for (i = 0; i < KYBER_K; i++) { 1685 | + PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta1(sp.vec + i, coins, nonce++); 1686 | + } 1687 | + for (i = 0; i < KYBER_K; i++) { 1688 | + PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta2(ep.vec + i, coins, nonce++); 1689 | + } 1690 | + PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta2(&epp, coins, nonce++); 1691 | + 1692 | + PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&sp); 1693 | + 1694 | + // matrix-vector multiplication 1695 | + for (i = 0; i < KYBER_K; i++) { 1696 | + PQCLEAN_KYBER512_CLEAN_polyvec_basemul_acc_montgomery(&b.vec[i], &at[i], &sp); 1697 | + } 1698 | + 1699 | + PQCLEAN_KYBER512_CLEAN_polyvec_basemul_acc_montgomery(&v, &pkpv, &sp); 1700 | + 1701 | + PQCLEAN_KYBER512_CLEAN_polyvec_invntt_tomont(&b); 1702 | + PQCLEAN_KYBER512_CLEAN_poly_invntt_tomont(&v); 1703 | + 1704 | + PQCLEAN_KYBER512_CLEAN_polyvec_add(&b, &b, &ep); 1705 | + PQCLEAN_KYBER512_CLEAN_poly_add(&v, &v, &epp); 1706 | + PQCLEAN_KYBER512_CLEAN_poly_add(&v, &v, &k); 1707 | + PQCLEAN_KYBER512_CLEAN_polyvec_reduce(&b); 1708 | + PQCLEAN_KYBER512_CLEAN_poly_reduce(&v); 1709 | + 1710 | + pack_ciphertext(c, &b, &v); 1711 | +} 1712 | + 1713 | +/************************************************* 1714 | +* Name: PQCLEAN_KYBER512_CLEAN_indcpa_dec 1715 | +* 1716 | +* Description: Decryption function of the CPA-secure 1717 | +* public-key encryption scheme underlying Kyber. 1718 | +* 1719 | +* Arguments: - uint8_t *m: pointer to output decrypted message 1720 | +* (of length KYBER_INDCPA_MSGBYTES) 1721 | +* - const uint8_t *c: pointer to input ciphertext 1722 | +* (of length KYBER_INDCPA_BYTES) 1723 | +* - const uint8_t *sk: pointer to input secret key 1724 | +* (of length KYBER_INDCPA_SECRETKEYBYTES) 1725 | +**************************************************/ 1726 | +void PQCLEAN_KYBER512_CLEAN_indcpa_dec(uint8_t m[KYBER_INDCPA_MSGBYTES], 1727 | + const uint8_t c[KYBER_INDCPA_BYTES], 1728 | + const uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES]) { 1729 | + polyvec b, skpv; 1730 | + poly v, mp; 1731 | + 1732 | + unpack_ciphertext(&b, &v, c); 1733 | + unpack_sk(&skpv, sk); 1734 | + 1735 | + PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&b); 1736 | + PQCLEAN_KYBER512_CLEAN_polyvec_basemul_acc_montgomery(&mp, &skpv, &b); 1737 | + PQCLEAN_KYBER512_CLEAN_poly_invntt_tomont(&mp); 1738 | + 1739 | + PQCLEAN_KYBER512_CLEAN_poly_sub(&mp, &v, &mp); 1740 | + PQCLEAN_KYBER512_CLEAN_poly_reduce(&mp); 1741 | + 1742 | + PQCLEAN_KYBER512_CLEAN_poly_tomsg(m, &mp); 1743 | +} 1744 | diff --git a/lib/freebl/kyber512/indcpa.h b/lib/freebl/kyber512/indcpa.h 1745 | new file mode 100644 1746 | index 000000000..84464a931 1747 | --- /dev/null 1748 | +++ b/lib/freebl/kyber512/indcpa.h 1749 | @@ -0,0 +1,20 @@ 1750 | +#ifndef PQCLEAN_KYBER512_CLEAN_INDCPA_H 1751 | +#define PQCLEAN_KYBER512_CLEAN_INDCPA_H 1752 | +#include "params.h" 1753 | +#include "polyvec.h" 1754 | +#include 1755 | + 1756 | +void PQCLEAN_KYBER512_CLEAN_gen_matrix(polyvec *a, const uint8_t seed[KYBER_SYMBYTES], int transposed); 1757 | +void PQCLEAN_KYBER512_CLEAN_indcpa_keypair(uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES], 1758 | + uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES]); 1759 | + 1760 | +void PQCLEAN_KYBER512_CLEAN_indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES], 1761 | + const uint8_t m[KYBER_INDCPA_MSGBYTES], 1762 | + const uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES], 1763 | + const uint8_t coins[KYBER_SYMBYTES]); 1764 | + 1765 | +void PQCLEAN_KYBER512_CLEAN_indcpa_dec(uint8_t m[KYBER_INDCPA_MSGBYTES], 1766 | + const uint8_t c[KYBER_INDCPA_BYTES], 1767 | + const uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES]); 1768 | + 1769 | +#endif 1770 | diff --git a/lib/freebl/kyber512/kem.c b/lib/freebl/kyber512/kem.c 1771 | new file mode 100644 1772 | index 000000000..510c78886 1773 | --- /dev/null 1774 | +++ b/lib/freebl/kyber512/kem.c 1775 | @@ -0,0 +1,126 @@ 1776 | +#include "indcpa.h" 1777 | +#include "kem.h" 1778 | +#include "params.h" 1779 | +#include "randombytes.h" 1780 | +#include "symmetric.h" 1781 | +#include "verify.h" 1782 | +#include 1783 | +#include 1784 | + 1785 | +/************************************************* 1786 | +* Name: PQCLEAN_KYBER512_CLEAN_crypto_kem_keypair 1787 | +* 1788 | +* Description: Generates public and private key 1789 | +* for CCA-secure Kyber key encapsulation mechanism 1790 | +* 1791 | +* Arguments: - uint8_t *pk: pointer to output public key 1792 | +* (an already allocated array of KYBER_PUBLICKEYBYTES bytes) 1793 | +* - uint8_t *sk: pointer to output private key 1794 | +* (an already allocated array of KYBER_SECRETKEYBYTES bytes) 1795 | +* 1796 | +* Returns 0 (success) 1797 | +**************************************************/ 1798 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_keypair(uint8_t *pk, 1799 | + uint8_t *sk) { 1800 | + size_t i; 1801 | + PQCLEAN_KYBER512_CLEAN_indcpa_keypair(pk, sk); 1802 | + for (i = 0; i < KYBER_INDCPA_PUBLICKEYBYTES; i++) { 1803 | + sk[i + KYBER_INDCPA_SECRETKEYBYTES] = pk[i]; 1804 | + } 1805 | + hash_h(sk + KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); 1806 | + /* Value z for pseudo-random output on reject */ 1807 | + randombytes(sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES); 1808 | + return 0; 1809 | +} 1810 | + 1811 | +/************************************************* 1812 | +* Name: PQCLEAN_KYBER512_CLEAN_crypto_kem_enc 1813 | +* 1814 | +* Description: Generates cipher text and shared 1815 | +* secret for given public key 1816 | +* 1817 | +* Arguments: - uint8_t *ct: pointer to output cipher text 1818 | +* (an already allocated array of KYBER_CIPHERTEXTBYTES bytes) 1819 | +* - uint8_t *ss: pointer to output shared secret 1820 | +* (an already allocated array of KYBER_SSBYTES bytes) 1821 | +* - const uint8_t *pk: pointer to input public key 1822 | +* (an already allocated array of KYBER_PUBLICKEYBYTES bytes) 1823 | +* 1824 | +* Returns 0 (success) 1825 | +**************************************************/ 1826 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_enc(uint8_t *ct, 1827 | + uint8_t *ss, 1828 | + const uint8_t *pk) { 1829 | + uint8_t buf[2 * KYBER_SYMBYTES]; 1830 | + /* Will contain key, coins */ 1831 | + uint8_t kr[2 * KYBER_SYMBYTES]; 1832 | + 1833 | + randombytes(buf, KYBER_SYMBYTES); 1834 | + /* Don't release system RNG output */ 1835 | + hash_h(buf, buf, KYBER_SYMBYTES); 1836 | + 1837 | + /* Multitarget countermeasure for coins + contributory KEM */ 1838 | + hash_h(buf + KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); 1839 | + hash_g(kr, buf, 2 * KYBER_SYMBYTES); 1840 | + 1841 | + /* coins are in kr+KYBER_SYMBYTES */ 1842 | + PQCLEAN_KYBER512_CLEAN_indcpa_enc(ct, buf, pk, kr + KYBER_SYMBYTES); 1843 | + 1844 | + /* overwrite coins in kr with H(c) */ 1845 | + hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); 1846 | + /* hash concatenation of pre-k and H(c) to k */ 1847 | + kdf(ss, kr, 2 * KYBER_SYMBYTES); 1848 | + return 0; 1849 | +} 1850 | + 1851 | +/************************************************* 1852 | +* Name: PQCLEAN_KYBER512_CLEAN_crypto_kem_dec 1853 | +* 1854 | +* Description: Generates shared secret for given 1855 | +* cipher text and private key 1856 | +* 1857 | +* Arguments: - uint8_t *ss: pointer to output shared secret 1858 | +* (an already allocated array of KYBER_SSBYTES bytes) 1859 | +* - const uint8_t *ct: pointer to input cipher text 1860 | +* (an already allocated array of KYBER_CIPHERTEXTBYTES bytes) 1861 | +* - const uint8_t *sk: pointer to input private key 1862 | +* (an already allocated array of KYBER_SECRETKEYBYTES bytes) 1863 | +* 1864 | +* Returns 0. 1865 | +* 1866 | +* On failure, ss will contain a pseudo-random value. 1867 | +**************************************************/ 1868 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_dec(uint8_t *ss, 1869 | + const uint8_t *ct, 1870 | + const uint8_t *sk) { 1871 | + size_t i; 1872 | + int fail; 1873 | + uint8_t buf[2 * KYBER_SYMBYTES]; 1874 | + /* Will contain key, coins */ 1875 | + uint8_t kr[2 * KYBER_SYMBYTES]; 1876 | + uint8_t cmp[KYBER_CIPHERTEXTBYTES]; 1877 | + const uint8_t *pk = sk + KYBER_INDCPA_SECRETKEYBYTES; 1878 | + 1879 | + PQCLEAN_KYBER512_CLEAN_indcpa_dec(buf, ct, sk); 1880 | + 1881 | + /* Multitarget countermeasure for coins + contributory KEM */ 1882 | + for (i = 0; i < KYBER_SYMBYTES; i++) { 1883 | + buf[KYBER_SYMBYTES + i] = sk[KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES + i]; 1884 | + } 1885 | + hash_g(kr, buf, 2 * KYBER_SYMBYTES); 1886 | + 1887 | + /* coins are in kr+KYBER_SYMBYTES */ 1888 | + PQCLEAN_KYBER512_CLEAN_indcpa_enc(cmp, buf, pk, kr + KYBER_SYMBYTES); 1889 | + 1890 | + fail = PQCLEAN_KYBER512_CLEAN_verify(ct, cmp, KYBER_CIPHERTEXTBYTES); 1891 | + 1892 | + /* overwrite coins in kr with H(c) */ 1893 | + hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); 1894 | + 1895 | + /* Overwrite pre-k with z on re-encryption failure */ 1896 | + PQCLEAN_KYBER512_CLEAN_cmov(kr, sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES, (uint8_t)fail); 1897 | + 1898 | + /* hash concatenation of pre-k and H(c) to k */ 1899 | + kdf(ss, kr, 2 * KYBER_SYMBYTES); 1900 | + return 0; 1901 | +} 1902 | diff --git a/lib/freebl/kyber512/kem.h b/lib/freebl/kyber512/kem.h 1903 | new file mode 100644 1904 | index 000000000..722209b5b 1905 | --- /dev/null 1906 | +++ b/lib/freebl/kyber512/kem.h 1907 | @@ -0,0 +1,19 @@ 1908 | +#ifndef PQCLEAN_KYBER512_CLEAN_KEM_H 1909 | +#define PQCLEAN_KYBER512_CLEAN_KEM_H 1910 | +#include "params.h" 1911 | +#include 1912 | + 1913 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_SECRETKEYBYTES KYBER_SECRETKEYBYTES 1914 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_PUBLICKEYBYTES KYBER_PUBLICKEYBYTES 1915 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_CIPHERTEXTBYTES KYBER_CIPHERTEXTBYTES 1916 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_BYTES KYBER_SSBYTES 1917 | + 1918 | +#define PQCLEAN_KYBER512_CLEAN_CRYPTO_ALGNAME "Kyber512" 1919 | + 1920 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk); 1921 | + 1922 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk); 1923 | + 1924 | +int PQCLEAN_KYBER512_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk); 1925 | + 1926 | +#endif 1927 | diff --git a/lib/freebl/kyber512/ntt.c b/lib/freebl/kyber512/ntt.c 1928 | new file mode 100644 1929 | index 000000000..e284a8c52 1930 | --- /dev/null 1931 | +++ b/lib/freebl/kyber512/ntt.c 1932 | @@ -0,0 +1,146 @@ 1933 | +#include "ntt.h" 1934 | +#include "params.h" 1935 | +#include "reduce.h" 1936 | +#include 1937 | + 1938 | +/* Code to generate PQCLEAN_KYBER512_CLEAN_zetas and zetas_inv used in the number-theoretic transform: 1939 | + 1940 | +#define KYBER_ROOT_OF_UNITY 17 1941 | + 1942 | +static const uint8_t tree[128] = { 1943 | + 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, 1944 | + 4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124, 1945 | + 2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122, 1946 | + 6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126, 1947 | + 1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121, 1948 | + 5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, 1949 | + 3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, 1950 | + 7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127 1951 | +}; 1952 | + 1953 | +void init_ntt() { 1954 | + unsigned int i; 1955 | + int16_t tmp[128]; 1956 | + 1957 | + tmp[0] = MONT; 1958 | + for(i=1;i<128;i++) 1959 | + tmp[i] = fqmul(tmp[i-1],MONT*KYBER_ROOT_OF_UNITY % KYBER_Q); 1960 | + 1961 | + for(i=0;i<128;i++) { 1962 | + PQCLEAN_KYBER512_CLEAN_zetas[i] = tmp[tree[i]]; 1963 | + if(PQCLEAN_KYBER512_CLEAN_zetas[i] > KYBER_Q/2) 1964 | + PQCLEAN_KYBER512_CLEAN_zetas[i] -= KYBER_Q; 1965 | + if(PQCLEAN_KYBER512_CLEAN_zetas[i] < -KYBER_Q/2) 1966 | + PQCLEAN_KYBER512_CLEAN_zetas[i] += KYBER_Q; 1967 | + } 1968 | +} 1969 | +*/ 1970 | + 1971 | +const int16_t PQCLEAN_KYBER512_CLEAN_zetas[128] = { 1972 | + -1044, -758, -359, -1517, 1493, 1422, 287, 202, 1973 | + -171, 622, 1577, 182, 962, -1202, -1474, 1468, 1974 | + 573, -1325, 264, 383, -829, 1458, -1602, -130, 1975 | + -681, 1017, 732, 608, -1542, 411, -205, -1571, 1976 | + 1223, 652, -552, 1015, -1293, 1491, -282, -1544, 1977 | + 516, -8, -320, -666, -1618, -1162, 126, 1469, 1978 | + -853, -90, -271, 830, 107, -1421, -247, -951, 1979 | + -398, 961, -1508, -725, 448, -1065, 677, -1275, 1980 | + -1103, 430, 555, 843, -1251, 871, 1550, 105, 1981 | + 422, 587, 177, -235, -291, -460, 1574, 1653, 1982 | + -246, 778, 1159, -147, -777, 1483, -602, 1119, 1983 | + -1590, 644, -872, 349, 418, 329, -156, -75, 1984 | + 817, 1097, 603, 610, 1322, -1285, -1465, 384, 1985 | + -1215, -136, 1218, -1335, -874, 220, -1187, -1659, 1986 | + -1185, -1530, -1278, 794, -1510, -854, -870, 478, 1987 | + -108, -308, 996, 991, 958, -1460, 1522, 1628 1988 | + }; 1989 | + 1990 | +/************************************************* 1991 | +* Name: fqmul 1992 | +* 1993 | +* Description: Multiplication followed by Montgomery reduction 1994 | +* 1995 | +* Arguments: - int16_t a: first factor 1996 | +* - int16_t b: second factor 1997 | +* 1998 | +* Returns 16-bit integer congruent to a*b*R^{-1} mod q 1999 | +**************************************************/ 2000 | +static int16_t fqmul(int16_t a, int16_t b) { 2001 | + return PQCLEAN_KYBER512_CLEAN_montgomery_reduce((int32_t)a * b); 2002 | +} 2003 | + 2004 | +/************************************************* 2005 | +* Name: PQCLEAN_KYBER512_CLEAN_ntt 2006 | +* 2007 | +* Description: Inplace number-theoretic transform (NTT) in Rq. 2008 | +* input is in standard order, output is in bitreversed order 2009 | +* 2010 | +* Arguments: - int16_t r[256]: pointer to input/output vector of elements of Zq 2011 | +**************************************************/ 2012 | +void PQCLEAN_KYBER512_CLEAN_ntt(int16_t r[256]) { 2013 | + unsigned int len, start, j, k; 2014 | + int16_t t, zeta; 2015 | + 2016 | + k = 1; 2017 | + for (len = 128; len >= 2; len >>= 1) { 2018 | + for (start = 0; start < 256; start = j + len) { 2019 | + zeta = PQCLEAN_KYBER512_CLEAN_zetas[k++]; 2020 | + for (j = start; j < start + len; j++) { 2021 | + t = fqmul(zeta, r[j + len]); 2022 | + r[j + len] = r[j] - t; 2023 | + r[j] = r[j] + t; 2024 | + } 2025 | + } 2026 | + } 2027 | +} 2028 | + 2029 | +/************************************************* 2030 | +* Name: invntt_tomont 2031 | +* 2032 | +* Description: Inplace inverse number-theoretic transform in Rq and 2033 | +* multiplication by Montgomery factor 2^16. 2034 | +* Input is in bitreversed order, output is in standard order 2035 | +* 2036 | +* Arguments: - int16_t r[256]: pointer to input/output vector of elements of Zq 2037 | +**************************************************/ 2038 | +void PQCLEAN_KYBER512_CLEAN_invntt(int16_t r[256]) { 2039 | + unsigned int start, len, j, k; 2040 | + int16_t t, zeta; 2041 | + const int16_t f = 1441; // mont^2/128 2042 | + 2043 | + k = 127; 2044 | + for (len = 2; len <= 128; len <<= 1) { 2045 | + for (start = 0; start < 256; start = j + len) { 2046 | + zeta = PQCLEAN_KYBER512_CLEAN_zetas[k--]; 2047 | + for (j = start; j < start + len; j++) { 2048 | + t = r[j]; 2049 | + r[j] = PQCLEAN_KYBER512_CLEAN_barrett_reduce(t + r[j + len]); 2050 | + r[j + len] = r[j + len] - t; 2051 | + r[j + len] = fqmul(zeta, r[j + len]); 2052 | + } 2053 | + } 2054 | + } 2055 | + 2056 | + for (j = 0; j < 256; j++) { 2057 | + r[j] = fqmul(r[j], f); 2058 | + } 2059 | +} 2060 | + 2061 | +/************************************************* 2062 | +* Name: PQCLEAN_KYBER512_CLEAN_basemul 2063 | +* 2064 | +* Description: Multiplication of polynomials in Zq[X]/(X^2-zeta) 2065 | +* used for multiplication of elements in Rq in NTT domain 2066 | +* 2067 | +* Arguments: - int16_t r[2]: pointer to the output polynomial 2068 | +* - const int16_t a[2]: pointer to the first factor 2069 | +* - const int16_t b[2]: pointer to the second factor 2070 | +* - int16_t zeta: integer defining the reduction polynomial 2071 | +**************************************************/ 2072 | +void PQCLEAN_KYBER512_CLEAN_basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta) { 2073 | + r[0] = fqmul(a[1], b[1]); 2074 | + r[0] = fqmul(r[0], zeta); 2075 | + r[0] += fqmul(a[0], b[0]); 2076 | + r[1] = fqmul(a[0], b[1]); 2077 | + r[1] += fqmul(a[1], b[0]); 2078 | +} 2079 | diff --git a/lib/freebl/kyber512/ntt.h b/lib/freebl/kyber512/ntt.h 2080 | new file mode 100644 2081 | index 000000000..d25bc40c0 2082 | --- /dev/null 2083 | +++ b/lib/freebl/kyber512/ntt.h 2084 | @@ -0,0 +1,14 @@ 2085 | +#ifndef PQCLEAN_KYBER512_CLEAN_NTT_H 2086 | +#define PQCLEAN_KYBER512_CLEAN_NTT_H 2087 | +#include "params.h" 2088 | +#include 2089 | + 2090 | +extern const int16_t PQCLEAN_KYBER512_CLEAN_zetas[128]; 2091 | + 2092 | +void PQCLEAN_KYBER512_CLEAN_ntt(int16_t r[256]); 2093 | + 2094 | +void PQCLEAN_KYBER512_CLEAN_invntt(int16_t r[256]); 2095 | + 2096 | +void PQCLEAN_KYBER512_CLEAN_basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta); 2097 | + 2098 | +#endif 2099 | diff --git a/lib/freebl/kyber512/params.h b/lib/freebl/kyber512/params.h 2100 | new file mode 100644 2101 | index 000000000..f2c7efc78 2102 | --- /dev/null 2103 | +++ b/lib/freebl/kyber512/params.h 2104 | @@ -0,0 +1,33 @@ 2105 | +#ifndef PQCLEAN_KYBER512_CLEAN_PARAMS_H 2106 | +#define PQCLEAN_KYBER512_CLEAN_PARAMS_H 2107 | + 2108 | + 2109 | + 2110 | + 2111 | +#define KYBER_N 256 2112 | +#define KYBER_Q 3329 2113 | + 2114 | +#define KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */ 2115 | +#define KYBER_SSBYTES 32 /* size in bytes of shared key */ 2116 | + 2117 | +#define KYBER_POLYBYTES 384 2118 | +#define KYBER_POLYVECBYTES (KYBER_K * KYBER_POLYBYTES) 2119 | + 2120 | +#define KYBER_K 2 2121 | +#define KYBER_ETA1 3 2122 | +#define KYBER_POLYCOMPRESSEDBYTES 128 2123 | +#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 320) 2124 | + 2125 | +#define KYBER_ETA2 2 2126 | + 2127 | +#define KYBER_INDCPA_MSGBYTES (KYBER_SYMBYTES) 2128 | +#define KYBER_INDCPA_PUBLICKEYBYTES (KYBER_POLYVECBYTES + KYBER_SYMBYTES) 2129 | +#define KYBER_INDCPA_SECRETKEYBYTES (KYBER_POLYVECBYTES) 2130 | +#define KYBER_INDCPA_BYTES (KYBER_POLYVECCOMPRESSEDBYTES + KYBER_POLYCOMPRESSEDBYTES) 2131 | + 2132 | +#define KYBER_PUBLICKEYBYTES (KYBER_INDCPA_PUBLICKEYBYTES) 2133 | +/* 32 bytes of additional space to save H(pk) */ 2134 | +#define KYBER_SECRETKEYBYTES (KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES + 2*KYBER_SYMBYTES) 2135 | +#define KYBER_CIPHERTEXTBYTES (KYBER_INDCPA_BYTES) 2136 | + 2137 | +#endif 2138 | diff --git a/lib/freebl/kyber512/poly.c b/lib/freebl/kyber512/poly.c 2139 | new file mode 100644 2140 | index 000000000..f10afd7db 2141 | --- /dev/null 2142 | +++ b/lib/freebl/kyber512/poly.c 2143 | @@ -0,0 +1,287 @@ 2144 | +#include "cbd.h" 2145 | +#include "ntt.h" 2146 | +#include "params.h" 2147 | +#include "poly.h" 2148 | +#include "reduce.h" 2149 | +#include "symmetric.h" 2150 | +#include 2151 | + 2152 | +/************************************************* 2153 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_compress 2154 | +* 2155 | +* Description: Compression and subsequent serialization of a polynomial 2156 | +* 2157 | +* Arguments: - uint8_t *r: pointer to output byte array 2158 | +* (of length KYBER_POLYCOMPRESSEDBYTES) 2159 | +* - const poly *a: pointer to input polynomial 2160 | +**************************************************/ 2161 | +void PQCLEAN_KYBER512_CLEAN_poly_compress(uint8_t r[KYBER_POLYCOMPRESSEDBYTES], const poly *a) { 2162 | + size_t i, j; 2163 | + int16_t u; 2164 | + uint8_t t[8]; 2165 | + 2166 | + for (i = 0; i < KYBER_N / 8; i++) { 2167 | + for (j = 0; j < 8; j++) { 2168 | + // map to positive standard representatives 2169 | + u = a->coeffs[8 * i + j]; 2170 | + u += (u >> 15) & KYBER_Q; 2171 | + t[j] = ((((uint16_t)u << 4) + KYBER_Q / 2) / KYBER_Q) & 15; 2172 | + } 2173 | + 2174 | + r[0] = t[0] | (t[1] << 4); 2175 | + r[1] = t[2] | (t[3] << 4); 2176 | + r[2] = t[4] | (t[5] << 4); 2177 | + r[3] = t[6] | (t[7] << 4); 2178 | + r += 4; 2179 | + } 2180 | +} 2181 | + 2182 | +/************************************************* 2183 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_decompress 2184 | +* 2185 | +* Description: De-serialization and subsequent decompression of a polynomial; 2186 | +* approximate inverse of PQCLEAN_KYBER512_CLEAN_poly_compress 2187 | +* 2188 | +* Arguments: - poly *r: pointer to output polynomial 2189 | +* - const uint8_t *a: pointer to input byte array 2190 | +* (of length KYBER_POLYCOMPRESSEDBYTES bytes) 2191 | +**************************************************/ 2192 | +void PQCLEAN_KYBER512_CLEAN_poly_decompress(poly *r, const uint8_t a[KYBER_POLYCOMPRESSEDBYTES]) { 2193 | + size_t i; 2194 | + 2195 | + for (i = 0; i < KYBER_N / 2; i++) { 2196 | + r->coeffs[2 * i + 0] = (((uint16_t)(a[0] & 15) * KYBER_Q) + 8) >> 4; 2197 | + r->coeffs[2 * i + 1] = (((uint16_t)(a[0] >> 4) * KYBER_Q) + 8) >> 4; 2198 | + a += 1; 2199 | + } 2200 | +} 2201 | + 2202 | +/************************************************* 2203 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_tobytes 2204 | +* 2205 | +* Description: Serialization of a polynomial 2206 | +* 2207 | +* Arguments: - uint8_t *r: pointer to output byte array 2208 | +* (needs space for KYBER_POLYBYTES bytes) 2209 | +* - const poly *a: pointer to input polynomial 2210 | +**************************************************/ 2211 | +void PQCLEAN_KYBER512_CLEAN_poly_tobytes(uint8_t r[KYBER_POLYBYTES], const poly *a) { 2212 | + size_t i; 2213 | + uint16_t t0, t1; 2214 | + 2215 | + for (i = 0; i < KYBER_N / 2; i++) { 2216 | + // map to positive standard representatives 2217 | + t0 = a->coeffs[2 * i]; 2218 | + t0 += ((int16_t)t0 >> 15) & KYBER_Q; 2219 | + t1 = a->coeffs[2 * i + 1]; 2220 | + t1 += ((int16_t)t1 >> 15) & KYBER_Q; 2221 | + r[3 * i + 0] = (uint8_t)(t0 >> 0); 2222 | + r[3 * i + 1] = (uint8_t)((t0 >> 8) | (t1 << 4)); 2223 | + r[3 * i + 2] = (uint8_t)(t1 >> 4); 2224 | + } 2225 | +} 2226 | + 2227 | +/************************************************* 2228 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_frombytes 2229 | +* 2230 | +* Description: De-serialization of a polynomial; 2231 | +* inverse of PQCLEAN_KYBER512_CLEAN_poly_tobytes 2232 | +* 2233 | +* Arguments: - poly *r: pointer to output polynomial 2234 | +* - const uint8_t *a: pointer to input byte array 2235 | +* (of KYBER_POLYBYTES bytes) 2236 | +**************************************************/ 2237 | +void PQCLEAN_KYBER512_CLEAN_poly_frombytes(poly *r, const uint8_t a[KYBER_POLYBYTES]) { 2238 | + size_t i; 2239 | + for (i = 0; i < KYBER_N / 2; i++) { 2240 | + r->coeffs[2 * i] = ((a[3 * i + 0] >> 0) | ((uint16_t)a[3 * i + 1] << 8)) & 0xFFF; 2241 | + r->coeffs[2 * i + 1] = ((a[3 * i + 1] >> 4) | ((uint16_t)a[3 * i + 2] << 4)) & 0xFFF; 2242 | + } 2243 | +} 2244 | + 2245 | +/************************************************* 2246 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_frommsg 2247 | +* 2248 | +* Description: Convert 32-byte message to polynomial 2249 | +* 2250 | +* Arguments: - poly *r: pointer to output polynomial 2251 | +* - const uint8_t *msg: pointer to input message 2252 | +**************************************************/ 2253 | +void PQCLEAN_KYBER512_CLEAN_poly_frommsg(poly *r, const uint8_t msg[KYBER_INDCPA_MSGBYTES]) { 2254 | + size_t i, j; 2255 | + int16_t mask; 2256 | + 2257 | + for (i = 0; i < KYBER_N / 8; i++) { 2258 | + for (j = 0; j < 8; j++) { 2259 | + mask = -(int16_t)((msg[i] >> j) & 1); 2260 | + r->coeffs[8 * i + j] = mask & ((KYBER_Q + 1) / 2); 2261 | + } 2262 | + } 2263 | +} 2264 | + 2265 | +/************************************************* 2266 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_tomsg 2267 | +* 2268 | +* Description: Convert polynomial to 32-byte message 2269 | +* 2270 | +* Arguments: - uint8_t *msg: pointer to output message 2271 | +* - const poly *a: pointer to input polynomial 2272 | +**************************************************/ 2273 | +void PQCLEAN_KYBER512_CLEAN_poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *a) { 2274 | + size_t i, j; 2275 | + uint16_t t; 2276 | + 2277 | + for (i = 0; i < KYBER_N / 8; i++) { 2278 | + msg[i] = 0; 2279 | + for (j = 0; j < 8; j++) { 2280 | + t = a->coeffs[8 * i + j]; 2281 | + t += ((int16_t)t >> 15) & KYBER_Q; 2282 | + t = (((t << 1) + KYBER_Q / 2) / KYBER_Q) & 1; 2283 | + msg[i] |= t << j; 2284 | + } 2285 | + } 2286 | +} 2287 | + 2288 | +/************************************************* 2289 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta1 2290 | +* 2291 | +* Description: Sample a polynomial deterministically from a seed and a nonce, 2292 | +* with output polynomial close to centered binomial distribution 2293 | +* with parameter KYBER_ETA1 2294 | +* 2295 | +* Arguments: - poly *r: pointer to output polynomial 2296 | +* - const uint8_t *seed: pointer to input seed 2297 | +* (of length KYBER_SYMBYTES bytes) 2298 | +* - uint8_t nonce: one-byte input nonce 2299 | +**************************************************/ 2300 | +void PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta1(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce) { 2301 | + uint8_t buf[KYBER_ETA1 * KYBER_N / 4]; 2302 | + prf(buf, sizeof(buf), seed, nonce); 2303 | + PQCLEAN_KYBER512_CLEAN_poly_cbd_eta1(r, buf); 2304 | +} 2305 | + 2306 | +/************************************************* 2307 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta2 2308 | +* 2309 | +* Description: Sample a polynomial deterministically from a seed and a nonce, 2310 | +* with output polynomial close to centered binomial distribution 2311 | +* with parameter KYBER_ETA2 2312 | +* 2313 | +* Arguments: - poly *r: pointer to output polynomial 2314 | +* - const uint8_t *seed: pointer to input seed 2315 | +* (of length KYBER_SYMBYTES bytes) 2316 | +* - uint8_t nonce: one-byte input nonce 2317 | +**************************************************/ 2318 | +void PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta2(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce) { 2319 | + uint8_t buf[KYBER_ETA2 * KYBER_N / 4]; 2320 | + prf(buf, sizeof(buf), seed, nonce); 2321 | + PQCLEAN_KYBER512_CLEAN_poly_cbd_eta2(r, buf); 2322 | +} 2323 | + 2324 | + 2325 | +/************************************************* 2326 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_ntt 2327 | +* 2328 | +* Description: Computes negacyclic number-theoretic transform (NTT) of 2329 | +* a polynomial in place; 2330 | +* inputs assumed to be in normal order, output in bitreversed order 2331 | +* 2332 | +* Arguments: - uint16_t *r: pointer to in/output polynomial 2333 | +**************************************************/ 2334 | +void PQCLEAN_KYBER512_CLEAN_poly_ntt(poly *r) { 2335 | + PQCLEAN_KYBER512_CLEAN_ntt(r->coeffs); 2336 | + PQCLEAN_KYBER512_CLEAN_poly_reduce(r); 2337 | +} 2338 | + 2339 | +/************************************************* 2340 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_invntt_tomont 2341 | +* 2342 | +* Description: Computes inverse of negacyclic number-theoretic transform (NTT) 2343 | +* of a polynomial in place; 2344 | +* inputs assumed to be in bitreversed order, output in normal order 2345 | +* 2346 | +* Arguments: - uint16_t *a: pointer to in/output polynomial 2347 | +**************************************************/ 2348 | +void PQCLEAN_KYBER512_CLEAN_poly_invntt_tomont(poly *r) { 2349 | + PQCLEAN_KYBER512_CLEAN_invntt(r->coeffs); 2350 | +} 2351 | + 2352 | +/************************************************* 2353 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_basemul_montgomery 2354 | +* 2355 | +* Description: Multiplication of two polynomials in NTT domain 2356 | +* 2357 | +* Arguments: - poly *r: pointer to output polynomial 2358 | +* - const poly *a: pointer to first input polynomial 2359 | +* - const poly *b: pointer to second input polynomial 2360 | +**************************************************/ 2361 | +void PQCLEAN_KYBER512_CLEAN_poly_basemul_montgomery(poly *r, const poly *a, const poly *b) { 2362 | + size_t i; 2363 | + for (i = 0; i < KYBER_N / 4; i++) { 2364 | + PQCLEAN_KYBER512_CLEAN_basemul(&r->coeffs[4 * i], &a->coeffs[4 * i], &b->coeffs[4 * i], PQCLEAN_KYBER512_CLEAN_zetas[64 + i]); 2365 | + PQCLEAN_KYBER512_CLEAN_basemul(&r->coeffs[4 * i + 2], &a->coeffs[4 * i + 2], &b->coeffs[4 * i + 2], -PQCLEAN_KYBER512_CLEAN_zetas[64 + i]); 2366 | + } 2367 | +} 2368 | + 2369 | +/************************************************* 2370 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_tomont 2371 | +* 2372 | +* Description: Inplace conversion of all coefficients of a polynomial 2373 | +* from normal domain to Montgomery domain 2374 | +* 2375 | +* Arguments: - poly *r: pointer to input/output polynomial 2376 | +**************************************************/ 2377 | +void PQCLEAN_KYBER512_CLEAN_poly_tomont(poly *r) { 2378 | + size_t i; 2379 | + const int16_t f = (1ULL << 32) % KYBER_Q; 2380 | + for (i = 0; i < KYBER_N; i++) { 2381 | + r->coeffs[i] = PQCLEAN_KYBER512_CLEAN_montgomery_reduce((int32_t)r->coeffs[i] * f); 2382 | + } 2383 | +} 2384 | + 2385 | +/************************************************* 2386 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_reduce 2387 | +* 2388 | +* Description: Applies Barrett reduction to all coefficients of a polynomial 2389 | +* for details of the Barrett reduction see comments in reduce.c 2390 | +* 2391 | +* Arguments: - poly *r: pointer to input/output polynomial 2392 | +**************************************************/ 2393 | +void PQCLEAN_KYBER512_CLEAN_poly_reduce(poly *r) { 2394 | + size_t i; 2395 | + for (i = 0; i < KYBER_N; i++) { 2396 | + r->coeffs[i] = PQCLEAN_KYBER512_CLEAN_barrett_reduce(r->coeffs[i]); 2397 | + } 2398 | +} 2399 | + 2400 | +/************************************************* 2401 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_add 2402 | +* 2403 | +* Description: Add two polynomials; no modular reduction is performed 2404 | +* 2405 | +* Arguments: - poly *r: pointer to output polynomial 2406 | +* - const poly *a: pointer to first input polynomial 2407 | +* - const poly *b: pointer to second input polynomial 2408 | +**************************************************/ 2409 | +void PQCLEAN_KYBER512_CLEAN_poly_add(poly *r, const poly *a, const poly *b) { 2410 | + size_t i; 2411 | + for (i = 0; i < KYBER_N; i++) { 2412 | + r->coeffs[i] = a->coeffs[i] + b->coeffs[i]; 2413 | + } 2414 | +} 2415 | + 2416 | +/************************************************* 2417 | +* Name: PQCLEAN_KYBER512_CLEAN_poly_sub 2418 | +* 2419 | +* Description: Subtract two polynomials; no modular reduction is performed 2420 | +* 2421 | +* Arguments: - poly *r: pointer to output polynomial 2422 | +* - const poly *a: pointer to first input polynomial 2423 | +* - const poly *b: pointer to second input polynomial 2424 | +**************************************************/ 2425 | +void PQCLEAN_KYBER512_CLEAN_poly_sub(poly *r, const poly *a, const poly *b) { 2426 | + size_t i; 2427 | + for (i = 0; i < KYBER_N; i++) { 2428 | + r->coeffs[i] = a->coeffs[i] - b->coeffs[i]; 2429 | + } 2430 | +} 2431 | diff --git a/lib/freebl/kyber512/poly.h b/lib/freebl/kyber512/poly.h 2432 | new file mode 100644 2433 | index 000000000..5ca491d15 2434 | --- /dev/null 2435 | +++ b/lib/freebl/kyber512/poly.h 2436 | @@ -0,0 +1,37 @@ 2437 | +#ifndef PQCLEAN_KYBER512_CLEAN_POLY_H 2438 | +#define PQCLEAN_KYBER512_CLEAN_POLY_H 2439 | +#include "params.h" 2440 | +#include 2441 | + 2442 | +/* 2443 | + * Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial 2444 | + * coeffs[0] + X*coeffs[1] + X^2*xoeffs[2] + ... + X^{n-1}*coeffs[n-1] 2445 | + */ 2446 | +typedef struct { 2447 | + int16_t coeffs[KYBER_N]; 2448 | +} poly; 2449 | + 2450 | +void PQCLEAN_KYBER512_CLEAN_poly_compress(uint8_t r[KYBER_POLYCOMPRESSEDBYTES], const poly *a); 2451 | +void PQCLEAN_KYBER512_CLEAN_poly_decompress(poly *r, const uint8_t a[KYBER_POLYCOMPRESSEDBYTES]); 2452 | + 2453 | +void PQCLEAN_KYBER512_CLEAN_poly_tobytes(uint8_t r[KYBER_POLYBYTES], const poly *a); 2454 | +void PQCLEAN_KYBER512_CLEAN_poly_frombytes(poly *r, const uint8_t a[KYBER_POLYBYTES]); 2455 | + 2456 | +void PQCLEAN_KYBER512_CLEAN_poly_frommsg(poly *r, const uint8_t msg[KYBER_INDCPA_MSGBYTES]); 2457 | +void PQCLEAN_KYBER512_CLEAN_poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *a); 2458 | + 2459 | +void PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta1(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce); 2460 | + 2461 | +void PQCLEAN_KYBER512_CLEAN_poly_getnoise_eta2(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce); 2462 | + 2463 | +void PQCLEAN_KYBER512_CLEAN_poly_ntt(poly *r); 2464 | +void PQCLEAN_KYBER512_CLEAN_poly_invntt_tomont(poly *r); 2465 | +void PQCLEAN_KYBER512_CLEAN_poly_basemul_montgomery(poly *r, const poly *a, const poly *b); 2466 | +void PQCLEAN_KYBER512_CLEAN_poly_tomont(poly *r); 2467 | + 2468 | +void PQCLEAN_KYBER512_CLEAN_poly_reduce(poly *r); 2469 | + 2470 | +void PQCLEAN_KYBER512_CLEAN_poly_add(poly *r, const poly *a, const poly *b); 2471 | +void PQCLEAN_KYBER512_CLEAN_poly_sub(poly *r, const poly *a, const poly *b); 2472 | + 2473 | +#endif 2474 | diff --git a/lib/freebl/kyber512/polyvec.c b/lib/freebl/kyber512/polyvec.c 2475 | new file mode 100644 2476 | index 000000000..9f169f388 2477 | --- /dev/null 2478 | +++ b/lib/freebl/kyber512/polyvec.c 2479 | @@ -0,0 +1,181 @@ 2480 | +#include "params.h" 2481 | +#include "poly.h" 2482 | +#include "polyvec.h" 2483 | +#include 2484 | + 2485 | +/************************************************* 2486 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_compress 2487 | +* 2488 | +* Description: Compress and serialize vector of polynomials 2489 | +* 2490 | +* Arguments: - uint8_t *r: pointer to output byte array 2491 | +* (needs space for KYBER_POLYVECCOMPRESSEDBYTES) 2492 | +* - const polyvec *a: pointer to input vector of polynomials 2493 | +**************************************************/ 2494 | +void PQCLEAN_KYBER512_CLEAN_polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a) { 2495 | + unsigned int i, j, k; 2496 | + 2497 | + uint16_t t[4]; 2498 | + for (i = 0; i < KYBER_K; i++) { 2499 | + for (j = 0; j < KYBER_N / 4; j++) { 2500 | + for (k = 0; k < 4; k++) { 2501 | + t[k] = a->vec[i].coeffs[4 * j + k]; 2502 | + t[k] += ((int16_t)t[k] >> 15) & KYBER_Q; 2503 | + t[k] = ((((uint32_t)t[k] << 10) + KYBER_Q / 2) / KYBER_Q) & 0x3ff; 2504 | + } 2505 | + 2506 | + r[0] = (uint8_t)(t[0] >> 0); 2507 | + r[1] = (uint8_t)((t[0] >> 8) | (t[1] << 2)); 2508 | + r[2] = (uint8_t)((t[1] >> 6) | (t[2] << 4)); 2509 | + r[3] = (uint8_t)((t[2] >> 4) | (t[3] << 6)); 2510 | + r[4] = (uint8_t)(t[3] >> 2); 2511 | + r += 5; 2512 | + } 2513 | + } 2514 | +} 2515 | + 2516 | +/************************************************* 2517 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_decompress 2518 | +* 2519 | +* Description: De-serialize and decompress vector of polynomials; 2520 | +* approximate inverse of PQCLEAN_KYBER512_CLEAN_polyvec_compress 2521 | +* 2522 | +* Arguments: - polyvec *r: pointer to output vector of polynomials 2523 | +* - const uint8_t *a: pointer to input byte array 2524 | +* (of length KYBER_POLYVECCOMPRESSEDBYTES) 2525 | +**************************************************/ 2526 | +void PQCLEAN_KYBER512_CLEAN_polyvec_decompress(polyvec *r, const uint8_t a[KYBER_POLYVECCOMPRESSEDBYTES]) { 2527 | + unsigned int i, j, k; 2528 | + 2529 | + uint16_t t[4]; 2530 | + for (i = 0; i < KYBER_K; i++) { 2531 | + for (j = 0; j < KYBER_N / 4; j++) { 2532 | + t[0] = (a[0] >> 0) | ((uint16_t)a[1] << 8); 2533 | + t[1] = (a[1] >> 2) | ((uint16_t)a[2] << 6); 2534 | + t[2] = (a[2] >> 4) | ((uint16_t)a[3] << 4); 2535 | + t[3] = (a[3] >> 6) | ((uint16_t)a[4] << 2); 2536 | + a += 5; 2537 | + 2538 | + for (k = 0; k < 4; k++) { 2539 | + r->vec[i].coeffs[4 * j + k] = ((uint32_t)(t[k] & 0x3FF) * KYBER_Q + 512) >> 10; 2540 | + } 2541 | + } 2542 | + } 2543 | +} 2544 | + 2545 | +/************************************************* 2546 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_tobytes 2547 | +* 2548 | +* Description: Serialize vector of polynomials 2549 | +* 2550 | +* Arguments: - uint8_t *r: pointer to output byte array 2551 | +* (needs space for KYBER_POLYVECBYTES) 2552 | +* - const polyvec *a: pointer to input vector of polynomials 2553 | +**************************************************/ 2554 | +void PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(uint8_t r[KYBER_POLYVECBYTES], const polyvec *a) { 2555 | + unsigned int i; 2556 | + for (i = 0; i < KYBER_K; i++) { 2557 | + PQCLEAN_KYBER512_CLEAN_poly_tobytes(r + i * KYBER_POLYBYTES, &a->vec[i]); 2558 | + } 2559 | +} 2560 | + 2561 | +/************************************************* 2562 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_frombytes 2563 | +* 2564 | +* Description: De-serialize vector of polynomials; 2565 | +* inverse of PQCLEAN_KYBER512_CLEAN_polyvec_tobytes 2566 | +* 2567 | +* Arguments: - uint8_t *r: pointer to output byte array 2568 | +* - const polyvec *a: pointer to input vector of polynomials 2569 | +* (of length KYBER_POLYVECBYTES) 2570 | +**************************************************/ 2571 | +void PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(polyvec *r, const uint8_t a[KYBER_POLYVECBYTES]) { 2572 | + unsigned int i; 2573 | + for (i = 0; i < KYBER_K; i++) { 2574 | + PQCLEAN_KYBER512_CLEAN_poly_frombytes(&r->vec[i], a + i * KYBER_POLYBYTES); 2575 | + } 2576 | +} 2577 | + 2578 | +/************************************************* 2579 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_ntt 2580 | +* 2581 | +* Description: Apply forward NTT to all elements of a vector of polynomials 2582 | +* 2583 | +* Arguments: - polyvec *r: pointer to in/output vector of polynomials 2584 | +**************************************************/ 2585 | +void PQCLEAN_KYBER512_CLEAN_polyvec_ntt(polyvec *r) { 2586 | + unsigned int i; 2587 | + for (i = 0; i < KYBER_K; i++) { 2588 | + PQCLEAN_KYBER512_CLEAN_poly_ntt(&r->vec[i]); 2589 | + } 2590 | +} 2591 | + 2592 | +/************************************************* 2593 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_invntt_tomont 2594 | +* 2595 | +* Description: Apply inverse NTT to all elements of a vector of polynomials 2596 | +* and multiply by Montgomery factor 2^16 2597 | +* 2598 | +* Arguments: - polyvec *r: pointer to in/output vector of polynomials 2599 | +**************************************************/ 2600 | +void PQCLEAN_KYBER512_CLEAN_polyvec_invntt_tomont(polyvec *r) { 2601 | + unsigned int i; 2602 | + for (i = 0; i < KYBER_K; i++) { 2603 | + PQCLEAN_KYBER512_CLEAN_poly_invntt_tomont(&r->vec[i]); 2604 | + } 2605 | +} 2606 | + 2607 | +/************************************************* 2608 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_basemul_acc_montgomery 2609 | +* 2610 | +* Description: Multiply elements of a and b in NTT domain, accumulate into r, 2611 | +* and multiply by 2^-16. 2612 | +* 2613 | +* Arguments: - poly *r: pointer to output polynomial 2614 | +* - const polyvec *a: pointer to first input vector of polynomials 2615 | +* - const polyvec *b: pointer to second input vector of polynomials 2616 | +**************************************************/ 2617 | +void PQCLEAN_KYBER512_CLEAN_polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, const polyvec *b) { 2618 | + unsigned int i; 2619 | + poly t; 2620 | + 2621 | + PQCLEAN_KYBER512_CLEAN_poly_basemul_montgomery(r, &a->vec[0], &b->vec[0]); 2622 | + for (i = 1; i < KYBER_K; i++) { 2623 | + PQCLEAN_KYBER512_CLEAN_poly_basemul_montgomery(&t, &a->vec[i], &b->vec[i]); 2624 | + PQCLEAN_KYBER512_CLEAN_poly_add(r, r, &t); 2625 | + } 2626 | + 2627 | + PQCLEAN_KYBER512_CLEAN_poly_reduce(r); 2628 | +} 2629 | + 2630 | +/************************************************* 2631 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_reduce 2632 | +* 2633 | +* Description: Applies Barrett reduction to each coefficient 2634 | +* of each element of a vector of polynomials; 2635 | +* for details of the Barrett reduction see comments in reduce.c 2636 | +* 2637 | +* Arguments: - polyvec *r: pointer to input/output polynomial 2638 | +**************************************************/ 2639 | +void PQCLEAN_KYBER512_CLEAN_polyvec_reduce(polyvec *r) { 2640 | + unsigned int i; 2641 | + for (i = 0; i < KYBER_K; i++) { 2642 | + PQCLEAN_KYBER512_CLEAN_poly_reduce(&r->vec[i]); 2643 | + } 2644 | +} 2645 | + 2646 | +/************************************************* 2647 | +* Name: PQCLEAN_KYBER512_CLEAN_polyvec_add 2648 | +* 2649 | +* Description: Add vectors of polynomials 2650 | +* 2651 | +* Arguments: - polyvec *r: pointer to output vector of polynomials 2652 | +* - const polyvec *a: pointer to first input vector of polynomials 2653 | +* - const polyvec *b: pointer to second input vector of polynomials 2654 | +**************************************************/ 2655 | +void PQCLEAN_KYBER512_CLEAN_polyvec_add(polyvec *r, const polyvec *a, const polyvec *b) { 2656 | + unsigned int i; 2657 | + for (i = 0; i < KYBER_K; i++) { 2658 | + PQCLEAN_KYBER512_CLEAN_poly_add(&r->vec[i], &a->vec[i], &b->vec[i]); 2659 | + } 2660 | +} 2661 | diff --git a/lib/freebl/kyber512/polyvec.h b/lib/freebl/kyber512/polyvec.h 2662 | new file mode 100644 2663 | index 000000000..e0b2e13d0 2664 | --- /dev/null 2665 | +++ b/lib/freebl/kyber512/polyvec.h 2666 | @@ -0,0 +1,26 @@ 2667 | +#ifndef PQCLEAN_KYBER512_CLEAN_POLYVEC_H 2668 | +#define PQCLEAN_KYBER512_CLEAN_POLYVEC_H 2669 | +#include "params.h" 2670 | +#include "poly.h" 2671 | +#include 2672 | + 2673 | +typedef struct { 2674 | + poly vec[KYBER_K]; 2675 | +} polyvec; 2676 | + 2677 | +void PQCLEAN_KYBER512_CLEAN_polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a); 2678 | +void PQCLEAN_KYBER512_CLEAN_polyvec_decompress(polyvec *r, const uint8_t a[KYBER_POLYVECCOMPRESSEDBYTES]); 2679 | + 2680 | +void PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(uint8_t r[KYBER_POLYVECBYTES], const polyvec *a); 2681 | +void PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(polyvec *r, const uint8_t a[KYBER_POLYVECBYTES]); 2682 | + 2683 | +void PQCLEAN_KYBER512_CLEAN_polyvec_ntt(polyvec *r); 2684 | +void PQCLEAN_KYBER512_CLEAN_polyvec_invntt_tomont(polyvec *r); 2685 | + 2686 | +void PQCLEAN_KYBER512_CLEAN_polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, const polyvec *b); 2687 | + 2688 | +void PQCLEAN_KYBER512_CLEAN_polyvec_reduce(polyvec *r); 2689 | + 2690 | +void PQCLEAN_KYBER512_CLEAN_polyvec_add(polyvec *r, const polyvec *a, const polyvec *b); 2691 | + 2692 | +#endif 2693 | diff --git a/lib/freebl/kyber512/randombytes.c b/lib/freebl/kyber512/randombytes.c 2694 | new file mode 100644 2695 | index 000000000..5c1bdb754 2696 | --- /dev/null 2697 | +++ b/lib/freebl/kyber512/randombytes.c 2698 | @@ -0,0 +1,362 @@ 2699 | +/* 2700 | +The MIT License 2701 | + 2702 | +Copyright (c) 2017 Daan Sprenkels 2703 | + 2704 | +Permission is hereby granted, free of charge, to any person obtaining a copy 2705 | +of this software and associated documentation files (the "Software"), to deal 2706 | +in the Software without restriction, including without limitation the rights 2707 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2708 | +copies of the Software, and to permit persons to whom the Software is 2709 | +furnished to do so, subject to the following conditions: 2710 | + 2711 | +The above copyright notice and this permission notice shall be included in 2712 | +all copies or substantial portions of the Software. 2713 | + 2714 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2715 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2716 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2717 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2718 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2719 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2720 | +THE SOFTWARE. 2721 | +*/ 2722 | +// In the case that are compiling on linux, we need to define _GNU_SOURCE 2723 | +// *before* randombytes.h is included. Otherwise SYS_getrandom will not be 2724 | +// declared. 2725 | +#if defined(__linux__) 2726 | +# define _GNU_SOURCE 2727 | +#endif /* defined(__linux__) */ 2728 | + 2729 | +#include "randombytes.h" 2730 | + 2731 | +#if defined(_WIN32) 2732 | +/* Windows */ 2733 | +# include 2734 | +# include /* CryptAcquireContext, CryptGenRandom */ 2735 | +#endif /* defined(_WIN32) */ 2736 | + 2737 | +/* wasi */ 2738 | +#if defined(__wasi__) 2739 | +#include 2740 | +#endif 2741 | + 2742 | +#if defined(__linux__) 2743 | +/* Linux */ 2744 | +// We would need to include , but not every target has access 2745 | +// to the linux headers. We only need RNDGETENTCNT, so we instead inline it. 2746 | +// RNDGETENTCNT is originally defined in `include/uapi/linux/random.h` in the 2747 | +// linux repo. 2748 | +# define RNDGETENTCNT 0x80045200 2749 | + 2750 | +# include 2751 | +# include 2752 | +# include 2753 | +# include 2754 | +# include 2755 | +# include 2756 | +# include 2757 | +# if defined(__linux__) && defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC_MINOR__ > 24)) 2758 | +# define USE_GLIBC 2759 | +# include 2760 | +# endif /* defined(__linux__) && defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC_MINOR__ > 24)) */ 2761 | +# include 2762 | +# include 2763 | +# include 2764 | +# include 2765 | + 2766 | +// We need SSIZE_MAX as the maximum read len from /dev/urandom 2767 | +# if !defined(SSIZE_MAX) 2768 | +# define SSIZE_MAX (SIZE_MAX / 2 - 1) 2769 | +# endif /* defined(SSIZE_MAX) */ 2770 | + 2771 | +#endif /* defined(__linux__) */ 2772 | + 2773 | + 2774 | +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) 2775 | +/* Dragonfly, FreeBSD, NetBSD, OpenBSD (has arc4random) */ 2776 | +# include 2777 | +# if defined(BSD) 2778 | +# include 2779 | +# endif 2780 | +#endif 2781 | + 2782 | +#if defined(__EMSCRIPTEN__) 2783 | +# include 2784 | +# include 2785 | +# include 2786 | +# include 2787 | +#endif /* defined(__EMSCRIPTEN__) */ 2788 | + 2789 | + 2790 | +#if defined(_WIN32) 2791 | +static int randombytes_win32_randombytes(void *buf, const size_t n) { 2792 | + HCRYPTPROV ctx; 2793 | + BOOL tmp; 2794 | + 2795 | + tmp = CryptAcquireContext(&ctx, NULL, NULL, PROV_RSA_FULL, 2796 | + CRYPT_VERIFYCONTEXT); 2797 | + if (tmp == FALSE) { 2798 | + return -1; 2799 | + } 2800 | + 2801 | + tmp = CryptGenRandom(ctx, (unsigned long)n, (BYTE *) buf); 2802 | + if (tmp == FALSE) { 2803 | + return -1; 2804 | + } 2805 | + 2806 | + tmp = CryptReleaseContext(ctx, 0); 2807 | + if (tmp == FALSE) { 2808 | + return -1; 2809 | + } 2810 | + 2811 | + return 0; 2812 | +} 2813 | +#endif /* defined(_WIN32) */ 2814 | + 2815 | +#if defined(__wasi__) 2816 | +static int randombytes_wasi_randombytes(void *buf, size_t n) { 2817 | + arc4random_buf(buf, n); 2818 | + return 0; 2819 | +} 2820 | +#endif /* defined(__wasi__) */ 2821 | + 2822 | +#if defined(__linux__) && (defined(USE_GLIBC) || defined(SYS_getrandom)) 2823 | +# if defined(USE_GLIBC) 2824 | +// getrandom is declared in glibc. 2825 | +# elif defined(SYS_getrandom) 2826 | +static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { 2827 | + return syscall(SYS_getrandom, buf, buflen, flags); 2828 | +} 2829 | +# endif 2830 | + 2831 | +static int randombytes_linux_randombytes_getrandom(void *buf, size_t n) { 2832 | + /* I have thought about using a separate PRF, seeded by getrandom, but 2833 | + * it turns out that the performance of getrandom is good enough 2834 | + * (250 MB/s on my laptop). 2835 | + */ 2836 | + size_t offset = 0, chunk; 2837 | + int ret; 2838 | + while (n > 0) { 2839 | + /* getrandom does not allow chunks larger than 33554431 */ 2840 | + chunk = n <= 33554431 ? n : 33554431; 2841 | + do { 2842 | + ret = getrandom((char *)buf + offset, chunk, 0); 2843 | + } while (ret == -1 && errno == EINTR); 2844 | + if (ret < 0) { 2845 | + return ret; 2846 | + } 2847 | + offset += ret; 2848 | + n -= ret; 2849 | + } 2850 | + assert(n == 0); 2851 | + return 0; 2852 | +} 2853 | +#endif // defined(__linux__) && (defined(USE_GLIBC) || defined(SYS_getrandom)) 2854 | + 2855 | + 2856 | +#if defined(__linux__) && !defined(SYS_getrandom) 2857 | +static int randombytes_linux_read_entropy_ioctl(int device, int *entropy) { 2858 | + return ioctl(device, RNDGETENTCNT, entropy); 2859 | +} 2860 | + 2861 | +static int randombytes_linux_read_entropy_proc(FILE *stream, int *entropy) { 2862 | + int retcode; 2863 | + do { 2864 | + rewind(stream); 2865 | + retcode = fscanf(stream, "%d", entropy); 2866 | + } while (retcode != 1 && errno == EINTR); 2867 | + if (retcode != 1) { 2868 | + return -1; 2869 | + } 2870 | + return 0; 2871 | +} 2872 | + 2873 | +static int randombytes_linux_wait_for_entropy(int device) { 2874 | + /* We will block on /dev/random, because any increase in the OS' entropy 2875 | + * level will unblock the request. I use poll here (as does libsodium), 2876 | + * because we don't *actually* want to read from the device. */ 2877 | + enum { IOCTL, PROC } strategy = IOCTL; 2878 | + const int bits = 128; 2879 | + struct pollfd pfd; 2880 | + int fd; 2881 | + FILE *proc_file; 2882 | + int retcode, retcode_error = 0; // Used as return codes throughout this function 2883 | + int entropy = 0; 2884 | + 2885 | + /* If the device has enough entropy already, we will want to return early */ 2886 | + retcode = randombytes_linux_read_entropy_ioctl(device, &entropy); 2887 | + // printf("errno: %d (%s)\n", errno, strerror(errno)); 2888 | + if (retcode != 0 && (errno == ENOTTY || errno == ENOSYS)) { 2889 | + // The ioctl call on /dev/urandom has failed due to a 2890 | + // - ENOTTY (unsupported action), or 2891 | + // - ENOSYS (invalid ioctl; this happens on MIPS, see #22). 2892 | + // 2893 | + // We will fall back to reading from 2894 | + // `/proc/sys/kernel/random/entropy_avail`. This less ideal, 2895 | + // because it allocates a file descriptor, and it may not work 2896 | + // in a chroot. But at this point it seems we have no better 2897 | + // options left. 2898 | + strategy = PROC; 2899 | + // Open the entropy count file 2900 | + proc_file = fopen("/proc/sys/kernel/random/entropy_avail", "r"); 2901 | + } else if (retcode != 0) { 2902 | + // Unrecoverable ioctl error 2903 | + return -1; 2904 | + } 2905 | + if (entropy >= bits) { 2906 | + return 0; 2907 | + } 2908 | + 2909 | + do { 2910 | + fd = open("/dev/random", O_RDONLY); 2911 | + } while (fd == -1 && errno == EINTR); /* EAGAIN will not occur */ 2912 | + if (fd == -1) { 2913 | + /* Unrecoverable IO error */ 2914 | + return -1; 2915 | + } 2916 | + 2917 | + pfd.fd = fd; 2918 | + pfd.events = POLLIN; 2919 | + for (;;) { 2920 | + retcode = poll(&pfd, 1, -1); 2921 | + if (retcode == -1 && (errno == EINTR || errno == EAGAIN)) { 2922 | + continue; 2923 | + } else if (retcode == 1) { 2924 | + if (strategy == IOCTL) { 2925 | + retcode = randombytes_linux_read_entropy_ioctl(device, &entropy); 2926 | + } else if (strategy == PROC) { 2927 | + retcode = randombytes_linux_read_entropy_proc(proc_file, &entropy); 2928 | + } else { 2929 | + return -1; // Unreachable 2930 | + } 2931 | + 2932 | + if (retcode != 0) { 2933 | + // Unrecoverable I/O error 2934 | + retcode_error = retcode; 2935 | + break; 2936 | + } 2937 | + if (entropy >= bits) { 2938 | + break; 2939 | + } 2940 | + } else { 2941 | + // Unreachable: poll() should only return -1 or 1 2942 | + retcode_error = -1; 2943 | + break; 2944 | + } 2945 | + } 2946 | + do { 2947 | + retcode = close(fd); 2948 | + } while (retcode == -1 && errno == EINTR); 2949 | + if (strategy == PROC) { 2950 | + do { 2951 | + retcode = fclose(proc_file); 2952 | + } while (retcode == -1 && errno == EINTR); 2953 | + } 2954 | + if (retcode_error != 0) { 2955 | + return retcode_error; 2956 | + } 2957 | + return retcode; 2958 | +} 2959 | + 2960 | + 2961 | +static int randombytes_linux_randombytes_urandom(void *buf, size_t n) { 2962 | + int fd; 2963 | + size_t offset = 0, count; 2964 | + ssize_t tmp; 2965 | + do { 2966 | + fd = open("/dev/urandom", O_RDONLY); 2967 | + } while (fd == -1 && errno == EINTR); 2968 | + if (fd == -1) { 2969 | + return -1; 2970 | + } 2971 | + if (randombytes_linux_wait_for_entropy(fd) == -1) { 2972 | + return -1; 2973 | + } 2974 | + 2975 | + while (n > 0) { 2976 | + count = n <= SSIZE_MAX ? n : SSIZE_MAX; 2977 | + tmp = read(fd, (char *)buf + offset, count); 2978 | + if (tmp == -1 && (errno == EAGAIN || errno == EINTR)) { 2979 | + continue; 2980 | + } 2981 | + if (tmp == -1) { 2982 | + return -1; /* Unrecoverable IO error */ 2983 | + } 2984 | + offset += tmp; 2985 | + n -= tmp; 2986 | + } 2987 | + close(fd); 2988 | + assert(n == 0); 2989 | + return 0; 2990 | +} 2991 | +#endif /* defined(__linux__) && !defined(SYS_getrandom) */ 2992 | + 2993 | + 2994 | +#if defined(BSD) 2995 | +static int randombytes_bsd_randombytes(void *buf, size_t n) { 2996 | + arc4random_buf(buf, n); 2997 | + return 0; 2998 | +} 2999 | +#endif /* defined(BSD) */ 3000 | + 3001 | + 3002 | +#if defined(__EMSCRIPTEN__) 3003 | +static int randombytes_js_randombytes_nodejs(void *buf, size_t n) { 3004 | + const int ret = EM_ASM_INT({ 3005 | + var crypto; 3006 | + try { 3007 | + crypto = require('crypto'); 3008 | + } catch (error) { 3009 | + return -2; 3010 | + } 3011 | + try { 3012 | + writeArrayToMemory(crypto.randomBytes($1), $0); 3013 | + return 0; 3014 | + } catch (error) { 3015 | + return -1; 3016 | + } 3017 | + }, buf, n); 3018 | + switch (ret) { 3019 | + case 0: 3020 | + return 0; 3021 | + case -1: 3022 | + errno = EINVAL; 3023 | + return -1; 3024 | + case -2: 3025 | + errno = ENOSYS; 3026 | + return -1; 3027 | + } 3028 | + assert(false); // Unreachable 3029 | +} 3030 | +#endif /* defined(__EMSCRIPTEN__) */ 3031 | + 3032 | + 3033 | +int randombytes(uint8_t *output, size_t n) { 3034 | + void *buf = (void *)output; 3035 | + #if defined(__EMSCRIPTEN__) 3036 | + return randombytes_js_randombytes_nodejs(buf, n); 3037 | + #elif defined(__linux__) 3038 | + # if defined(USE_GLIBC) 3039 | + /* Use getrandom system call */ 3040 | + return randombytes_linux_randombytes_getrandom(buf, n); 3041 | + # elif defined(SYS_getrandom) 3042 | + /* Use getrandom system call */ 3043 | + return randombytes_linux_randombytes_getrandom(buf, n); 3044 | + # else 3045 | + /* When we have enough entropy, we can read from /dev/urandom */ 3046 | + return randombytes_linux_randombytes_urandom(buf, n); 3047 | + # endif 3048 | + #elif defined(BSD) 3049 | + /* Use arc4random system call */ 3050 | + return randombytes_bsd_randombytes(buf, n); 3051 | + #elif defined(_WIN32) 3052 | + /* Use windows API */ 3053 | + return randombytes_win32_randombytes(buf, n); 3054 | + #elif defined(__wasi__) 3055 | + /* Use WASI */ 3056 | + return randombytes_wasi_randombytes(buf, n); 3057 | + #else 3058 | +# error "randombytes(...) is not supported on this platform" 3059 | + #endif 3060 | +} 3061 | diff --git a/lib/freebl/kyber512/randombytes.h b/lib/freebl/kyber512/randombytes.h 3062 | new file mode 100644 3063 | index 000000000..aa53c231a 3064 | --- /dev/null 3065 | +++ b/lib/freebl/kyber512/randombytes.h 3066 | @@ -0,0 +1,28 @@ 3067 | +#ifndef PQCLEAN_RANDOMBYTES_H 3068 | +#define PQCLEAN_RANDOMBYTES_H 3069 | + 3070 | +#ifdef __cplusplus 3071 | +extern "C" { 3072 | +#endif 3073 | + 3074 | +#include 3075 | + 3076 | +#ifdef _WIN32 3077 | +/* Load size_t on windows */ 3078 | +#include 3079 | +#else 3080 | +#include 3081 | +#endif /* _WIN32 */ 3082 | + 3083 | + 3084 | +/* 3085 | + * Write `n` bytes of high quality random bytes to `buf` 3086 | + */ 3087 | +#define randombytes PQCLEAN_randombytes 3088 | +int randombytes(uint8_t *output, size_t n); 3089 | + 3090 | +#ifdef __cplusplus 3091 | +} 3092 | +#endif 3093 | + 3094 | +#endif /* PQCLEAN_RANDOMBYTES_H */ 3095 | diff --git a/lib/freebl/kyber512/reduce.c b/lib/freebl/kyber512/reduce.c 3096 | new file mode 100644 3097 | index 000000000..7c1366e1c 3098 | --- /dev/null 3099 | +++ b/lib/freebl/kyber512/reduce.c 3100 | @@ -0,0 +1,41 @@ 3101 | +#include "params.h" 3102 | +#include "reduce.h" 3103 | +#include 3104 | + 3105 | +/************************************************* 3106 | +* Name: PQCLEAN_KYBER512_CLEAN_montgomery_reduce 3107 | +* 3108 | +* Description: Montgomery reduction; given a 32-bit integer a, computes 3109 | +* 16-bit integer congruent to a * R^-1 mod q, where R=2^16 3110 | +* 3111 | +* Arguments: - int32_t a: input integer to be reduced; 3112 | +* has to be in {-q2^15,...,q2^15-1} 3113 | +* 3114 | +* Returns: integer in {-q+1,...,q-1} congruent to a * R^-1 modulo q. 3115 | +**************************************************/ 3116 | +int16_t PQCLEAN_KYBER512_CLEAN_montgomery_reduce(int32_t a) { 3117 | + int16_t t; 3118 | + 3119 | + t = (int16_t)a * QINV; 3120 | + t = (a - (int32_t)t * KYBER_Q) >> 16; 3121 | + return t; 3122 | +} 3123 | + 3124 | +/************************************************* 3125 | +* Name: PQCLEAN_KYBER512_CLEAN_barrett_reduce 3126 | +* 3127 | +* Description: Barrett reduction; given a 16-bit integer a, computes 3128 | +* centered representative congruent to a mod q in {-(q-1)/2,...,(q-1)/2} 3129 | +* 3130 | +* Arguments: - int16_t a: input integer to be reduced 3131 | +* 3132 | +* Returns: integer in {-(q-1)/2,...,(q-1)/2} congruent to a modulo q. 3133 | +**************************************************/ 3134 | +int16_t PQCLEAN_KYBER512_CLEAN_barrett_reduce(int16_t a) { 3135 | + int16_t t; 3136 | + const int16_t v = ((1 << 26) + KYBER_Q / 2) / KYBER_Q; 3137 | + 3138 | + t = ((int32_t)v * a + (1 << 25)) >> 26; 3139 | + t *= KYBER_Q; 3140 | + return a - t; 3141 | +} 3142 | diff --git a/lib/freebl/kyber512/reduce.h b/lib/freebl/kyber512/reduce.h 3143 | new file mode 100644 3144 | index 000000000..0b5327fa4 3145 | --- /dev/null 3146 | +++ b/lib/freebl/kyber512/reduce.h 3147 | @@ -0,0 +1,13 @@ 3148 | +#ifndef PQCLEAN_KYBER512_CLEAN_REDUCE_H 3149 | +#define PQCLEAN_KYBER512_CLEAN_REDUCE_H 3150 | +#include "params.h" 3151 | +#include 3152 | + 3153 | +#define MONT (-1044) // 2^16 mod q 3154 | +#define QINV (-3327) // q^-1 mod 2^16 3155 | + 3156 | +int16_t PQCLEAN_KYBER512_CLEAN_montgomery_reduce(int32_t a); 3157 | + 3158 | +int16_t PQCLEAN_KYBER512_CLEAN_barrett_reduce(int16_t a); 3159 | + 3160 | +#endif 3161 | diff --git a/lib/freebl/kyber512/symmetric-shake.c b/lib/freebl/kyber512/symmetric-shake.c 3162 | new file mode 100644 3163 | index 000000000..28c016689 3164 | --- /dev/null 3165 | +++ b/lib/freebl/kyber512/symmetric-shake.c 3166 | @@ -0,0 +1,49 @@ 3167 | +#include "fips202.h" 3168 | +#include "params.h" 3169 | +#include "symmetric.h" 3170 | +#include 3171 | +#include 3172 | +#include 3173 | + 3174 | +/************************************************* 3175 | +* Name: PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb 3176 | +* 3177 | +* Description: Absorb step of the SHAKE128 specialized for the Kyber context. 3178 | +* 3179 | +* Arguments: - xof_state *state: pointer to (uninitialized) output Keccak state 3180 | +* - const uint8_t *seed: pointer to KYBER_SYMBYTES input to be absorbed into state 3181 | +* - uint8_t i: additional byte of input 3182 | +* - uint8_t j: additional byte of input 3183 | +**************************************************/ 3184 | +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(xof_state *state, 3185 | + const uint8_t seed[KYBER_SYMBYTES], 3186 | + uint8_t x, 3187 | + uint8_t y) { 3188 | + uint8_t extseed[KYBER_SYMBYTES + 2]; 3189 | + 3190 | + memcpy(extseed, seed, KYBER_SYMBYTES); 3191 | + extseed[KYBER_SYMBYTES + 0] = x; 3192 | + extseed[KYBER_SYMBYTES + 1] = y; 3193 | + 3194 | + shake128_absorb(state, extseed, sizeof(extseed)); 3195 | +} 3196 | + 3197 | +/************************************************* 3198 | +* Name: PQCLEAN_KYBER512_CLEAN_kyber_shake256_prf 3199 | +* 3200 | +* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input 3201 | +* and then generates outlen bytes of SHAKE256 output 3202 | +* 3203 | +* Arguments: - uint8_t *out: pointer to output 3204 | +* - size_t outlen: number of requested output bytes 3205 | +* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES) 3206 | +* - uint8_t nonce: single-byte nonce (public PRF input) 3207 | +**************************************************/ 3208 | +void PQCLEAN_KYBER512_CLEAN_kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce) { 3209 | + uint8_t extkey[KYBER_SYMBYTES + 1]; 3210 | + 3211 | + memcpy(extkey, key, KYBER_SYMBYTES); 3212 | + extkey[KYBER_SYMBYTES] = nonce; 3213 | + 3214 | + shake256(out, outlen, extkey, sizeof(extkey)); 3215 | +} 3216 | diff --git a/lib/freebl/kyber512/symmetric.h b/lib/freebl/kyber512/symmetric.h 3217 | new file mode 100644 3218 | index 000000000..7b9e78ad4 3219 | --- /dev/null 3220 | +++ b/lib/freebl/kyber512/symmetric.h 3221 | @@ -0,0 +1,30 @@ 3222 | +#ifndef PQCLEAN_KYBER512_CLEAN_SYMMETRIC_H 3223 | +#define PQCLEAN_KYBER512_CLEAN_SYMMETRIC_H 3224 | +#include "fips202.h" 3225 | +#include "params.h" 3226 | +#include 3227 | +#include 3228 | + 3229 | + 3230 | + 3231 | +typedef shake128ctx xof_state; 3232 | + 3233 | +void PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(xof_state *s, 3234 | + const uint8_t seed[KYBER_SYMBYTES], 3235 | + uint8_t x, 3236 | + uint8_t y); 3237 | + 3238 | +void PQCLEAN_KYBER512_CLEAN_kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce); 3239 | + 3240 | +#define XOF_BLOCKBYTES SHAKE128_RATE 3241 | + 3242 | +#define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) 3243 | +#define hash_g(OUT, IN, INBYTES) sha3_512(OUT, IN, INBYTES) 3244 | +#define xof_absorb(STATE, SEED, X, Y) PQCLEAN_KYBER512_CLEAN_kyber_shake128_absorb(STATE, SEED, X, Y) 3245 | +#define xof_squeezeblocks(OUT, OUTBLOCKS, STATE) shake128_squeezeblocks(OUT, OUTBLOCKS, STATE) 3246 | +#define xof_ctx_release(STATE) shake128_ctx_release(STATE) 3247 | +#define prf(OUT, OUTBYTES, KEY, NONCE) PQCLEAN_KYBER512_CLEAN_kyber_shake256_prf(OUT, OUTBYTES, KEY, NONCE) 3248 | +#define kdf(OUT, IN, INBYTES) shake256(OUT, KYBER_SSBYTES, IN, INBYTES) 3249 | + 3250 | + 3251 | +#endif /* SYMMETRIC_H */ 3252 | diff --git a/lib/freebl/kyber512/verify.c b/lib/freebl/kyber512/verify.c 3253 | new file mode 100644 3254 | index 000000000..772293f03 3255 | --- /dev/null 3256 | +++ b/lib/freebl/kyber512/verify.c 3257 | @@ -0,0 +1,47 @@ 3258 | +#include "verify.h" 3259 | +#include 3260 | +#include 3261 | + 3262 | +/************************************************* 3263 | +* Name: PQCLEAN_KYBER512_CLEAN_verify 3264 | +* 3265 | +* Description: Compare two arrays for equality in constant time. 3266 | +* 3267 | +* Arguments: const uint8_t *a: pointer to first byte array 3268 | +* const uint8_t *b: pointer to second byte array 3269 | +* size_t len: length of the byte arrays 3270 | +* 3271 | +* Returns 0 if the byte arrays are equal, 1 otherwise 3272 | +**************************************************/ 3273 | +int PQCLEAN_KYBER512_CLEAN_verify(const uint8_t *a, const uint8_t *b, size_t len) { 3274 | + size_t i; 3275 | + uint8_t r = 0; 3276 | + 3277 | + for (i = 0; i < len; i++) { 3278 | + r |= a[i] ^ b[i]; 3279 | + } 3280 | + 3281 | + return (-(uint64_t)r) >> 63; 3282 | +} 3283 | + 3284 | +/************************************************* 3285 | +* Name: PQCLEAN_KYBER512_CLEAN_cmov 3286 | +* 3287 | +* Description: Copy len bytes from x to r if b is 1; 3288 | +* don't modify x if b is 0. Requires b to be in {0,1}; 3289 | +* assumes two's complement representation of negative integers. 3290 | +* Runs in constant time. 3291 | +* 3292 | +* Arguments: uint8_t *r: pointer to output byte array 3293 | +* const uint8_t *x: pointer to input byte array 3294 | +* size_t len: Amount of bytes to be copied 3295 | +* uint8_t b: Condition bit; has to be in {0,1} 3296 | +**************************************************/ 3297 | +void PQCLEAN_KYBER512_CLEAN_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) { 3298 | + size_t i; 3299 | + 3300 | + b = -b; 3301 | + for (i = 0; i < len; i++) { 3302 | + r[i] ^= b & (r[i] ^ x[i]); 3303 | + } 3304 | +} 3305 | diff --git a/lib/freebl/kyber512/verify.h b/lib/freebl/kyber512/verify.h 3306 | new file mode 100644 3307 | index 000000000..47c5579a6 3308 | --- /dev/null 3309 | +++ b/lib/freebl/kyber512/verify.h 3310 | @@ -0,0 +1,11 @@ 3311 | +#ifndef PQCLEAN_KYBER512_CLEAN_VERIFY_H 3312 | +#define PQCLEAN_KYBER512_CLEAN_VERIFY_H 3313 | +#include "params.h" 3314 | +#include 3315 | +#include 3316 | + 3317 | +int PQCLEAN_KYBER512_CLEAN_verify(const uint8_t *a, const uint8_t *b, size_t len); 3318 | + 3319 | +void PQCLEAN_KYBER512_CLEAN_cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b); 3320 | + 3321 | +#endif 3322 | diff --git a/lib/freebl/ldvector.c b/lib/freebl/ldvector.c 3323 | index ac3b862b5..d80e5b58e 100644 3324 | --- a/lib/freebl/ldvector.c 3325 | +++ b/lib/freebl/ldvector.c 3326 | @@ -376,9 +376,12 @@ static const struct FREEBLVectorStr vector = 3327 | /* End of version 3.024 */ 3328 | ChaCha20_InitContext, 3329 | ChaCha20_CreateContext, 3330 | - ChaCha20_DestroyContext 3331 | + ChaCha20_DestroyContext, 3332 | 3333 | /* End of version 3.025 */ 3334 | + X25519Kyber512Draft00_Generate, 3335 | + X25519Kyber512Draft00_Encapsulate, 3336 | + X25519Kyber512Draft00_Decapsulate 3337 | }; 3338 | 3339 | const FREEBLVector* 3340 | diff --git a/lib/freebl/loader.c b/lib/freebl/loader.c 3341 | index 692a8831b..2291974bc 100644 3342 | --- a/lib/freebl/loader.c 3343 | +++ b/lib/freebl/loader.c 3344 | @@ -2446,3 +2446,27 @@ CMAC_Destroy(CMACContext *ctx, PRBool free_it) 3345 | return; 3346 | (vector->p_CMAC_Destroy)(ctx, free_it); 3347 | } 3348 | + 3349 | +SECStatus 3350 | +X25519Kyber512Draft00_Generate(SECItem **publicKey, SECItem **secretKey) 3351 | +{ 3352 | + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) 3353 | + return SECFailure; 3354 | + return (vector->p_X25519Kyber512Draft00_Generate)(publicKey, secretKey); 3355 | +} 3356 | + 3357 | +SECStatus 3358 | +X25519Kyber512Draft00_Encapsulate(SECItem **ciphertext, SECItem **sharedSecret, SECItem *publicKey) 3359 | +{ 3360 | + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) 3361 | + return SECFailure; 3362 | + return (vector->p_X25519Kyber512Draft00_Encapsulate)(ciphertext, sharedSecret, publicKey); 3363 | +} 3364 | + 3365 | +SECStatus 3366 | +X25519Kyber512Draft00_Decapsulate(SECItem **sharedSecret, SECItem *ciphertext, SECItem *secretKey) 3367 | +{ 3368 | + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) 3369 | + return SECFailure; 3370 | + return (vector->p_X25519Kyber512Draft00_Decapsulate)(sharedSecret, ciphertext, secretKey); 3371 | +} 3372 | diff --git a/lib/freebl/loader.h b/lib/freebl/loader.h 3373 | index eb3046d27..74ce37318 100644 3374 | --- a/lib/freebl/loader.h 3375 | +++ b/lib/freebl/loader.h 3376 | @@ -10,7 +10,7 @@ 3377 | 3378 | #include "blapi.h" 3379 | 3380 | -#define FREEBL_VERSION 0x0325 3381 | +#define FREEBL_VERSION 0x0326 3382 | 3383 | struct FREEBLVectorStr { 3384 | 3385 | @@ -834,6 +834,9 @@ struct FREEBLVectorStr { 3386 | 3387 | /* Add new function pointers at the end of this struct and bump 3388 | * FREEBL_VERSION at the beginning of this file. */ 3389 | + SECStatus (*p_X25519Kyber512Draft00_Generate)(SECItem **publicKey, SECItem **secretKey); 3390 | + SECStatus (*p_X25519Kyber512Draft00_Encapsulate)(SECItem **ciphertext, SECItem **sharedSecret, SECItem *publicKey); 3391 | + SECStatus (*p_X25519Kyber512Draft00_Decapsulate)(SECItem **sharedSecret, SECItem *ciphertext, SECItem *privateKey); 3392 | }; 3393 | 3394 | typedef struct FREEBLVectorStr FREEBLVector; 3395 | diff --git a/lib/freebl/manifest.mn b/lib/freebl/manifest.mn 3396 | index b6c5fb358..518aa72a5 100644 3397 | --- a/lib/freebl/manifest.mn 3398 | +++ b/lib/freebl/manifest.mn 3399 | @@ -151,6 +151,7 @@ CSRCS = \ 3400 | tlsprfalg.c \ 3401 | jpake.c \ 3402 | secmpi.c \ 3403 | + x25519Kyber512.c \ 3404 | $(MPI_SRCS) \ 3405 | $(MPCPU_SRCS) \ 3406 | $(ECL_SRCS) \ 3407 | diff --git a/lib/freebl/x25519Kyber512.c b/lib/freebl/x25519Kyber512.c 3408 | new file mode 100644 3409 | index 000000000..974598f59 3410 | --- /dev/null 3411 | +++ b/lib/freebl/x25519Kyber512.c 3412 | @@ -0,0 +1,156 @@ 3413 | +/* This Source Code Form is subject to the terms of the Mozilla Public 3414 | + * License, v. 2.0. If a copy of the MPL was not distributed with this 3415 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 3416 | + 3417 | +#ifdef FREEBL_NO_DEPEND 3418 | +#include "stubs.h" 3419 | +#endif 3420 | + 3421 | +#include "blapi.h" 3422 | +#include "secerr.h" 3423 | +#include "secitem.h" 3424 | +#include "ecl-priv.h" 3425 | +#include "ecl-curve.h" 3426 | + 3427 | +#include "kyber512/api.h" 3428 | + 3429 | +#define CHECK_OK(func) \ 3430 | + if (func == NULL) \ 3431 | + goto cleanup 3432 | +#define CHECK_SEC_OK(func) \ 3433 | + if (SECSuccess != (rv = func)) \ 3434 | + return SECFailure 3435 | + 3436 | +// TODO(goutam): Generate the classical key 3437 | +// Classical first, then PQ 3438 | + 3439 | +static SECStatus 3440 | +gf_populate_params_bytes(ECCurveName name, ECFieldType field_type, ECParams *params) 3441 | +{ 3442 | + SECStatus rv = SECFailure; 3443 | + const ECCurveBytes *curveParams; 3444 | + 3445 | + if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve)) 3446 | + goto cleanup; 3447 | + params->name = name; 3448 | + curveParams = ecCurve_map[params->name]; 3449 | + CHECK_OK(curveParams); 3450 | + params->fieldID.size = curveParams->size; 3451 | + params->fieldID.type = field_type; 3452 | + if (field_type != ec_field_GFp && field_type != ec_field_plain) { 3453 | + return SECFailure; 3454 | + } 3455 | + params->fieldID.u.prime.len = curveParams->scalarSize; 3456 | + params->fieldID.u.prime.data = (unsigned char *)curveParams->irr; 3457 | + params->curve.a.len = curveParams->scalarSize; 3458 | + params->curve.a.data = (unsigned char *)curveParams->curvea; 3459 | + params->curve.b.len = curveParams->scalarSize; 3460 | + params->curve.b.data = (unsigned char *)curveParams->curveb; 3461 | + params->base.len = curveParams->pointSize; 3462 | + params->base.data = (unsigned char *)curveParams->base; 3463 | + params->order.len = curveParams->scalarSize; 3464 | + params->order.data = (unsigned char *)curveParams->order; 3465 | + params->cofactor = curveParams->cofactor; 3466 | + 3467 | + rv = SECSuccess; 3468 | + 3469 | +cleanup: 3470 | + return rv; 3471 | +} 3472 | + 3473 | +SECStatus 3474 | +X25519Kyber512Draft00_Generate(SECItem **publicKey, SECItem **secretKey) 3475 | +{ 3476 | + SECStatus rv = SECFailure; 3477 | + 3478 | + ECParams *params; 3479 | + PLArenaPool *arena; 3480 | + if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE))) 3481 | + return SECFailure; 3482 | + params = (ECParams *)PORT_ArenaZAlloc(arena, sizeof(ECParams)); 3483 | + if (!params) { 3484 | + PORT_FreeArena(arena, PR_TRUE); 3485 | + return SECFailure; 3486 | + } 3487 | + 3488 | + CHECK_SEC_OK(gf_populate_params_bytes(ECCurve25519, ec_field_plain, params)); 3489 | + 3490 | + ECPrivateKey *x25519Key = NULL; 3491 | + CHECK_SEC_OK(EC_NewKey(params, &x25519Key)); 3492 | + 3493 | + *publicKey = SECITEM_AllocItem(NULL, *publicKey, x25519Key->publicValue.len + PQCLEAN_KYBER512_CLEAN_CRYPTO_PUBLICKEYBYTES); 3494 | + if (*publicKey == NULL) { 3495 | + PORT_SetError(SEC_ERROR_NO_MEMORY); 3496 | + return SECFailure; 3497 | + } 3498 | + 3499 | + *secretKey = SECITEM_AllocItem(NULL, *secretKey, x25519Key->privateValue.len + PQCLEAN_KYBER512_CLEAN_CRYPTO_SECRETKEYBYTES); 3500 | + if (*secretKey == NULL) { 3501 | + PORT_SetError(SEC_ERROR_NO_MEMORY); 3502 | + return SECFailure; 3503 | + } 3504 | + 3505 | + /* Write out classical part first */ 3506 | + memcpy((*publicKey)->data, x25519Key->publicValue.data, 32); 3507 | + memcpy((*secretKey)->data, x25519Key->privateValue.data, 32); 3508 | + 3509 | + /* Generate PQ key */ 3510 | + int rc = PQCLEAN_KYBER512_CLEAN_crypto_kem_keypair((*publicKey)->data + x25519Key->publicValue.len, 3511 | + (*secretKey)->data + x25519Key->privateValue.len); 3512 | + if (rc != 0) { 3513 | + return SECFailure; 3514 | + } 3515 | + 3516 | + return SECSuccess; 3517 | +} 3518 | + 3519 | +SECStatus 3520 | +X25519Kyber512Draft00_Encapsulate(SECItem **ciphertext, SECItem **sharedSecret, SECItem *publicKey) 3521 | +{ 3522 | + SECStatus rv = SECFailure; 3523 | + ECParams params; 3524 | + CHECK_SEC_OK(gf_populate_params_bytes(ECCurve25519, ec_field_plain, ¶ms)); 3525 | + ECPrivateKey *x25519Key; 3526 | + CHECK_SEC_OK(EC_NewKey(¶ms, &x25519Key)); 3527 | + 3528 | + *ciphertext = SECITEM_AllocItem(NULL, *ciphertext, x25519Key->publicValue.len + PQCLEAN_KYBER512_CLEAN_CRYPTO_CIPHERTEXTBYTES); 3529 | + if (*ciphertext == NULL) { 3530 | + PORT_SetError(SEC_ERROR_NO_MEMORY); 3531 | + return SECFailure; 3532 | + } 3533 | + 3534 | + *sharedSecret = SECITEM_AllocItem(NULL, *sharedSecret, 32 + PQCLEAN_KYBER512_CLEAN_CRYPTO_BYTES); 3535 | + if (*sharedSecret == NULL) { 3536 | + PORT_SetError(SEC_ERROR_NO_MEMORY); 3537 | + return SECFailure; 3538 | + } 3539 | + 3540 | + ec_Curve25519_mul((*sharedSecret)->data, x25519Key->privateValue.data, publicKey->data); 3541 | + 3542 | + memcpy((*ciphertext)->data, x25519Key->publicValue.data, 32); 3543 | + int rc = PQCLEAN_KYBER512_CLEAN_crypto_kem_enc((*ciphertext)->data + x25519Key->publicValue.len, (*sharedSecret)->data + 32, publicKey->data); 3544 | + if (rc != 0) { 3545 | + return SECFailure; 3546 | + } 3547 | + 3548 | + return SECSuccess; 3549 | +} 3550 | + 3551 | +SECStatus 3552 | +X25519Kyber512Draft00_Decapsulate(SECItem **sharedSecret, SECItem *ciphertext, SECItem *secretKey) 3553 | +{ 3554 | + *sharedSecret = SECITEM_AllocItem(NULL, *sharedSecret, 32 + PQCLEAN_KYBER512_CLEAN_CRYPTO_BYTES); 3555 | + if (*sharedSecret == NULL) { 3556 | + PORT_SetError(SEC_ERROR_NO_MEMORY); 3557 | + return SECFailure; 3558 | + } 3559 | + ec_Curve25519_mul((*sharedSecret)->data, secretKey->data, ciphertext->data); 3560 | + 3561 | + 3562 | + int rc = PQCLEAN_KYBER512_CLEAN_crypto_kem_dec((*sharedSecret)->data + 32, ciphertext->data + 32, secretKey->data + 32); 3563 | + if (rc != 0) { 3564 | + return SECFailure; 3565 | + } 3566 | + 3567 | + return SECSuccess; 3568 | +} 3569 | diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c 3570 | index 310d65662..bf271b64c 100644 3571 | --- a/lib/pk11wrap/pk11akey.c 3572 | +++ b/lib/pk11wrap/pk11akey.c 3573 | @@ -44,6 +44,13 @@ pk11_MakeIDFromPublicKey(SECKEYPublicKey *pubKey) 3574 | case ecKey: 3575 | pubKeyIndex = &pubKey->u.ec.publicValue; 3576 | break; 3577 | + case x25519Kyber512Draft00Key: 3578 | + { 3579 | + unsigned char buf[1] = {0}; 3580 | + pubKeyIndex = SECITEM_AllocItem(NULL, pubKeyIndex, 1); 3581 | + pubKeyIndex->data = buf; 3582 | + break; 3583 | + } 3584 | default: 3585 | return NULL; 3586 | } 3587 | @@ -619,6 +626,9 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType, CK_OBJECT_HANDLE id) 3588 | case CKK_EC: 3589 | keyType = ecKey; 3590 | break; 3591 | + case CKK_NSS_X25519KYBER512DRAFT00: 3592 | + keyType = x25519Kyber512Draft00Key; 3593 | + break; 3594 | default: 3595 | PORT_SetError(SEC_ERROR_BAD_KEY); 3596 | return NULL; 3597 | @@ -773,6 +783,9 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType, CK_OBJECT_HANDLE id) 3598 | &pubKey->u.ec.DEREncodedParams, value, 3599 | &pubKey->u.ec.publicValue); 3600 | break; 3601 | + case x25519Kyber512Draft00Key: 3602 | + crv = CKR_OK; 3603 | + break; 3604 | case fortezzaKey: 3605 | case nullKey: 3606 | default: 3607 | @@ -826,6 +839,9 @@ PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, 3608 | case CKK_EC: 3609 | keyType = ecKey; 3610 | break; 3611 | + case CKK_NSS_X25519KYBER512DRAFT00: 3612 | + keyType = x25519Kyber512Draft00Key; 3613 | + break; 3614 | default: 3615 | break; 3616 | } 3617 | @@ -1208,6 +1224,15 @@ PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 3618 | { CKA_MODIFIABLE, NULL, 0 }, 3619 | }; 3620 | SECKEYECParams *ecParams; 3621 | + CK_ATTRIBUTE x25519Kyber512Draft00PubTemplate[] = { 3622 | + { CKA_TOKEN, NULL, 0 }, 3623 | + { CKA_DERIVE, NULL, 0 }, 3624 | + { CKA_WRAP, NULL, 0 }, 3625 | + { CKA_VERIFY, NULL, 0 }, 3626 | + { CKA_VERIFY_RECOVER, NULL, 0 }, 3627 | + { CKA_ENCRYPT, NULL, 0 }, 3628 | + { CKA_MODIFIABLE, NULL, 0 }, 3629 | + }; 3630 | 3631 | /*CK_ULONG key_size = 0;*/ 3632 | CK_ATTRIBUTE *pubTemplate; 3633 | @@ -1244,7 +1269,7 @@ PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 3634 | return NULL; 3635 | } 3636 | 3637 | - if (!param) { 3638 | + if (!param && type != CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN) { 3639 | PORT_SetError(SEC_ERROR_INVALID_ARGS); 3640 | return NULL; 3641 | } 3642 | @@ -1413,6 +1438,12 @@ PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 3643 | test_mech2.mechanism = CKM_ECDSA; 3644 | } 3645 | break; 3646 | + case CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN: 3647 | + test_mech.mechanism = CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN; 3648 | + attrs = x25519Kyber512Draft00PubTemplate; 3649 | + pubTemplate = x25519Kyber512Draft00PubTemplate; 3650 | + keyType = x25519Kyber512Draft00Key; 3651 | + break; 3652 | default: 3653 | PORT_SetError(SEC_ERROR_BAD_KEY); 3654 | return NULL; 3655 | diff --git a/lib/pk11wrap/pk11cert.c b/lib/pk11wrap/pk11cert.c 3656 | index 84d830035..1f7f5839e 100644 3657 | --- a/lib/pk11wrap/pk11cert.c 3658 | +++ b/lib/pk11wrap/pk11cert.c 3659 | @@ -177,6 +177,7 @@ PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert, 3660 | break; 3661 | case keaKey: 3662 | case fortezzaKey: 3663 | + case x25519Kyber512Draft00Key: 3664 | case nullKey: 3665 | /* fall through and return false */ 3666 | break; 3667 | diff --git a/lib/pk11wrap/pk11mech.c b/lib/pk11wrap/pk11mech.c 3668 | index 685f0e934..3ac67a8eb 100644 3669 | --- a/lib/pk11wrap/pk11mech.c 3670 | +++ b/lib/pk11wrap/pk11mech.c 3671 | @@ -425,6 +425,8 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, unsigned long len) 3672 | case CKM_TLS_PRF_GENERAL: 3673 | case CKM_NSS_TLS_PRF_GENERAL_SHA256: 3674 | return CKK_GENERIC_SECRET; 3675 | + case CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN: 3676 | + return CKK_NSS_X25519KYBER512DRAFT00; 3677 | default: 3678 | return pk11_lookup(type)->keyType; 3679 | } 3680 | diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c 3681 | index 66b4ed6a1..9d3d06a5e 100644 3682 | --- a/lib/pk11wrap/pk11skey.c 3683 | +++ b/lib/pk11wrap/pk11skey.c 3684 | @@ -2104,6 +2104,7 @@ PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, 3685 | case rsaKey: 3686 | case rsaPssKey: 3687 | case rsaOaepKey: 3688 | + case x25519Kyber512Draft00Key: 3689 | case nullKey: 3690 | PORT_SetError(SEC_ERROR_BAD_KEY); 3691 | break; 3692 | diff --git a/lib/pk11wrap/pk11slot.c b/lib/pk11wrap/pk11slot.c 3693 | index 1b150888d..48bc103d5 100644 3694 | --- a/lib/pk11wrap/pk11slot.c 3695 | +++ b/lib/pk11wrap/pk11slot.c 3696 | @@ -93,7 +93,8 @@ static PK11SlotList 3697 | pk11_tlsSlotList, 3698 | pk11_randomSlotList, 3699 | pk11_sha256SlotList, 3700 | - pk11_sha512SlotList; /* slots do SHA512 and SHA384 */ 3701 | + pk11_sha512SlotList, /* slots do SHA512 and SHA384 */ 3702 | + pk11_x25519Kyber512Draft00SlotList; 3703 | 3704 | /************************************************************ 3705 | * Generic Slot List and Slot List element manipulations 3706 | @@ -847,6 +848,7 @@ PK11_InitSlotLists(void) 3707 | pk11_InitSlotListStatic(&pk11_randomSlotList); 3708 | pk11_InitSlotListStatic(&pk11_sha256SlotList); 3709 | pk11_InitSlotListStatic(&pk11_sha512SlotList); 3710 | + pk11_InitSlotListStatic(&pk11_x25519Kyber512Draft00SlotList); 3711 | return SECSuccess; 3712 | } 3713 | 3714 | @@ -873,6 +875,7 @@ PK11_DestroySlotLists(void) 3715 | pk11_FreeSlotListStatic(&pk11_randomSlotList); 3716 | pk11_FreeSlotListStatic(&pk11_sha256SlotList); 3717 | pk11_FreeSlotListStatic(&pk11_sha512SlotList); 3718 | + pk11_FreeSlotListStatic(&pk11_x25519Kyber512Draft00SlotList); 3719 | return; 3720 | } 3721 | 3722 | @@ -951,6 +954,8 @@ PK11_GetSlotList(CK_MECHANISM_TYPE type) 3723 | return &pk11_ideaSlotList; 3724 | case CKM_FAKE_RANDOM: 3725 | return &pk11_randomSlotList; 3726 | + case CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN: 3727 | + return &pk11_x25519Kyber512Draft00SlotList; 3728 | } 3729 | return NULL; 3730 | } 3731 | diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c 3732 | index 28d219d8e..fdc615bb2 100644 3733 | --- a/lib/softoken/pkcs11.c 3734 | +++ b/lib/softoken/pkcs11.c 3735 | @@ -606,7 +606,9 @@ static const struct mechanismList mechanisms[] = { 3736 | { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE }, 3737 | { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }, 3738 | { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }, 3739 | - { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE } 3740 | + { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE }, 3741 | + /* --------------------X25519KYBER512DRAFT00 ----------------------- */ 3742 | + { CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN, { 0, 0, CKF_GENERATE }, PR_TRUE }, 3743 | }; 3744 | static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]); 3745 | 3746 | @@ -1048,6 +1050,13 @@ sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object, 3747 | recover = CK_FALSE; 3748 | wrap = CK_FALSE; 3749 | break; 3750 | + case CKK_NSS_X25519KYBER512DRAFT00: 3751 | + derive = CK_TRUE; 3752 | + verify = CK_FALSE; 3753 | + encrypt = CK_FALSE; 3754 | + recover = CK_FALSE; 3755 | + wrap = CK_FALSE; 3756 | + break; 3757 | default: 3758 | return CKR_ATTRIBUTE_VALUE_INVALID; 3759 | } 3760 | @@ -1247,6 +1256,15 @@ sftk_handlePrivateKeyObject(SFTKSession *session, SFTKObject *object, CK_KEY_TYP 3761 | derive = CK_TRUE; 3762 | createObjectInfo = PR_FALSE; 3763 | break; 3764 | + case CKK_NSS_X25519KYBER512DRAFT00: 3765 | + if (!sftk_hasAttribute(object, CKA_VALUE)) { 3766 | + return CKR_TEMPLATE_INCOMPLETE; 3767 | + } 3768 | + encrypt = CK_FALSE; 3769 | + sign = CK_FALSE; 3770 | + recover = CK_FALSE; 3771 | + wrap = CK_FALSE; 3772 | + break; 3773 | default: 3774 | return CKR_ATTRIBUTE_VALUE_INVALID; 3775 | } 3776 | @@ -1930,6 +1948,9 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type, 3777 | crv = CKR_ATTRIBUTE_VALUE_INVALID; 3778 | } 3779 | break; 3780 | + case CKK_NSS_X25519KYBER512DRAFT00: 3781 | + crv = CKR_OK; 3782 | + break; 3783 | default: 3784 | crv = CKR_KEY_TYPE_INCONSISTENT; 3785 | break; 3786 | @@ -2083,7 +2104,8 @@ sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp) 3787 | #endif 3788 | } 3789 | break; 3790 | - 3791 | + case CKK_NSS_X25519KYBER512DRAFT00: 3792 | + break; 3793 | default: 3794 | crv = CKR_KEY_TYPE_INCONSISTENT; 3795 | break; 3796 | diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c 3797 | index a0ef85aca..6bb7486d4 100644 3798 | --- a/lib/softoken/pkcs11c.c 3799 | +++ b/lib/softoken/pkcs11c.c 3800 | @@ -5677,6 +5677,32 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hSession, 3801 | PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE); 3802 | break; 3803 | 3804 | + case CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN: 3805 | + key_type = CKK_NSS_X25519KYBER512DRAFT00; 3806 | + 3807 | + SECItem *pub = NULL; 3808 | + SECItem *priv = NULL; 3809 | + 3810 | + rv = X25519Kyber512Draft00_Generate(&pub, &priv); 3811 | + if (rv != SECSuccess) { 3812 | + crv = sftk_MapCryptError(PORT_GetError()); 3813 | + break; 3814 | + } 3815 | + 3816 | + crv = sftk_AddAttributeType(publicKey, CKA_VALUE, 3817 | + sftk_item_expand(pub)); 3818 | + if (crv != CKR_OK) { 3819 | + break; 3820 | + } 3821 | + 3822 | + crv = sftk_AddAttributeType(privateKey, CKA_VALUE, 3823 | + sftk_item_expand(priv)); 3824 | + if (crv != CKR_OK) { 3825 | + break; 3826 | + } 3827 | + 3828 | + break; 3829 | + 3830 | default: 3831 | crv = CKR_MECHANISM_INVALID; 3832 | } 3833 | @@ -5760,7 +5786,7 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hSession, 3834 | &cktrue, sizeof(CK_BBOOL)); 3835 | } 3836 | 3837 | - if (crv == CKR_OK) { 3838 | + if (crv == CKR_OK && key_type != CKK_NSS_X25519KYBER512DRAFT00) { 3839 | /* Perform FIPS 140-2 pairwise consistency check. */ 3840 | crv = sftk_PairwiseConsistencyCheck(hSession, slot, 3841 | publicKey, privateKey, key_type); 3842 | diff --git a/lib/ssl/manifest.mn b/lib/ssl/manifest.mn 3843 | index fedc42b4e..9d369f814 100644 3844 | --- a/lib/ssl/manifest.mn 3845 | +++ b/lib/ssl/manifest.mn 3846 | @@ -63,6 +63,7 @@ CSRCS = \ 3847 | tls13psk.c \ 3848 | tls13replay.c \ 3849 | tls13subcerts.c \ 3850 | + tls13x25519Kyber512.c \ 3851 | $(NULL) 3852 | 3853 | LIBRARY_NAME = ssl 3854 | diff --git a/lib/ssl/ssl.gyp b/lib/ssl/ssl.gyp 3855 | index 2aa35cc96..5436e0f3e 100644 3856 | --- a/lib/ssl/ssl.gyp 3857 | +++ b/lib/ssl/ssl.gyp 3858 | @@ -52,6 +52,7 @@ 3859 | 'tls13psk.c', 3860 | 'tls13replay.c', 3861 | 'tls13subcerts.c', 3862 | + 'tls13x25519Kyber512.c', 3863 | ], 3864 | 'conditions': [ 3865 | [ 'OS=="win"', { 3866 | diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c 3867 | index ad7480586..8f599edc0 100644 3868 | --- a/lib/ssl/ssl3con.c 3869 | +++ b/lib/ssl/ssl3con.c 3870 | @@ -377,6 +377,7 @@ static const CK_MECHANISM_TYPE kea_alg_defs[] = { 3871 | CKM_ECDH1_DERIVE, /* ssl_kea_ecdh_psk */ 3872 | CKM_DH_PKCS_DERIVE, /* ssl_kea_dh_psk */ 3873 | CKM_INVALID_MECHANISM, /* ssl_kea_tls13_any */ 3874 | + CKM_INVALID_MECHANISM, /* ssl_kea_x25519Kyber512Draft00 */ 3875 | }; 3876 | PR_STATIC_ASSERT(PR_ARRAY_SIZE(kea_alg_defs) == ssl_kea_size); 3877 | 3878 | @@ -735,6 +736,9 @@ ssl_KEAEnabled(const sslSocket *ss, SSLKEAType keaType) 3879 | case ssl_kea_ecdh_psk: 3880 | return ssl_NamedGroupTypeEnabled(ss, ssl_kea_ecdh); 3881 | 3882 | + case ssl_kea_x25519Kyber512Draft00: 3883 | + return ssl_NamedGroupTypeEnabled(ss, ssl_kea_x25519Kyber512Draft00); 3884 | + 3885 | case ssl_kea_tls13_any: 3886 | return PR_TRUE; 3887 | 3888 | diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h 3889 | index 5a9da21a0..33ef448b4 100644 3890 | --- a/lib/ssl/sslimpl.h 3891 | +++ b/lib/ssl/sslimpl.h 3892 | @@ -128,7 +128,7 @@ typedef enum { SSLAppOpRead = 0, 3893 | #define DTLS_RETRANSMIT_FINISHED_MS 30000 3894 | 3895 | /* default number of entries in namedGroupPreferences */ 3896 | -#define SSL_NAMED_GROUP_COUNT 31 3897 | +#define SSL_NAMED_GROUP_COUNT 32 3898 | 3899 | /* The maximum DH and RSA bit-length supported. */ 3900 | #define SSL_MAX_DH_KEY_BITS 8192 3901 | @@ -1027,6 +1027,7 @@ struct sslSocketStr { 3902 | * these on the client side. The server inserts a single value into this 3903 | * list for all versions. */ 3904 | PRCList /**/ ephemeralKeyPairs; 3905 | + SECItem *keyShareToSend; 3906 | 3907 | /* Callbacks */ 3908 | SSLAuthCertificate authCertificate; 3909 | @@ -1980,6 +1981,10 @@ SECStatus SSLExp_SetTls13GreaseEchSize(PRFileDesc *fd, PRUint8 size); 3910 | SECStatus SSLExp_EnableTls13BackendEch(PRFileDesc *fd, PRBool enabled); 3911 | SECStatus SSLExp_CallExtensionWriterOnEchInner(PRFileDesc *fd, PRBool enabled); 3912 | 3913 | +/* X25519Kyber512Draft00 */ 3914 | + 3915 | +SECStatus tls13_GenerateX25519Kyber512Draft00KeyPair(const sslSocket *ss, const sslNamedGroupDef *group, sslEphemeralKeyPair **keyPair); 3916 | + 3917 | SEC_END_PROTOS 3918 | 3919 | #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) 3920 | diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c 3921 | index 6b40be759..915d721b2 100644 3922 | --- a/lib/ssl/sslsock.c 3923 | +++ b/lib/ssl/sslsock.c 3924 | @@ -159,6 +159,7 @@ static const PRUint16 srtpCiphers[] = { 3925 | } 3926 | 3927 | const sslNamedGroupDef ssl_named_groups[] = { 3928 | + { ssl_grp_x25519Kyber512Draft00, 128, ssl_kea_x25519Kyber512Draft00, 0, PR_TRUE }, 3929 | /* Note that 256 for 25519 is a lie, but we only use it for checking bit 3930 | * security and expect 256 bits there (not 255). */ 3931 | { ssl_grp_ec_curve25519, 256, ssl_kea_ecdh, SEC_OID_CURVE25519, PR_TRUE }, 3932 | diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h 3933 | index 59e82e34d..6fac8bc08 100644 3934 | --- a/lib/ssl/sslt.h 3935 | +++ b/lib/ssl/sslt.h 3936 | @@ -83,6 +83,7 @@ typedef enum { 3937 | ssl_kea_ecdh_psk = 5, 3938 | ssl_kea_dh_psk = 6, 3939 | ssl_kea_tls13_any = 7, 3940 | + ssl_kea_x25519Kyber512Draft00 = 8, 3941 | ssl_kea_size /* number of ssl_kea_ algorithms */ 3942 | } SSLKEAType; 3943 | 3944 | @@ -258,7 +259,8 @@ typedef enum { 3945 | ssl_grp_ffdhe_6144 = 259, 3946 | ssl_grp_ffdhe_8192 = 260, 3947 | ssl_grp_none = 65537, /* special value */ 3948 | - ssl_grp_ffdhe_custom = 65538 /* special value */ 3949 | + ssl_grp_ffdhe_custom = 65538, /* special value */ 3950 | + ssl_grp_x25519Kyber512Draft00 = 0xfe30 3951 | } SSLNamedGroup; 3952 | 3953 | typedef struct SSLExtraServerCertDataStr { 3954 | diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c 3955 | index 51dfebff3..df0688e20 100644 3956 | --- a/lib/ssl/tls13con.c 3957 | +++ b/lib/ssl/tls13con.c 3958 | @@ -26,6 +26,7 @@ 3959 | #include "tls13hashstate.h" 3960 | #include "tls13subcerts.h" 3961 | #include "tls13psk.h" 3962 | +#include "blapi.h" 3963 | 3964 | static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch, 3965 | SSLSecretDirection install, 3966 | @@ -389,6 +390,12 @@ tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef, 3967 | return SECFailure; 3968 | } 3969 | break; 3970 | + case ssl_kea_x25519Kyber512Draft00: 3971 | + rv = tls13_GenerateX25519Kyber512Draft00KeyPair(ss, groupDef, keyPair); 3972 | + if (rv != SECSuccess) { 3973 | + return SECFailure; 3974 | + } 3975 | + break; 3976 | default: 3977 | PORT_Assert(0); 3978 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 3979 | @@ -2332,30 +2339,47 @@ tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare) 3980 | 3981 | tls13_SetKeyExchangeType(ss, peerShare->group); 3982 | 3983 | - /* Generate our key */ 3984 | - rv = tls13_AddKeyShare(ss, peerShare->group); 3985 | - if (rv != SECSuccess) { 3986 | - return rv; 3987 | - } 3988 | + if (peerShare->group->name == ssl_grp_x25519Kyber512Draft00) { 3989 | + SECItem *sharedSecret = NULL; 3990 | + ss->keyShareToSend = NULL; 3991 | + rv = X25519Kyber512Draft00_Encapsulate(&ss->keyShareToSend, &sharedSecret, &peerShare->key_exchange); 3992 | + if (rv != SECSuccess) { 3993 | + return rv; 3994 | + } 3995 | 3996 | - /* We should have exactly one key share. */ 3997 | - PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); 3998 | - PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) == 3999 | - PR_NEXT_LINK(&ss->ephemeralKeyPairs)); 4000 | + PK11SlotInfo *slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL); 4001 | + if (!slot) { 4002 | + return SECFailure; 4003 | + } 4004 | + ss->ssl3.hs.dheSecret = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap, CKA_DERIVE, sharedSecret, NULL); 4005 | + if (ss->ssl3.hs.dheSecret == NULL) { 4006 | + return SECFailure; 4007 | + } 4008 | + } else { 4009 | + /* Generate our key */ 4010 | + rv = tls13_AddKeyShare(ss, peerShare->group); 4011 | + if (rv != SECSuccess) { 4012 | + return rv; 4013 | + } 4014 | 4015 | - keyPair = ((sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs)); 4016 | - ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->keys->pubKey); 4017 | + /* We should have exactly one key share. */ 4018 | + PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); 4019 | + PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) == 4020 | + PR_NEXT_LINK(&ss->ephemeralKeyPairs)); 4021 | + 4022 | + keyPair = ((sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs)); 4023 | + ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->keys->pubKey); 4024 | 4025 | + rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys, 4026 | + tls13_GetHash(ss), 4027 | + &ss->ssl3.hs.dheSecret); 4028 | + } 4029 | /* Register the sender */ 4030 | rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_tls13_key_share_xtn, 4031 | tls13_ServerSendKeyShareXtn); 4032 | if (rv != SECSuccess) { 4033 | return SECFailure; /* Error code set already. */ 4034 | } 4035 | - 4036 | - rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys, 4037 | - tls13_GetHash(ss), 4038 | - &ss->ssl3.hs.dheSecret); 4039 | return rv; /* Error code set already. */ 4040 | } 4041 | 4042 | @@ -3120,6 +3144,11 @@ tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group) 4043 | ss->statelessResume ? ssl_kea_dh_psk : ssl_kea_dh; 4044 | ss->sec.keaType = ssl_kea_dh; 4045 | break; 4046 | + case ssl_kea_x25519Kyber512Draft00: 4047 | + // TODO(goutam): Look into resumption 4048 | + ss->ssl3.hs.kea_def_mutable.exchKeyType = ssl_kea_x25519Kyber512Draft00; 4049 | + ss->sec.keaType = ssl_kea_x25519Kyber512Draft00; 4050 | + break; 4051 | default: 4052 | PORT_Assert(0); 4053 | } 4054 | @@ -3159,12 +3188,37 @@ tls13_HandleServerKeyShare(sslSocket *ss) 4055 | } 4056 | 4057 | PORT_Assert(ssl_NamedGroupEnabled(ss, entry->group)); 4058 | + if (entry->group->name == ssl_grp_x25519Kyber512Draft00) { 4059 | + SECItem privateKey; 4060 | + SECItem *sharedSecret = NULL; 4061 | 4062 | - rv = tls13_HandleKeyShare(ss, entry, keyPair->keys, 4063 | - tls13_GetHash(ss), 4064 | - &ss->ssl3.hs.dheSecret); 4065 | - if (rv != SECSuccess) 4066 | - return SECFailure; /* Error code set by caller. */ 4067 | + rv = PK11_ReadRawAttribute(PK11_TypePrivKey, keyPair->keys->privKey, CKA_VALUE, &privateKey); 4068 | + if (rv != SECSuccess) { 4069 | + return rv; 4070 | + } 4071 | + 4072 | + rv = X25519Kyber512Draft00_Decapsulate(&sharedSecret, &entry->key_exchange, &privateKey); 4073 | + if (rv != SECSuccess) { 4074 | + return rv; 4075 | + } 4076 | + 4077 | + PK11SlotInfo *slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL); 4078 | + if (!slot) { 4079 | + rv = SECFailure; 4080 | + return rv; 4081 | + } 4082 | + ss->ssl3.hs.dheSecret = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap, CKA_DERIVE, sharedSecret, NULL); 4083 | + if (ss->ssl3.hs.dheSecret == NULL) { 4084 | + rv = SECFailure; 4085 | + return rv; 4086 | + } 4087 | + } else { 4088 | + rv = tls13_HandleKeyShare(ss, entry, keyPair->keys, 4089 | + tls13_GetHash(ss), 4090 | + &ss->ssl3.hs.dheSecret); 4091 | + if (rv != SECSuccess) 4092 | + return SECFailure; /* Error code set by caller. */ 4093 | + } 4094 | 4095 | tls13_SetKeyExchangeType(ss, entry->group); 4096 | ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->keys->pubKey); 4097 | diff --git a/lib/ssl/tls13exthandle.c b/lib/ssl/tls13exthandle.c 4098 | index 6acdf2473..6f844a64a 100644 4099 | --- a/lib/ssl/tls13exthandle.c 4100 | +++ b/lib/ssl/tls13exthandle.c 4101 | @@ -83,6 +83,8 @@ tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey) 4102 | return 2 + 2 + pubKey->u.ec.publicValue.len; 4103 | case dhKey: 4104 | return 2 + 2 + pubKey->u.dh.prime.len; 4105 | + case x25519Kyber512Draft00Key: 4106 | + return 2 + 2 + 32 + X25519KYBER512DRAFT00_PUBLICKEYBYTES; 4107 | default: 4108 | PORT_Assert(0); 4109 | } 4110 | @@ -111,6 +113,17 @@ tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group, 4111 | case dhKey: 4112 | rv = ssl_AppendPaddedDHKeyShare(buf, pubKey, PR_FALSE); 4113 | break; 4114 | + case x25519Kyber512Draft00Key: 4115 | + { 4116 | + SECItem pubKeyRaw; 4117 | + rv = PK11_ReadRawAttribute(PK11_TypePubKey, pubKey, CKA_VALUE, &pubKeyRaw); 4118 | + if (rv != SECSuccess) 4119 | + return rv; 4120 | + rv = sslBuffer_Append(buf, pubKeyRaw.data, pubKeyRaw.len); 4121 | + if (rv != SECSuccess) 4122 | + return rv; 4123 | + break; 4124 | + } 4125 | default: 4126 | PORT_Assert(0); 4127 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 4128 | @@ -362,17 +375,29 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, 4129 | SECStatus rv; 4130 | sslEphemeralKeyPair *keyPair; 4131 | 4132 | - /* There should be exactly one key share. */ 4133 | - PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); 4134 | - PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) == 4135 | - PR_NEXT_LINK(&ss->ephemeralKeyPairs)); 4136 | + if (ss->sec.keaGroup->keaType == ssl_kea_x25519Kyber512Draft00) { 4137 | + rv = sslBuffer_AppendNumber(buf, ssl_grp_x25519Kyber512Draft00, 2); 4138 | + if (rv != SECSuccess) 4139 | + return SECFailure; 4140 | + rv = sslBuffer_AppendNumber(buf, ss->keyShareToSend->len, 2); 4141 | + if (rv != SECSuccess) 4142 | + return SECFailure; 4143 | + rv = sslBuffer_Append(buf, ss->keyShareToSend->data, ss->keyShareToSend->len); 4144 | + if (rv != SECSuccess) 4145 | + return SECFailure; 4146 | + } else { 4147 | + /* There should be exactly one key share. */ 4148 | + PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); 4149 | + PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) == 4150 | + PR_NEXT_LINK(&ss->ephemeralKeyPairs)); 4151 | 4152 | - keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); 4153 | + keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); 4154 | 4155 | - rv = tls13_EncodeKeyShareEntry(buf, keyPair->group->name, 4156 | - keyPair->keys->pubKey); 4157 | - if (rv != SECSuccess) { 4158 | - return SECFailure; 4159 | + rv = tls13_EncodeKeyShareEntry(buf, keyPair->group->name, 4160 | + keyPair->keys->pubKey); 4161 | + if (rv != SECSuccess) { 4162 | + return SECFailure; 4163 | + } 4164 | } 4165 | 4166 | *added = PR_TRUE; 4167 | diff --git a/lib/ssl/tls13x25519Kyber512.c b/lib/ssl/tls13x25519Kyber512.c 4168 | new file mode 100644 4169 | index 000000000..19835c2bd 4170 | --- /dev/null 4171 | +++ b/lib/ssl/tls13x25519Kyber512.c 4172 | @@ -0,0 +1,47 @@ 4173 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 4174 | +/* 4175 | + * 4176 | + * This Source Code Form is subject to the terms of the Mozilla Public 4177 | + * License, v. 2.0. If a copy of the MPL was not distributed with this 4178 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4179 | + 4180 | +#include "secitem.h" 4181 | +#include "sslimpl.h" 4182 | +#include "pk11func.h" 4183 | +#include "blapi.h" 4184 | + 4185 | +SECStatus 4186 | +tls13_GenerateX25519Kyber512Draft00KeyPair(const sslSocket *ss, 4187 | + const sslNamedGroupDef *group, 4188 | + sslEphemeralKeyPair **keyPair) 4189 | +{ 4190 | + SECKEYPrivateKey *privKey = NULL; 4191 | + SECKEYPublicKey *pubKey = NULL; 4192 | + sslEphemeralKeyPair *pair; 4193 | + 4194 | + PK11SlotInfo *slot = PK11_GetBestSlot(CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN, NULL); 4195 | + if (!slot) { 4196 | + return SECFailure; 4197 | + } 4198 | + 4199 | + privKey = PK11_GenerateKeyPair(slot, CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN, NULL, &pubKey, 4200 | + PR_FALSE, PR_FALSE, NULL); 4201 | + PK11_FreeSlot(slot); 4202 | + 4203 | + 4204 | + if (!privKey || !pubKey || 4205 | + !(pair = ssl_NewEphemeralKeyPair(group, privKey, pubKey))) { 4206 | + if (privKey) { 4207 | + SECKEY_DestroyPrivateKey(privKey); 4208 | + } 4209 | + if (pubKey) { 4210 | + SECKEY_DestroyPublicKey(pubKey); 4211 | + } 4212 | + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); 4213 | + return SECFailure; 4214 | + } 4215 | + 4216 | + *keyPair = pair; 4217 | + 4218 | + return SECSuccess; 4219 | +} 4220 | diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h 4221 | index cb7672048..bc2382122 100644 4222 | --- a/lib/util/pkcs11n.h 4223 | +++ b/lib/util/pkcs11n.h 4224 | @@ -55,6 +55,8 @@ 4225 | 4226 | #define CKK_NSS_CHACHA20 (CKK_NSS + 4) 4227 | 4228 | +#define CKK_NSS_X25519KYBER512DRAFT00 (CKK_NSS + 5) 4229 | + 4230 | /* 4231 | * NSS-defined certificate types 4232 | * 4233 | @@ -258,6 +260,9 @@ 4234 | #define CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA (CKM_NSS + 43) 4235 | #define CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA (CKM_NSS + 44) 4236 | 4237 | +/* X25519KYBER512DRAFT00 */ 4238 | +#define CKM_NSS_X25519KYBER512DRAFT00_KEY_GEN (CKM_NSS + 45) 4239 | + 4240 | /* 4241 | * HISTORICAL: 4242 | * Do not attempt to use these. They are only used by NSS's internal 4243 | --------------------------------------------------------------------------------