diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 17b9f75..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -project(dilithium C ASM) - -set(CMAKE_C_STANDARD 99) -set(CMAKE_C_STANDARD_REQUIRED ON) - -enable_testing() - -#find_package(OpenSSL REQUIRED) -#include_directories(${OPENSSL_INCLUDE_DIR}) - -add_subdirectory(ref) -#add_subdirectory(avx2) diff --git a/README.md b/README.md index 5a5d48d..7ae2789 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/pq-crystals/dilithium.svg?branch=master)](https://travis-ci.org/pq-crystals/dilithium) [![Coverage Status](https://coveralls.io/repos/github/pq-crystals/dilithium/badge.svg?branch=master)](https://coveralls.io/github/pq-crystals/dilithium?branch=master) -This repository contains the official reference implementation of the [Dilithium](https://www.pq-crystals.org/dilithium/) signature scheme, and an optimized implementation for x86 CPUs supporting the AVX2 instruction set. Dilithium is a [finalist](https://csrc.nist.gov/Projects/post-quantum-cryptography/round-3-submissions) in the [NIST PQC](https://csrc.nist.gov/projects/post-quantum-cryptography) standardization project. +This repository contains the official reference implementation of the [Dilithium](https://www.pq-crystals.org/dilithium/) signature scheme, and an optimized implementation for x86 CPUs supporting the AVX2 instruction set. Dilithium is standardized as [FIPS 204](https://csrc.nist.gov/pubs/fips/204/final). ## Build instructions @@ -34,9 +34,9 @@ This produces the executables ```sh test/test_dilithium$ALG test/test_vectors$ALG -PQCgenKAT_sign$ALG +nistkat/PQCgenKAT_sign$ALG ``` -where `$ALG` ranges over the parameter sets 2, 3, 5, 2aes, 3aes, and 5aes. +where `$ALG` ranges over the parameter sets 2, 3, and 5. * `test_dilithium$ALG` tests 10000 times to generate keys, sign a random message of 59 bytes and verify the produced signature. Also, the program will try to verify wrong signatures where a single random byte of a valid signature was randomly distorted. The program will abort with an error message and return -1 if there was an error. Otherwise it will output the key and signature sizes and return 0. * `test_vectors$ALG` performs further tests of internal functions and prints deterministically generated test vectors for several intermediate values that occur in the Dilithium algorithms. Namely, a 48 byte seed, the matrix A corresponding to the first 32 bytes of seed, a short secret vector s corresponding to the first 32 bytes of seed and nonce 0, a masking vector y corresponding to the seed and nonce 0, the high bits w1 and the low bits w0 of the vector w = Ay, the power-of-two rounding t1 of w and the corresponding low part t0, and the challenge c for the seed and w1. This program is meant to help to ensure compatibility of independent implementations. @@ -76,20 +76,8 @@ For example in the directory `ref/` of the reference implementation, this produc ```sh libpqcrystals_dilithium$ALG_ref.so ``` -for all parameter sets `$ALG`, and the required symmetric crypto libraries +for all parameter sets `$ALG`, and the required symmetric crypto library ``` -libpqcrystals_aes256ctr_ref.so libpqcrystals_fips202_ref.so ``` -All global symbols in the libraries lie in the namespaces `pqcrystals_dilithium$ALG_ref`, `libpqcrystals_aes256ctr_ref` and `libpqcrystals_fips202_ref`. Hence it is possible to link a program against all libraries simultaneously and obtain access to all implementations for all parameter sets. The corresponding API header file is `ref/api.h`, which contains prototypes for all API functions and preprocessor defines for the key and signature lengths. - -## CMake - -Also available is a portable [cmake](https://cmake.org) based build system that permits building the reference implementation. - -By calling -``` -mkdir build && cd build && cmake .. && cmake --build . && ctest -``` - -the Dilithium reference implementation gets built and tested. +All global symbols in the libraries lie in the namespaces `pqcrystals_dilithium$ALG_ref` and `libpqcrystals_fips202_ref`. Hence it is possible to link a program against all libraries simultaneously and obtain access to all implementations for all parameter sets. The corresponding API header file is `ref/api.h`, which contains prototypes for all API functions and preprocessor defines for the key and signature lengths. diff --git a/SHA256SUMS b/SHA256SUMS index 2b56362..7dacce8 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -1,3 +1,3 @@ -e1313e5a1958dc70faa9f4a03a4f6549083b7ec6edfad6054311ab2fe2079587 tvecs2 -4d391effb3b02706a3940225d2d50d3c6261516c42e75990b3fb6254be978684 tvecs3 -e9f73f84918220502ff572fad1dfabc272895e0b2b510b46fdf1b8b908461669 tvecs5 +de6e62b7bfc5d5f0c13d640958edf4890555a25637fd87365ae25289f5aed509 tvecs2 +beefebab47f07b26a08668e0358e424d2b4c93ee4c1ddd7365f29e48aede53c9 tvecs3 +bab5ec301c9a697743800c0c441f84f4bda397a1be3212b3b32d47144a5bfa8f tvecs5 diff --git a/avx2/Makefile b/avx2/Makefile index af0a360..f85cfc0 100644 --- a/avx2/Makefile +++ b/avx2/Makefile @@ -104,7 +104,6 @@ test/test_mul: test/test_mul.c randombytes.c $(KECCAK_SOURCES) \ $(KECCAK_HEADERS) $(CC) $(CFLAGS) -UDBENCH -o $@ $< randombytes.c $(KECCAK_SOURCES) - clean: rm -f *.o *.a *.so rm -f test/test_dilithium2 diff --git a/avx2/api.h b/avx2/api.h index 1948a96..b942549 100644 --- a/avx2/api.h +++ b/avx2/api.h @@ -5,7 +5,7 @@ #include #define pqcrystals_dilithium2_PUBLICKEYBYTES 1312 -#define pqcrystals_dilithium2_SECRETKEYBYTES 2528 +#define pqcrystals_dilithium2_SECRETKEYBYTES 2560 #define pqcrystals_dilithium2_BYTES 2420 #define pqcrystals_dilithium2_avx2_PUBLICKEYBYTES pqcrystals_dilithium2_PUBLICKEYBYTES @@ -31,9 +31,9 @@ int pqcrystals_dilithium2_avx2_open(uint8_t *m, size_t *mlen, const uint8_t *pk); -#define pqcrystals_dilithium3_PUBLICKEYBYTES 1952 -#define pqcrystals_dilithium3_SECRETKEYBYTES 4000 -#define pqcrystals_dilithium3_BYTES 3293 +#define pqcrystals_dilithium5_PUBLICKEYBYTES 2592 +#define pqcrystals_dilithium5_SECRETKEYBYTES 4896 +#define pqcrystals_dilithium5_BYTES 4627 #define pqcrystals_dilithium3_avx2_PUBLICKEYBYTES pqcrystals_dilithium3_PUBLICKEYBYTES #define pqcrystals_dilithium3_avx2_SECRETKEYBYTES pqcrystals_dilithium3_SECRETKEYBYTES diff --git a/avx2/f1600x4.S b/avx2/f1600x4.S index 497b8ca..5455129 100644 --- a/avx2/f1600x4.S +++ b/avx2/f1600x4.S @@ -905,3 +905,5 @@ addq $32, %rsi subq $1, %rax jnz looptop ret + +.section .note.GNU-stack,"",@progbits diff --git a/avx2/invntt.S b/avx2/invntt.S index 3e9864c..d40ca13 100644 --- a/avx2/invntt.S +++ b/avx2/invntt.S @@ -236,3 +236,5 @@ levels6t7 2 levels6t7 3 ret + +.section .note.GNU-stack,"",@progbits diff --git a/avx2/ntt.S b/avx2/ntt.S index 38415de..026f057 100644 --- a/avx2/ntt.S +++ b/avx2/ntt.S @@ -195,3 +195,4 @@ levels2t7 3 ret +.section .note.GNU-stack,"",@progbits diff --git a/avx2/pointwise.S b/avx2/pointwise.S index ae7ff79..6b687c7 100644 --- a/avx2/pointwise.S +++ b/avx2/pointwise.S @@ -209,3 +209,5 @@ cmp $16,%eax jb _looptop2 ret + +.section .note.GNU-stack,"",@progbits diff --git a/avx2/poly.c b/avx2/poly.c index c1b21c1..01263c8 100644 --- a/avx2/poly.c +++ b/avx2/poly.c @@ -664,16 +664,16 @@ void poly_uniform_gamma1_4x(poly *a0, * SHAKE256(seed). * * Arguments: - poly *c: pointer to output polynomial -* - const uint8_t mu[]: byte array containing seed of length SEEDBYTES +* - const uint8_t mu[]: byte array containing seed of length CTILDEBYTES **************************************************/ -void poly_challenge(poly * restrict c, const uint8_t seed[SEEDBYTES]) { +void poly_challenge(poly * restrict c, const uint8_t seed[CTILDEBYTES]) { unsigned int i, b, pos; uint64_t signs; ALIGNED_UINT8(SHAKE256_RATE) buf; keccak_state state; shake256_init(&state); - shake256_absorb(&state, seed, SEEDBYTES); + shake256_absorb(&state, seed, CTILDEBYTES); shake256_finalize(&state); shake256_squeezeblocks(buf.coeffs, 1, &state); diff --git a/avx2/poly.h b/avx2/poly.h index 7bcd8e5..7d93088 100644 --- a/avx2/poly.h +++ b/avx2/poly.h @@ -53,7 +53,7 @@ void poly_uniform_gamma1_preinit(poly *a, stream256_state *state); #define poly_uniform_gamma1 DILITHIUM_NAMESPACE(poly_uniform_gamma1) void poly_uniform_gamma1(poly *a, const uint8_t seed[CRHBYTES], uint16_t nonce); #define poly_challenge DILITHIUM_NAMESPACE(poly_challenge) -void poly_challenge(poly *c, const uint8_t seed[SEEDBYTES]); +void poly_challenge(poly *c, const uint8_t seed[CTILDEBYTES]); #define poly_uniform_4x DILITHIUM_NAMESPACE(poly_uniform_4x) void poly_uniform_4x(poly *a0, diff --git a/avx2/shuffle.S b/avx2/shuffle.S index 133e051..08c757c 100644 --- a/avx2/shuffle.S +++ b/avx2/shuffle.S @@ -50,3 +50,5 @@ call nttunpack128_avx add $256,%rdi call nttunpack128_avx ret + +.section .note.GNU-stack,"",@progbits diff --git a/avx2/sign.c b/avx2/sign.c index c8f2398..208a314 100644 --- a/avx2/sign.c +++ b/avx2/sign.c @@ -74,7 +74,9 @@ int crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { /* Get randomness for rho, rhoprime and key */ randombytes(seedbuf, SEEDBYTES); - shake256(seedbuf, 2*SEEDBYTES + CRHBYTES, seedbuf, SEEDBYTES); + seedbuf[SEEDBYTES+0] = K; + seedbuf[SEEDBYTES+1] = L; + shake256(seedbuf, 2*SEEDBYTES + CRHBYTES, seedbuf, SEEDBYTES+2); rho = seedbuf; rhoprime = rho + SEEDBYTES; key = rhoprime + CRHBYTES; @@ -143,11 +145,15 @@ int crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { * - size_t *siglen: pointer to output length of signature * - uint8_t *m: pointer to message to be signed * - size_t mlen: length of message +* - uint8_t *ctx: pointer to context string +* - size_t ctxlen: length of context string * - uint8_t *sk: pointer to bit-packed secret key * -* Returns 0 (success) +* Returns 0 (success) or -1 (context string too long) **************************************************/ -int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *sk) { +int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, const uint8_t *sk) +{ unsigned int i, n, pos; uint8_t seedbuf[2*SEEDBYTES + TRBYTES + RNDBYTES + 2*CRHBYTES]; uint8_t *rho, *tr, *key, *rnd, *mu, *rhoprime; @@ -163,6 +169,9 @@ int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t } tmpv; keccak_state state; + if(ctxlen > 255) + return -1; + rho = seedbuf; tr = rho + SEEDBYTES; key = tr + TRBYTES; @@ -171,9 +180,13 @@ int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t rhoprime = mu + CRHBYTES; unpack_sk(rho, tr, key, &t0, &s1, &s2, sk); - /* Compute CRH(tr, msg) */ + /* Compute CRH(tr, 0, ctxlen, ctx, msg) */ shake256_init(&state); shake256_absorb(&state, tr, TRBYTES); + mu[0] = 0; + mu[1] = ctxlen; + shake256_absorb(&state, mu, 2); + shake256_absorb(&state, ctx, ctxlen); shake256_absorb(&state, m, mlen); shake256_finalize(&state); shake256_squeeze(mu, CRHBYTES, &state); @@ -292,18 +305,23 @@ int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t * message * - const uint8_t *m: pointer to message to be signed * - size_t mlen: length of message +* - const uint8_t *ctx: pointer to context string +* - size_t ctxlen: length of context string * - const uint8_t *sk: pointer to bit-packed secret key * * Returns 0 (success) **************************************************/ -int crypto_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, const uint8_t *sk) { +int crypto_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen, + const uint8_t *sk) +{ size_t i; + int ret; for(i = 0; i < mlen; ++i) sm[CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; - crypto_sign_signature(sm, smlen, sm + CRYPTO_BYTES, mlen, sk); + ret = crypto_sign_signature(sm, smlen, sm + CRYPTO_BYTES, mlen, ctx, ctxlen, sk); *smlen += mlen; - return 0; + return ret; } /************************************************* @@ -315,11 +333,14 @@ int crypto_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, const * - size_t siglen: length of signature * - const uint8_t *m: pointer to message * - size_t mlen: length of message +* - const uint8_t *ctx: pointer to context string +* - size_t ctxlen: length of context string * - const uint8_t *pk: pointer to bit-packed public key * * Returns 0 if signature could be verified correctly and -1 otherwise **************************************************/ -int crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pk) { +int crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, const uint8_t *pk) { unsigned int i, j, pos = 0; /* polyw1_pack writes additional 14 bytes */ ALIGNED_UINT8(K*POLYW1_PACKEDBYTES+14) buf; @@ -331,13 +352,17 @@ int crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size poly c, w1, h; keccak_state state; - if(siglen != CRYPTO_BYTES) + if(ctxlen > 255 || siglen != CRYPTO_BYTES) return -1; /* Compute CRH(H(rho, t1), msg) */ - shake256(mu, CRHBYTES, pk, CRYPTO_PUBLICKEYBYTES); + shake256(mu, TRBYTES, pk, CRYPTO_PUBLICKEYBYTES); shake256_init(&state); shake256_absorb(&state, mu, CRHBYTES); + mu[0] = 0; + mu[1] = ctxlen; + shake256_absorb(&state, mu, 2); + shake256_absorb(&state, ctx, ctxlen); shake256_absorb(&state, m, mlen); shake256_finalize(&state); shake256_squeeze(mu, CRHBYTES, &state); @@ -412,18 +437,21 @@ int crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size * - size_t *mlen: pointer to output length of message * - const uint8_t *sm: pointer to signed message * - size_t smlen: length of signed message +* - const uint8_t *ctx: pointer to context string +* - size_t ctxlen: length of context string * - const uint8_t *pk: pointer to bit-packed public key * * Returns 0 if signed message could be verified correctly and -1 otherwise **************************************************/ -int crypto_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, const uint8_t *pk) { +int crypto_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, const uint8_t *pk) { size_t i; if(smlen < CRYPTO_BYTES) goto badsig; *mlen = smlen - CRYPTO_BYTES; - if(crypto_sign_verify(sm, CRYPTO_BYTES, sm + CRYPTO_BYTES, *mlen, pk)) + if(crypto_sign_verify(sm, CRYPTO_BYTES, sm + CRYPTO_BYTES, *mlen, ctx, ctxlen, pk)) goto badsig; else { /* All good, copy msg, return 0 */ diff --git a/avx2/test/test_vectors.c b/avx2/test/test_vectors.c index 137ce4a..5b37af3 100644 --- a/avx2/test/test_vectors.c +++ b/avx2/test/test_vectors.c @@ -11,6 +11,7 @@ #include "../packing.h" #define MLEN 32 +#define CTXLEN 13 #define NVECTORS 10000 static unsigned int nttidx(unsigned int k) { @@ -27,8 +28,7 @@ static unsigned int nttidx(unsigned int k) { * Permute before squeeze is achieved by setting pos to SHAKE128_RATE */ static keccak_state rngstate = {{0x1F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (1ULL << 63), 0, 0, 0, 0}, SHAKE128_RATE}; -void randombytes(uint8_t *x,size_t xlen) -{ +void randombytes(uint8_t *x,size_t xlen) { shake128_squeeze(x, xlen, &rngstate); } @@ -38,6 +38,7 @@ int main(void) { uint8_t sk[CRYPTO_SECRETKEYBYTES]; uint8_t sig[CRYPTO_BYTES]; uint8_t m[MLEN]; + uint8_t ctx[CTXLEN] = {0}; uint8_t seed[CRHBYTES]; uint8_t buf[CRYPTO_SECRETKEYBYTES]; size_t siglen; @@ -45,6 +46,8 @@ int main(void) { polyvecl s, y, mat[K]; polyveck w, w1, w0, t1, t0; + snprintf((char*)ctx,CTXLEN,"test_vectors"); + for(i = 0; i < NVECTORS; ++i) { printf("count = %u\n", i); @@ -66,14 +69,14 @@ int main(void) { printf("%02x", buf[j]); printf("\n"); - crypto_sign_signature(sig, &siglen, m, MLEN, sk); + crypto_sign_signature(sig, &siglen, m, MLEN, ctx, CTXLEN, sk); shake256(buf, 32, sig, CRYPTO_BYTES); printf("sig = "); for(j = 0; j < 32; ++j) printf("%02x", buf[j]); printf("\n"); - if(crypto_sign_verify(sig, siglen, m, MLEN, pk)) + if(crypto_sign_verify(sig, siglen, m, MLEN, ctx, CTXLEN, pk)) fprintf(stderr,"Signature verification failed!\n"); randombytes(seed, sizeof(seed)); diff --git a/ref/Makefile b/ref/Makefile index 01d0f2a..2c94d35 100644 --- a/ref/Makefile +++ b/ref/Makefile @@ -16,10 +16,12 @@ all: \ test/test_dilithium5 \ test/test_vectors2 \ test/test_vectors3 \ - test/test_vectors5 \ + test/test_vectors5 + +nistkat: \ nistkat/PQCgenKAT_sign2 \ nistkat/PQCgenKAT_sign3 \ - nistkat/PQCgenKAT_sign5 \ + nistkat/PQCgenKAT_sign5 speed: \ test/test_mul \ @@ -132,6 +134,6 @@ clean: rm -f test/test_speed3 rm -f test/test_speed5 rm -f test/test_mul - rm -f PQCgenKAT_sign2 - rm -f PQCgenKAT_sign3 - rm -f PQCgenKAT_sign5 + rm -f nistkat/PQCgenKAT_sign2 + rm -f nistkat/PQCgenKAT_sign3 + rm -f nistkat/PQCgenKAT_sign5 diff --git a/ref/api.h b/ref/api.h index cc5c6fe..a87005a 100644 --- a/ref/api.h +++ b/ref/api.h @@ -30,10 +30,9 @@ int pqcrystals_dilithium2_ref_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, const uint8_t *pk); - #define pqcrystals_dilithium3_PUBLICKEYBYTES 1952 #define pqcrystals_dilithium3_SECRETKEYBYTES 4032 -#define pqcrystals_dilithium3_BYTES 3293 +#define pqcrystals_dilithium3_BYTES 3309 #define pqcrystals_dilithium3_ref_PUBLICKEYBYTES pqcrystals_dilithium3_PUBLICKEYBYTES #define pqcrystals_dilithium3_ref_SECRETKEYBYTES pqcrystals_dilithium3_SECRETKEYBYTES @@ -57,10 +56,9 @@ int pqcrystals_dilithium3_ref_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, const uint8_t *pk); - #define pqcrystals_dilithium5_PUBLICKEYBYTES 2592 #define pqcrystals_dilithium5_SECRETKEYBYTES 4896 -#define pqcrystals_dilithium5_BYTES 4595 +#define pqcrystals_dilithium5_BYTES 4627 #define pqcrystals_dilithium5_ref_PUBLICKEYBYTES pqcrystals_dilithium5_PUBLICKEYBYTES #define pqcrystals_dilithium5_ref_SECRETKEYBYTES pqcrystals_dilithium5_SECRETKEYBYTES diff --git a/ref/nistkat/PQCgenKAT_sign.c b/ref/nistkat/PQCgenKAT_sign.c index d0cec24..005ce41 100644 --- a/ref/nistkat/PQCgenKAT_sign.c +++ b/ref/nistkat/PQCgenKAT_sign.c @@ -120,7 +120,7 @@ main() fprintBstr(fp_rsp, "pk = ", pk, CRYPTO_PUBLICKEYBYTES); fprintBstr(fp_rsp, "sk = ", sk, CRYPTO_SECRETKEYBYTES); - if ( (ret_val = crypto_sign(sm, &smlen, m, mlen, sk)) != 0) { + if ( (ret_val = crypto_sign(sm, &smlen, m, mlen, NULL, 0, sk)) != 0) { printf("crypto_sign returned <%d>\n", ret_val); return KAT_CRYPTO_FAILURE; } @@ -128,7 +128,7 @@ main() fprintBstr(fp_rsp, "sm = ", sm, smlen); fprintf(fp_rsp, "\n"); - if ( (ret_val = crypto_sign_open(m1, &mlen1, sm, smlen, pk)) != 0) { + if ( (ret_val = crypto_sign_open(m1, &mlen1, sm, smlen, NULL, 0, pk)) != 0) { printf("crypto_sign_open returned <%d>\n", ret_val); return KAT_CRYPTO_FAILURE; } diff --git a/ref/packing.h b/ref/packing.h index 1e8e9e7..8e47728 100644 --- a/ref/packing.h +++ b/ref/packing.h @@ -18,7 +18,7 @@ void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], const polyveck *s2); #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); +void pack_sig(uint8_t sig[CRYPTO_BYTES], const uint8_t c[CTILDEBYTES], const polyvecl *z, const polyveck *h); #define unpack_pk DILITHIUM_NAMESPACE(unpack_pk) void unpack_pk(uint8_t rho[SEEDBYTES], polyveck *t1, const uint8_t pk[CRYPTO_PUBLICKEYBYTES]); @@ -33,6 +33,6 @@ void unpack_sk(uint8_t rho[SEEDBYTES], const uint8_t sk[CRYPTO_SECRETKEYBYTES]); #define unpack_sig DILITHIUM_NAMESPACE(unpack_sig) -int unpack_sig(uint8_t c[SEEDBYTES], polyvecl *z, polyveck *h, const uint8_t sig[CRYPTO_BYTES]); +int unpack_sig(uint8_t c[CTILDEBYTES], polyvecl *z, polyveck *h, const uint8_t sig[CRYPTO_BYTES]); #endif diff --git a/ref/poly.c b/ref/poly.c index fe3b787..1ae1e67 100644 --- a/ref/poly.c +++ b/ref/poly.c @@ -484,16 +484,16 @@ void poly_uniform_gamma1(poly *a, * SHAKE256(seed). * * Arguments: - poly *c: pointer to output polynomial -* - const uint8_t mu[]: byte array containing seed of length SEEDBYTES +* - const uint8_t mu[]: byte array containing seed of length CTILDEBYTES **************************************************/ -void poly_challenge(poly *c, const uint8_t seed[SEEDBYTES]) { +void poly_challenge(poly *c, const uint8_t seed[CTILDEBYTES]) { unsigned int i, b, pos; uint64_t signs; uint8_t buf[SHAKE256_RATE]; keccak_state state; shake256_init(&state); - shake256_absorb(&state, seed, SEEDBYTES); + shake256_absorb(&state, seed, CTILDEBYTES); shake256_finalize(&state); shake256_squeezeblocks(buf, 1, &state); diff --git a/ref/poly.h b/ref/poly.h index d2fd989..904baa1 100644 --- a/ref/poly.h +++ b/ref/poly.h @@ -51,7 +51,7 @@ void poly_uniform_gamma1(poly *a, const uint8_t seed[CRHBYTES], uint16_t nonce); #define poly_challenge DILITHIUM_NAMESPACE(poly_challenge) -void poly_challenge(poly *c, const uint8_t seed[SEEDBYTES]); +void poly_challenge(poly *c, const uint8_t seed[CTILDEBYTES]); #define polyeta_pack DILITHIUM_NAMESPACE(polyeta_pack) void polyeta_pack(uint8_t *r, const poly *a); diff --git a/ref/sign.c b/ref/sign.c index d25a399..204eaa5 100644 --- a/ref/sign.c +++ b/ref/sign.c @@ -30,7 +30,9 @@ int crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { /* Get randomness for rho, rhoprime and key */ randombytes(seedbuf, SEEDBYTES); - shake256(seedbuf, 2*SEEDBYTES + CRHBYTES, seedbuf, SEEDBYTES); + seedbuf[SEEDBYTES+0] = K; + seedbuf[SEEDBYTES+1] = L; + shake256(seedbuf, 2*SEEDBYTES + CRHBYTES, seedbuf, SEEDBYTES+2); rho = seedbuf; rhoprime = rho + SEEDBYTES; key = rhoprime + CRHBYTES; @@ -73,14 +75,18 @@ int crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { * - size_t *siglen: pointer to output length of signature * - uint8_t *m: pointer to message to be signed * - size_t mlen: length of message +* - uint8_t *ctx: pointer to context string +* - size_t ctxlen: length of context string * - uint8_t *sk: pointer to bit-packed secret key * -* Returns 0 (success) +* Returns 0 (success) or -1 (context string too long) **************************************************/ int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, + size_t ctxlen, const uint8_t *sk) { unsigned int n; @@ -92,6 +98,9 @@ int crypto_sign_signature(uint8_t *sig, poly cp; keccak_state state; + if(ctxlen > 255) + return -1; + rho = seedbuf; tr = rho + SEEDBYTES; key = tr + TRBYTES; @@ -100,10 +109,13 @@ int crypto_sign_signature(uint8_t *sig, rhoprime = mu + CRHBYTES; unpack_sk(rho, tr, key, &t0, &s1, &s2, sk); - - /* Compute mu = CRH(tr, msg) */ + /* Compute mu = CRH(tr, 0, ctxlen, ctx, msg) */ + mu[0] = 0; + mu[1] = ctxlen; shake256_init(&state); shake256_absorb(&state, tr, TRBYTES); + shake256_absorb(&state, mu, 2); + shake256_absorb(&state, ctx, ctxlen); shake256_absorb(&state, m, mlen); shake256_finalize(&state); shake256_squeeze(mu, CRHBYTES, &state); @@ -143,7 +155,7 @@ int crypto_sign_signature(uint8_t *sig, shake256_absorb(&state, sig, K*POLYW1_PACKEDBYTES); shake256_finalize(&state); shake256_squeeze(sig, CTILDEBYTES, &state); - poly_challenge(&cp, sig); /* uses only the first SEEDBYTES bytes of sig */ + poly_challenge(&cp, sig); poly_ntt(&cp); /* Compute z, reject if it reveals secret */ @@ -193,23 +205,28 @@ int crypto_sign_signature(uint8_t *sig, * message * - const uint8_t *m: pointer to message to be signed * - size_t mlen: length of message +* - const uint8_t *ctx: pointer to context string +* - size_t ctxlen: length of context string * - const uint8_t *sk: pointer to bit-packed secret key * -* Returns 0 (success) +* Returns 0 (success) or -1 (context string too long) **************************************************/ int crypto_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, + size_t ctxlen, const uint8_t *sk) { + int ret; size_t i; for(i = 0; i < mlen; ++i) sm[CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i]; - crypto_sign_signature(sm, smlen, sm + CRYPTO_BYTES, mlen, sk); + ret = crypto_sign_signature(sm, smlen, sm + CRYPTO_BYTES, mlen, ctx, ctxlen, sk); *smlen += mlen; - return 0; + return ret; } /************************************************* @@ -221,6 +238,8 @@ int crypto_sign(uint8_t *sm, * - size_t siglen: length of signature * - const uint8_t *m: pointer to message * - size_t mlen: length of message +* - const uint8_t *ctx: pointer to context string +* - size_t ctxlen: length of context string * - const uint8_t *pk: pointer to bit-packed public key * * Returns 0 if signature could be verified correctly and -1 otherwise @@ -229,6 +248,8 @@ int crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, + size_t ctxlen, const uint8_t *pk) { unsigned int i; @@ -242,7 +263,7 @@ int crypto_sign_verify(const uint8_t *sig, polyveck t1, w1, h; keccak_state state; - if(siglen != CRYPTO_BYTES) + if(ctxlen > 255 || siglen != CRYPTO_BYTES) return -1; unpack_pk(rho, &t1, pk); @@ -252,15 +273,19 @@ int crypto_sign_verify(const uint8_t *sig, return -1; /* Compute CRH(H(rho, t1), msg) */ - shake256(mu, CRHBYTES, pk, CRYPTO_PUBLICKEYBYTES); + shake256(mu, TRBYTES, pk, CRYPTO_PUBLICKEYBYTES); shake256_init(&state); - shake256_absorb(&state, mu, CRHBYTES); + shake256_absorb(&state, mu, TRBYTES); + mu[0] = 0; + mu[1] = ctxlen; + shake256_absorb(&state, mu, 2); + shake256_absorb(&state, ctx, ctxlen); shake256_absorb(&state, m, mlen); shake256_finalize(&state); shake256_squeeze(mu, CRHBYTES, &state); /* Matrix-vector multiplication; compute Az - c2^dt1 */ - poly_challenge(&cp, c); /* uses only the first SEEDBYTES bytes of c */ + poly_challenge(&cp, c); polyvec_matrix_expand(mat, rho); polyvecl_ntt(&z); @@ -303,6 +328,8 @@ int crypto_sign_verify(const uint8_t *sig, * - size_t *mlen: pointer to output length of message * - const uint8_t *sm: pointer to signed message * - size_t smlen: length of signed message +* - const uint8_t *ctx: pointer to context tring +* - size_t ctxlen: length of context string * - const uint8_t *pk: pointer to bit-packed public key * * Returns 0 if signed message could be verified correctly and -1 otherwise @@ -311,6 +338,8 @@ int crypto_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, + size_t ctxlen, const uint8_t *pk) { size_t i; @@ -319,7 +348,7 @@ int crypto_sign_open(uint8_t *m, goto badsig; *mlen = smlen - CRYPTO_BYTES; - if(crypto_sign_verify(sm, CRYPTO_BYTES, sm + CRYPTO_BYTES, *mlen, pk)) + if(crypto_sign_verify(sm, CRYPTO_BYTES, sm + CRYPTO_BYTES, *mlen, ctx, ctxlen, pk)) goto badsig; else { /* All good, copy msg, return 0 */ diff --git a/ref/sign.h b/ref/sign.h index 295f378..e1f9403 100644 --- a/ref/sign.h +++ b/ref/sign.h @@ -8,7 +8,7 @@ #include "poly.h" #define challenge DILITHIUM_NAMESPACE(challenge) -void challenge(poly *c, const uint8_t seed[SEEDBYTES]); +void challenge(poly *c, const uint8_t seed[CTILDEBYTES]); #define crypto_sign_keypair DILITHIUM_NAMESPACE(keypair) int crypto_sign_keypair(uint8_t *pk, uint8_t *sk); @@ -16,21 +16,25 @@ int crypto_sign_keypair(uint8_t *pk, uint8_t *sk); #define crypto_sign_signature DILITHIUM_NAMESPACE(signature) int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, const uint8_t *sk); #define crypto_sign DILITHIUM_NAMESPACETOP int crypto_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, const uint8_t *sk); #define crypto_sign_verify DILITHIUM_NAMESPACE(verify) int crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, + const uint8_t *ctx, size_t ctxlen, const uint8_t *pk); #define crypto_sign_open DILITHIUM_NAMESPACE(open) int crypto_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen, + const uint8_t *ctx, size_t ctxlen, const uint8_t *pk); #endif diff --git a/ref/test/test_dilithium.c b/ref/test/test_dilithium.c index bd2c425..66beb4c 100644 --- a/ref/test/test_dilithium.c +++ b/ref/test/test_dilithium.c @@ -5,6 +5,7 @@ #include "../sign.h" #define MLEN 59 +#define CTXLEN 14 #define NTESTS 10000 int main(void) @@ -13,18 +14,21 @@ int main(void) int ret; size_t mlen, smlen; uint8_t b; + uint8_t ctx[CTXLEN] = {0}; uint8_t m[MLEN + CRYPTO_BYTES]; uint8_t m2[MLEN + CRYPTO_BYTES]; uint8_t sm[MLEN + CRYPTO_BYTES]; uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; + snprintf((char*)ctx,CTXLEN,"test_dilitium"); + for(i = 0; i < NTESTS; ++i) { randombytes(m, MLEN); crypto_sign_keypair(pk, sk); - crypto_sign(sm, &smlen, m, MLEN, sk); - ret = crypto_sign_open(m2, &mlen, sm, smlen, pk); + crypto_sign(sm, &smlen, m, MLEN, ctx, CTXLEN, sk); + ret = crypto_sign_open(m2, &mlen, sm, smlen, ctx, CTXLEN, pk); if(ret) { fprintf(stderr, "Verification failed\n"); @@ -50,7 +54,7 @@ int main(void) randombytes(&b, 1); } while(!b); sm[j % (MLEN + CRYPTO_BYTES)] += b; - ret = crypto_sign_open(m2, &mlen, sm, smlen, pk); + ret = crypto_sign_open(m2, &mlen, sm, smlen, ctx, CTXLEN, pk); if(!ret) { fprintf(stderr, "Trivial forgeries possible\n"); return -1; diff --git a/ref/test/test_speed.c b/ref/test/test_speed.c index e36e840..688d930 100644 --- a/ref/test/test_speed.c +++ b/ref/test/test_speed.c @@ -73,13 +73,13 @@ int main(void) for(i = 0; i < NTESTS; ++i) { t[i] = cpucycles(); - crypto_sign_signature(sig, &siglen, sig, CRHBYTES, sk); + crypto_sign_signature(sig, &siglen, sig, CRHBYTES, NULL, 0, sk); } print_results("Sign:", t, NTESTS); for(i = 0; i < NTESTS; ++i) { t[i] = cpucycles(); - crypto_sign_verify(sig, CRYPTO_BYTES, sig, CRHBYTES, pk); + crypto_sign_verify(sig, CRYPTO_BYTES, sig, CRHBYTES, NULL, 0, pk); } print_results("Verify:", t, NTESTS); diff --git a/ref/test/test_vectors.c b/ref/test/test_vectors.c index f344be6..7e935d0 100644 --- a/ref/test/test_vectors.c +++ b/ref/test/test_vectors.c @@ -11,24 +11,24 @@ #include "../packing.h" #define MLEN 32 +#define CTXLEN 13 #define NVECTORS 10000 /* Initital state after absorbing empty string * Permute before squeeze is achieved by setting pos to SHAKE128_RATE */ static keccak_state rngstate = {{0x1F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (1ULL << 63), 0, 0, 0, 0}, SHAKE128_RATE}; -void randombytes(uint8_t *x,size_t xlen) -{ +void randombytes(uint8_t *x,size_t xlen) { shake128_squeeze(x, xlen, &rngstate); } - int main(void) { unsigned int i, j, k, l; uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; uint8_t sig[CRYPTO_BYTES]; uint8_t m[MLEN]; + uint8_t ctx[CTXLEN] = {0}; uint8_t seed[CRHBYTES]; uint8_t buf[CRYPTO_SECRETKEYBYTES]; size_t siglen; @@ -36,6 +36,8 @@ int main(void) { polyvecl s, y, mat[K]; polyveck w, w1, w0, t1, t0, h; + snprintf((char*)ctx,CTXLEN,"test_vectors"); + for(i = 0; i < NVECTORS; ++i) { printf("count = %u\n", i); @@ -57,14 +59,14 @@ int main(void) { printf("%02x", buf[j]); printf("\n"); - crypto_sign_signature(sig, &siglen, m, MLEN, sk); + crypto_sign_signature(sig, &siglen, m, MLEN, ctx, CTXLEN, sk); shake256(buf, 32, sig, CRYPTO_BYTES); printf("sig = "); for(j = 0; j < 32; ++j) printf("%02x", buf[j]); printf("\n"); - if(crypto_sign_verify(sig, siglen, m, MLEN, pk)) + if(crypto_sign_verify(sig, siglen, m, MLEN, ctx, CTXLEN, pk)) fprintf(stderr,"Signature verification failed!\n"); randombytes(seed, sizeof(seed));