1
1
mirror of https://github.com/henrydcase/pqc.git synced 2024-11-23 07:59:01 +00:00
pqcrypto/crypto_kem/kyber512/clean/indcpa.c
2021-03-24 21:02:49 +00:00

337 lines
13 KiB
C

#include "indcpa.h"
#include "ntt.h"
#include "params.h"
#include "poly.h"
#include "polyvec.h"
#include "randombytes.h"
#include "symmetric.h"
#include <stddef.h>
#include <stdint.h>
/*************************************************
* Name: pack_pk
*
* Description: Serialize the public key as concatenation of the
* serialized vector of polynomials pk
* and the public seed used to generate the matrix A.
*
* Arguments: uint8_t *r: pointer to the output serialized public key
* polyvec *pk: pointer to the input public-key polyvec
* const uint8_t *seed: pointer to the input public seed
**************************************************/
static void pack_pk(uint8_t r[KYBER_INDCPA_PUBLICKEYBYTES],
polyvec *pk,
const uint8_t seed[KYBER_SYMBYTES]) {
size_t i = 0;
PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(r, pk);
for (i = 0; i < KYBER_SYMBYTES; i++) {
r[i + KYBER_POLYVECBYTES] = seed[i];
}
}
/*************************************************
* Name: unpack_pk
*
* Description: De-serialize public key from a byte array;
* approximate inverse of pack_pk
*
* Arguments: - polyvec *pk: pointer to output public-key
* polynomial vector
* - uint8_t *seed: pointer to output seed to generate
* matrix A
* - const uint8_t *packedpk: pointer to input serialized public key
**************************************************/
static void unpack_pk(polyvec *pk,
uint8_t seed[KYBER_SYMBYTES],
const uint8_t packedpk[KYBER_INDCPA_PUBLICKEYBYTES]) {
size_t i = 0;
PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(pk, packedpk);
for (i = 0; i < KYBER_SYMBYTES; i++) {
seed[i] = packedpk[i + KYBER_POLYVECBYTES];
}
}
/*************************************************
* Name: pack_sk
*
* Description: Serialize the secret key
*
* Arguments: - uint8_t *r: pointer to output serialized secret key
* - polyvec *sk: pointer to input vector of polynomials (secret key)
**************************************************/
static void pack_sk(uint8_t r[KYBER_INDCPA_SECRETKEYBYTES], polyvec *sk) {
PQCLEAN_KYBER512_CLEAN_polyvec_tobytes(r, sk);
}
/*************************************************
* Name: unpack_sk
*
* Description: De-serialize the secret key;
* inverse of pack_sk
*
* Arguments: - polyvec *sk: pointer to output vector of
* polynomials (secret key)
* - const uint8_t *packedsk: pointer to input serialized secret key
**************************************************/
static void unpack_sk(polyvec *sk,
const uint8_t packedsk[KYBER_INDCPA_SECRETKEYBYTES]) {
PQCLEAN_KYBER512_CLEAN_polyvec_frombytes(sk, packedsk);
}
/*************************************************
* Name: pack_ciphertext
*
* Description: Serialize the ciphertext as concatenation of the
* compressed and serialized vector of polynomials b
* and the compressed and serialized polynomial v
*
* Arguments: uint8_t *r: pointer to the output serialized ciphertext
* poly *pk: pointer to the input vector of polynomials b
* poly *v: pointer to the input polynomial v
**************************************************/
static void pack_ciphertext(uint8_t r[KYBER_INDCPA_BYTES],
polyvec *b,
poly *v) {
PQCLEAN_KYBER512_CLEAN_polyvec_compress(r, b);
PQCLEAN_KYBER512_CLEAN_poly_compress(r + KYBER_POLYVECCOMPRESSEDBYTES, v);
}
/*************************************************
* Name: unpack_ciphertext
*
* Description: De-serialize and decompress ciphertext from a byte array;
* approximate inverse of pack_ciphertext
*
* Arguments: - polyvec *b: pointer to the output vector of polynomials b
* - poly *v: pointer to the output polynomial v
* - const uint8_t *c: pointer to the input serialized ciphertext
**************************************************/
static void unpack_ciphertext(polyvec *b,
poly *v,
const uint8_t c[KYBER_INDCPA_BYTES]) {
PQCLEAN_KYBER512_CLEAN_polyvec_decompress(b, c);
PQCLEAN_KYBER512_CLEAN_poly_decompress(v, c + KYBER_POLYVECCOMPRESSEDBYTES);
}
/*************************************************
* Name: rej_uniform
*
* Description: Run rejection sampling on uniform random bytes to generate
* uniform random integers mod q
*
* Arguments: - int16_t *r: pointer to output buffer
* - unsigned int len: requested number of 16-bit integers
* (uniform mod q)
* - const uint8_t *buf: pointer to input buffer
* (assumed to be uniform random bytes)
* - unsigned int buflen: length of input buffer in bytes
*
* Returns number of sampled 16-bit integers (at most len)
**************************************************/
static unsigned int rej_uniform(int16_t *r,
unsigned int len,
const uint8_t *buf,
unsigned int buflen) {
unsigned int ctr = 0, pos = 0;
uint16_t val = 0;
ctr = pos = 0;
while (ctr < len && pos + 2 <= buflen) {
val = buf[pos] | ((uint16_t)buf[pos + 1] << 8);
pos += 2;
if (val < 19 * KYBER_Q) {
val -= (val >> 12) * KYBER_Q; // Barrett reduction
r[ctr++] = (int16_t)val;
}
}
return ctr;
}
#define gen_a(A,B) PQCLEAN_KYBER512_CLEAN_gen_matrix(A,B,0)
#define gen_at(A,B) PQCLEAN_KYBER512_CLEAN_gen_matrix(A,B,1)
/*************************************************
* Name: PQCLEAN_KYBER512_CLEAN_gen_matrix
*
* Description: Deterministically generate matrix A (or the transpose of A)
* from a seed. Entries of the matrix are polynomials that look
* uniformly random. Performs rejection sampling on output of
* a XOF
*
* Arguments: - polyvec *a: pointer to ouptput matrix A
* - const uint8_t *seed: pointer to input seed
* - int transposed: boolean deciding whether A or A^T
* is generated
**************************************************/
#define GEN_MATRIX_NBLOCKS ((2*KYBER_N*(1U << 16)/(19*KYBER_Q) \
+ XOF_BLOCKBYTES)/XOF_BLOCKBYTES)
// Not static for benchmarking
void PQCLEAN_KYBER512_CLEAN_gen_matrix(polyvec *a, const uint8_t seed[KYBER_SYMBYTES], int transposed) {
unsigned int ctr = 0;
uint8_t i = 0, j = 0;
uint8_t buf[GEN_MATRIX_NBLOCKS * XOF_BLOCKBYTES];
xof_state state;
for (i = 0; i < KYBER_K; i++) {
for (j = 0; j < KYBER_K; j++) {
if (transposed) {
xof_absorb(&state, seed, i, j);
} else {
xof_absorb(&state, seed, j, i);
}
xof_squeezeblocks(buf, GEN_MATRIX_NBLOCKS, &state);
ctr = rej_uniform(a[i].vec[j].coeffs, KYBER_N, buf, sizeof(buf));
while (ctr < KYBER_N) {
xof_squeezeblocks(buf, 1, &state);
ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf,
XOF_BLOCKBYTES);
}
xof_ctx_release(&state);
}
}
}
/*************************************************
* Name: PQCLEAN_KYBER512_CLEAN_indcpa_keypair
*
* Description: Generates public and private key for the CPA-secure
* public-key encryption scheme underlying Kyber
*
* Arguments: - uint8_t *pk: pointer to output public key
* (of length KYBER_INDCPA_PUBLICKEYBYTES bytes)
* - uint8_t *sk: pointer to output private key
(of length KYBER_INDCPA_SECRETKEYBYTES bytes)
**************************************************/
void PQCLEAN_KYBER512_CLEAN_indcpa_keypair(uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES],
uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES]) {
unsigned int i = 0;
uint8_t buf[2 * KYBER_SYMBYTES];
const uint8_t *publicseed = buf;
const uint8_t *noiseseed = buf + KYBER_SYMBYTES;
uint8_t nonce = 0;
polyvec a[KYBER_K], e, pkpv, skpv;
randombytes(buf, KYBER_SYMBYTES);
hash_g(buf, buf, KYBER_SYMBYTES);
gen_a(a, publicseed);
for (i = 0; i < KYBER_K; i++) {
PQCLEAN_KYBER512_CLEAN_poly_getnoise(&skpv.vec[i], noiseseed, nonce++);
}
for (i = 0; i < KYBER_K; i++) {
PQCLEAN_KYBER512_CLEAN_poly_getnoise(&e.vec[i], noiseseed, nonce++);
}
PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&skpv);
PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&e);
// matrix-vector multiplication
for (i = 0; i < KYBER_K; i++) {
PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc_montgomery(&pkpv.vec[i], &a[i], &skpv);
PQCLEAN_KYBER512_CLEAN_poly_tomont(&pkpv.vec[i]);
}
PQCLEAN_KYBER512_CLEAN_polyvec_add(&pkpv, &pkpv, &e);
PQCLEAN_KYBER512_CLEAN_polyvec_reduce(&pkpv);
pack_sk(sk, &skpv);
pack_pk(pk, &pkpv, publicseed);
}
/*************************************************
* Name: PQCLEAN_KYBER512_CLEAN_indcpa_enc
*
* Description: Encryption function of the CPA-secure
* public-key encryption scheme underlying Kyber.
*
* Arguments: - uint8_t *c: pointer to output ciphertext
* (of length KYBER_INDCPA_BYTES bytes)
* - const uint8_t *m: pointer to input message
* (of length KYBER_INDCPA_MSGBYTES bytes)
* - const uint8_t *pk: pointer to input public key
* (of length KYBER_INDCPA_PUBLICKEYBYTES)
* - const uint8_t *coins: pointer to input random coins
* used as seed (of length KYBER_SYMBYTES)
* to deterministically generate all
* randomness
**************************************************/
void PQCLEAN_KYBER512_CLEAN_indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES],
const uint8_t m[KYBER_INDCPA_MSGBYTES],
const uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES],
const uint8_t coins[KYBER_SYMBYTES]) {
unsigned int i = 0;
uint8_t seed[KYBER_SYMBYTES];
uint8_t nonce = 0;
polyvec sp, pkpv, ep, at[KYBER_K], bp;
poly v, k, epp;
unpack_pk(&pkpv, seed, pk);
PQCLEAN_KYBER512_CLEAN_poly_frommsg(&k, m);
gen_at(at, seed);
for (i = 0; i < KYBER_K; i++) {
PQCLEAN_KYBER512_CLEAN_poly_getnoise(sp.vec + i, coins, nonce++);
}
for (i = 0; i < KYBER_K; i++) {
PQCLEAN_KYBER512_CLEAN_poly_getnoise(ep.vec + i, coins, nonce++);
}
PQCLEAN_KYBER512_CLEAN_poly_getnoise(&epp, coins, nonce++);
PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&sp);
// matrix-vector multiplication
for (i = 0; i < KYBER_K; i++) {
PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc_montgomery(&bp.vec[i], &at[i], &sp);
}
PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc_montgomery(&v, &pkpv, &sp);
PQCLEAN_KYBER512_CLEAN_polyvec_invntt_tomont(&bp);
PQCLEAN_KYBER512_CLEAN_poly_invntt_tomont(&v);
PQCLEAN_KYBER512_CLEAN_polyvec_add(&bp, &bp, &ep);
PQCLEAN_KYBER512_CLEAN_poly_add(&v, &v, &epp);
PQCLEAN_KYBER512_CLEAN_poly_add(&v, &v, &k);
PQCLEAN_KYBER512_CLEAN_polyvec_reduce(&bp);
PQCLEAN_KYBER512_CLEAN_poly_reduce(&v);
pack_ciphertext(c, &bp, &v);
}
/*************************************************
* Name: PQCLEAN_KYBER512_CLEAN_indcpa_dec
*
* Description: Decryption function of the CPA-secure
* public-key encryption scheme underlying Kyber.
*
* Arguments: - uint8_t *m: pointer to output decrypted message
* (of length KYBER_INDCPA_MSGBYTES)
* - const uint8_t *c: pointer to input ciphertext
* (of length KYBER_INDCPA_BYTES)
* - const uint8_t *sk: pointer to input secret key
* (of length KYBER_INDCPA_SECRETKEYBYTES)
**************************************************/
void PQCLEAN_KYBER512_CLEAN_indcpa_dec(uint8_t m[KYBER_INDCPA_MSGBYTES],
const uint8_t c[KYBER_INDCPA_BYTES],
const uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES]) {
polyvec bp, skpv;
poly v, mp;
unpack_ciphertext(&bp, &v, c);
unpack_sk(&skpv, sk);
PQCLEAN_KYBER512_CLEAN_polyvec_ntt(&bp);
PQCLEAN_KYBER512_CLEAN_polyvec_pointwise_acc_montgomery(&mp, &skpv, &bp);
PQCLEAN_KYBER512_CLEAN_poly_invntt_tomont(&mp);
PQCLEAN_KYBER512_CLEAN_poly_sub(&mp, &v, &mp);
PQCLEAN_KYBER512_CLEAN_poly_reduce(&mp);
PQCLEAN_KYBER512_CLEAN_poly_tomsg(m, &mp);
}