diff --git a/crypto_sign/dilithium2/META.yml b/crypto_sign/dilithium2/META.yml new file mode 100644 index 00000000..68c8bf3d --- /dev/null +++ b/crypto_sign/dilithium2/META.yml @@ -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 diff --git a/crypto_sign/dilithium2/clean/LICENSE b/crypto_sign/dilithium2/clean/LICENSE new file mode 100644 index 00000000..0299dbff --- /dev/null +++ b/crypto_sign/dilithium2/clean/LICENSE @@ -0,0 +1,2 @@ +Public Domain +Authors: Léo Ducas, Eike Kiltz, Tancrède Lepoint, Vadim Lyubashevsky, Gregor Seiler, Peter Schwabe, Damien Stehlé diff --git a/crypto_sign/dilithium2/clean/Makefile b/crypto_sign/dilithium2/clean/Makefile new file mode 100644 index 00000000..61c55b73 --- /dev/null +++ b/crypto_sign/dilithium2/clean/Makefile @@ -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) diff --git a/crypto_sign/dilithium2/clean/Makefile.Microsoft_nmake b/crypto_sign/dilithium2/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..cb972a38 --- /dev/null +++ b/crypto_sign/dilithium2/clean/Makefile.Microsoft_nmake @@ -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) diff --git a/crypto_sign/dilithium2/clean/api.h b/crypto_sign/dilithium2/clean/api.h new file mode 100644 index 00000000..176824a1 --- /dev/null +++ b/crypto_sign/dilithium2/clean/api.h @@ -0,0 +1,32 @@ +#ifndef PQCLEAN_DILITHIUM2_CLEAN_API_H +#define PQCLEAN_DILITHIUM2_CLEAN_API_H + +#include + +#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 diff --git a/crypto_sign/dilithium2/clean/ntt.c b/crypto_sign/dilithium2/clean/ntt.c new file mode 100644 index 00000000..45a9e98e --- /dev/null +++ b/crypto_sign/dilithium2/clean/ntt.c @@ -0,0 +1,137 @@ +#include "ntt.h" +#include "params.h" +#include "poly.h" +#include "reduce.h" +#include + +/* 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]); + } +} diff --git a/crypto_sign/dilithium2/clean/ntt.h b/crypto_sign/dilithium2/clean/ntt.h new file mode 100644 index 00000000..5ba0fcac --- /dev/null +++ b/crypto_sign/dilithium2/clean/ntt.h @@ -0,0 +1,10 @@ +#ifndef NTT_H +#define NTT_H + +#include "params.h" +#include + +void PQCLEAN_DILITHIUM2_CLEAN_ntt(uint32_t p[N]); +void PQCLEAN_DILITHIUM2_CLEAN_invntt_frominvmont(uint32_t p[N]); + +#endif diff --git a/crypto_sign/dilithium2/clean/packing.c b/crypto_sign/dilithium2/clean/packing.c new file mode 100644 index 00000000..31c5ce9a --- /dev/null +++ b/crypto_sign/dilithium2/clean/packing.c @@ -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; +} diff --git a/crypto_sign/dilithium2/clean/packing.h b/crypto_sign/dilithium2/clean/packing.h new file mode 100644 index 00000000..3937b634 --- /dev/null +++ b/crypto_sign/dilithium2/clean/packing.h @@ -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 diff --git a/crypto_sign/dilithium2/clean/params.h b/crypto_sign/dilithium2/clean/params.h new file mode 100644 index 00000000..ab615ec7 --- /dev/null +++ b/crypto_sign/dilithium2/clean/params.h @@ -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 diff --git a/crypto_sign/dilithium2/clean/poly.c b/crypto_sign/dilithium2/clean/poly.c new file mode 100644 index 00000000..9a0d19ff --- /dev/null +++ b/crypto_sign/dilithium2/clean/poly.c @@ -0,0 +1,737 @@ +#include "ntt.h" +#include "params.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" +#include + + +/************************************************* +* 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)); + } + +} diff --git a/crypto_sign/dilithium2/clean/poly.h b/crypto_sign/dilithium2/clean/poly.h new file mode 100644 index 00000000..434f8ebb --- /dev/null +++ b/crypto_sign/dilithium2/clean/poly.h @@ -0,0 +1,53 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" +#include + +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 diff --git a/crypto_sign/dilithium2/clean/polyvec.c b/crypto_sign/dilithium2/clean/polyvec.c new file mode 100644 index 00000000..47c612ac --- /dev/null +++ b/crypto_sign/dilithium2/clean/polyvec.c @@ -0,0 +1,357 @@ +#include "params.h" +#include "poly.h" +#include "polyvec.h" +#include + +/**************************************************************/ +/************ 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]); + } +} diff --git a/crypto_sign/dilithium2/clean/polyvec.h b/crypto_sign/dilithium2/clean/polyvec.h new file mode 100644 index 00000000..814043fc --- /dev/null +++ b/crypto_sign/dilithium2/clean/polyvec.h @@ -0,0 +1,51 @@ +#ifndef POLYVEC_H +#define POLYVEC_H + +#include "params.h" +#include "poly.h" +#include + +/* 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 diff --git a/crypto_sign/dilithium2/clean/reduce.c b/crypto_sign/dilithium2/clean/reduce.c new file mode 100644 index 00000000..8b07c59e --- /dev/null +++ b/crypto_sign/dilithium2/clean/reduce.c @@ -0,0 +1,74 @@ +#include "params.h" +#include "reduce.h" +#include + +/************************************************* +* 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; +} diff --git a/crypto_sign/dilithium2/clean/reduce.h b/crypto_sign/dilithium2/clean/reduce.h new file mode 100644 index 00000000..91ba25b2 --- /dev/null +++ b/crypto_sign/dilithium2/clean/reduce.h @@ -0,0 +1,21 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +#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 diff --git a/crypto_sign/dilithium2/clean/rounding.c b/crypto_sign/dilithium2/clean/rounding.c new file mode 100644 index 00000000..126719e2 --- /dev/null +++ b/crypto_sign/dilithium2/clean/rounding.c @@ -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; +} diff --git a/crypto_sign/dilithium2/clean/rounding.h b/crypto_sign/dilithium2/clean/rounding.h new file mode 100644 index 00000000..94773a3b --- /dev/null +++ b/crypto_sign/dilithium2/clean/rounding.h @@ -0,0 +1,11 @@ +#ifndef ROUNDING_H +#define ROUNDING_H + +#include + +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 diff --git a/crypto_sign/dilithium2/clean/sign.c b/crypto_sign/dilithium2/clean/sign.c new file mode 100644 index 00000000..7d643f94 --- /dev/null +++ b/crypto_sign/dilithium2/clean/sign.c @@ -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 + +/************************************************* +* 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; +} + diff --git a/crypto_sign/dilithium2/clean/sign.h b/crypto_sign/dilithium2/clean/sign.h new file mode 100644 index 00000000..0d909396 --- /dev/null +++ b/crypto_sign/dilithium2/clean/sign.h @@ -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 diff --git a/crypto_sign/dilithium2/clean/symmetric.c b/crypto_sign/dilithium2/clean/symmetric.c new file mode 100644 index 00000000..3618b057 --- /dev/null +++ b/crypto_sign/dilithium2/clean/symmetric.c @@ -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)); +} diff --git a/crypto_sign/dilithium2/clean/symmetric.h b/crypto_sign/dilithium2/clean/symmetric.h new file mode 100644 index 00000000..c26cc354 --- /dev/null +++ b/crypto_sign/dilithium2/clean/symmetric.h @@ -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 diff --git a/crypto_sign/dilithium3/META.yml b/crypto_sign/dilithium3/META.yml new file mode 100644 index 00000000..06ee40fe --- /dev/null +++ b/crypto_sign/dilithium3/META.yml @@ -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 diff --git a/crypto_sign/dilithium3/clean/LICENSE b/crypto_sign/dilithium3/clean/LICENSE new file mode 100644 index 00000000..0299dbff --- /dev/null +++ b/crypto_sign/dilithium3/clean/LICENSE @@ -0,0 +1,2 @@ +Public Domain +Authors: Léo Ducas, Eike Kiltz, Tancrède Lepoint, Vadim Lyubashevsky, Gregor Seiler, Peter Schwabe, Damien Stehlé diff --git a/crypto_sign/dilithium3/clean/Makefile b/crypto_sign/dilithium3/clean/Makefile new file mode 100644 index 00000000..452ef92e --- /dev/null +++ b/crypto_sign/dilithium3/clean/Makefile @@ -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) diff --git a/crypto_sign/dilithium3/clean/Makefile.Microsoft_nmake b/crypto_sign/dilithium3/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..9c660a82 --- /dev/null +++ b/crypto_sign/dilithium3/clean/Makefile.Microsoft_nmake @@ -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) diff --git a/crypto_sign/dilithium3/clean/api.h b/crypto_sign/dilithium3/clean/api.h new file mode 100644 index 00000000..2af3c081 --- /dev/null +++ b/crypto_sign/dilithium3/clean/api.h @@ -0,0 +1,32 @@ +#ifndef PQCLEAN_DILITHIUM3_CLEAN_API_H +#define PQCLEAN_DILITHIUM3_CLEAN_API_H + +#include + + +#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 diff --git a/crypto_sign/dilithium3/clean/ntt.c b/crypto_sign/dilithium3/clean/ntt.c new file mode 100644 index 00000000..95bdd46c --- /dev/null +++ b/crypto_sign/dilithium3/clean/ntt.c @@ -0,0 +1,137 @@ +#include "ntt.h" +#include "params.h" +#include "poly.h" +#include "reduce.h" +#include + +/* 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]); + } +} diff --git a/crypto_sign/dilithium3/clean/ntt.h b/crypto_sign/dilithium3/clean/ntt.h new file mode 100644 index 00000000..8ab80e45 --- /dev/null +++ b/crypto_sign/dilithium3/clean/ntt.h @@ -0,0 +1,10 @@ +#ifndef NTT_H +#define NTT_H + +#include "params.h" +#include + +void PQCLEAN_DILITHIUM3_CLEAN_ntt(uint32_t p[N]); +void PQCLEAN_DILITHIUM3_CLEAN_invntt_frominvmont(uint32_t p[N]); + +#endif diff --git a/crypto_sign/dilithium3/clean/packing.c b/crypto_sign/dilithium3/clean/packing.c new file mode 100644 index 00000000..f52bb072 --- /dev/null +++ b/crypto_sign/dilithium3/clean/packing.c @@ -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; +} diff --git a/crypto_sign/dilithium3/clean/packing.h b/crypto_sign/dilithium3/clean/packing.h new file mode 100644 index 00000000..ef1634c0 --- /dev/null +++ b/crypto_sign/dilithium3/clean/packing.h @@ -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 diff --git a/crypto_sign/dilithium3/clean/params.h b/crypto_sign/dilithium3/clean/params.h new file mode 100644 index 00000000..edae8066 --- /dev/null +++ b/crypto_sign/dilithium3/clean/params.h @@ -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 diff --git a/crypto_sign/dilithium3/clean/poly.c b/crypto_sign/dilithium3/clean/poly.c new file mode 100644 index 00000000..2b9ff9a1 --- /dev/null +++ b/crypto_sign/dilithium3/clean/poly.c @@ -0,0 +1,737 @@ +#include "ntt.h" +#include "params.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" +#include + + +/************************************************* +* 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)); + } + +} diff --git a/crypto_sign/dilithium3/clean/poly.h b/crypto_sign/dilithium3/clean/poly.h new file mode 100644 index 00000000..ce1aa8ce --- /dev/null +++ b/crypto_sign/dilithium3/clean/poly.h @@ -0,0 +1,53 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" +#include + +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 diff --git a/crypto_sign/dilithium3/clean/polyvec.c b/crypto_sign/dilithium3/clean/polyvec.c new file mode 100644 index 00000000..6850032e --- /dev/null +++ b/crypto_sign/dilithium3/clean/polyvec.c @@ -0,0 +1,357 @@ +#include "params.h" +#include "poly.h" +#include "polyvec.h" +#include + +/**************************************************************/ +/************ 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]); + } +} diff --git a/crypto_sign/dilithium3/clean/polyvec.h b/crypto_sign/dilithium3/clean/polyvec.h new file mode 100644 index 00000000..73b8341f --- /dev/null +++ b/crypto_sign/dilithium3/clean/polyvec.h @@ -0,0 +1,51 @@ +#ifndef POLYVEC_H +#define POLYVEC_H + +#include "params.h" +#include "poly.h" +#include + +/* 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 diff --git a/crypto_sign/dilithium3/clean/reduce.c b/crypto_sign/dilithium3/clean/reduce.c new file mode 100644 index 00000000..651d0a2b --- /dev/null +++ b/crypto_sign/dilithium3/clean/reduce.c @@ -0,0 +1,74 @@ +#include "params.h" +#include "reduce.h" +#include + +/************************************************* +* 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; +} diff --git a/crypto_sign/dilithium3/clean/reduce.h b/crypto_sign/dilithium3/clean/reduce.h new file mode 100644 index 00000000..4c6e8578 --- /dev/null +++ b/crypto_sign/dilithium3/clean/reduce.h @@ -0,0 +1,21 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +#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 diff --git a/crypto_sign/dilithium3/clean/rounding.c b/crypto_sign/dilithium3/clean/rounding.c new file mode 100644 index 00000000..603a7d59 --- /dev/null +++ b/crypto_sign/dilithium3/clean/rounding.c @@ -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; +} diff --git a/crypto_sign/dilithium3/clean/rounding.h b/crypto_sign/dilithium3/clean/rounding.h new file mode 100644 index 00000000..ad979f09 --- /dev/null +++ b/crypto_sign/dilithium3/clean/rounding.h @@ -0,0 +1,11 @@ +#ifndef ROUNDING_H +#define ROUNDING_H + +#include + +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 diff --git a/crypto_sign/dilithium3/clean/sign.c b/crypto_sign/dilithium3/clean/sign.c new file mode 100644 index 00000000..1e0a8523 --- /dev/null +++ b/crypto_sign/dilithium3/clean/sign.c @@ -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 + +/************************************************* +* 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; +} + diff --git a/crypto_sign/dilithium3/clean/sign.h b/crypto_sign/dilithium3/clean/sign.h new file mode 100644 index 00000000..4c309571 --- /dev/null +++ b/crypto_sign/dilithium3/clean/sign.h @@ -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 diff --git a/crypto_sign/dilithium3/clean/symmetric.c b/crypto_sign/dilithium3/clean/symmetric.c new file mode 100644 index 00000000..955e686d --- /dev/null +++ b/crypto_sign/dilithium3/clean/symmetric.c @@ -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)); +} diff --git a/crypto_sign/dilithium3/clean/symmetric.h b/crypto_sign/dilithium3/clean/symmetric.h new file mode 100644 index 00000000..53e9760f --- /dev/null +++ b/crypto_sign/dilithium3/clean/symmetric.h @@ -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 diff --git a/crypto_sign/dilithium4/META.yml b/crypto_sign/dilithium4/META.yml new file mode 100644 index 00000000..3730fe06 --- /dev/null +++ b/crypto_sign/dilithium4/META.yml @@ -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 diff --git a/crypto_sign/dilithium4/clean/LICENSE b/crypto_sign/dilithium4/clean/LICENSE new file mode 100644 index 00000000..0299dbff --- /dev/null +++ b/crypto_sign/dilithium4/clean/LICENSE @@ -0,0 +1,2 @@ +Public Domain +Authors: Léo Ducas, Eike Kiltz, Tancrède Lepoint, Vadim Lyubashevsky, Gregor Seiler, Peter Schwabe, Damien Stehlé diff --git a/crypto_sign/dilithium4/clean/Makefile b/crypto_sign/dilithium4/clean/Makefile new file mode 100644 index 00000000..265034fe --- /dev/null +++ b/crypto_sign/dilithium4/clean/Makefile @@ -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) diff --git a/crypto_sign/dilithium4/clean/Makefile.Microsoft_nmake b/crypto_sign/dilithium4/clean/Makefile.Microsoft_nmake new file mode 100644 index 00000000..9ce715bc --- /dev/null +++ b/crypto_sign/dilithium4/clean/Makefile.Microsoft_nmake @@ -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) diff --git a/crypto_sign/dilithium4/clean/api.h b/crypto_sign/dilithium4/clean/api.h new file mode 100644 index 00000000..608ccd74 --- /dev/null +++ b/crypto_sign/dilithium4/clean/api.h @@ -0,0 +1,31 @@ +#ifndef PQCLEAN_DILITHIUM4_CLEAN_API_H +#define PQCLEAN_DILITHIUM4_CLEAN_API_H + +#include + +#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 diff --git a/crypto_sign/dilithium4/clean/ntt.c b/crypto_sign/dilithium4/clean/ntt.c new file mode 100644 index 00000000..e46b42bd --- /dev/null +++ b/crypto_sign/dilithium4/clean/ntt.c @@ -0,0 +1,137 @@ +#include "ntt.h" +#include "params.h" +#include "poly.h" +#include "reduce.h" +#include + +/* 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]); + } +} diff --git a/crypto_sign/dilithium4/clean/ntt.h b/crypto_sign/dilithium4/clean/ntt.h new file mode 100644 index 00000000..0a03fefa --- /dev/null +++ b/crypto_sign/dilithium4/clean/ntt.h @@ -0,0 +1,10 @@ +#ifndef NTT_H +#define NTT_H + +#include "params.h" +#include + +void PQCLEAN_DILITHIUM4_CLEAN_ntt(uint32_t p[N]); +void PQCLEAN_DILITHIUM4_CLEAN_invntt_frominvmont(uint32_t p[N]); + +#endif diff --git a/crypto_sign/dilithium4/clean/packing.c b/crypto_sign/dilithium4/clean/packing.c new file mode 100644 index 00000000..2d10aec6 --- /dev/null +++ b/crypto_sign/dilithium4/clean/packing.c @@ -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; +} diff --git a/crypto_sign/dilithium4/clean/packing.h b/crypto_sign/dilithium4/clean/packing.h new file mode 100644 index 00000000..7b6ce97a --- /dev/null +++ b/crypto_sign/dilithium4/clean/packing.h @@ -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 diff --git a/crypto_sign/dilithium4/clean/params.h b/crypto_sign/dilithium4/clean/params.h new file mode 100644 index 00000000..5cd83242 --- /dev/null +++ b/crypto_sign/dilithium4/clean/params.h @@ -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 diff --git a/crypto_sign/dilithium4/clean/poly.c b/crypto_sign/dilithium4/clean/poly.c new file mode 100644 index 00000000..85006681 --- /dev/null +++ b/crypto_sign/dilithium4/clean/poly.c @@ -0,0 +1,760 @@ +#include "ntt.h" +#include "params.h" +#include "poly.h" +#include "reduce.h" +#include "rounding.h" +#include "symmetric.h" +#include + + +/************************************************* +* 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)); + } + +} diff --git a/crypto_sign/dilithium4/clean/poly.h b/crypto_sign/dilithium4/clean/poly.h new file mode 100644 index 00000000..2767e259 --- /dev/null +++ b/crypto_sign/dilithium4/clean/poly.h @@ -0,0 +1,53 @@ +#ifndef POLY_H +#define POLY_H + +#include "params.h" +#include + +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 diff --git a/crypto_sign/dilithium4/clean/polyvec.c b/crypto_sign/dilithium4/clean/polyvec.c new file mode 100644 index 00000000..b75203d0 --- /dev/null +++ b/crypto_sign/dilithium4/clean/polyvec.c @@ -0,0 +1,357 @@ +#include "params.h" +#include "poly.h" +#include "polyvec.h" +#include + +/**************************************************************/ +/************ 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]); + } +} diff --git a/crypto_sign/dilithium4/clean/polyvec.h b/crypto_sign/dilithium4/clean/polyvec.h new file mode 100644 index 00000000..9481672b --- /dev/null +++ b/crypto_sign/dilithium4/clean/polyvec.h @@ -0,0 +1,51 @@ +#ifndef POLYVEC_H +#define POLYVEC_H + +#include "params.h" +#include "poly.h" +#include + +/* 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 diff --git a/crypto_sign/dilithium4/clean/reduce.c b/crypto_sign/dilithium4/clean/reduce.c new file mode 100644 index 00000000..8901a453 --- /dev/null +++ b/crypto_sign/dilithium4/clean/reduce.c @@ -0,0 +1,74 @@ +#include "params.h" +#include "reduce.h" +#include + +/************************************************* +* 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; +} diff --git a/crypto_sign/dilithium4/clean/reduce.h b/crypto_sign/dilithium4/clean/reduce.h new file mode 100644 index 00000000..7fe2fd2d --- /dev/null +++ b/crypto_sign/dilithium4/clean/reduce.h @@ -0,0 +1,21 @@ +#ifndef REDUCE_H +#define REDUCE_H + +#include + +#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 diff --git a/crypto_sign/dilithium4/clean/rounding.c b/crypto_sign/dilithium4/clean/rounding.c new file mode 100644 index 00000000..95897924 --- /dev/null +++ b/crypto_sign/dilithium4/clean/rounding.c @@ -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; +} diff --git a/crypto_sign/dilithium4/clean/rounding.h b/crypto_sign/dilithium4/clean/rounding.h new file mode 100644 index 00000000..66cfa6f7 --- /dev/null +++ b/crypto_sign/dilithium4/clean/rounding.h @@ -0,0 +1,11 @@ +#ifndef ROUNDING_H +#define ROUNDING_H + +#include + +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 diff --git a/crypto_sign/dilithium4/clean/sign.c b/crypto_sign/dilithium4/clean/sign.c new file mode 100644 index 00000000..4e7354e1 --- /dev/null +++ b/crypto_sign/dilithium4/clean/sign.c @@ -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 + +/************************************************* +* 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; +} + diff --git a/crypto_sign/dilithium4/clean/sign.h b/crypto_sign/dilithium4/clean/sign.h new file mode 100644 index 00000000..2ade7be9 --- /dev/null +++ b/crypto_sign/dilithium4/clean/sign.h @@ -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 diff --git a/crypto_sign/dilithium4/clean/symmetric.c b/crypto_sign/dilithium4/clean/symmetric.c new file mode 100644 index 00000000..f7c767d0 --- /dev/null +++ b/crypto_sign/dilithium4/clean/symmetric.c @@ -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)); +} diff --git a/crypto_sign/dilithium4/clean/symmetric.h b/crypto_sign/dilithium4/clean/symmetric.h new file mode 100644 index 00000000..01afe773 --- /dev/null +++ b/crypto_sign/dilithium4/clean/symmetric.h @@ -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 diff --git a/test/duplicate_consistency/dilithium2_clean.yml b/test/duplicate_consistency/dilithium2_clean.yml new file mode 100644 index 00000000..0b88ceb7 --- /dev/null +++ b/test/duplicate_consistency/dilithium2_clean.yml @@ -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 diff --git a/test/duplicate_consistency/dilithium3_clean.yml b/test/duplicate_consistency/dilithium3_clean.yml new file mode 100644 index 00000000..c7b391c2 --- /dev/null +++ b/test/duplicate_consistency/dilithium3_clean.yml @@ -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 diff --git a/test/duplicate_consistency/dilithium4_clean.yml b/test/duplicate_consistency/dilithium4_clean.yml new file mode 100644 index 00000000..ad2f29b2 --- /dev/null +++ b/test/duplicate_consistency/dilithium4_clean.yml @@ -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 diff --git a/test/test_dynamic_memory.py b/test/test_dynamic_memory.py index 4f348c96..d9a60e52 100644 --- a/test/test_dynamic_memory.py +++ b/test/test_dynamic_memory.py @@ -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))