#include "decode.h"
#include "cleanup.h"
#include "decode_internal.h"
#include "gf2x.h"
#include "utilities.h"
#if defined(BG_DECODER)
# if(LEVEL == 1)
# define MAX_IT 3
# elif(LEVEL == 3)
# define MAX_IT 4
# else
# error "Level can only be 1/3"
# endif
#elif defined(BGF_DECODER)
# define MAX_IT 5
#endif
void compute_syndrome(OUT syndrome_t *syndrome,
IN const pad_r_t *c0,
IN const pad_r_t *h0,
IN const decode_ctx *ctx)
{
DEFER_CLEANUP(pad_r_t pad_s, pad_r_cleanup);
gf2x_mod_mul(&pad_s, c0, h0);
bike_memcpy((uint8_t *)syndrome->qw, pad_s.val.raw, R_BYTES);
ctx->dup(syndrome);
}
void recompute_syndrome(OUT syndrome_t *syndrome,
IN const pad_r_t *c0,
IN const pad_r_t *h0,
IN const pad_r_t *pk,
IN const e_t *e,
IN const decode_ctx *ctx)
{
DEFER_CLEANUP(pad_r_t tmp_c0, pad_r_cleanup);
DEFER_CLEANUP(pad_r_t e0 = {0}, pad_r_cleanup);
DEFER_CLEANUP(pad_r_t e1 = {0}, pad_r_cleanup);
e0.val = e->val[0];
e1.val = e->val[1];
gf2x_mod_mul(&tmp_c0, &e1, pk);
gf2x_mod_add(&tmp_c0, &tmp_c0, c0);
gf2x_mod_add(&tmp_c0, &tmp_c0, &e0);
compute_syndrome(syndrome, &tmp_c0, h0, ctx);
}
#define MUL64HIGH(c, a, b) \
do { \
uint64_t a_lo, a_hi, b_lo, b_hi; \
a_lo = a & 0xffffffff; \
b_lo = b & 0xffffffff; \
a_hi = a >> 32; \
b_hi = b >> 32; \
c = a_hi*b_hi + ((a_hi*b_lo + a_lo*b_hi) >> 32); \
} while(0)
_INLINE_ uint8_t get_threshold(IN const syndrome_t *s)
{
bike_static_assert(sizeof(*s) >= sizeof(r_t), syndrome_is_large_enough);
const uint64_t syndrome_weight = r_bits_vector_weight((const r_t *)s->qw);
uint64_t thr = THRESHOLD_COEFF0 + (THRESHOLD_COEFF1 * syndrome_weight);
MUL64HIGH(thr, thr, THRESHOLD_MUL_CONST);
thr >>= THRESHOLD_SHR_CONST;
const uint32_t mask = secure_l32_mask((uint32_t)thr, THRESHOLD_MIN);
thr = (u32_barrier(mask) & thr) | (u32_barrier(~mask) & THRESHOLD_MIN);
DMSG(" Threshold: %d\n", thr);
return thr;
}
_INLINE_ void find_err1(OUT e_t *e,
OUT e_t *black_e,
OUT e_t *gray_e,
IN const syndrome_t * syndrome,
IN const compressed_idx_d_ar_t wlist,
IN const uint8_t threshold,
IN const decode_ctx *ctx)
{
DEFER_CLEANUP(syndrome_t rotated_syndrome = {0}, syndrome_cleanup);
DEFER_CLEANUP(upc_t upc, upc_cleanup);
for(uint32_t i = 0; i < N0; i++) {
bike_memset(&upc, 0, sizeof(upc));
for(size_t j = 0; j < D; j++) {
ctx->rotate_right(&rotated_syndrome, syndrome, wlist[i].val[j]);
ctx->bit_sliced_adder(&upc, &rotated_syndrome, LOG2_MSB(j + 1));
}
ctx->bit_slice_full_subtract(&upc, threshold);
const r_t *last_slice = &(upc.slice[SLICES - 1].u.r.val);
for(size_t j = 0; j < R_BYTES; j++) {
const uint8_t sum_msb = (~last_slice->raw[j]);
black_e->val[i].raw[j] = sum_msb;
e->val[i].raw[j] ^= sum_msb;
}
e->val[i].raw[R_BYTES - 1] &= LAST_R_BYTE_MASK;
for(size_t l = 0; l < DELTA; l++) {
bike_memset((uint8_t *)rotated_syndrome.qw, 0xff, R_BYTES);
ctx->bit_sliced_adder(&upc, &rotated_syndrome, SLICES);
}
for(size_t j = 0; j < R_BYTES; j++) {
const uint8_t sum_msb = (~last_slice->raw[j]);
gray_e->val[i].raw[j] = (~(black_e->val[i].raw[j])) & sum_msb;
}
}
}
_INLINE_ void find_err2(OUT e_t *e,
IN e_t * pos_e,
IN const syndrome_t * syndrome,
IN const compressed_idx_d_ar_t wlist,
IN const uint8_t threshold,
IN const decode_ctx *ctx)
{
DEFER_CLEANUP(syndrome_t rotated_syndrome = {0}, syndrome_cleanup);
DEFER_CLEANUP(upc_t upc, upc_cleanup);
for(uint32_t i = 0; i < N0; i++) {
bike_memset(&upc, 0, sizeof(upc));
for(size_t j = 0; j < D; j++) {
ctx->rotate_right(&rotated_syndrome, syndrome, wlist[i].val[j]);
ctx->bit_sliced_adder(&upc, &rotated_syndrome, LOG2_MSB(j + 1));
}
ctx->bit_slice_full_subtract(&upc, threshold);
const r_t *last_slice = &(upc.slice[SLICES - 1].u.r.val);
for(size_t j = 0; j < R_BYTES; j++) {
const uint8_t sum_msb = (~last_slice->raw[j]);
e->val[i].raw[j] ^= (pos_e->val[i].raw[j] & sum_msb);
}
e->val[i].raw[R_BYTES - 1] &= LAST_R_BYTE_MASK;
}
}
void decode(OUT e_t *e, IN const ct_t *ct, IN const sk_t *sk)
{
decode_ctx ctx;
decode_ctx_init(&ctx);
DEFER_CLEANUP(e_t black_e = {0}, e_cleanup);
DEFER_CLEANUP(e_t gray_e = {0}, e_cleanup);
DEFER_CLEANUP(pad_r_t c0 = {0}, pad_r_cleanup);
DEFER_CLEANUP(pad_r_t h0 = {0}, pad_r_cleanup);
pad_r_t pk = {0};
c0.val = ct->c0;
h0.val = sk->bin[0];
pk.val = sk->pk;
DEFER_CLEANUP(syndrome_t s = {0}, syndrome_cleanup);
DMSG(" Computing s.\n");
compute_syndrome(&s, &c0, &h0, &ctx);
ctx.dup(&s);
bike_memset(e, 0, sizeof(*e));
for(uint32_t iter = 0; iter < MAX_IT; iter++) {
const uint8_t threshold = get_threshold(&s);
DMSG(" Iteration: %d\n", iter);
DMSG(" Weight of e: %lu\n",
r_bits_vector_weight(&e->val[0]) + r_bits_vector_weight(&e->val[1]));
DMSG(" Weight of syndrome: %lu\n", r_bits_vector_weight((r_t *)s.qw));
find_err1(e, &black_e, &gray_e, &s, sk->wlist, threshold, &ctx);
recompute_syndrome(&s, &c0, &h0, &pk, e, &ctx);
#if defined(BGF_DECODER)
if(iter >= 1) {
continue;
}
#endif
DMSG(" Weight of e: %lu\n",
r_bits_vector_weight(&e->val[0]) + r_bits_vector_weight(&e->val[1]));
DMSG(" Weight of syndrome: %lu\n", r_bits_vector_weight((r_t *)s.qw));
find_err2(e, &black_e, &s, sk->wlist, ((D + 1) / 2) + 1, &ctx);
recompute_syndrome(&s, &c0, &h0, &pk, e, &ctx);
DMSG(" Weight of e: %lu\n",
r_bits_vector_weight(&e->val[0]) + r_bits_vector_weight(&e->val[1]));
DMSG(" Weight of syndrome: %lu\n", r_bits_vector_weight((r_t *)s.qw));
find_err2(e, &gray_e, &s, sk->wlist, ((D + 1) / 2) + 1, &ctx);
recompute_syndrome(&s, &c0, &h0, &pk, e, &ctx);
}
}