* fixes dynamic memory allocation test. previously a function called freeze() would trigger it * this adds DilithiumII. Preprocessor conditionals still need to be removed * fix ms Makefile * fix MS compiler warnings * clean-up * remove preprocessor conditionals * add dilithium3 * add dilithium4 * add duplicate consistency checks * SHA2 state constants in common * clean up symmetric.h * Port SPHINCS+-SHA256 to sha256ctx struct * Implement ctx struct for fips202 * Port Kyber{512,768,1024} to fips202 ctx struct * Port NewHope to fips202 structs * Port SPHINCS+-SHAKE256 to fips202 ctx structs * Use opaque fips202 structs in MQDSS * port dilithium to use fips202 ctx structs * include -Wredundant-decls * remove comment; format NTT constants * reduce casts in power2roundmaster
@@ -0,0 +1,19 @@ | |||
name: DilithiumII | |||
type: signature | |||
claimed-nist-level: 1 | |||
length-public-key: 1184 | |||
length-secret-key: 2800 | |||
length-signature: 2044 | |||
nistkat-sha256: 23b7d52a268bbd8633d139b64a1b0e3263777cb2b074f7af0a7fd315afe94d18 | |||
testvectors-sha256: d647039ae7e1785414c64934d5ae37518f259acab95d6a6e873e9b6d3ad63dfd | |||
principal-submitter: Vadim Lyubashevsky | |||
auxiliary-submitters: | |||
- Léo Ducas | |||
- Eike Kiltz | |||
- Tancrède Lepoint | |||
- Peter Schwabe | |||
- Gregor Seiler | |||
- Damien Stehlé | |||
implementations: | |||
- name: clean | |||
version: https://github.com/pq-crystals/dilithium/commit/40f79645879b5c69835cd91d06945d7c24f39922 |
@@ -0,0 +1,2 @@ | |||
Public Domain | |||
Authors: Léo Ducas, Eike Kiltz, Tancrède Lepoint, Vadim Lyubashevsky, Gregor Seiler, Peter Schwabe, Damien Stehlé |
@@ -0,0 +1,22 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=libdilithium2_clean.a | |||
SOURCES = sign.c polyvec.c poly.c packing.c ntt.c reduce.c rounding.c symmetric.c | |||
OBJECTS = sign.o polyvec.o poly.o packing.o ntt.o reduce.o rounding.o symmetric.o | |||
HEADERS = api.h params.h sign.h polyvec.h poly.h packing.h ntt.h \ | |||
reduce.h rounding.h symmetric.h | |||
CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
%.o: %.c $(HEADERS) | |||
$(CC) $(CFLAGS) -c -o $@ $< | |||
$(LIB): $(OBJECTS) | |||
$(AR) -r $@ $(OBJECTS) | |||
clean: | |||
$(RM) $(OBJECTS) | |||
$(RM) $(LIB) |
@@ -0,0 +1,18 @@ | |||
# This Makefile can be used with Microsoft Visual Studio's nmake using the command: | |||
# nmake /f Makefile.Microsoft_nmake | |||
LIBRARY=libdilithium2_clean.lib | |||
OBJECTS=sign.obj polyvec.obj poly.obj packing.obj ntt.obj reduce.obj rounding.obj symmetric.obj | |||
CFLAGS=/nologo /I ..\..\..\common /W4 /WX | |||
all: $(LIBRARY) | |||
# Make sure objects are recompiled if headers change. | |||
$(OBJECTS): *.h | |||
$(LIBRARY): $(OBJECTS) | |||
LIB.EXE /NOLOGO /WX /OUT:$@ $** | |||
clean: | |||
-DEL $(OBJECTS) | |||
-DEL $(LIBRARY) |
@@ -0,0 +1,32 @@ | |||
#ifndef PQCLEAN_DILITHIUM2_CLEAN_API_H | |||
#define PQCLEAN_DILITHIUM2_CLEAN_API_H | |||
#include <stdint.h> | |||
#define MODE 2 | |||
#define PQCLEAN_DILITHIUM2_CLEAN_CRYPTO_PUBLICKEYBYTES 1184U | |||
#define PQCLEAN_DILITHIUM2_CLEAN_CRYPTO_SECRETKEYBYTES 2800U | |||
#define PQCLEAN_DILITHIUM2_CLEAN_CRYPTO_BYTES 2044U | |||
#define PQCLEAN_DILITHIUM2_CLEAN_CRYPTO_ALGNAME "Dilithium2" | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *pk); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen, | |||
const uint8_t *msg, size_t len, | |||
const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen, | |||
const uint8_t *sm, size_t smlen, | |||
const uint8_t *pk); | |||
#endif |
@@ -0,0 +1,137 @@ | |||
#include "ntt.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "reduce.h" | |||
#include <stdint.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 PQCLEAN_DILITHIUM2_CLEAN_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 = PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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] = PQCLEAN_DILITHIUM2_CLEAN_montgomery_reduce((uint64_t)zeta * p[j + len]); | |||
} | |||
} | |||
} | |||
for (j = 0; j < N; ++j) { | |||
p[j] = PQCLEAN_DILITHIUM2_CLEAN_montgomery_reduce((uint64_t)f * p[j]); | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
#ifndef NTT_H | |||
#define NTT_H | |||
#include "params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_DILITHIUM2_CLEAN_ntt(uint32_t p[N]); | |||
void PQCLEAN_DILITHIUM2_CLEAN_invntt_frominvmont(uint32_t p[N]); | |||
#endif |
@@ -0,0 +1,297 @@ | |||
#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 PQCLEAN_DILITHIUM2_CLEAN_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) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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) { | |||
PQCLEAN_DILITHIUM2_CLEAN_polyeta_pack(sk + i * POLETA_SIZE_PACKED, &s1->vec[i]); | |||
} | |||
sk += L * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_polyeta_pack(sk + i * POLETA_SIZE_PACKED, &s2->vec[i]); | |||
} | |||
sk += K * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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) { | |||
PQCLEAN_DILITHIUM2_CLEAN_polyeta_unpack(&s1->vec[i], sk + i * POLETA_SIZE_PACKED); | |||
} | |||
sk += L * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_polyeta_unpack(&s2->vec[i], sk + i * POLETA_SIZE_PACKED); | |||
} | |||
sk += K * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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++] = (unsigned char) j; | |||
} | |||
} | |||
sig[OMEGA + i] = (unsigned char) 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] |= (unsigned char) (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] = (unsigned char) (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 PQCLEAN_DILITHIUM2_CLEAN_unpack_sig(polyvecl *z, | |||
polyveck *h, | |||
poly *c, | |||
const unsigned char sig[CRYPTO_BYTES]) { | |||
unsigned int i, j, k; | |||
uint64_t signs; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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; | |||
} | |||
for (i = 0; i < N / 8; ++i) { | |||
for (j = 0; j < 8; ++j) { | |||
if ((sig[i] >> j) & 0x01) { | |||
c->coeffs[8 * i + j] = 1; | |||
c->coeffs[8 * i + j] ^= -((int32_t) signs & 1) & (1 ^ (Q - 1)); | |||
signs >>= 1; | |||
} | |||
} | |||
} | |||
return 0; | |||
} |
@@ -0,0 +1,31 @@ | |||
#ifndef PACKING_H | |||
#define PACKING_H | |||
#include "params.h" | |||
#include "polyvec.h" | |||
void PQCLEAN_DILITHIUM2_CLEAN_pack_pk(unsigned char pk[CRYPTO_PUBLICKEYBYTES], | |||
const unsigned char rho[SEEDBYTES], const polyveck *t1); | |||
void PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_pack_sig(unsigned char sig[CRYPTO_BYTES], | |||
const polyvecl *z, const polyveck *h, const poly *c); | |||
void PQCLEAN_DILITHIUM2_CLEAN_unpack_pk(unsigned char rho[SEEDBYTES], polyveck *t1, | |||
const unsigned char pk[CRYPTO_PUBLICKEYBYTES]); | |||
void PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_unpack_sig(polyvecl *z, polyveck *h, poly *c, | |||
const unsigned char sig[CRYPTO_BYTES]); | |||
#endif |
@@ -0,0 +1,35 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
#define SEEDBYTES 32 | |||
#define CRHBYTES 48 | |||
#define N 256 | |||
#define Q 8380417 | |||
#define QBITS 23 | |||
#define ROOT_OF_UNITY 1753 | |||
#define D 14 | |||
#define GAMMA1 ((Q - 1)/16) | |||
#define GAMMA2 (GAMMA1/2) | |||
#define ALPHA (2*GAMMA2) | |||
// DilithiumII parameters | |||
#define K 4 | |||
#define L 3 | |||
#define ETA 6 | |||
#define SETABITS 4 | |||
#define BETA 325 | |||
#define OMEGA 80 | |||
#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 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,737 @@ | |||
#include "ntt.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "reduce.h" | |||
#include "rounding.h" | |||
#include "symmetric.h" | |||
#include <stdint.h> | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_poly_reduce | |||
* | |||
* Description: Reduce all coefficients of input polynomial to representative | |||
* in [0,2*Q[. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_reduce(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM2_CLEAN_reduce32(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_poly_csubq(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM2_CLEAN_csubq(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_poly_freeze | |||
* | |||
* Description: Reduce all coefficients of the polynomial to standard | |||
* representatives. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_freeze(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM2_CLEAN_freeze(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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: PQCLEAN_DILITHIUM2_CLEAN_poly_shiftl | |||
* | |||
* Description: Multiply polynomial by 2^D without modular reduction. Assumes | |||
* input coefficients to be less than 2^{32-D}. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_shiftl(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] <<= D; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_poly_ntt(poly *a) { | |||
PQCLEAN_DILITHIUM2_CLEAN_ntt(a->coeffs); | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_poly_invntt_montgomery(poly *a) { | |||
PQCLEAN_DILITHIUM2_CLEAN_invntt_frominvmont(a->coeffs); | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
c->coeffs[i] = PQCLEAN_DILITHIUM2_CLEAN_montgomery_reduce((uint64_t)a->coeffs[i] * b->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_poly_power2round(poly *a1, poly *a0, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a1->coeffs[i] = PQCLEAN_DILITHIUM2_CLEAN_power2round(a->coeffs[i], &a0->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_poly_decompose(poly *a1, poly *a0, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a1->coeffs[i] = PQCLEAN_DILITHIUM2_CLEAN_decompose(a->coeffs[i], &a0->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_poly_make_hint | |||
* | |||
* Description: Compute hint polynomial. The coefficients of which indicate | |||
* whether the low bits of the corresponding coefficient of | |||
* the input polynomial overflow into the high bits. | |||
* | |||
* Arguments: - poly *h: pointer to output hint polynomial | |||
* - const poly *a0: pointer to low part of input polynomial | |||
* - const poly *a1: pointer to high part of input polynomial | |||
* | |||
* Returns number of 1 bits. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM2_CLEAN_poly_make_hint(poly *h, const poly *a0, const poly *a1) { | |||
unsigned int i, s = 0; | |||
for (i = 0; i < N; ++i) { | |||
h->coeffs[i] = PQCLEAN_DILITHIUM2_CLEAN_make_hint(a0->coeffs[i], a1->coeffs[i]); | |||
s += h->coeffs[i]; | |||
} | |||
return s; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_poly_use_hint(poly *a, const poly *b, const poly *h) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM2_CLEAN_use_hint(b->coeffs[i], h->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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 = (int32_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: rej_uniform | |||
* | |||
* Description: Sample uniformly random coefficients in [0, Q-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_uniform(uint32_t *a, | |||
unsigned int len, | |||
const unsigned char *buf, | |||
unsigned int buflen) { | |||
unsigned int ctr, pos; | |||
uint32_t t; | |||
ctr = pos = 0; | |||
while (ctr < len && pos + 3 <= buflen) { | |||
t = buf[pos++]; | |||
t |= (uint32_t)buf[pos++] << 8; | |||
t |= (uint32_t)buf[pos++] << 16; | |||
t &= 0x7FFFFF; | |||
if (t < Q) { | |||
a[ctr++] = t; | |||
} | |||
} | |||
return ctr; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_poly_uniform | |||
* | |||
* Description: Sample polynomial with uniformly random coefficients | |||
* in [0,Q-1] 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 | |||
* - uint16_t nonce: 2-byte nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_NBLOCKS ((769 + STREAM128_BLOCKBYTES)/STREAM128_BLOCKBYTES) | |||
#define POLY_UNIFORM_BUFLEN (POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_uniform(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int i, ctr, off; | |||
unsigned int buflen = POLY_UNIFORM_BUFLEN; | |||
unsigned char buf[POLY_UNIFORM_BUFLEN + 2]; | |||
shake128ctx state; | |||
stream128_init(&state, seed, nonce); | |||
stream128_squeezeblocks(buf, POLY_UNIFORM_NBLOCKS, &state); | |||
ctr = rej_uniform(a->coeffs, N, buf, buflen); | |||
while (ctr < N) { | |||
off = buflen % 3; | |||
for (i = 0; i < off; ++i) { | |||
buf[i] = buf[buflen - off + i]; | |||
} | |||
buflen = STREAM128_BLOCKBYTES + off; | |||
stream128_squeezeblocks(buf + off, 1, &state); | |||
ctr += rej_uniform(a->coeffs + ctr, N - ctr, buf, buflen); | |||
} | |||
} | |||
/************************************************* | |||
* 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) { | |||
unsigned int ctr, pos; | |||
uint32_t t0, t1; | |||
ctr = pos = 0; | |||
while (ctr < len && pos < buflen) { | |||
t0 = buf[pos] & 0x0F; | |||
t1 = buf[pos++] >> 4; | |||
if (t0 <= 2 * ETA) { | |||
a[ctr++] = Q + ETA - t0; | |||
} | |||
if (t1 <= 2 * ETA && ctr < len) { | |||
a[ctr++] = Q + ETA - t1; | |||
} | |||
} | |||
return ctr; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 | |||
* - uint16_t nonce: 2-byte nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_ETA_NBLOCKS (((N/2 * (1U << SETABITS)) / (2*ETA + 1)\ | |||
+ STREAM128_BLOCKBYTES) / STREAM128_BLOCKBYTES) | |||
#define POLY_UNIFORM_ETA_BUFLEN (POLY_UNIFORM_ETA_NBLOCKS*STREAM128_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_uniform_eta(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int ctr; | |||
unsigned char buf[POLY_UNIFORM_ETA_BUFLEN]; | |||
shake128ctx state; | |||
stream128_init(&state, seed, nonce); | |||
stream128_squeezeblocks(buf, POLY_UNIFORM_ETA_NBLOCKS, &state); | |||
ctr = rej_eta(a->coeffs, N, buf, POLY_UNIFORM_ETA_BUFLEN); | |||
while (ctr < N) { | |||
stream128_squeezeblocks(buf, 1, &state); | |||
ctr += rej_eta(a->coeffs + ctr, N - ctr, buf, STREAM128_BLOCKBYTES); | |||
} | |||
} | |||
/************************************************* | |||
* 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) { | |||
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: PQCLEAN_DILITHIUM2_CLEAN_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 | |||
* CRHBYTES | |||
* - uint16_t nonce: 16-bit nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_GAMMA1M1_NBLOCKS ((641 + STREAM256_BLOCKBYTES) / STREAM256_BLOCKBYTES) | |||
#define POLY_UNIFORM_GAMMA1M1_BUFLEN (POLY_UNIFORM_GAMMA1M1_NBLOCKS * STREAM256_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_uniform_gamma1m1(poly *a, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce) { | |||
unsigned int i, ctr, off; | |||
unsigned int buflen = POLY_UNIFORM_GAMMA1M1_BUFLEN; | |||
unsigned char buf[POLY_UNIFORM_GAMMA1M1_BUFLEN + 4]; | |||
shake256ctx state; | |||
stream256_init(&state, seed, nonce); | |||
stream256_squeezeblocks(buf, POLY_UNIFORM_GAMMA1M1_NBLOCKS, &state); | |||
ctr = rej_gamma1m1(a->coeffs, N, buf, buflen); | |||
while (ctr < N) { | |||
off = buflen % 5; | |||
for (i = 0; i < off; ++i) { | |||
buf[i] = buf[buflen - off + i]; | |||
} | |||
buflen = STREAM256_BLOCKBYTES + off; | |||
stream256_squeezeblocks(buf + off, 1, &state); | |||
ctr += rej_gamma1m1(a->coeffs + ctr, N - ctr, buf, buflen); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyeta_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
unsigned char t[8]; | |||
for (i = 0; i < N / 2; ++i) { | |||
t[0] = (uint8_t) (Q + ETA - a->coeffs[2 * i + 0]); | |||
t[1] = (uint8_t) (Q + ETA - a->coeffs[2 * i + 1]); | |||
r[i] = (uint8_t) (t[0] | (t[1] << 4)); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyeta_unpack(poly *r, const unsigned char *a) { | |||
unsigned int i; | |||
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]; | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM2_CLEAN_polyt1_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 8; ++i) { | |||
r[9 * i + 0] = (uint8_t) ((a->coeffs[8 * i + 0] >> 0)); | |||
r[9 * i + 1] = (uint8_t) ((a->coeffs[8 * i + 0] >> 8) | (a->coeffs[8 * i + 1] << 1)); | |||
r[9 * i + 2] = (uint8_t) ((a->coeffs[8 * i + 1] >> 7) | (a->coeffs[8 * i + 2] << 2)); | |||
r[9 * i + 3] = (uint8_t) ((a->coeffs[8 * i + 2] >> 6) | (a->coeffs[8 * i + 3] << 3)); | |||
r[9 * i + 4] = (uint8_t) ((a->coeffs[8 * i + 3] >> 5) | (a->coeffs[8 * i + 4] << 4)); | |||
r[9 * i + 5] = (uint8_t) ((a->coeffs[8 * i + 4] >> 4) | (a->coeffs[8 * i + 5] << 5)); | |||
r[9 * i + 6] = (uint8_t) ((a->coeffs[8 * i + 5] >> 3) | (a->coeffs[8 * i + 6] << 6)); | |||
r[9 * i + 7] = (uint8_t) ((a->coeffs[8 * i + 6] >> 2) | (a->coeffs[8 * i + 7] << 7)); | |||
r[9 * i + 8] = (uint8_t) ((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 PQCLEAN_DILITHIUM2_CLEAN_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] << 8)) & 0x1FF; | |||
r->coeffs[8 * i + 1] = ((a[9 * i + 1] >> 1) | ((uint32_t)a[9 * i + 2] << 7)) & 0x1FF; | |||
r->coeffs[8 * i + 2] = ((a[9 * i + 2] >> 2) | ((uint32_t)a[9 * i + 3] << 6)) & 0x1FF; | |||
r->coeffs[8 * i + 3] = ((a[9 * i + 3] >> 3) | ((uint32_t)a[9 * i + 4] << 5)) & 0x1FF; | |||
r->coeffs[8 * i + 4] = ((a[9 * i + 4] >> 4) | ((uint32_t)a[9 * i + 5] << 4)) & 0x1FF; | |||
r->coeffs[8 * i + 5] = ((a[9 * i + 5] >> 5) | ((uint32_t)a[9 * i + 6] << 3)) & 0x1FF; | |||
r->coeffs[8 * i + 6] = ((a[9 * i + 6] >> 6) | ((uint32_t)a[9 * i + 7] << 2)) & 0x1FF; | |||
r->coeffs[8 * i + 7] = ((a[9 * i + 7] >> 7) | ((uint32_t)a[9 * i + 8] << 1)) & 0x1FF; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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 + (1U << (D - 1)) - a->coeffs[4 * i + 0]; | |||
t[1] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 1]; | |||
t[2] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 2]; | |||
t[3] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 3]; | |||
r[7 * i + 0] = (uint8_t) (t[0]); | |||
r[7 * i + 1] = (uint8_t) (t[0] >> 8); | |||
r[7 * i + 1] |= (uint8_t) (t[1] << 6); | |||
r[7 * i + 2] = (uint8_t) (t[1] >> 2); | |||
r[7 * i + 3] = (uint8_t) (t[1] >> 10); | |||
r[7 * i + 3] |= (uint8_t) (t[2] << 4); | |||
r[7 * i + 4] = (uint8_t) (t[2] >> 4); | |||
r[7 * i + 5] = (uint8_t) (t[2] >> 12); | |||
r[7 * i + 5] |= (uint8_t) (t[3] << 2); | |||
r[7 * i + 6] = (uint8_t) (t[3] >> 6); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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 + (1U << (D - 1)) - r->coeffs[4 * i + 0]; | |||
r->coeffs[4 * i + 1] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 1]; | |||
r->coeffs[4 * i + 2] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 2]; | |||
r->coeffs[4 * i + 3] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 3]; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyz_pack(unsigned char *r, const poly *a) { | |||
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] = (uint8_t) (t[0]); | |||
r[5 * i + 1] = (uint8_t) (t[0] >> 8); | |||
r[5 * i + 2] = (uint8_t) (t[0] >> 16); | |||
r[5 * i + 2] |= (uint8_t) (t[1] << 4); | |||
r[5 * i + 3] = (uint8_t) (t[1] >> 4); | |||
r[5 * i + 4] = (uint8_t) (t[1] >> 12); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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: PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyw1_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 2; ++i) { | |||
r[i] = (uint8_t) (a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)); | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
#include "params.h" | |||
#include <stdint.h> | |||
typedef struct { | |||
uint32_t coeffs[N]; | |||
} poly; | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_reduce(poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_csubq(poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_freeze(poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_add(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_sub(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_shiftl(poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_ntt(poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_invntt_montgomery(poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_power2round(poly *a1, poly *a0, const poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_decompose(poly *a1, poly *a0, const poly *a); | |||
unsigned int PQCLEAN_DILITHIUM2_CLEAN_poly_make_hint(poly *h, const poly *a0, const poly *a1); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_use_hint(poly *a, const poly *b, const poly *h); | |||
int PQCLEAN_DILITHIUM2_CLEAN_poly_chknorm(const poly *a, uint32_t B); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_uniform(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_uniform_eta(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM2_CLEAN_poly_uniform_gamma1m1(poly *a, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyeta_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyeta_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyt1_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyt1_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyt0_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyt0_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyz_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyz_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyw1_pack(unsigned char *r, const poly *a); | |||
#endif |
@@ -0,0 +1,357 @@ | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.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 PQCLEAN_DILITHIUM2_CLEAN_polyvecl_freeze(polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyvecl_ntt(polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyvecl_pointwise_acc_invmontgomery(poly *w, | |||
const polyvecl *u, | |||
const polyvecl *v) { | |||
unsigned int i; | |||
poly t; | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_pointwise_invmontgomery(w, &u->vec[0], &v->vec[0]); | |||
for (i = 1; i < L; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_pointwise_invmontgomery(&t, &u->vec[i], &v->vec[i]); | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyvecl_chknorm(const polyvecl *v, uint32_t bound) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
if (PQCLEAN_DILITHIUM2_CLEAN_poly_chknorm(&v->vec[i], bound)) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
/**************************************************************/ | |||
/************ 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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_reduce(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_csubq(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_freeze(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_add(polyveck *w, const polyveck *u, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_sub(&w->vec[i], &u->vec[i], &v->vec[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyveck_shiftl | |||
* | |||
* Description: Multiply vector of polynomials of Length K by 2^D without modular | |||
* reduction. Assumes input coefficients to be less than 2^{32-D}. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_shiftl(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_shiftl(&v->vec[i]); | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_ntt(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_invntt_montgomery(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_chknorm(const polyveck *v, uint32_t bound) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
if (PQCLEAN_DILITHIUM2_CLEAN_poly_chknorm(&v->vec[i], bound)) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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 *v0: pointer to low part of input vector | |||
* - const polyveck *v1: pointer to high part of input vector | |||
* | |||
* Returns number of 1 bits. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM2_CLEAN_polyveck_make_hint(polyveck *h, | |||
const polyveck *v0, | |||
const polyveck *v1) { | |||
unsigned int i, s = 0; | |||
for (i = 0; i < K; ++i) { | |||
s += PQCLEAN_DILITHIUM2_CLEAN_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->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 PQCLEAN_DILITHIUM2_CLEAN_polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
#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 PQCLEAN_DILITHIUM2_CLEAN_polyvecl_freeze(polyvecl *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyvecl_ntt(polyvecl *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyvecl_pointwise_acc_invmontgomery(poly *w, | |||
const polyvecl *u, | |||
const polyvecl *v); | |||
int PQCLEAN_DILITHIUM2_CLEAN_polyvecl_chknorm(const polyvecl *v, uint32_t B); | |||
/* Vectors of polynomials of length K */ | |||
typedef struct { | |||
poly vec[K]; | |||
} polyveck; | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_reduce(polyveck *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_csubq(polyveck *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_freeze(polyveck *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_add(polyveck *w, const polyveck *u, const polyveck *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_shiftl(polyveck *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_ntt(polyveck *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_invntt_montgomery(polyveck *v); | |||
int PQCLEAN_DILITHIUM2_CLEAN_polyveck_chknorm(const polyveck *v, uint32_t B); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v); | |||
unsigned int PQCLEAN_DILITHIUM2_CLEAN_polyveck_make_hint(polyveck *h, | |||
const polyveck *v0, | |||
const polyveck *v1); | |||
void PQCLEAN_DILITHIUM2_CLEAN_polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h); | |||
#endif |
@@ -0,0 +1,74 @@ | |||
#include "params.h" | |||
#include "reduce.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 PQCLEAN_DILITHIUM2_CLEAN_montgomery_reduce(uint64_t a) { | |||
uint64_t t; | |||
t = a * QINV; | |||
t &= (1ULL << 32) - 1; | |||
t *= Q; | |||
t = a + t; | |||
t >>= 32; | |||
return (uint32_t) 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 PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_freeze(uint32_t a) { | |||
a = PQCLEAN_DILITHIUM2_CLEAN_reduce32(a); | |||
a = PQCLEAN_DILITHIUM2_CLEAN_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 PQCLEAN_DILITHIUM2_CLEAN_montgomery_reduce(uint64_t a); | |||
/* r < 2*Q */ | |||
uint32_t PQCLEAN_DILITHIUM2_CLEAN_reduce32(uint32_t a); | |||
/* a < 2*Q => r < Q */ | |||
uint32_t PQCLEAN_DILITHIUM2_CLEAN_csubq(uint32_t a); | |||
/* r < Q */ | |||
uint32_t PQCLEAN_DILITHIUM2_CLEAN_freeze(uint32_t a); | |||
#endif |
@@ -0,0 +1,105 @@ | |||
#include "params.h" | |||
#include "rounding.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 PQCLEAN_DILITHIUM2_CLEAN_power2round(uint32_t a, uint32_t *a0) { | |||
uint32_t t; | |||
/* Centralized remainder mod 2^D */ | |||
t = a & ((1U << D) - 1); | |||
t -= ((1U << (D - 1)) + 1); | |||
t += ((uint32_t)((int32_t)t >> 31) & (1U << D)); | |||
t -= ((1U << (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 PQCLEAN_DILITHIUM2_CLEAN_decompose(uint32_t a, uint32_t *a0) { | |||
int32_t t, u; | |||
/* Centralized remainder mod ALPHA */ | |||
t = a & 0x7FFFF; | |||
t += (int32_t) ((a >> 19) << 9); | |||
t -= ALPHA / 2 + 1; | |||
t += (t >> 31) & ALPHA; | |||
t -= ALPHA / 2 - 1; | |||
a -= (uint32_t) t; | |||
/* Divide by ALPHA (possible to avoid) */ | |||
u = (int32_t) a - 1; | |||
u >>= 31; | |||
a = (a >> 19) + 1; | |||
a -= u & 1; | |||
/* Border case */ | |||
*a0 = Q + (uint32_t)t - (a >> 4); | |||
a &= 0xF; | |||
return a; | |||
} | |||
/************************************************* | |||
* Name: make_hint | |||
* | |||
* Description: Compute hint bit indicating whether the low bits of the | |||
* input element overflow into the high bits. Inputs assumed to be | |||
* standard representatives. | |||
* | |||
* Arguments: - uint32_t a0: low bits of input element | |||
* - uint32_t a1: high bits of input element | |||
* | |||
* Returns 1 if high bits of a and b differ and 0 otherwise. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM2_CLEAN_make_hint(uint32_t a0, uint32_t a1) { | |||
if (a0 <= GAMMA2 || a0 > Q - GAMMA2 || (a0 == Q - GAMMA2 && a1 == 0)) { | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM2_CLEAN_use_hint(uint32_t a, unsigned int hint) { | |||
uint32_t a0, a1; | |||
a1 = PQCLEAN_DILITHIUM2_CLEAN_decompose(a, &a0); | |||
if (hint == 0) { | |||
return a1; | |||
} | |||
if (a0 > Q) { | |||
return (a1 + 1) & 0xF; | |||
} | |||
return (a1 - 1) & 0xF; | |||
} |
@@ -0,0 +1,11 @@ | |||
#ifndef ROUNDING_H | |||
#define ROUNDING_H | |||
#include <stdint.h> | |||
uint32_t PQCLEAN_DILITHIUM2_CLEAN_power2round(uint32_t a, uint32_t *a0); | |||
uint32_t PQCLEAN_DILITHIUM2_CLEAN_decompose(uint32_t a, uint32_t *a0); | |||
unsigned int PQCLEAN_DILITHIUM2_CLEAN_make_hint(uint32_t a0, uint32_t a1); | |||
uint32_t PQCLEAN_DILITHIUM2_CLEAN_use_hint(uint32_t a, unsigned int hint); | |||
#endif |
@@ -0,0 +1,414 @@ | |||
#include "fips202.h" | |||
#include "packing.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
#include "randombytes.h" | |||
#include "sign.h" | |||
#include "symmetric.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 PQCLEAN_DILITHIUM2_CLEAN_expand_mat(polyvecl mat[K], const unsigned char rho[SEEDBYTES]) { | |||
unsigned int i, j; | |||
for (i = 0; i < K; ++i) { | |||
for (j = 0; j < L; ++j) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_uniform(&mat[i].vec[j], rho, (uint16_t)((i << 8) + j)); | |||
} | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM2_CLEAN_challenge(poly *c, | |||
const unsigned char mu[CRHBYTES], | |||
const polyveck *w1) { | |||
unsigned int i, b, pos; | |||
uint64_t signs; | |||
unsigned char inbuf[CRHBYTES + K * POLW1_SIZE_PACKED]; | |||
unsigned char outbuf[SHAKE256_RATE]; | |||
shake256ctx state; | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
inbuf[i] = mu[i]; | |||
} | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_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; | |||
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] = 1; | |||
c->coeffs[b] ^= -((int32_t)signs & 1) & (1 ^ (Q - 1)); | |||
signs >>= 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 PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { | |||
unsigned int i; | |||
unsigned char seedbuf[3 * SEEDBYTES]; | |||
unsigned char tr[CRHBYTES]; | |||
const 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, 3 * SEEDBYTES); | |||
rho = seedbuf; | |||
rhoprime = seedbuf + SEEDBYTES; | |||
key = seedbuf + 2 * SEEDBYTES; | |||
/* Expand matrix */ | |||
PQCLEAN_DILITHIUM2_CLEAN_expand_mat(mat, rho); | |||
/* Sample short vectors s1 and s2 */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_uniform_eta(&s1.vec[i], rhoprime, nonce++); | |||
} | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_uniform_eta(&s2.vec[i], rhoprime, nonce++); | |||
} | |||
/* Matrix-vector multiplication */ | |||
s1hat = s1; | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_ntt(&s1hat); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_pointwise_acc_invmontgomery(&t.vec[i], &mat[i], &s1hat); | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_reduce(&t.vec[i]); | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_invntt_montgomery(&t.vec[i]); | |||
} | |||
/* Add error vector s2 */ | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_add(&t, &t, &s2); | |||
/* Extract t1 and write public key */ | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_freeze(&t); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_power2round(&t1, &t0, &t); | |||
PQCLEAN_DILITHIUM2_CLEAN_pack_pk(pk, rho, &t1); | |||
/* Compute CRH(rho, t1) and write secret key */ | |||
crh(tr, pk, CRYPTO_PUBLICKEYBYTES); | |||
PQCLEAN_DILITHIUM2_CLEAN_pack_sk(sk, rho, key, tr, &s1, &s2, &t0); | |||
return 0; | |||
} | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk) { | |||
unsigned long long i; | |||
unsigned int n; | |||
unsigned char seedbuf[2 * SEEDBYTES + 3 * CRHBYTES]; | |||
unsigned char *rho, *tr, *key, *mu, *rhoprime; | |||
uint16_t nonce = 0; | |||
poly c, chat; | |||
polyvecl mat[K], s1, y, yhat, z; | |||
polyveck t0, s2, w, w1, w0; | |||
polyveck h, cs2, ct0; | |||
rho = seedbuf; | |||
tr = rho + SEEDBYTES; | |||
key = tr + CRHBYTES; | |||
mu = key + SEEDBYTES; | |||
rhoprime = mu + CRHBYTES; | |||
PQCLEAN_DILITHIUM2_CLEAN_unpack_sk(rho, key, tr, &s1, &s2, &t0, sk); | |||
// use incremental hash API instead of copying around buffers | |||
/* Compute CRH(tr, msg) */ | |||
shake256incctx state; | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, tr, CRHBYTES); | |||
shake256_inc_absorb(&state, m, mlen); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
sig[CRYPTO_BYTES - CRHBYTES + i] = tr[i]; | |||
} | |||
crh(rhoprime, key, SEEDBYTES + CRHBYTES); | |||
/* Expand matrix and transform vectors */ | |||
PQCLEAN_DILITHIUM2_CLEAN_expand_mat(mat, rho); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_ntt(&s1); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_ntt(&s2); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_ntt(&t0); | |||
rej: | |||
/* Sample intermediate vector y */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_uniform_gamma1m1(&y.vec[i], rhoprime, nonce++); | |||
} | |||
/* Matrix-vector multiplication */ | |||
yhat = y; | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_ntt(&yhat); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_pointwise_acc_invmontgomery(&w.vec[i], &mat[i], &yhat); | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_reduce(&w.vec[i]); | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_invntt_montgomery(&w.vec[i]); | |||
} | |||
/* Decompose w and call the random oracle */ | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_csubq(&w); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_decompose(&w1, &w0, &w); | |||
PQCLEAN_DILITHIUM2_CLEAN_challenge(&c, mu, &w1); | |||
chat = c; | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_ntt(&chat); | |||
/* Check that subtracting cs2 does not change high bits of w and low bits | |||
* do not reveal secret information */ | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_pointwise_invmontgomery(&cs2.vec[i], &chat, &s2.vec[i]); | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_invntt_montgomery(&cs2.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_sub(&w0, &w0, &cs2); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_freeze(&w0); | |||
if (PQCLEAN_DILITHIUM2_CLEAN_polyveck_chknorm(&w0, GAMMA2 - BETA)) { | |||
goto rej; | |||
} | |||
/* Compute z, reject if it reveals secret */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_pointwise_invmontgomery(&z.vec[i], &chat, &s1.vec[i]); | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_invntt_montgomery(&z.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_add(&z, &z, &y); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_freeze(&z); | |||
if (PQCLEAN_DILITHIUM2_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) { | |||
goto rej; | |||
} | |||
/* Compute hints for w1 */ | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_pointwise_invmontgomery(&ct0.vec[i], &chat, &t0.vec[i]); | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_invntt_montgomery(&ct0.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_csubq(&ct0); | |||
if (PQCLEAN_DILITHIUM2_CLEAN_polyveck_chknorm(&ct0, GAMMA2)) { | |||
goto rej; | |||
} | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_add(&w0, &w0, &ct0); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_csubq(&w0); | |||
n = PQCLEAN_DILITHIUM2_CLEAN_polyveck_make_hint(&h, &w0, &w1); | |||
if (n > OMEGA) { | |||
goto rej; | |||
} | |||
/* Write signature */ | |||
PQCLEAN_DILITHIUM2_CLEAN_pack_sig(sig, &z, &h, &c); | |||
*siglen = CRYPTO_BYTES; | |||
return 0; | |||
} | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *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 (siglen < CRYPTO_BYTES) { | |||
return -1; | |||
} | |||
PQCLEAN_DILITHIUM2_CLEAN_unpack_pk(rho, &t1, pk); | |||
if (PQCLEAN_DILITHIUM2_CLEAN_unpack_sig(&z, &h, &c, sig)) { | |||
return -1; | |||
} | |||
if (PQCLEAN_DILITHIUM2_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) { | |||
return -1; | |||
} | |||
/* Compute CRH(CRH(rho, t1), msg) */ | |||
shake256incctx state; | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, pk, CRYPTO_PUBLICKEYBYTES); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, mu, CRHBYTES); | |||
shake256_inc_absorb(&state, m, mlen); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
/* Matrix-vector multiplication; compute Az - c2^dt1 */ | |||
PQCLEAN_DILITHIUM2_CLEAN_expand_mat(mat, rho); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_ntt(&z); | |||
for (i = 0; i < K ; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_polyvecl_pointwise_acc_invmontgomery(&tmp1.vec[i], &mat[i], &z); | |||
} | |||
chat = c; | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_ntt(&chat); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_shiftl(&t1); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_ntt(&t1); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM2_CLEAN_poly_pointwise_invmontgomery(&tmp2.vec[i], &chat, &t1.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_sub(&tmp1, &tmp1, &tmp2); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_reduce(&tmp1); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_invntt_montgomery(&tmp1); | |||
/* Reconstruct w1 */ | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_csubq(&tmp1); | |||
PQCLEAN_DILITHIUM2_CLEAN_polyveck_use_hint(&w1, &tmp1, &h); | |||
/* Call random oracle and verify challenge */ | |||
PQCLEAN_DILITHIUM2_CLEAN_challenge(&cp, mu, &w1); | |||
for (i = 0; i < N; ++i) { | |||
if (c.coeffs[i] != cp.coeffs[i]) { | |||
return -1; | |||
} | |||
} | |||
// All good | |||
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 PQCLEAN_DILITHIUM2_CLEAN_crypto_sign(uint8_t *sm, | |||
size_t *smlen, | |||
const uint8_t *m, | |||
size_t mlen, | |||
const uint8_t *sk) { | |||
size_t i; | |||
int rc; | |||
for (i = 0; i < mlen; i++) { | |||
sm[CRYPTO_BYTES + i] = m[i]; | |||
} | |||
rc = PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_signature(sm, smlen, m, mlen, sk); | |||
*smlen += mlen; | |||
return rc; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_open(uint8_t *m, | |||
size_t *mlen, | |||
const uint8_t *sm, | |||
size_t smlen, | |||
const uint8_t *pk) { | |||
size_t i; | |||
if (smlen < CRYPTO_BYTES) { | |||
goto badsig; | |||
} | |||
*mlen = smlen - CRYPTO_BYTES; | |||
if (PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_verify(sm, CRYPTO_BYTES, | |||
sm + CRYPTO_BYTES, *mlen, pk)) { | |||
goto badsig; | |||
} else { | |||
/* 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 = (size_t) -1; | |||
for (i = 0; i < smlen; ++i) { | |||
m[i] = 0; | |||
} | |||
return -1; | |||
} | |||
@@ -0,0 +1,30 @@ | |||
#ifndef SIGN_H | |||
#define SIGN_H | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
void PQCLEAN_DILITHIUM2_CLEAN_expand_mat(polyvecl mat[K], const unsigned char rho[SEEDBYTES]); | |||
void PQCLEAN_DILITHIUM2_CLEAN_challenge(poly *c, const unsigned char mu[CRHBYTES], | |||
const polyveck *w1); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *pk); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen, | |||
const uint8_t *msg, size_t len, | |||
const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM2_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen, | |||
const uint8_t *sm, size_t smlen, | |||
const uint8_t *pk); | |||
#endif |
@@ -0,0 +1,32 @@ | |||
#include "symmetric.h" | |||
#include "fips202.h" | |||
void PQCLEAN_DILITHIUM2_CLEAN_shake128_stream_init(shake128ctx *state, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int i; | |||
unsigned char buf[SEEDBYTES + 2]; | |||
for (i = 0; i < SEEDBYTES; ++i) { | |||
buf[i] = seed[i]; | |||
} | |||
buf[SEEDBYTES] = (uint8_t) nonce; | |||
buf[SEEDBYTES + 1] = (uint8_t) (nonce >> 8); | |||
shake128_absorb(state, buf, sizeof(buf)); | |||
} | |||
void PQCLEAN_DILITHIUM2_CLEAN_shake256_stream_init(shake256ctx *state, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce) { | |||
unsigned int i; | |||
unsigned char buf[CRHBYTES + 2]; | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
buf[i] = seed[i]; | |||
} | |||
buf[CRHBYTES] = (uint8_t) nonce; | |||
buf[CRHBYTES + 1] = (uint8_t) (nonce >> 8); | |||
shake256_absorb(state, buf, sizeof(buf)); | |||
} |
@@ -0,0 +1,23 @@ | |||
#ifndef SYMMETRIC_H | |||
#define SYMMETRIC_H | |||
#include "fips202.h" | |||
#include "params.h" | |||
#define crh(OUT, IN, INBYTES) shake256(OUT, CRHBYTES, IN, INBYTES) | |||
#define stream128_init(STATE, SEED, NONCE) PQCLEAN_DILITHIUM2_CLEAN_shake128_stream_init(STATE, SEED, NONCE) | |||
#define stream128_squeezeblocks(OUT, OUTBLOCKS, STATE) shake128_squeezeblocks(OUT, OUTBLOCKS, STATE) | |||
#define stream256_init(STATE, SEED, NONCE) PQCLEAN_DILITHIUM2_CLEAN_shake256_stream_init(STATE, SEED, NONCE) | |||
#define stream256_squeezeblocks(OUT, OUTBLOCKS, STATE) shake256_squeezeblocks(OUT, OUTBLOCKS, STATE) | |||
#define STREAM128_BLOCKBYTES SHAKE128_RATE | |||
#define STREAM256_BLOCKBYTES SHAKE256_RATE | |||
void PQCLEAN_DILITHIUM2_CLEAN_shake128_stream_init(shake128ctx *state, | |||
const unsigned char *seed, | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM2_CLEAN_shake256_stream_init(shake256ctx *state, | |||
const unsigned char *seed, | |||
uint16_t nonce); | |||
#endif |
@@ -0,0 +1,19 @@ | |||
name: DilithiumIII | |||
type: signature | |||
claimed-nist-level: 2 | |||
length-public-key: 1472 | |||
length-secret-key: 3504 | |||
length-signature: 2701 | |||
nistkat-sha256: 900268789819cc81b03e6384d97336b7bc700a5a9ffd5d3c993deacb6fe7f5b6 | |||
testvectors-sha256: 35d7e51b9e4e456c68bfc5ae393d311c96005d8563eb3240a051c97f3710c45d | |||
principal-submitter: Vadim Lyubashevsky | |||
auxiliary-submitters: | |||
- Léo Ducas | |||
- Eike Kiltz | |||
- Tancrède Lepoint | |||
- Peter Schwabe | |||
- Gregor Seiler | |||
- Damien Stehlé | |||
implementations: | |||
- name: clean | |||
version: https://github.com/pq-crystals/dilithium/commit/40f79645879b5c69835cd91d06945d7c24f39922 |
@@ -0,0 +1,2 @@ | |||
Public Domain | |||
Authors: Léo Ducas, Eike Kiltz, Tancrède Lepoint, Vadim Lyubashevsky, Gregor Seiler, Peter Schwabe, Damien Stehlé |
@@ -0,0 +1,22 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=libdilithium3_clean.a | |||
SOURCES = sign.c polyvec.c poly.c packing.c ntt.c reduce.c rounding.c symmetric.c | |||
OBJECTS = sign.o polyvec.o poly.o packing.o ntt.o reduce.o rounding.o symmetric.o | |||
HEADERS = api.h params.h sign.h polyvec.h poly.h packing.h ntt.h \ | |||
reduce.h rounding.h symmetric.h | |||
CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
%.o: %.c $(HEADERS) | |||
$(CC) $(CFLAGS) -c -o $@ $< | |||
$(LIB): $(OBJECTS) | |||
$(AR) -r $@ $(OBJECTS) | |||
clean: | |||
$(RM) $(OBJECTS) | |||
$(RM) $(LIB) |
@@ -0,0 +1,18 @@ | |||
# This Makefile can be used with Microsoft Visual Studio's nmake using the command: | |||
# nmake /f Makefile.Microsoft_nmake | |||
LIBRARY=libdilithium3_clean.lib | |||
OBJECTS=sign.obj polyvec.obj poly.obj packing.obj ntt.obj reduce.obj rounding.obj symmetric.obj | |||
CFLAGS=/nologo /I ..\..\..\common /W4 /WX | |||
all: $(LIBRARY) | |||
# Make sure objects are recompiled if headers change. | |||
$(OBJECTS): *.h | |||
$(LIBRARY): $(OBJECTS) | |||
LIB.EXE /NOLOGO /WX /OUT:$@ $** | |||
clean: | |||
-DEL $(OBJECTS) | |||
-DEL $(LIBRARY) |
@@ -0,0 +1,32 @@ | |||
#ifndef PQCLEAN_DILITHIUM3_CLEAN_API_H | |||
#define PQCLEAN_DILITHIUM3_CLEAN_API_H | |||
#include <stdint.h> | |||
#define PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_PUBLICKEYBYTES 1472U | |||
#define PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_SECRETKEYBYTES 3504U | |||
#define PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_BYTES 2701U | |||
#define PQCLEAN_DILITHIUM3_CLEAN_CRYPTO_ALGNAME "Dilithium3" | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *pk); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen, | |||
const uint8_t *msg, size_t len, | |||
const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen, | |||
const uint8_t *sm, size_t smlen, | |||
const uint8_t *pk); | |||
#endif |
@@ -0,0 +1,137 @@ | |||
#include "ntt.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "reduce.h" | |||
#include <stdint.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 PQCLEAN_DILITHIUM3_CLEAN_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 = PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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] = PQCLEAN_DILITHIUM3_CLEAN_montgomery_reduce((uint64_t)zeta * p[j + len]); | |||
} | |||
} | |||
} | |||
for (j = 0; j < N; ++j) { | |||
p[j] = PQCLEAN_DILITHIUM3_CLEAN_montgomery_reduce((uint64_t)f * p[j]); | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
#ifndef NTT_H | |||
#define NTT_H | |||
#include "params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_DILITHIUM3_CLEAN_ntt(uint32_t p[N]); | |||
void PQCLEAN_DILITHIUM3_CLEAN_invntt_frominvmont(uint32_t p[N]); | |||
#endif |
@@ -0,0 +1,297 @@ | |||
#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 PQCLEAN_DILITHIUM3_CLEAN_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) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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) { | |||
PQCLEAN_DILITHIUM3_CLEAN_polyeta_pack(sk + i * POLETA_SIZE_PACKED, &s1->vec[i]); | |||
} | |||
sk += L * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_polyeta_pack(sk + i * POLETA_SIZE_PACKED, &s2->vec[i]); | |||
} | |||
sk += K * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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) { | |||
PQCLEAN_DILITHIUM3_CLEAN_polyeta_unpack(&s1->vec[i], sk + i * POLETA_SIZE_PACKED); | |||
} | |||
sk += L * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_polyeta_unpack(&s2->vec[i], sk + i * POLETA_SIZE_PACKED); | |||
} | |||
sk += K * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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++] = (unsigned char) j; | |||
} | |||
} | |||
sig[OMEGA + i] = (unsigned char) 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] |= (unsigned char) (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] = (unsigned char) (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 PQCLEAN_DILITHIUM3_CLEAN_unpack_sig(polyvecl *z, | |||
polyveck *h, | |||
poly *c, | |||
const unsigned char sig[CRYPTO_BYTES]) { | |||
unsigned int i, j, k; | |||
uint64_t signs; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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; | |||
} | |||
for (i = 0; i < N / 8; ++i) { | |||
for (j = 0; j < 8; ++j) { | |||
if ((sig[i] >> j) & 0x01) { | |||
c->coeffs[8 * i + j] = 1; | |||
c->coeffs[8 * i + j] ^= -((int32_t) signs & 1) & (1 ^ (Q - 1)); | |||
signs >>= 1; | |||
} | |||
} | |||
} | |||
return 0; | |||
} |
@@ -0,0 +1,31 @@ | |||
#ifndef PACKING_H | |||
#define PACKING_H | |||
#include "params.h" | |||
#include "polyvec.h" | |||
void PQCLEAN_DILITHIUM3_CLEAN_pack_pk(unsigned char pk[CRYPTO_PUBLICKEYBYTES], | |||
const unsigned char rho[SEEDBYTES], const polyveck *t1); | |||
void PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_pack_sig(unsigned char sig[CRYPTO_BYTES], | |||
const polyvecl *z, const polyveck *h, const poly *c); | |||
void PQCLEAN_DILITHIUM3_CLEAN_unpack_pk(unsigned char rho[SEEDBYTES], polyveck *t1, | |||
const unsigned char pk[CRYPTO_PUBLICKEYBYTES]); | |||
void PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_unpack_sig(polyvecl *z, polyveck *h, poly *c, | |||
const unsigned char sig[CRYPTO_BYTES]); | |||
#endif |
@@ -0,0 +1,33 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
#define SEEDBYTES 32 | |||
#define CRHBYTES 48 | |||
#define N 256 | |||
#define Q 8380417 | |||
#define QBITS 23 | |||
#define ROOT_OF_UNITY 1753 | |||
#define D 14 | |||
#define GAMMA1 ((Q - 1)/16) | |||
#define GAMMA2 (GAMMA1/2) | |||
#define ALPHA (2*GAMMA2) | |||
// DilithiumIII parameters | |||
#define K 5 | |||
#define L 4 | |||
#define ETA 5 | |||
#define SETABITS 4 | |||
#define BETA 275 | |||
#define OMEGA 96 | |||
#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 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,737 @@ | |||
#include "ntt.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "reduce.h" | |||
#include "rounding.h" | |||
#include "symmetric.h" | |||
#include <stdint.h> | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_poly_reduce | |||
* | |||
* Description: Reduce all coefficients of input polynomial to representative | |||
* in [0,2*Q[. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_reduce(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM3_CLEAN_reduce32(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_poly_csubq(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM3_CLEAN_csubq(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_poly_freeze | |||
* | |||
* Description: Reduce all coefficients of the polynomial to standard | |||
* representatives. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_freeze(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM3_CLEAN_freeze(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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: PQCLEAN_DILITHIUM3_CLEAN_poly_shiftl | |||
* | |||
* Description: Multiply polynomial by 2^D without modular reduction. Assumes | |||
* input coefficients to be less than 2^{32-D}. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_shiftl(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] <<= D; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_poly_ntt(poly *a) { | |||
PQCLEAN_DILITHIUM3_CLEAN_ntt(a->coeffs); | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_poly_invntt_montgomery(poly *a) { | |||
PQCLEAN_DILITHIUM3_CLEAN_invntt_frominvmont(a->coeffs); | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
c->coeffs[i] = PQCLEAN_DILITHIUM3_CLEAN_montgomery_reduce((uint64_t)a->coeffs[i] * b->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_poly_power2round(poly *a1, poly *a0, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a1->coeffs[i] = PQCLEAN_DILITHIUM3_CLEAN_power2round(a->coeffs[i], &a0->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_poly_decompose(poly *a1, poly *a0, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a1->coeffs[i] = PQCLEAN_DILITHIUM3_CLEAN_decompose(a->coeffs[i], &a0->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_poly_make_hint | |||
* | |||
* Description: Compute hint polynomial. The coefficients of which indicate | |||
* whether the low bits of the corresponding coefficient of | |||
* the input polynomial overflow into the high bits. | |||
* | |||
* Arguments: - poly *h: pointer to output hint polynomial | |||
* - const poly *a0: pointer to low part of input polynomial | |||
* - const poly *a1: pointer to high part of input polynomial | |||
* | |||
* Returns number of 1 bits. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM3_CLEAN_poly_make_hint(poly *h, const poly *a0, const poly *a1) { | |||
unsigned int i, s = 0; | |||
for (i = 0; i < N; ++i) { | |||
h->coeffs[i] = PQCLEAN_DILITHIUM3_CLEAN_make_hint(a0->coeffs[i], a1->coeffs[i]); | |||
s += h->coeffs[i]; | |||
} | |||
return s; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_poly_use_hint(poly *a, const poly *b, const poly *h) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM3_CLEAN_use_hint(b->coeffs[i], h->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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 = (int32_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: rej_uniform | |||
* | |||
* Description: Sample uniformly random coefficients in [0, Q-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_uniform(uint32_t *a, | |||
unsigned int len, | |||
const unsigned char *buf, | |||
unsigned int buflen) { | |||
unsigned int ctr, pos; | |||
uint32_t t; | |||
ctr = pos = 0; | |||
while (ctr < len && pos + 3 <= buflen) { | |||
t = buf[pos++]; | |||
t |= (uint32_t)buf[pos++] << 8; | |||
t |= (uint32_t)buf[pos++] << 16; | |||
t &= 0x7FFFFF; | |||
if (t < Q) { | |||
a[ctr++] = t; | |||
} | |||
} | |||
return ctr; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_poly_uniform | |||
* | |||
* Description: Sample polynomial with uniformly random coefficients | |||
* in [0,Q-1] 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 | |||
* - uint16_t nonce: 2-byte nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_NBLOCKS ((769 + STREAM128_BLOCKBYTES)/STREAM128_BLOCKBYTES) | |||
#define POLY_UNIFORM_BUFLEN (POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_uniform(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int i, ctr, off; | |||
unsigned int buflen = POLY_UNIFORM_BUFLEN; | |||
unsigned char buf[POLY_UNIFORM_BUFLEN + 2]; | |||
shake128ctx state; | |||
stream128_init(&state, seed, nonce); | |||
stream128_squeezeblocks(buf, POLY_UNIFORM_NBLOCKS, &state); | |||
ctr = rej_uniform(a->coeffs, N, buf, buflen); | |||
while (ctr < N) { | |||
off = buflen % 3; | |||
for (i = 0; i < off; ++i) { | |||
buf[i] = buf[buflen - off + i]; | |||
} | |||
buflen = STREAM128_BLOCKBYTES + off; | |||
stream128_squeezeblocks(buf + off, 1, &state); | |||
ctr += rej_uniform(a->coeffs + ctr, N - ctr, buf, buflen); | |||
} | |||
} | |||
/************************************************* | |||
* 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) { | |||
unsigned int ctr, pos; | |||
uint32_t t0, t1; | |||
ctr = pos = 0; | |||
while (ctr < len && pos < buflen) { | |||
t0 = buf[pos] & 0x0F; | |||
t1 = buf[pos++] >> 4; | |||
if (t0 <= 2 * ETA) { | |||
a[ctr++] = Q + ETA - t0; | |||
} | |||
if (t1 <= 2 * ETA && ctr < len) { | |||
a[ctr++] = Q + ETA - t1; | |||
} | |||
} | |||
return ctr; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 | |||
* - uint16_t nonce: 2-byte nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_ETA_NBLOCKS (((N/2 * (1U << SETABITS)) / (2*ETA + 1)\ | |||
+ STREAM128_BLOCKBYTES) / STREAM128_BLOCKBYTES) | |||
#define POLY_UNIFORM_ETA_BUFLEN (POLY_UNIFORM_ETA_NBLOCKS*STREAM128_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_uniform_eta(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int ctr; | |||
unsigned char buf[POLY_UNIFORM_ETA_BUFLEN]; | |||
shake128ctx state; | |||
stream128_init(&state, seed, nonce); | |||
stream128_squeezeblocks(buf, POLY_UNIFORM_ETA_NBLOCKS, &state); | |||
ctr = rej_eta(a->coeffs, N, buf, POLY_UNIFORM_ETA_BUFLEN); | |||
while (ctr < N) { | |||
stream128_squeezeblocks(buf, 1, &state); | |||
ctr += rej_eta(a->coeffs + ctr, N - ctr, buf, STREAM128_BLOCKBYTES); | |||
} | |||
} | |||
/************************************************* | |||
* 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) { | |||
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: PQCLEAN_DILITHIUM3_CLEAN_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 | |||
* CRHBYTES | |||
* - uint16_t nonce: 16-bit nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_GAMMA1M1_NBLOCKS ((641 + STREAM256_BLOCKBYTES) / STREAM256_BLOCKBYTES) | |||
#define POLY_UNIFORM_GAMMA1M1_BUFLEN (POLY_UNIFORM_GAMMA1M1_NBLOCKS * STREAM256_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_uniform_gamma1m1(poly *a, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce) { | |||
unsigned int i, ctr, off; | |||
unsigned int buflen = POLY_UNIFORM_GAMMA1M1_BUFLEN; | |||
unsigned char buf[POLY_UNIFORM_GAMMA1M1_BUFLEN + 4]; | |||
shake256ctx state; | |||
stream256_init(&state, seed, nonce); | |||
stream256_squeezeblocks(buf, POLY_UNIFORM_GAMMA1M1_NBLOCKS, &state); | |||
ctr = rej_gamma1m1(a->coeffs, N, buf, buflen); | |||
while (ctr < N) { | |||
off = buflen % 5; | |||
for (i = 0; i < off; ++i) { | |||
buf[i] = buf[buflen - off + i]; | |||
} | |||
buflen = STREAM256_BLOCKBYTES + off; | |||
stream256_squeezeblocks(buf + off, 1, &state); | |||
ctr += rej_gamma1m1(a->coeffs + ctr, N - ctr, buf, buflen); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyeta_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
unsigned char t[8]; | |||
for (i = 0; i < N / 2; ++i) { | |||
t[0] = (uint8_t) (Q + ETA - a->coeffs[2 * i + 0]); | |||
t[1] = (uint8_t) (Q + ETA - a->coeffs[2 * i + 1]); | |||
r[i] = (uint8_t) (t[0] | (t[1] << 4)); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyeta_unpack(poly *r, const unsigned char *a) { | |||
unsigned int i; | |||
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]; | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM3_CLEAN_polyt1_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 8; ++i) { | |||
r[9 * i + 0] = (uint8_t) ((a->coeffs[8 * i + 0] >> 0)); | |||
r[9 * i + 1] = (uint8_t) ((a->coeffs[8 * i + 0] >> 8) | (a->coeffs[8 * i + 1] << 1)); | |||
r[9 * i + 2] = (uint8_t) ((a->coeffs[8 * i + 1] >> 7) | (a->coeffs[8 * i + 2] << 2)); | |||
r[9 * i + 3] = (uint8_t) ((a->coeffs[8 * i + 2] >> 6) | (a->coeffs[8 * i + 3] << 3)); | |||
r[9 * i + 4] = (uint8_t) ((a->coeffs[8 * i + 3] >> 5) | (a->coeffs[8 * i + 4] << 4)); | |||
r[9 * i + 5] = (uint8_t) ((a->coeffs[8 * i + 4] >> 4) | (a->coeffs[8 * i + 5] << 5)); | |||
r[9 * i + 6] = (uint8_t) ((a->coeffs[8 * i + 5] >> 3) | (a->coeffs[8 * i + 6] << 6)); | |||
r[9 * i + 7] = (uint8_t) ((a->coeffs[8 * i + 6] >> 2) | (a->coeffs[8 * i + 7] << 7)); | |||
r[9 * i + 8] = (uint8_t) ((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 PQCLEAN_DILITHIUM3_CLEAN_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] << 8)) & 0x1FF; | |||
r->coeffs[8 * i + 1] = ((a[9 * i + 1] >> 1) | ((uint32_t)a[9 * i + 2] << 7)) & 0x1FF; | |||
r->coeffs[8 * i + 2] = ((a[9 * i + 2] >> 2) | ((uint32_t)a[9 * i + 3] << 6)) & 0x1FF; | |||
r->coeffs[8 * i + 3] = ((a[9 * i + 3] >> 3) | ((uint32_t)a[9 * i + 4] << 5)) & 0x1FF; | |||
r->coeffs[8 * i + 4] = ((a[9 * i + 4] >> 4) | ((uint32_t)a[9 * i + 5] << 4)) & 0x1FF; | |||
r->coeffs[8 * i + 5] = ((a[9 * i + 5] >> 5) | ((uint32_t)a[9 * i + 6] << 3)) & 0x1FF; | |||
r->coeffs[8 * i + 6] = ((a[9 * i + 6] >> 6) | ((uint32_t)a[9 * i + 7] << 2)) & 0x1FF; | |||
r->coeffs[8 * i + 7] = ((a[9 * i + 7] >> 7) | ((uint32_t)a[9 * i + 8] << 1)) & 0x1FF; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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 + (1U << (D - 1)) - a->coeffs[4 * i + 0]; | |||
t[1] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 1]; | |||
t[2] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 2]; | |||
t[3] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 3]; | |||
r[7 * i + 0] = (uint8_t) (t[0]); | |||
r[7 * i + 1] = (uint8_t) (t[0] >> 8); | |||
r[7 * i + 1] |= (uint8_t) (t[1] << 6); | |||
r[7 * i + 2] = (uint8_t) (t[1] >> 2); | |||
r[7 * i + 3] = (uint8_t) (t[1] >> 10); | |||
r[7 * i + 3] |= (uint8_t) (t[2] << 4); | |||
r[7 * i + 4] = (uint8_t) (t[2] >> 4); | |||
r[7 * i + 5] = (uint8_t) (t[2] >> 12); | |||
r[7 * i + 5] |= (uint8_t) (t[3] << 2); | |||
r[7 * i + 6] = (uint8_t) (t[3] >> 6); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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 + (1U << (D - 1)) - r->coeffs[4 * i + 0]; | |||
r->coeffs[4 * i + 1] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 1]; | |||
r->coeffs[4 * i + 2] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 2]; | |||
r->coeffs[4 * i + 3] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 3]; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyz_pack(unsigned char *r, const poly *a) { | |||
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] = (uint8_t) (t[0]); | |||
r[5 * i + 1] = (uint8_t) (t[0] >> 8); | |||
r[5 * i + 2] = (uint8_t) (t[0] >> 16); | |||
r[5 * i + 2] |= (uint8_t) (t[1] << 4); | |||
r[5 * i + 3] = (uint8_t) (t[1] >> 4); | |||
r[5 * i + 4] = (uint8_t) (t[1] >> 12); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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: PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyw1_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 2; ++i) { | |||
r[i] = (uint8_t) (a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)); | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
#include "params.h" | |||
#include <stdint.h> | |||
typedef struct { | |||
uint32_t coeffs[N]; | |||
} poly; | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_reduce(poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_csubq(poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_freeze(poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_add(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_sub(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_shiftl(poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_ntt(poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_invntt_montgomery(poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_power2round(poly *a1, poly *a0, const poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_decompose(poly *a1, poly *a0, const poly *a); | |||
unsigned int PQCLEAN_DILITHIUM3_CLEAN_poly_make_hint(poly *h, const poly *a0, const poly *a1); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_use_hint(poly *a, const poly *b, const poly *h); | |||
int PQCLEAN_DILITHIUM3_CLEAN_poly_chknorm(const poly *a, uint32_t B); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_uniform(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_uniform_eta(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM3_CLEAN_poly_uniform_gamma1m1(poly *a, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyeta_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyeta_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyt1_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyt1_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyt0_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyt0_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyz_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyz_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyw1_pack(unsigned char *r, const poly *a); | |||
#endif |
@@ -0,0 +1,357 @@ | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.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 PQCLEAN_DILITHIUM3_CLEAN_polyvecl_freeze(polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyvecl_ntt(polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyvecl_pointwise_acc_invmontgomery(poly *w, | |||
const polyvecl *u, | |||
const polyvecl *v) { | |||
unsigned int i; | |||
poly t; | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_pointwise_invmontgomery(w, &u->vec[0], &v->vec[0]); | |||
for (i = 1; i < L; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_pointwise_invmontgomery(&t, &u->vec[i], &v->vec[i]); | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyvecl_chknorm(const polyvecl *v, uint32_t bound) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
if (PQCLEAN_DILITHIUM3_CLEAN_poly_chknorm(&v->vec[i], bound)) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
/**************************************************************/ | |||
/************ 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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_reduce(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_csubq(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_freeze(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_add(polyveck *w, const polyveck *u, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_sub(&w->vec[i], &u->vec[i], &v->vec[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyveck_shiftl | |||
* | |||
* Description: Multiply vector of polynomials of Length K by 2^D without modular | |||
* reduction. Assumes input coefficients to be less than 2^{32-D}. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_shiftl(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_shiftl(&v->vec[i]); | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_ntt(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_invntt_montgomery(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_chknorm(const polyveck *v, uint32_t bound) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
if (PQCLEAN_DILITHIUM3_CLEAN_poly_chknorm(&v->vec[i], bound)) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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 *v0: pointer to low part of input vector | |||
* - const polyveck *v1: pointer to high part of input vector | |||
* | |||
* Returns number of 1 bits. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM3_CLEAN_polyveck_make_hint(polyveck *h, | |||
const polyveck *v0, | |||
const polyveck *v1) { | |||
unsigned int i, s = 0; | |||
for (i = 0; i < K; ++i) { | |||
s += PQCLEAN_DILITHIUM3_CLEAN_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->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 PQCLEAN_DILITHIUM3_CLEAN_polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
#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 PQCLEAN_DILITHIUM3_CLEAN_polyvecl_freeze(polyvecl *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyvecl_ntt(polyvecl *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyvecl_pointwise_acc_invmontgomery(poly *w, | |||
const polyvecl *u, | |||
const polyvecl *v); | |||
int PQCLEAN_DILITHIUM3_CLEAN_polyvecl_chknorm(const polyvecl *v, uint32_t B); | |||
/* Vectors of polynomials of length K */ | |||
typedef struct { | |||
poly vec[K]; | |||
} polyveck; | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_reduce(polyveck *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_csubq(polyveck *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_freeze(polyveck *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_add(polyveck *w, const polyveck *u, const polyveck *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_shiftl(polyveck *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_ntt(polyveck *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_invntt_montgomery(polyveck *v); | |||
int PQCLEAN_DILITHIUM3_CLEAN_polyveck_chknorm(const polyveck *v, uint32_t B); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v); | |||
unsigned int PQCLEAN_DILITHIUM3_CLEAN_polyveck_make_hint(polyveck *h, | |||
const polyveck *v0, | |||
const polyveck *v1); | |||
void PQCLEAN_DILITHIUM3_CLEAN_polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h); | |||
#endif |
@@ -0,0 +1,74 @@ | |||
#include "params.h" | |||
#include "reduce.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 PQCLEAN_DILITHIUM3_CLEAN_montgomery_reduce(uint64_t a) { | |||
uint64_t t; | |||
t = a * QINV; | |||
t &= (1ULL << 32) - 1; | |||
t *= Q; | |||
t = a + t; | |||
t >>= 32; | |||
return (uint32_t) 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 PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_freeze(uint32_t a) { | |||
a = PQCLEAN_DILITHIUM3_CLEAN_reduce32(a); | |||
a = PQCLEAN_DILITHIUM3_CLEAN_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 PQCLEAN_DILITHIUM3_CLEAN_montgomery_reduce(uint64_t a); | |||
/* r < 2*Q */ | |||
uint32_t PQCLEAN_DILITHIUM3_CLEAN_reduce32(uint32_t a); | |||
/* a < 2*Q => r < Q */ | |||
uint32_t PQCLEAN_DILITHIUM3_CLEAN_csubq(uint32_t a); | |||
/* r < Q */ | |||
uint32_t PQCLEAN_DILITHIUM3_CLEAN_freeze(uint32_t a); | |||
#endif |
@@ -0,0 +1,105 @@ | |||
#include "params.h" | |||
#include "rounding.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 PQCLEAN_DILITHIUM3_CLEAN_power2round(uint32_t a, uint32_t *a0) { | |||
uint32_t t; | |||
/* Centralized remainder mod 2^D */ | |||
t = a & ((1U << D) - 1); | |||
t -= ((1U << (D - 1)) + 1); | |||
t += ((uint32_t)((int32_t)t >> 31) & (1U << D)); | |||
t -= ((1U << (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 PQCLEAN_DILITHIUM3_CLEAN_decompose(uint32_t a, uint32_t *a0) { | |||
int32_t t, u; | |||
/* Centralized remainder mod ALPHA */ | |||
t = a & 0x7FFFF; | |||
t += (int32_t) ((a >> 19) << 9); | |||
t -= ALPHA / 2 + 1; | |||
t += (t >> 31) & ALPHA; | |||
t -= ALPHA / 2 - 1; | |||
a -= (uint32_t) t; | |||
/* Divide by ALPHA (possible to avoid) */ | |||
u = (int32_t) a - 1; | |||
u >>= 31; | |||
a = (a >> 19) + 1; | |||
a -= u & 1; | |||
/* Border case */ | |||
*a0 = Q + (uint32_t)t - (a >> 4); | |||
a &= 0xF; | |||
return a; | |||
} | |||
/************************************************* | |||
* Name: make_hint | |||
* | |||
* Description: Compute hint bit indicating whether the low bits of the | |||
* input element overflow into the high bits. Inputs assumed to be | |||
* standard representatives. | |||
* | |||
* Arguments: - uint32_t a0: low bits of input element | |||
* - uint32_t a1: high bits of input element | |||
* | |||
* Returns 1 if high bits of a and b differ and 0 otherwise. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM3_CLEAN_make_hint(uint32_t a0, uint32_t a1) { | |||
if (a0 <= GAMMA2 || a0 > Q - GAMMA2 || (a0 == Q - GAMMA2 && a1 == 0)) { | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM3_CLEAN_use_hint(uint32_t a, unsigned int hint) { | |||
uint32_t a0, a1; | |||
a1 = PQCLEAN_DILITHIUM3_CLEAN_decompose(a, &a0); | |||
if (hint == 0) { | |||
return a1; | |||
} | |||
if (a0 > Q) { | |||
return (a1 + 1) & 0xF; | |||
} | |||
return (a1 - 1) & 0xF; | |||
} |
@@ -0,0 +1,11 @@ | |||
#ifndef ROUNDING_H | |||
#define ROUNDING_H | |||
#include <stdint.h> | |||
uint32_t PQCLEAN_DILITHIUM3_CLEAN_power2round(uint32_t a, uint32_t *a0); | |||
uint32_t PQCLEAN_DILITHIUM3_CLEAN_decompose(uint32_t a, uint32_t *a0); | |||
unsigned int PQCLEAN_DILITHIUM3_CLEAN_make_hint(uint32_t a0, uint32_t a1); | |||
uint32_t PQCLEAN_DILITHIUM3_CLEAN_use_hint(uint32_t a, unsigned int hint); | |||
#endif |
@@ -0,0 +1,414 @@ | |||
#include "fips202.h" | |||
#include "packing.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
#include "randombytes.h" | |||
#include "sign.h" | |||
#include "symmetric.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 PQCLEAN_DILITHIUM3_CLEAN_expand_mat(polyvecl mat[K], const unsigned char rho[SEEDBYTES]) { | |||
unsigned int i, j; | |||
for (i = 0; i < K; ++i) { | |||
for (j = 0; j < L; ++j) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_uniform(&mat[i].vec[j], rho, (uint16_t)((i << 8) + j)); | |||
} | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM3_CLEAN_challenge(poly *c, | |||
const unsigned char mu[CRHBYTES], | |||
const polyveck *w1) { | |||
unsigned int i, b, pos; | |||
uint64_t signs; | |||
unsigned char inbuf[CRHBYTES + K * POLW1_SIZE_PACKED]; | |||
unsigned char outbuf[SHAKE256_RATE]; | |||
shake256ctx state; | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
inbuf[i] = mu[i]; | |||
} | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_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; | |||
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] = 1; | |||
c->coeffs[b] ^= -((int32_t)signs & 1) & (1 ^ (Q - 1)); | |||
signs >>= 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 PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { | |||
unsigned int i; | |||
unsigned char seedbuf[3 * SEEDBYTES]; | |||
unsigned char tr[CRHBYTES]; | |||
const 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, 3 * SEEDBYTES); | |||
rho = seedbuf; | |||
rhoprime = seedbuf + SEEDBYTES; | |||
key = seedbuf + 2 * SEEDBYTES; | |||
/* Expand matrix */ | |||
PQCLEAN_DILITHIUM3_CLEAN_expand_mat(mat, rho); | |||
/* Sample short vectors s1 and s2 */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_uniform_eta(&s1.vec[i], rhoprime, nonce++); | |||
} | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_uniform_eta(&s2.vec[i], rhoprime, nonce++); | |||
} | |||
/* Matrix-vector multiplication */ | |||
s1hat = s1; | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_ntt(&s1hat); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_pointwise_acc_invmontgomery(&t.vec[i], &mat[i], &s1hat); | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_reduce(&t.vec[i]); | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_invntt_montgomery(&t.vec[i]); | |||
} | |||
/* Add error vector s2 */ | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_add(&t, &t, &s2); | |||
/* Extract t1 and write public key */ | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_freeze(&t); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_power2round(&t1, &t0, &t); | |||
PQCLEAN_DILITHIUM3_CLEAN_pack_pk(pk, rho, &t1); | |||
/* Compute CRH(rho, t1) and write secret key */ | |||
crh(tr, pk, CRYPTO_PUBLICKEYBYTES); | |||
PQCLEAN_DILITHIUM3_CLEAN_pack_sk(sk, rho, key, tr, &s1, &s2, &t0); | |||
return 0; | |||
} | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk) { | |||
unsigned long long i; | |||
unsigned int n; | |||
unsigned char seedbuf[2 * SEEDBYTES + 3 * CRHBYTES]; | |||
unsigned char *rho, *tr, *key, *mu, *rhoprime; | |||
uint16_t nonce = 0; | |||
poly c, chat; | |||
polyvecl mat[K], s1, y, yhat, z; | |||
polyveck t0, s2, w, w1, w0; | |||
polyveck h, cs2, ct0; | |||
rho = seedbuf; | |||
tr = rho + SEEDBYTES; | |||
key = tr + CRHBYTES; | |||
mu = key + SEEDBYTES; | |||
rhoprime = mu + CRHBYTES; | |||
PQCLEAN_DILITHIUM3_CLEAN_unpack_sk(rho, key, tr, &s1, &s2, &t0, sk); | |||
// use incremental hash API instead of copying around buffers | |||
/* Compute CRH(tr, msg) */ | |||
shake256incctx state; | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, tr, CRHBYTES); | |||
shake256_inc_absorb(&state, m, mlen); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
sig[CRYPTO_BYTES - CRHBYTES + i] = tr[i]; | |||
} | |||
crh(rhoprime, key, SEEDBYTES + CRHBYTES); | |||
/* Expand matrix and transform vectors */ | |||
PQCLEAN_DILITHIUM3_CLEAN_expand_mat(mat, rho); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_ntt(&s1); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_ntt(&s2); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_ntt(&t0); | |||
rej: | |||
/* Sample intermediate vector y */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_uniform_gamma1m1(&y.vec[i], rhoprime, nonce++); | |||
} | |||
/* Matrix-vector multiplication */ | |||
yhat = y; | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_ntt(&yhat); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_pointwise_acc_invmontgomery(&w.vec[i], &mat[i], &yhat); | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_reduce(&w.vec[i]); | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_invntt_montgomery(&w.vec[i]); | |||
} | |||
/* Decompose w and call the random oracle */ | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_csubq(&w); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_decompose(&w1, &w0, &w); | |||
PQCLEAN_DILITHIUM3_CLEAN_challenge(&c, mu, &w1); | |||
chat = c; | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_ntt(&chat); | |||
/* Check that subtracting cs2 does not change high bits of w and low bits | |||
* do not reveal secret information */ | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_pointwise_invmontgomery(&cs2.vec[i], &chat, &s2.vec[i]); | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_invntt_montgomery(&cs2.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_sub(&w0, &w0, &cs2); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_freeze(&w0); | |||
if (PQCLEAN_DILITHIUM3_CLEAN_polyveck_chknorm(&w0, GAMMA2 - BETA)) { | |||
goto rej; | |||
} | |||
/* Compute z, reject if it reveals secret */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_pointwise_invmontgomery(&z.vec[i], &chat, &s1.vec[i]); | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_invntt_montgomery(&z.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_add(&z, &z, &y); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_freeze(&z); | |||
if (PQCLEAN_DILITHIUM3_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) { | |||
goto rej; | |||
} | |||
/* Compute hints for w1 */ | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_pointwise_invmontgomery(&ct0.vec[i], &chat, &t0.vec[i]); | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_invntt_montgomery(&ct0.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_csubq(&ct0); | |||
if (PQCLEAN_DILITHIUM3_CLEAN_polyveck_chknorm(&ct0, GAMMA2)) { | |||
goto rej; | |||
} | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_add(&w0, &w0, &ct0); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_csubq(&w0); | |||
n = PQCLEAN_DILITHIUM3_CLEAN_polyveck_make_hint(&h, &w0, &w1); | |||
if (n > OMEGA) { | |||
goto rej; | |||
} | |||
/* Write signature */ | |||
PQCLEAN_DILITHIUM3_CLEAN_pack_sig(sig, &z, &h, &c); | |||
*siglen = CRYPTO_BYTES; | |||
return 0; | |||
} | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *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 (siglen < CRYPTO_BYTES) { | |||
return -1; | |||
} | |||
PQCLEAN_DILITHIUM3_CLEAN_unpack_pk(rho, &t1, pk); | |||
if (PQCLEAN_DILITHIUM3_CLEAN_unpack_sig(&z, &h, &c, sig)) { | |||
return -1; | |||
} | |||
if (PQCLEAN_DILITHIUM3_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) { | |||
return -1; | |||
} | |||
/* Compute CRH(CRH(rho, t1), msg) */ | |||
shake256incctx state; | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, pk, CRYPTO_PUBLICKEYBYTES); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, mu, CRHBYTES); | |||
shake256_inc_absorb(&state, m, mlen); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
/* Matrix-vector multiplication; compute Az - c2^dt1 */ | |||
PQCLEAN_DILITHIUM3_CLEAN_expand_mat(mat, rho); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_ntt(&z); | |||
for (i = 0; i < K ; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_polyvecl_pointwise_acc_invmontgomery(&tmp1.vec[i], &mat[i], &z); | |||
} | |||
chat = c; | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_ntt(&chat); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_shiftl(&t1); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_ntt(&t1); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM3_CLEAN_poly_pointwise_invmontgomery(&tmp2.vec[i], &chat, &t1.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_sub(&tmp1, &tmp1, &tmp2); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_reduce(&tmp1); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_invntt_montgomery(&tmp1); | |||
/* Reconstruct w1 */ | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_csubq(&tmp1); | |||
PQCLEAN_DILITHIUM3_CLEAN_polyveck_use_hint(&w1, &tmp1, &h); | |||
/* Call random oracle and verify challenge */ | |||
PQCLEAN_DILITHIUM3_CLEAN_challenge(&cp, mu, &w1); | |||
for (i = 0; i < N; ++i) { | |||
if (c.coeffs[i] != cp.coeffs[i]) { | |||
return -1; | |||
} | |||
} | |||
// All good | |||
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 PQCLEAN_DILITHIUM3_CLEAN_crypto_sign(uint8_t *sm, | |||
size_t *smlen, | |||
const uint8_t *m, | |||
size_t mlen, | |||
const uint8_t *sk) { | |||
size_t i; | |||
int rc; | |||
for (i = 0; i < mlen; i++) { | |||
sm[CRYPTO_BYTES + i] = m[i]; | |||
} | |||
rc = PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_signature(sm, smlen, m, mlen, sk); | |||
*smlen += mlen; | |||
return rc; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_open(uint8_t *m, | |||
size_t *mlen, | |||
const uint8_t *sm, | |||
size_t smlen, | |||
const uint8_t *pk) { | |||
size_t i; | |||
if (smlen < CRYPTO_BYTES) { | |||
goto badsig; | |||
} | |||
*mlen = smlen - CRYPTO_BYTES; | |||
if (PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_verify(sm, CRYPTO_BYTES, | |||
sm + CRYPTO_BYTES, *mlen, pk)) { | |||
goto badsig; | |||
} else { | |||
/* 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 = (size_t) -1; | |||
for (i = 0; i < smlen; ++i) { | |||
m[i] = 0; | |||
} | |||
return -1; | |||
} | |||
@@ -0,0 +1,30 @@ | |||
#ifndef SIGN_H | |||
#define SIGN_H | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
void PQCLEAN_DILITHIUM3_CLEAN_expand_mat(polyvecl mat[K], const unsigned char rho[SEEDBYTES]); | |||
void PQCLEAN_DILITHIUM3_CLEAN_challenge(poly *c, const unsigned char mu[CRHBYTES], | |||
const polyveck *w1); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *pk); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen, | |||
const uint8_t *msg, size_t len, | |||
const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen, | |||
const uint8_t *sm, size_t smlen, | |||
const uint8_t *pk); | |||
#endif |
@@ -0,0 +1,32 @@ | |||
#include "symmetric.h" | |||
#include "fips202.h" | |||
void PQCLEAN_DILITHIUM3_CLEAN_shake128_stream_init(shake128ctx *state, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int i; | |||
unsigned char buf[SEEDBYTES + 2]; | |||
for (i = 0; i < SEEDBYTES; ++i) { | |||
buf[i] = seed[i]; | |||
} | |||
buf[SEEDBYTES] = (uint8_t) nonce; | |||
buf[SEEDBYTES + 1] = (uint8_t) (nonce >> 8); | |||
shake128_absorb(state, buf, sizeof(buf)); | |||
} | |||
void PQCLEAN_DILITHIUM3_CLEAN_shake256_stream_init(shake256ctx *state, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce) { | |||
unsigned int i; | |||
unsigned char buf[CRHBYTES + 2]; | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
buf[i] = seed[i]; | |||
} | |||
buf[CRHBYTES] = (uint8_t) nonce; | |||
buf[CRHBYTES + 1] = (uint8_t) (nonce >> 8); | |||
shake256_absorb(state, buf, sizeof(buf)); | |||
} |
@@ -0,0 +1,23 @@ | |||
#ifndef SYMMETRIC_H | |||
#define SYMMETRIC_H | |||
#include "fips202.h" | |||
#include "params.h" | |||
#define crh(OUT, IN, INBYTES) shake256(OUT, CRHBYTES, IN, INBYTES) | |||
#define stream128_init(STATE, SEED, NONCE) PQCLEAN_DILITHIUM3_CLEAN_shake128_stream_init(STATE, SEED, NONCE) | |||
#define stream128_squeezeblocks(OUT, OUTBLOCKS, STATE) shake128_squeezeblocks(OUT, OUTBLOCKS, STATE) | |||
#define stream256_init(STATE, SEED, NONCE) PQCLEAN_DILITHIUM3_CLEAN_shake256_stream_init(STATE, SEED, NONCE) | |||
#define stream256_squeezeblocks(OUT, OUTBLOCKS, STATE) shake256_squeezeblocks(OUT, OUTBLOCKS, STATE) | |||
#define STREAM128_BLOCKBYTES SHAKE128_RATE | |||
#define STREAM256_BLOCKBYTES SHAKE256_RATE | |||
void PQCLEAN_DILITHIUM3_CLEAN_shake128_stream_init(shake128ctx *state, | |||
const unsigned char *seed, | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM3_CLEAN_shake256_stream_init(shake256ctx *state, | |||
const unsigned char *seed, | |||
uint16_t nonce); | |||
#endif |
@@ -0,0 +1,19 @@ | |||
name: DilithiumIV | |||
type: signature | |||
claimed-nist-level: 3 | |||
length-public-key: 1760 | |||
length-secret-key: 3856 | |||
length-signature: 3366 | |||
nistkat-sha256: 87844f967b4340d60dc4d83aac0f1d3a244fa8f9490017f72fd4969bba168f88 | |||
testvectors-sha256: 91087880c84678bf66008d843e7fa1ab5231114a8ca9e9e36c41065f14172af2 | |||
principal-submitter: Vadim Lyubashevsky | |||
auxiliary-submitters: | |||
- Léo Ducas | |||
- Eike Kiltz | |||
- Tancrède Lepoint | |||
- Peter Schwabe | |||
- Gregor Seiler | |||
- Damien Stehlé | |||
implementations: | |||
- name: clean | |||
version: https://github.com/pq-crystals/dilithium/commit/40f79645879b5c69835cd91d06945d7c24f39922 |
@@ -0,0 +1,2 @@ | |||
Public Domain | |||
Authors: Léo Ducas, Eike Kiltz, Tancrède Lepoint, Vadim Lyubashevsky, Gregor Seiler, Peter Schwabe, Damien Stehlé |
@@ -0,0 +1,22 @@ | |||
# This Makefile can be used with GNU Make or BSD Make | |||
LIB=libdilithium4_clean.a | |||
SOURCES = sign.c polyvec.c poly.c packing.c ntt.c reduce.c rounding.c symmetric.c | |||
OBJECTS = sign.o polyvec.o poly.o packing.o ntt.o reduce.o rounding.o symmetric.o | |||
HEADERS = api.h params.h sign.h polyvec.h poly.h packing.h ntt.h \ | |||
reduce.h rounding.h symmetric.h | |||
CFLAGS=-O3 -Wall -Wconversion -Wextra -Wpedantic -Wvla -Werror -Wmissing-prototypes -Wredundant-decls -std=c99 -I../../../common $(EXTRAFLAGS) | |||
all: $(LIB) | |||
%.o: %.c $(HEADERS) | |||
$(CC) $(CFLAGS) -c -o $@ $< | |||
$(LIB): $(OBJECTS) | |||
$(AR) -r $@ $(OBJECTS) | |||
clean: | |||
$(RM) $(OBJECTS) | |||
$(RM) $(LIB) |
@@ -0,0 +1,18 @@ | |||
# This Makefile can be used with Microsoft Visual Studio's nmake using the command: | |||
# nmake /f Makefile.Microsoft_nmake | |||
LIBRARY=libdilithium4_clean.lib | |||
OBJECTS=sign.obj polyvec.obj poly.obj packing.obj ntt.obj reduce.obj rounding.obj symmetric.obj | |||
CFLAGS=/nologo /I ..\..\..\common /W4 /WX | |||
all: $(LIBRARY) | |||
# Make sure objects are recompiled if headers change. | |||
$(OBJECTS): *.h | |||
$(LIBRARY): $(OBJECTS) | |||
LIB.EXE /NOLOGO /WX /OUT:$@ $** | |||
clean: | |||
-DEL $(OBJECTS) | |||
-DEL $(LIBRARY) |
@@ -0,0 +1,31 @@ | |||
#ifndef PQCLEAN_DILITHIUM4_CLEAN_API_H | |||
#define PQCLEAN_DILITHIUM4_CLEAN_API_H | |||
#include <stdint.h> | |||
#define PQCLEAN_DILITHIUM4_CLEAN_CRYPTO_PUBLICKEYBYTES 1760U | |||
#define PQCLEAN_DILITHIUM4_CLEAN_CRYPTO_SECRETKEYBYTES 3856U | |||
#define PQCLEAN_DILITHIUM4_CLEAN_CRYPTO_BYTES 3366U | |||
#define PQCLEAN_DILITHIUM4_CLEAN_CRYPTO_ALGNAME "Dilithium4" | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *pk); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen, | |||
const uint8_t *msg, size_t len, | |||
const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen, | |||
const uint8_t *sm, size_t smlen, | |||
const uint8_t *pk); | |||
#endif |
@@ -0,0 +1,137 @@ | |||
#include "ntt.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "reduce.h" | |||
#include <stdint.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 PQCLEAN_DILITHIUM4_CLEAN_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 = PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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] = PQCLEAN_DILITHIUM4_CLEAN_montgomery_reduce((uint64_t)zeta * p[j + len]); | |||
} | |||
} | |||
} | |||
for (j = 0; j < N; ++j) { | |||
p[j] = PQCLEAN_DILITHIUM4_CLEAN_montgomery_reduce((uint64_t)f * p[j]); | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
#ifndef NTT_H | |||
#define NTT_H | |||
#include "params.h" | |||
#include <stdint.h> | |||
void PQCLEAN_DILITHIUM4_CLEAN_ntt(uint32_t p[N]); | |||
void PQCLEAN_DILITHIUM4_CLEAN_invntt_frominvmont(uint32_t p[N]); | |||
#endif |
@@ -0,0 +1,297 @@ | |||
#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 PQCLEAN_DILITHIUM4_CLEAN_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) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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) { | |||
PQCLEAN_DILITHIUM4_CLEAN_polyeta_pack(sk + i * POLETA_SIZE_PACKED, &s1->vec[i]); | |||
} | |||
sk += L * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_polyeta_pack(sk + i * POLETA_SIZE_PACKED, &s2->vec[i]); | |||
} | |||
sk += K * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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) { | |||
PQCLEAN_DILITHIUM4_CLEAN_polyeta_unpack(&s1->vec[i], sk + i * POLETA_SIZE_PACKED); | |||
} | |||
sk += L * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_polyeta_unpack(&s2->vec[i], sk + i * POLETA_SIZE_PACKED); | |||
} | |||
sk += K * POLETA_SIZE_PACKED; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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++] = (unsigned char) j; | |||
} | |||
} | |||
sig[OMEGA + i] = (unsigned char) 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] |= (unsigned char) (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] = (unsigned char) (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 PQCLEAN_DILITHIUM4_CLEAN_unpack_sig(polyvecl *z, | |||
polyveck *h, | |||
poly *c, | |||
const unsigned char sig[CRYPTO_BYTES]) { | |||
unsigned int i, j, k; | |||
uint64_t signs; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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; | |||
} | |||
for (i = 0; i < N / 8; ++i) { | |||
for (j = 0; j < 8; ++j) { | |||
if ((sig[i] >> j) & 0x01) { | |||
c->coeffs[8 * i + j] = 1; | |||
c->coeffs[8 * i + j] ^= -((int32_t) signs & 1) & (1 ^ (Q - 1)); | |||
signs >>= 1; | |||
} | |||
} | |||
} | |||
return 0; | |||
} |
@@ -0,0 +1,31 @@ | |||
#ifndef PACKING_H | |||
#define PACKING_H | |||
#include "params.h" | |||
#include "polyvec.h" | |||
void PQCLEAN_DILITHIUM4_CLEAN_pack_pk(unsigned char pk[CRYPTO_PUBLICKEYBYTES], | |||
const unsigned char rho[SEEDBYTES], const polyveck *t1); | |||
void PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_pack_sig(unsigned char sig[CRYPTO_BYTES], | |||
const polyvecl *z, const polyveck *h, const poly *c); | |||
void PQCLEAN_DILITHIUM4_CLEAN_unpack_pk(unsigned char rho[SEEDBYTES], polyveck *t1, | |||
const unsigned char pk[CRYPTO_PUBLICKEYBYTES]); | |||
void PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_unpack_sig(polyvecl *z, polyveck *h, poly *c, | |||
const unsigned char sig[CRYPTO_BYTES]); | |||
#endif |
@@ -0,0 +1,34 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
#define SEEDBYTES 32 | |||
#define CRHBYTES 48 | |||
#define N 256 | |||
#define Q 8380417 | |||
#define QBITS 23 | |||
#define ROOT_OF_UNITY 1753 | |||
#define D 14 | |||
#define GAMMA1 ((Q - 1)/16) | |||
#define GAMMA2 (GAMMA1/2) | |||
#define ALPHA (2*GAMMA2) | |||
// DilithiumIV parameters | |||
#define K 6 | |||
#define L 5 | |||
#define ETA 3 | |||
#define SETABITS 3 | |||
#define BETA 175 | |||
#define OMEGA 120 | |||
#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 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,760 @@ | |||
#include "ntt.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "reduce.h" | |||
#include "rounding.h" | |||
#include "symmetric.h" | |||
#include <stdint.h> | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_poly_reduce | |||
* | |||
* Description: Reduce all coefficients of input polynomial to representative | |||
* in [0,2*Q[. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_reduce(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM4_CLEAN_reduce32(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_poly_csubq(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM4_CLEAN_csubq(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_poly_freeze | |||
* | |||
* Description: Reduce all coefficients of the polynomial to standard | |||
* representatives. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_freeze(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM4_CLEAN_freeze(a->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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: PQCLEAN_DILITHIUM4_CLEAN_poly_shiftl | |||
* | |||
* Description: Multiply polynomial by 2^D without modular reduction. Assumes | |||
* input coefficients to be less than 2^{32-D}. | |||
* | |||
* Arguments: - poly *a: pointer to input/output polynomial | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_shiftl(poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] <<= D; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_poly_ntt(poly *a) { | |||
PQCLEAN_DILITHIUM4_CLEAN_ntt(a->coeffs); | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_poly_invntt_montgomery(poly *a) { | |||
PQCLEAN_DILITHIUM4_CLEAN_invntt_frominvmont(a->coeffs); | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
c->coeffs[i] = PQCLEAN_DILITHIUM4_CLEAN_montgomery_reduce((uint64_t)a->coeffs[i] * b->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_poly_power2round(poly *a1, poly *a0, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a1->coeffs[i] = PQCLEAN_DILITHIUM4_CLEAN_power2round(a->coeffs[i], &a0->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_poly_decompose(poly *a1, poly *a0, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a1->coeffs[i] = PQCLEAN_DILITHIUM4_CLEAN_decompose(a->coeffs[i], &a0->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_poly_make_hint | |||
* | |||
* Description: Compute hint polynomial. The coefficients of which indicate | |||
* whether the low bits of the corresponding coefficient of | |||
* the input polynomial overflow into the high bits. | |||
* | |||
* Arguments: - poly *h: pointer to output hint polynomial | |||
* - const poly *a0: pointer to low part of input polynomial | |||
* - const poly *a1: pointer to high part of input polynomial | |||
* | |||
* Returns number of 1 bits. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM4_CLEAN_poly_make_hint(poly *h, const poly *a0, const poly *a1) { | |||
unsigned int i, s = 0; | |||
for (i = 0; i < N; ++i) { | |||
h->coeffs[i] = PQCLEAN_DILITHIUM4_CLEAN_make_hint(a0->coeffs[i], a1->coeffs[i]); | |||
s += h->coeffs[i]; | |||
} | |||
return s; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_poly_use_hint(poly *a, const poly *b, const poly *h) { | |||
unsigned int i; | |||
for (i = 0; i < N; ++i) { | |||
a->coeffs[i] = PQCLEAN_DILITHIUM4_CLEAN_use_hint(b->coeffs[i], h->coeffs[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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 = (int32_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: rej_uniform | |||
* | |||
* Description: Sample uniformly random coefficients in [0, Q-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_uniform(uint32_t *a, | |||
unsigned int len, | |||
const unsigned char *buf, | |||
unsigned int buflen) { | |||
unsigned int ctr, pos; | |||
uint32_t t; | |||
ctr = pos = 0; | |||
while (ctr < len && pos + 3 <= buflen) { | |||
t = buf[pos++]; | |||
t |= (uint32_t)buf[pos++] << 8; | |||
t |= (uint32_t)buf[pos++] << 16; | |||
t &= 0x7FFFFF; | |||
if (t < Q) { | |||
a[ctr++] = t; | |||
} | |||
} | |||
return ctr; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_poly_uniform | |||
* | |||
* Description: Sample polynomial with uniformly random coefficients | |||
* in [0,Q-1] 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 | |||
* - uint16_t nonce: 2-byte nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_NBLOCKS ((769 + STREAM128_BLOCKBYTES)/STREAM128_BLOCKBYTES) | |||
#define POLY_UNIFORM_BUFLEN (POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_uniform(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int i, ctr, off; | |||
unsigned int buflen = POLY_UNIFORM_BUFLEN; | |||
unsigned char buf[POLY_UNIFORM_BUFLEN + 2]; | |||
shake128ctx state; | |||
stream128_init(&state, seed, nonce); | |||
stream128_squeezeblocks(buf, POLY_UNIFORM_NBLOCKS, &state); | |||
ctr = rej_uniform(a->coeffs, N, buf, buflen); | |||
while (ctr < N) { | |||
off = buflen % 3; | |||
for (i = 0; i < off; ++i) { | |||
buf[i] = buf[buflen - off + i]; | |||
} | |||
buflen = STREAM128_BLOCKBYTES + off; | |||
stream128_squeezeblocks(buf + off, 1, &state); | |||
ctr += rej_uniform(a->coeffs + ctr, N - ctr, buf, buflen); | |||
} | |||
} | |||
/************************************************* | |||
* 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) { | |||
unsigned int ctr, pos; | |||
uint32_t t0, t1; | |||
ctr = pos = 0; | |||
while (ctr < len && pos < buflen) { | |||
t0 = buf[pos] & 0x07; | |||
t1 = buf[pos++] >> 5; | |||
if (t0 <= 2 * ETA) { | |||
a[ctr++] = Q + ETA - t0; | |||
} | |||
if (t1 <= 2 * ETA && ctr < len) { | |||
a[ctr++] = Q + ETA - t1; | |||
} | |||
} | |||
return ctr; | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 | |||
* - uint16_t nonce: 2-byte nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_ETA_NBLOCKS (((N/2 * (1U << SETABITS)) / (2*ETA + 1)\ | |||
+ STREAM128_BLOCKBYTES) / STREAM128_BLOCKBYTES) | |||
#define POLY_UNIFORM_ETA_BUFLEN (POLY_UNIFORM_ETA_NBLOCKS*STREAM128_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_uniform_eta(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int ctr; | |||
unsigned char buf[POLY_UNIFORM_ETA_BUFLEN]; | |||
shake128ctx state; | |||
stream128_init(&state, seed, nonce); | |||
stream128_squeezeblocks(buf, POLY_UNIFORM_ETA_NBLOCKS, &state); | |||
ctr = rej_eta(a->coeffs, N, buf, POLY_UNIFORM_ETA_BUFLEN); | |||
while (ctr < N) { | |||
stream128_squeezeblocks(buf, 1, &state); | |||
ctr += rej_eta(a->coeffs + ctr, N - ctr, buf, STREAM128_BLOCKBYTES); | |||
} | |||
} | |||
/************************************************* | |||
* 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) { | |||
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: PQCLEAN_DILITHIUM4_CLEAN_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 | |||
* CRHBYTES | |||
* - uint16_t nonce: 16-bit nonce | |||
**************************************************/ | |||
#define POLY_UNIFORM_GAMMA1M1_NBLOCKS ((641 + STREAM256_BLOCKBYTES) / STREAM256_BLOCKBYTES) | |||
#define POLY_UNIFORM_GAMMA1M1_BUFLEN (POLY_UNIFORM_GAMMA1M1_NBLOCKS * STREAM256_BLOCKBYTES) | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_uniform_gamma1m1(poly *a, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce) { | |||
unsigned int i, ctr, off; | |||
unsigned int buflen = POLY_UNIFORM_GAMMA1M1_BUFLEN; | |||
unsigned char buf[POLY_UNIFORM_GAMMA1M1_BUFLEN + 4]; | |||
shake256ctx state; | |||
stream256_init(&state, seed, nonce); | |||
stream256_squeezeblocks(buf, POLY_UNIFORM_GAMMA1M1_NBLOCKS, &state); | |||
ctr = rej_gamma1m1(a->coeffs, N, buf, buflen); | |||
while (ctr < N) { | |||
off = buflen % 5; | |||
for (i = 0; i < off; ++i) { | |||
buf[i] = buf[buflen - off + i]; | |||
} | |||
buflen = STREAM256_BLOCKBYTES + off; | |||
stream256_squeezeblocks(buf + off, 1, &state); | |||
ctr += rej_gamma1m1(a->coeffs + ctr, N - ctr, buf, buflen); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyeta_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
unsigned char t[8]; | |||
for (i = 0; i < N / 8; ++i) { | |||
t[0] = (uint8_t) (Q + ETA - a->coeffs[8 * i + 0]); | |||
t[1] = (uint8_t) (Q + ETA - a->coeffs[8 * i + 1]); | |||
t[2] = (uint8_t) (Q + ETA - a->coeffs[8 * i + 2]); | |||
t[3] = (uint8_t) (Q + ETA - a->coeffs[8 * i + 3]); | |||
t[4] = (uint8_t) (Q + ETA - a->coeffs[8 * i + 4]); | |||
t[5] = (uint8_t) (Q + ETA - a->coeffs[8 * i + 5]); | |||
t[6] = (uint8_t) (Q + ETA - a->coeffs[8 * i + 6]); | |||
t[7] = (uint8_t) (Q + ETA - a->coeffs[8 * i + 7]); | |||
r[3 * i + 0] = (uint8_t) ((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)); | |||
r[3 * i + 1] = (uint8_t) ((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)); | |||
r[3 * i + 2] = (uint8_t) ((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyeta_unpack(poly *r, const unsigned char *a) { | |||
unsigned int i; | |||
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] = (uint32_t) ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 0x07; | |||
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] = (uint32_t) ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 0x07; | |||
r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 0x07; | |||
r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 0x07; | |||
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]; | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM4_CLEAN_polyt1_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 8; ++i) { | |||
r[9 * i + 0] = (uint8_t) ((a->coeffs[8 * i + 0] >> 0)); | |||
r[9 * i + 1] = (uint8_t) ((a->coeffs[8 * i + 0] >> 8) | (a->coeffs[8 * i + 1] << 1)); | |||
r[9 * i + 2] = (uint8_t) ((a->coeffs[8 * i + 1] >> 7) | (a->coeffs[8 * i + 2] << 2)); | |||
r[9 * i + 3] = (uint8_t) ((a->coeffs[8 * i + 2] >> 6) | (a->coeffs[8 * i + 3] << 3)); | |||
r[9 * i + 4] = (uint8_t) ((a->coeffs[8 * i + 3] >> 5) | (a->coeffs[8 * i + 4] << 4)); | |||
r[9 * i + 5] = (uint8_t) ((a->coeffs[8 * i + 4] >> 4) | (a->coeffs[8 * i + 5] << 5)); | |||
r[9 * i + 6] = (uint8_t) ((a->coeffs[8 * i + 5] >> 3) | (a->coeffs[8 * i + 6] << 6)); | |||
r[9 * i + 7] = (uint8_t) ((a->coeffs[8 * i + 6] >> 2) | (a->coeffs[8 * i + 7] << 7)); | |||
r[9 * i + 8] = (uint8_t) ((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 PQCLEAN_DILITHIUM4_CLEAN_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] << 8)) & 0x1FF; | |||
r->coeffs[8 * i + 1] = ((a[9 * i + 1] >> 1) | ((uint32_t)a[9 * i + 2] << 7)) & 0x1FF; | |||
r->coeffs[8 * i + 2] = ((a[9 * i + 2] >> 2) | ((uint32_t)a[9 * i + 3] << 6)) & 0x1FF; | |||
r->coeffs[8 * i + 3] = ((a[9 * i + 3] >> 3) | ((uint32_t)a[9 * i + 4] << 5)) & 0x1FF; | |||
r->coeffs[8 * i + 4] = ((a[9 * i + 4] >> 4) | ((uint32_t)a[9 * i + 5] << 4)) & 0x1FF; | |||
r->coeffs[8 * i + 5] = ((a[9 * i + 5] >> 5) | ((uint32_t)a[9 * i + 6] << 3)) & 0x1FF; | |||
r->coeffs[8 * i + 6] = ((a[9 * i + 6] >> 6) | ((uint32_t)a[9 * i + 7] << 2)) & 0x1FF; | |||
r->coeffs[8 * i + 7] = ((a[9 * i + 7] >> 7) | ((uint32_t)a[9 * i + 8] << 1)) & 0x1FF; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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 + (1U << (D - 1)) - a->coeffs[4 * i + 0]; | |||
t[1] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 1]; | |||
t[2] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 2]; | |||
t[3] = Q + (1U << (D - 1)) - a->coeffs[4 * i + 3]; | |||
r[7 * i + 0] = (uint8_t) (t[0]); | |||
r[7 * i + 1] = (uint8_t) (t[0] >> 8); | |||
r[7 * i + 1] |= (uint8_t) (t[1] << 6); | |||
r[7 * i + 2] = (uint8_t) (t[1] >> 2); | |||
r[7 * i + 3] = (uint8_t) (t[1] >> 10); | |||
r[7 * i + 3] |= (uint8_t) (t[2] << 4); | |||
r[7 * i + 4] = (uint8_t) (t[2] >> 4); | |||
r[7 * i + 5] = (uint8_t) (t[2] >> 12); | |||
r[7 * i + 5] |= (uint8_t) (t[3] << 2); | |||
r[7 * i + 6] = (uint8_t) (t[3] >> 6); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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 + (1U << (D - 1)) - r->coeffs[4 * i + 0]; | |||
r->coeffs[4 * i + 1] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 1]; | |||
r->coeffs[4 * i + 2] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 2]; | |||
r->coeffs[4 * i + 3] = Q + (1U << (D - 1)) - r->coeffs[4 * i + 3]; | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyz_pack(unsigned char *r, const poly *a) { | |||
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] = (uint8_t) (t[0]); | |||
r[5 * i + 1] = (uint8_t) (t[0] >> 8); | |||
r[5 * i + 2] = (uint8_t) (t[0] >> 16); | |||
r[5 * i + 2] |= (uint8_t) (t[1] << 4); | |||
r[5 * i + 3] = (uint8_t) (t[1] >> 4); | |||
r[5 * i + 4] = (uint8_t) (t[1] >> 12); | |||
} | |||
} | |||
/************************************************* | |||
* Name: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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: PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyw1_pack(unsigned char *r, const poly *a) { | |||
unsigned int i; | |||
for (i = 0; i < N / 2; ++i) { | |||
r[i] = (uint8_t) (a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)); | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
#ifndef POLY_H | |||
#define POLY_H | |||
#include "params.h" | |||
#include <stdint.h> | |||
typedef struct { | |||
uint32_t coeffs[N]; | |||
} poly; | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_reduce(poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_csubq(poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_freeze(poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_add(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_sub(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_shiftl(poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_ntt(poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_invntt_montgomery(poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_pointwise_invmontgomery(poly *c, const poly *a, const poly *b); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_power2round(poly *a1, poly *a0, const poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_decompose(poly *a1, poly *a0, const poly *a); | |||
unsigned int PQCLEAN_DILITHIUM4_CLEAN_poly_make_hint(poly *h, const poly *a0, const poly *a1); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_use_hint(poly *a, const poly *b, const poly *h); | |||
int PQCLEAN_DILITHIUM4_CLEAN_poly_chknorm(const poly *a, uint32_t B); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_uniform(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_uniform_eta(poly *a, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM4_CLEAN_poly_uniform_gamma1m1(poly *a, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyeta_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyeta_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyt1_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyt1_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyt0_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyt0_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyz_pack(unsigned char *r, const poly *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyz_unpack(poly *r, const unsigned char *a); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyw1_pack(unsigned char *r, const poly *a); | |||
#endif |
@@ -0,0 +1,357 @@ | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.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 PQCLEAN_DILITHIUM4_CLEAN_polyvecl_freeze(polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyvecl_ntt(polyvecl *v) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyvecl_pointwise_acc_invmontgomery(poly *w, | |||
const polyvecl *u, | |||
const polyvecl *v) { | |||
unsigned int i; | |||
poly t; | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_pointwise_invmontgomery(w, &u->vec[0], &v->vec[0]); | |||
for (i = 1; i < L; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_pointwise_invmontgomery(&t, &u->vec[i], &v->vec[i]); | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyvecl_chknorm(const polyvecl *v, uint32_t bound) { | |||
unsigned int i; | |||
for (i = 0; i < L; ++i) { | |||
if (PQCLEAN_DILITHIUM4_CLEAN_poly_chknorm(&v->vec[i], bound)) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
/**************************************************************/ | |||
/************ 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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_reduce(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_csubq(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_freeze(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_add(polyveck *w, const polyveck *u, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_sub(&w->vec[i], &u->vec[i], &v->vec[i]); | |||
} | |||
} | |||
/************************************************* | |||
* Name: polyveck_shiftl | |||
* | |||
* Description: Multiply vector of polynomials of Length K by 2^D without modular | |||
* reduction. Assumes input coefficients to be less than 2^{32-D}. | |||
* | |||
* Arguments: - polyveck *v: pointer to input/output vector | |||
**************************************************/ | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_shiftl(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_shiftl(&v->vec[i]); | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_ntt(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_invntt_montgomery(polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_chknorm(const polyveck *v, uint32_t bound) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
if (PQCLEAN_DILITHIUM4_CLEAN_poly_chknorm(&v->vec[i], bound)) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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 *v0: pointer to low part of input vector | |||
* - const polyveck *v1: pointer to high part of input vector | |||
* | |||
* Returns number of 1 bits. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM4_CLEAN_polyveck_make_hint(polyveck *h, | |||
const polyveck *v0, | |||
const polyveck *v1) { | |||
unsigned int i, s = 0; | |||
for (i = 0; i < K; ++i) { | |||
s += PQCLEAN_DILITHIUM4_CLEAN_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->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 PQCLEAN_DILITHIUM4_CLEAN_polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h) { | |||
unsigned int i; | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
#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 PQCLEAN_DILITHIUM4_CLEAN_polyvecl_freeze(polyvecl *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyvecl_ntt(polyvecl *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyvecl_pointwise_acc_invmontgomery(poly *w, | |||
const polyvecl *u, | |||
const polyvecl *v); | |||
int PQCLEAN_DILITHIUM4_CLEAN_polyvecl_chknorm(const polyvecl *v, uint32_t B); | |||
/* Vectors of polynomials of length K */ | |||
typedef struct { | |||
poly vec[K]; | |||
} polyveck; | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_reduce(polyveck *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_csubq(polyveck *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_freeze(polyveck *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_add(polyveck *w, const polyveck *u, const polyveck *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_shiftl(polyveck *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_ntt(polyveck *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_invntt_montgomery(polyveck *v); | |||
int PQCLEAN_DILITHIUM4_CLEAN_polyveck_chknorm(const polyveck *v, uint32_t B); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v); | |||
unsigned int PQCLEAN_DILITHIUM4_CLEAN_polyveck_make_hint(polyveck *h, | |||
const polyveck *v0, | |||
const polyveck *v1); | |||
void PQCLEAN_DILITHIUM4_CLEAN_polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h); | |||
#endif |
@@ -0,0 +1,74 @@ | |||
#include "params.h" | |||
#include "reduce.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 PQCLEAN_DILITHIUM4_CLEAN_montgomery_reduce(uint64_t a) { | |||
uint64_t t; | |||
t = a * QINV; | |||
t &= (1ULL << 32) - 1; | |||
t *= Q; | |||
t = a + t; | |||
t >>= 32; | |||
return (uint32_t) 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 PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_freeze(uint32_t a) { | |||
a = PQCLEAN_DILITHIUM4_CLEAN_reduce32(a); | |||
a = PQCLEAN_DILITHIUM4_CLEAN_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 PQCLEAN_DILITHIUM4_CLEAN_montgomery_reduce(uint64_t a); | |||
/* r < 2*Q */ | |||
uint32_t PQCLEAN_DILITHIUM4_CLEAN_reduce32(uint32_t a); | |||
/* a < 2*Q => r < Q */ | |||
uint32_t PQCLEAN_DILITHIUM4_CLEAN_csubq(uint32_t a); | |||
/* r < Q */ | |||
uint32_t PQCLEAN_DILITHIUM4_CLEAN_freeze(uint32_t a); | |||
#endif |
@@ -0,0 +1,105 @@ | |||
#include "params.h" | |||
#include "rounding.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 PQCLEAN_DILITHIUM4_CLEAN_power2round(uint32_t a, uint32_t *a0) { | |||
uint32_t t; | |||
/* Centralized remainder mod 2^D */ | |||
t = a & ((1U << D) - 1); | |||
t -= ((1U << (D - 1)) + 1); | |||
t += ((uint32_t)((int32_t)t >> 31) & (1U << D)); | |||
t -= ((1U << (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 PQCLEAN_DILITHIUM4_CLEAN_decompose(uint32_t a, uint32_t *a0) { | |||
int32_t t, u; | |||
/* Centralized remainder mod ALPHA */ | |||
t = a & 0x7FFFF; | |||
t += (int32_t) ((a >> 19) << 9); | |||
t -= ALPHA / 2 + 1; | |||
t += (t >> 31) & ALPHA; | |||
t -= ALPHA / 2 - 1; | |||
a -= (uint32_t) t; | |||
/* Divide by ALPHA (possible to avoid) */ | |||
u = (int32_t) a - 1; | |||
u >>= 31; | |||
a = (a >> 19) + 1; | |||
a -= u & 1; | |||
/* Border case */ | |||
*a0 = Q + (uint32_t)t - (a >> 4); | |||
a &= 0xF; | |||
return a; | |||
} | |||
/************************************************* | |||
* Name: make_hint | |||
* | |||
* Description: Compute hint bit indicating whether the low bits of the | |||
* input element overflow into the high bits. Inputs assumed to be | |||
* standard representatives. | |||
* | |||
* Arguments: - uint32_t a0: low bits of input element | |||
* - uint32_t a1: high bits of input element | |||
* | |||
* Returns 1 if high bits of a and b differ and 0 otherwise. | |||
**************************************************/ | |||
unsigned int PQCLEAN_DILITHIUM4_CLEAN_make_hint(uint32_t a0, uint32_t a1) { | |||
if (a0 <= GAMMA2 || a0 > Q - GAMMA2 || (a0 == Q - GAMMA2 && a1 == 0)) { | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM4_CLEAN_use_hint(uint32_t a, unsigned int hint) { | |||
uint32_t a0, a1; | |||
a1 = PQCLEAN_DILITHIUM4_CLEAN_decompose(a, &a0); | |||
if (hint == 0) { | |||
return a1; | |||
} | |||
if (a0 > Q) { | |||
return (a1 + 1) & 0xF; | |||
} | |||
return (a1 - 1) & 0xF; | |||
} |
@@ -0,0 +1,11 @@ | |||
#ifndef ROUNDING_H | |||
#define ROUNDING_H | |||
#include <stdint.h> | |||
uint32_t PQCLEAN_DILITHIUM4_CLEAN_power2round(uint32_t a, uint32_t *a0); | |||
uint32_t PQCLEAN_DILITHIUM4_CLEAN_decompose(uint32_t a, uint32_t *a0); | |||
unsigned int PQCLEAN_DILITHIUM4_CLEAN_make_hint(uint32_t a0, uint32_t a1); | |||
uint32_t PQCLEAN_DILITHIUM4_CLEAN_use_hint(uint32_t a, unsigned int hint); | |||
#endif |
@@ -0,0 +1,414 @@ | |||
#include "fips202.h" | |||
#include "packing.h" | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
#include "randombytes.h" | |||
#include "sign.h" | |||
#include "symmetric.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 PQCLEAN_DILITHIUM4_CLEAN_expand_mat(polyvecl mat[K], const unsigned char rho[SEEDBYTES]) { | |||
unsigned int i, j; | |||
for (i = 0; i < K; ++i) { | |||
for (j = 0; j < L; ++j) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_uniform(&mat[i].vec[j], rho, (uint16_t)((i << 8) + j)); | |||
} | |||
} | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM4_CLEAN_challenge(poly *c, | |||
const unsigned char mu[CRHBYTES], | |||
const polyveck *w1) { | |||
unsigned int i, b, pos; | |||
uint64_t signs; | |||
unsigned char inbuf[CRHBYTES + K * POLW1_SIZE_PACKED]; | |||
unsigned char outbuf[SHAKE256_RATE]; | |||
shake256ctx state; | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
inbuf[i] = mu[i]; | |||
} | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_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; | |||
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] = 1; | |||
c->coeffs[b] ^= -((int32_t)signs & 1) & (1 ^ (Q - 1)); | |||
signs >>= 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 PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { | |||
unsigned int i; | |||
unsigned char seedbuf[3 * SEEDBYTES]; | |||
unsigned char tr[CRHBYTES]; | |||
const 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, 3 * SEEDBYTES); | |||
rho = seedbuf; | |||
rhoprime = seedbuf + SEEDBYTES; | |||
key = seedbuf + 2 * SEEDBYTES; | |||
/* Expand matrix */ | |||
PQCLEAN_DILITHIUM4_CLEAN_expand_mat(mat, rho); | |||
/* Sample short vectors s1 and s2 */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_uniform_eta(&s1.vec[i], rhoprime, nonce++); | |||
} | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_uniform_eta(&s2.vec[i], rhoprime, nonce++); | |||
} | |||
/* Matrix-vector multiplication */ | |||
s1hat = s1; | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_ntt(&s1hat); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_pointwise_acc_invmontgomery(&t.vec[i], &mat[i], &s1hat); | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_reduce(&t.vec[i]); | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_invntt_montgomery(&t.vec[i]); | |||
} | |||
/* Add error vector s2 */ | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_add(&t, &t, &s2); | |||
/* Extract t1 and write public key */ | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_freeze(&t); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_power2round(&t1, &t0, &t); | |||
PQCLEAN_DILITHIUM4_CLEAN_pack_pk(pk, rho, &t1); | |||
/* Compute CRH(rho, t1) and write secret key */ | |||
crh(tr, pk, CRYPTO_PUBLICKEYBYTES); | |||
PQCLEAN_DILITHIUM4_CLEAN_pack_sk(sk, rho, key, tr, &s1, &s2, &t0); | |||
return 0; | |||
} | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk) { | |||
unsigned long long i; | |||
unsigned int n; | |||
unsigned char seedbuf[2 * SEEDBYTES + 3 * CRHBYTES]; | |||
unsigned char *rho, *tr, *key, *mu, *rhoprime; | |||
uint16_t nonce = 0; | |||
poly c, chat; | |||
polyvecl mat[K], s1, y, yhat, z; | |||
polyveck t0, s2, w, w1, w0; | |||
polyveck h, cs2, ct0; | |||
rho = seedbuf; | |||
tr = rho + SEEDBYTES; | |||
key = tr + CRHBYTES; | |||
mu = key + SEEDBYTES; | |||
rhoprime = mu + CRHBYTES; | |||
PQCLEAN_DILITHIUM4_CLEAN_unpack_sk(rho, key, tr, &s1, &s2, &t0, sk); | |||
// use incremental hash API instead of copying around buffers | |||
/* Compute CRH(tr, msg) */ | |||
shake256incctx state; | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, tr, CRHBYTES); | |||
shake256_inc_absorb(&state, m, mlen); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
sig[CRYPTO_BYTES - CRHBYTES + i] = tr[i]; | |||
} | |||
crh(rhoprime, key, SEEDBYTES + CRHBYTES); | |||
/* Expand matrix and transform vectors */ | |||
PQCLEAN_DILITHIUM4_CLEAN_expand_mat(mat, rho); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_ntt(&s1); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_ntt(&s2); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_ntt(&t0); | |||
rej: | |||
/* Sample intermediate vector y */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_uniform_gamma1m1(&y.vec[i], rhoprime, nonce++); | |||
} | |||
/* Matrix-vector multiplication */ | |||
yhat = y; | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_ntt(&yhat); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_pointwise_acc_invmontgomery(&w.vec[i], &mat[i], &yhat); | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_reduce(&w.vec[i]); | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_invntt_montgomery(&w.vec[i]); | |||
} | |||
/* Decompose w and call the random oracle */ | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_csubq(&w); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_decompose(&w1, &w0, &w); | |||
PQCLEAN_DILITHIUM4_CLEAN_challenge(&c, mu, &w1); | |||
chat = c; | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_ntt(&chat); | |||
/* Check that subtracting cs2 does not change high bits of w and low bits | |||
* do not reveal secret information */ | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_pointwise_invmontgomery(&cs2.vec[i], &chat, &s2.vec[i]); | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_invntt_montgomery(&cs2.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_sub(&w0, &w0, &cs2); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_freeze(&w0); | |||
if (PQCLEAN_DILITHIUM4_CLEAN_polyveck_chknorm(&w0, GAMMA2 - BETA)) { | |||
goto rej; | |||
} | |||
/* Compute z, reject if it reveals secret */ | |||
for (i = 0; i < L; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_pointwise_invmontgomery(&z.vec[i], &chat, &s1.vec[i]); | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_invntt_montgomery(&z.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_add(&z, &z, &y); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_freeze(&z); | |||
if (PQCLEAN_DILITHIUM4_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) { | |||
goto rej; | |||
} | |||
/* Compute hints for w1 */ | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_pointwise_invmontgomery(&ct0.vec[i], &chat, &t0.vec[i]); | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_invntt_montgomery(&ct0.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_csubq(&ct0); | |||
if (PQCLEAN_DILITHIUM4_CLEAN_polyveck_chknorm(&ct0, GAMMA2)) { | |||
goto rej; | |||
} | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_add(&w0, &w0, &ct0); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_csubq(&w0); | |||
n = PQCLEAN_DILITHIUM4_CLEAN_polyveck_make_hint(&h, &w0, &w1); | |||
if (n > OMEGA) { | |||
goto rej; | |||
} | |||
/* Write signature */ | |||
PQCLEAN_DILITHIUM4_CLEAN_pack_sig(sig, &z, &h, &c); | |||
*siglen = CRYPTO_BYTES; | |||
return 0; | |||
} | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *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 (siglen < CRYPTO_BYTES) { | |||
return -1; | |||
} | |||
PQCLEAN_DILITHIUM4_CLEAN_unpack_pk(rho, &t1, pk); | |||
if (PQCLEAN_DILITHIUM4_CLEAN_unpack_sig(&z, &h, &c, sig)) { | |||
return -1; | |||
} | |||
if (PQCLEAN_DILITHIUM4_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) { | |||
return -1; | |||
} | |||
/* Compute CRH(CRH(rho, t1), msg) */ | |||
shake256incctx state; | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, pk, CRYPTO_PUBLICKEYBYTES); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
shake256_inc_init(&state); | |||
shake256_inc_absorb(&state, mu, CRHBYTES); | |||
shake256_inc_absorb(&state, m, mlen); | |||
shake256_inc_finalize(&state); | |||
shake256_inc_squeeze(mu, CRHBYTES, &state); | |||
/* Matrix-vector multiplication; compute Az - c2^dt1 */ | |||
PQCLEAN_DILITHIUM4_CLEAN_expand_mat(mat, rho); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_ntt(&z); | |||
for (i = 0; i < K ; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_polyvecl_pointwise_acc_invmontgomery(&tmp1.vec[i], &mat[i], &z); | |||
} | |||
chat = c; | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_ntt(&chat); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_shiftl(&t1); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_ntt(&t1); | |||
for (i = 0; i < K; ++i) { | |||
PQCLEAN_DILITHIUM4_CLEAN_poly_pointwise_invmontgomery(&tmp2.vec[i], &chat, &t1.vec[i]); | |||
} | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_sub(&tmp1, &tmp1, &tmp2); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_reduce(&tmp1); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_invntt_montgomery(&tmp1); | |||
/* Reconstruct w1 */ | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_csubq(&tmp1); | |||
PQCLEAN_DILITHIUM4_CLEAN_polyveck_use_hint(&w1, &tmp1, &h); | |||
/* Call random oracle and verify challenge */ | |||
PQCLEAN_DILITHIUM4_CLEAN_challenge(&cp, mu, &w1); | |||
for (i = 0; i < N; ++i) { | |||
if (c.coeffs[i] != cp.coeffs[i]) { | |||
return -1; | |||
} | |||
} | |||
// All good | |||
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 PQCLEAN_DILITHIUM4_CLEAN_crypto_sign(uint8_t *sm, | |||
size_t *smlen, | |||
const uint8_t *m, | |||
size_t mlen, | |||
const uint8_t *sk) { | |||
size_t i; | |||
int rc; | |||
for (i = 0; i < mlen; i++) { | |||
sm[CRYPTO_BYTES + i] = m[i]; | |||
} | |||
rc = PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_signature(sm, smlen, m, mlen, sk); | |||
*smlen += mlen; | |||
return rc; | |||
} | |||
/************************************************* | |||
* 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 PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_open(uint8_t *m, | |||
size_t *mlen, | |||
const uint8_t *sm, | |||
size_t smlen, | |||
const uint8_t *pk) { | |||
size_t i; | |||
if (smlen < CRYPTO_BYTES) { | |||
goto badsig; | |||
} | |||
*mlen = smlen - CRYPTO_BYTES; | |||
if (PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_verify(sm, CRYPTO_BYTES, | |||
sm + CRYPTO_BYTES, *mlen, pk)) { | |||
goto badsig; | |||
} else { | |||
/* 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 = (size_t) -1; | |||
for (i = 0; i < smlen; ++i) { | |||
m[i] = 0; | |||
} | |||
return -1; | |||
} | |||
@@ -0,0 +1,30 @@ | |||
#ifndef SIGN_H | |||
#define SIGN_H | |||
#include "params.h" | |||
#include "poly.h" | |||
#include "polyvec.h" | |||
void PQCLEAN_DILITHIUM4_CLEAN_expand_mat(polyvecl mat[K], const unsigned char rho[SEEDBYTES]); | |||
void PQCLEAN_DILITHIUM4_CLEAN_challenge(poly *c, const unsigned char mu[CRHBYTES], | |||
const polyveck *w1); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_signature( | |||
uint8_t *sig, size_t *siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_verify( | |||
const uint8_t *sig, size_t siglen, | |||
const uint8_t *m, size_t mlen, const uint8_t *pk); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen, | |||
const uint8_t *msg, size_t len, | |||
const uint8_t *sk); | |||
int PQCLEAN_DILITHIUM4_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen, | |||
const uint8_t *sm, size_t smlen, | |||
const uint8_t *pk); | |||
#endif |
@@ -0,0 +1,32 @@ | |||
#include "symmetric.h" | |||
#include "fips202.h" | |||
void PQCLEAN_DILITHIUM4_CLEAN_shake128_stream_init(shake128ctx *state, | |||
const unsigned char seed[SEEDBYTES], | |||
uint16_t nonce) { | |||
unsigned int i; | |||
unsigned char buf[SEEDBYTES + 2]; | |||
for (i = 0; i < SEEDBYTES; ++i) { | |||
buf[i] = seed[i]; | |||
} | |||
buf[SEEDBYTES] = (uint8_t) nonce; | |||
buf[SEEDBYTES + 1] = (uint8_t) (nonce >> 8); | |||
shake128_absorb(state, buf, sizeof(buf)); | |||
} | |||
void PQCLEAN_DILITHIUM4_CLEAN_shake256_stream_init(shake256ctx *state, | |||
const unsigned char seed[CRHBYTES], | |||
uint16_t nonce) { | |||
unsigned int i; | |||
unsigned char buf[CRHBYTES + 2]; | |||
for (i = 0; i < CRHBYTES; ++i) { | |||
buf[i] = seed[i]; | |||
} | |||
buf[CRHBYTES] = (uint8_t) nonce; | |||
buf[CRHBYTES + 1] = (uint8_t) (nonce >> 8); | |||
shake256_absorb(state, buf, sizeof(buf)); | |||
} |
@@ -0,0 +1,23 @@ | |||
#ifndef SYMMETRIC_H | |||
#define SYMMETRIC_H | |||
#include "fips202.h" | |||
#include "params.h" | |||
#define crh(OUT, IN, INBYTES) shake256(OUT, CRHBYTES, IN, INBYTES) | |||
#define stream128_init(STATE, SEED, NONCE) PQCLEAN_DILITHIUM4_CLEAN_shake128_stream_init(STATE, SEED, NONCE) | |||
#define stream128_squeezeblocks(OUT, OUTBLOCKS, STATE) shake128_squeezeblocks(OUT, OUTBLOCKS, STATE) | |||
#define stream256_init(STATE, SEED, NONCE) PQCLEAN_DILITHIUM4_CLEAN_shake256_stream_init(STATE, SEED, NONCE) | |||
#define stream256_squeezeblocks(OUT, OUTBLOCKS, STATE) shake256_squeezeblocks(OUT, OUTBLOCKS, STATE) | |||
#define STREAM128_BLOCKBYTES SHAKE128_RATE | |||
#define STREAM256_BLOCKBYTES SHAKE256_RATE | |||
void PQCLEAN_DILITHIUM4_CLEAN_shake128_stream_init(shake128ctx *state, | |||
const unsigned char *seed, | |||
uint16_t nonce); | |||
void PQCLEAN_DILITHIUM4_CLEAN_shake256_stream_init(shake256ctx *state, | |||
const unsigned char *seed, | |||
uint16_t nonce); | |||
#endif |
@@ -0,0 +1,40 @@ | |||
consistency_checks: | |||
- source: | |||
scheme: dilithium3 | |||
implementation: clean | |||
files: | |||
- ntt.c | |||
- ntt.h | |||
- packing.c | |||
- packing.h | |||
- poly.c | |||
- poly.h | |||
- polyvec.c | |||
- polyvec.h | |||
- reduce.c | |||
- reduce.h | |||
- rounding.c | |||
- rounding.h | |||
- sign.c | |||
- sign.h | |||
- symmetric.c | |||
- symmetric.h | |||
- source: | |||
scheme: dilithium4 | |||
implementation: clean | |||
files: | |||
- ntt.c | |||
- ntt.h | |||
- packing.c | |||
- packing.h | |||
- poly.h | |||
- polyvec.c | |||
- polyvec.h | |||
- reduce.c | |||
- reduce.h | |||
- rounding.c | |||
- rounding.h | |||
- sign.c | |||
- sign.h | |||
- symmetric.c | |||
- symmetric.h |
@@ -0,0 +1,40 @@ | |||
consistency_checks: | |||
- source: | |||
scheme: dilithium2 | |||
implementation: clean | |||
files: | |||
- ntt.c | |||
- ntt.h | |||
- packing.c | |||
- packing.h | |||
- poly.c | |||
- poly.h | |||
- polyvec.c | |||
- polyvec.h | |||
- reduce.c | |||
- reduce.h | |||
- rounding.c | |||
- rounding.h | |||
- sign.c | |||
- sign.h | |||
- symmetric.c | |||
- symmetric.h | |||
- source: | |||
scheme: dilithium4 | |||
implementation: clean | |||
files: | |||
- ntt.c | |||
- ntt.h | |||
- packing.c | |||
- packing.h | |||
- poly.h | |||
- polyvec.c | |||
- polyvec.h | |||
- reduce.c | |||
- reduce.h | |||
- rounding.c | |||
- rounding.h | |||
- sign.c | |||
- sign.h | |||
- symmetric.c | |||
- symmetric.h |
@@ -0,0 +1,39 @@ | |||
consistency_checks: | |||
- source: | |||
scheme: dilithium2 | |||
implementation: clean | |||
files: | |||
- ntt.c | |||
- ntt.h | |||
- packing.c | |||
- packing.h | |||
- poly.h | |||
- polyvec.c | |||
- polyvec.h | |||
- reduce.c | |||
- reduce.h | |||
- rounding.c | |||
- rounding.h | |||
- sign.c | |||
- sign.h | |||
- symmetric.c | |||
- symmetric.h | |||
- source: | |||
scheme: dilithium3 | |||
implementation: clean | |||
files: | |||
- ntt.c | |||
- ntt.h | |||
- packing.c | |||
- packing.h | |||
- poly.h | |||
- polyvec.c | |||
- polyvec.h | |||
- reduce.c | |||
- reduce.h | |||
- rounding.c | |||
- rounding.h | |||
- sign.c | |||
- sign.h | |||
- symmetric.c | |||
- symmetric.h |
@@ -28,7 +28,7 @@ def check_dynamic_memory(implementation, function): | |||
lines = out.strip().split("\n") | |||
for line in lines: | |||
if 'U {}'.format(function) in line: | |||
if line.endswith('U {}'.format(function)): | |||
raise AssertionError( | |||
"Illegal use of dynamic memory function '{}'".format(function)) | |||