/
githubmirror
/
libgcrypt
Обзор
Документация
Войти
/
githubmirror
/
libgcrypt
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
cipher/dilithium-dep.c
1 370 строк
41 KB
NIIBE Yutaka
cipher:dilithium: Have cipher/dilithium.h.
01 июл 2025, 03:20
Не верифицирован
01 июл 2025, 03:20
cce9c02
Код
Авторство
О чём код?
/* dilithium-dep.c - the Dilithium (DILITHIUM_MODE dependent part) * Copyright (C) 2025 g10 Code GmbH * * This file was modified for use by Libgcrypt. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see <https://www.gnu.org/licenses/>. * SPDX-License-Identifier: LGPL-2.1-or-later * * You can also use this file under the same licence of original code. * SPDX-License-Identifier: CC0 OR Apache-2.0 * */ /* Original code from: Repository: https://github.com/pq-crystals/dilithium.git Branch: master Commit: 444cdcc84eb36b66fe27b3a2529ee48f6d8150c2 Licence: Public Domain (https://creativecommons.org/share-your-work/public-domain/cc0/); or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html). Authors: Léo Ducas Eike Kiltz Tancrède Lepoint Vadim Lyubashevsky Gregor Seiler Peter Schwabe Damien Stehlé Dilithium Home: https://github.com/pq-crystals/dilithium.git */ /*************** dilithium/ref/polyvec.h */ /* Vectors of polynomials of length L */ typedef struct { poly vec[L]; } polyvecl; static void polyvecl_uniform_eta(polyvecl *v, const uint8_t seed[CRHBYTES], uint16_t nonce); static void polyvecl_uniform_gamma1(polyvecl *v, const uint8_t seed[CRHBYTES], uint16_t nonce); static void polyvecl_reduce(polyvecl *v); static void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v); static void polyvecl_ntt(polyvecl *v); static void polyvecl_invntt_tomont(polyvecl *v); static void polyvecl_pointwise_poly_montgomery(polyvecl *r, const poly *a, const polyvecl *v); static void polyvecl_pointwise_acc_montgomery(poly *w, const polyvecl *u, const polyvecl *v); static int polyvecl_chknorm(const polyvecl *v, int32_t B); /* Vectors of polynomials of length K */ typedef struct { poly vec[K]; } polyveck; static void polyveck_uniform_eta(polyveck *v, const uint8_t seed[CRHBYTES], uint16_t nonce); static void polyveck_reduce(polyveck *v); static void polyveck_caddq(polyveck *v); static void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v); static void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v); static void polyveck_shiftl(polyveck *v); static void polyveck_ntt(polyveck *v); static void polyveck_invntt_tomont(polyveck *v); static void polyveck_pointwise_poly_montgomery(polyveck *r, const poly *a, const polyveck *v); static int polyveck_chknorm(const polyveck *v, int32_t B); static void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v); static void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v); static unsigned int polyveck_make_hint(polyveck *h, const polyveck *v0, const polyveck *v1); static void polyveck_use_hint(polyveck *w, const polyveck *v, const polyveck *h); static void polyveck_pack_w1(uint8_t r[K*POLYW1_PACKEDBYTES], const polyveck *w1); static void polyvec_matrix_expand(polyvecl mat[K], const uint8_t rho[SEEDBYTES]); static void polyvec_matrix_pointwise_montgomery(polyveck *t, const polyvecl mat[K], const polyvecl *v); /*************** dilithium/ref/packing.h */ static void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES], const uint8_t rho[SEEDBYTES], const polyveck *t1); static void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], const uint8_t rho[SEEDBYTES], const uint8_t tr[TRBYTES], const uint8_t key[SEEDBYTES], const polyveck *t0, const polyvecl *s1, const polyveck *s2); static void pack_sig(uint8_t sig[CRYPTO_BYTES], const uint8_t c[CTILDEBYTES], const polyvecl *z, const polyveck *h); static void unpack_pk(uint8_t rho[SEEDBYTES], polyveck *t1, const uint8_t pk[CRYPTO_PUBLICKEYBYTES]); static void unpack_sk(uint8_t rho[SEEDBYTES], uint8_t tr[TRBYTES], uint8_t key[SEEDBYTES], polyveck *t0, polyvecl *s1, polyveck *s2, const uint8_t sk[CRYPTO_SECRETKEYBYTES]); static int unpack_sig(uint8_t c[CTILDEBYTES], polyvecl *z, polyveck *h, const uint8_t sig[CRYPTO_BYTES]); /*************** dilithium/ref/packing.c */ /************************************************* * Name: pack_pk * * Description: Bit-pack public key pk = (rho, t1). * * Arguments: - uint8_t pk[]: output byte array * - const uint8_t rho[]: byte array containing rho * - const polyveck *t1: pointer to vector t1 **************************************************/ void pack_pk(uint8_t pk[CRYPTO_PUBLICKEYBYTES], const uint8_t rho[SEEDBYTES], const polyveck *t1) { unsigned int i; for(i = 0; i < SEEDBYTES; ++i) pk[i] = rho[i]; pk += SEEDBYTES; for(i = 0; i < K; ++i) polyt1_pack(pk + i*POLYT1_PACKEDBYTES, &t1->vec[i]); } /************************************************* * Name: unpack_pk * * Description: Unpack public key pk = (rho, t1). * * Arguments: - const uint8_t rho[]: output byte array for rho * - const polyveck *t1: pointer to output vector t1 * - uint8_t pk[]: byte array containing bit-packed pk **************************************************/ void unpack_pk(uint8_t rho[SEEDBYTES], polyveck *t1, const uint8_t pk[CRYPTO_PUBLICKEYBYTES]) { unsigned int i; for(i = 0; i < SEEDBYTES; ++i) rho[i] = pk[i]; pk += SEEDBYTES; for(i = 0; i < K; ++i) polyt1_unpack(&t1->vec[i], pk + i*POLYT1_PACKEDBYTES); } /************************************************* * Name: pack_sk * * Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2). * * Arguments: - uint8_t sk[]: output byte array * - const uint8_t rho[]: byte array containing rho * - const uint8_t tr[]: byte array containing tr * - const uint8_t key[]: byte array containing key * - const polyveck *t0: pointer to vector t0 * - const polyvecl *s1: pointer to vector s1 * - const polyveck *s2: pointer to vector s2 **************************************************/ void pack_sk(uint8_t sk[CRYPTO_SECRETKEYBYTES], const uint8_t rho[SEEDBYTES], const uint8_t tr[TRBYTES], const uint8_t key[SEEDBYTES], const polyveck *t0, const polyvecl *s1, const polyveck *s2) { unsigned int i; for(i = 0; i < SEEDBYTES; ++i) sk[i] = rho[i]; sk += SEEDBYTES; for(i = 0; i < SEEDBYTES; ++i) sk[i] = key[i]; sk += SEEDBYTES; for(i = 0; i < TRBYTES; ++i) sk[i] = tr[i]; sk += TRBYTES; for(i = 0; i < L; ++i) polyeta_pack(sk + i*POLYETA_PACKEDBYTES, &s1->vec[i]); sk += L*POLYETA_PACKEDBYTES; for(i = 0; i < K; ++i) polyeta_pack(sk + i*POLYETA_PACKEDBYTES, &s2->vec[i]); sk += K*POLYETA_PACKEDBYTES; for(i = 0; i < K; ++i) polyt0_pack(sk + i*POLYT0_PACKEDBYTES, &t0->vec[i]); } /************************************************* * Name: unpack_sk * * Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2). * * Arguments: - const uint8_t rho[]: output byte array for rho * - const uint8_t tr[]: output byte array for tr * - const uint8_t key[]: output byte array for key * - const polyveck *t0: pointer to output vector t0 * - const polyvecl *s1: pointer to output vector s1 * - const polyveck *s2: pointer to output vector s2 * - uint8_t sk[]: byte array containing bit-packed sk **************************************************/ void unpack_sk(uint8_t rho[SEEDBYTES], uint8_t tr[TRBYTES], uint8_t key[SEEDBYTES], polyveck *t0, polyvecl *s1, polyveck *s2, const uint8_t sk[CRYPTO_SECRETKEYBYTES]) { unsigned int i; for(i = 0; i < SEEDBYTES; ++i) rho[i] = sk[i]; sk += SEEDBYTES; for(i = 0; i < SEEDBYTES; ++i) key[i] = sk[i]; sk += SEEDBYTES; for(i = 0; i < TRBYTES; ++i) tr[i] = sk[i]; sk += TRBYTES; for(i=0; i < L; ++i) polyeta_unpack(&s1->vec[i], sk + i*POLYETA_PACKEDBYTES); sk += L*POLYETA_PACKEDBYTES; for(i=0; i < K; ++i) polyeta_unpack(&s2->vec[i], sk + i*POLYETA_PACKEDBYTES); sk += K*POLYETA_PACKEDBYTES; for(i=0; i < K; ++i) polyt0_unpack(&t0->vec[i], sk + i*POLYT0_PACKEDBYTES); } /************************************************* * Name: pack_sig * * Description: Bit-pack signature sig = (c, z, h). * * Arguments: - uint8_t sig[]: output byte array * - const uint8_t *c: pointer to challenge hash length SEEDBYTES * - const polyvecl *z: pointer to vector z * - const polyveck *h: pointer to hint vector h **************************************************/ void pack_sig(uint8_t sig[CRYPTO_BYTES], const uint8_t c[CTILDEBYTES], const polyvecl *z, const polyveck *h) { unsigned int i, j, k; for(i=0; i < CTILDEBYTES; ++i) sig[i] = c[i]; sig += CTILDEBYTES; for(i = 0; i < L; ++i) polyz_pack(sig + i*POLYZ_PACKEDBYTES, &z->vec[i]); sig += L*POLYZ_PACKEDBYTES; /* Encode h */ for(i = 0; i < OMEGA + K; ++i) sig[i] = 0; k = 0; for(i = 0; i < K; ++i) { for(j = 0; j < N; ++j) if(h->vec[i].coeffs[j] != 0) sig[k++] = j; sig[OMEGA + i] = k; } } /************************************************* * Name: unpack_sig * * Description: Unpack signature sig = (c, z, h). * * Arguments: - uint8_t *c: pointer to output challenge hash * - polyvecl *z: pointer to output vector z * - polyveck *h: pointer to output hint vector h * - const uint8_t sig[]: byte array containing * bit-packed signature * * Returns 1 in case of malformed signature; otherwise 0. **************************************************/ int unpack_sig(uint8_t c[CTILDEBYTES], polyvecl *z, polyveck *h, const uint8_t sig[CRYPTO_BYTES]) { unsigned int i, j, k; for(i = 0; i < CTILDEBYTES; ++i) c[i] = sig[i]; sig += CTILDEBYTES; for(i = 0; i < L; ++i) polyz_unpack(&z->vec[i], sig + i*POLYZ_PACKEDBYTES); sig += L*POLYZ_PACKEDBYTES; /* Decode h */ k = 0; for(i = 0; i < K; ++i) { for(j = 0; j < N; ++j) h->vec[i].coeffs[j] = 0; if(sig[OMEGA + i] < k || sig[OMEGA + i] > OMEGA) return 1; for(j = k; j < sig[OMEGA + i]; ++j) { /* Coefficients are ordered for strong unforgeability */ if(j > k && sig[j] <= sig[j-1]) return 1; h->vec[i].coeffs[sig[j]] = 1; } k = sig[OMEGA + i]; } /* Extra indices are zero for strong unforgeability */ for(j = k; j < OMEGA; ++j) if(sig[j]) return 1; return 0; } /*************** dilithium/ref/poly.c */ /************************************************* * Name: challenge * * Description: Implementation of H. Samples polynomial with TAU nonzero * coefficients in {-1,1} using the output stream of * SHAKE256(seed). * * Arguments: - poly *c: pointer to output polynomial * - const uint8_t mu[]: byte array containing seed of length CTILDEBYTES **************************************************/ static 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, CTILDEBYTES); shake256_finalize(&state); shake256_squeezeblocks(buf, 1, &state); signs = 0; for(i = 0; i < 8; ++i) signs |= (uint64_t)buf[i] << 8*i; pos = 8; for(i = 0; i < N; ++i) c->coeffs[i] = 0; for(i = N-TAU; i < N; ++i) { do { if(pos >= SHAKE256_RATE) { shake256_squeezeblocks(buf, 1, &state); pos = 0; } b = buf[pos++]; } while(b > i); c->coeffs[i] = c->coeffs[b]; c->coeffs[b] = 1 - 2*(signs & 1); signs >>= 1; } shake256_close(&state); } /*************** dilithium/ref/polyvec.c */ /************************************************* * Name: expand_mat * * Description: Implementation of ExpandA. Generates matrix A with uniformly * random coefficients a_{i,j} by performing rejection * sampling on the output stream of SHAKE128(rho|j|i) * * Arguments: - polyvecl mat[K]: output matrix * - const uint8_t rho[]: byte array containing seed rho **************************************************/ void polyvec_matrix_expand(polyvecl mat[K], const uint8_t rho[SEEDBYTES]) { unsigned int i, j; for(i = 0; i < K; ++i) for(j = 0; j < L; ++j) poly_uniform(&mat[i].vec[j], rho, (i << 8) + j); } void polyvec_matrix_pointwise_montgomery(polyveck *t, const polyvecl mat[K], const polyvecl *v) { unsigned int i; for(i = 0; i < K; ++i) polyvecl_pointwise_acc_montgomery(&t->vec[i], &mat[i], v); } /**************************************************************/ /************ Vectors of polynomials of length L **************/ /**************************************************************/ void polyvecl_uniform_eta(polyvecl *v, const uint8_t seed[CRHBYTES], uint16_t nonce) { unsigned int i; for(i = 0; i < L; ++i) poly_uniform_eta(&v->vec[i], seed, nonce++); } void polyvecl_uniform_gamma1(polyvecl *v, const uint8_t seed[CRHBYTES], uint16_t nonce) { unsigned int i; for(i = 0; i < L; ++i) poly_uniform_gamma1(&v->vec[i], seed, L*nonce + i); } void polyvecl_reduce(polyvecl *v) { unsigned int i; for(i = 0; i < L; ++i) poly_reduce(&v->vec[i]); } /************************************************* * Name: polyvecl_add * * Description: Add vectors of polynomials of length L. * No modular reduction is performed. * * Arguments: - polyvecl *w: pointer to output vector * - const polyvecl *u: pointer to first summand * - const polyvecl *v: pointer to second summand **************************************************/ void polyvecl_add(polyvecl *w, const polyvecl *u, const polyvecl *v) { unsigned int i; for(i = 0; i < L; ++i) poly_add(&w->vec[i], &u->vec[i], &v->vec[i]); } /************************************************* * Name: polyvecl_ntt * * Description: Forward NTT of all polynomials in vector of length L. Output * coefficients can be up to 16*Q larger than input coefficients. * * Arguments: - polyvecl *v: pointer to input/output vector **************************************************/ void polyvecl_ntt(polyvecl *v) { unsigned int i; for(i = 0; i < L; ++i) poly_ntt(&v->vec[i]); } void polyvecl_invntt_tomont(polyvecl *v) { unsigned int i; for(i = 0; i < L; ++i) poly_invntt_tomont(&v->vec[i]); } void polyvecl_pointwise_poly_montgomery(polyvecl *r, const poly *a, const polyvecl *v) { unsigned int i; for(i = 0; i < L; ++i) poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); } /************************************************* * Name: polyvecl_pointwise_acc_montgomery * * Description: Pointwise multiply vectors of polynomials of length L, multiply * resulting vector by 2^{-32} and add (accumulate) polynomials * in it. Input/output vectors are in NTT domain representation. * * Arguments: - poly *w: output polynomial * - const polyvecl *u: pointer to first input vector * - const polyvecl *v: pointer to second input vector **************************************************/ void polyvecl_pointwise_acc_montgomery(poly *w, const polyvecl *u, const polyvecl *v) { unsigned int i; poly t; poly_pointwise_montgomery(w, &u->vec[0], &v->vec[0]); for(i = 1; i < L; ++i) { poly_pointwise_montgomery(&t, &u->vec[i], &v->vec[i]); poly_add(w, w, &t); } } /************************************************* * Name: polyvecl_chknorm * * Description: Check infinity norm of polynomials in vector of length L. * Assumes input polyvecl to be reduced by polyvecl_reduce(). * * Arguments: - const polyvecl *v: pointer to vector * - int32_t B: norm bound * * Returns 0 if norm of all polynomials is strictly smaller than B <= (Q-1)/8 * and 1 otherwise. **************************************************/ int polyvecl_chknorm(const polyvecl *v, int32_t bound) { unsigned int i; for(i = 0; i < L; ++i) if(poly_chknorm(&v->vec[i], bound)) return 1; return 0; } /**************************************************************/ /************ Vectors of polynomials of length K **************/ /**************************************************************/ void polyveck_uniform_eta(polyveck *v, const uint8_t seed[CRHBYTES], uint16_t nonce) { unsigned int i; for(i = 0; i < K; ++i) poly_uniform_eta(&v->vec[i], seed, nonce++); } /************************************************* * Name: polyveck_reduce * * Description: Reduce coefficients of polynomials in vector of length K * to representatives in [-6283008,6283008]. * * Arguments: - polyveck *v: pointer to input/output vector **************************************************/ void polyveck_reduce(polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_reduce(&v->vec[i]); } /************************************************* * Name: polyveck_caddq * * Description: For all coefficients of polynomials in vector of length K * add Q if coefficient is negative. * * Arguments: - polyveck *v: pointer to input/output vector **************************************************/ void polyveck_caddq(polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_caddq(&v->vec[i]); } /************************************************* * Name: polyveck_add * * Description: Add vectors of polynomials of length K. * No modular reduction is performed. * * Arguments: - polyveck *w: pointer to output vector * - const polyveck *u: pointer to first summand * - const polyveck *v: pointer to second summand **************************************************/ void polyveck_add(polyveck *w, const polyveck *u, const polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_add(&w->vec[i], &u->vec[i], &v->vec[i]); } /************************************************* * Name: polyveck_sub * * Description: Subtract vectors of polynomials of length K. * No modular reduction is performed. * * Arguments: - polyveck *w: pointer to output vector * - const polyveck *u: pointer to first input vector * - const polyveck *v: pointer to second input vector to be * subtracted from first input vector **************************************************/ void polyveck_sub(polyveck *w, const polyveck *u, const polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_sub(&w->vec[i], &u->vec[i], &v->vec[i]); } /************************************************* * Name: polyveck_shiftl * * Description: Multiply vector of polynomials of Length K by 2^D without modular * reduction. Assumes input coefficients to be less than 2^{31-D}. * * Arguments: - polyveck *v: pointer to input/output vector **************************************************/ void polyveck_shiftl(polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_shiftl(&v->vec[i]); } /************************************************* * Name: polyveck_ntt * * Description: Forward NTT of all polynomials in vector of length K. Output * coefficients can be up to 16*Q larger than input coefficients. * * Arguments: - polyveck *v: pointer to input/output vector **************************************************/ void polyveck_ntt(polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_ntt(&v->vec[i]); } /************************************************* * Name: polyveck_invntt_tomont * * Description: Inverse NTT and multiplication by 2^{32} of polynomials * in vector of length K. Input coefficients need to be less * than 2*Q. * * Arguments: - polyveck *v: pointer to input/output vector **************************************************/ void polyveck_invntt_tomont(polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_invntt_tomont(&v->vec[i]); } void polyveck_pointwise_poly_montgomery(polyveck *r, const poly *a, const polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]); } /************************************************* * Name: polyveck_chknorm * * Description: Check infinity norm of polynomials in vector of length K. * Assumes input polyveck to be reduced by polyveck_reduce(). * * Arguments: - const polyveck *v: pointer to vector * - int32_t B: norm bound * * Returns 0 if norm of all polynomials are strictly smaller than B <= (Q-1)/8 * and 1 otherwise. **************************************************/ int polyveck_chknorm(const polyveck *v, int32_t bound) { unsigned int i; for(i = 0; i < K; ++i) if(poly_chknorm(&v->vec[i], bound)) return 1; return 0; } /************************************************* * Name: polyveck_power2round * * Description: For all coefficients a of polynomials in vector of length K, * compute a0, a1 such that a mod^+ Q = a1*2^D + a0 * with -2^{D-1} < a0 <= 2^{D-1}. Assumes coefficients to be * standard representatives. * * Arguments: - polyveck *v1: pointer to output vector of polynomials with * coefficients a1 * - polyveck *v0: pointer to output vector of polynomials with * coefficients a0 * - const polyveck *v: pointer to input vector **************************************************/ void polyveck_power2round(polyveck *v1, polyveck *v0, const polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]); } /************************************************* * Name: polyveck_decompose * * Description: For all coefficients a of polynomials in vector of length K, * compute high and low bits a0, a1 such a mod^+ Q = a1*ALPHA + a0 * with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (Q-1)/ALPHA where we * set a1 = 0 and -ALPHA/2 <= a0 = a mod Q - Q < 0. * Assumes coefficients to be standard representatives. * * Arguments: - polyveck *v1: pointer to output vector of polynomials with * coefficients a1 * - polyveck *v0: pointer to output vector of polynomials with * coefficients a0 * - const polyveck *v: pointer to input vector **************************************************/ void polyveck_decompose(polyveck *v1, polyveck *v0, const polyveck *v) { unsigned int i; for(i = 0; i < K; ++i) poly_decompose(&v1->vec[i], &v0->vec[i], &v->vec[i]); } /************************************************* * Name: polyveck_make_hint * * Description: Compute hint vector. * * Arguments: - polyveck *h: pointer to output vector * - const polyveck *v0: pointer to low part of input vector * - const polyveck *v1: pointer to high part of input vector * * Returns number of 1 bits. **************************************************/ unsigned int polyveck_make_hint(polyveck *h, const polyveck *v0, const polyveck *v1) { unsigned int i, s = 0; for(i = 0; i < K; ++i) s += poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]); return s; } /************************************************* * Name: polyveck_use_hint * * Description: Use hint vector to correct the high bits of input vector. * * Arguments: - polyveck *w: pointer to output vector of polynomials with * corrected high bits * - const polyveck *u: pointer to input vector * - const polyveck *h: pointer to input hint vector **************************************************/ void polyveck_use_hint(polyveck *w, const polyveck *u, const polyveck *h) { unsigned int i; for(i = 0; i < K; ++i) poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]); } void polyveck_pack_w1(uint8_t r[K*POLYW1_PACKEDBYTES], const polyveck *w1) { unsigned int i; for(i = 0; i < K; ++i) polyw1_pack(&r[i*POLYW1_PACKEDBYTES], &w1->vec[i]); } /*************** dilithium/ref/sign.c */ /************************************************* * Name: crypto_sign_keypair * * Description: Generates public and private key. * * Arguments: - uint8_t *pk: pointer to output public key (allocated * array of CRYPTO_PUBLICKEYBYTES bytes) * - uint8_t *sk: pointer to output private key (allocated * array of CRYPTO_SECRETKEYBYTES bytes) * * Returns 0 (success) **************************************************/ #ifndef DILITHIUM_INTERNAL_API_ONLY int crypto_sign_keypair(uint8_t *pk, uint8_t *sk) { uint8_t seedbuf[2*SEEDBYTES + CRHBYTES]; uint8_t tr[TRBYTES]; const uint8_t *rho, *rhoprime, *key; polyvecl mat[K]; polyvecl s1, s1hat; polyveck s2, t1, t0; /* Get randomness for rho, rhoprime and key */ randombytes(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 matrix */ polyvec_matrix_expand(mat, rho); /* Sample short vectors s1 and s2 */ polyvecl_uniform_eta(&s1, rhoprime, 0); polyveck_uniform_eta(&s2, rhoprime, L); /* 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); /* Extract t1 and write public key */ polyveck_caddq(&t1); polyveck_power2round(&t1, &t0, &t1); pack_pk(pk, rho, &t1); /* Compute H(rho, t1) and write secret key */ shake256(tr, TRBYTES, pk, CRYPTO_PUBLICKEYBYTES); pack_sk(sk, rho, tr, key, &t0, &s1, &s2); return 0; } #else int crypto_sign_keypair_internal(uint8_t *pk, uint8_t *sk, const uint8_t seed[SEEDBYTES]) { uint8_t seedbuf[2*SEEDBYTES + CRHBYTES]; uint8_t tr[TRBYTES]; const uint8_t *rho, *rhoprime, *key; polyvecl mat[K]; polyvecl s1, s1hat; polyveck s2, t1, t0; size_t i; /* Get randomness for rho, rhoprime and key */ for (i = 0; i < SEEDBYTES; i++) seedbuf[i] = seed[i]; 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 matrix */ polyvec_matrix_expand(mat, rho); /* Sample short vectors s1 and s2 */ polyvecl_uniform_eta(&s1, rhoprime, 0); polyveck_uniform_eta(&s2, rhoprime, L); /* 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); /* Extract t1 and write public key */ polyveck_caddq(&t1); polyveck_power2round(&t1, &t0, &t1); pack_pk(pk, rho, &t1); /* Compute H(rho, t1) and write secret key */ shake256(tr, TRBYTES, pk, CRYPTO_PUBLICKEYBYTES); pack_sk(sk, rho, tr, key, &t0, &s1, &s2); return 0; } #endif /************************************************* * Name: crypto_sign_signature_internal * * Description: Computes signature. Internal API. * * Arguments: - uint8_t *sig: pointer to output signature (of length CRYPTO_BYTES) * - 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 *pre: pointer to prefix string * - size_t prelen: length of prefix string * - uint8_t *rnd: pointer to random seed * - uint8_t *sk: pointer to bit-packed secret key * * Returns 0 (success) **************************************************/ int crypto_sign_signature_internal(uint8_t *sig, size_t *siglen, const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, const uint8_t rnd[RNDBYTES], const uint8_t *sk) { unsigned int n; uint8_t seedbuf[2*SEEDBYTES + TRBYTES + 2*CRHBYTES]; uint8_t *rho, *tr, *key, *mu, *rhoprime; uint16_t nonce = 0; polyvecl mat[K], s1, y, z; polyveck t0, s2, w1, w0, h; poly cp; keccak_state state; rho = seedbuf; tr = rho + SEEDBYTES; key = tr + TRBYTES; mu = key + SEEDBYTES; rhoprime = mu + CRHBYTES; unpack_sk(rho, tr, key, &t0, &s1, &s2, sk); /* Compute mu = CRH(tr, pre, msg) */ shake256_init(&state); shake256_absorb(&state, tr, TRBYTES); shake256_absorb(&state, pre, prelen); shake256_absorb(&state, m, mlen); shake256_finalize(&state); shake256_squeeze(mu, CRHBYTES, &state); shake256_close(&state); /* Compute rhoprime = CRH(key, rnd, mu) */ shake256_init(&state); shake256_absorb(&state, key, SEEDBYTES); shake256_absorb(&state, rnd, RNDBYTES); shake256_absorb(&state, mu, CRHBYTES); shake256_finalize(&state); shake256_squeeze(rhoprime, CRHBYTES, &state); shake256_close(&state); /* Expand matrix and transform vectors */ polyvec_matrix_expand(mat, rho); polyvecl_ntt(&s1); polyveck_ntt(&s2); polyveck_ntt(&t0); rej: /* Sample intermediate vector y */ polyvecl_uniform_gamma1(&y, rhoprime, nonce++); /* Matrix-vector multiplication */ z = y; polyvecl_ntt(&z); polyvec_matrix_pointwise_montgomery(&w1, mat, &z); polyveck_reduce(&w1); polyveck_invntt_tomont(&w1); /* Decompose w and call the random oracle */ polyveck_caddq(&w1); polyveck_decompose(&w1, &w0, &w1); polyveck_pack_w1(sig, &w1); shake256_init(&state); shake256_absorb(&state, mu, CRHBYTES); shake256_absorb(&state, sig, K*POLYW1_PACKEDBYTES); shake256_finalize(&state); shake256_squeeze(sig, CTILDEBYTES, &state); shake256_close(&state); poly_challenge(&cp, sig); poly_ntt(&cp); /* Compute z, reject if it reveals secret */ polyvecl_pointwise_poly_montgomery(&z, &cp, &s1); polyvecl_invntt_tomont(&z); polyvecl_add(&z, &z, &y); polyvecl_reduce(&z); if(polyvecl_chknorm(&z, GAMMA1 - BETA)) goto rej; /* Check that subtracting cs2 does not change high bits of w and low bits * do not reveal secret information */ polyveck_pointwise_poly_montgomery(&h, &cp, &s2); polyveck_invntt_tomont(&h); polyveck_sub(&w0, &w0, &h); polyveck_reduce(&w0); if(polyveck_chknorm(&w0, GAMMA2 - BETA)) goto rej; /* Compute hints for w1 */ polyveck_pointwise_poly_montgomery(&h, &cp, &t0); polyveck_invntt_tomont(&h); polyveck_reduce(&h); if(polyveck_chknorm(&h, GAMMA2)) goto rej; polyveck_add(&w0, &w0, &h); n = polyveck_make_hint(&h, &w0, &w1); if(n > OMEGA) goto rej; /* Write signature */ pack_sig(sig, sig, &z, &h); *siglen = CRYPTO_BYTES; return 0; } /************************************************* * Name: crypto_sign_signature * * Description: Computes signature. * * Arguments: - uint8_t *sig: pointer to output signature (of length CRYPTO_BYTES) * - 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 contex string * - size_t ctxlen: length of contex string * - uint8_t *sk: pointer to bit-packed secret key * * Returns 0 (success) or -1 (context string too long) **************************************************/ #ifndef DILITHIUM_INTERNAL_API_ONLY 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) { size_t i; uint8_t pre[257]; uint8_t rnd[RNDBYTES]; if(ctxlen > 255) return -1; /* Prepare pre = (0, ctxlen, ctx) */ pre[0] = 0; pre[1] = ctxlen; for(i = 0; i < ctxlen; i++) pre[2 + i] = ctx[i]; #ifdef DILITHIUM_RANDOMIZED_SIGNING randombytes(rnd, RNDBYTES); #else for(i=0;i<RNDBYTES;i++) rnd[i] = 0; #endif crypto_sign_signature_internal(sig,siglen,m,mlen,pre,2+ctxlen,rnd,sk); return 0; } #endif /************************************************* * Name: crypto_sign * * Description: Compute signed message. * * Arguments: - uint8_t *sm: pointer to output signed message (allocated * array with CRYPTO_BYTES + mlen bytes), * can be equal to m * - size_t *smlen: pointer to output length of signed * 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) or -1 (context string too long) **************************************************/ #ifndef DILITHIUM_INTERNAL_API_ONLY 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]; ret = crypto_sign_signature(sm, smlen, sm + CRYPTO_BYTES, mlen, ctx, ctxlen, sk); *smlen += mlen; return ret; } #endif /************************************************* * Name: crypto_sign_verify_internal * * Description: Verifies signature. Internal API. * * Arguments: - uint8_t *m: pointer to input signature * - size_t siglen: length of signature * - const uint8_t *m: pointer to message * - size_t mlen: length of message * - const uint8_t *pre: pointer to prefix string * - size_t prelen: length of prefix 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_internal(const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen, const uint8_t *pk) { unsigned int i; uint8_t buf[K*POLYW1_PACKEDBYTES]; uint8_t rho[SEEDBYTES]; uint8_t mu[CRHBYTES]; uint8_t c[CTILDEBYTES]; uint8_t c2[CTILDEBYTES]; poly cp; polyvecl mat[K], z; polyveck t1, w1, h; keccak_state 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), pre, msg) */ shake256(mu, TRBYTES, pk, CRYPTO_PUBLICKEYBYTES); shake256_init(&state); shake256_absorb(&state, mu, TRBYTES); shake256_absorb(&state, pre, prelen); shake256_absorb(&state, m, mlen); shake256_finalize(&state); shake256_squeeze(mu, CRHBYTES, &state); shake256_close(&state); /* Matrix-vector multiplication; compute Az - c2^dt1 */ poly_challenge(&cp, c); polyvec_matrix_expand(mat, rho); 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); polyveck_sub(&w1, &w1, &t1); polyveck_reduce(&w1); polyveck_invntt_tomont(&w1); /* Reconstruct w1 */ polyveck_caddq(&w1); polyveck_use_hint(&w1, &w1, &h); polyveck_pack_w1(buf, &w1); /* Call random oracle and verify challenge */ shake256_init(&state); shake256_absorb(&state, mu, CRHBYTES); shake256_absorb(&state, buf, K*POLYW1_PACKEDBYTES); shake256_finalize(&state); shake256_squeeze(c2, CTILDEBYTES, &state); shake256_close(&state); for(i = 0; i < CTILDEBYTES; ++i) if(c[i] != c2[i]) return -1; return 0; } /************************************************* * Name: crypto_sign_verify * * Description: Verifies signature. * * Arguments: - uint8_t *m: pointer to input signature * - 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 **************************************************/ #ifndef DILITHIUM_INTERNAL_API_ONLY 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) { size_t i; uint8_t pre[257]; if(ctxlen > 255) return -1; pre[0] = 0; pre[1] = ctxlen; for(i = 0; i < ctxlen; i++) pre[2 + i] = ctx[i]; return crypto_sign_verify_internal(sig,siglen,m,mlen,pre,2+ctxlen,pk); } #endif /************************************************* * Name: crypto_sign_open * * Description: Verify signed message. * * Arguments: - uint8_t *m: pointer to output message (allocated * array with smlen bytes), can be equal to sm * - 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 **************************************************/ #ifndef DILITHIUM_INTERNAL_API_ONLY 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, ctx, ctxlen, pk)) goto badsig; else { /* All good, copy msg, return 0 */ for(i = 0; i < *mlen; ++i) m[i] = sm[CRYPTO_BYTES + i]; return 0; } badsig: /* Signature verification failed */ *mlen = 0; for(i = 0; i < smlen; ++i) m[i] = 0; return -1; } #endif #undef DILITHIUM_MODE #undef CRYPTO_PUBLICKEYBYTES #undef CRYPTO_SECRETKEYBYTES #undef CRYPTO_BYTES #undef POLYZ_PACKEDBYTES #undef POLYW1_PACKEDBYTES #undef POLYETA_PACKEDBYTES #undef CRYPTO_ALGNAME #undef K #undef L #undef ETA #undef TAU #undef BETA #undef GAMMA1 #undef GAMMA2 #undef OMEGA #undef CTILDEBYTES #undef poly_decompose #undef poly_make_hint #undef poly_use_hint #undef poly_uniform_eta #undef poly_uniform_gamma1 #undef polyz_pack #undef polyz_unpack #undef polyeta_pack #undef polyeta_unpack #undef polyw1_pack #undef polyvecl #undef polyveck #undef pack_pk #undef unpack_pk #undef pack_sk #undef unpack_sk #undef pack_sig #undef unpack_sig #undef poly_challenge #undef polyvec_matrix_expand #undef polyvec_matrix_pointwise_montgomery #undef polyveck_power2round #undef polyveck_make_hint #undef polyveck_use_hint #undef polyvecl_uniform_eta #undef polyvecl_uniform_gamma1 #undef polyvecl_reduce #undef polyvecl_add #undef polyvecl_ntt #undef polyvecl_invntt_tomont #undef polyvecl_pointwise_poly_montgomery #undef polyvecl_pointwise_acc_montgomery #undef polyvecl_chknorm #undef polyveck_uniform_eta #undef polyveck_reduce #undef polyveck_caddq #undef polyveck_add #undef polyveck_sub #undef polyveck_shiftl #undef polyveck_ntt #undef polyveck_invntt_tomont #undef polyveck_pointwise_poly_montgomery #undef polyveck_chknorm #undef polyveck_pack_w1 #undef polyveck_decompose #undef crypto_sign_keypair #undef crypto_sign_keypair_internal #undef crypto_sign_signature_internal #undef crypto_sign_signature #undef crypto_sign #undef crypto_sign_verify_internal #undef crypto_sign_verify #undef crypto_sign_open