Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,37 @@ LIBS = #-lm

# =====================================================================

OBJ = codec.o common.o deterministic.o falcon.o fft.o fpr.o keygen.o rng.o shake.o sign.o vrfy.o
OBJ = codec.o common.o deterministic1024.o deterministic512.o falcon.o fft.o fpr.o keygen.o rng.o shake.o sign.o vrfy.o

all: tests/test_deterministic tests/test_falcon tests/speed
all: tests/test_deterministic tests/test_deterministic512 tests/test_falcon tests/speed

clean:
-rm -f $(OBJ) tests/test_deterministic tests/test_deterministic.o tests/test_falcon tests/test_falcon.o tests/speed tests/speed.o
-rm -f $(OBJ) tests/test_deterministic tests/test_deterministic.o tests/test_deterministic512 tests/test_deterministic512.o tests/test_falcon tests/test_falcon.o tests/speed tests/speed.o

# deterministic1024.c (FALCON-DET1024) and deterministic512.c (FALCON-DET512)
# are generated from the single template deterministic.c.tmpl. They are
# committed to the repository, so a normal build just compiles them. After
# editing the template, run "make gen" to regenerate them; "make check-gen"
# verifies that the committed files are in sync with the template (useful in CI).
gen: deterministic.c.tmpl scripts/gen_deterministic.sh
sh scripts/gen_deterministic.sh "$(CC)" .

check-gen: deterministic.c.tmpl scripts/gen_deterministic.sh
@tmp=`mktemp -d`; \
sh scripts/gen_deterministic.sh "$(CC)" "$$tmp"; \
rc=0; \
cmp -s "$$tmp/deterministic1024.c" deterministic1024.c || { echo "ERROR: deterministic1024.c is out of sync with deterministic.c.tmpl"; rc=1; }; \
cmp -s "$$tmp/deterministic512.c" deterministic512.c || { echo "ERROR: deterministic512.c is out of sync with deterministic.c.tmpl"; rc=1; }; \
rm -rf "$$tmp"; \
if [ $$rc -eq 0 ]; then echo "OK: deterministic1024.c and deterministic512.c are in sync with deterministic.c.tmpl"; else echo "Run 'make gen' to regenerate."; fi; \
exit $$rc

tests/test_deterministic: tests/test_deterministic.o $(OBJ)
$(LD) $(LDFLAGS) -o tests/test_deterministic tests/test_deterministic.o $(OBJ) $(LIBS)

tests/test_deterministic512: tests/test_deterministic512.o $(OBJ)
$(LD) $(LDFLAGS) -o tests/test_deterministic512 tests/test_deterministic512.o $(OBJ) $(LIBS)

tests/test_falcon: tests/test_falcon.o $(OBJ)
$(LD) $(LDFLAGS) -o tests/test_falcon tests/test_falcon.o $(OBJ) $(LIBS)

Expand All @@ -73,8 +94,11 @@ codec.o: codec.c config.h inner.h fpr.h
common.o: common.c config.h inner.h fpr.h
$(CC) $(CFLAGS) -c -o common.o common.c

deterministic.o: deterministic.c deterministic.h falcon.h
$(CC) $(CFLAGS) -c -o deterministic.o deterministic.c
deterministic1024.o: deterministic1024.c deterministic.h falcon.h
$(CC) $(CFLAGS) -c -o deterministic1024.o deterministic1024.c

deterministic512.o: deterministic512.c deterministic.h falcon.h
$(CC) $(CFLAGS) -c -o deterministic512.o deterministic512.c

falcon.o: falcon.c falcon.h config.h inner.h fpr.h
$(CC) $(CFLAGS) -c -o falcon.o falcon.c
Expand Down Expand Up @@ -103,8 +127,11 @@ tests/speed.o: tests/speed.c falcon.h
tests/test_falcon.o: tests/test_falcon.c falcon.h config.h inner.h fpr.h
$(CC) $(CFLAGS) -c -o tests/test_falcon.o tests/test_falcon.c

tests/test_deterministic.o: tests/test_deterministic.c deterministic.h falcon.h config.h inner.h fpr.h
tests/test_deterministic.o: tests/test_deterministic.c tests/test_deterministic_kat.h deterministic.h falcon.h config.h inner.h fpr.h
$(CC) $(CFLAGS) -c -o tests/test_deterministic.o tests/test_deterministic.c

tests/test_deterministic512.o: tests/test_deterministic512.c tests/test_deterministic512_kat.h deterministic.h falcon.h config.h inner.h fpr.h
$(CC) $(CFLAGS) -c -o tests/test_deterministic512.o tests/test_deterministic512.c

vrfy.o: vrfy.c config.h inner.h fpr.h
$(CC) $(CFLAGS) -c -o vrfy.o vrfy.c
308 changes: 308 additions & 0 deletions deterministic.c.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
/*
* Template for the Deterministic Falcon implementation.
*
* The two generated sources -- one per Falcon parameter set, n = 1024 and
* n = 512 -- are produced from this single template by the C preprocessor;
* see the Makefile. Do not edit the generated files; edit this template and
* run "make gen" to regenerate them.
*
* The lines up to the first generator marker below are copied verbatim into
* each generated file; the remainder is macro-expanded with DET_N set to
* 1024 or 512. DET_N selects the falcon_det1024_* / falcon_det512_* function
* family and the matching parameter set, so a single algorithm body produces
* both variants and they cannot diverge.
*/
/*__FALCON_DET_VERBATIM__*/
#include <stdint.h>
#include <string.h>

#include "falcon.h"
#include "inner.h"
#include "deterministic.h"

#define Q 12289
/*__FALCON_DET_EXPAND__*/
#if DET_N == 1024
#define DET_FN(name) falcon_det1024_##name
#define DET_LOGN FALCON_DET1024_LOGN
#define DET_PUBKEY_SIZE FALCON_DET1024_PUBKEY_SIZE
#define DET_PRIVKEY_SIZE FALCON_DET1024_PRIVKEY_SIZE
#define DET_CURRENT_SALT_VERSION FALCON_DET1024_CURRENT_SALT_VERSION
#define DET_SIG_COMPRESSED_HEADER FALCON_DET1024_SIG_COMPRESSED_HEADER
#define DET_SIG_CT_HEADER FALCON_DET1024_SIG_CT_HEADER
#define DET_SIG_CT_SIZE FALCON_DET1024_SIG_CT_SIZE
#elif DET_N == 512
#define DET_FN(name) falcon_det512_##name
#define DET_LOGN FALCON_DET512_LOGN
#define DET_PUBKEY_SIZE FALCON_DET512_PUBKEY_SIZE
#define DET_PRIVKEY_SIZE FALCON_DET512_PRIVKEY_SIZE
#define DET_CURRENT_SALT_VERSION FALCON_DET512_CURRENT_SALT_VERSION
#define DET_SIG_COMPRESSED_HEADER FALCON_DET512_SIG_COMPRESSED_HEADER
#define DET_SIG_CT_HEADER FALCON_DET512_SIG_CT_HEADER
#define DET_SIG_CT_SIZE FALCON_DET512_SIG_CT_SIZE
#else
#error "DET_N must be defined to 1024 or 512"
#endif

#define DET_TMPSIZE_KEYGEN FALCON_TMPSIZE_KEYGEN(DET_LOGN)
#define DET_TMPSIZE_SIGNDYN FALCON_TMPSIZE_SIGNDYN(DET_LOGN)
#define DET_TMPSIZE_VERIFY FALCON_TMPSIZE_VERIFY(DET_LOGN)
#define DET_SALTED_SIG_COMPRESSED_MAXSIZE FALCON_SIG_COMPRESSED_MAXSIZE(DET_LOGN)
#define DET_SALTED_SIG_CT_SIZE FALCON_SIG_CT_SIZE(DET_LOGN)

int DET_FN(keygen)(shake256_context *rng, void *privkey, void *pubkey) {
uint8_t tmpkg[DET_TMPSIZE_KEYGEN];

return falcon_keygen_make(rng, DET_LOGN,
privkey, DET_PRIVKEY_SIZE,
pubkey, DET_PUBKEY_SIZE,
tmpkg, DET_TMPSIZE_KEYGEN);
}

// Domain separator used to construct the fixed versioned salt string.
uint8_t DET_FN(salt_rest)[38] = {"FALCON_DET"};

// Construct the fixed salt for a given version.
void DET_FN(write_salt)(uint8_t dst[40], uint8_t salt_version) {
dst[0] = salt_version;
dst[1] = DET_LOGN;
memcpy(dst+2, DET_FN(salt_rest), 38);
}

int DET_FN(sign_compressed)(void *sig, size_t *sig_len,
const void *privkey, const void *data, size_t data_len) {

shake256_context detrng;
shake256_context hd;
uint8_t tmpsd[DET_TMPSIZE_SIGNDYN];
uint8_t logn[1] = {DET_LOGN};
uint8_t salt[40];

size_t saltedsig_len = DET_SALTED_SIG_COMPRESSED_MAXSIZE;
uint8_t saltedsig[DET_SALTED_SIG_COMPRESSED_MAXSIZE];

if (falcon_get_logn(privkey, DET_PRIVKEY_SIZE) != DET_LOGN) {
return FALCON_ERR_FORMAT;
}

// SHAKE(logn || privkey || data), set to output mode.
shake256_init(&detrng);
shake256_inject(&detrng, logn, 1);
shake256_inject(&detrng, privkey, DET_PRIVKEY_SIZE);
shake256_inject(&detrng, data, data_len);
shake256_flip(&detrng);

DET_FN(write_salt)(salt, DET_CURRENT_SALT_VERSION);

// SHAKE(salt || data), still in input mode.
shake256_init(&hd);
shake256_inject(&hd, salt, 40);
shake256_inject(&hd, data, data_len);

int r = falcon_sign_dyn_finish(&detrng, saltedsig, &saltedsig_len,
FALCON_SIG_COMPRESSED, privkey, DET_PRIVKEY_SIZE,
&hd, salt, tmpsd, DET_TMPSIZE_SIGNDYN);
if (r != 0) {
return r;
}

// Transform the salted signature to unsalted format.
uint8_t *sigbytes = sig;
sigbytes[0] = saltedsig[0] | 0x80;
sigbytes[1] = DET_CURRENT_SALT_VERSION;
memcpy(sigbytes+2, saltedsig+41, saltedsig_len-41);

*sig_len = saltedsig_len-40+1;

return 0;
}

int DET_FN(convert_compressed_to_ct)(void *sig_ct,
const void *sig_compressed, size_t sig_compressed_len) {

int16_t coeffs[1 << DET_LOGN];
size_t v;

if (((uint8_t*)sig_compressed)[0] != DET_SIG_COMPRESSED_HEADER) {
return FALCON_ERR_BADSIG;
}

// Decode the signature's s_bytes into the n signed-integer coefficients.
v = Zf(comp_decode)(coeffs, DET_LOGN, ((uint8_t*)sig_compressed)+2, sig_compressed_len-2);
if (v == 0) {
return FALCON_ERR_SIZE;
}

uint8_t *sig = sig_ct;
sig[0] = DET_SIG_CT_HEADER;
sig[1] = ((uint8_t*)sig_compressed)[1]; // Copy the salt_version byte.

// Encode the signed-integer coefficients into CT format.
v = Zf(trim_i16_encode)(sig+2, DET_SIG_CT_SIZE-2, coeffs, DET_LOGN,
Zf(max_sig_bits)[DET_LOGN]);
if (v == 0) {
return FALCON_ERR_SIZE;
}

return 0;
}

// Construct the corresponding salted signature from an unsalted one.
void DET_FN(resalt)(uint8_t *salted_sig,
const uint8_t *unsalted_sig, size_t unsalted_sig_len) {

salted_sig[0] = unsalted_sig[0] & ~0x80; // Reset MSB to 0.
DET_FN(write_salt)(salted_sig+1, unsalted_sig[1]);
memcpy(salted_sig+41, unsalted_sig+2, unsalted_sig_len-2);
}

int DET_FN(verify_compressed)(const void *sig, size_t sig_len,
const void *pubkey, const void *data, size_t data_len) {

uint8_t tmpvv[DET_TMPSIZE_VERIFY];
uint8_t salted_sig[DET_SALTED_SIG_COMPRESSED_MAXSIZE];

if (sig_len < 2) {
return FALCON_ERR_BADSIG;
}

if (((uint8_t*)sig)[0] != DET_SIG_COMPRESSED_HEADER) {
return FALCON_ERR_BADSIG;
}

// Add back the salt; drop the version byte.
size_t salted_sig_len = sig_len + 40 - 1;

if (salted_sig_len > DET_SALTED_SIG_COMPRESSED_MAXSIZE){
return FALCON_ERR_BADSIG;
}


DET_FN(resalt)(salted_sig, sig, sig_len);

return falcon_verify(salted_sig, salted_sig_len, FALCON_SIG_COMPRESSED,
pubkey, DET_PUBKEY_SIZE, data, data_len,
tmpvv, DET_TMPSIZE_VERIFY);
}

int DET_FN(verify_ct)(const void *sig,
const void *pubkey, const void *data, size_t data_len) {

uint8_t tmpvv[DET_TMPSIZE_VERIFY];
uint8_t salted_sig[DET_SALTED_SIG_CT_SIZE];

if (((uint8_t*)sig)[0] != DET_SIG_CT_HEADER) {
return FALCON_ERR_BADSIG;
}

DET_FN(resalt)(salted_sig, sig, DET_SIG_CT_SIZE);

return falcon_verify(salted_sig, DET_SALTED_SIG_CT_SIZE, FALCON_SIG_CT,
pubkey, DET_PUBKEY_SIZE, data, data_len,
tmpvv, DET_TMPSIZE_VERIFY);
}

int DET_FN(get_salt_version)(const void* sig) {
return ((uint8_t*)sig)[1];
}


int DET_FN(pubkey_coeffs)(uint16_t *h, const void *pubkey) {
/*
* Decode public key.
*/
if (Zf(modq_decode)(h, DET_LOGN, (uint8_t*)pubkey + 1, DET_PUBKEY_SIZE - 1)
!= DET_PUBKEY_SIZE - 1)
{
return FALCON_ERR_FORMAT;
}
return 0;
}

void DET_FN(hash_to_point_coeffs)(uint16_t *c, const void *data, size_t data_len, uint8_t salt_version) {
uint8_t salt[40];
DET_FN(write_salt)(salt, salt_version);

shake256_context ctx;
shake256_init(&ctx);
shake256_inject(&ctx, salt, 40);
shake256_inject(&ctx, data, data_len);
shake256_flip(&ctx);

uint8_t tmp[(1<<DET_LOGN)*2];
Zf(hash_to_point_ct)((inner_shake256_context *)&ctx, c, DET_LOGN, tmp);
}

int DET_FN(s2_coeffs)(int16_t *s2, const void* sig) {
unsigned logn = DET_LOGN;

// This function is limited to CT signatures for now,
// but support for compressed signatures can be added later.
if (((uint8_t*)sig)[0] != DET_SIG_CT_HEADER) {
return FALCON_ERR_FORMAT;
}

size_t v = Zf(trim_i16_decode)(s2, logn, Zf(max_sig_bits)[logn], (uint8_t*)sig+2, DET_SIG_CT_SIZE-2);
if (v != DET_SIG_CT_SIZE-2) {
return FALCON_ERR_FORMAT;
}
return 0;
}

int DET_FN(s1_coeffs)(int16_t *s1, const uint16_t *h, const uint16_t *c, const int16_t *s2) {
unsigned logn = DET_LOGN;
size_t u, n;
n = (size_t)1<<logn;

uint16_t h_ntt[1<<DET_LOGN];
for (u = 0; u < n; u++) {
h_ntt[u] = h[u];
}
Zf(to_ntt_monty)(h_ntt, logn);

// Copied from verify_raw.
uint16_t tt[1<<DET_LOGN];
/*
* Reduce s2 elements modulo q ([0..q-1] range).
*/
for (u = 0; u < n; u ++) {
uint32_t w;

w = (uint32_t)s2[u];
w += Q & -(w >> 31);
tt[u] = (uint16_t)w;
}

/*
* Compute s1 = c - s2*h mod phi mod q (in tt[]).
*/
Zf(mq_NTT)(tt, logn); // tt = s2
Zf(mq_poly_montymul_ntt)(tt, h_ntt, logn); // tt = s2*h
Zf(mq_iNTT)(tt, logn);
// don't use mq_poly_sub because it overwrites the first
// argument (c); use an explicit loop instead
for (u = 0; u < n; u ++) {
tt[u] = (uint16_t)Zf(mq_sub)(c[u], tt[u]);
}

/*
* Normalize s1 elements into the [-q/2..q/2] range.
*/
for (u = 0; u < n; u ++) {
int32_t w;

w = (int32_t)tt[u];
w -= (int32_t)(Q & -(((Q >> 1) - (uint32_t)w) >> 31));
s1[u] = (int16_t)w;
}

/*
* Test if the aggregate (s1,s2) vector is short enough.
*/
int vv = Zf(is_short)(s1, s2, logn);
if (vv != 1) {
return FALCON_ERR_BADSIG;
}

return 0;
}
Loading