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;