1
1
mirror of https://github.com/henrydcase/pqc.git synced 2024-11-23 07:59:01 +00:00
pqcrypto/crypto_sign/qtesla-p-I/clean/sample.c
Sebastian 56a0fcb135 qTESLA (#239)
* 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
2019-10-21 14:26:27 +02:00

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_QTESLAPI_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_QTESLAPI_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;
}
}