56a0fcb135
* Copied qTESLA-p-I round2 (2019-08-19) code * Code compiles, NIST-KAT works * Included detached signature API * Generated testvectors * Fixed name in api.h * code style * Fixed error in Makefile * Passing pytest * Fixing types (uint8_t bytes and size_t indices) * Replaced SHAKE with SHAKE128 where necessary * Fixed bug: (signed) integer overflow * Added qTESLA-p-III * Code is now independent of machine endianness * repaired Microsoft makefile
90 lines
3.1 KiB
C
90 lines
3.1 KiB
C
/*************************************************************************************
|
|
* qTESLA: an efficient post-quantum signature scheme based on the R-LWE problem
|
|
*
|
|
* Abstract: sampling functions
|
|
**************************************************************************************/
|
|
|
|
#include "api.h"
|
|
#include "params.h"
|
|
#include "sample.h"
|
|
#include "sp800-185.h"
|
|
|
|
#define NBLOCKS_SHAKE (SHAKE_RATE/(((PARAM_B_BITS+1)+7)/8))
|
|
#define BPLUS1BYTES (((PARAM_B_BITS+1)+7)/8)
|
|
|
|
|
|
void PQCLEAN_QTESLAPIII_CLEAN_sample_y(poly y, const uint8_t *seed, uint16_t nonce) {
|
|
// Sample polynomial y, such that each coefficient is in the range [-B,B]
|
|
size_t i = 0, pos = 0, nblocks = PARAM_N;
|
|
uint8_t buf[PARAM_N * BPLUS1BYTES + 1];
|
|
uint16_t dmsp = (uint16_t)(nonce << 8);
|
|
uint8_t dmsp_bytes[2];
|
|
|
|
dmsp_bytes[0] = (uint8_t)(dmsp & 0xff);
|
|
dmsp_bytes[1] = (uint8_t)(dmsp >> 8);
|
|
cSHAKE(buf, PARAM_N * BPLUS1BYTES, (uint8_t *)NULL, 0, dmsp_bytes, 2, seed, CRYPTO_RANDOMBYTES);
|
|
++dmsp;
|
|
|
|
while (i < PARAM_N) {
|
|
if (pos >= nblocks * BPLUS1BYTES) {
|
|
nblocks = NBLOCKS_SHAKE;
|
|
dmsp_bytes[0] = (uint8_t)(dmsp & 0xff);
|
|
dmsp_bytes[1] = (uint8_t)(dmsp >> 8);
|
|
cSHAKE(buf, SHAKE_RATE, (uint8_t *)NULL, 0, dmsp_bytes, 2, seed, CRYPTO_RANDOMBYTES);
|
|
++dmsp;
|
|
pos = 0;
|
|
}
|
|
y[i] = (uint32_t)((buf[pos] | (buf[pos + 1] << 8) | (buf[pos + 2] << 16)) & ((1 << (PARAM_B_BITS + 1)) - 1));
|
|
y[i] -= PARAM_B;
|
|
if (y[i] != (1 << PARAM_B_BITS)) {
|
|
i++;
|
|
}
|
|
pos += BPLUS1BYTES;
|
|
}
|
|
}
|
|
|
|
|
|
void PQCLEAN_QTESLAPIII_CLEAN_encode_c(uint32_t *pos_list, int16_t *sign_list, uint8_t *c_bin) {
|
|
// Encoding of c' by mapping the output of the hash function H to an N-element vector with entries {-1,0,1}
|
|
size_t i, pos, cnt = 0;
|
|
int16_t c[PARAM_N];
|
|
uint8_t r[SHAKE128_RATE];
|
|
uint16_t dmsp = 0;
|
|
uint8_t dmsp_bytes[2];
|
|
|
|
// Use the hash value as key to generate some randomness
|
|
dmsp_bytes[0] = (uint8_t)(dmsp & 0xff);
|
|
dmsp_bytes[1] = (uint8_t)(dmsp >> 8);
|
|
cshake128(r, SHAKE128_RATE, (uint8_t *)NULL, 0, dmsp_bytes, 2, c_bin, CRYPTO_RANDOMBYTES);
|
|
++dmsp;
|
|
|
|
// Use rejection sampling to determine positions to be set in the new vector
|
|
for (i = 0; i < PARAM_N; i++) {
|
|
c[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < PARAM_H;) { // Sample a unique position k times. Use two bytes
|
|
if (cnt > (SHAKE128_RATE - 3)) {
|
|
dmsp_bytes[0] = (uint8_t)(dmsp & 0xff);
|
|
dmsp_bytes[1] = (uint8_t)(dmsp >> 8);
|
|
cshake128(r, SHAKE128_RATE, (uint8_t *)NULL, 0, dmsp_bytes, 2, c_bin, CRYPTO_RANDOMBYTES);
|
|
++dmsp;
|
|
cnt = 0;
|
|
}
|
|
pos = (size_t)((r[cnt] << 8) | (r[cnt + 1]));
|
|
pos = pos & (PARAM_N - 1); // Position is in the range [0,N-1]
|
|
|
|
if (c[pos] == 0) { // Position has not been set yet. Determine sign
|
|
if ((r[cnt + 2] & 1) == 1) {
|
|
c[pos] = -1;
|
|
} else {
|
|
c[pos] = 1;
|
|
}
|
|
pos_list[i] = (uint32_t)pos;
|
|
sign_list[i] = c[pos];
|
|
i++;
|
|
}
|
|
cnt += 3;
|
|
}
|
|
}
|