-rw-r--r-- 6470 libntruprime-20240825/src/kem/sntrupP/factored/kem.c raw
#include "params.h"
#include "randombytes.h"
#include "crypto_hash_sha512.h"
#include "crypto_sort_uint32.h"
#include "crypto_declassify.h"
#include "crypto_int8.h"
#include "crypto_int16.h"
#include "crypto_int32.h"
#include "crypto_uint16.h"
#include "crypto_uint32.h"
#define int8 crypto_int8
#define int16 crypto_int16
#define int32 crypto_int32
#define uint16 crypto_uint16
#define uint32 crypto_uint32
/* ----- arithmetic mod 3 */
typedef int8 small;
/* F3 is always represented as -1,0,1 */
/* ----- arithmetic mod q */
typedef int16 Fq;
/* always represented as -(q-1)/2...(q-1)/2 */
/* ----- small polynomials */
/* R3_fromR(R_fromRq(r)) */
static void R3_fromRq(small *out,const Fq *r)
{
crypto_encode_pxfreeze3((unsigned char *) out,(unsigned char *) r);
}
/* h = f*g in the ring R3 */
static void R3_mult(small *h,const small *f,const small *g)
{
crypto_core_mult3((unsigned char *) h,(const unsigned char *) f,(const unsigned char *) g,0);
}
/* ----- polynomials mod q */
/* h = h*g in the ring Rq */
static void Rq_mult_small(Fq *h,const small *g)
{
crypto_encode_pxint16((unsigned char *) h,h);
crypto_core_mult((unsigned char *) h,(const unsigned char *) h,(const unsigned char *) g,0);
crypto_decode_pxint16(h,(const unsigned char *) h);
}
/* h = 3f in Rq */
static void Rq_mult3(Fq *h,const Fq *f)
{
crypto_encode_pxint16((unsigned char *) h,f);
crypto_core_scale3((unsigned char *) h,(const unsigned char *) h,0,0);
crypto_decode_pxint16(h,(const unsigned char *) h);
}
/* out = 1/(3*in) in Rq */
/* caller must have 2p+1 bytes free in out, not just 2p */
static void Rq_recip3(Fq *out,const small *in)
{
crypto_core_inv((unsigned char *) out,(const unsigned char *) in,0,0);
/* could check byte 2*p for failure; but, in context, inv always works */
crypto_decode_pxint16(out,(unsigned char *) out);
}
/* ----- underlying hash function */
#define Hash_bytes 32
static void Hash(unsigned char *out,const unsigned char *in,int inlen)
{
unsigned char h[64];
int i;
crypto_hash_sha512(h,in,inlen);
for (i = 0;i < 32;++i) out[i] = h[i];
}
/* ----- higher-level randomness */
static void Short_random(small *out)
{
uint32 L[ppadsort];
int i;
randombytes((unsigned char *) L,4*p);
crypto_decode_pxint32(L,(unsigned char *) L);
for (i = 0;i < w;++i) L[i] = L[i]&(uint32)-2;
for (i = w;i < p;++i) L[i] = (L[i]&(uint32)-3)|1;
for (i = p;i < ppadsort;++i) L[i] = 0xffffffff;
crypto_sort_uint32(L,ppadsort);
for (i = 0;i < p;++i) out[i] = (L[i]&3)-1;
}
static void Small_random(small *out)
{
uint32 L[p];
int i;
randombytes((unsigned char *) L,sizeof L);
crypto_decode_pxint32(L,(unsigned char *) L);
for (i = 0;i < p;++i) out[i] = (((L[i]&0x3fffffff)*3)>>30)-1;
}
/* ----- Streamlined NTRU Prime */
typedef small Inputs[p]; /* passed by reference */
#define Ciphertexts_bytes Rounded_bytes
#define SecretKeys_bytes (2*Small_bytes)
#define PublicKeys_bytes Rq_bytes
#define Confirm_bytes 32
/* c,r_enc[1:] = Hide(r,pk,cache); cache is Hash4(pk) */
/* also set r_enc[0]=3 */
/* also set x[0]=2, and x[1:1+Hash_bytes] = Hash3(r_enc) */
/* also overwrite x[1+Hash_bytes:1+2*Hash_bytes] */
static void Hide(unsigned char *x,unsigned char *c,unsigned char *r_enc,const Inputs r,const unsigned char *pk,const unsigned char *cache)
{
Fq h[p];
int i;
Small_encode(r_enc+1,r);
Rq_decode(h,pk);
Rq_mult_small(h,r);
Round_and_encode(c,h);
r_enc[0] = 3;
Hash(x+1,r_enc,1+Small_bytes);
for (i = 0;i < Hash_bytes;++i) x[1+Hash_bytes+i] = cache[i];
x[0] = 2;
Hash(c+Ciphertexts_bytes,x,1+Hash_bytes*2);
}
#include "crypto_kem.h"
int crypto_kem_keypair(unsigned char *pk,unsigned char *sk)
{
small g[p];
for (;;) {
Small_random(g);
{
small v[p+1];
small vp;
crypto_core_inv3((unsigned char *) v,(const unsigned char *) g,0,0);
vp = v[p];
crypto_declassify(&vp,sizeof vp);
if (vp == 0) {
Small_encode(sk+Small_bytes,v);
break;
}
}
}
{
small f[p];
Short_random(f);
Small_encode(sk,f);
{
Fq h[p+1];
Rq_recip3(h,f); /* always works */
Rq_mult_small(h,g);
Rq_encode(pk,h);
}
}
{
int i;
unsigned char sksave = sk[SecretKeys_bytes-1];
for (i = 0;i < PublicKeys_bytes;++i) sk[SecretKeys_bytes+i] = pk[i];
sk[SecretKeys_bytes-1] = 4;
Hash(sk+SecretKeys_bytes+PublicKeys_bytes+Small_bytes,sk+SecretKeys_bytes-1,1+PublicKeys_bytes);
sk[SecretKeys_bytes-1] = sksave;
randombytes(sk+SecretKeys_bytes+PublicKeys_bytes,Small_bytes);
}
return 0;
}
int crypto_kem_enc(unsigned char *c,unsigned char *k,const unsigned char *pk)
{
unsigned char cache[Hash_bytes];
int i;
{
unsigned char y[1+PublicKeys_bytes]; /* XXX: can eliminate with incremental hashing */
for (i = 0;i < PublicKeys_bytes;++i) y[1+i] = pk[i];
y[0] = 4;
Hash(cache,y,sizeof y);
}
{
Inputs r;
Short_random(r);
{
unsigned char r_enc[Small_bytes+1];
unsigned char x[1+Hash_bytes+Ciphertexts_bytes+Confirm_bytes];
Hide(x,c,r_enc,r,pk,cache);
for (i = 0;i < Ciphertexts_bytes+Confirm_bytes;++i) x[1+Hash_bytes+i] = c[i];
x[0] = 1;
Hash(k,x,sizeof x);
}
}
return 0;
}
int crypto_kem_dec(unsigned char *k,const unsigned char *c,const unsigned char *sk)
{
const unsigned char *pk = sk+SecretKeys_bytes;
const unsigned char *rho = pk+PublicKeys_bytes;
const unsigned char *cache = rho+Small_bytes;
int mask,i;
Inputs r;
{
Fq d[p];
Rounded_decode(d,c);
{
small f[p];
Small_decode(f,sk);
Rq_mult_small(d,f);
Rq_mult3(d,d);
}
{
small e[p];
small v[p];
R3_fromRq(e,d);
Small_decode(v,sk+Small_bytes);
R3_mult(r,e,v);
}
crypto_core_wforce((unsigned char *) r,(unsigned char *) r,0,0);
}
{
unsigned char r_enc[1+Small_bytes];
unsigned char cnew[Ciphertexts_bytes+Confirm_bytes];
unsigned char x[1+Hash_bytes+Ciphertexts_bytes+Confirm_bytes];
/* XXX: can use incremental hashing to reduce x size */
Hide(x,cnew,r_enc,r,pk,cache);
mask = crypto_verify_clen(c,cnew);
for (i = 0;i < Small_bytes;++i) r_enc[i+1] ^= mask&(r_enc[i+1]^rho[i]);
Hash(x+1,r_enc,1+Small_bytes); /* XXX: can instead do cmov on cached hash of rho */
for (i = 0;i < Ciphertexts_bytes+Confirm_bytes;++i) x[1+Hash_bytes+i] = c[i];
x[0] = 1+mask;
Hash(k,x,sizeof x);
}
return 0;
}