/* This file is for secret-key generation */ // 20240805 djb: more use of cryptoint // 20240508 djb: switch to vec_mul_gf_using_64 // 20221230 djb: add linker lines // linker define genpoly_gen // linker use gf_mul gf_inv // linker use vec_GF_mul // linker use vec_mul_asm // linker use transpose_64x64_asm #include "sk_gen.h" #include "randombytes.h" #include "controlbits.h" #include "transpose.h" #include "params.h" #include "util.h" #include "vec.h" #include "gf.h" #include "crypto_declassify.h" #include "crypto_uint16.h" #include "crypto_int64.h" static inline crypto_uint16 gf_is_zero_declassify(gf t) { crypto_uint16 mask = crypto_uint16_zero_mask(t); crypto_declassify(&mask,sizeof mask); return mask; } /* input: v, a list of GF(2^m) elements in bitsliced form */ /* input: idx, an index */ /* return: the idx-th element in v */ static inline gf extract_gf(vec v[GFBITS], int idx) { int i; gf ret; ret = 0; for (i = GFBITS-1; i >= 0; i--) { ret <<= 1; ret |= crypto_int64_bitmod_01(v[i], idx); } return ret; } /* same as extract_gf but reduces return value to 1 bit */ static inline vec extract_bit(vec v[GFBITS], int idx) { int i; vec ret; ret = 0; for (i = GFBITS-1; i >= 0; i--) ret |= v[i]; return crypto_int64_bitmod_01(ret, idx); } /* input: f, element in GF((2^m)^t) */ /* output: out, minimal polynomial of f */ /* return: 0 for success and -1 for failure */ int genpoly_gen(gf *out, gf *f) { int i, j, k; gf t, inv; vec v[ GFBITS ], buf[ GFBITS ][ 64 ], mat[ 64 ][ GFBITS ], mask; // fill matrix buf[0][0] = 1; for (i = 1; i < GFBITS; i++) buf[i][0] = 0; for (j = 0; j < GFBITS; j++) for (i = SYS_T-1; i >= 0; i--) { v[j] <<= 1; v[j] |= crypto_int64_bitmod_01(f[i], j); } for (i = 0; i < GFBITS; i++) buf[i][1] = v[i]; for (k = 2; k <= SYS_T; k++) { vec_GF_mul(v, v, f); if (k < SYS_T) { for (i = 0; i < GFBITS; i++) buf[i][k] = v[i]; } else { for (i = 0; i < SYS_T; i++) out[i] = extract_gf(v, i); } } for (i = 0; i < GFBITS; i++) transpose_64x64(buf[i]); for (j = 0; j < SYS_T; j++) for (i = 0; i < GFBITS; i++) mat[j][i] = buf[i][j]; // gaussian for (i = 0; i < SYS_T; i++) { for (j = i+1; j < SYS_T; j++) { mask = extract_bit(mat[i], i); mask -= 1; for (k = 0; k < GFBITS; k++) mat[i][k] ^= mat[j][k] & mask; out[i] ^= out[j] & mask; } // t = extract_gf(mat[i], i); if (gf_is_zero_declassify(t)) return -1; // return if not systematic // inv = gf_inv(t); vec_mul_gf_using_64(mat[i], mat[i], inv); out[i] = gf_mul(out[i], inv); for (j = 0; j < SYS_T; j++) { if (j != i) { t = extract_gf(mat[j], i); vec_mul_gf_using_64(v, mat[i], t); vec_add(mat[j], mat[j], v); out[j] ^= gf_mul(out[i], t); } } } return 0; }