1
1
mirror of https://github.com/henrydcase/pqc.git synced 2024-11-30 03:11:43 +00:00
pqcrypto/crypto_kem/hqc-128-1-cca2/leaktime/kem.c
Sebastian 4054af0c42 HQC submission (#202)
* Sebastian's HQC merge request

* Clean up changes to common infrastructure

* Fix Bitmask macro

It assumed that ``unsigned long`` was 64 bit

* Remove maxlen from nistseedexpander

It's a complicated thing to handle because the value is larger than size_t supports on 32-bit platforms

* Initialize buffers to help linter

* Add Nistseedexpander test

* Resolve UB in gf2x.c

Some of the shifts could be larger than WORD_SIZE_BITS, ie. larger than
the width of uint64_t. This apparently on Intel gets interpreted as the
shift mod 64, but on ARM something else happened.

* Fix Windows complaints

* rename log, exp which appear to be existing functions on MS

* Solve endianness problems

* remove all spaces before ';'

* Fix duplicate consistency

* Fix duplicate consistency

* Fix complaints by MSVC about narrowing int

* Add nistseedexpander.obj to COMMON_OBJECTS_NOPATH

* astyle format util.[ch]

* add util.h to makefile

* Sort includes in util.h

* Fix more Windows MSVC complaints

Co-authored-by: Sebastian Verschoor <sebastian@zeroknowledge.me>
Co-authored-by: Thom Wiggers <thom@thomwiggers.nl>
2021-03-24 21:02:46 +00:00

155 lines
4.8 KiB
C

/**
* @file kem.c
* @brief Implementation of api.h
*/
#include "api.h"
#include "hqc.h"
#include "nistseedexpander.h"
#include "parameters.h"
#include "parsing.h"
#include "sha2.h"
#include "vector.h"
#include <stdint.h>
#include <string.h>
/**
* @brief Keygen of the HQC_KEM IND_CAA2 scheme
*
* The public key is composed of the syndrome <b>s</b> as well as the seed used to generate the vector <b>h</b>.
*
* The secret key is composed of the seed used to generate vectors <b>x</b> and <b>y</b>.
* As a technicality, the public key is appended to the secret key in order to respect NIST API.
*
* @param[out] pk String containing the public key
* @param[out] sk String containing the secret key
* @returns 0 if keygen is successful
*/
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_keygen(pk, sk);
return 0;
}
/**
* @brief Encapsulation of the HQC_KEM IND_CAA2 scheme
*
* @param[out] ct String containing the ciphertext
* @param[out] ss String containing the shared secret
* @param[in] pk String containing the public key
* @returns 0 if encapsulation is successful
*/
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
AES_XOF_struct G_seedexpander;
uint8_t seed_G[VEC_K_SIZE_BYTES];
uint8_t diversifier_bytes[8] = {0};
uint8_t m[VEC_K_SIZE_BYTES] = {0};
uint8_t theta[SEED_BYTES] = {0};
uint8_t u[VEC_N_SIZE_BYTES] = {0};
uint8_t v[VEC_N1N2_SIZE_BYTES] = {0};
uint8_t d[SHA512_BYTES] = {0};
uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0};
// Computing m
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_set_random_from_randombytes(m);
// Generating G function
memcpy(seed_G, m, VEC_K_SIZE_BYTES);
seedexpander_init(&G_seedexpander, seed_G, diversifier_bytes, SEEDEXPANDER_MAX_LENGTH);
// Computing theta
seedexpander(&G_seedexpander, theta, SEED_BYTES);
// Encrypting m
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_encrypt(u, v, m, theta, pk);
// Computing d
sha512(d, m, VEC_K_SIZE_BYTES);
// Computing shared secret
memcpy(mc, m, VEC_K_SIZE_BYTES);
memcpy(mc + VEC_K_SIZE_BYTES, u, VEC_N_SIZE_BYTES);
memcpy(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
sha512(ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES);
// Computing ciphertext
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_ciphertext_to_string(ct, u, v, d);
return 0;
}
/**
* @brief Decapsulation of the HQC_KEM IND_CAA2 scheme
*
* @param[out] ss String containing the shared secret
* @param[in] ct String containing the cipĥertext
* @param[in] sk String containing the secret key
* @returns 0 if decapsulation is successful, -1 otherwise
*/
int PQCLEAN_HQC1281CCA2_LEAKTIME_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
AES_XOF_struct G_seedexpander;
uint8_t seed_G[VEC_K_SIZE_BYTES] = {0};
uint8_t diversifier_bytes[8] = {0};
uint8_t u[VEC_N_SIZE_BYTES] = {0};
uint8_t v[VEC_N1N2_SIZE_BYTES] = {0};
uint8_t d[SHA512_BYTES] = {0};
uint8_t pk[PUBLIC_KEY_BYTES] = {0};
uint8_t m[VEC_K_SIZE_BYTES] = {0};
uint8_t theta[SEED_BYTES] = {0};
uint8_t u2[VEC_N_SIZE_BYTES] = {0};
uint8_t v2[VEC_N1N2_SIZE_BYTES] = {0};
uint8_t d2[SHA512_BYTES] = {0};
uint8_t mc[VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES] = {0};
int8_t abort = 0;
// Retrieving u, v and d from ciphertext
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_ciphertext_from_string(u, v, d, ct);
// Retrieving pk from sk
memcpy(pk, sk + SEED_BYTES, PUBLIC_KEY_BYTES);
// Decryting
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_decrypt(m, u, v, sk);
// Generating G function
memcpy(seed_G, m, VEC_K_SIZE_BYTES);
seedexpander_init(&G_seedexpander, seed_G, diversifier_bytes, SEEDEXPANDER_MAX_LENGTH);
// Computing theta
seedexpander(&G_seedexpander, theta, SEED_BYTES);
// Encrypting m'
PQCLEAN_HQC1281CCA2_LEAKTIME_hqc_pke_encrypt(u2, v2, m, theta, pk);
// Checking that c = c' and abort otherwise
if (PQCLEAN_HQC1281CCA2_LEAKTIME_vect_compare(u, u2, VEC_N_SIZE_BYTES) != 0 ||
PQCLEAN_HQC1281CCA2_LEAKTIME_vect_compare(v, v2, VEC_N1N2_SIZE_BYTES) != 0) {
abort = 1;
}
// Computing d'
sha512(d2, m, VEC_K_SIZE_BYTES);
// Checking that d = d' and abort otherwise
if (memcmp(d, d2, SHA512_BYTES) != 0) {
abort = 1;
}
if (abort == 1) {
memset(ss, 0, SHARED_SECRET_BYTES);
return -1;
}
// Computing shared secret
memcpy(mc, m, VEC_K_SIZE_BYTES);
memcpy(mc + VEC_K_SIZE_BYTES, u, VEC_N_SIZE_BYTES);
memcpy(mc + VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES, v, VEC_N1N2_SIZE_BYTES);
sha512(ss, mc, VEC_K_SIZE_BYTES + VEC_N_SIZE_BYTES + VEC_N1N2_SIZE_BYTES);
return 0;
}