/*
* SPDX - License - Identifier : Apache - 2 . 0
*
* This file was generated from
* https : //github.com/pq-crystals/kyber/commit/e0d1c6ff
*
* Files from that repository are listed here surrounded by
* " * begin : [ file ] * " and " * end : [ file ] * " comments .
*
* The following changes have been made :
* - include guards have been removed ,
* - include directives have been removed ,
* - " # ifdef KYBER90S " blocks have been evaluated with " KYBER90S " undefined ,
* - functions outside of kem . c have been made static .
*/
/** begin: ref/LICENSE **
Public Domain ( https : //creativecommons.org/share-your-work/public-domain/cc0/);
or Apache 2 . 0 License ( https : //www.apache.org/licenses/LICENSE-2.0.html).
For Keccak and AES we are using public - domain
code from sources and by authors listed in
comments on top of the respective files .
** end: ref/LICENSE **/
/** begin: ref/AUTHORS **
Joppe Bos ,
L é o Ducas ,
Eike Kiltz ,
Tancr è de Lepoint ,
Vadim Lyubashevsky ,
John Schanck ,
Peter Schwabe ,
Gregor Seiler ,
Damien Stehl é
** end: ref/AUTHORS **/
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "secport.h"
// We need to provide an implementation of randombytes to avoid an unused
// function warning. We don't use the randomized API in freebl, so we'll make
// calling randombytes an error.
static void
randombytes(uint8_t *out, size_t outlen)
{
// this memset is to avoid "maybe-uninitialized" warnings that gcc-11 issues
// for the (unused) crypto_kem_keypair and crypto_kem_enc functions.
memset(out, 0 , outlen);
assert(0 );
}
/*************************************************
* Name : verify
*
* Description : Compare two arrays for equality in constant time .
*
* Arguments : const uint8_t * a : pointer to first byte array
* const uint8_t * b : pointer to second byte array
* size_t len : length of the byte arrays
*
* Returns 0 if the byte arrays are equal , 1 otherwise
**************************************************/
static int
verify(const uint8_t *a, const uint8_t *b, size_t len)
{
return NSS_SecureMemcmp(a, b, len);
}
/*************************************************
* Name : cmov
*
* Description : Copy len bytes from x to r if b is 1 ;
* don ' t modify x if b is 0 . Requires b to be in { 0 , 1 } ;
* assumes two ' s complement representation of negative integers .
* Runs in constant time .
*
* Arguments : uint8_t * r : pointer to output byte array
* const uint8_t * x : pointer to input byte array
* size_t len : Amount of bytes to be copied
* uint8_t b : Condition bit ; has to be in { 0 , 1 }
**************************************************/
static void
cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b)
{
NSS_SecureSelect(r, r, x, len, b);
}
/** begin: ref/params.h **/
#ifndef KYBER_K
#define KYBER_K 3 /* Change this for different security strengths */
#endif
//#define KYBER_90S /* Uncomment this if you want the 90S variant */
/* Don't change parameters below this line */
#if (KYBER_K == 2 )
#define KYBER_NAMESPACE(s) pqcrystals_kyber512_ref_## s
#elif (KYBER_K == 3 )
#define KYBER_NAMESPACE(s) pqcrystals_kyber768_ref_## s
#elif (KYBER_K == 4 )
#define KYBER_NAMESPACE(s) pqcrystals_kyber1024_ref_## s
#else
#error "KYBER_K must be in {2,3,4}"
#endif
#define KYBER_N 256
#define KYBER_Q 3329
#define KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */
#define KYBER_SSBYTES 32 /* size in bytes of shared key */
#define KYBER_POLYBYTES 384
#define KYBER_POLYVECBYTES (KYBER_K * KYBER_POLYBYTES)
#if KYBER_K == 2
#define KYBER_ETA1 3
#define KYBER_POLYCOMPRESSEDBYTES 128
#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 320 )
#elif KYBER_K == 3
#define KYBER_ETA1 2
#define KYBER_POLYCOMPRESSEDBYTES 128
#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 320 )
#elif KYBER_K == 4
#define KYBER_ETA1 2
#define KYBER_POLYCOMPRESSEDBYTES 160
#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 352 )
#endif
#define KYBER_ETA2 2
#define KYBER_INDCPA_MSGBYTES (KYBER_SYMBYTES)
#define KYBER_INDCPA_PUBLICKEYBYTES (KYBER_POLYVECBYTES + KYBER_SYMBYTES)
#define KYBER_INDCPA_SECRETKEYBYTES (KYBER_POLYVECBYTES)
#define KYBER_INDCPA_BYTES (KYBER_POLYVECCOMPRESSEDBYTES + KYBER_POLYCOMPRESSEDBYTES)
#define KYBER_PUBLICKEYBYTES (KYBER_INDCPA_PUBLICKEYBYTES)
/* 32 bytes of additional space to save H(pk) */
#define KYBER_SECRETKEYBYTES (KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES + 2 * KYBER_SYMBYTES)
#define KYBER_CIPHERTEXTBYTES (KYBER_INDCPA_BYTES)
/** end: ref/params.h **/
/** begin: ref/reduce.h **/
#define MONT -1044 // 2^16 mod q
#define QINV -3327 // q^-1 mod 2^16
#define montgomery_reduce KYBER_NAMESPACE(montgomery_reduce)
static int16_t montgomery_reduce(int32_t a);
#define barrett_reduce KYBER_NAMESPACE(barrett_reduce)
static int16_t barrett_reduce(int16_t a);
/** end: ref/reduce.h **/
/** begin: ref/ntt.h **/
#define zetas KYBER_NAMESPACE(zetas)
extern const int16_t zetas[128 ];
#define ntt KYBER_NAMESPACE(ntt)
static void ntt(int16_t poly[256 ]);
#define invntt KYBER_NAMESPACE(invntt)
static void invntt(int16_t poly[256 ]);
#define basemul KYBER_NAMESPACE(basemul)
static void basemul(int16_t r[2 ], const int16_t a[2 ], const int16_t b[2 ], int16_t zeta);
/** end: ref/ntt.h **/
/** begin: ref/poly.h **/
/*
* Elements of R_q = Z_q [ X ] / ( X ^ n + 1 ) . Represents polynomial
* coeffs [ 0 ] + X * coeffs [ 1 ] + X ^ 2 * coeffs [ 2 ] + . . . + X ^ { n - 1 } * coeffs [ n - 1 ]
*/
typedef struct {
int16_t coeffs[KYBER_N];
} poly;
#define poly_compress KYBER_NAMESPACE(poly_compress)
static void poly_compress(uint8_t r[KYBER_POLYCOMPRESSEDBYTES], const poly *a);
#define poly_decompress KYBER_NAMESPACE(poly_decompress)
static void poly_decompress(poly *r, const uint8_t a[KYBER_POLYCOMPRESSEDBYTES]);
#define poly_tobytes KYBER_NAMESPACE(poly_tobytes)
static void poly_tobytes(uint8_t r[KYBER_POLYBYTES], const poly *a);
#define poly_frombytes KYBER_NAMESPACE(poly_frombytes)
static void poly_frombytes(poly *r, const uint8_t a[KYBER_POLYBYTES]);
#define poly_frommsg KYBER_NAMESPACE(poly_frommsg)
static void poly_frommsg(poly *r, const uint8_t msg[KYBER_INDCPA_MSGBYTES]);
#define poly_tomsg KYBER_NAMESPACE(poly_tomsg)
static void poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *r);
#define poly_getnoise_eta1 KYBER_NAMESPACE(poly_getnoise_eta1)
static void poly_getnoise_eta1(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce);
#define poly_getnoise_eta2 KYBER_NAMESPACE(poly_getnoise_eta2)
static void poly_getnoise_eta2(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce);
#define poly_ntt KYBER_NAMESPACE(poly_ntt)
static void poly_ntt(poly *r);
#define poly_invntt_tomont KYBER_NAMESPACE(poly_invntt_tomont)
static void poly_invntt_tomont(poly *r);
#define poly_basemul_montgomery KYBER_NAMESPACE(poly_basemul_montgomery)
static void poly_basemul_montgomery(poly *r, const poly *a, const poly *b);
#define poly_tomont KYBER_NAMESPACE(poly_tomont)
static void poly_tomont(poly *r);
#define poly_reduce KYBER_NAMESPACE(poly_reduce)
static void poly_reduce(poly *r);
#define poly_add KYBER_NAMESPACE(poly_add)
static void poly_add(poly *r, const poly *a, const poly *b);
#define poly_sub KYBER_NAMESPACE(poly_sub)
static void poly_sub(poly *r, const poly *a, const poly *b);
/** end: ref/poly.h **/
/** begin: ref/cbd.h **/
#define poly_cbd_eta1 KYBER_NAMESPACE(poly_cbd_eta1)
static void poly_cbd_eta1(poly *r, const uint8_t buf[KYBER_ETA1 * KYBER_N / 4 ]);
#define poly_cbd_eta2 KYBER_NAMESPACE(poly_cbd_eta2)
static void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2 * KYBER_N / 4 ]);
/** end: ref/cbd.h **/
/** begin: ref/polyvec.h **/
typedef struct {
poly vec[KYBER_K];
} polyvec;
#define polyvec_compress KYBER_NAMESPACE(polyvec_compress)
static void polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a);
#define polyvec_decompress KYBER_NAMESPACE(polyvec_decompress)
static void polyvec_decompress(polyvec *r, const uint8_t a[KYBER_POLYVECCOMPRESSEDBYTES]);
#define polyvec_tobytes KYBER_NAMESPACE(polyvec_tobytes)
static void polyvec_tobytes(uint8_t r[KYBER_POLYVECBYTES], const polyvec *a);
#define polyvec_frombytes KYBER_NAMESPACE(polyvec_frombytes)
static void polyvec_frombytes(polyvec *r, const uint8_t a[KYBER_POLYVECBYTES]);
#define polyvec_ntt KYBER_NAMESPACE(polyvec_ntt)
static void polyvec_ntt(polyvec *r);
#define polyvec_invntt_tomont KYBER_NAMESPACE(polyvec_invntt_tomont)
static void polyvec_invntt_tomont(polyvec *r);
#define polyvec_basemul_acc_montgomery KYBER_NAMESPACE(polyvec_basemul_acc_montgomery)
static void polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, const polyvec *b);
#define polyvec_reduce KYBER_NAMESPACE(polyvec_reduce)
static void polyvec_reduce(polyvec *r);
#define polyvec_add KYBER_NAMESPACE(polyvec_add)
static void polyvec_add(polyvec *r, const polyvec *a, const polyvec *b);
/** end: ref/polyvec.h **/
/** begin: ref/indcpa.h **/
#define gen_matrix KYBER_NAMESPACE(gen_matrix)
static void gen_matrix(polyvec *a, const uint8_t seed[KYBER_SYMBYTES], int transposed);
#define indcpa_keypair_derand KYBER_NAMESPACE(indcpa_keypair_derand)
static void indcpa_keypair_derand(uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES],
uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES],
const uint8_t coins[KYBER_SYMBYTES]);
#define indcpa_enc KYBER_NAMESPACE(indcpa_enc)
static void 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]);
#define indcpa_dec KYBER_NAMESPACE(indcpa_dec)
static void indcpa_dec(uint8_t m[KYBER_INDCPA_MSGBYTES],
const uint8_t c[KYBER_INDCPA_BYTES],
const uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES]);
/** end: ref/indcpa.h **/
/** begin: ref/fips202.h **/
#define SHAKE128_RATE 168
#define SHAKE256_RATE 136
#define SHA3_256_RATE 136
#define SHA3_512_RATE 72
#define FIPS202_NAMESPACE(s) pqcrystals_kyber_fips202_ref_## s
typedef struct {
uint64_t s[25 ];
unsigned int pos;
} keccak_state;
#define shake128_init FIPS202_NAMESPACE(shake128_init)
void shake128_init(keccak_state *state);
#define shake128_absorb FIPS202_NAMESPACE(shake128_absorb)
void shake128_absorb(keccak_state *state, const uint8_t *in, size_t inlen);
#define shake128_finalize FIPS202_NAMESPACE(shake128_finalize)
void shake128_finalize(keccak_state *state);
#define shake128_squeeze FIPS202_NAMESPACE(shake128_squeeze)
void shake128_squeeze(uint8_t *out, size_t outlen, keccak_state *state);
#define shake128_absorb_once FIPS202_NAMESPACE(shake128_absorb_once)
void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen);
#define shake128_squeezeblocks FIPS202_NAMESPACE(shake128_squeezeblocks)
void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state);
#define shake256_init FIPS202_NAMESPACE(shake256_init)
void shake256_init(keccak_state *state);
#define shake256_absorb FIPS202_NAMESPACE(shake256_absorb)
void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen);
#define shake256_finalize FIPS202_NAMESPACE(shake256_finalize)
void shake256_finalize(keccak_state *state);
#define shake256_squeeze FIPS202_NAMESPACE(shake256_squeeze)
void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state);
#define shake256_absorb_once FIPS202_NAMESPACE(shake256_absorb_once)
void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen);
#define shake256_squeezeblocks FIPS202_NAMESPACE(shake256_squeezeblocks)
void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state);
#define shake128 FIPS202_NAMESPACE(shake128)
void shake128(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen);
#define shake256 FIPS202_NAMESPACE(shake256)
void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen);
#define sha3_256 FIPS202_NAMESPACE(sha3_256)
void sha3_256(uint8_t h[32 ], const uint8_t *in, size_t inlen);
#define sha3_512 FIPS202_NAMESPACE(sha3_512)
void sha3_512(uint8_t h[64 ], const uint8_t *in, size_t inlen);
/** end: ref/fips202.h **/
/** begin: ref/symmetric.h **/
typedef keccak_state xof_state;
#define kyber_shake128_absorb KYBER_NAMESPACE(kyber_shake128_absorb)
static void kyber_shake128_absorb(keccak_state *s,
const uint8_t seed[KYBER_SYMBYTES],
uint8_t x,
uint8_t y);
#define kyber_shake256_prf KYBER_NAMESPACE(kyber_shake256_prf)
static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce);
#define XOF_BLOCKBYTES SHAKE128_RATE
#define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES)
#define hash_g(OUT, IN, INBYTES) sha3_512(OUT, IN, INBYTES)
#define xof_absorb(STATE, SEED, X, Y) kyber_shake128_absorb(STATE, SEED, X, Y)
#define xof_squeezeblocks(OUT, OUTBLOCKS, STATE) shake128_squeezeblocks(OUT, OUTBLOCKS, STATE)
#define prf(OUT, OUTBYTES, KEY, NONCE) kyber_shake256_prf(OUT, OUTBYTES, KEY, NONCE)
#define kdf(OUT, IN, INBYTES) shake256(OUT, KYBER_SSBYTES, IN, INBYTES)
/** end: ref/symmetric.h **/
/** begin: ref/kem.h **/
#define CRYPTO_SECRETKEYBYTES KYBER_SECRETKEYBYTES
#define CRYPTO_PUBLICKEYBYTES KYBER_PUBLICKEYBYTES
#define CRYPTO_CIPHERTEXTBYTES KYBER_CIPHERTEXTBYTES
#define CRYPTO_BYTES KYBER_SSBYTES
#if (KYBER_K == 2 )
#define CRYPTO_ALGNAME "Kyber512"
#elif (KYBER_K == 3 )
#define CRYPTO_ALGNAME "Kyber768"
#elif (KYBER_K == 4 )
#define CRYPTO_ALGNAME "Kyber1024"
#endif
#define crypto_kem_keypair_derand KYBER_NAMESPACE(keypair_derand)
int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
#define crypto_kem_keypair KYBER_NAMESPACE(keypair)
int crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
#define crypto_kem_enc_derand KYBER_NAMESPACE(enc_derand)
int crypto_kem_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
#define crypto_kem_enc KYBER_NAMESPACE(enc)
int crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
#define crypto_kem_dec KYBER_NAMESPACE(dec)
int crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
/** end: ref/kem.h **/
/** begin: ref/reduce.c **/
/*************************************************
* Name : montgomery_reduce
*
* Description : Montgomery reduction ; given a 32 - bit integer a , computes
* 16 - bit integer congruent to a * R ^ - 1 mod q , where R = 2 ^ 16
*
* Arguments : - int32_t a : input integer to be reduced ;
* has to be in { - q2 ^ 15 , . . . , q2 ^ 15 - 1 }
*
* Returns : integer in { - q + 1 , . . . , q - 1 } congruent to a * R ^ - 1 modulo q .
**************************************************/
static int16_t
montgomery_reduce(int32_t a)
{
int16_t t;
t = (int16_t)a * QINV;
t = (a - (int32_t)t * KYBER_Q) >> 16 ;
return t;
}
/*************************************************
* Name : barrett_reduce
*
* Description : Barrett reduction ; given a 16 - bit integer a , computes
* centered representative congruent to a mod q in { - ( q - 1 ) / 2 , . . . , ( q - 1 ) / 2 }
*
* Arguments : - int16_t a : input integer to be reduced
*
* Returns : integer in { - ( q - 1 ) / 2 , . . . , ( q - 1 ) / 2 } congruent to a modulo q .
**************************************************/
static int16_t
barrett_reduce(int16_t a)
{
int16_t t;
const int16_t v = ((1 << 26 ) + KYBER_Q / 2 ) / KYBER_Q;
t = ((int32_t)v * a + (1 << 25 )) >> 26 ;
t *= KYBER_Q;
return a - t;
}
/** end: ref/reduce.c **/
/** begin: ref/cbd.c **/
/*************************************************
* Name : load32_littleendian
*
* Description : load 4 bytes into a 32 - bit integer
* in little - endian order
*
* Arguments : - const uint8_t * x : pointer to input byte array
*
* Returns 32 - bit unsigned integer loaded from x
**************************************************/
static uint32_t
load32_littleendian(const uint8_t x[4 ])
{
uint32_t r;
r = (uint32_t)x[0 ];
r |= (uint32_t)x[1 ] << 8 ;
r |= (uint32_t)x[2 ] << 16 ;
r |= (uint32_t)x[3 ] << 24 ;
return r;
}
/*************************************************
* Name : load24_littleendian
*
* Description : load 3 bytes into a 32 - bit integer
* in little - endian order .
* This function is only needed for Kyber - 512
*
* Arguments : - const uint8_t * x : pointer to input byte array
*
* Returns 32 - bit unsigned integer loaded from x ( most significant byte is zero )
**************************************************/
#if KYBER_ETA1 == 3
static uint32_t
load24_littleendian(const uint8_t x[3 ])
{
uint32_t r;
r = (uint32_t)x[0 ];
r |= (uint32_t)x[1 ] << 8 ;
r |= (uint32_t)x[2 ] << 16 ;
return r;
}
#endif
/*************************************************
* Name : cbd2
*
* Description : Given an array of uniformly random bytes , compute
* polynomial with coefficients distributed according to
* a centered binomial distribution with parameter eta = 2
*
* Arguments : - poly * r : pointer to output polynomial
* - const uint8_t * buf : pointer to input byte array
**************************************************/
static void
cbd2(poly *r, const uint8_t buf[2 * KYBER_N / 4 ])
{
unsigned int i, j;
uint32_t t, d;
int16_t a, b;
for (i = 0 ; i < KYBER_N / 8 ; i++) {
t = load32_littleendian(buf + 4 * i);
d = t & 0 x55555555;
d += (t >> 1 ) & 0 x55555555;
for (j = 0 ; j < 8 ; j++) {
a = (d >> (4 * j + 0 )) & 0 x3;
b = (d >> (4 * j + 2 )) & 0 x3;
r->coeffs[8 * i + j] = a - b;
}
}
}
/*************************************************
* Name : cbd3
*
* Description : Given an array of uniformly random bytes , compute
* polynomial with coefficients distributed according to
* a centered binomial distribution with parameter eta = 3 .
* This function is only needed for Kyber - 512
*
* Arguments : - poly * r : pointer to output polynomial
* - const uint8_t * buf : pointer to input byte array
**************************************************/
#if KYBER_ETA1 == 3
static void
cbd3(poly *r, const uint8_t buf[3 * KYBER_N / 4 ])
{
unsigned int i, j;
uint32_t t, d;
int16_t a, b;
for (i = 0 ; i < KYBER_N / 4 ; i++) {
t = load24_littleendian(buf + 3 * i);
d = t & 0 x00249249;
d += (t >> 1 ) & 0 x00249249;
d += (t >> 2 ) & 0 x00249249;
for (j = 0 ; j < 4 ; j++) {
a = (d >> (6 * j + 0 )) & 0 x7;
b = (d >> (6 * j + 3 )) & 0 x7;
r->coeffs[4 * i + j] = a - b;
}
}
}
#endif
static void
poly_cbd_eta1(poly *r, const uint8_t buf[KYBER_ETA1 * KYBER_N / 4 ])
{
#if KYBER_ETA1 == 2
cbd2(r, buf);
#elif KYBER_ETA1 == 3
cbd3(r, buf);
#else
#error "This implementation requires eta1 in {2,3}"
#endif
}
static void
poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2 * KYBER_N / 4 ])
{
#if KYBER_ETA2 == 2
cbd2(r, buf);
#else
#error "This implementation requires eta2 = 2"
#endif
}
/** end: ref/cbd.c **/
/** begin: ref/ntt.c **/
/* Code to generate zetas and zetas_inv used in the number-theoretic transform:
# define KYBER_ROOT_OF_UNITY 17
static const uint8_t tree [ 128 ] = {
0 , 64 , 32 , 96 , 16 , 80 , 48 , 112 , 8 , 72 , 40 , 104 , 24 , 88 , 56 , 120 ,
4 , 68 , 36 , 100 , 20 , 84 , 52 , 116 , 12 , 76 , 44 , 108 , 28 , 92 , 60 , 124 ,
2 , 66 , 34 , 98 , 18 , 82 , 50 , 114 , 10 , 74 , 42 , 106 , 26 , 90 , 58 , 122 ,
6 , 70 , 38 , 102 , 22 , 86 , 54 , 118 , 14 , 78 , 46 , 110 , 30 , 94 , 62 , 126 ,
1 , 65 , 33 , 97 , 17 , 81 , 49 , 113 , 9 , 73 , 41 , 105 , 25 , 89 , 57 , 121 ,
5 , 69 , 37 , 101 , 21 , 85 , 53 , 117 , 13 , 77 , 45 , 109 , 29 , 93 , 61 , 125 ,
3 , 67 , 35 , 99 , 19 , 83 , 51 , 115 , 11 , 75 , 43 , 107 , 27 , 91 , 59 , 123 ,
7 , 71 , 39 , 103 , 23 , 87 , 55 , 119 , 15 , 79 , 47 , 111 , 31 , 95 , 63 , 127
} ;
static void init_ntt ( ) {
unsigned int i ;
int16_t tmp [ 128 ] ;
tmp [ 0 ] = MONT ;
for ( i = 1 ; i < 128 ; i + + )
tmp [ i ] = fqmul ( tmp [ i - 1 ] , MONT * KYBER_ROOT_OF_UNITY % KYBER_Q ) ;
for ( i = 0 ; i < 128 ; i + + ) {
zetas [ i ] = tmp [ tree [ i ] ] ;
if ( zetas [ i ] > KYBER_Q / 2 )
zetas [ i ] - = KYBER_Q ;
if ( zetas [ i ] < - KYBER_Q / 2 )
zetas [ i ] + = KYBER_Q ;
}
}
*/
const int16_t zetas[128 ] = {
-1044 , -758 , -359 , -1517 , 1493 , 1422 , 287 , 202 ,
-171 , 622 , 1577 , 182 , 962 , -1202 , -1474 , 1468 ,
573 , -1325 , 264 , 383 , -829 , 1458 , -1602 , -130 ,
-681 , 1017 , 732 , 608 , -1542 , 411 , -205 , -1571 ,
1223 , 652 , -552 , 1015 , -1293 , 1491 , -282 , -1544 ,
516 , -8 , -320 , -666 , -1618 , -1162 , 126 , 1469 ,
-853 , -90 , -271 , 830 , 107 , -1421 , -247 , -951 ,
-398 , 961 , -1508 , -725 , 448 , -1065 , 677 , -1275 ,
-1103 , 430 , 555 , 843 , -1251 , 871 , 1550 , 105 ,
422 , 587 , 177 , -235 , -291 , -460 , 1574 , 1653 ,
-246 , 778 , 1159 , -147 , -777 , 1483 , -602 , 1119 ,
-1590 , 644 , -872 , 349 , 418 , 329 , -156 , -75 ,
817 , 1097 , 603 , 610 , 1322 , -1285 , -1465 , 384 ,
-1215 , -136 , 1218 , -1335 , -874 , 220 , -1187 , -1659 ,
-1185 , -1530 , -1278 , 794 , -1510 , -854 , -870 , 478 ,
-108 , -308 , 996 , 991 , 958 , -1460 , 1522 , 1628
};
/*************************************************
* Name : fqmul
*
* Description : Multiplication followed by Montgomery reduction
*
* Arguments : - int16_t a : first factor
* - int16_t b : second factor
*
* Returns 16 - bit integer congruent to a * b * R ^ { - 1 } mod q
**************************************************/
static int16_t
fqmul(int16_t a, int16_t b)
{
return montgomery_reduce((int32_t)a * b);
}
/*************************************************
* Name : ntt
*
* Description : Inplace number - theoretic transform ( NTT ) in Rq .
* input is in standard order , output is in bitreversed order
*
* Arguments : - int16_t r [ 256 ] : pointer to input / output vector of elements of Zq
**************************************************/
static void
ntt(int16_t r[256 ])
{
unsigned int len, start, j, k;
int16_t t, zeta;
k = 1 ;
for (len = 128 ; len >= 2 ; len >>= 1 ) {
for (start = 0 ; start < 256 ; start = j + len) {
zeta = zetas[k++];
for (j = start; j < start + len; j++) {
t = fqmul(zeta, r[j + len]);
r[j + len] = r[j] - t;
r[j] = r[j] + t;
}
}
}
}
/*************************************************
* Name : invntt_tomont
*
* Description : Inplace inverse number - theoretic transform in Rq and
* multiplication by Montgomery factor 2 ^ 16 .
* Input is in bitreversed order , output is in standard order
*
* Arguments : - int16_t r [ 256 ] : pointer to input / output vector of elements of Zq
**************************************************/
static void
invntt(int16_t r[256 ])
{
unsigned int start, len, j, k;
int16_t t, zeta;
const int16_t f = 1441 ; // mont^2/128
k = 127 ;
for (len = 2 ; len <= 128 ; len <<= 1 ) {
for (start = 0 ; start < 256 ; start = j + len) {
zeta = zetas[k--];
for (j = start; j < start + len; j++) {
t = r[j];
r[j] = barrett_reduce(t + r[j + len]);
r[j + len] = r[j + len] - t;
r[j + len] = fqmul(zeta, r[j + len]);
}
}
}
for (j = 0 ; j < 256 ; j++)
r[j] = fqmul(r[j], f);
}
/*************************************************
* Name : basemul
*
* Description : Multiplication of polynomials in Zq [ X ] / ( X ^ 2 - zeta )
* used for multiplication of elements in Rq in NTT domain
*
* Arguments : - int16_t r [ 2 ] : pointer to the output polynomial
* - const int16_t a [ 2 ] : pointer to the first factor
* - const int16_t b [ 2 ] : pointer to the second factor
* - int16_t zeta : integer defining the reduction polynomial
**************************************************/
static void
basemul(int16_t r[2 ], const int16_t a[2 ], const int16_t b[2 ], int16_t zeta)
{
r[0 ] = fqmul(a[1 ], b[1 ]);
r[0 ] = fqmul(r[0 ], zeta);
r[0 ] += fqmul(a[0 ], b[0 ]);
r[1 ] = fqmul(a[0 ], b[1 ]);
r[1 ] += fqmul(a[1 ], b[0 ]);
}
/** end: ref/ntt.c **/
/** begin: ref/poly.c **/
/*************************************************
* Name : poly_compress
*
* Description : Compression and subsequent serialization of a polynomial
*
* Arguments : - uint8_t * r : pointer to output byte array
* ( of length KYBER_POLYCOMPRESSEDBYTES )
* - const poly * a : pointer to input polynomial
**************************************************/
static void
poly_compress(uint8_t r[KYBER_POLYCOMPRESSEDBYTES], const poly *a)
{
unsigned int i, j;
int16_t u;
uint32_t d0;
uint8_t t[8 ];
#if (KYBER_POLYCOMPRESSEDBYTES == 128 )
for (i = 0 ; i < KYBER_N / 8 ; i++) {
for (j = 0 ; j < 8 ; j++) {
// map to positive standard representatives
u = a->coeffs[8 * i + j];
u += (u >> 15 ) & KYBER_Q;
/* t[j] = ((((uint16_t)u << 4) + KYBER_Q/2)/KYBER_Q) & 15; */
d0 = u << 4 ;
d0 += 1665 ;
d0 *= 80635 ;
d0 >>= 28 ;
t[j] = d0 & 0 xf;
}
r[0 ] = t[0 ] | (t[1 ] << 4 );
r[1 ] = t[2 ] | (t[3 ] << 4 );
r[2 ] = t[4 ] | (t[5 ] << 4 );
r[3 ] = t[6 ] | (t[7 ] << 4 );
r += 4 ;
}
#elif (KYBER_POLYCOMPRESSEDBYTES == 160 )
for (i = 0 ; i < KYBER_N / 8 ; i++) {
for (j = 0 ; j < 8 ; j++) {
// map to positive standard representatives
u = a->coeffs[8 * i + j];
u += (u >> 15 ) & KYBER_Q;
/* t[j] = ((((uint32_t)u << 5) + KYBER_Q/2)/KYBER_Q) & 31; */
d0 = u << 5 ;
d0 += 1664 ;
d0 *= 40318 ;
d0 >>= 27 ;
t[j] = d0 & 0 x1f;
}
r[0 ] = (t[0 ] >> 0 ) | (t[1 ] << 5 );
r[1 ] = (t[1 ] >> 3 ) | (t[2 ] << 2 ) | (t[3 ] << 7 );
r[2 ] = (t[3 ] >> 1 ) | (t[4 ] << 4 );
r[3 ] = (t[4 ] >> 4 ) | (t[5 ] << 1 ) | (t[6 ] << 6 );
r[4 ] = (t[6 ] >> 2 ) | (t[7 ] << 3 );
r += 5 ;
}
#else
#error "KYBER_POLYCOMPRESSEDBYTES needs to be in {128, 160}"
#endif
}
/*************************************************
* Name : poly_decompress
*
* Description : De - serialization and subsequent decompression of a polynomial ;
* approximate inverse of poly_compress
*
* Arguments : - poly * r : pointer to output polynomial
* - const uint8_t * a : pointer to input byte array
* ( of length KYBER_POLYCOMPRESSEDBYTES bytes )
**************************************************/
static void
poly_decompress(poly *r, const uint8_t a[KYBER_POLYCOMPRESSEDBYTES])
{
unsigned int i;
#if (KYBER_POLYCOMPRESSEDBYTES == 128 )
for (i = 0 ; i < KYBER_N / 2 ; i++) {
r->coeffs[2 * i + 0 ] = (((uint16_t)(a[0 ] & 15 ) * KYBER_Q) + 8 ) >> 4 ;
r->coeffs[2 * i + 1 ] = (((uint16_t)(a[0 ] >> 4 ) * KYBER_Q) + 8 ) >> 4 ;
a += 1 ;
}
#elif (KYBER_POLYCOMPRESSEDBYTES == 160 )
unsigned int j;
uint8_t t[8 ];
for (i = 0 ; i < KYBER_N / 8 ; i++) {
t[0 ] = (a[0 ] >> 0 );
t[1 ] = (a[0 ] >> 5 ) | (a[1 ] << 3 );
t[2 ] = (a[1 ] >> 2 );
t[3 ] = (a[1 ] >> 7 ) | (a[2 ] << 1 );
t[4 ] = (a[2 ] >> 4 ) | (a[3 ] << 4 );
t[5 ] = (a[3 ] >> 1 );
t[6 ] = (a[3 ] >> 6 ) | (a[4 ] << 2 );
t[7 ] = (a[4 ] >> 3 );
a += 5 ;
for (j = 0 ; j < 8 ; j++)
r->coeffs[8 * i + j] = ((uint32_t)(t[j] & 31 ) * KYBER_Q + 16 ) >> 5 ;
}
#else
#error "KYBER_POLYCOMPRESSEDBYTES needs to be in {128, 160}"
#endif
}
/*************************************************
* Name : poly_tobytes
*
* Description : Serialization of a polynomial
*
* Arguments : - uint8_t * r : pointer to output byte array
* ( needs space for KYBER_POLYBYTES bytes )
* - const poly * a : pointer to input polynomial
**************************************************/
static void
poly_tobytes(uint8_t r[KYBER_POLYBYTES], const poly *a)
{
unsigned int i;
uint16_t t0, t1;
for (i = 0 ; i < KYBER_N / 2 ; i++) {
// map to positive standard representatives
t0 = a->coeffs[2 * i];
t0 += ((int16_t)t0 >> 15 ) & KYBER_Q;
t1 = a->coeffs[2 * i + 1 ];
t1 += ((int16_t)t1 >> 15 ) & KYBER_Q;
r[3 * i + 0 ] = (t0 >> 0 );
r[3 * i + 1 ] = (t0 >> 8 ) | (t1 << 4 );
r[3 * i + 2 ] = (t1 >> 4 );
}
}
/*************************************************
* Name : poly_frombytes
*
* Description : De - serialization of a polynomial ;
* inverse of poly_tobytes
*
* Arguments : - poly * r : pointer to output polynomial
* - const uint8_t * a : pointer to input byte array
* ( of KYBER_POLYBYTES bytes )
**************************************************/
static void
poly_frombytes(poly *r, const uint8_t a[KYBER_POLYBYTES])
{
unsigned int i;
for (i = 0 ; i < KYBER_N / 2 ; i++) {
r->coeffs[2 * i] = ((a[3 * i + 0 ] >> 0 ) | ((uint16_t)a[3 * i + 1 ] << 8 )) & 0 xFFF;
r->coeffs[2 * i + 1 ] = ((a[3 * i + 1 ] >> 4 ) | ((uint16_t)a[3 * i + 2 ] << 4 )) & 0 xFFF;
}
}
/*************************************************
* Name : poly_frommsg
*
* Description : Convert 32 - byte message to polynomial
*
* Arguments : - poly * r : pointer to output polynomial
* - const uint8_t * msg : pointer to input message
**************************************************/
static void
poly_frommsg(poly *r, const uint8_t msg[KYBER_INDCPA_MSGBYTES])
{
unsigned int i, j;
int16_t mask;
#if (KYBER_INDCPA_MSGBYTES != KYBER_N / 8 )
#error "KYBER_INDCPA_MSGBYTES must be equal to KYBER_N/8 bytes!"
#endif
for (i = 0 ; i < KYBER_N / 8 ; i++) {
for (j = 0 ; j < 8 ; j++) {
mask = -(int16_t)((msg[i] >> j) & 1 );
r->coeffs[8 * i + j] = mask & ((KYBER_Q + 1 ) / 2 );
}
}
}
/*************************************************
* Name : poly_tomsg
*
* Description : Convert polynomial to 32 - byte message
*
* Arguments : - uint8_t * msg : pointer to output message
* - const poly * a : pointer to input polynomial
**************************************************/
static void
poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *a)
{
unsigned int i, j;
uint32_t t;
for (i = 0 ; i < KYBER_N / 8 ; i++) {
msg[i] = 0 ;
for (j = 0 ; j < 8 ; j++) {
t = a->coeffs[8 * i + j];
// t += ((int16_t)t >> 15) & KYBER_Q;
// t = (((t << 1) + KYBER_Q/2)/KYBER_Q) & 1;
t <<= 1 ;
t += 1665 ;
t *= 80635 ;
t >>= 28 ;
t &= 1 ;
msg[i] |= t << j;
}
}
}
/*************************************************
* Name : poly_getnoise_eta1
*
* Description : Sample a polynomial deterministically from a seed and a nonce ,
* with output polynomial close to centered binomial distribution
* with parameter KYBER_ETA1
*
* Arguments : - poly * r : pointer to output polynomial
* - const uint8_t * seed : pointer to input seed
* ( of length KYBER_SYMBYTES bytes )
* - uint8_t nonce : one - byte input nonce
**************************************************/
static void
poly_getnoise_eta1(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce)
{
uint8_t buf[KYBER_ETA1 * KYBER_N / 4 ];
prf(buf, sizeof (buf), seed, nonce);
poly_cbd_eta1(r, buf);
}
/*************************************************
* Name : poly_getnoise_eta2
*
* Description : Sample a polynomial deterministically from a seed and a nonce ,
* with output polynomial close to centered binomial distribution
* with parameter KYBER_ETA2
*
* Arguments : - poly * r : pointer to output polynomial
* - const uint8_t * seed : pointer to input seed
* ( of length KYBER_SYMBYTES bytes )
* - uint8_t nonce : one - byte input nonce
**************************************************/
static void
poly_getnoise_eta2(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce)
{
uint8_t buf[KYBER_ETA2 * KYBER_N / 4 ];
prf(buf, sizeof (buf), seed, nonce);
poly_cbd_eta2(r, buf);
}
/*************************************************
* Name : poly_ntt
*
* Description : Computes negacyclic number - theoretic transform ( NTT ) of
* a polynomial in place ;
* inputs assumed to be in normal order , output in bitreversed order
*
* Arguments : - uint16_t * r : pointer to in / output polynomial
**************************************************/
static void
poly_ntt(poly *r)
{
ntt(r->coeffs);
poly_reduce(r);
}
/*************************************************
* Name : poly_invntt_tomont
*
* Description : Computes inverse of negacyclic number - theoretic transform ( NTT )
* of a polynomial in place ;
* inputs assumed to be in bitreversed order , output in normal order
*
* Arguments : - uint16_t * a : pointer to in / output polynomial
**************************************************/
static void
poly_invntt_tomont(poly *r)
{
invntt(r->coeffs);
}
/*************************************************
* Name : poly_basemul_montgomery
*
* Description : Multiplication of two polynomials in NTT domain
*
* Arguments : - poly * r : pointer to output polynomial
* - const poly * a : pointer to first input polynomial
* - const poly * b : pointer to second input polynomial
**************************************************/
static void
poly_basemul_montgomery(poly *r, const poly *a, const poly *b)
{
unsigned int i;
for (i = 0 ; i < KYBER_N / 4 ; i++) {
basemul(&r->coeffs[4 * i], &a->coeffs[4 * i], &b->coeffs[4 * i], zetas[64 + i]);
basemul(&r->coeffs[4 * i + 2 ], &a->coeffs[4 * i + 2 ], &b->coeffs[4 * i + 2 ], -zetas[64 + i]);
}
}
/*************************************************
* Name : poly_tomont
*
* Description : Inplace conversion of all coefficients of a polynomial
* from normal domain to Montgomery domain
*
* Arguments : - poly * r : pointer to input / output polynomial
**************************************************/
static void
poly_tomont(poly *r)
{
unsigned int i;
const int16_t f = (1 ULL << 32 ) % KYBER_Q;
for (i = 0 ; i < KYBER_N; i++)
r->coeffs[i] = montgomery_reduce((int32_t)r->coeffs[i] * f);
}
/*************************************************
* Name : poly_reduce
*
* Description : Applies Barrett reduction to all coefficients of a polynomial
* for details of the Barrett reduction see comments in reduce . c
*
* Arguments : - poly * r : pointer to input / output polynomial
**************************************************/
static void
poly_reduce(poly *r)
{
unsigned int i;
for (i = 0 ; i < KYBER_N; i++)
r->coeffs[i] = barrett_reduce(r->coeffs[i]);
}
/*************************************************
* Name : poly_add
*
* Description : Add two polynomials ; no modular reduction is performed
*
* Arguments : - poly * r : pointer to output polynomial
* - const poly * a : pointer to first input polynomial
* - const poly * b : pointer to second input polynomial
**************************************************/
static void
poly_add(poly *r, const poly *a, const poly *b)
{
unsigned int i;
for (i = 0 ; i < KYBER_N; i++)
r->coeffs[i] = a->coeffs[i] + b->coeffs[i];
}
/*************************************************
* Name : poly_sub
*
* Description : Subtract two polynomials ; no modular reduction is performed
*
* Arguments : - poly * r : pointer to output polynomial
* - const poly * a : pointer to first input polynomial
* - const poly * b : pointer to second input polynomial
**************************************************/
static void
poly_sub(poly *r, const poly *a, const poly *b)
{
unsigned int i;
for (i = 0 ; i < KYBER_N; i++)
r->coeffs[i] = a->coeffs[i] - b->coeffs[i];
}
/** end: ref/poly.c **/
/** begin: ref/polyvec.c **/
/*************************************************
* Name : polyvec_compress
*
* Description : Compress and serialize vector of polynomials
*
* Arguments : - uint8_t * r : pointer to output byte array
* ( needs space for KYBER_POLYVECCOMPRESSEDBYTES )
* - const polyvec * a : pointer to input vector of polynomials
**************************************************/
static void
polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a)
{
unsigned int i, j, k;
uint64_t d0;
#if (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 352 ))
uint16_t t[8 ];
for (i = 0 ; i < KYBER_K; i++) {
for (j = 0 ; j < KYBER_N / 8 ; j++) {
for (k = 0 ; k < 8 ; k++) {
t[k] = a->vec[i].coeffs[8 * j + k];
t[k] += ((int16_t)t[k] >> 15 ) & KYBER_Q;
/* t[k] = ((((uint32_t)t[k] << 11) + KYBER_Q/2)/KYBER_Q) & 0x7ff; */
d0 = t[k];
d0 <<= 11 ;
d0 += 1664 ;
d0 *= 645084 ;
d0 >>= 31 ;
t[k] = d0 & 0 x7ff;
}
r[0 ] = (t[0 ] >> 0 );
r[1 ] = (t[0 ] >> 8 ) | (t[1 ] << 3 );
r[2 ] = (t[1 ] >> 5 ) | (t[2 ] << 6 );
r[3 ] = (t[2 ] >> 2 );
r[4 ] = (t[2 ] >> 10 ) | (t[3 ] << 1 );
r[5 ] = (t[3 ] >> 7 ) | (t[4 ] << 4 );
r[6 ] = (t[4 ] >> 4 ) | (t[5 ] << 7 );
r[7 ] = (t[5 ] >> 1 );
r[8 ] = (t[5 ] >> 9 ) | (t[6 ] << 2 );
r[9 ] = (t[6 ] >> 6 ) | (t[7 ] << 5 );
r[10 ] = (t[7 ] >> 3 );
r += 11 ;
}
}
#elif (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 320 ))
uint16_t t[4 ];
for (i = 0 ; i < KYBER_K; i++) {
for (j = 0 ; j < KYBER_N / 4 ; j++) {
for (k = 0 ; k < 4 ; k++) {
t[k] = a->vec[i].coeffs[4 * j + k];
t[k] += ((int16_t)t[k] >> 15 ) & KYBER_Q;
/* t[k] = ((((uint32_t)t[k] << 10) + KYBER_Q/2)/ KYBER_Q) & 0x3ff; */
d0 = t[k];
d0 <<= 10 ;
d0 += 1665 ;
d0 *= 1290167 ;
d0 >>= 32 ;
t[k] = d0 & 0 x3ff;
}
r[0 ] = (t[0 ] >> 0 );
r[1 ] = (t[0 ] >> 8 ) | (t[1 ] << 2 );
r[2 ] = (t[1 ] >> 6 ) | (t[2 ] << 4 );
r[3 ] = (t[2 ] >> 4 ) | (t[3 ] << 6 );
r[4 ] = (t[3 ] >> 2 );
r += 5 ;
}
}
#else
#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}"
#endif
}
/*************************************************
* Name : polyvec_decompress
*
* Description : De - serialize and decompress vector of polynomials ;
* approximate inverse of polyvec_compress
*
* Arguments : - polyvec * r : pointer to output vector of polynomials
* - const uint8_t * a : pointer to input byte array
* ( of length KYBER_POLYVECCOMPRESSEDBYTES )
**************************************************/
static void
polyvec_decompress(polyvec *r, const uint8_t a[KYBER_POLYVECCOMPRESSEDBYTES])
{
unsigned int i, j, k;
#if (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 352 ))
uint16_t t[8 ];
for (i = 0 ; i < KYBER_K; i++) {
for (j = 0 ; j < KYBER_N / 8 ; j++) {
t[0 ] = (a[0 ] >> 0 ) | ((uint16_t)a[1 ] << 8 );
t[1 ] = (a[1 ] >> 3 ) | ((uint16_t)a[2 ] << 5 );
t[2 ] = (a[2 ] >> 6 ) | ((uint16_t)a[3 ] << 2 ) | ((uint16_t)a[4 ] << 10 );
t[3 ] = (a[4 ] >> 1 ) | ((uint16_t)a[5 ] << 7 );
t[4 ] = (a[5 ] >> 4 ) | ((uint16_t)a[6 ] << 4 );
t[5 ] = (a[6 ] >> 7 ) | ((uint16_t)a[7 ] << 1 ) | ((uint16_t)a[8 ] << 9 );
t[6 ] = (a[8 ] >> 2 ) | ((uint16_t)a[9 ] << 6 );
t[7 ] = (a[9 ] >> 5 ) | ((uint16_t)a[10 ] << 3 );
a += 11 ;
for (k = 0 ; k < 8 ; k++)
r->vec[i].coeffs[8 * j + k] = ((uint32_t)(t[k] & 0 x7FF) * KYBER_Q + 1024 ) >> 11 ;
}
}
#elif (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 320 ))
uint16_t t[4 ];
for (i = 0 ; i < KYBER_K; i++) {
for (j = 0 ; j < KYBER_N / 4 ; j++) {
t[0 ] = (a[0 ] >> 0 ) | ((uint16_t)a[1 ] << 8 );
t[1 ] = (a[1 ] >> 2 ) | ((uint16_t)a[2 ] << 6 );
t[2 ] = (a[2 ] >> 4 ) | ((uint16_t)a[3 ] << 4 );
t[3 ] = (a[3 ] >> 6 ) | ((uint16_t)a[4 ] << 2 );
a += 5 ;
for (k = 0 ; k < 4 ; k++)
r->vec[i].coeffs[4 * j + k] = ((uint32_t)(t[k] & 0 x3FF) * KYBER_Q + 512 ) >> 10 ;
}
}
#else
#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}"
#endif
}
/*************************************************
* Name : polyvec_tobytes
*
* Description : Serialize vector of polynomials
*
* Arguments : - uint8_t * r : pointer to output byte array
* ( needs space for KYBER_POLYVECBYTES )
* - const polyvec * a : pointer to input vector of polynomials
**************************************************/
static void
polyvec_tobytes(uint8_t r[KYBER_POLYVECBYTES], const polyvec *a)
{
unsigned int i;
for (i = 0 ; i < KYBER_K; i++)
poly_tobytes(r + i * KYBER_POLYBYTES, &a->vec[i]);
}
/*************************************************
* Name : polyvec_frombytes
*
* Description : De - serialize vector of polynomials ;
* inverse of polyvec_tobytes
*
* Arguments : - uint8_t * r : pointer to output byte array
* - const polyvec * a : pointer to input vector of polynomials
* ( of length KYBER_POLYVECBYTES )
**************************************************/
static void
polyvec_frombytes(polyvec *r, const uint8_t a[KYBER_POLYVECBYTES])
{
unsigned int i;
for (i = 0 ; i < KYBER_K; i++)
poly_frombytes(&r->vec[i], a + i * KYBER_POLYBYTES);
}
/*************************************************
* Name : polyvec_ntt
*
* Description : Apply forward NTT to all elements of a vector of polynomials
*
* Arguments : - polyvec * r : pointer to in / output vector of polynomials
**************************************************/
static void
polyvec_ntt(polyvec *r)
{
unsigned int i;
for (i = 0 ; i < KYBER_K; i++)
poly_ntt(&r->vec[i]);
}
/*************************************************
* Name : polyvec_invntt_tomont
*
* Description : Apply inverse NTT to all elements of a vector of polynomials
* and multiply by Montgomery factor 2 ^ 16
*
* Arguments : - polyvec * r : pointer to in / output vector of polynomials
**************************************************/
static void
polyvec_invntt_tomont(polyvec *r)
{
unsigned int i;
for (i = 0 ; i < KYBER_K; i++)
poly_invntt_tomont(&r->vec[i]);
}
/*************************************************
* Name : polyvec_basemul_acc_montgomery
*
* Description : Multiply elements of a and b in NTT domain , accumulate into r ,
* and multiply by 2 ^ - 16 .
*
* Arguments : - poly * r : pointer to output polynomial
* - const polyvec * a : pointer to first input vector of polynomials
* - const polyvec * b : pointer to second input vector of polynomials
**************************************************/
static void
polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, const polyvec *b)
{
unsigned int i;
poly t;
poly_basemul_montgomery(r, &a->vec[0 ], &b->vec[0 ]);
for (i = 1 ; i < KYBER_K; i++) {
poly_basemul_montgomery(&t, &a->vec[i], &b->vec[i]);
poly_add(r, r, &t);
}
poly_reduce(r);
}
/*************************************************
* Name : polyvec_reduce
*
* Description : Applies Barrett reduction to each coefficient
* of each element of a vector of polynomials ;
* for details of the Barrett reduction see comments in reduce . c
*
* Arguments : - polyvec * r : pointer to input / output polynomial
**************************************************/
static void
polyvec_reduce(polyvec *r)
{
unsigned int i;
for (i = 0 ; i < KYBER_K; i++)
poly_reduce(&r->vec[i]);
}
/*************************************************
* Name : polyvec_add
*
* Description : Add vectors of polynomials
*
* Arguments : - polyvec * r : pointer to output vector of polynomials
* - const polyvec * a : pointer to first input vector of polynomials
* - const polyvec * b : pointer to second input vector of polynomials
**************************************************/
static void
polyvec_add(polyvec *r, const polyvec *a, const polyvec *b)
{
unsigned int i;
for (i = 0 ; i < KYBER_K; i++)
poly_add(&r->vec[i], &a->vec[i], &b->vec[i]);
}
/** end: ref/polyvec.c **/
/** begin: ref/indcpa.c **/
/*************************************************
* 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;
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;
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)
{
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])
{
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)
{
polyvec_compress(r, b);
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])
{
polyvec_decompress(b, c);
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 uniformly 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, pos;
uint16_t val0, val1;
ctr = pos = 0 ;
while (ctr < len && pos + 3 <= buflen) {
val0 = ((buf[pos + 0 ] >> 0 ) | ((uint16_t)buf[pos + 1 ] << 8 )) & 0 xFFF;
val1 = ((buf[pos + 1 ] >> 4 ) | ((uint16_t)buf[pos + 2 ] << 4 )) & 0 xFFF;
pos += 3 ;
if (val0 < KYBER_Q)
r[ctr++] = val0;
if (ctr < len && val1 < KYBER_Q)
r[ctr++] = val1;
}
return ctr;
}
#define gen_a(A, B) gen_matrix(A, B, 0 )
#define gen_at(A, B) gen_matrix(A, B, 1 )
/*************************************************
* Name : 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 ((12 * KYBER_N / 8 * (1 << 12 ) / KYBER_Q + XOF_BLOCKBYTES) / XOF_BLOCKBYTES)
// Not static for benchmarking
static void
gen_matrix(polyvec *a, const uint8_t seed[KYBER_SYMBYTES], int transposed)
{
unsigned int ctr, i, j, k;
unsigned int buflen, off;
uint8_t buf[GEN_MATRIX_NBLOCKS * XOF_BLOCKBYTES + 2 ];
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);
buflen = GEN_MATRIX_NBLOCKS * XOF_BLOCKBYTES;
ctr = rej_uniform(a[i].vec[j].coeffs, KYBER_N, buf, buflen);
while (ctr < KYBER_N) {
off = buflen % 3 ;
for (k = 0 ; k < off; k++)
buf[k] = buf[buflen - off + k];
xof_squeezeblocks(buf + off, 1 , &state);
buflen = off + XOF_BLOCKBYTES;
ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf, buflen);
}
}
}
}
/*************************************************
* Name : indcpa_keypair_derand
*
* 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 )
* - const uint8_t * coins : pointer to input randomness
* ( of length KYBER_SYMBYTES bytes )
**************************************************/
static void
indcpa_keypair_derand(uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES],
uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES],
const uint8_t coins[KYBER_SYMBYTES])
{
unsigned int i;
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;
hash_g(buf, coins, KYBER_SYMBYTES);
gen_a(a, publicseed);
for (i = 0 ; i < KYBER_K; i++)
poly_getnoise_eta1(&skpv.vec[i], noiseseed, nonce++);
for (i = 0 ; i < KYBER_K; i++)
poly_getnoise_eta1(&e.vec[i], noiseseed, nonce++);
polyvec_ntt(&skpv);
polyvec_ntt(&e);
// matrix-vector multiplication
for (i = 0 ; i < KYBER_K; i++) {
polyvec_basemul_acc_montgomery(&pkpv.vec[i], &a[i], &skpv);
poly_tomont(&pkpv.vec[i]);
}
polyvec_add(&pkpv, &pkpv, &e);
polyvec_reduce(&pkpv);
pack_sk(sk, &skpv);
pack_pk(pk, &pkpv, publicseed);
}
/*************************************************
* Name : 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
**************************************************/
static void
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;
uint8_t seed[KYBER_SYMBYTES];
uint8_t nonce = 0 ;
polyvec sp, pkpv, ep, at[KYBER_K], b;
poly v, k, epp;
unpack_pk(&pkpv, seed, pk);
poly_frommsg(&k, m);
gen_at(at, seed);
for (i = 0 ; i < KYBER_K; i++)
poly_getnoise_eta1(sp.vec + i, coins, nonce++);
for (i = 0 ; i < KYBER_K; i++)
poly_getnoise_eta2(ep.vec + i, coins, nonce++);
poly_getnoise_eta2(&epp, coins, nonce++);
polyvec_ntt(&sp);
// matrix-vector multiplication
for (i = 0 ; i < KYBER_K; i++)
polyvec_basemul_acc_montgomery(&b.vec[i], &at[i], &sp);
polyvec_basemul_acc_montgomery(&v, &pkpv, &sp);
polyvec_invntt_tomont(&b);
poly_invntt_tomont(&v);
polyvec_add(&b, &b, &ep);
poly_add(&v, &v, &epp);
poly_add(&v, &v, &k);
polyvec_reduce(&b);
poly_reduce(&v);
pack_ciphertext(c, &b, &v);
}
/*************************************************
* Name : 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 )
**************************************************/
static void
indcpa_dec(uint8_t m[KYBER_INDCPA_MSGBYTES],
const uint8_t c[KYBER_INDCPA_BYTES],
const uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES])
{
polyvec b, skpv;
poly v, mp;
unpack_ciphertext(&b, &v, c);
unpack_sk(&skpv, sk);
polyvec_ntt(&b);
polyvec_basemul_acc_montgomery(&mp, &skpv, &b);
poly_invntt_tomont(&mp);
poly_sub(&mp, &v, &mp);
poly_reduce(&mp);
poly_tomsg(m, &mp);
}
/** end: ref/indcpa.c **/
/** begin: ref/fips202.c **/
/* Based on the public domain implementation in crypto_hash/keccakc512/simple/ from
* http : //bench.cr.yp.to/supercop.html by Ronny Van Keer and the public domain "TweetFips202"
* implementation from https : //twitter.com/tweetfips202 by Gilles Van Assche, Daniel J. Bernstein,
* and Peter Schwabe */
#define NROUNDS 24
#define ROL(a, offset) ((a << offset) ^ (a >> (64 - offset)))
/*************************************************
* Name : load64
*
* Description : Load 8 bytes into uint64_t in little - endian order
*
* Arguments : - const uint8_t * x : pointer to input byte array
*
* Returns the loaded 64 - bit unsigned integer
**************************************************/
static uint64_t
load64(const uint8_t x[8 ])
{
unsigned int i;
uint64_t r = 0 ;
for (i = 0 ; i < 8 ; i++)
r |= (uint64_t)x[i] << 8 * i;
return r;
}
/*************************************************
* Name : store64
*
* Description : Store a 64 - bit integer to array of 8 bytes in little - endian order
*
* Arguments : - uint8_t * x : pointer to the output byte array ( allocated )
* - uint64_t u : input 64 - bit unsigned integer
**************************************************/
static void
store64(uint8_t x[8 ], uint64_t u)
{
unsigned int i;
for (i = 0 ; i < 8 ; i++)
x[i] = u >> 8 * i;
}
/* Keccak round constants */
static const uint64_t KeccakF_RoundConstants[NROUNDS] = {
(uint64_t)0 x0000000000000001ULL,
(uint64_t)0 x0000000000008082ULL,
(uint64_t)0 x800000000000808aULL,
(uint64_t)0 x8000000080008000ULL,
(uint64_t)0 x000000000000808bULL,
(uint64_t)0 x0000000080000001ULL,
(uint64_t)0 x8000000080008081ULL,
(uint64_t)0 x8000000000008009ULL,
(uint64_t)0 x000000000000008aULL,
(uint64_t)0 x0000000000000088ULL,
(uint64_t)0 x0000000080008009ULL,
(uint64_t)0 x000000008000000aULL,
(uint64_t)0 x000000008000808bULL,
(uint64_t)0 x800000000000008bULL,
(uint64_t)0 x8000000000008089ULL,
(uint64_t)0 x8000000000008003ULL,
(uint64_t)0 x8000000000008002ULL,
(uint64_t)0 x8000000000000080ULL,
(uint64_t)0 x000000000000800aULL,
(uint64_t)0 x800000008000000aULL,
(uint64_t)0 x8000000080008081ULL,
(uint64_t)0 x8000000000008080ULL,
(uint64_t)0 x0000000080000001ULL,
(uint64_t)0 x8000000080008008ULL
};
/*************************************************
* Name : KeccakF1600_StatePermute
*
* Description : The Keccak F1600 Permutation
*
* Arguments : - uint64_t * state : pointer to input / output Keccak state
**************************************************/
static void
KeccakF1600_StatePermute(uint64_t state[25 ])
{
int round;
uint64_t Aba, Abe, Abi, Abo, Abu;
uint64_t Aga, Age, Agi, Ago, Agu;
uint64_t Aka, Ake, Aki, Ako, Aku;
uint64_t Ama, Ame, Ami, Amo, Amu;
uint64_t Asa, Ase, Asi, Aso, Asu;
uint64_t BCa, BCe, BCi, BCo, BCu;
uint64_t Da, De, Di, Do , Du;
uint64_t Eba, Ebe, Ebi, Ebo, Ebu;
uint64_t Ega, Ege, Egi, Ego, Egu;
uint64_t Eka, Eke, Eki, Eko, Eku;
uint64_t Ema, Eme, Emi, Emo, Emu;
uint64_t Esa, Ese, Esi, Eso, Esu;
// copyFromState(A, state)
Aba = state[0 ];
Abe = state[1 ];
Abi = state[2 ];
Abo = state[3 ];
Abu = state[4 ];
Aga = state[5 ];
Age = state[6 ];
Agi = state[7 ];
Ago = state[8 ];
Agu = state[9 ];
Aka = state[10 ];
Ake = state[11 ];
Aki = state[12 ];
Ako = state[13 ];
Aku = state[14 ];
Ama = state[15 ];
Ame = state[16 ];
Ami = state[17 ];
Amo = state[18 ];
Amu = state[19 ];
Asa = state[20 ];
Ase = state[21 ];
Asi = state[22 ];
Aso = state[23 ];
Asu = state[24 ];
for (round = 0 ; round < NROUNDS; round += 2 ) {
// prepareTheta
BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa;
BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase;
BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi;
BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso;
BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu;
// thetaRhoPiChiIotaPrepareTheta(round, A, E)
Da = BCu ^ ROL(BCe, 1 );
De = BCa ^ ROL(BCi, 1 );
Di = BCe ^ ROL(BCo, 1 );
Do = BCi ^ ROL(BCu, 1 );
Du = BCo ^ ROL(BCa, 1 );
Aba ^= Da;
BCa = Aba;
Age ^= De;
BCe = ROL(Age, 44 );
Aki ^= Di;
BCi = ROL(Aki, 43 );
Amo ^= Do ;
BCo = ROL(Amo, 21 );
Asu ^= Du;
BCu = ROL(Asu, 14 );
Eba = BCa ^ ((~BCe) & BCi);
Eba ^= (uint64_t)KeccakF_RoundConstants[round];
Ebe = BCe ^ ((~BCi) & BCo);
Ebi = BCi ^ ((~BCo) & BCu);
Ebo = BCo ^ ((~BCu) & BCa);
Ebu = BCu ^ ((~BCa) & BCe);
Abo ^= Do ;
BCa = ROL(Abo, 28 );
Agu ^= Du;
BCe = ROL(Agu, 20 );
Aka ^= Da;
BCi = ROL(Aka, 3 );
Ame ^= De;
BCo = ROL(Ame, 45 );
Asi ^= Di;
BCu = ROL(Asi, 61 );
Ega = BCa ^ ((~BCe) & BCi);
Ege = BCe ^ ((~BCi) & BCo);
Egi = BCi ^ ((~BCo) & BCu);
Ego = BCo ^ ((~BCu) & BCa);
Egu = BCu ^ ((~BCa) & BCe);
Abe ^= De;
BCa = ROL(Abe, 1 );
Agi ^= Di;
BCe = ROL(Agi, 6 );
Ako ^= Do ;
BCi = ROL(Ako, 25 );
Amu ^= Du;
BCo = ROL(Amu, 8 );
Asa ^= Da;
BCu = ROL(Asa, 18 );
Eka = BCa ^ ((~BCe) & BCi);
Eke = BCe ^ ((~BCi) & BCo);
Eki = BCi ^ ((~BCo) & BCu);
Eko = BCo ^ ((~BCu) & BCa);
Eku = BCu ^ ((~BCa) & BCe);
Abu ^= Du;
BCa = ROL(Abu, 27 );
Aga ^= Da;
BCe = ROL(Aga, 36 );
Ake ^= De;
BCi = ROL(Ake, 10 );
Ami ^= Di;
BCo = ROL(Ami, 15 );
Aso ^= Do ;
BCu = ROL(Aso, 56 );
Ema = BCa ^ ((~BCe) & BCi);
Eme = BCe ^ ((~BCi) & BCo);
Emi = BCi ^ ((~BCo) & BCu);
Emo = BCo ^ ((~BCu) & BCa);
Emu = BCu ^ ((~BCa) & BCe);
Abi ^= Di;
BCa = ROL(Abi, 62 );
Ago ^= Do ;
BCe = ROL(Ago, 55 );
Aku ^= Du;
BCi = ROL(Aku, 39 );
Ama ^= Da;
BCo = ROL(Ama, 41 );
Ase ^= De;
BCu = ROL(Ase, 2 );
Esa = BCa ^ ((~BCe) & BCi);
Ese = BCe ^ ((~BCi) & BCo);
Esi = BCi ^ ((~BCo) & BCu);
Eso = BCo ^ ((~BCu) & BCa);
Esu = BCu ^ ((~BCa) & BCe);
// prepareTheta
BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa;
BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese;
BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi;
BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso;
BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu;
// thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
Da = BCu ^ ROL(BCe, 1 );
De = BCa ^ ROL(BCi, 1 );
Di = BCe ^ ROL(BCo, 1 );
Do = BCi ^ ROL(BCu, 1 );
Du = BCo ^ ROL(BCa, 1 );
Eba ^= Da;
BCa = Eba;
Ege ^= De;
BCe = ROL(Ege, 44 );
Eki ^= Di;
BCi = ROL(Eki, 43 );
Emo ^= Do ;
BCo = ROL(Emo, 21 );
Esu ^= Du;
BCu = ROL(Esu, 14 );
Aba = BCa ^ ((~BCe) & BCi);
Aba ^= (uint64_t)KeccakF_RoundConstants[round + 1 ];
Abe = BCe ^ ((~BCi) & BCo);
Abi = BCi ^ ((~BCo) & BCu);
Abo = BCo ^ ((~BCu) & BCa);
Abu = BCu ^ ((~BCa) & BCe);
Ebo ^= Do ;
BCa = ROL(Ebo, 28 );
Egu ^= Du;
BCe = ROL(Egu, 20 );
Eka ^= Da;
BCi = ROL(Eka, 3 );
Eme ^= De;
BCo = ROL(Eme, 45 );
Esi ^= Di;
BCu = ROL(Esi, 61 );
Aga = BCa ^ ((~BCe) & BCi);
Age = BCe ^ ((~BCi) & BCo);
Agi = BCi ^ ((~BCo) & BCu);
Ago = BCo ^ ((~BCu) & BCa);
Agu = BCu ^ ((~BCa) & BCe);
Ebe ^= De;
BCa = ROL(Ebe, 1 );
Egi ^= Di;
BCe = ROL(Egi, 6 );
Eko ^= Do ;
BCi = ROL(Eko, 25 );
Emu ^= Du;
BCo = ROL(Emu, 8 );
Esa ^= Da;
BCu = ROL(Esa, 18 );
Aka = BCa ^ ((~BCe) & BCi);
Ake = BCe ^ ((~BCi) & BCo);
Aki = BCi ^ ((~BCo) & BCu);
Ako = BCo ^ ((~BCu) & BCa);
Aku = BCu ^ ((~BCa) & BCe);
Ebu ^= Du;
BCa = ROL(Ebu, 27 );
Ega ^= Da;
BCe = ROL(Ega, 36 );
Eke ^= De;
BCi = ROL(Eke, 10 );
Emi ^= Di;
BCo = ROL(Emi, 15 );
Eso ^= Do ;
BCu = ROL(Eso, 56 );
Ama = BCa ^ ((~BCe) & BCi);
Ame = BCe ^ ((~BCi) & BCo);
Ami = BCi ^ ((~BCo) & BCu);
Amo = BCo ^ ((~BCu) & BCa);
Amu = BCu ^ ((~BCa) & BCe);
Ebi ^= Di;
BCa = ROL(Ebi, 62 );
Ego ^= Do ;
BCe = ROL(Ego, 55 );
Eku ^= Du;
BCi = ROL(Eku, 39 );
Ema ^= Da;
BCo = ROL(Ema, 41 );
Ese ^= De;
BCu = ROL(Ese, 2 );
Asa = BCa ^ ((~BCe) & BCi);
Ase = BCe ^ ((~BCi) & BCo);
Asi = BCi ^ ((~BCo) & BCu);
Aso = BCo ^ ((~BCu) & BCa);
Asu = BCu ^ ((~BCa) & BCe);
}
// copyToState(state, A)
state[0 ] = Aba;
state[1 ] = Abe;
state[2 ] = Abi;
state[3 ] = Abo;
state[4 ] = Abu;
state[5 ] = Aga;
state[6 ] = Age;
state[7 ] = Agi;
state[8 ] = Ago;
state[9 ] = Agu;
state[10 ] = Aka;
state[11 ] = Ake;
state[12 ] = Aki;
state[13 ] = Ako;
state[14 ] = Aku;
state[15 ] = Ama;
state[16 ] = Ame;
state[17 ] = Ami;
state[18 ] = Amo;
state[19 ] = Amu;
state[20 ] = Asa;
state[21 ] = Ase;
state[22 ] = Asi;
state[23 ] = Aso;
state[24 ] = Asu;
}
/*************************************************
* Name : keccak_init
*
* Description : Initializes the Keccak state .
*
* Arguments : - uint64_t * s : pointer to Keccak state
**************************************************/
static void
keccak_init(uint64_t s[25 ])
{
unsigned int i;
for (i = 0 ; i < 25 ; i++)
s[i] = 0 ;
}
/*************************************************
* Name : keccak_absorb
*
* Description : Absorb step of Keccak ; incremental .
*
* Arguments : - uint64_t * s : pointer to Keccak state
* - unsigned int pos : position in current block to be absorbed
* - unsigned int r : rate in bytes ( e . g . , 168 for SHAKE128 )
* - const uint8_t * in : pointer to input to be absorbed into s
* - size_t inlen : length of input in bytes
*
* Returns new position pos in current block
**************************************************/
static unsigned int
keccak_absorb(uint64_t s[25 ],
unsigned int pos,
unsigned int r,
const uint8_t *in,
size_t inlen)
{
unsigned int i;
while (pos + inlen >= r) {
for (i = pos; i < r; i++)
s[i / 8 ] ^= (uint64_t)*in++ << 8 * (i % 8 );
inlen -= r - pos;
KeccakF1600_StatePermute(s);
pos = 0 ;
}
for (i = pos; i < pos + inlen; i++)
s[i / 8 ] ^= (uint64_t)*in++ << 8 * (i % 8 );
return i;
}
/*************************************************
* Name : keccak_finalize
*
* Description : Finalize absorb step .
*
* Arguments : - uint64_t * s : pointer to Keccak state
* - unsigned int pos : position in current block to be absorbed
* - unsigned int r : rate in bytes ( e . g . , 168 for SHAKE128 )
* - uint8_t p : domain separation byte
**************************************************/
static void
keccak_finalize(uint64_t s[25 ], unsigned int pos, unsigned int r, uint8_t p)
{
s[pos / 8 ] ^= (uint64_t)p << 8 * (pos % 8 );
s[r / 8 - 1 ] ^= 1 ULL << 63 ;
}
/*************************************************
* Name : keccak_squeeze
*
* Description : Squeeze step of Keccak . Squeezes arbitratrily many bytes .
* Modifies the state . Can be called multiple times to keep
* squeezing , i . e . , is incremental .
*
* Arguments : - uint8_t * out : pointer to output
* - size_t outlen : number of bytes to be squeezed ( written to out )
* - uint64_t * s : pointer to input / output Keccak state
* - unsigned int pos : number of bytes in current block already squeezed
* - unsigned int r : rate in bytes ( e . g . , 168 for SHAKE128 )
*
* Returns new position pos in current block
**************************************************/
static unsigned int
keccak_squeeze(uint8_t *out,
size_t outlen,
uint64_t s[25 ],
unsigned int pos,
unsigned int r)
{
unsigned int i;
while (outlen) {
if (pos == r) {
KeccakF1600_StatePermute(s);
pos = 0 ;
}
for (i = pos; i < r && i < pos + outlen; i++)
*out++ = s[i / 8 ] >> 8 * (i % 8 );
outlen -= i - pos;
pos = i;
}
return pos;
}
/*************************************************
* Name : keccak_absorb_once
*
* Description : Absorb step of Keccak ;
* non - incremental , starts by zeroeing the state .
*
* Arguments : - uint64_t * s : pointer to ( uninitialized ) output Keccak state
* - unsigned int r : rate in bytes ( e . g . , 168 for SHAKE128 )
* - const uint8_t * in : pointer to input to be absorbed into s
* - size_t inlen : length of input in bytes
* - uint8_t p : domain - separation byte for different Keccak - derived functions
**************************************************/
static void
keccak_absorb_once(uint64_t s[25 ],
unsigned int r,
const uint8_t *in,
size_t inlen,
uint8_t p)
{
unsigned int i;
for (i = 0 ; i < 25 ; i++)
s[i] = 0 ;
while (inlen >= r) {
for (i = 0 ; i < r / 8 ; i++)
s[i] ^= load64(in + 8 * i);
in += r;
inlen -= r;
KeccakF1600_StatePermute(s);
}
for (i = 0 ; i < inlen; i++)
s[i / 8 ] ^= (uint64_t)in[i] << 8 * (i % 8 );
s[i / 8 ] ^= (uint64_t)p << 8 * (i % 8 );
s[(r - 1 ) / 8 ] ^= 1 ULL << 63 ;
}
/*************************************************
* Name : keccak_squeezeblocks
*
* Description : Squeeze step of Keccak . Squeezes full blocks of r bytes each .
* Modifies the state . Can be called multiple times to keep
* squeezing , i . e . , is incremental . Assumes zero bytes of current
* block have already been squeezed .
*
* Arguments : - uint8_t * out : pointer to output blocks
* - size_t nblocks : number of blocks to be squeezed ( written to out )
* - uint64_t * s : pointer to input / output Keccak state
* - unsigned int r : rate in bytes ( e . g . , 168 for SHAKE128 )
**************************************************/
static void
keccak_squeezeblocks(uint8_t *out,
size_t nblocks,
uint64_t s[25 ],
unsigned int r)
{
unsigned int i;
while (nblocks) {
KeccakF1600_StatePermute(s);
for (i = 0 ; i < r / 8 ; i++)
store64(out + 8 * i, s[i]);
out += r;
nblocks -= 1 ;
}
}
/*************************************************
* Name : shake128_init
*
* Description : Initilizes Keccak state for use as SHAKE128 XOF
*
* Arguments : - keccak_state * state : pointer to ( uninitialized ) Keccak state
**************************************************/
void
shake128_init(keccak_state *state)
{
keccak_init(state->s);
state->pos = 0 ;
}
/*************************************************
* Name : shake128_absorb
*
* Description : Absorb step of the SHAKE128 XOF ; incremental .
*
* Arguments : - keccak_state * state : pointer to ( initialized ) output Keccak state
* - const uint8_t * in : pointer to input to be absorbed into s
* - size_t inlen : length of input in bytes
**************************************************/
void
shake128_absorb(keccak_state *state, const uint8_t *in, size_t inlen)
{
state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen);
}
/*************************************************
* Name : shake128_finalize
*
* Description : Finalize absorb step of the SHAKE128 XOF .
*
* Arguments : - keccak_state * state : pointer to Keccak state
**************************************************/
void
shake128_finalize(keccak_state *state)
{
keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0 x1F);
state->pos = SHAKE128_RATE;
}
/*************************************************
* Name : shake128_squeeze
*
* Description : Squeeze step of SHAKE128 XOF . Squeezes arbitraily many
* bytes . Can be called multiple times to keep squeezing .
*
* Arguments : - uint8_t * out : pointer to output blocks
* - size_t outlen : number of bytes to be squeezed ( written to output )
* - keccak_state * s : pointer to input / output Keccak state
**************************************************/
void
shake128_squeeze(uint8_t *out, size_t outlen, keccak_state *state)
{
state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE);
}
/*************************************************
* Name : shake128_absorb_once
*
* Description : Initialize , absorb into and finalize SHAKE128 XOF ; non - incremental .
*
* Arguments : - keccak_state * state : pointer to ( uninitialized ) output Keccak state
* - const uint8_t * in : pointer to input to be absorbed into s
* - size_t inlen : length of input in bytes
**************************************************/
void
shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen)
{
keccak_absorb_once(state->s, SHAKE128_RATE, in, inlen, 0 x1F);
state->pos = SHAKE128_RATE;
}
/*************************************************
* Name : shake128_squeezeblocks
*
* Description : Squeeze step of SHAKE128 XOF . Squeezes full blocks of
* SHAKE128_RATE bytes each . Can be called multiple times
* to keep squeezing . Assumes new block has not yet been
* started ( state - > pos = SHAKE128_RATE ) .
*
* Arguments : - uint8_t * out : pointer to output blocks
* - size_t nblocks : number of blocks to be squeezed ( written to output )
* - keccak_state * s : pointer to input / output Keccak state
**************************************************/
void
shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state)
{
java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
********************java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
* unsigned long parent_ratejava.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
Description:Initilizes Keccakstate for useasSHAKE256XOF
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
************/
shake256_init(keccak_state *state)
{
keccak_init(tate-s;
-> =0
}
********************
* Name: shake256_absorb
*
* Description: Absorb step of the SHAKE256 XOF; incremental.
*
:- *state pointer (nitialized output Keccakstate
* -const *n:pointer to to absorbed intos
* - size_t inlen:
*************/
/*
java.lang.StringIndexOutOfBoundsException: Range [42, 15) out of bounds for length 69
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
statep keccak_absorbstate-s state-pos SHAKE256_RATE in inlen;
}
/*************************************************
* Name : shake256_finalize
*
* Description : Finalize absorb step of the SHAKE256 XOF .
*
* Arguments : - keccak_state * state : pointer to Keccak state
**************************************************/
void
shake256_finalize(keccak_state *state)
{
keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0 x1F);
state->pos = SHAKE256_RATE;
}
/*************************************************
* Name : shake256_squeeze
*
* Description : Squeeze step of SHAKE256 XOF . Squeezes arbitraily many
* bytes . Can be called multiple times to keep squeezing .
*
* Arguments : - uint8_t * out : pointer to output blocks
* - size_t outlen : number of bytes to be squeezed ( written to output )
* - keccak_state * s : pointer to input / output Keccak state
**************************************************/
void
shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state)
{
state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE);
}
/*************************************************
* Name : shake256_absorb_once
*
* Description : Initialize , absorb into and finalize SHAKE256 XOF ; non - incremental .
*
* Arguments : - keccak_state * state : pointer to ( uninitialized ) output Keccak state
* - const uint8_t * in : pointer to input to be absorbed into s
* - size_t inlen : length of input in bytes
**************************************************/
void
shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen)
{
keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0 x1F);
state->pos = SHAKE256_RATE;
}
/*************************************************
* Name : shake256_squeezeblocks
*
* Description : Squeeze step of SHAKE256 XOF . Squeezes full blocks of
* SHAKE256_RATE bytes each . Can be called multiple times
* to keep squeezing . Assumes next block has not yet been
* started ( state - > pos = SHAKE256_RATE ) .
*
* Arguments : - uint8_t * out : pointer to output blocks
* - size_t nblocks : number of blocks to be squeezed ( written to output )
* - keccak_state * s : pointer to input / output Keccak state
**************************************************/
void
shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state)
{
keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE);
}
/*************************************************
* Name : shake128
*
* Description : SHAKE128 XOF with non - incremental API
*
* Arguments : - uint8_t * out : pointer to output
* - size_t outlen : requested output length in bytes
* - const uint8_t * in : pointer to input
* - size_t inlen : length of input in bytes
**************************************************/
void
shake128(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
{
size_t nblocks;
keccak_state state;
shake128_absorb_once(&state, in, inlen);
nblocks = outlen / SHAKE128_RATE;
shake128_squeezeblocks(out, nblocks, &state);
outlen -= nblocks * SHAKE128_RATE;
out += nblocks * SHAKE128_RATE;
shake128_squeeze(out, outlen, &state);
}
/*************************************************
* Name : shake256
*
* Description : SHAKE256 XOF with non - incremental API
*
* Arguments : - uint8_t * out : pointer to output
* - size_t outlen : requested output length in bytes
* - const uint8_t * in : pointer to input
* - size_t inlen : length of input in bytes
**************************************************/
void
shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
{
size_t nblocks;
keccak_state state;
shake256_absorb_once(&state, in, inlen);
nblocks = outlen / SHAKE256_RATE;
shake256_squeezeblocks(out, nblocks, &state);
outlen -= nblocks * SHAKE256_RATE;
out += nblocks * SHAKE256_RATE;
shake256_squeeze(out, outlen, &state);
}
/*************************************************
* Name : sha3_256
*
* Description : SHA3 - 256 with non - incremental API
*
* Arguments : - uint8_t * h : pointer to output ( 32 bytes )
* - const uint8_t * in : pointer to input
* - size_t inlen : length of input in bytes
**************************************************/
void
sha3_256(uint8_t h[32 ], const uint8_t *in, size_t inlen)
{
unsigned int i;
uint64_t s[25 ];
keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0 x06);
KeccakF1600_StatePermute(s);
for (i = 0 ; i < 4 ; i++)
store64(h + 8 * i, s[i]);
}
/*************************************************
* Name : sha3_512
*
* Description : SHA3 - 512 with non - incremental API
*
* Arguments : - uint8_t * h : pointer to output ( 64 bytes )
* - const uint8_t * in : pointer to input
* - size_t inlen : length of input in bytes
**************************************************/
void
sha3_512(uint8_t h[64 ], const uint8_t *in, size_t inlen)
{
unsigned int i;
uint64_t s[25 ];
keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0 x06);
KeccakF1600_StatePermute(s);
for (i = 0 ; i < 8 ; i++)
store64(h + 8 * i, s[i]);
}
/** end: ref/fips202.c **/
/** begin: ref/symmetric-shake.c **/
/*************************************************
* Name : kyber_shake128_absorb
*
* Description : Absorb step of the SHAKE128 specialized for the Kyber context .
*
* Arguments : - keccak_state * state : pointer to ( uninitialized ) output Keccak state
* - const uint8_t * seed : pointer to KYBER_SYMBYTES input to be absorbed into state
* - uint8_t i : additional byte of input
* - uint8_t j : additional byte of input
**************************************************/
static void
kyber_shake128_absorb(keccak_state *state,
const uint8_t seed[KYBER_SYMBYTES],
uint8_t x,
uint8_t y)
{
uint8_t extseed[KYBER_SYMBYTES + 2 ];
memcpy(extseed, seed, KYBER_SYMBYTES);
extseed[KYBER_SYMBYTES + 0 ] = x;
extseed[KYBER_SYMBYTES + 1 ] = y;
shake128_absorb_once(state, extseed, sizeof (extseed));
}
/*************************************************
* Name : kyber_shake256_prf
*
* Description : Usage of SHAKE256 as a PRF , concatenates secret and public input
* and then generates outlen bytes of SHAKE256 output
*
* Arguments : - uint8_t * out : pointer to output
* - size_t outlen : number of requested output bytes
* - const uint8_t * key : pointer to the key ( of length KYBER_SYMBYTES )
* - uint8_t nonce : single - byte nonce ( public PRF input )
**************************************************/
static void
kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce)
{
uint8_t extkey[KYBER_SYMBYTES + 1 ];
memcpy(extkey, key, KYBER_SYMBYTES);
extkey[KYBER_SYMBYTES] = nonce;
shake256(out, outlen, extkey, sizeof (extkey));
}
/** end: ref/symmetric-shake.c **/
/** begin: ref/kem.c **/
/*************************************************
* Name : crypto_kem_keypair_derand
*
* Description : Generates public and private key
* for CCA - secure Kyber key encapsulation mechanism
*
* Arguments : - uint8_t * pk : pointer to output public key
* ( an already allocated array of KYBER_PUBLICKEYBYTES bytes )
* - uint8_t * sk : pointer to output private key
* ( an already allocated array of KYBER_SECRETKEYBYTES bytes )
* - uint8_t * coins : pointer to input randomness
* ( an already allocated array filled with 2 * KYBER_SYMBYTES random bytes )
* *
* Returns 0 ( success )
**************************************************/
int
crypto_kem_keypair_derand(uint8_t *pk,
uint8_t *sk,
const uint8_t *coins)
{
size_t i;
indcpa_keypair_derand(pk, sk, coins);
for (i = 0 ; i < KYBER_INDCPA_PUBLICKEYBYTES; i++)
sk[i + KYBER_INDCPA_SECRETKEYBYTES] = pk[i];
hash_h(sk + KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES);
/* Value z for pseudo-random output on reject */
for (i = 0 ; i < KYBER_SYMBYTES; i++)
sk[KYBER_SECRETKEYBYTES - KYBER_SYMBYTES + i] = coins[KYBER_SYMBYTES + i];
return 0 ;
}
/*************************************************
* Name : crypto_kem_keypair
*
* Description : Generates public and private key
* for CCA - secure Kyber key encapsulation mechanism
*
* Arguments : - uint8_t * pk : pointer to output public key
* ( an already allocated array of KYBER_PUBLICKEYBYTES bytes )
* - uint8_t * sk : pointer to output private key
* ( an already allocated array of KYBER_SECRETKEYBYTES bytes )
*
* Returns 0 ( success )
**************************************************/
int
crypto_kem_keypair(uint8_t *pk,
uint8_t *sk)
{
uint8_t coins[2 * KYBER_SYMBYTES];
randombytes(coins, KYBER_SYMBYTES);
randombytes(coins + KYBER_SYMBYTES, KYBER_SYMBYTES);
crypto_kem_keypair_derand(pk, sk, coins);
return 0 ;
}
/*************************************************
* Name : crypto_kem_enc_derand
*
* Description : Generates cipher text and shared
* secret for given public key
*
* Arguments : - uint8_t * ct : pointer to output cipher text
* ( an already allocated array of KYBER_CIPHERTEXTBYTES bytes )
* - uint8_t * ss : pointer to output shared secret
* ( an already allocated array of KYBER_SSBYTES bytes )
* - const uint8_t * pk : pointer to input public key
* ( an already allocated array of KYBER_PUBLICKEYBYTES bytes )
* - const uint8_t * coins : pointer to input randomness
* ( an already allocated array filled with KYBER_SYMBYTES random bytes )
* *
* Returns 0 ( success )
**************************************************/
int
crypto_kem_enc_derand(uint8_t *ct,
uint8_t *ss,
const uint8_t *pk,
const uint8_t *coins)
{
uint8_t buf[2 * KYBER_SYMBYTES];
/* Will contain key, coins */
uint8_t kr[2 * KYBER_SYMBYTES];
/* Don't release system RNG output */
hash_h(buf, coins, KYBER_SYMBYTES);
/* Multitarget countermeasure for coins + contributory KEM */
hash_h(buf + KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES);
hash_g(kr, buf, 2 * KYBER_SYMBYTES);
/* coins are in kr+KYBER_SYMBYTES */
indcpa_enc(ct, buf, pk, kr + KYBER_SYMBYTES);
/* overwrite coins in kr with H(c) */
hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES);
/* hash concatenation of pre-k and H(c) to k */
kdf(ss, kr, 2 * KYBER_SYMBYTES);
return 0 ;
}
/*************************************************
* Name : crypto_kem_enc
*
* Description : Generates cipher text and shared
* secret for given public key
*
* Arguments : - uint8_t * ct : pointer to output cipher text
* ( an already allocated array of KYBER_CIPHERTEXTBYTES bytes )
* - uint8_t * ss : pointer to output shared secret
* ( an already allocated array of KYBER_SSBYTES bytes )
* - const uint8_t * pk : pointer to input public key
* ( an already allocated array of KYBER_PUBLICKEYBYTES bytes )
*
* Returns 0 ( success )
**************************************************/
int
crypto_kem_enc(uint8_t *ct,
uint8_t *ss,
const uint8_t *pk)
{
uint8_t coins[KYBER_SYMBYTES];
randombytes(coins, KYBER_SYMBYTES);
crypto_kem_enc_derand(ct, ss, pk, coins);
return 0 ;
}
/*************************************************
* Name : crypto_kem_dec
*
* Description : Generates shared secret for given
* cipher text and private key
*
* Arguments : - uint8_t * ss : pointer to output shared secret
* ( an already allocated array of KYBER_SSBYTES bytes )
* - const uint8_t * ct : pointer to input cipher text
* ( an already allocated array of KYBER_CIPHERTEXTBYTES bytes )
* - const uint8_t * sk : pointer to input private key
* ( an already allocated array of KYBER_SECRETKEYBYTES bytes )
*
* Returns 0 .
*
* On failure , ss will contain a pseudo - random value .
**************************************************/
int
crypto_kem_dec(uint8_t *ss,
const uint8_t *ct,
const uint8_t *sk)
{
size_t i;
int fail;
uint8_t buf[2 * KYBER_SYMBYTES];
/* Will contain key, coins */
uint8_t kr[2 * KYBER_SYMBYTES];
uint8_t cmp[KYBER_CIPHERTEXTBYTES];
const uint8_t *pk = sk + KYBER_INDCPA_SECRETKEYBYTES;
indcpa_dec(buf, ct, sk);
/* Multitarget countermeasure for coins + contributory KEM */
for (i = 0 ; i < KYBER_SYMBYTES; i++)
buf[KYBER_SYMBYTES + i] = sk[KYBER_SECRETKEYBYTES - 2 * KYBER_SYMBYTES + i];
hash_g(kr, buf, 2 * KYBER_SYMBYTES);
/* coins are in kr+KYBER_SYMBYTES */
indcpa_enc(cmp, buf, pk, kr + KYBER_SYMBYTES);
fail = verify(ct, cmp, KYBER_CIPHERTEXTBYTES);
/* overwrite coins in kr with H(c) */
hash_h(kr + KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES);
/* Overwrite pre-k with z on re-encryption failure */
cmov(kr, sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, KYBER_SYMBYTES, fail);
/* hash concatenation of pre-k and H(c) to k */
kdf(ss, kr, 2 * KYBER_SYMBYTES);
return 0 ;
}
/** end: ref/kem.c **/
Messung V0.5 in Prozent C=94 H=94 G=93
¤ Dauer der Verarbeitung: 0.63 Sekunden
(vorverarbeitet am 2026-10-11)
¤
*© Formatika GbR, Deutschland