@@ -1,5 +1,6 @@ | |||
--- | |||
Language: Cpp | |||
BasedOnStyle: LLVM | |||
AllowShortFunctionsOnASingleLine: false | |||
... | |||
@@ -6,7 +6,7 @@ | |||
* by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe */ | |||
#include "fips202.h" | |||
#include <assert.h> | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#define NROUNDS 24 | |||
@@ -22,11 +22,12 @@ | |||
* Returns the loaded 64-bit unsigned integer | |||
**************************************************/ | |||
static uint64_t load64(const unsigned char *x) { | |||
unsigned long long r = 0, i; | |||
unsigned int i; | |||
uint64_t r = 0; | |||
for (i = 0; i < 8; ++i) | |||
r |= (uint64_t)x[i] << 8 * i; | |||
for (i = 0; i < 8; ++i) { | |||
r |= (unsigned long long)x[i] << 8 * i; | |||
} | |||
return r; | |||
} | |||
@@ -41,10 +42,8 @@ static uint64_t load64(const unsigned char *x) { | |||
static void store64(uint8_t *x, uint64_t u) { | |||
unsigned int i; | |||
for (i = 0; i < 8; ++i) { | |||
x[i] = u; | |||
u >>= 8; | |||
} | |||
for (i = 0; i < 8; ++i) | |||
x[i] = u >> 8 * i; | |||
} | |||
/* Keccak round constants */ | |||
@@ -67,9 +66,9 @@ static const uint64_t KeccakF_RoundConstants[NROUNDS] = { | |||
* | |||
* Description: The Keccak F1600 Permutation | |||
* | |||
* Arguments: - uint64_t * state: pointer to in/output Keccak state | |||
* Arguments: - uint64_t *state: pointer to input/output Keccak state | |||
**************************************************/ | |||
void KeccakF1600_StatePermute(uint64_t *state) { | |||
static void KeccakF1600_StatePermute(uint64_t *state) { | |||
int round; | |||
uint64_t Aba, Abe, Abi, Abo, Abu; | |||
@@ -330,35 +329,27 @@ void KeccakF1600_StatePermute(uint64_t *state) { | |||
state[22] = Asi; | |||
state[23] = Aso; | |||
state[24] = Asu; | |||
#undef round | |||
} | |||
#include <string.h> | |||
#define MIN(a, b) ((a) < (b) ? (a) : (b)) | |||
/************************************************* | |||
* Name: keccak_absorb | |||
* | |||
* Description: Absorb step of Keccak; | |||
* non-incremental, starts by zeroeing the state. | |||
* | |||
* Arguments: - uint64_t *s: pointer to (uninitialized) output | |||
*Keccak state | |||
* - unsigned int r: rate in bytes (e.g., 168 for | |||
*SHAKE128) | |||
* - const unsigned char *m: pointer to input to be absorbed into | |||
*s | |||
* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state | |||
* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) | |||
* - const unsigned char *m: pointer to input to be absorbed into s | |||
* - unsigned long long mlen: length of input in bytes | |||
* - unsigned char p: domain-separation byte for different | |||
*Keccak-derived functions | |||
* - unsigned char p: domain-separation byte for different | |||
* Keccak-derived functions | |||
**************************************************/ | |||
static void keccak_absorb(uint64_t *s, unsigned int r, const unsigned char *m, | |||
unsigned long long int mlen, unsigned char p) { | |||
unsigned long long i; | |||
unsigned long long mlen, unsigned char p) { | |||
unsigned int i; | |||
unsigned char t[200]; | |||
// Zero state | |||
/* Zero state */ | |||
for (i = 0; i < 25; ++i) | |||
s[i] = 0; | |||
@@ -386,20 +377,18 @@ static void keccak_absorb(uint64_t *s, unsigned int r, const unsigned char *m, | |||
* | |||
* Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each. | |||
* Modifies the state. Can be called multiple times to keep | |||
*squeezing, i.e., is incremental. | |||
* squeezing, i.e., is incremental. | |||
* | |||
* Arguments: - unsigned char *h: pointer to output blocks | |||
* Arguments: - unsigned char *h: pointer to output blocks | |||
* - unsigned long long int nblocks: number of blocks to be | |||
*squeezed (written to h) | |||
* - uint64_t *s: pointer to in/output Keccak | |||
*state | |||
* - unsigned int r: rate in bytes (e.g., 168 for | |||
*SHAKE128) | |||
* squeezed (written to h) | |||
* - uint64_t *s: pointer to input/output Keccak state | |||
* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) | |||
**************************************************/ | |||
static void keccak_squeezeblocks(unsigned char *h, | |||
unsigned long long int nblocks, uint64_t *s, | |||
unsigned int r) { | |||
static void keccak_squeezeblocks(unsigned char *h, unsigned long nblocks, | |||
uint64_t *s, unsigned int r) { | |||
unsigned int i; | |||
while (nblocks > 0) { | |||
KeccakF1600_StatePermute(s); | |||
for (i = 0; i < (r >> 3); i++) { | |||
@@ -416,63 +405,122 @@ static void keccak_squeezeblocks(unsigned char *h, | |||
* Description: Absorb step of the SHAKE128 XOF. | |||
* non-incremental, starts by zeroeing the state. | |||
* | |||
* Arguments: - uint64_t *s: pointer to (uninitialized) | |||
*output Keccak state | |||
* - const unsigned char *input: pointer to input to be | |||
*absorbed into s | |||
* - unsigned long long inputByteLen: length of input in bytes | |||
* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state | |||
* - const unsigned char *input: pointer to input to be absorbed | |||
* into s | |||
* - unsigned long long inlen: length of input in bytes | |||
**************************************************/ | |||
void shake128_absorb(uint64_t *s, const unsigned char *input, | |||
unsigned int inputByteLen) { | |||
keccak_absorb(s, SHAKE128_RATE, input, inputByteLen, 0x1F); | |||
unsigned long long inlen) { | |||
keccak_absorb(s, SHAKE128_RATE, input, inlen, 0x1F); | |||
} | |||
/************************************************* | |||
* Name: shake128_squeezeblocks | |||
* | |||
* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of | |||
*SHAKE128_RATE bytes each. Modifies the state. Can be called multiple times to | |||
*keep squeezing, i.e., is incremental. | |||
* SHAKE128_RATE bytes each. Modifies the state. Can be called | |||
* multiple times to keep squeezing, i.e., is incremental. | |||
* | |||
* Arguments: - unsigned char *output: pointer to output blocks | |||
* Arguments: - unsigned char *output: pointer to output blocks | |||
* - unsigned long long nblocks: number of blocks to be squeezed | |||
*(written to output) | |||
* - uint64_t *s: pointer to in/output Keccak state | |||
* (written to output) | |||
* - uint64_t *s: pointer to input/output Keccak state | |||
**************************************************/ | |||
void shake128_squeezeblocks(unsigned char *output, unsigned long long nblocks, | |||
void shake128_squeezeblocks(unsigned char *output, unsigned long nblocks, | |||
uint64_t *s) { | |||
keccak_squeezeblocks(output, nblocks, s, SHAKE128_RATE); | |||
} | |||
/************************************************* | |||
* Name: shake256 | |||
* | |||
* Description: SHAKE256 XOF with non-incremental API | |||
* | |||
* Arguments: - unsigned char *output: pointer to output | |||
* - unsigned long long outlen: requested output length in bytes | |||
- const unsigned char *input: pointer to input | |||
- unsigned long long inlen: length of input in bytes | |||
**************************************************/ | |||
void shake256(unsigned char *output, unsigned long long outlen, | |||
* Name: shake256_absorb | |||
* | |||
* Description: Absorb step of the SHAKE256 XOF. | |||
* non-incremental, starts by zeroeing the state. | |||
* | |||
* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state | |||
* - const unsigned char *input: pointer to input to be absorbed | |||
* into s | |||
* - unsigned long long inlen: length of input in bytes | |||
**************************************************/ | |||
void shake256_absorb(uint64_t *s, const unsigned char *input, | |||
unsigned long long inlen) { | |||
keccak_absorb(s, SHAKE256_RATE, input, inlen, 0x1F); | |||
} | |||
/************************************************* | |||
* Name: shake256_squeezeblocks | |||
* | |||
* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of | |||
* SHAKE256_RATE bytes each. Modifies the state. Can be called | |||
* multiple times to keep squeezing, i.e., is incremental. | |||
* | |||
* Arguments: - unsigned char *output: pointer to output blocks | |||
* - unsigned long long nblocks: number of blocks to be squeezed | |||
* (written to output) | |||
* - uint64_t *s: pointer to input/output Keccak state | |||
**************************************************/ | |||
void shake256_squeezeblocks(unsigned char *output, unsigned long nblocks, | |||
uint64_t *s) { | |||
keccak_squeezeblocks(output, nblocks, s, SHAKE256_RATE); | |||
} | |||
/************************************************* | |||
* Name: shake128 | |||
* | |||
* Description: SHAKE128 XOF with non-incremental API | |||
* | |||
* Arguments: - unsigned char *output: pointer to output | |||
* - unsigned long long outlen: requested output length in bytes | |||
* - const unsigned char *input: pointer to input | |||
* - unsigned long long inlen: length of input in bytes | |||
**************************************************/ | |||
void shake128(unsigned char *output, unsigned long long outlen, | |||
const unsigned char *input, unsigned long long inlen) { | |||
unsigned int i; | |||
unsigned long nblocks = outlen / SHAKE128_RATE; | |||
unsigned char t[SHAKE128_RATE]; | |||
uint64_t s[25]; | |||
unsigned char t[SHAKE256_RATE]; | |||
unsigned long long nblocks = outlen / SHAKE256_RATE; | |||
size_t i; | |||
/* Absorb input */ | |||
keccak_absorb(s, SHAKE256_RATE, input, inlen, 0x1F); | |||
shake128_absorb(s, input, inlen); | |||
shake128_squeezeblocks(output, nblocks, s); | |||
/* Squeeze output */ | |||
keccak_squeezeblocks(output, nblocks, s, SHAKE256_RATE); | |||
output += nblocks * SHAKE128_RATE; | |||
outlen -= nblocks * SHAKE128_RATE; | |||
if (outlen) { | |||
shake128_squeezeblocks(t, 1, s); | |||
for (i = 0; i < outlen; ++i) | |||
output[i] = t[i]; | |||
} | |||
} | |||
/************************************************* | |||
* Name: shake256 | |||
* | |||
* Description: SHAKE256 XOF with non-incremental API | |||
* | |||
* Arguments: - unsigned char *output: pointer to output | |||
* - unsigned long long outlen: requested output length in bytes | |||
* - const unsigned char *input: pointer to input | |||
* - unsigned long long inlen: length of input in bytes | |||
**************************************************/ | |||
void shake256(unsigned char *output, unsigned long long outlen, | |||
const unsigned char *input, unsigned long long inlen) { | |||
unsigned int i; | |||
unsigned long nblocks = outlen / SHAKE256_RATE; | |||
unsigned char t[SHAKE256_RATE]; | |||
uint64_t s[25]; | |||
shake256_absorb(s, input, inlen); | |||
shake256_squeezeblocks(output, nblocks, s); | |||
output += nblocks * SHAKE256_RATE; | |||
outlen -= nblocks * SHAKE256_RATE; | |||
if (outlen) { | |||
keccak_squeezeblocks(t, 1, s, SHAKE256_RATE); | |||
for (i = 0; i < outlen; i++) | |||
shake256_squeezeblocks(t, 1, s); | |||
for (i = 0; i < outlen; ++i) | |||
output[i] = t[i]; | |||
} | |||
} | |||
@@ -9,12 +9,23 @@ | |||
#define SHA3_512_RATE 72 | |||
void shake128_absorb(uint64_t *s, const unsigned char *input, | |||
unsigned int inputByteLen); | |||
void shake128_squeezeblocks(unsigned char *output, unsigned long long nblocks, | |||
unsigned long long inlen); | |||
void shake128_squeezeblocks(unsigned char *output, unsigned long nblocks, | |||
uint64_t *s); | |||
void shake256_absorb(uint64_t *s, const unsigned char *input, | |||
unsigned long long inlen); | |||
void shake256_squeezeblocks(unsigned char *output, unsigned long nblocks, | |||
uint64_t *s); | |||
void shake128(unsigned char *output, unsigned long long outlen, | |||
const unsigned char *input, unsigned long long inlen); | |||
void shake256(unsigned char *output, unsigned long long outlen, | |||
const unsigned char *input, unsigned long long inlen); | |||
void sha3_256(unsigned char *output, const unsigned char *input, | |||
unsigned long long inlen); | |||
void sha3_512(unsigned char *output, const unsigned char *input, | |||
@@ -155,7 +155,9 @@ void poly_getnoise(poly *r, const unsigned char *seed, unsigned char nonce) { | |||
* | |||
* Arguments: - uint16_t *r: pointer to in/output polynomial | |||
**************************************************/ | |||
void poly_ntt(poly *r) { ntt(r->coeffs); } | |||
void poly_ntt(poly *r) { | |||
ntt(r->coeffs); | |||
} | |||
/************************************************* | |||
* Name: poly_invntt | |||
@@ -166,7 +168,9 @@ void poly_ntt(poly *r) { ntt(r->coeffs); } | |||
* | |||
* Arguments: - uint16_t *a: pointer to in/output polynomial | |||
**************************************************/ | |||
void poly_invntt(poly *r) { invntt(r->coeffs); } | |||
void poly_invntt(poly *r) { | |||
invntt(r->coeffs); | |||
} | |||
/************************************************* | |||
* Name: poly_add | |||
@@ -0,0 +1,22 @@ | |||
#ifndef API_H | |||
#define API_H | |||
#define MODE 2 | |||
#define CRYPTO_PUBLICKEYBYTES 1472U | |||
#define CRYPTO_SECRETKEYBYTES 3504U | |||
#define CRYPTO_BYTES 2701U | |||
#define CRYPTO_ALGNAME "Dilithium-III" | |||
int crypto_sign_keypair(unsigned char *pk, unsigned char *sk); | |||
int crypto_sign(unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *msg, unsigned long long len, | |||
const unsigned char *sk); | |||
int crypto_sign_open(unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk); | |||
#endif |
@@ -0,0 +1,135 @@ | |||
#include "ntt.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "reduce.h" | |||
/* Roots of unity in order needed by forward ntt */ | |||
static const uint32_t zetas[N] = { | |||
0, 25847, 5771523, 7861508, 237124, 7602457, 7504169, 466468, | |||
1826347, 2353451, 8021166, 6288512, 3119733, 5495562, 3111497, 2680103, | |||
2725464, 1024112, 7300517, 3585928, 7830929, 7260833, 2619752, 6271868, | |||
6262231, 4520680, 6980856, 5102745, 1757237, 8360995, 4010497, 280005, | |||
2706023, 95776, 3077325, 3530437, 6718724, 4788269, 5842901, 3915439, | |||
4519302, 5336701, 3574422, 5512770, 3539968, 8079950, 2348700, 7841118, | |||
6681150, 6736599, 3505694, 4558682, 3507263, 6239768, 6779997, 3699596, | |||
811944, 531354, 954230, 3881043, 3900724, 5823537, 2071892, 5582638, | |||
4450022, 6851714, 4702672, 5339162, 6927966, 3475950, 2176455, 6795196, | |||
7122806, 1939314, 4296819, 7380215, 5190273, 5223087, 4747489, 126922, | |||
3412210, 7396998, 2147896, 2715295, 5412772, 4686924, 7969390, 5903370, | |||
7709315, 7151892, 8357436, 7072248, 7998430, 1349076, 1852771, 6949987, | |||
5037034, 264944, 508951, 3097992, 44288, 7280319, 904516, 3958618, | |||
4656075, 8371839, 1653064, 5130689, 2389356, 8169440, 759969, 7063561, | |||
189548, 4827145, 3159746, 6529015, 5971092, 8202977, 1315589, 1341330, | |||
1285669, 6795489, 7567685, 6940675, 5361315, 4499357, 4751448, 3839961, | |||
2091667, 3407706, 2316500, 3817976, 5037939, 2244091, 5933984, 4817955, | |||
266997, 2434439, 7144689, 3513181, 4860065, 4621053, 7183191, 5187039, | |||
900702, 1859098, 909542, 819034, 495491, 6767243, 8337157, 7857917, | |||
7725090, 5257975, 2031748, 3207046, 4823422, 7855319, 7611795, 4784579, | |||
342297, 286988, 5942594, 4108315, 3437287, 5038140, 1735879, 203044, | |||
2842341, 2691481, 5790267, 1265009, 4055324, 1247620, 2486353, 1595974, | |||
4613401, 1250494, 2635921, 4832145, 5386378, 1869119, 1903435, 7329447, | |||
7047359, 1237275, 5062207, 6950192, 7929317, 1312455, 3306115, 6417775, | |||
7100756, 1917081, 5834105, 7005614, 1500165, 777191, 2235880, 3406031, | |||
7838005, 5548557, 6709241, 6533464, 5796124, 4656147, 594136, 4603424, | |||
6366809, 2432395, 2454455, 8215696, 1957272, 3369112, 185531, 7173032, | |||
5196991, 162844, 1616392, 3014001, 810149, 1652634, 4686184, 6581310, | |||
5341501, 3523897, 3866901, 269760, 2213111, 7404533, 1717735, 472078, | |||
7953734, 1723600, 6577327, 1910376, 6712985, 7276084, 8119771, 4546524, | |||
5441381, 6144432, 7959518, 6094090, 183443, 7403526, 1612842, 4834730, | |||
7826001, 3919660, 8332111, 7018208, 3937738, 1400424, 7534263, 1976782}; | |||
/* Roots of unity in order needed by inverse ntt */ | |||
static const uint32_t zetas_inv[N] = { | |||
6403635, 846154, 6979993, 4442679, 1362209, 48306, 4460757, 554416, | |||
3545687, 6767575, 976891, 8196974, 2286327, 420899, 2235985, 2939036, | |||
3833893, 260646, 1104333, 1667432, 6470041, 1803090, 6656817, 426683, | |||
7908339, 6662682, 975884, 6167306, 8110657, 4513516, 4856520, 3038916, | |||
1799107, 3694233, 6727783, 7570268, 5366416, 6764025, 8217573, 3183426, | |||
1207385, 8194886, 5011305, 6423145, 164721, 5925962, 5948022, 2013608, | |||
3776993, 7786281, 3724270, 2584293, 1846953, 1671176, 2831860, 542412, | |||
4974386, 6144537, 7603226, 6880252, 1374803, 2546312, 6463336, 1279661, | |||
1962642, 5074302, 7067962, 451100, 1430225, 3318210, 7143142, 1333058, | |||
1050970, 6476982, 6511298, 2994039, 3548272, 5744496, 7129923, 3767016, | |||
6784443, 5894064, 7132797, 4325093, 7115408, 2590150, 5688936, 5538076, | |||
8177373, 6644538, 3342277, 4943130, 4272102, 2437823, 8093429, 8038120, | |||
3595838, 768622, 525098, 3556995, 5173371, 6348669, 3122442, 655327, | |||
522500, 43260, 1613174, 7884926, 7561383, 7470875, 6521319, 7479715, | |||
3193378, 1197226, 3759364, 3520352, 4867236, 1235728, 5945978, 8113420, | |||
3562462, 2446433, 6136326, 3342478, 4562441, 6063917, 4972711, 6288750, | |||
4540456, 3628969, 3881060, 3019102, 1439742, 812732, 1584928, 7094748, | |||
7039087, 7064828, 177440, 2409325, 1851402, 5220671, 3553272, 8190869, | |||
1316856, 7620448, 210977, 5991061, 3249728, 6727353, 8578, 3724342, | |||
4421799, 7475901, 1100098, 8336129, 5282425, 7871466, 8115473, 3343383, | |||
1430430, 6527646, 7031341, 381987, 1308169, 22981, 1228525, 671102, | |||
2477047, 411027, 3693493, 2967645, 5665122, 6232521, 983419, 4968207, | |||
8253495, 3632928, 3157330, 3190144, 1000202, 4083598, 6441103, 1257611, | |||
1585221, 6203962, 4904467, 1452451, 3041255, 3677745, 1528703, 3930395, | |||
2797779, 6308525, 2556880, 4479693, 4499374, 7426187, 7849063, 7568473, | |||
4680821, 1600420, 2140649, 4873154, 3821735, 4874723, 1643818, 1699267, | |||
539299, 6031717, 300467, 4840449, 2867647, 4805995, 3043716, 3861115, | |||
4464978, 2537516, 3592148, 1661693, 4849980, 5303092, 8284641, 5674394, | |||
8100412, 4369920, 19422, 6623180, 3277672, 1399561, 3859737, 2118186, | |||
2108549, 5760665, 1119584, 549488, 4794489, 1079900, 7356305, 5654953, | |||
5700314, 5268920, 2884855, 5260684, 2091905, 359251, 6026966, 6554070, | |||
7913949, 876248, 777960, 8143293, 518909, 2608894, 8354570}; | |||
/************************************************* | |||
* Name: ntt | |||
* | |||
* Description: Forward NTT, in-place. No modular reduction is performed after | |||
* additions or subtractions. Hence output coefficients can be up | |||
* to 16*Q larger than the coefficients of the input polynomial. | |||
* Output vector is in bitreversed order. | |||
* | |||
* Arguments: - uint32_t p[N]: input/output coefficient array | |||
**************************************************/ | |||
void ntt(uint32_t p[N]) { | |||
unsigned int len, start, j, k; | |||
uint32_t zeta, t; | |||
k = 1; | |||
for (len = 128; len > 0; len >>= 1) { | |||
for (start = 0; start < N; start = j + len) { | |||
zeta = zetas[k++]; | |||
for (j = start; j < start + len; ++j) { | |||
t = montgomery_reduce((uint64_t)zeta * p[j + len]); | |||
p[j + len] = p[j] + 2 * Q - t; | |||
p[j] = p[j] + t; | |||
} | |||
} | |||
} | |||
} | |||
/************************************************* | |||
* Name: invntt_frominvmont | |||
* | |||
* Description: Inverse NTT and multiplication by Montgomery factor 2^32. | |||
* In-place. No modular reductions after additions or | |||
* subtractions. Input coefficient need to be smaller than 2*Q. | |||
* Output coefficient are smaller than 2*Q. | |||
* | |||
* Arguments: - uint32_t p[N]: input/output coefficient array | |||
**************************************************/ | |||
void invntt_frominvmont(uint32_t p[N]) { | |||
unsigned int start, len, j, k; | |||
uint32_t t, zeta; | |||
const uint32_t f = | |||
(((uint64_t)MONT * MONT % Q) * (Q - 1) % Q) * ((Q - 1) >> 8) % Q; | |||
k = 0; | |||
for (len = 1; len < N; len <<= 1) { | |||
for (start = 0; start < N; start = j + len) { | |||
zeta = zetas_inv[k++]; | |||
for (j = start; j < start + len; ++j) { | |||
t = p[j]; | |||
p[j] = t + p[j + len]; | |||
p[j + len] = t + 256 * Q - p[j + len]; | |||
p[j + len] = montgomery_reduce((uint64_t)zeta * p[j + len]); | |||
} | |||
} | |||
} | |||
for (j = 0; j < N; ++j) { | |||
p[j] = montgomery_reduce((uint64_t)f * p[j]); | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
#ifndef NTT_H | |||
#define NTT_H | |||
#include "params.h" | |||
#include <stdint.h> | |||
void ntt(uint32_t p[N]); | |||
void invntt_frominvmont(uint32_t p[N]); | |||
#endif |
@@ -0,0 +1,256 @@ | |||
#include "packing.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
/************************************************* | |||
* Name: pack_pk | |||
* | |||
* Description: Bit-pack public key pk = (rho, t1). | |||
* | |||
* Arguments: - unsigned char pk[]: output byte array | |||
* - const unsigned char rho[]: byte array containing rho | |||
* - const polyveck *t1: pointer to vector t1 | |||
**************************************************/ | |||
void pack_pk(unsigned char pk[CRYPTO_PUBLICKEYBYTES], | |||
const unsigned char rho[SEEDBYTES], const polyveck *t1) { | |||
unsigned int i; | |||
for (i = 0; i < SEEDBYTES; ++i) | |||
pk[i] = rho[i]; | |||
pk += SEEDBYTES; | |||
for (i = 0; i < K; ++i) | |||
polyt1_pack(pk + i * POLT1_SIZE_PACKED, t1->vec + i); | |||
} | |||
/************************************************* | |||
* Name: unpack_pk | |||
* | |||
* Description: Unpack public key pk = (rho, t1). | |||
* | |||
* Arguments: - const unsigned char rho[]: output byte array for rho | |||
* - const polyveck *t1: pointer to output vector t1 | |||
* - unsigned char pk[]: byte array containing bit-packed pk | |||
**************************************************/ | |||
void unpack_pk(unsigned char rho[SEEDBYTES], polyveck *t1, | |||
const unsigned char pk[CRYPTO_PUBLICKEYBYTES]) { | |||
unsigned int i; | |||
for (i = 0; i < SEEDBYTES; ++i) | |||
rho[i] = pk[i]; | |||
pk += SEEDBYTES; | |||
for (i = 0; i < K; ++i) | |||
polyt1_unpack(t1->vec + i, pk + i * POLT1_SIZE_PACKED); | |||
} | |||
/************************************************* | |||
* Name: pack_sk | |||
* | |||
* Description: Bit-pack secret key sk = (rho, key, tr, s1, s2, t0). | |||
* | |||
* Arguments: - unsigned char sk[]: output byte array | |||
* - const unsigned char rho[]: byte array containing rho | |||
* - const unsigned char key[]: byte array containing key | |||
* - const unsigned char tr[]: byte array containing tr | |||
* - const polyvecl *s1: pointer to vector s1 | |||
* - const polyveck *s2: pointer to vector s2 | |||
* - const polyveck *t0: pointer to vector t0 | |||
**************************************************/ | |||
void pack_sk(unsigned char sk[CRYPTO_SECRETKEYBYTES], | |||
const unsigned char rho[SEEDBYTES], | |||
const unsigned char key[SEEDBYTES], | |||
const unsigned char tr[CRHBYTES], const polyvecl *s1, | |||
const polyveck *s2, const polyveck *t0) { | |||
unsigned int i; | |||
for (i = 0; i < SEEDBYTES; ++i) | |||
sk[i] = rho[i]; | |||
sk += SEEDBYTES; | |||
for (i = 0; i < SEEDBYTES; ++i) | |||
sk[i] = key[i]; | |||
sk += SEEDBYTES; | |||
for (i = 0; i < CRHBYTES; ++i) | |||
sk[i] = tr[i]; | |||
sk += CRHBYTES; | |||
for (i = 0; i < L; ++i) | |||
polyeta_pack(sk + i * POLETA_SIZE_PACKED, s1->vec + i); | |||
sk += L * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) | |||
polyeta_pack(sk + i * POLETA_SIZE_PACKED, s2->vec + i); | |||
sk += K * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) | |||
polyt0_pack(sk + i * POLT0_SIZE_PACKED, t0->vec + i); | |||
} | |||
/************************************************* | |||
* Name: unpack_sk | |||
* | |||
* Description: Unpack secret key sk = (rho, key, tr, s1, s2, t0). | |||
* | |||
* Arguments: - const unsigned char rho[]: output byte array for rho | |||
* - const unsigned char key[]: output byte array for key | |||
* - const unsigned char tr[]: output byte array for tr | |||
* - const polyvecl *s1: pointer to output vector s1 | |||
* - const polyveck *s2: pointer to output vector s2 | |||
* - const polyveck *r0: pointer to output vector t0 | |||
* - unsigned char sk[]: byte array containing bit-packed sk | |||
**************************************************/ | |||
void unpack_sk(unsigned char rho[SEEDBYTES], unsigned char key[SEEDBYTES], | |||
unsigned char tr[CRHBYTES], polyvecl *s1, polyveck *s2, | |||
polyveck *t0, const unsigned char sk[CRYPTO_SECRETKEYBYTES]) { | |||
unsigned int i; | |||
for (i = 0; i < SEEDBYTES; ++i) | |||
rho[i] = sk[i]; | |||
sk += SEEDBYTES; | |||
for (i = 0; i < SEEDBYTES; ++i) | |||
key[i] = sk[i]; | |||
sk += SEEDBYTES; | |||
for (i = 0; i < CRHBYTES; ++i) | |||
tr[i] = sk[i]; | |||
sk += CRHBYTES; | |||
for (i = 0; i < L; ++i) | |||
polyeta_unpack(s1->vec + i, sk + i * POLETA_SIZE_PACKED); | |||
sk += L * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) | |||
polyeta_unpack(s2->vec + i, sk + i * POLETA_SIZE_PACKED); | |||
sk += K * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) | |||
polyt0_unpack(t0->vec + i, sk + i * POLT0_SIZE_PACKED); | |||
} | |||
/************************************************* | |||
* Name: pack_sig | |||
* | |||
* Description: Bit-pack signature sig = (z, h, c). | |||
* | |||
* Arguments: - unsigned char sig[]: output byte array | |||
* - const polyvecl *z: pointer to vector z | |||
* - const polyveck *h: pointer to hint vector h | |||
* - const poly *c: pointer to challenge polynomial | |||
**************************************************/ | |||
void pack_sig(unsigned char sig[CRYPTO_BYTES], const polyvecl *z, | |||
const polyveck *h, const poly *c) { | |||
unsigned int i, j, k; | |||
uint64_t signs, mask; | |||
for (i = 0; i < L; ++i) | |||
polyz_pack(sig + i * POLZ_SIZE_PACKED, z->vec + i); | |||
sig += L * POLZ_SIZE_PACKED; | |||
/* Encode h */ | |||
k = 0; | |||
for (i = 0; i < K; ++i) { | |||
for (j = 0; j < N; ++j) | |||
if (h->vec[i].coeffs[j] != 0) | |||
sig[k++] = j; | |||
sig[OMEGA + i] = k; | |||
} | |||
while (k < OMEGA) | |||
sig[k++] = 0; | |||
sig += OMEGA + K; | |||
/* Encode c */ | |||
signs = 0; | |||
mask = 1; | |||
for (i = 0; i < N / 8; ++i) { | |||
sig[i] = 0; | |||
for (j = 0; j < 8; ++j) { | |||
if (c->coeffs[8 * i + j] != 0) { | |||
sig[i] |= (1U << j); | |||
if (c->coeffs[8 * i + j] == (Q - 1)) | |||
signs |= mask; | |||
mask <<= 1; | |||
} | |||
} | |||
} | |||
sig += N / 8; | |||
for (i = 0; i < 8; ++i) | |||
sig[i] = signs >> 8 * i; | |||
} | |||
/************************************************* | |||
* Name: unpack_sig | |||
* | |||
* Description: Unpack signature sig = (z, h, c). | |||
* | |||
* Arguments: - polyvecl *z: pointer to output vector z | |||
* - polyveck *h: pointer to output hint vector h | |||
* - poly *c: pointer to output challenge polynomial | |||
* - const unsigned char sig[]: byte array containing | |||
* bit-packed signature | |||
* | |||
* Returns 1 in case of malformed signature; otherwise 0. | |||
**************************************************/ | |||
int unpack_sig(polyvecl *z, polyveck *h, poly *c, | |||
const unsigned char sig[CRYPTO_BYTES]) { | |||
unsigned int i, j, k; | |||
uint64_t signs, mask; | |||
for (i = 0; i < L; ++i) | |||
polyz_unpack(z->vec + i, sig + i * POLZ_SIZE_PACKED); | |||
sig += L * POLZ_SIZE_PACKED; | |||
/* Decode h */ | |||
k = 0; | |||
for (i = 0; i < K; ++i) { | |||
for (j = 0; j < N; ++j) | |||
h->vec[i].coeffs[j] = 0; | |||
if (sig[OMEGA + i] < k || sig[OMEGA + i] > OMEGA) | |||
return 1; | |||
for (j = k; j < sig[OMEGA + i]; ++j) { | |||
/* Coefficients are ordered for strong unforgeability */ | |||
if (j > k && sig[j] <= sig[j - 1]) | |||
return 1; | |||
h->vec[i].coeffs[sig[j]] = 1; | |||
} | |||
k = sig[OMEGA + i]; | |||
} | |||
/* Extra indices are zero for strong unforgeability */ | |||
for (j = k; j < OMEGA; ++j) | |||
if (sig[j]) | |||
return 1; | |||
sig += OMEGA + K; | |||
/* Decode c */ | |||
for (i = 0; i < N; ++i) | |||
c->coeffs[i] = 0; | |||
signs = 0; | |||
for (i = 0; i < 8; ++i) | |||
signs |= (uint64_t)sig[N / 8 + i] << 8 * i; | |||
/* Extra sign bits are zero for strong unforgeability */ | |||
if (signs >> 60) | |||
return 1; | |||
mask = 1; | |||
for (i = 0; i < N / 8; ++i) { | |||
for (j = 0; j < 8; ++j) { | |||
if ((sig[i] >> j) & 0x01) { | |||
c->coeffs[8 * i + j] = (signs & mask) ? Q - 1 : 1; | |||
mask <<= 1; | |||
} | |||
} | |||
} | |||
return 0; | |||
} |
@@ -0,0 +1,25 @@ | |||
#ifndef PACKING_H | |||
#define PACKING_H | |||
#include "params.h" | |||
#include "polyvec.h" | |||
void pack_pk(unsigned char pk[CRYPTO_PUBLICKEYBYTES], | |||
const unsigned char rho[SEEDBYTES], const polyveck *t1); | |||
void pack_sk(unsigned char sk[CRYPTO_SECRETKEYBYTES], | |||
const unsigned char rho[SEEDBYTES], | |||
const unsigned char key[SEEDBYTES], | |||
const unsigned char tr[CRHBYTES], const polyvecl *s1, | |||
const polyveck *s2, const polyveck *t0); | |||
void pack_sig(unsigned char sig[CRYPTO_BYTES], const polyvecl *z, | |||
const polyveck *h, const poly *c); | |||
void unpack_pk(unsigned char rho[SEEDBYTES], polyveck *t1, | |||
const unsigned char pk[CRYPTO_PUBLICKEYBYTES]); | |||
void unpack_sk(unsigned char rho[SEEDBYTES], unsigned char key[SEEDBYTES], | |||
unsigned char tr[CRHBYTES], polyvecl *s1, polyveck *s2, | |||
polyveck *t0, const unsigned char sk[CRYPTO_SECRETKEYBYTES]); | |||
int unpack_sig(polyvecl *z, polyveck *h, poly *c, | |||
const unsigned char sig[CRYPTO_BYTES]); | |||
#endif |
@@ -0,0 +1,68 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
#ifndef MODE | |||
#define MODE 2 | |||
#endif | |||
#define SEEDBYTES 32U | |||
#define CRHBYTES 48U | |||
#define N 256U | |||
#define Q 8380417U | |||
#define QBITS 23U | |||
#define ROOT_OF_UNITY 1753U | |||
#define D 14U | |||
#define GAMMA1 ((Q - 1U) / 16U) | |||
#define GAMMA2 (GAMMA1 / 2U) | |||
#define ALPHA (2U * GAMMA2) | |||
#if MODE == 0 | |||
#define K 3U | |||
#define L 2U | |||
#define ETA 7U | |||
#define SETABITS 4U | |||
#define BETA 375U | |||
#define OMEGA 64U | |||
#elif MODE == 1 | |||
#define K 4U | |||
#define L 3U | |||
#define ETA 6U | |||
#define SETABITS 4U | |||
#define BETA 325U | |||
#define OMEGA 80U | |||
#elif MODE == 2 | |||
#define K 5U | |||
#define L 4U | |||
#define ETA 5U | |||
#define SETABITS 4U | |||
#define BETA 275U | |||
#define OMEGA 96U | |||
#elif MODE == 3 | |||
#define K 6U | |||
#define L 5U | |||
#define ETA 3U | |||
#define SETABITS 3U | |||
#define BETA 175U | |||
#define OMEGA 120U | |||
#endif | |||
#define POL_SIZE_PACKED ((N * QBITS) / 8) | |||
#define POLT1_SIZE_PACKED ((N * (QBITS - D)) / 8) | |||
#define POLT0_SIZE_PACKED ((N * D) / 8) | |||
#define POLETA_SIZE_PACKED ((N * SETABITS) / 8) | |||
#define POLZ_SIZE_PACKED ((N * (QBITS - 3)) / 8) | |||
#define POLW1_SIZE_PACKED ((N * 4) / 8) | |||
#define POLVECK_SIZE_PACKED (K * POL_SIZE_PACKED) | |||
#define POLVECL_SIZE_PACKED (L * POL_SIZE_PACKED) | |||
#define CRYPTO_PUBLICKEYBYTES (SEEDBYTES + K * POLT1_SIZE_PACKED) | |||
#define CRYPTO_SECRETKEYBYTES \ | |||
(2 * SEEDBYTES + (L + K) * POLETA_SIZE_PACKED + CRHBYTES + \ | |||
K * POLT0_SIZE_PACKED) | |||
#define CRYPTO_BYTES (L * POLZ_SIZE_PACKED + (OMEGA + K) + (N / 8 + 8)) | |||
#endif |
@@ -0,0 +1,764 @@ | |||
#include "poly.h" | |||
#include "fips202.h" | |||
#include "ntt.h" | |||
#include "params.h" | |||
#include "reduce.h" | |||
#include "rounding.h" | |||
#include <stdint.h> | |||
/************************************************* | |||
* Name: poly_reduce | |||
* | |||
* Description: Reduce all coefficients of input polynomial to representative | |||
* in [0,2*Q[. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void poly_reduce(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
a->coeffs[i] = reduce32(a->coeffs[i]); | |||
} | |||
/************************************************* | |||
* Name: poly_csubq | |||
* | |||
* Description: For all coefficients of input polynomial subtract Q if | |||
* coefficient is bigger than Q. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void poly_csubq(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
a->coeffs[i] = csubq(a->coeffs[i]); | |||
} | |||
/************************************************* | |||
* Name: poly_freeze | |||
* | |||
* Description: Reduce all coefficients of the polynomial to standard | |||
* representatives. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void poly_freeze(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
a->coeffs[i] = freeze(a->coeffs[i]); | |||
} | |||
/************************************************* | |||
* Name: poly_add | |||
* | |||
* Description: Add polynomials. No modular reduction is performed. | |||
* | |||
* Arguments: - poly *c: pointer to output polynomial | |||
* - const poly *a: pointer to first summand | |||
* - const poly *b: pointer to second summand | |||
**************************************************/ | |||
void poly_add(poly *c, const poly *a, const poly *b) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
c->coeffs[i] = a->coeffs[i] + b->coeffs[i]; | |||
} | |||
/************************************************* | |||
* Name: poly_sub | |||
* | |||
* Description: Subtract polynomials. Assumes coefficients of second input | |||
* polynomial to be less than 2*Q. No modular reduction is | |||
* performed. | |||
* | |||
* Arguments: - poly *c: pointer to output polynomial | |||
* - const poly *a: pointer to first input polynomial | |||
* - const poly *b: pointer to second input polynomial to be | |||
* subtraced from first input polynomial | |||
**************************************************/ | |||
void poly_sub(poly *c, const poly *a, const poly *b) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
c->coeffs[i] = a->coeffs[i] + 2 * Q - b->coeffs[i]; | |||
} | |||
/************************************************* | |||
* Name: poly_neg | |||
* | |||
* Description: Negate polynomial. Assumes input coefficients to be standard | |||
* representatives. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void poly_neg(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
a->coeffs[i] = Q - a->coeffs[i]; | |||
} | |||
/************************************************* | |||
* Name: poly_shiftl | |||
* | |||
* Description: Multiply polynomial by 2^k without modular reduction. Assumes | |||
* input coefficients to be less than 2^{32-k}. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
* - unsigned int k: exponent | |||
**************************************************/ | |||
void poly_shiftl(poly *a, unsigned int k) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
a->coeffs[i] <<= k; | |||
} | |||
/************************************************* | |||
* Name: poly_ntt | |||
* | |||
* Description: Forward NTT. Output coefficients can be up to 16*Q larger than | |||
* input coefficients. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void poly_ntt(poly *a) { | |||
ntt(a->coeffs); | |||
} | |||
/************************************************* | |||
* Name: poly_invntt_montgomery | |||
* | |||
* Description: Inverse NTT and multiplication with 2^{32}. Input coefficients | |||
* need to be less than 2*Q. Output coefficients are less than 2*Q. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void poly_invntt_montgomery(poly *a) { | |||
invntt_frominvmont(a->coeffs); | |||
} | |||
/************************************************* | |||
* Name: poly_pointwise_invmontgomery | |||
* | |||
* Description: Pointwise multiplication of polynomials in NTT domain | |||
* representation and multiplication of resulting polynomial | |||
* with 2^{-32}. Output coefficients are less than 2*Q if input | |||
* coefficient are less than 22*Q. | |||
* | |||
* Arguments: - poly *c: pointer to output polynomial | |||
* - const poly *a: pointer to first input polynomial | |||
* - const poly *b: pointer to second input polynomial | |||
**************************************************/ | |||
void poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
c->coeffs[i] = montgomery_reduce((uint64_t)a->coeffs[i] * b->coeffs[i]); | |||
} | |||
/************************************************* | |||
* Name: poly_power2round | |||
* | |||
* Description: For all coefficients c of the input polynomial, | |||
* compute c0, c1 such that c mod Q = c1*2^D + c0 | |||
* with -2^{D-1} < c0 <= 2^{D-1}. Assumes coefficients to be | |||
* standard representatives. | |||
* | |||
* Arguments: - poly *a1: pointer to output polynomial with coefficients c1 | |||
* - poly *a0: pointer to output polynomial with coefficients Q + | |||
*a0 | |||
* - const poly *v: pointer to input polynomial | |||
**************************************************/ | |||
void poly_power2round(poly *a1, poly *a0, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
a1->coeffs[i] = power2round(a->coeffs[i], a0->coeffs + i); | |||
} | |||
/************************************************* | |||
* Name: poly_decompose | |||
* | |||
* Description: For all coefficients c of the input polynomial, | |||
* compute high and low bits c0, c1 such c mod Q = c1*ALPHA + c0 | |||
* with -ALPHA/2 < c0 <= ALPHA/2 except c1 = (Q-1)/ALPHA where we | |||
* set c1 = 0 and -ALPHA/2 <= c0 = c mod Q - Q < 0. | |||
* Assumes coefficients to be standard representatives. | |||
* | |||
* Arguments: - poly *a1: pointer to output polynomial with coefficients c1 | |||
* - poly *a0: pointer to output polynomial with coefficients Q + | |||
*a0 | |||
* - const poly *c: pointer to input polynomial | |||
**************************************************/ | |||
void poly_decompose(poly *a1, poly *a0, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
a1->coeffs[i] = decompose(a->coeffs[i], a0->coeffs + i); | |||
} | |||
/************************************************* | |||
* Name: poly_make_hint | |||
* | |||
* Description: Compute hint polynomial. The coefficients of which indicate | |||
* whether the high bits of the corresponding coefficients | |||
* of the first input polynomial and of the sum of the input | |||
* polynomials differ. | |||
* | |||
* Arguments: - poly *h: pointer to output hint polynomial | |||
* - const poly *a: pointer to first input polynomial | |||
* - const poly *b: pointer to second input polynomial | |||
* | |||
* Returns number of 1 bits. | |||
**************************************************/ | |||
unsigned int poly_make_hint(poly *h, const poly *a, const poly *b) { | |||
unsigned int i, s = 0; | |||
for (i = 0; i < N; ++i) { | |||
h->coeffs[i] = make_hint(a->coeffs[i], b->coeffs[i]); | |||
s += h->coeffs[i]; | |||
} | |||
return s; | |||
} | |||
/************************************************* | |||
* Name: poly_use_hint | |||
* | |||
* Description: Use hint polynomial to correct the high bits of a polynomial. | |||
* | |||
* Arguments: - poly *a: pointer to output polynomial with corrected high bits | |||
* - const poly *b: pointer to input polynomial | |||
* - const poly *h: pointer to input hint polynomial | |||
**************************************************/ | |||
void poly_use_hint(poly *a, const poly *b, const poly *h) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) | |||
a->coeffs[i] = use_hint(b->coeffs[i], h->coeffs[i]); | |||
} | |||
/************************************************* | |||
* Name: poly_chknorm | |||
* | |||
* Description: Check infinity norm of polynomial against given bound. | |||
* Assumes input coefficients to be standard representatives. | |||
* | |||
* Arguments: - const poly *a: pointer to polynomial | |||
* - uint32_t B: norm bound | |||
* | |||
* Returns 0 if norm is strictly smaller than B and 1 otherwise. | |||
**************************************************/ | |||
int poly_chknorm(const poly *a, uint32_t B) { | |||
unsigned int i; | |||
int32_t t; | |||
/* It is ok to leak which coefficient violates the bound since | |||
the probability for each coefficient is independent of secret | |||
data but we must not leak the sign of the centralized representative. */ | |||
for (i = 0; i < N; ++i) { | |||
/* Absolute value of centralized representative */ | |||
t = (Q - 1) / 2 - a->coeffs[i]; | |||
t ^= (t >> 31); | |||
t = (Q - 1) / 2 - t; | |||
if ((uint32_t)t >= B) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
/************************************************* | |||
* Name: poly_uniform | |||
* | |||
* Description: Sample uniformly random polynomial using stream of random bytes. | |||
* Assumes that enough random bytes are given (e.g. | |||
* 5*SHAKE128_RATE bytes). | |||
* | |||
* Arguments: - poly *a: pointer to output polynomial | |||
* - const unsigned char *buf: array of random bytes | |||
**************************************************/ | |||
void poly_uniform(poly *a, const unsigned char *buf) { | |||
unsigned int ctr, pos; | |||
uint32_t t; | |||
ctr = pos = 0; | |||
while (ctr < N) { | |||
t = buf[pos++]; | |||
t |= (uint32_t)buf[pos++] << 8; | |||
t |= (uint32_t)buf[pos++] << 16; | |||
t &= 0x7FFFFF; | |||
if (t < Q) | |||
a->coeffs[ctr++] = t; | |||
} | |||
} | |||
/************************************************* | |||
* Name: rej_eta | |||
* | |||
* Description: Sample uniformly random coefficients in [-ETA, ETA] by | |||
* performing rejection sampling using array of random bytes. | |||
* | |||
* Arguments: - uint32_t *a: pointer to output array (allocated) | |||
* - unsigned int len: number of coefficients to be sampled | |||
* - const unsigned char *buf: array of random bytes | |||
* - unsigned int buflen: length of array of random bytes | |||
* | |||
* Returns number of sampled coefficients. Can be smaller than len if not enough | |||
* random bytes were given. | |||
**************************************************/ | |||
static unsigned int rej_eta(uint32_t *a, unsigned int len, | |||
const unsigned char *buf, unsigned int buflen) { | |||
#if ETA > 7 | |||
#error "rej_eta() assumes ETA <= 7" | |||
#endif | |||
unsigned int ctr, pos; | |||
unsigned char t0, t1; | |||
ctr = pos = 0; | |||
while (ctr < len && pos < buflen) { | |||
#if ETA <= 3 | |||
t0 = buf[pos] & 0x07; | |||
t1 = buf[pos++] >> 5; | |||
#else | |||
t0 = buf[pos] & 0x0F; | |||
t1 = buf[pos++] >> 4; | |||
#endif | |||
if (t0 <= 2 * ETA) | |||
a[ctr++] = Q + ETA - t0; | |||
if (t1 <= 2 * ETA && ctr < len) | |||
a[ctr++] = Q + ETA - t1; | |||
} | |||
return ctr; | |||
} | |||
/************************************************* | |||
* Name: poly_uniform_eta | |||
* | |||
* Description: Sample polynomial with uniformly random coefficients | |||
* in [-ETA,ETA] by performing rejection sampling using the | |||
* output stream from SHAKE256(seed|nonce). | |||
* | |||
* Arguments: - poly *a: pointer to output polynomial | |||
* - const unsigned char seed[]: byte array with seed of length | |||
* SEEDBYTES | |||
* - unsigned char nonce: nonce byte | |||
**************************************************/ | |||
void poly_uniform_eta(poly *a, const unsigned char seed[SEEDBYTES], | |||
unsigned char nonce) { | |||
unsigned int i, ctr; | |||
unsigned char inbuf[SEEDBYTES + 1]; | |||
/* Probability that we need more than 2 blocks: < 2^{-84} | |||
Probability that we need more than 3 blocks: < 2^{-352} */ | |||
unsigned char outbuf[2 * SHAKE256_RATE]; | |||
uint64_t state[25]; | |||
for (i = 0; i < SEEDBYTES; ++i) | |||
inbuf[i] = seed[i]; | |||
inbuf[SEEDBYTES] = nonce; | |||
shake256_absorb(state, inbuf, SEEDBYTES + 1); | |||
shake256_squeezeblocks(outbuf, 2, state); | |||
ctr = rej_eta(a->coeffs, N, outbuf, 2 * SHAKE256_RATE); | |||
if (ctr < N) { | |||
shake256_squeezeblocks(outbuf, 1, state); | |||
rej_eta(a->coeffs + ctr, N - ctr, outbuf, SHAKE256_RATE); | |||
} | |||
} | |||
/************************************************* | |||
* Name: rej_gamma1m1 | |||
* | |||
* Description: Sample uniformly random coefficients | |||
* in [-(GAMMA1 - 1), GAMMA1 - 1] by performing rejection sampling | |||
* using array of random bytes. | |||
* | |||
* Arguments: - uint32_t *a: pointer to output array (allocated) | |||
* - unsigned int len: number of coefficients to be sampled | |||
* - const unsigned char *buf: array of random bytes | |||
* - unsigned int buflen: length of array of random bytes | |||
* | |||
* Returns number of sampled coefficients. Can be smaller than len if not enough | |||
* random bytes were given. | |||
**************************************************/ | |||
static unsigned int rej_gamma1m1(uint32_t *a, unsigned int len, | |||
const unsigned char *buf, | |||
unsigned int buflen) { | |||
#if GAMMA1 > (1 << 19) | |||
#error "rej_gamma1m1() assumes GAMMA1 - 1 fits in 19 bits" | |||
#endif | |||
unsigned int ctr, pos; | |||
uint32_t t0, t1; | |||
ctr = pos = 0; | |||
while (ctr < len && pos + 5 <= buflen) { | |||
t0 = buf[pos]; | |||
t0 |= (uint32_t)buf[pos + 1] << 8; | |||
t0 |= (uint32_t)buf[pos + 2] << 16; | |||
t0 &= 0xFFFFF; | |||
t1 = buf[pos + 2] >> 4; | |||
t1 |= (uint32_t)buf[pos + 3] << 4; | |||
t1 |= (uint32_t)buf[pos + 4] << 12; | |||
pos += 5; | |||
if (t0 <= 2 * GAMMA1 - 2) | |||
a[ctr++] = Q + GAMMA1 - 1 - t0; | |||
if (t1 <= 2 * GAMMA1 - 2 && ctr < len) | |||
a[ctr++] = Q + GAMMA1 - 1 - t1; | |||
} | |||
return ctr; | |||
} | |||
/************************************************* | |||
* Name: poly_uniform_gamma1m1 | |||
* | |||
* Description: Sample polynomial with uniformly random coefficients | |||
* in [-(GAMMA1 - 1), GAMMA1 - 1] by performing rejection | |||
* sampling on output stream of SHAKE256(seed|nonce). | |||
* | |||
* Arguments: - poly *a: pointer to output polynomial | |||
* - const unsigned char seed[]: byte array with seed of length | |||
* SEEDBYTES + CRHBYTES | |||
* - uint16_t nonce: 16-bit nonce | |||
**************************************************/ | |||
void poly_uniform_gamma1m1(poly *a, | |||
const unsigned char seed[SEEDBYTES + CRHBYTES], | |||
uint16_t nonce) { | |||
unsigned int i, ctr; | |||
unsigned char inbuf[SEEDBYTES + CRHBYTES + 2]; | |||
/* Probability that we need more than 5 blocks: < 2^{-81} | |||
Probability that we need more than 6 blocks: < 2^{-467} */ | |||
unsigned char outbuf[5 * SHAKE256_RATE]; | |||
uint64_t state[25]; | |||
for (i = 0; i < SEEDBYTES + CRHBYTES; ++i) | |||
inbuf[i] = seed[i]; | |||
inbuf[SEEDBYTES + CRHBYTES] = nonce & 0xFF; | |||
inbuf[SEEDBYTES + CRHBYTES + 1] = nonce >> 8; | |||
shake256_absorb(state, inbuf, SEEDBYTES + CRHBYTES + 2); | |||
shake256_squeezeblocks(outbuf, 5, state); | |||
ctr = rej_gamma1m1(a->coeffs, N, outbuf, 5 * SHAKE256_RATE); | |||
if (ctr < N) { | |||
/* There are no bytes left in outbuf | |||
since 5*SHAKE256_RATE is divisible by 5 */ | |||
shake256_squeezeblocks(outbuf, 1, state); | |||
rej_gamma1m1(a->coeffs + ctr, N - ctr, outbuf, SHAKE256_RATE); | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyeta_pack | |||
* | |||
* Description: Bit-pack polynomial with coefficients in [-ETA,ETA]. | |||
* Input coefficients are assumed to lie in [Q-ETA,Q+ETA]. | |||
* | |||
* Arguments: - unsigned char *r: pointer to output byte array with at least | |||
* POLETA_SIZE_PACKED bytes | |||
* - const poly *a: pointer to input polynomial | |||
**************************************************/ | |||
void polyeta_pack(unsigned char *r, const poly *a) { | |||
#if ETA > 7 | |||
#error "polyeta_pack() assumes ETA <= 7" | |||
#endif | |||
unsigned int i; | |||
unsigned char t[8]; | |||
#if ETA <= 3 | |||
for (i = 0; i < N / 8; ++i) { | |||
t[0] = Q + ETA - a->coeffs[8 * i + 0]; | |||
t[1] = Q + ETA - a->coeffs[8 * i + 1]; | |||
t[2] = Q + ETA - a->coeffs[8 * i + 2]; | |||
t[3] = Q + ETA - a->coeffs[8 * i + 3]; | |||
t[4] = Q + ETA - a->coeffs[8 * i + 4]; | |||
t[5] = Q + ETA - a->coeffs[8 * i + 5]; | |||
t[6] = Q + ETA - a->coeffs[8 * i + 6]; | |||
t[7] = Q + ETA - a->coeffs[8 * i + 7]; | |||
r[3 * i + 0] = t[0]; | |||
r[3 * i + 0] |= t[1] << 3; | |||
r[3 * i + 0] |= t[2] << 6; | |||
r[3 * i + 1] = t[2] >> 2; | |||
r[3 * i + 1] |= t[3] << 1; | |||
r[3 * i + 1] |= t[4] << 4; | |||
r[3 * i + 1] |= t[5] << 7; | |||
r[3 * i + 2] = t[5] >> 1; | |||
r[3 * i + 2] |= t[6] << 2; | |||
r[3 * i + 2] |= t[7] << 5; | |||
} | |||
#else | |||
for (i = 0; i < N / 2; ++i) { | |||
t[0] = Q + ETA - a->coeffs[2 * i + 0]; | |||
t[1] = Q + ETA - a->coeffs[2 * i + 1]; | |||
r[i] = t[0] | (t[1] << 4); | |||
} | |||
#endif | |||
} | |||
/************************************************* | |||
* Name: polyeta_unpack | |||
* | |||
* Description: Unpack polynomial with coefficients in [-ETA,ETA]. | |||
* Output coefficients lie in [Q-ETA,Q+ETA]. | |||
* | |||
* Arguments: - poly *r: pointer to output polynomial | |||
* - const unsigned char *a: byte array with bit-packed polynomial | |||
**************************************************/ | |||
void polyeta_unpack(poly *r, const unsigned char *a) { | |||
unsigned int i; | |||
#if ETA <= 3 | |||
for (i = 0; i < N / 8; ++i) { | |||
r->coeffs[8 * i + 0] = a[3 * i + 0] & 0x07; | |||
r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 0x07; | |||
r->coeffs[8 * i + 2] = (a[3 * i + 0] >> 6) | ((a[3 * i + 1] & 0x01) << 2); | |||
r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 0x07; | |||
r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 0x07; | |||
r->coeffs[8 * i + 5] = (a[3 * i + 1] >> 7) | ((a[3 * i + 2] & 0x03) << 1); | |||
r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 0x07; | |||
r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5); | |||
r->coeffs[8 * i + 0] = Q + ETA - r->coeffs[8 * i + 0]; | |||
r->coeffs[8 * i + 1] = Q + ETA - r->coeffs[8 * i + 1]; | |||
r->coeffs[8 * i + 2] = Q + ETA - r->coeffs[8 * i + 2]; | |||
r->coeffs[8 * i + 3] = Q + ETA - r->coeffs[8 * i + 3]; | |||
r->coeffs[8 * i + 4] = Q + ETA - r->coeffs[8 * i + 4]; | |||
r->coeffs[8 * i + 5] = Q + ETA - r->coeffs[8 * i + 5]; | |||
r->coeffs[8 * i + 6] = Q + ETA - r->coeffs[8 * i + 6]; | |||
r->coeffs[8 * i + 7] = Q + ETA - r->coeffs[8 * i + 7]; | |||
} | |||
#else | |||
for (i = 0; i < N / 2; ++i) { | |||
r->coeffs[2 * i + 0] = a[i] & 0x0F; | |||
r->coeffs[2 * i + 1] = a[i] >> 4; | |||
r->coeffs[2 * i + 0] = Q + ETA - r->coeffs[2 * i + 0]; | |||
r->coeffs[2 * i + 1] = Q + ETA - r->coeffs[2 * i + 1]; | |||
} | |||
#endif | |||
} | |||
/************************************************* | |||
* Name: polyt1_pack | |||
* | |||
* Description: Bit-pack polynomial t1 with coefficients fitting in 9 bits. | |||
* Input coefficients are assumed to be standard representatives. | |||
* | |||
* Arguments: - unsigned char *r: pointer to output byte array with at least | |||
* POLT1_SIZE_PACKED bytes | |||
* - const poly *a: pointer to input polynomial | |||
**************************************************/ | |||
void polyt1_pack(unsigned char *r, const poly *a) { | |||
#if D != 14 | |||
#error "polyt1_pack() assumes D == 14" | |||
#endif | |||
unsigned int i; | |||
for (i = 0; i < N / 8; ++i) { | |||
r[9 * i + 0] = a->coeffs[8 * i + 0] & 0xFF; | |||
r[9 * i + 1] = | |||
(a->coeffs[8 * i + 0] >> 8) | ((a->coeffs[8 * i + 1] & 0x7F) << 1); | |||
r[9 * i + 2] = | |||
(a->coeffs[8 * i + 1] >> 7) | ((a->coeffs[8 * i + 2] & 0x3F) << 2); | |||
r[9 * i + 3] = | |||
(a->coeffs[8 * i + 2] >> 6) | ((a->coeffs[8 * i + 3] & 0x1F) << 3); | |||
r[9 * i + 4] = | |||
(a->coeffs[8 * i + 3] >> 5) | ((a->coeffs[8 * i + 4] & 0x0F) << 4); | |||
r[9 * i + 5] = | |||
(a->coeffs[8 * i + 4] >> 4) | ((a->coeffs[8 * i + 5] & 0x07) << 5); | |||
r[9 * i + 6] = | |||
(a->coeffs[8 * i + 5] >> 3) | ((a->coeffs[8 * i + 6] & 0x03) << 6); | |||
r[9 * i + 7] = | |||
(a->coeffs[8 * i + 6] >> 2) | ((a->coeffs[8 * i + 7] & 0x01) << 7); | |||
r[9 * i + 8] = a->coeffs[8 * i + 7] >> 1; | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyt1_unpack | |||
* | |||
* Description: Unpack polynomial t1 with 9-bit coefficients. | |||
* Output coefficients are standard representatives. | |||
* | |||
* Arguments: - poly *r: pointer to output polynomial | |||
* - const unsigned char *a: byte array with bit-packed polynomial | |||
**************************************************/ | |||
void polyt1_unpack(poly *r, const unsigned char *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 8; ++i) { | |||
r->coeffs[8 * i + 0] = | |||
a[9 * i + 0] | ((uint32_t)(a[9 * i + 1] & 0x01) << 8); | |||
r->coeffs[8 * i + 1] = | |||
(a[9 * i + 1] >> 1) | ((uint32_t)(a[9 * i + 2] & 0x03) << 7); | |||
r->coeffs[8 * i + 2] = | |||
(a[9 * i + 2] >> 2) | ((uint32_t)(a[9 * i + 3] & 0x07) << 6); | |||
r->coeffs[8 * i + 3] = | |||
(a[9 * i + 3] >> 3) | ((uint32_t)(a[9 * i + 4] & 0x0F) << 5); | |||
r->coeffs[8 * i + 4] = | |||
(a[9 * i + 4] >> 4) | ((uint32_t)(a[9 * i + 5] & 0x1F) << 4); | |||
r->coeffs[8 * i + 5] = | |||
(a[9 * i + 5] >> 5) | ((uint32_t)(a[9 * i + 6] & 0x3F) << 3); | |||
r->coeffs[8 * i + 6] = | |||
(a[9 * i + 6] >> 6) | ((uint32_t)(a[9 * i + 7] & 0x7F) << 2); | |||
r->coeffs[8 * i + 7] = | |||
(a[9 * i + 7] >> 7) | ((uint32_t)(a[9 * i + 8] & 0xFF) << 1); | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyt0_pack | |||
* | |||
* Description: Bit-pack polynomial t0 with coefficients in ]-2^{D-1}, 2^{D-1}]. | |||
* Input coefficients are assumed to lie in ]Q-2^{D-1}, Q+2^{D-1}]. | |||
* | |||
* Arguments: - unsigned char *r: pointer to output byte array with at least | |||
* POLT0_SIZE_PACKED bytes | |||
* - const poly *a: pointer to input polynomial | |||
**************************************************/ | |||
void polyt0_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
uint32_t t[4]; | |||
for (i = 0; i < N / 4; ++i) { | |||
t[0] = Q + (1 << (D - 1)) - a->coeffs[4 * i + 0]; | |||
t[1] = Q + (1 << (D - 1)) - a->coeffs[4 * i + 1]; | |||
t[2] = Q + (1 << (D - 1)) - a->coeffs[4 * i + 2]; | |||
t[3] = Q + (1 << (D - 1)) - a->coeffs[4 * i + 3]; | |||
r[7 * i + 0] = t[0]; | |||
r[7 * i + 1] = t[0] >> 8; | |||
r[7 * i + 1] |= t[1] << 6; | |||
r[7 * i + 2] = t[1] >> 2; | |||
r[7 * i + 3] = t[1] >> 10; | |||
r[7 * i + 3] |= t[2] << 4; | |||
r[7 * i + 4] = t[2] >> 4; | |||
r[7 * i + 5] = t[2] >> 12; | |||
r[7 * i + 5] |= t[3] << 2; | |||
r[7 * i + 6] = t[3] >> 6; | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyt0_unpack | |||
* | |||
* Description: Unpack polynomial t0 with coefficients in ]-2^{D-1}, 2^{D-1}]. | |||
* Output coefficients lie in ]Q-2^{D-1},Q+2^{D-1}]. | |||
* | |||
* Arguments: - poly *r: pointer to output polynomial | |||
* - const unsigned char *a: byte array with bit-packed polynomial | |||
**************************************************/ | |||
void polyt0_unpack(poly *r, const unsigned char *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 4; ++i) { | |||
r->coeffs[4 * i + 0] = a[7 * i + 0]; | |||
r->coeffs[4 * i + 0] |= (uint32_t)(a[7 * i + 1] & 0x3F) << 8; | |||
r->coeffs[4 * i + 1] = a[7 * i + 1] >> 6; | |||
r->coeffs[4 * i + 1] |= (uint32_t)a[7 * i + 2] << 2; | |||
r->coeffs[4 * i + 1] |= (uint32_t)(a[7 * i + 3] & 0x0F) << 10; | |||
r->coeffs[4 * i + 2] = a[7 * i + 3] >> 4; | |||
r->coeffs[4 * i + 2] |= (uint32_t)a[7 * i + 4] << 4; | |||
r->coeffs[4 * i + 2] |= (uint32_t)(a[7 * i + 5] & 0x03) << 12; | |||
r->coeffs[4 * i + 3] = a[7 * i + 5] >> 2; | |||
r->coeffs[4 * i + 3] |= (uint32_t)a[7 * i + 6] << 6; | |||
r->coeffs[4 * i + 0] = Q + (1 << (D - 1)) - r->coeffs[4 * i + 0]; | |||
r->coeffs[4 * i + 1] = Q + (1 << (D - 1)) - r->coeffs[4 * i + 1]; | |||
r->coeffs[4 * i + 2] = Q + (1 << (D - 1)) - r->coeffs[4 * i + 2]; | |||
r->coeffs[4 * i + 3] = Q + (1 << (D - 1)) - r->coeffs[4 * i + 3]; | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyz_pack | |||
* | |||
* Description: Bit-pack polynomial z with coefficients | |||
* in [-(GAMMA1 - 1), GAMMA1 - 1]. | |||
* Input coefficients are assumed to be standard representatives. | |||
* | |||
* Arguments: - unsigned char *r: pointer to output byte array with at least | |||
* POLZ_SIZE_PACKED bytes | |||
* - const poly *a: pointer to input polynomial | |||
**************************************************/ | |||
void polyz_pack(unsigned char *r, const poly *a) { | |||
#if GAMMA1 > (1 << 19) | |||
#error "polyz_pack() assumes GAMMA1 <= 2^{19}" | |||
#endif | |||
unsigned int i; | |||
uint32_t t[2]; | |||
for (i = 0; i < N / 2; ++i) { | |||
/* Map to {0,...,2*GAMMA1 - 2} */ | |||
t[0] = GAMMA1 - 1 - a->coeffs[2 * i + 0]; | |||
t[0] += ((int32_t)t[0] >> 31) & Q; | |||
t[1] = GAMMA1 - 1 - a->coeffs[2 * i + 1]; | |||
t[1] += ((int32_t)t[1] >> 31) & Q; | |||
r[5 * i + 0] = t[0]; | |||
r[5 * i + 1] = t[0] >> 8; | |||
r[5 * i + 2] = t[0] >> 16; | |||
r[5 * i + 2] |= t[1] << 4; | |||
r[5 * i + 3] = t[1] >> 4; | |||
r[5 * i + 4] = t[1] >> 12; | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyz_unpack | |||
* | |||
* Description: Unpack polynomial z with coefficients | |||
* in [-(GAMMA1 - 1), GAMMA1 - 1]. | |||
* Output coefficients are standard representatives. | |||
* | |||
* Arguments: - poly *r: pointer to output polynomial | |||
* - const unsigned char *a: byte array with bit-packed polynomial | |||
**************************************************/ | |||
void polyz_unpack(poly *r, const unsigned char *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 2; ++i) { | |||
r->coeffs[2 * i + 0] = a[5 * i + 0]; | |||
r->coeffs[2 * i + 0] |= (uint32_t)a[5 * i + 1] << 8; | |||
r->coeffs[2 * i + 0] |= (uint32_t)(a[5 * i + 2] & 0x0F) << 16; | |||
r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4; | |||
r->coeffs[2 * i + 1] |= (uint32_t)a[5 * i + 3] << 4; | |||
r->coeffs[2 * i + 1] |= (uint32_t)a[5 * i + 4] << 12; | |||
r->coeffs[2 * i + 0] = GAMMA1 - 1 - r->coeffs[2 * i + 0]; | |||
r->coeffs[2 * i + 0] += ((int32_t)r->coeffs[2 * i + 0] >> 31) & Q; | |||
r->coeffs[2 * i + 1] = GAMMA1 - 1 - r->coeffs[2 * i + 1]; | |||
r->coeffs[2 * i + 1] += ((int32_t)r->coeffs[2 * i + 1] >> 31) & Q; | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyw1_pack | |||
* | |||
* Description: Bit-pack polynomial w1 with coefficients in [0, 15]. | |||
* Input coefficients are assumed to be standard representatives. | |||
* | |||
* Arguments: - unsigned char *r: pointer to output byte array with at least | |||
* POLW1_SIZE_PACKED bytes | |||
* - const poly *a: pointer to input polynomial | |||
**************************************************/ | |||
void polyw1_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 2; ++i) | |||
r[i] = a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4); | |||
} |
@@ -0,0 +1,51 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
#include "fips202.h" | |||
#include "params.h" | |||
#include <stdint.h> | |||
typedef struct { | |||
uint32_t coeffs[N]; | |||
} poly __attribute__((aligned(32))); | |||
void poly_reduce(poly *a); | |||
void poly_csubq(poly *a); | |||
void poly_freeze(poly *a); | |||
void poly_add(poly *c, const poly *a, const poly *b); | |||
void poly_sub(poly *c, const poly *a, const poly *b); | |||
void poly_neg(poly *a); | |||
void poly_shiftl(poly *a, unsigned int k); | |||
void poly_ntt(poly *a); | |||
void poly_invntt_montgomery(poly *a); | |||
void poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b); | |||
void poly_power2round(poly *a1, poly *a0, const poly *a); | |||
void poly_decompose(poly *a1, poly *a0, const poly *a); | |||
unsigned int poly_make_hint(poly *h, const poly *a, const poly *b); | |||
void poly_use_hint(poly *a, const poly *b, const poly *h); | |||
int poly_chknorm(const poly *a, uint32_t B); | |||
void poly_uniform(poly *a, const unsigned char *buf); | |||
void poly_uniform_eta(poly *a, const unsigned char seed[SEEDBYTES], | |||
unsigned char nonce); | |||
void poly_uniform_gamma1m1(poly *a, | |||
const unsigned char seed[SEEDBYTES + CRHBYTES], | |||
uint16_t nonce); | |||
void polyeta_pack(unsigned char *r, const poly *a); | |||
void polyeta_unpack(poly *r, const unsigned char *a); | |||
void polyt1_pack(unsigned char *r, const poly *a); | |||
void polyt1_unpack(poly *r, const unsigned char *a); | |||
void polyt0_pack(unsigned char *r, const poly *a); | |||
void polyt0_unpack(poly *r, const unsigned char *a); | |||
void polyz_pack(unsigned char *r, const poly *a); | |||
void polyz_unpack(poly *r, const unsigned char *a); | |||
void polyw1_pack(unsigned char *r, const poly *a); | |||
#endif |
@@ -0,0 +1,338 @@ | |||
#include "polyvec.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
/**************************************************************/ | |||
/************ Vectors of polynomials of length L **************/ | |||
/**************************************************************/ | |||
/************************************************* | |||
* Name: polyvecl_freeze | |||
* | |||
* Description: Reduce coefficients of polynomials in vector of length L | |||
* to standard representatives. | |||
* | |||
* Arguments: - polyvecl *v: pointer to input/output vector | |||
**************************************************/ | |||
void polyvecl_freeze(polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) | |||
poly_freeze(v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyvecl_add | |||
* | |||
* Description: Add vectors of polynomials of length L. | |||
* No modular reduction is performed. | |||
* | |||
* Arguments: - polyvecl *w: pointer to output vector | |||
* - const polyvecl *u: pointer to first summand | |||
* - const polyvecl *v: pointer to second summand | |||
**************************************************/ | |||
void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) | |||
poly_add(w->vec + i, u->vec + i, v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyvecl_ntt | |||
* | |||
* Description: Forward NTT of all polynomials in vector of length L. Output | |||
* coefficients can be up to 16*Q larger than input coefficients. | |||
* | |||
* Arguments: - polyvecl *v: pointer to input/output vector | |||
**************************************************/ | |||
void polyvecl_ntt(polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) | |||
poly_ntt(v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyvecl_pointwise_acc_invmontgomery | |||
* | |||
* Description: Pointwise multiply vectors of polynomials of length L, multiply | |||
* resulting vector by 2^{-32} and add (accumulate) polynomials | |||
* in it. Input/output vectors are in NTT domain representation. | |||
* Input coefficients are assumed to be less than 22*Q. Output | |||
* coeffcient are less than 2*L*Q. | |||
* | |||
* Arguments: - poly *w: output polynomial | |||
* - const polyvecl *u: pointer to first input vector | |||
* - const polyvecl *v: pointer to second input vector | |||
**************************************************/ | |||
void polyvecl_pointwise_acc_invmontgomery(poly *w, const polyvecl *u, | |||
const polyvecl *v) { | |||
unsigned int i; | |||
poly t; | |||
poly_pointwise_invmontgomery(w, u->vec + 0, v->vec + 0); | |||
for (i = 1; i < L; ++i) { | |||
poly_pointwise_invmontgomery(&t, u->vec + i, v->vec + i); | |||
poly_add(w, w, &t); | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyvecl_chknorm | |||
* | |||
* Description: Check infinity norm of polynomials in vector of length L. | |||
* Assumes input coefficients to be standard representatives. | |||
* | |||
* Arguments: - const polyvecl *v: pointer to vector | |||
* - uint32_t B: norm bound | |||
* | |||
* Returns 0 if norm of all polynomials is strictly smaller than B and 1 | |||
* otherwise. | |||
**************************************************/ | |||
int polyvecl_chknorm(const polyvecl *v, uint32_t bound) { | |||
unsigned int i; | |||
int ret = 0; | |||
for (i = 0; i < L; ++i) | |||
ret |= poly_chknorm(v->vec + i, bound); | |||
return ret; | |||
} | |||
/**************************************************************/ | |||
/************ Vectors of polynomials of length K **************/ | |||
/**************************************************************/ | |||
/************************************************* | |||
* Name: polyveck_reduce | |||
* | |||
* Description: Reduce coefficients of polynomials in vector of length K | |||
* to representatives in [0,2*Q[. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
**************************************************/ | |||
void polyveck_reduce(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_reduce(v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_csubq | |||
* | |||
* Description: For all coefficients of polynomials in vector of length K | |||
* subtract Q if coefficient is bigger than Q. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
**************************************************/ | |||
void polyveck_csubq(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_csubq(v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_freeze | |||
* | |||
* Description: Reduce coefficients of polynomials in vector of length K | |||
* to standard representatives. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
**************************************************/ | |||
void polyveck_freeze(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_freeze(v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_add | |||
* | |||
* Description: Add vectors of polynomials of length K. | |||
* No modular reduction is performed. | |||
* | |||
* Arguments: - polyveck *w: pointer to output vector | |||
* - const polyveck *u: pointer to first summand | |||
* - const polyveck *v: pointer to second summand | |||
**************************************************/ | |||
void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_add(w->vec + i, u->vec + i, v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_sub | |||
* | |||
* Description: Subtract vectors of polynomials of length K. | |||
* Assumes coefficients of polynomials in second input vector | |||
* to be less than 2*Q. No modular reduction is performed. | |||
* | |||
* Arguments: - polyveck *w: pointer to output vector | |||
* - const polyveck *u: pointer to first input vector | |||
* - const polyveck *v: pointer to second input vector to be | |||
* subtracted from first input vector | |||
**************************************************/ | |||
void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_sub(w->vec + i, u->vec + i, v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_shiftl | |||
* | |||
* Description: Multiply vector of polynomials of Length K by 2^k without | |||
*modular reduction. Assumes input coefficients to be less than 2^{32-k}. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
* - unsigned int k: exponent | |||
**************************************************/ | |||
void polyveck_shiftl(polyveck *v, unsigned int k) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_shiftl(v->vec + i, k); | |||
} | |||
/************************************************* | |||
* Name: polyveck_ntt | |||
* | |||
* Description: Forward NTT of all polynomials in vector of length K. Output | |||
* coefficients can be up to 16*Q larger than input coefficients. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
**************************************************/ | |||
void polyveck_ntt(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_ntt(v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_invntt_montgomery | |||
* | |||
* Description: Inverse NTT and multiplication by 2^{32} of polynomials | |||
* in vector of length K. Input coefficients need to be less | |||
* than 2*Q. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
**************************************************/ | |||
void polyveck_invntt_montgomery(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_invntt_montgomery(v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_chknorm | |||
* | |||
* Description: Check infinity norm of polynomials in vector of length K. | |||
* Assumes input coefficients to be standard representatives. | |||
* | |||
* Arguments: - const polyveck *v: pointer to vector | |||
* - uint32_t B: norm bound | |||
* | |||
* Returns 0 if norm of all polynomials are strictly smaller than B and 1 | |||
* otherwise. | |||
**************************************************/ | |||
int polyveck_chknorm(const polyveck *v, uint32_t bound) { | |||
unsigned int i; | |||
int ret = 0; | |||
for (i = 0; i < K; ++i) | |||
ret |= poly_chknorm(v->vec + i, bound); | |||
return ret; | |||
} | |||
/************************************************* | |||
* Name: polyveck_power2round | |||
* | |||
* Description: For all coefficients a of polynomials in vector of length K, | |||
* compute a0, a1 such that a mod Q = a1*2^D + a0 | |||
* with -2^{D-1} < a0 <= 2^{D-1}. Assumes coefficients to be | |||
* standard representatives. | |||
* | |||
* Arguments: - polyveck *v1: pointer to output vector of polynomials with | |||
* coefficients a1 | |||
* - polyveck *v0: pointer to output vector of polynomials with | |||
* coefficients Q + a0 | |||
* - const polyveck *v: pointer to input vector | |||
**************************************************/ | |||
void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_power2round(v1->vec + i, v0->vec + i, v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_decompose | |||
* | |||
* Description: For all coefficients a of polynomials in vector of length K, | |||
* compute high and low bits a0, a1 such a mod Q = a1*ALPHA + a0 | |||
* with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (Q-1)/ALPHA where we | |||
* set a1 = 0 and -ALPHA/2 <= a0 = a mod Q - Q < 0. | |||
* Assumes coefficients to be standard representatives. | |||
* | |||
* Arguments: - polyveck *v1: pointer to output vector of polynomials with | |||
* coefficients a1 | |||
* - polyveck *v0: pointer to output vector of polynomials with | |||
* coefficients Q + a0 | |||
* - const polyveck *v: pointer to input vector | |||
**************************************************/ | |||
void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_decompose(v1->vec + i, v0->vec + i, v->vec + i); | |||
} | |||
/************************************************* | |||
* Name: polyveck_make_hint | |||
* | |||
* Description: Compute hint vector. | |||
* | |||
* Arguments: - polyveck *h: pointer to output vector | |||
* - const polyveck *u: pointer to first input vector | |||
* - const polyveck *u: pointer to second input vector | |||
* | |||
* Returns number of 1 bits. | |||
**************************************************/ | |||
unsigned int polyveck_make_hint(polyveck *h, const polyveck *u, | |||
const polyveck *v) { | |||
unsigned int i, s = 0; | |||
for (i = 0; i < K; ++i) | |||
s += poly_make_hint(h->vec + i, u->vec + i, v->vec + i); | |||
return s; | |||
} | |||
/************************************************* | |||
* Name: polyveck_use_hint | |||
* | |||
* Description: Use hint vector to correct the high bits of input vector. | |||
* | |||
* Arguments: - polyveck *w: pointer to output vector of polynomials with | |||
* corrected high bits | |||
* - const polyveck *u: pointer to input vector | |||
* - const polyveck *h: pointer to input hint vector | |||
**************************************************/ | |||
void polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) | |||
poly_use_hint(w->vec + i, u->vec + i, h->vec + i); | |||
} |
@@ -0,0 +1,47 @@ | |||
#ifndef POLYVEC_H | |||
#define POLYVEC_H | |||
#include "params.h" | |||
#include "poly.h" | |||
#include <stdint.h> | |||
/* Vectors of polynomials of length L */ | |||
typedef struct { | |||
poly vec[L]; | |||
} polyvecl; | |||
void polyvecl_freeze(polyvecl *v); | |||
void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v); | |||
void polyvecl_ntt(polyvecl *v); | |||
void polyvecl_pointwise_acc_invmontgomery(poly *w, const polyvecl *u, | |||
const polyvecl *v); | |||
int polyvecl_chknorm(const polyvecl *v, uint32_t B); | |||
/* Vectors of polynomials of length K */ | |||
typedef struct { | |||
poly vec[K]; | |||
} polyveck; | |||
void polyveck_reduce(polyveck *v); | |||
void polyveck_csubq(polyveck *v); | |||
void polyveck_freeze(polyveck *v); | |||
void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v); | |||
void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v); | |||
void polyveck_shiftl(polyveck *v, unsigned int k); | |||
void polyveck_ntt(polyveck *v); | |||
void polyveck_invntt_montgomery(polyveck *v); | |||
int polyveck_chknorm(const polyveck *v, uint32_t B); | |||
void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v); | |||
void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v); | |||
unsigned int polyveck_make_hint(polyveck *h, const polyveck *u, | |||
const polyveck *v); | |||
void polyveck_use_hint(polyveck *w, const polyveck *v, const polyveck *h); | |||
#endif |
@@ -0,0 +1,74 @@ | |||
#include "reduce.h" | |||
#include "params.h" | |||
#include <stdint.h> | |||
/************************************************* | |||
* Name: montgomery_reduce | |||
* | |||
* Description: For finite field element a with 0 <= a <= Q*2^32, | |||
* compute r \equiv a*2^{-32} (mod Q) such that 0 <= r < 2*Q. | |||
* | |||
* Arguments: - uint64_t: finite field element a | |||
* | |||
* Returns r. | |||
**************************************************/ | |||
uint32_t montgomery_reduce(uint64_t a) { | |||
uint64_t t; | |||
t = a * QINV; | |||
t &= (1ULL << 32) - 1; | |||
t *= Q; | |||
t = a + t; | |||
t >>= 32; | |||
return t; | |||
} | |||
/************************************************* | |||
* Name: reduce32 | |||
* | |||
* Description: For finite field element a, compute r \equiv a (mod Q) | |||
* such that 0 <= r < 2*Q. | |||
* | |||
* Arguments: - uint32_t: finite field element a | |||
* | |||
* Returns r. | |||
**************************************************/ | |||
uint32_t reduce32(uint32_t a) { | |||
uint32_t t; | |||
t = a & 0x7FFFFF; | |||
a >>= 23; | |||
t += (a << 13) - a; | |||
return t; | |||
} | |||
/************************************************* | |||
* Name: csubq | |||
* | |||
* Description: Subtract Q if input coefficient is bigger than Q. | |||
* | |||
* Arguments: - uint32_t: finite field element a | |||
* | |||
* Returns r. | |||
**************************************************/ | |||
uint32_t csubq(uint32_t a) { | |||
a -= Q; | |||
a += ((int32_t)a >> 31) & Q; | |||
return a; | |||
} | |||
/************************************************* | |||
* Name: freeze | |||
* | |||
* Description: For finite field element a, compute standard | |||
* representative r = a mod Q. | |||
* | |||
* Arguments: - uint32_t: finite field element a | |||
* | |||
* Returns r. | |||
**************************************************/ | |||
uint32_t freeze(uint32_t a) { | |||
a = reduce32(a); | |||
a = csubq(a); | |||
return a; | |||
} |
@@ -0,0 +1,21 @@ | |||
#ifndef REDUCE_H | |||
#define REDUCE_H | |||
#include <stdint.h> | |||
#define MONT 4193792U // 2^32 % Q | |||
#define QINV 4236238847U // -q^(-1) mod 2^32 | |||
/* a <= Q*2^32 => r < 2*Q */ | |||
uint32_t montgomery_reduce(uint64_t a); | |||
/* r < 2*Q */ | |||
uint32_t reduce32(uint32_t a); | |||
/* a < 2*Q => r < Q */ | |||
uint32_t csubq(uint32_t a); | |||
/* r < Q */ | |||
uint32_t freeze(uint32_t a); | |||
#endif |
@@ -0,0 +1,115 @@ | |||
#include "params.h" | |||
#include <stdint.h> | |||
/************************************************* | |||
* Name: power2round | |||
* | |||
* Description: For finite field element a, compute a0, a1 such that | |||
* a mod Q = a1*2^D + a0 with -2^{D-1} < a0 <= 2^{D-1}. | |||
* Assumes a to be standard representative. | |||
* | |||
* Arguments: - uint32_t a: input element | |||
* - uint32_t *a0: pointer to output element Q + a0 | |||
* | |||
* Returns a1. | |||
**************************************************/ | |||
uint32_t power2round(uint32_t a, uint32_t *a0) { | |||
int32_t t; | |||
/* Centralized remainder mod 2^D */ | |||
t = a & ((1 << D) - 1); | |||
t -= (1 << (D - 1)) + 1; | |||
t += (t >> 31) & (1 << D); | |||
t -= (1 << (D - 1)) - 1; | |||
*a0 = Q + t; | |||
a = (a - t) >> D; | |||
return a; | |||
} | |||
/************************************************* | |||
* Name: decompose | |||
* | |||
* Description: For finite field element a, compute high and low bits a0, a1 | |||
*such that a mod Q = a1*ALPHA + a0 with -ALPHA/2 < a0 <= ALPHA/2 except if a1 = | |||
*(Q-1)/ALPHA where we set a1 = 0 and -ALPHA/2 <= a0 = a mod Q - Q < 0. Assumes | |||
*a to be standard representative. | |||
* | |||
* Arguments: - uint32_t a: input element | |||
* - uint32_t *a0: pointer to output element Q + a0 | |||
* | |||
* Returns a1. | |||
**************************************************/ | |||
uint32_t decompose(uint32_t a, uint32_t *a0) { | |||
#if ALPHA != (Q - 1) / 16 | |||
#error "decompose assumes ALPHA == (Q-1)/16" | |||
#endif | |||
int32_t t, u; | |||
/* Centralized remainder mod ALPHA */ | |||
t = a & 0x7FFFF; | |||
t += (a >> 19) << 9; | |||
t -= ALPHA / 2 + 1; | |||
t += (t >> 31) & ALPHA; | |||
t -= ALPHA / 2 - 1; | |||
a -= t; | |||
/* Divide by ALPHA (possible to avoid) */ | |||
u = a - 1; | |||
u >>= 31; | |||
a = (a >> 19) + 1; | |||
a -= u & 1; | |||
/* Border case */ | |||
*a0 = Q + t - (a >> 4); | |||
a &= 0xF; | |||
return a; | |||
} | |||
/************************************************* | |||
* Name: make_hint | |||
* | |||
* Description: Compute hint bit indicating whether or not high bits of two | |||
* finite field elements differ. Assumes input elements to be | |||
* standard representatives. | |||
* | |||
* Arguments: - uint32_t a: first input element | |||
* - uint32_t b: second input element | |||
* | |||
* Returns 1 if high bits of a and b differ and 0 otherwise. | |||
**************************************************/ | |||
unsigned int make_hint(const uint32_t a, const uint32_t b) { | |||
uint32_t t; | |||
return decompose(a, &t) != decompose(b, &t); | |||
} | |||
/************************************************* | |||
* Name: use_hint | |||
* | |||
* Description: Correct high bits according to hint. | |||
* | |||
* Arguments: - uint32_t a: input element | |||
* - unsigned int hint: hint bit | |||
* | |||
* Returns corrected high bits. | |||
**************************************************/ | |||
uint32_t use_hint(const uint32_t a, const unsigned int hint) { | |||
uint32_t a0, a1; | |||
a1 = decompose(a, &a0); | |||
if (hint == 0) | |||
return a1; | |||
else if (a0 > Q) | |||
return (a1 + 1) & 0xF; | |||
else | |||
return (a1 - 1) & 0xF; | |||
/* If decompose does not divide out ALPHA: | |||
if(hint == 0) | |||
return a1; | |||
else if(a0 > Q) | |||
return (a1 + ALPHA) % (Q - 1); | |||
else | |||
return (a1 - ALPHA) % (Q - 1); | |||
*/ | |||
} |
@@ -0,0 +1,11 @@ | |||
#ifndef ROUNDING_H | |||
#define ROUNDING_H | |||
#include <stdint.h> | |||
uint32_t power2round(const uint32_t a, uint32_t *a0); | |||
uint32_t decompose(uint32_t a, uint32_t *a0); | |||
unsigned int make_hint(const uint32_t a, const uint32_t b); | |||
uint32_t use_hint(const uint32_t a, const unsigned int hint); | |||
#endif |
@@ -0,0 +1,360 @@ | |||
#include "sign.h" | |||
#include "fips202.h" | |||
#include "packing.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
#include "randombytes.h" | |||
#include <stdint.h> | |||
/************************************************* | |||
* Name: expand_mat | |||
* | |||
* Description: Implementation of ExpandA. Generates matrix A with uniformly | |||
* random coefficients a_{i,j} by performing rejection | |||
* sampling on the output stream of SHAKE128(rho|i|j). | |||
* | |||
* Arguments: - polyvecl mat[K]: output matrix | |||
* - const unsigned char rho[]: byte array containing seed rho | |||
**************************************************/ | |||
void expand_mat(polyvecl mat[K], const unsigned char rho[SEEDBYTES]) { | |||
unsigned int i, j; | |||
unsigned char inbuf[SEEDBYTES + 1]; | |||
/* Don't change this to smaller values, | |||
* sampling later assumes sufficient SHAKE output! | |||
* Probability that we need more than 5 blocks: < 2^{-132}. | |||
* Probability that we need more than 6 blocks: < 2^{-546}. */ | |||
unsigned char outbuf[5 * SHAKE128_RATE]; | |||
for (i = 0; i < SEEDBYTES; ++i) | |||
inbuf[i] = rho[i]; | |||
for (i = 0; i < K; ++i) { | |||
for (j = 0; j < L; ++j) { | |||
inbuf[SEEDBYTES] = i + (j << 4); | |||
shake128(outbuf, sizeof(outbuf), inbuf, SEEDBYTES + 1); | |||
poly_uniform(mat[i].vec + j, outbuf); | |||
} | |||
} | |||
} | |||
/************************************************* | |||
* Name: challenge | |||
* | |||
* Description: Implementation of H. Samples polynomial with 60 nonzero | |||
* coefficients in {-1,1} using the output stream of | |||
* SHAKE256(mu|w1). | |||
* | |||
* Arguments: - poly *c: pointer to output polynomial | |||
* - const unsigned char mu[]: byte array containing mu | |||
* - const polyveck *w1: pointer to vector w1 | |||
**************************************************/ | |||
void challenge(poly *c, const unsigned char mu[CRHBYTES], const polyveck *w1) { | |||
unsigned int i, b, pos; | |||
unsigned char inbuf[CRHBYTES + K * POLW1_SIZE_PACKED]; | |||
unsigned char outbuf[SHAKE256_RATE]; | |||
uint64_t state[25], signs, mask; | |||
for (i = 0; i < CRHBYTES; ++i) | |||
inbuf[i] = mu[i]; | |||
for (i = 0; i < K; ++i) | |||
polyw1_pack(inbuf + CRHBYTES + i * POLW1_SIZE_PACKED, w1->vec + i); | |||
shake256_absorb(state, inbuf, sizeof(inbuf)); | |||
shake256_squeezeblocks(outbuf, 1, state); | |||
signs = 0; | |||
for (i = 0; i < 8; ++i) | |||
signs |= (uint64_t)outbuf[i] << 8 * i; | |||
pos = 8; | |||
mask = 1; | |||
for (i = 0; i < N; ++i) | |||
c->coeffs[i] = 0; | |||
for (i = 196; i < 256; ++i) { | |||
do { | |||
if (pos >= SHAKE256_RATE) { | |||
shake256_squeezeblocks(outbuf, 1, state); | |||
pos = 0; | |||
} | |||
b = outbuf[pos++]; | |||
} while (b > i); | |||
c->coeffs[i] = c->coeffs[b]; | |||
c->coeffs[b] = (signs & mask) ? Q - 1 : 1; | |||
mask <<= 1; | |||
} | |||
} | |||
/************************************************* | |||
* Name: crypto_sign_keypair | |||
* | |||
* Description: Generates public and private key. | |||
* | |||
* Arguments: - unsigned char *pk: pointer to output public key (allocated | |||
* array of CRYPTO_PUBLICKEYBYTES bytes) | |||
* - unsigned char *sk: pointer to output private key (allocated | |||
* array of CRYPTO_SECRETKEYBYTES bytes) | |||
* | |||
* Returns 0 (success) | |||
**************************************************/ | |||
int crypto_sign_keypair(unsigned char *pk, unsigned char *sk) { | |||
unsigned int i; | |||
unsigned char seedbuf[3 * SEEDBYTES]; | |||
unsigned char tr[CRHBYTES]; | |||
unsigned char *rho, *rhoprime, *key; | |||
uint16_t nonce = 0; | |||
polyvecl mat[K]; | |||
polyvecl s1, s1hat; | |||
polyveck s2, t, t1, t0; | |||
/* Expand 32 bytes of randomness into rho, rhoprime and key */ | |||
randombytes(seedbuf, SEEDBYTES); | |||
shake256(seedbuf, 3 * SEEDBYTES, seedbuf, SEEDBYTES); | |||
rho = seedbuf; | |||
rhoprime = rho + SEEDBYTES; | |||
key = rho + 2 * SEEDBYTES; | |||
/* Expand matrix */ | |||
expand_mat(mat, rho); | |||
/* Sample short vectors s1 and s2 */ | |||
for (i = 0; i < L; ++i) | |||
poly_uniform_eta(s1.vec + i, rhoprime, nonce++); | |||
for (i = 0; i < K; ++i) | |||
poly_uniform_eta(s2.vec + i, rhoprime, nonce++); | |||
/* Matrix-vector multiplication */ | |||
s1hat = s1; | |||
polyvecl_ntt(&s1hat); | |||
for (i = 0; i < K; ++i) { | |||
polyvecl_pointwise_acc_invmontgomery(t.vec + i, mat + i, &s1hat); | |||
poly_reduce(t.vec + i); | |||
poly_invntt_montgomery(t.vec + i); | |||
} | |||
/* Add noise vector s2 */ | |||
polyveck_add(&t, &t, &s2); | |||
/* Extract t1 and write public key */ | |||
polyveck_freeze(&t); | |||
polyveck_power2round(&t1, &t0, &t); | |||
pack_pk(pk, rho, &t1); | |||
/* Compute CRH(rho, t1) and write secret key */ | |||
shake256(tr, CRHBYTES, pk, CRYPTO_PUBLICKEYBYTES); | |||
pack_sk(sk, rho, key, tr, &s1, &s2, &t0); | |||
return 0; | |||
} | |||
/************************************************* | |||
* Name: crypto_sign | |||
* | |||
* Description: Compute signed message. | |||
* | |||
* Arguments: - unsigned char *sm: pointer to output signed message (allocated | |||
* array with CRYPTO_BYTES + mlen bytes), | |||
* can be equal to m | |||
* - unsigned long long *smlen: pointer to output length of signed | |||
* message | |||
* - const unsigned char *m: pointer to message to be signed | |||
* - unsigned long long mlen: length of message | |||
* - const unsigned char *sk: pointer to bit-packed secret key | |||
* | |||
* Returns 0 (success) | |||
**************************************************/ | |||
int crypto_sign(unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen, | |||
const unsigned char *sk) { | |||
unsigned long long i, j; | |||
unsigned int n; | |||
unsigned char | |||
seedbuf[2 * SEEDBYTES + CRHBYTES]; // TODO: nonce in seedbuf (2x) | |||
unsigned char tr[CRHBYTES]; | |||
unsigned char *rho, *key, *mu; | |||
uint16_t nonce = 0; | |||
poly c, chat; | |||
polyvecl mat[K], s1, y, yhat, z; | |||
polyveck s2, t0, w, w1; | |||
polyveck h, wcs2, wcs20, ct0, tmp; | |||
rho = seedbuf; | |||
key = seedbuf + SEEDBYTES; | |||
mu = seedbuf + 2 * SEEDBYTES; | |||
unpack_sk(rho, key, tr, &s1, &s2, &t0, sk); | |||
/* Copy tr and message into the sm buffer, | |||
* backwards since m and sm can be equal in SUPERCOP API */ | |||
for (i = 1; i <= mlen; ++i) | |||
sm[CRYPTO_BYTES + mlen - i] = m[mlen - i]; | |||
for (i = 0; i < CRHBYTES; ++i) | |||
sm[CRYPTO_BYTES - CRHBYTES + i] = tr[i]; | |||
/* Compute CRH(tr, msg) */ | |||
shake256(mu, CRHBYTES, sm + CRYPTO_BYTES - CRHBYTES, CRHBYTES + mlen); | |||
/* Expand matrix and transform vectors */ | |||
expand_mat(mat, rho); | |||
polyvecl_ntt(&s1); | |||
polyveck_ntt(&s2); | |||
polyveck_ntt(&t0); | |||
rej: | |||
/* Sample intermediate vector y */ | |||
for (i = 0; i < L; ++i) | |||
poly_uniform_gamma1m1(y.vec + i, key, nonce++); | |||
/* Matrix-vector multiplication */ | |||
yhat = y; | |||
polyvecl_ntt(&yhat); | |||
for (i = 0; i < K; ++i) { | |||
polyvecl_pointwise_acc_invmontgomery(w.vec + i, mat + i, &yhat); | |||
poly_reduce(w.vec + i); | |||
poly_invntt_montgomery(w.vec + i); | |||
} | |||
/* Decompose w and call the random oracle */ | |||
polyveck_csubq(&w); | |||
polyveck_decompose(&w1, &tmp, &w); | |||
challenge(&c, mu, &w1); | |||
/* Compute z, reject if it reveals secret */ | |||
chat = c; | |||
poly_ntt(&chat); | |||
for (i = 0; i < L; ++i) { | |||
poly_pointwise_invmontgomery(z.vec + i, &chat, s1.vec + i); | |||
poly_invntt_montgomery(z.vec + i); | |||
} | |||
polyvecl_add(&z, &z, &y); | |||
polyvecl_freeze(&z); | |||
if (polyvecl_chknorm(&z, GAMMA1 - BETA)) | |||
goto rej; | |||
/* Compute w - cs2, reject if w1 can not be computed from it */ | |||
for (i = 0; i < K; ++i) { | |||
poly_pointwise_invmontgomery(wcs2.vec + i, &chat, s2.vec + i); | |||
poly_invntt_montgomery(wcs2.vec + i); | |||
} | |||
polyveck_sub(&wcs2, &w, &wcs2); | |||
polyveck_freeze(&wcs2); | |||
polyveck_decompose(&tmp, &wcs20, &wcs2); | |||
polyveck_csubq(&wcs20); | |||
if (polyveck_chknorm(&wcs20, GAMMA2 - BETA)) | |||
goto rej; | |||
for (i = 0; i < K; ++i) | |||
for (j = 0; j < N; ++j) | |||
if (tmp.vec[i].coeffs[j] != w1.vec[i].coeffs[j]) | |||
goto rej; | |||
/* Compute hints for w1 */ | |||
for (i = 0; i < K; ++i) { | |||
poly_pointwise_invmontgomery(ct0.vec + i, &chat, t0.vec + i); | |||
poly_invntt_montgomery(ct0.vec + i); | |||
} | |||
polyveck_csubq(&ct0); | |||
if (polyveck_chknorm(&ct0, GAMMA2)) | |||
goto rej; | |||
polyveck_add(&tmp, &wcs2, &ct0); | |||
polyveck_csubq(&tmp); | |||
n = polyveck_make_hint(&h, &wcs2, &tmp); | |||
if (n > OMEGA) | |||
goto rej; | |||
/* Write signature */ | |||
pack_sig(sm, &z, &h, &c); | |||
*smlen = mlen + CRYPTO_BYTES; | |||
return 0; | |||
} | |||
/************************************************* | |||
* Name: crypto_sign_open | |||
* | |||
* Description: Verify signed message. | |||
* | |||
* Arguments: - unsigned char *m: pointer to output message (allocated | |||
* array with smlen bytes), can be equal to sm | |||
* - unsigned long long *mlen: pointer to output length of message | |||
* - const unsigned char *sm: pointer to signed message | |||
* - unsigned long long smlen: length of signed message | |||
* - const unsigned char *sk: pointer to bit-packed public key | |||
* | |||
* Returns 0 if signed message could be verified correctly and -1 otherwise | |||
**************************************************/ | |||
int crypto_sign_open(unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk) { | |||
unsigned long long i; | |||
unsigned char rho[SEEDBYTES]; | |||
unsigned char mu[CRHBYTES]; | |||
poly c, chat, cp; | |||
polyvecl mat[K], z; | |||
polyveck t1, w1, h, tmp1, tmp2; | |||
if (smlen < CRYPTO_BYTES) | |||
goto badsig; | |||
*mlen = smlen - CRYPTO_BYTES; | |||
unpack_pk(rho, &t1, pk); | |||
if (unpack_sig(&z, &h, &c, sm)) | |||
goto badsig; | |||
if (polyvecl_chknorm(&z, GAMMA1 - BETA)) | |||
goto badsig; | |||
/* Compute CRH(CRH(rho, t1), msg) using m as "playground" buffer */ | |||
if (sm != m) | |||
for (i = 0; i < *mlen; ++i) | |||
m[CRYPTO_BYTES + i] = sm[CRYPTO_BYTES + i]; | |||
shake256(m + CRYPTO_BYTES - CRHBYTES, CRHBYTES, pk, CRYPTO_PUBLICKEYBYTES); | |||
shake256(mu, CRHBYTES, m + CRYPTO_BYTES - CRHBYTES, CRHBYTES + *mlen); | |||
/* Matrix-vector multiplication; compute Az - c2^dt1 */ | |||
expand_mat(mat, rho); | |||
polyvecl_ntt(&z); | |||
for (i = 0; i < K; ++i) | |||
polyvecl_pointwise_acc_invmontgomery(tmp1.vec + i, mat + i, &z); | |||
chat = c; | |||
poly_ntt(&chat); | |||
polyveck_shiftl(&t1, D); | |||
polyveck_ntt(&t1); | |||
for (i = 0; i < K; ++i) | |||
poly_pointwise_invmontgomery(tmp2.vec + i, &chat, t1.vec + i); | |||
polyveck_sub(&tmp1, &tmp1, &tmp2); | |||
polyveck_reduce(&tmp1); | |||
polyveck_invntt_montgomery(&tmp1); | |||
/* Reconstruct w1 */ | |||
polyveck_csubq(&tmp1); | |||
polyveck_use_hint(&w1, &tmp1, &h); | |||
/* Call random oracle and verify challenge */ | |||
challenge(&cp, mu, &w1); | |||
for (i = 0; i < N; ++i) | |||
if (c.coeffs[i] != cp.coeffs[i]) | |||
goto badsig; | |||
/* All good, copy msg, return 0 */ | |||
for (i = 0; i < *mlen; ++i) | |||
m[i] = sm[CRYPTO_BYTES + i]; | |||
return 0; | |||
/* Signature verification failed */ | |||
badsig: | |||
*mlen = (unsigned long long)-1; | |||
for (i = 0; i < smlen; ++i) | |||
m[i] = 0; | |||
return -1; | |||
} |
@@ -0,0 +1,21 @@ | |||
#ifndef SIGN_H | |||
#define SIGN_H | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
void expand_mat(polyvecl mat[K], const unsigned char rho[SEEDBYTES]); | |||
void challenge(poly *c, const unsigned char mu[CRHBYTES], const polyveck *w1); | |||
int crypto_sign_keypair(unsigned char *pk, unsigned char *sk); | |||
int crypto_sign(unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *msg, unsigned long long len, | |||
const unsigned char *sk); | |||
int crypto_sign_open(unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk); | |||
#endif |
@@ -0,0 +1,95 @@ | |||
#include "api.h" | |||
#include "randombytes.h" | |||
#include <stdio.h> | |||
#include <string.h> | |||
#define NTESTS 15 | |||
#define MLEN 32 | |||
/* allocate a bit more for all keys and messages and | |||
* make sure it is not touched by the implementations. | |||
*/ | |||
static void write_canary(unsigned char *d) { | |||
*((uint64_t *)d) = 0x0123456789ABCDEF; | |||
} | |||
static int check_canary(unsigned char *d) { | |||
if (*(uint64_t *)d != 0x0123456789ABCDEF) | |||
return -1; | |||
else | |||
return 0; | |||
} | |||
static int test_sign(void) { | |||
unsigned char pk[CRYPTO_PUBLICKEYBYTES + 16]; | |||
unsigned char sk[CRYPTO_SECRETKEYBYTES + 16]; | |||
unsigned char sm[MLEN + CRYPTO_BYTES + 16]; | |||
unsigned char m[MLEN + 16]; | |||
unsigned long long mlen; | |||
unsigned long long smlen; | |||
int i; | |||
write_canary(pk); | |||
write_canary(pk + sizeof(pk) - 8); | |||
write_canary(sk); | |||
write_canary(sk + sizeof(sk) - 8); | |||
write_canary(sm); | |||
write_canary(sm + sizeof(sm) - 8); | |||
write_canary(m); | |||
write_canary(m + sizeof(m) - 8); | |||
for (i = 0; i < NTESTS; i++) { | |||
crypto_sign_keypair(pk + 8, sk + 8); | |||
randombytes(m + 8, MLEN); | |||
crypto_sign(sm + 8, &smlen, m + 8, MLEN, sk + 8); | |||
// By relying on m == sm we prevent having to allocate CRYPTO_BYTES twice | |||
if (crypto_sign_open(sm + 8, &mlen, sm + 8, smlen, pk + 8)) { | |||
printf("ERROR Signature did not verify correctly!\n"); | |||
} else if (check_canary(pk) || check_canary(pk + sizeof(pk) - 8) || | |||
check_canary(sk) || check_canary(sk + sizeof(sk) - 8) || | |||
check_canary(sm) || check_canary(sm + sizeof(sm) - 8) || | |||
check_canary(m) || check_canary(m + sizeof(m) - 8)) { | |||
printf("ERROR canary overwritten\n"); | |||
} | |||
} | |||
return 0; | |||
} | |||
static int test_wrong_pk(void) { | |||
unsigned char pk[CRYPTO_PUBLICKEYBYTES]; | |||
unsigned char pk2[CRYPTO_PUBLICKEYBYTES]; | |||
unsigned char sk[CRYPTO_SECRETKEYBYTES]; | |||
unsigned char sm[MLEN + CRYPTO_BYTES]; | |||
unsigned char m[MLEN]; | |||
unsigned long long mlen; | |||
unsigned long long smlen; | |||
int i; | |||
for (i = 0; i < NTESTS; i++) { | |||
crypto_sign_keypair(pk2, sk); | |||
crypto_sign_keypair(pk, sk); | |||
randombytes(m, MLEN); | |||
crypto_sign(sm, &smlen, m, MLEN, sk); | |||
// By relying on m == sm we prevent having to allocate CRYPTO_BYTES twice | |||
if (!crypto_sign_open(sm, &mlen, sm, smlen, pk2)) { | |||
printf("ERROR Signature did verify correctly under wrong public key!\n"); | |||
} | |||
} | |||
return 0; | |||
} | |||
int main(void) { | |||
test_sign(); | |||
test_wrong_pk(); | |||
return 0; | |||
} |