Skip to content

Commit

Permalink
update to final standard
Browse files Browse the repository at this point in the history
  • Loading branch information
gregorseiler committed Sep 4, 2024
1 parent e7bed62 commit cf998be
Show file tree
Hide file tree
Showing 25 changed files with 152 additions and 100 deletions.
14 changes: 0 additions & 14 deletions CMakeLists.txt

This file was deleted.

22 changes: 5 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
6 changes: 3 additions & 3 deletions SHA256SUMS
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
e1313e5a1958dc70faa9f4a03a4f6549083b7ec6edfad6054311ab2fe2079587 tvecs2
4d391effb3b02706a3940225d2d50d3c6261516c42e75990b3fb6254be978684 tvecs3
e9f73f84918220502ff572fad1dfabc272895e0b2b510b46fdf1b8b908461669 tvecs5
de6e62b7bfc5d5f0c13d640958edf4890555a25637fd87365ae25289f5aed509 tvecs2
beefebab47f07b26a08668e0358e424d2b4c93ee4c1ddd7365f29e48aede53c9 tvecs3
bab5ec301c9a697743800c0c441f84f4bda397a1be3212b3b32d47144a5bfa8f tvecs5
1 change: 0 additions & 1 deletion avx2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions avx2/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <stdint.h>

#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
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions avx2/f1600x4.S
Original file line number Diff line number Diff line change
Expand Up @@ -905,3 +905,5 @@ addq $32, %rsi
subq $1, %rax
jnz looptop
ret

.section .note.GNU-stack,"",@progbits
2 changes: 2 additions & 0 deletions avx2/invntt.S
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,5 @@ levels6t7 2
levels6t7 3

ret

.section .note.GNU-stack,"",@progbits
1 change: 1 addition & 0 deletions avx2/ntt.S
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,4 @@ levels2t7 3

ret

.section .note.GNU-stack,"",@progbits
2 changes: 2 additions & 0 deletions avx2/pointwise.S
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,5 @@ cmp $16,%eax
jb _looptop2

ret

.section .note.GNU-stack,"",@progbits
6 changes: 3 additions & 3 deletions avx2/poly.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion avx2/poly.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions avx2/shuffle.S
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ call nttunpack128_avx
add $256,%rdi
call nttunpack128_avx
ret

.section .note.GNU-stack,"",@progbits
52 changes: 40 additions & 12 deletions avx2/sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

/*************************************************
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down
11 changes: 7 additions & 4 deletions avx2/test/test_vectors.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "../packing.h"

#define MLEN 32
#define CTXLEN 13
#define NVECTORS 10000

static unsigned int nttidx(unsigned int k) {
Expand All @@ -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);
}

Expand All @@ -38,13 +38,16 @@ 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;
poly c, tmp;
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);

Expand All @@ -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));
Expand Down
12 changes: 7 additions & 5 deletions ref/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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
6 changes: 2 additions & 4 deletions ref/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Loading

0 comments on commit cf998be

Please sign in to comment.