in src/kem.c [15:75]
int crypto_kem_keypair(unsigned char* pk, unsigned char* sk)
{ // FrodoKEM's key generation
// Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes)
// secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes)
uint8_t *pk_seedA = &pk[0];
uint8_t *pk_b = &pk[BYTES_SEED_A];
uint8_t *sk_s = &sk[0];
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR];
uint16_t B[PARAMS_N*PARAMS_NBAR] = {0};
uint16_t S[2*PARAMS_N*PARAMS_NBAR] = {0}; // contains secret data
uint16_t *E = (uint16_t *)&S[PARAMS_N*PARAMS_NBAR]; // contains secret data
uint8_t randomness[2*CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
uint8_t *randomness_s = &randomness[0]; // contains secret data
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
uint8_t *randomness_z = &randomness[2*CRYPTO_BYTES];
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
#ifdef DO_VALGRIND_CHECK
VALGRIND_MAKE_MEM_UNDEFINED(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
#endif
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
shake_input_seedSE[0] = 0x5F;
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
shake((uint8_t*)S, 2*PARAMS_N*PARAMS_NBAR*sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
S[i] = LE_TO_UINT16(S[i]);
}
frodo_sample_n(S, PARAMS_N*PARAMS_NBAR);
frodo_sample_n(E, PARAMS_N*PARAMS_NBAR);
frodo_mul_add_as_plus_e(B, S, E, pk);
// Encode the second part of the public key
frodo_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N*PARAMS_NBAR, PARAMS_LOGQ);
// Add s, pk and S to the secret key
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
S[i] = UINT16_TO_LE(S[i]);
}
memcpy(sk_S, S, 2*PARAMS_N*PARAMS_NBAR);
// Add H(pk) to the secret key
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
// Cleanup:
clear_bytes((uint8_t *)S, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
clear_bytes((uint8_t *)E, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
clear_bytes(randomness, 2*CRYPTO_BYTES);
clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
#ifdef DO_VALGRIND_CHECK
VALGRIND_MAKE_MEM_DEFINED(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
#endif
return 0;
}