/* This file is for Niederreiter decryption */ // 20240805 djb: more cryptoint usage // 20240503 djb: remove #ifdef KAT ... #endif // 20221230 djb: add linker lines // linker define decrypt // linker use benes bm fft fft_tr // linker use vec_mul vec_sq vec_inv #include "decrypt.h" #include "params.h" #include "fft_tr.h" #include "benes.h" #include "util.h" #include "fft.h" #include "vec.h" #include "bm.h" #include "crypto_int16.h" #include "crypto_int8.h" #include "crypto_int64.h" static void scaling(vec out[][GFBITS], vec inv[][GFBITS], const unsigned char *sk, vec *recv) { int i, j; vec irr_int[ GFBITS ]; vec eval[64][ GFBITS ]; vec tmp[ GFBITS ]; // irr_load(irr_int, sk); fft(eval, irr_int); for (i = 0; i < 64; i++) vec_sq(eval[i], eval[i]); vec_copy(inv[0], eval[0]); for (i = 1; i < 64; i++) vec_mul(inv[i], inv[i-1], eval[i]); vec_inv(tmp, inv[63]); for (i = 62; i >= 0; i--) { vec_mul(inv[i+1], tmp, inv[i]); vec_mul(tmp, tmp, eval[i+1]); } vec_copy(inv[0], tmp); // for (i = 0; i < 64; i++) for (j = 0; j < GFBITS; j++) out[i][j] = inv[i][j] & recv[i]; } static void preprocess(vec *recv, const unsigned char *s) { int i; unsigned char r[ 512 ]; for (i = 0; i < SYND_BYTES; i++) r[i] = s[i]; for (i = SYND_BYTES; i < 512; i++) r[i] = 0; for (i = 0; i < 64; i++) recv[i] = load8(r + i*8); } static void postprocess(unsigned char * e, vec * err) { int i; unsigned char error8[ (1 << GFBITS)/8 ]; for (i = 0; i < 64; i++) store8(error8 + i*8, err[i]); for (i = 0; i < SYS_N/8; i++) e[i] = error8[i]; } static void scaling_inv(vec out[][GFBITS], vec inv[][GFBITS], vec *recv) { int i, j; for (i = 0; i < 64; i++) for (j = 0; j < GFBITS; j++) out[i][j] = inv[i][j] & recv[i]; } static int weight_check(unsigned char * e, vec * error) { int i; uint16_t w0 = 0; uint16_t w1 = 0; uint16_t check; for (i = 0; i < (1 << GFBITS); i++) w0 += crypto_int64_bitmod_01(error[i/64], i); for (i = 0; i < SYS_N; i++) w1 += crypto_int8_bitmod_01(e[i/8], i); check = (w0 ^ SYS_T) | (w1 ^ SYS_T); return -crypto_int16_zero_mask(check); } static uint16_t synd_cmp(vec s0[][ GFBITS ] , vec s1[][ GFBITS ]) { int i, j; vec diff = 0; for (i = 0; i < 2; i++) for (j = 0; j < GFBITS; j++) diff |= (s0[i][j] ^ s1[i][j]); return vec_testz(diff); } /* Niederreiter decryption with the Berlekamp decoder */ /* intput: sk, secret key */ /* s, ciphertext (syndrome) */ /* output: e, error vector */ /* return: 0 for success; 1 for failure */ int decrypt(unsigned char *e, const unsigned char *sk, const unsigned char *s) { int i; uint16_t check_synd; uint16_t check_weight; vec inv[ 64 ][ GFBITS ]; vec scaled[ 64 ][ GFBITS ]; vec eval[ 64 ][ GFBITS ]; vec error[ 64 ]; vec s_priv[ 2 ][ GFBITS ]; vec s_priv_cmp[ 2 ][ GFBITS ]; vec locator[ GFBITS ]; vec recv[ 64 ]; vec allone; // Berlekamp decoder preprocess(recv, s); benes(recv, sk + IRR_BYTES, 1); scaling(scaled, inv, sk, recv); fft_tr(s_priv, scaled); bm(locator, s_priv); fft(eval, locator); // reencryption and weight check allone = vec_setbits(1); for (i = 0; i < 64; i++) { error[i] = vec_or_reduce(eval[i]); error[i] ^= allone; } scaling_inv(scaled, inv, error); fft_tr(s_priv_cmp, scaled); check_synd = synd_cmp(s_priv, s_priv_cmp); // benes(error, sk + IRR_BYTES, 0); postprocess(e, error); check_weight = weight_check(e, error); return 1 - (check_synd & check_weight); }