diff --git a/benchmarks.csv b/benchmarks.csv index e12398b5..cbe69784 100644 --- a/benchmarks.csv +++ b/benchmarks.csv @@ -77,12 +77,12 @@ sntrup953 (100 executions),m4f,12761557,12761535,12761571,943350,943350,943350,7 Signature Schemes,,,,,,,,,, Scheme,Implementation,Key Generation [cycles] (mean),Key Generation [cycles] (min),Key Generation [cycles] (max),Sign [cycles] (mean),Sign [cycles] (min),Sign [cycles] (max),Verify [cycles] (mean),Verify [cycles] (min),Verify [cycles] (max) dilithium2 (100 executions),clean,1976311,1934124,2022613,7465108,3241343,29601126,2109292,2108823,2109692 -dilithium2 (10000 executions),m4f,1597282,1543011,1644501,4119336,1983077,34081046,1572328,1571561,1572863 +dilithium2 (10000 executions),m4f,1598273,1543984,1645520,4088281,1983092,23248321,1572681,1571953,1573212 dilithium2aes (100 executions),clean,5153665,5109045,5227715,12016668,6375642,28738015,4824282,4779372,4898600 dilithium3 (100 executions),clean,3414513,3413395,3416061,11722059,5037981,36169675,3499388,3498955,3499805 -dilithium3 (10000 executions),m4f,2829260,2827405,2842880,6652990,3235358,42043815,2691471,2690861,2691949 +dilithium3 (10000 executions),m4f,2829137,2827129,2831465,6644258,3235339,40269792,2691982,2691456,2692439 dilithium3aes (100 executions),clean,9258325,9166749,9369734,19417325,10745071,60023085,8581938,8491758,8694807 -dilithium5 (10000 executions),m4f,4826132,4737167,4901952,8817385,5433369,40315104,4705982,4705308,4706614 +dilithium5 (10000 executions),m4f,4825973,4749351,4913802,8773020,5433389,44507501,4705852,4705213,4706521 falcon-1024 (100 executions),clean,582455197,338850289,1754663445,133655078,133335905,133985773,1526901,1526233,1527648 falcon-1024 (100 executions),m4-ct,458300837,273960881,1558842038,85160712,84941964,85410952,977811,966969,985555 falcon-1024 (100 executions),opt-ct,445577914,273960881,1180316927,85152483,84871257,85396462,978443,966990,985220 @@ -214,11 +214,11 @@ Signature Schemes,,,,,,,,,, Scheme,Implementation,Key Generation [bytes],Sign [bytes],Verify [bytes],,,,,, dilithium2,clean,38284,51908,36196,,,,,, dilithium2aes,clean,39764,53388,37676,,,,,, -dilithium2,m4f,38276,49356,36296,,,,,, +dilithium2,m4f,25988,49356,23992,,,,,, dilithium3,clean,60812,79664,57700,,,,,, dilithium3aes,clean,62292,81036,59180,,,,,, -dilithium3,m4f,60804,68804,57692,,,,,, -dilithium5,m4f,97776,116016,92872,,,,,, +dilithium3,m4f,35196,68804,32076,,,,,, +dilithium5,m4f,47484,116016,42680,,,,,, falcon-1024,clean,36264,82428,8796,,,,,, falcon-1024,m4-ct,1488,2568,496,,,,,, falcon-1024,opt-ct,1448,2568,388,,,,,, @@ -486,11 +486,11 @@ Signature Schemes,,,,,,,,,, Scheme,Implementation,.text [bytes],.data [bytes],.bss [bytes],Total [bytes],,,,, dilithium2,clean,7948,0,0,7948,,,,, dilithium2aes,clean,14982,0,0,14982,,,,, -dilithium2,m4f,18440,0,0,18440,,,,, +dilithium2,m4f,18552,0,0,18552,,,,, dilithium3,clean,7444,0,0,7444,,,,, dilithium3aes,clean,14470,0,0,14470,,,,, -dilithium3,m4f,19912,0,0,19912,,,,, -dilithium5,m4f,18236,0,0,18236,,,,, +dilithium3,m4f,19980,0,0,19980,,,,, +dilithium5,m4f,18300,0,0,18300,,,,, falcon-1024,clean,82285,0,0,82285,,,,, falcon-1024,m4-ct,81265,0,79872,161137,,,,, falcon-1024,opt-ct,81265,0,79872,161137,,,,, diff --git a/benchmarks.md b/benchmarks.md index 940ff5b4..5ee8d53c 100644 --- a/benchmarks.md +++ b/benchmarks.md @@ -79,12 +79,12 @@ | scheme | implementation | key generation [cycles] | sign [cycles] | verify [cycles] | | ------ | -------------- | ----------------------- | ------------- | --------------- | | dilithium2 (100 executions) | clean | AVG: 1,976,311
MIN: 1,934,124
MAX: 2,022,613 | AVG: 7,465,108
MIN: 3,241,343
MAX: 29,601,126 | AVG: 2,109,292
MIN: 2,108,823
MAX: 2,109,692 | -| dilithium2 (10000 executions) | m4f | AVG: 1,597,282
MIN: 1,543,011
MAX: 1,644,501 | AVG: 4,119,336
MIN: 1,983,077
MAX: 34,081,046 | AVG: 1,572,328
MIN: 1,571,561
MAX: 1,572,863 | +| dilithium2 (10000 executions) | m4f | AVG: 1,598,273
MIN: 1,543,984
MAX: 1,645,520 | AVG: 4,088,281
MIN: 1,983,092
MAX: 23,248,321 | AVG: 1,572,681
MIN: 1,571,953
MAX: 1,573,212 | | dilithium2aes (100 executions) | clean | AVG: 5,153,665
MIN: 5,109,045
MAX: 5,227,715 | AVG: 12,016,668
MIN: 6,375,642
MAX: 28,738,015 | AVG: 4,824,282
MIN: 4,779,372
MAX: 4,898,600 | | dilithium3 (100 executions) | clean | AVG: 3,414,513
MIN: 3,413,395
MAX: 3,416,061 | AVG: 11,722,059
MIN: 5,037,981
MAX: 36,169,675 | AVG: 3,499,388
MIN: 3,498,955
MAX: 3,499,805 | -| dilithium3 (10000 executions) | m4f | AVG: 2,829,260
MIN: 2,827,405
MAX: 2,842,880 | AVG: 6,652,990
MIN: 3,235,358
MAX: 42,043,815 | AVG: 2,691,471
MIN: 2,690,861
MAX: 2,691,949 | +| dilithium3 (10000 executions) | m4f | AVG: 2,829,137
MIN: 2,827,129
MAX: 2,831,465 | AVG: 6,644,258
MIN: 3,235,339
MAX: 40,269,792 | AVG: 2,691,982
MIN: 2,691,456
MAX: 2,692,439 | | dilithium3aes (100 executions) | clean | AVG: 9,258,325
MIN: 9,166,749
MAX: 9,369,734 | AVG: 19,417,325
MIN: 10,745,071
MAX: 60,023,085 | AVG: 8,581,938
MIN: 8,491,758
MAX: 8,694,807 | -| dilithium5 (10000 executions) | m4f | AVG: 4,826,132
MIN: 4,737,167
MAX: 4,901,952 | AVG: 8,817,385
MIN: 5,433,369
MAX: 40,315,104 | AVG: 4,705,982
MIN: 4,705,308
MAX: 4,706,614 | +| dilithium5 (10000 executions) | m4f | AVG: 4,825,973
MIN: 4,749,351
MAX: 4,913,802 | AVG: 8,773,020
MIN: 5,433,389
MAX: 44,507,501 | AVG: 4,705,852
MIN: 4,705,213
MAX: 4,706,521 | | falcon-1024 (100 executions) | clean | AVG: 582,455,197
MIN: 338,850,289
MAX: 1,754,663,445 | AVG: 133,655,078
MIN: 133,335,905
MAX: 133,985,773 | AVG: 1,526,901
MIN: 1,526,233
MAX: 1,527,648 | | falcon-1024 (100 executions) | m4-ct | AVG: 458,300,837
MIN: 273,960,881
MAX: 1,558,842,038 | AVG: 85,160,712
MIN: 84,941,964
MAX: 85,410,952 | AVG: 977,811
MIN: 966,969
MAX: 985,555 | | falcon-1024 (100 executions) | opt-ct | AVG: 445,577,914
MIN: 273,960,881
MAX: 1,180,316,927 | AVG: 85,152,483
MIN: 84,871,257
MAX: 85,396,462 | AVG: 978,443
MIN: 966,990
MAX: 985,220 | @@ -217,12 +217,12 @@ | Scheme | Implementation | Key Generation [bytes] | Sign [bytes] | Verify [bytes] | | ------ | -------------- | ---------------------- | ------------ | -------------- | | dilithium2 | clean | 38,284 | 51,908 | 36,196 | -| dilithium2 | m4f | 38,276 | 49,356 | 36,296 | +| dilithium2 | m4f | 25,988 | 49,356 | 23,992 | | dilithium2aes | clean | 39,764 | 53,388 | 37,676 | | dilithium3 | clean | 60,812 | 79,664 | 57,700 | -| dilithium3 | m4f | 60,804 | 68,804 | 57,692 | +| dilithium3 | m4f | 35,196 | 68,804 | 32,076 | | dilithium3aes | clean | 62,292 | 81,036 | 59,180 | -| dilithium5 | m4f | 97,776 | 116,016 | 92,872 | +| dilithium5 | m4f | 47,484 | 116,016 | 42,680 | | falcon-1024 | clean | 36,264 | 82,428 | 8,796 | | falcon-1024 | m4-ct | 1,488 | 2,568 | 496 | | falcon-1024 | opt-ct | 1,448 | 2,568 | 388 | @@ -493,12 +493,12 @@ | Scheme | Implementation | .text [bytes] | .data [bytes] | .bss [bytes] | Total [bytes] | | ------ | -------------- | ------------- | ------------- | ------------ | ------------- | | dilithium2 | clean | 7,948 | 0 | 0 | 7,948 | -| dilithium2 | m4f | 18,440 | 0 | 0 | 18,440 | +| dilithium2 | m4f | 18,552 | 0 | 0 | 18,552 | | dilithium2aes | clean | 14,982 | 0 | 0 | 14,982 | | dilithium3 | clean | 7,444 | 0 | 0 | 7,444 | -| dilithium3 | m4f | 19,912 | 0 | 0 | 19,912 | +| dilithium3 | m4f | 19,980 | 0 | 0 | 19,980 | | dilithium3aes | clean | 14,470 | 0 | 0 | 14,470 | -| dilithium5 | m4f | 18,236 | 0 | 0 | 18,236 | +| dilithium5 | m4f | 18,300 | 0 | 0 | 18,300 | | falcon-1024 | clean | 82,285 | 0 | 0 | 82,285 | | falcon-1024 | m4-ct | 81,265 | 0 | 79,872 | 161,137 | | falcon-1024 | opt-ct | 81,265 | 0 | 79,872 | 161,137 | diff --git a/crypto_sign/dilithium2/m4f/packing.c b/crypto_sign/dilithium2/m4f/packing.c index 869822c4..6046f02b 100644 --- a/crypto_sign/dilithium2/m4f/packing.c +++ b/crypto_sign/dilithium2/m4f/packing.c @@ -26,6 +26,37 @@ void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES], polyt1_pack(pk + i*POLYT1_PACKEDBYTES, &t1->vec[i]); } +/************************************************* +* Name: pack_pk_rho +* +* Description: Bit-pack only rho in public key pk = (rho, t1). +* +* Arguments: - unsigned char pk[]: output byte array +* - const unsigned char rho[]: byte array containing rho +**************************************************/ +void pack_pk_rho(unsigned char pk[CRYPTO_PUBLICKEYBYTES], + const unsigned char rho[SEEDBYTES]) { + for (unsigned int i = 0; i < SEEDBYTES; ++i) { + pk[i] = rho[i]; + } +} + +/************************************************* +* Name: pack_pk_t1 +* +* Description: Bit-pack only the t1 elem at idx in public key pk = (rho, t1). +* +* Arguments: - unsigned char pk[]: output byte array +* - const polyveck *t1: pointer to vector t1 +* - const unsigned int idx: index to the elem to pack +**************************************************/ +void pack_pk_t1(unsigned char pk[CRYPTO_PUBLICKEYBYTES], + const poly *t1, + const unsigned int idx) { + pk += SEEDBYTES; + polyt1_pack(pk + idx * POLYT1_PACKEDBYTES, t1); +} + /************************************************* * Name: unpack_pk * @@ -96,6 +127,101 @@ void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], polyt0_pack(sk + i*POLYT0_PACKEDBYTES, &t0->vec[i]); } +/************************************************* +* Name: pack_sk_s1 +* +* Description: Bit-pack only some element of s1 in secret key sk = (rho, key, tr, s1, s2, t0). +* +* Arguments: - unsigned char sk[]: output byte array +* - const poly *s1_elem: pointer to vector element idx in s1 +* - const unisgned int idx: index to the element of s1 that should be packed +**************************************************/ +void pack_sk_s1(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const poly *s1_elem, + const unsigned int idx) { + sk += 3 * SEEDBYTES; + polyeta_pack(sk + idx * POLYETA_PACKEDBYTES, s1_elem); +} + +/************************************************* +* Name: pack_sk_s2 +* +* Description: Bit-pack only some element of s2 in secret key sk = (rho, key, tr, s1, s2, t0). +* +* Arguments: - unsigned char sk[]: output byte array +* - const poly *s2_elem: pointer to vector element idx in s2 +* - const unsigned int idx: index to the element of s1 that should be packed +**************************************************/ +void pack_sk_s2(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const poly *s2_elem, + const unsigned int idx) { + sk += 3 * SEEDBYTES + L * POLYETA_PACKEDBYTES; + polyeta_pack(sk + idx * POLYETA_PACKEDBYTES, s2_elem); +} + +/************************************************* +* Name: pack_sk_t0 +* +* Description: Bit-pack only some element of t0 in secret key sk = (rho, key, tr, s1, s2, t0). +* +* Arguments: - unsigned char sk[]: output byte array +* - const poly *t0_elem: pointer to vector element idx in s2 +* - const unsigned int idx: index to the element of s1 that should be packed +**************************************************/ +void pack_sk_t0(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const poly *t0_elem, + const unsigned int idx) { + sk += 3 * SEEDBYTES + L * POLYETA_PACKEDBYTES + K * POLYETA_PACKEDBYTES; + polyt0_pack(sk + idx * POLYT0_PACKEDBYTES, t0_elem); +} + +/************************************************* +* Name: pack_sk_rho +* +* Description: Bit-pack only rho in secret key sk = (rho, key, tr, s1, s2, t0). +* +* Arguments: - unsigned char sk[]: output byte array +* - const unsigned char rho[]: byte array containing rho +**************************************************/ +void pack_sk_rho(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const unsigned char rho[SEEDBYTES]) { + for (unsigned int i = 0; i < SEEDBYTES; ++i) { + sk[i] = rho[i]; + } +} + +/************************************************* +* Name: pack_sk_key +* +* Description: Bit-pack only key in secret key sk = (rho, key, tr, s1, s2, t0). +* +* Arguments: - unsigned char sk[]: output byte array +* - const unsigned char key[]: byte array containing key +**************************************************/ +void pack_sk_key(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const unsigned char key[SEEDBYTES]) { + sk += SEEDBYTES; + for (unsigned int i = 0; i < SEEDBYTES; ++i) { + sk[i] = key[i]; + } +} + +/************************************************* +* Name: pack_sk_tr +* +* Description: Bit-pack only tr in secret key sk = (rho, key, tr, s1, s2, t0). +* +* Arguments: - unsigned char sk[]: output byte array +* - const unsigned char tr[]: byte array containing tr +**************************************************/ +void pack_sk_tr(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const unsigned char tr[SEEDBYTES]) { + sk += 2*SEEDBYTES; + for (unsigned int i = 0; i < SEEDBYTES; ++i) { + sk[i] = tr[i]; + } +} + /************************************************* * Name: unpack_sk * @@ -283,3 +409,98 @@ int unpack_sig(uint8_t c[SEEDBYTES], return 0; } + +/************************************************* +* Name: unpack_sig_z +* +* Description: Unpack only z from signature sig = (c, z, h). +* +* Arguments: - polyvecl *z: pointer to output vector z +* - const unsigned char sig[]: byte array containing +* bit-packed signature +* +**************************************************/ +int unpack_sig_z(polyvecl *z, const unsigned char sig[CRYPTO_BYTES]) { + sig += SEEDBYTES; + for (unsigned int i = 0; i < L; ++i) { + polyz_unpack(&z->vec[i], sig + i * POLYZ_PACKEDBYTES); + } + return 0; +} + +/************************************************* +* Name: unpack_pk_t1 +* +* Description: Unpack public key pk = (rho, t1). +* +* Arguments: - const polyvec *t1: pointer to output vector t1 +* - const size_t idx: unpack n'th element from t1 +* - unsigned char pk[]: byte array containing bit-packed pk +**************************************************/ +void unpack_pk_t1(poly *t1, unsigned int idx, const unsigned char pk[CRYPTO_PUBLICKEYBYTES]) { + pk += SEEDBYTES; + polyt1_unpack(t1, pk + idx * POLYT1_PACKEDBYTES); +} + +/************************************************* +* Name: unpack_sig_h +* +* Description: Unpack only h from signature sig = (c, z, h). +* +* Arguments: - polyveck *h: pointer to output hint vector h +* - const unsigned char sig[]: byte array containing +* bit-packed signature +* +* Returns 1 in case of malformed signature; otherwise 0. +**************************************************/ +int unpack_sig_h(poly *h, unsigned int idx, const unsigned char sig[CRYPTO_BYTES]) { + sig += L * POLYZ_PACKEDBYTES; + sig += SEEDBYTES; + /* Decode h */ + unsigned int k = 0; + for (unsigned int i = 0; i < K; ++i) { + for (unsigned int j = 0; j < N; ++j) { + if (i == idx) { + h->coeffs[j] = 0; + } + } + + if (sig[OMEGA + i] < k || sig[OMEGA + i] > OMEGA) { + return 1; + } + + for (unsigned int j = k; j < sig[OMEGA + i]; ++j) { + /* Coefficients are ordered for strong unforgeability */ + if (j > k && sig[j] <= sig[j - 1]) { + return 1; + } + if (i == idx) { + h->coeffs[sig[j]] = 1; + } + } + + k = sig[OMEGA + i]; + } + + /* Extra indices are zero for strong unforgeability */ + for (unsigned int j = k; j < OMEGA; ++j) { + if (sig[j]) { + return 1; + } + } + return 0; +} + +/************************************************* +* Name: getoffset_pk_rho +* +* Description: Unpack only rho from public key pk = (rho, t1). +* +* Arguments: - const unsigned char *rho: pointer to rho inside of pk +* - unsigned char pk[]: byte array containing bit-packed pk +* +* The lifetime of rho MUST NOT exceed the lifetime of pk! +**************************************************/ +const unsigned char *getoffset_pk_rho(const unsigned char pk[CRYPTO_PUBLICKEYBYTES]) { + return pk; +} \ No newline at end of file diff --git a/crypto_sign/dilithium2/m4f/packing.h b/crypto_sign/dilithium2/m4f/packing.h index 030d31c5..a3fe87b6 100644 --- a/crypto_sign/dilithium2/m4f/packing.h +++ b/crypto_sign/dilithium2/m4f/packing.h @@ -9,6 +9,18 @@ #define pack_pk DILITHIUM_NAMESPACE(pack_pk) void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES], const uint8_t rho[SEEDBYTES], const polyveck *t1); +#define pack_pk_rho DILITHIUM_NAMESPACE(pack_pk_rho) +void pack_pk_rho(unsigned char pk[CRYPTO_PUBLICKEYBYTES], + const unsigned char rho[SEEDBYTES]); + +#define getoffset_pk_rho DILITHIUM_NAMESPACE(getoffset_pk_rho) +const unsigned char *getoffset_pk_rho(const unsigned char pk[CRYPTO_PUBLICKEYBYTES]); + +#define pack_pk_t1 DILITHIUM_NAMESPACE(pack_pk_t1) +void pack_pk_t1(unsigned char pk[CRYPTO_PUBLICKEYBYTES], + const poly *t1, + const unsigned int idx); + #define pack_sk DILITHIUM_NAMESPACE(pack_sk) void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], const uint8_t rho[SEEDBYTES], @@ -18,6 +30,33 @@ void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], const polyvecl *s1, const polyveck *s2); +#define pack_sk_s1 DILITHIUM_NAMESPACE(pack_sk_s1) +void pack_sk_s1(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const poly *s1_elem, + const unsigned int idx); + +#define pack_sk_s2 DILITHIUM_NAMESPACE(pack_sk_s2) +void pack_sk_s2(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const poly *s2_elem, + const unsigned int idx); + +#define pack_sk_t0 DILITHIUM_NAMESPACE(pack_sk_t0) +void pack_sk_t0(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const poly *t0_elem, + const unsigned int idx); + +#define pack_sk_rho DILITHIUM_NAMESPACE(pack_sk_rho) +void pack_sk_rho(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const unsigned char rho[SEEDBYTES]); + +#define pack_sk_key DILITHIUM_NAMESPACE(pack_sk_key) +void pack_sk_key(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const unsigned char key[SEEDBYTES]); + +#define pack_sk_tr DILITHIUM_NAMESPACE(pack_sk_tr) +void pack_sk_tr(unsigned char sk[CRYPTO_SECRETKEYBYTES], + const unsigned char tr[SEEDBYTES]); + #define pack_sig DILITHIUM_NAMESPACE(pack_sig) void pack_sig(uint8_t sig[CRYPTO_BYTES], const uint8_t c[SEEDBYTES], const polyvecl *z, const polyveck *h); @@ -36,6 +75,15 @@ void unpack_sk(uint8_t rho[SEEDBYTES], #define unpack_sig DILITHIUM_NAMESPACE(unpack_sig) int unpack_sig(uint8_t c[SEEDBYTES], polyvecl *z, polyveck *h, const uint8_t sig[CRYPTO_BYTES]); +#define unpack_sig_z DILITHIUM_NAMESPACE(unpack_sig_z) +int unpack_sig_z(polyvecl *z, const unsigned char sig[CRYPTO_BYTES]); + +#define unpack_sig_h DILITHIUM_NAMESPACE(unpack_sig_h) +int unpack_sig_h(poly *h, unsigned int idx, const unsigned char sig[CRYPTO_BYTES]); + +#define unpack_pk_t1 DILITHIUM_NAMESPACE(unpack_pk_t1) +void unpack_pk_t1(poly *t1, unsigned int idx, const unsigned char pk[CRYPTO_PUBLICKEYBYTES]); + #define pack_sig_c DILITHIUM_NAMESPACE(pack_sig_c) void pack_sig_c(uint8_t sig[CRYPTO_BYTES], const uint8_t c[SEEDBYTES]); diff --git a/crypto_sign/dilithium2/m4f/sign.c b/crypto_sign/dilithium2/m4f/sign.c index a1d4d7e4..3274f121 100644 --- a/crypto_sign/dilithium2/m4f/sign.c +++ b/crypto_sign/dilithium2/m4f/sign.c @@ -21,12 +21,12 @@ * Returns 0 (success) **************************************************/ int crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { + unsigned int i, j; uint8_t seedbuf[2*SEEDBYTES + CRHBYTES]; uint8_t tr[SEEDBYTES]; const uint8_t *rho, *rhoprime, *key; - polyvecl mat[K]; - polyvecl s1, s1hat; - polyveck s2, t1, t0; + uint16_t nonce = 0; + polyvecl s1; /* Get randomness for rho, rhoprime and key */ randombytes(seedbuf, SEEDBYTES); @@ -35,31 +35,60 @@ int crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { rhoprime = rho + SEEDBYTES; key = rhoprime + CRHBYTES; - /* Expand matrix */ - polyvec_matrix_expand(mat, rho); - - /* Sample short vectors s1 and s2 */ - polyvecl_uniform_eta(&s1, rhoprime, 0); - polyveck_uniform_eta(&s2, rhoprime, L); + pack_sk_rho(sk, rho); + pack_sk_key(sk, key); + pack_pk_rho(pk, rho); + + /* Sample short vector s1 and immediately store its time-domain version */ + for (i = 0; i < L; i++) + { + poly_uniform_eta(&s1.vec[i], rhoprime, nonce++); + pack_sk_s1(sk, &s1.vec[i], i); + /* Move s1 to NTT domain */ + poly_ntt(&s1.vec[i]); + } /* Matrix-vector multiplication */ - s1hat = s1; - polyvecl_ntt(&s1hat); - polyvec_matrix_pointwise_montgomery(&t1, mat, &s1hat); - polyveck_reduce(&t1); - polyveck_invntt_tomont(&t1); - - /* Add error vector s2 */ - polyveck_add(&t1, &t1, &s2); + for (i = 0; i < K; i++) + { + poly t; + { + poly tmp_elem; + /* expand part of the matrix */ + poly_uniform(&tmp_elem, rho, (i << 8) + 0); + /* partial matrix-vector multiplication */ + poly_pointwise_montgomery(&t, &tmp_elem, &s1.vec[0]); + for(j = 1; j < L; j++) + { + poly_uniform(&tmp_elem, rho, (i << 8) + j); + poly_pointwise_acc_montgomery(&t, &tmp_elem, &s1.vec[j]); + } + } + poly_reduce(&t); + poly_invntt_tomont(&t); + + /* Add error vector s2 */ + { + poly s2; + /* Sample short vector s2 */ + poly_uniform_eta(&s2, rhoprime, nonce++); + pack_sk_s2(sk, &s2, i); + poly_add(&t, &t, &s2); + } - /* Extract t1 and write public key */ - polyveck_caddq(&t1); - polyveck_power2round(&t1, &t0, &t1); - pack_pk(pk, rho, &t1); + /* Compute t{0,1} */ + { + poly t1, t0; + poly_caddq(&t); + poly_power2round(&t1, &t0, &t); + pack_sk_t0(sk, &t0, i); + pack_pk_t1(pk, &t1, i); + } + } /* Compute H(rho, t1) and write secret key */ shake256(tr, SEEDBYTES, pk, CRYPTO_PUBLICKEYBYTES); - pack_sk(sk, rho, tr, key, &t0, &s1, &s2); + pack_sk_tr(sk, tr); return 0; } @@ -165,7 +194,6 @@ int crypto_sign_signature(uint8_t *sig, unsigned int hints_written = 0; /* Check that subtracting cs2 does not change high bits of w and low bits * do not reveal secret information */ - pack_sig_z(sig, &z); for(unsigned int i = 0; i < K; ++i) { poly *tmp = &z.vec[0]; poly_small_basemul_invntt(tmp, &cp_small, &cp_small_prime, &s2_prime[i]); @@ -245,26 +273,17 @@ int crypto_sign_verify(const uint8_t *sig, size_t mlen, const uint8_t *pk) { - unsigned int i; - uint8_t buf[K*POLYW1_PACKEDBYTES]; - uint8_t rho[SEEDBYTES]; + unsigned int i, j; + const unsigned char *rho = getoffset_pk_rho(pk); uint8_t mu[CRHBYTES]; - uint8_t c[SEEDBYTES]; uint8_t c2[SEEDBYTES]; - poly cp; - polyvecl mat[K], z; - polyveck t1, w1, h; + polyvecl z; + poly c, w1_elem, tmp_elem; shake256incctx state; if(siglen != CRYPTO_BYTES) return -1; - unpack_pk(rho, &t1, pk); - if(unpack_sig(c, &z, &h, sig)) - return -1; - if(polyvecl_chknorm(&z, GAMMA1 - BETA)) - return -1; - /* Compute CRH(h(rho, t1), msg) */ shake256(mu, SEEDBYTES, pk, CRYPTO_PUBLICKEYBYTES); shake256_inc_init(&state); @@ -273,35 +292,61 @@ int crypto_sign_verify(const uint8_t *sig, shake256_inc_finalize(&state); shake256_inc_squeeze(mu, CRHBYTES, &state); - /* Matrix-vector multiplication; compute Az - c2^dt1 */ - poly_challenge(&cp, c); - polyvec_matrix_expand(mat, rho); + // Hash [mu || w1'] to get c. + shake256_inc_init(&state); + shake256_inc_absorb(&state, mu, CRHBYTES); + + poly_challenge(&c, sig); + poly_ntt(&c); + + if (unpack_sig_z(&z, sig) != 0) { + return -1; + }; + if (polyvecl_chknorm(&z, GAMMA1 - BETA)) { + return -1; + } polyvecl_ntt(&z); - polyvec_matrix_pointwise_montgomery(&w1, mat, &z); - poly_ntt(&cp); - polyveck_shiftl(&t1); - polyveck_ntt(&t1); - polyveck_pointwise_poly_montgomery(&t1, &cp, &t1); + for(i = 0; i < K; ++i) + { + /* partial matrix-vector multiplication */ + poly_uniform(&tmp_elem, rho, (uint16_t)((i << 8) + 0)); + poly_pointwise_montgomery(&w1_elem, &tmp_elem, &z.vec[0]); + for (j = 1; j < L; j++) + { + poly_uniform(&tmp_elem, rho, (uint16_t)((i << 8) + j)); + poly_pointwise_acc_montgomery(&w1_elem, &tmp_elem, &z.vec[j]); + } - polyveck_sub(&w1, &w1, &t1); - polyveck_reduce(&w1); - polyveck_invntt_tomont(&w1); + // Subtract c*(t1_{i} * 2^d) + unpack_pk_t1(&tmp_elem, i, pk); + poly_shiftl(&tmp_elem); + poly_ntt(&tmp_elem); - /* Reconstruct w1 */ - polyveck_caddq(&w1); - polyveck_use_hint(&w1, &w1, &h); - polyveck_pack_w1(buf, &w1); + poly_pointwise_montgomery(&tmp_elem, &c, &tmp_elem); + + poly_sub(&w1_elem, &w1_elem, &tmp_elem); + poly_reduce(&w1_elem); + poly_invntt_tomont(&w1_elem); + + /* Reconstruct w1 */ + poly_caddq(&w1_elem); + + if (unpack_sig_h(&tmp_elem, i, sig) != 0) { + return -1; + }; + poly_use_hint(&w1_elem, &w1_elem, &tmp_elem); + uint8_t w1_packed[POLYW1_PACKEDBYTES]; + polyw1_pack(w1_packed, &w1_elem); + shake256_inc_absorb(&state, w1_packed, POLYW1_PACKEDBYTES); +} /* Call random oracle and verify challenge */ - shake256_inc_init(&state); - shake256_inc_absorb(&state, mu, CRHBYTES); - shake256_inc_absorb(&state, buf, K*POLYW1_PACKEDBYTES); shake256_inc_finalize(&state); shake256_inc_squeeze(c2, SEEDBYTES, &state); for(i = 0; i < SEEDBYTES; ++i) - if(c[i] != c2[i]) + if(sig[i] != c2[i]) return -1; return 0;