mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-01-27 11:52:21 +01:00
10339 lines
351 KiB
C
10339 lines
351 KiB
C
/* dilithium.c
|
|
*
|
|
* Copyright (C) 2006-2025 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
/* Based on ed448.c and Reworked for Dilithium by Anthony Hu.
|
|
* WolfSSL implementation by Sean Parkinson.
|
|
*/
|
|
|
|
/* Possible Dilithium/ML-DSA options:
|
|
*
|
|
* HAVE_DILITHIUM Default: OFF
|
|
* Enables the code in this file to be compiled.
|
|
* WOLFSSL_WC_DILITHIUM Default: OFF
|
|
* Compiles the wolfSSL implementation of dilithium.
|
|
*
|
|
* WOLFSSL_NO_ML_DSA_44 Default: OFF
|
|
* Does not compile in parameter set ML-DSA-44 and any code specific to that
|
|
* parameter set.
|
|
* WOLFSSL_NO_ML_DSA_65 Default: OFF
|
|
* Does not compile in parameter set ML-DSA-65 and any code specific to that
|
|
* parameter set.
|
|
* WOLFSSL_NO_ML_DSA_87 Default: OFF
|
|
* Does not compile in parameter set ML-DSA-87 and any code specific to that
|
|
* parameter set.
|
|
*
|
|
* WOLFSSL_DILITHIUM_NO_LARGE_CODE Default: OFF
|
|
* Compiles smaller, fast code with speed trade-off.
|
|
* WOLFSSL_DILITHIUM_SMALL Default: OFF
|
|
* Compiles to small code size with a speed trade-off.
|
|
* WOLFSSL_DILITHIUM_VERIFY_ONLY Default: OFF
|
|
* Compiles in only the verification and public key operations.
|
|
* WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM Default: OFF
|
|
* Compiles verification implementation that uses smaller amounts of memory.
|
|
* WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC Default: OFF
|
|
* Only works with WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM.
|
|
* Don't allocate memory with XMALLOC. Memory is pinned against key.
|
|
* WOLFSSL_DILITHIUM_ASSIGN_KEY Default: OFF
|
|
* Key data is assigned into Dilithium key rather than copied.
|
|
* Life of key data passed in is tightly coupled to life of Dilithium key.
|
|
* Cannot be used when make key is enabled.
|
|
* WOLFSSL_DILITHIUM_SIGN_SMALL_MEM Default: OFF
|
|
* Compiles signature implementation that uses smaller amounts of memory but
|
|
* is considerably slower.
|
|
* WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC Default: OFF
|
|
* Compiles signature implementation that uses smaller amounts of memory but
|
|
* is considerably slower. Allocates vectors and decodes private key data
|
|
* into them upfront.
|
|
* WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A Default: OFF
|
|
* Compiles signature implementation that uses smaller amounts of memory but
|
|
* is slower. Allocates matrix A and calculates it upfront.
|
|
* WOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM Default: OFF
|
|
* Compiles key generation implementation that uses smaller amounts of memory
|
|
* but is slower.
|
|
* WOLFSSL_DILITHIUM_SMALL_MEM_POLY64 Default: OFF
|
|
* Compiles the small memory implementations to use a 64-bit polynomial.
|
|
* Uses 2KB of memory but is slightly quicker (2.75-7%).
|
|
*
|
|
* WOLFSSL_DILITHIUM_ALIGNMENT Default: 8
|
|
* Use to indicate whether loading and storing of words needs to be aligned.
|
|
* Default is to use WOLFSSL_GENERAL_ALIGNMENT - should be 4 on some ARM CPUs.
|
|
* Set this value explicitly if specific Dilithium implementation alignment is
|
|
* needed.
|
|
*
|
|
* WOLFSSL_DILITHIUM_NO_ASN1 Default: OFF
|
|
* Disables any ASN.1 encoding or decoding code.
|
|
* WOLFSSL_DILITHIUM_REVERSE_HASH_OID Default: OFF
|
|
* Reverse the DER encoded hash oid when signing and verifying a pre-hashed
|
|
* message.
|
|
*
|
|
* WC_DILITHIUM_CACHE_MATRIX_A Default: OFF
|
|
* Enable caching of the A matrix on import.
|
|
* Less work is required in sign and verify operations.
|
|
* WC_DILITHIUM_CACHE_PRIV_VECTORS Default: OFF
|
|
* Enable caching of private key vectors on import.
|
|
* Enables WC_DILITHIUM_CACHE_MATRIX_A.
|
|
* Less work is required in sign operations.
|
|
* WC_DILITHIUM_CACHE_PUB_VECTORS Default: OFF
|
|
* Enable caching of public key vectors on import.
|
|
* Enables WC_DILITHIUM_CACHE_MATRIX_A.
|
|
* Less work is required in sign operations.
|
|
* WC_DILITHIUM_FIXED_ARRAY Default: OFF
|
|
* Make the matrix and vectors of cached data fixed arrays that have
|
|
* maximumal sizes for the configured parameters.
|
|
* Useful in low dynamic memory situations.
|
|
*
|
|
* WOLFSSL_DILITHIUM_SIGN_CHECK_Y Default: OFF
|
|
* Check vector y is in required range as an early check on valid vector z.
|
|
* Falsely reports invalid in approximately 1-2% of checks.
|
|
* All valid reports are true.
|
|
* Fast fail gives faster signing times on average.
|
|
* DO NOT enable this if implementation must be conformant to FIPS 204.
|
|
* WOLFSSL_DILITHIUM_SIGN_CHECK_W0 Default: OFF
|
|
* Check vector w0 is in required range as an early check on valid vector r0.
|
|
* Falsely reports invalid in approximately 3-5% of checks.
|
|
* All valid reports are true.
|
|
* Fast fail gives faster signing times on average.
|
|
* DO NOT enable this if implementation must be conformant to FIPS 204.
|
|
*
|
|
* DILITHIUM_MUL_SLOW Default: OFF
|
|
* Define when multiplying by Q / 44 is slower than masking.
|
|
* Only applies to ML-DSA-44.
|
|
* DILITHIUM_MUL_44_SLOW Default: OFF
|
|
* Define when multiplying by 44 is slower than by 11.
|
|
* Only applies to ML-DSA-44.
|
|
* DILITHIUM_MUL_11_SLOW Default: OFF
|
|
* Define when multiplying by 11 is slower than adding and shifting.
|
|
* Only applies to ML-DSA-44.
|
|
* DILITHIUM_MUL_QINV_SLOW Default: OFF
|
|
* Define when multiplying by QINV 0x3802001 is slower than add, subtract and
|
|
* shift equivalent.
|
|
* DILITHIUM_MUL_Q_SLOW Default: OFF
|
|
* Define when multiplying by Q 0x7fe001 is slower than add, subtract and
|
|
* shift equivalent.
|
|
*/
|
|
|
|
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
|
|
#include <wolfssl/wolfcrypt/asn.h>
|
|
#endif
|
|
|
|
#if defined(HAVE_DILITHIUM)
|
|
|
|
#ifdef HAVE_LIBOQS
|
|
#include <oqs/oqs.h>
|
|
#endif
|
|
|
|
#include <wolfssl/wolfcrypt/dilithium.h>
|
|
#include <wolfssl/wolfcrypt/hash.h>
|
|
#include <wolfssl/wolfcrypt/sha3.h>
|
|
#ifdef NO_INLINE
|
|
#include <wolfssl/wolfcrypt/misc.h>
|
|
#else
|
|
#define WOLFSSL_MISC_INCLUDED
|
|
#include <wolfcrypt/src/misc.c>
|
|
#endif
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)
|
|
#define WOLFSSL_DILITHIUM_SIGN_SMALL_MEM
|
|
#endif
|
|
#if defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)
|
|
#define WOLFSSL_DILITHIUM_SIGN_SMALL_MEM
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
|
|
#error "PRECALC and PRECALC_A is equivalent to non small mem"
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
|
|
#ifdef DEBUG_DILITHIUM
|
|
void print_polys(const char* name, const sword32* a, int d1, int d2);
|
|
void print_polys(const char* name, const sword32* a, int d1, int d2)
|
|
{
|
|
int i;
|
|
int j;
|
|
int k;
|
|
|
|
fprintf(stderr, "%s\n", name);
|
|
for (i = 0; i < d1; i++) {
|
|
for (j = 0; j < d2; j++) {
|
|
for (k = 0; k < 256; k++) {
|
|
fprintf(stderr, "%9d,", a[(i*d2*256) + (j*256) + k]);
|
|
if ((k % 8) == 7) fprintf(stderr, "\n");
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void print_data(const char* name, const byte* d, int len);
|
|
void print_data(const char* name, const byte* d, int len)
|
|
{
|
|
int i;
|
|
|
|
fprintf(stderr, "%s\n", name);
|
|
for (i = 0; i < len; i++) {
|
|
fprintf(stderr, "0x%02x,", d[i]);
|
|
if ((i % 16) == 15) fprintf(stderr, "\n");
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
#endif
|
|
|
|
#if defined(WOLFSSL_NO_ML_DSA_44) && defined(WOLFSSL_NO_ML_DSA_65) && \
|
|
defined(WOLFSSL_NO_ML_DSA_87)
|
|
#error "No Dilithium parameters chosen"
|
|
#endif
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_ASSIGN_KEY) && \
|
|
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY)
|
|
#error "Cannot use assign key when making keys"
|
|
#endif
|
|
|
|
|
|
/* Number of bytes from first block to use for sign. */
|
|
#define DILITHIUM_SIGN_BYTES 8
|
|
|
|
|
|
/* Length of seed in bytes when generating y. */
|
|
#define DILITHIUM_Y_SEED_SZ (DILITHIUM_PRIV_RAND_SEED_SZ + 2)
|
|
|
|
|
|
/* Length of seed in bytes used in generating matrix a. */
|
|
#define DILITHIUM_GEN_A_SEED_SZ (DILITHIUM_PUB_SEED_SZ + 2)
|
|
/* Length of seed in bytes used in generating vectors s1 and s2. */
|
|
#define DILITHIUM_GEN_S_SEED_SZ (DILITHIUM_PRIV_SEED_SZ + 2)
|
|
|
|
|
|
/* MAX: (256 * 8 / (17 + 1)) = 576, or ((256 * 8 / (19 + 1)) = 640
|
|
* but need blocks of 17 * 8 bytes: 5 * 17 * 8 = 680 */
|
|
#define DILITHIUM_MAX_V_BLOCKS 5
|
|
/* Maximum number of bytes to generate into v to make y. */
|
|
#define DILITHIUM_MAX_V (DILITHIUM_MAX_V_BLOCKS * 8 * 17)
|
|
|
|
|
|
/* 2 blocks, each block 136 bytes = 272 bytes.
|
|
* ETA 2: Min req is 128 but reject rate is 2 in 16 so we need 146.3 on average.
|
|
* ETA 4: Min req is 128 but reject rate is 7 in 16 so we need 227.6 on average.
|
|
*/
|
|
#define DILITHIUM_GEN_S_NBLOCKS 2
|
|
/* Number of bytes to generate with SHAKE-256 when generating s1 and s2. */
|
|
#define DILITHIUM_GEN_S_BYTES \
|
|
(DILITHIUM_GEN_S_NBLOCKS * WC_SHA3_256_COUNT * 8)
|
|
/* Number of bytes to a block of SHAKE-256 when generating s1 and s2. */
|
|
#define DILITHIUM_GEN_S_BLOCK_BYTES (WC_SHA3_256_COUNT * 8)
|
|
|
|
/* Length of the hash OID to include in pre-hash message. */
|
|
#define DILITHIUM_HASH_OID_LEN 11
|
|
|
|
|
|
/* The ML-DSA parameters sets. */
|
|
static const wc_dilithium_params dilithium_params[] = {
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
{ WC_ML_DSA_44, PARAMS_ML_DSA_44_K, PARAMS_ML_DSA_44_L,
|
|
PARAMS_ML_DSA_44_ETA, PARAMS_ML_DSA_44_ETA_BITS,
|
|
PARAMS_ML_DSA_44_TAU, PARAMS_ML_DSA_44_BETA, PARAMS_ML_DSA_44_OMEGA,
|
|
PARAMS_ML_DSA_44_LAMBDA,
|
|
PARAMS_ML_DSA_44_GAMMA1_BITS, PARAMS_ML_DSA_44_GAMMA2,
|
|
PARAMS_ML_DSA_44_W1_ENC_SZ, PARAMS_ML_DSA_44_A_SIZE,
|
|
PARAMS_ML_DSA_44_S1_SIZE, PARAMS_ML_DSA_44_S1_ENC_SIZE,
|
|
PARAMS_ML_DSA_44_S2_SIZE, PARAMS_ML_DSA_44_S2_ENC_SIZE,
|
|
PARAMS_ML_DSA_44_Z_ENC_SIZE,
|
|
PARAMS_ML_DSA_44_PK_SIZE, PARAMS_ML_DSA_44_SIG_SIZE },
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
{ WC_ML_DSA_65, PARAMS_ML_DSA_65_K, PARAMS_ML_DSA_65_L,
|
|
PARAMS_ML_DSA_65_ETA, PARAMS_ML_DSA_65_ETA_BITS,
|
|
PARAMS_ML_DSA_65_TAU, PARAMS_ML_DSA_65_BETA, PARAMS_ML_DSA_65_OMEGA,
|
|
PARAMS_ML_DSA_65_LAMBDA,
|
|
PARAMS_ML_DSA_65_GAMMA1_BITS, PARAMS_ML_DSA_65_GAMMA2,
|
|
PARAMS_ML_DSA_65_W1_ENC_SZ, PARAMS_ML_DSA_65_A_SIZE,
|
|
PARAMS_ML_DSA_65_S1_SIZE, PARAMS_ML_DSA_65_S1_ENC_SIZE,
|
|
PARAMS_ML_DSA_65_S2_SIZE, PARAMS_ML_DSA_65_S2_ENC_SIZE,
|
|
PARAMS_ML_DSA_65_Z_ENC_SIZE,
|
|
PARAMS_ML_DSA_65_PK_SIZE, PARAMS_ML_DSA_65_SIG_SIZE },
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_87
|
|
{ WC_ML_DSA_87, PARAMS_ML_DSA_87_K, PARAMS_ML_DSA_87_L,
|
|
PARAMS_ML_DSA_87_ETA, PARAMS_ML_DSA_87_ETA_BITS,
|
|
PARAMS_ML_DSA_87_TAU, PARAMS_ML_DSA_87_BETA, PARAMS_ML_DSA_87_OMEGA,
|
|
PARAMS_ML_DSA_87_LAMBDA,
|
|
PARAMS_ML_DSA_87_GAMMA1_BITS, PARAMS_ML_DSA_87_GAMMA2,
|
|
PARAMS_ML_DSA_87_W1_ENC_SZ, PARAMS_ML_DSA_87_A_SIZE,
|
|
PARAMS_ML_DSA_87_S1_SIZE, PARAMS_ML_DSA_87_S1_ENC_SIZE,
|
|
PARAMS_ML_DSA_87_S2_SIZE, PARAMS_ML_DSA_87_S2_ENC_SIZE,
|
|
PARAMS_ML_DSA_87_Z_ENC_SIZE,
|
|
PARAMS_ML_DSA_87_PK_SIZE, PARAMS_ML_DSA_87_SIG_SIZE },
|
|
#endif
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
{ WC_ML_DSA_44_DRAFT, PARAMS_ML_DSA_44_K, PARAMS_ML_DSA_44_L,
|
|
PARAMS_ML_DSA_44_ETA, PARAMS_ML_DSA_44_ETA_BITS,
|
|
PARAMS_ML_DSA_44_TAU, PARAMS_ML_DSA_44_BETA, PARAMS_ML_DSA_44_OMEGA,
|
|
PARAMS_ML_DSA_44_LAMBDA,
|
|
PARAMS_ML_DSA_44_GAMMA1_BITS, PARAMS_ML_DSA_44_GAMMA2,
|
|
PARAMS_ML_DSA_44_W1_ENC_SZ, PARAMS_ML_DSA_44_A_SIZE,
|
|
PARAMS_ML_DSA_44_S1_SIZE, PARAMS_ML_DSA_44_S1_ENC_SIZE,
|
|
PARAMS_ML_DSA_44_S2_SIZE, PARAMS_ML_DSA_44_S2_ENC_SIZE,
|
|
PARAMS_ML_DSA_44_Z_ENC_SIZE,
|
|
PARAMS_ML_DSA_44_PK_SIZE, PARAMS_ML_DSA_44_SIG_SIZE },
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
{ WC_ML_DSA_65_DRAFT, PARAMS_ML_DSA_65_K, PARAMS_ML_DSA_65_L,
|
|
PARAMS_ML_DSA_65_ETA, PARAMS_ML_DSA_65_ETA_BITS,
|
|
PARAMS_ML_DSA_65_TAU, PARAMS_ML_DSA_65_BETA, PARAMS_ML_DSA_65_OMEGA,
|
|
PARAMS_ML_DSA_65_LAMBDA,
|
|
PARAMS_ML_DSA_65_GAMMA1_BITS, PARAMS_ML_DSA_65_GAMMA2,
|
|
PARAMS_ML_DSA_65_W1_ENC_SZ, PARAMS_ML_DSA_65_A_SIZE,
|
|
PARAMS_ML_DSA_65_S1_SIZE, PARAMS_ML_DSA_65_S1_ENC_SIZE,
|
|
PARAMS_ML_DSA_65_S2_SIZE, PARAMS_ML_DSA_65_S2_ENC_SIZE,
|
|
PARAMS_ML_DSA_65_Z_ENC_SIZE,
|
|
PARAMS_ML_DSA_65_PK_SIZE, PARAMS_ML_DSA_65_SIG_SIZE },
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_87
|
|
{ WC_ML_DSA_87_DRAFT, PARAMS_ML_DSA_87_K, PARAMS_ML_DSA_87_L,
|
|
PARAMS_ML_DSA_87_ETA, PARAMS_ML_DSA_87_ETA_BITS,
|
|
PARAMS_ML_DSA_87_TAU, PARAMS_ML_DSA_87_BETA, PARAMS_ML_DSA_87_OMEGA,
|
|
PARAMS_ML_DSA_87_LAMBDA,
|
|
PARAMS_ML_DSA_87_GAMMA1_BITS, PARAMS_ML_DSA_87_GAMMA2,
|
|
PARAMS_ML_DSA_87_W1_ENC_SZ, PARAMS_ML_DSA_87_A_SIZE,
|
|
PARAMS_ML_DSA_87_S1_SIZE, PARAMS_ML_DSA_87_S1_ENC_SIZE,
|
|
PARAMS_ML_DSA_87_S2_SIZE, PARAMS_ML_DSA_87_S2_ENC_SIZE,
|
|
PARAMS_ML_DSA_87_Z_ENC_SIZE,
|
|
PARAMS_ML_DSA_87_PK_SIZE, PARAMS_ML_DSA_87_SIG_SIZE },
|
|
#endif
|
|
#endif
|
|
};
|
|
/* Number of ML-DSA parameter sets compiled in. */
|
|
#define DILITHIUM_PARAMS_CNT \
|
|
((unsigned int)(sizeof(dilithium_params) / sizeof(wc_dilithium_params)))
|
|
|
|
/* Get the ML-DSA parameters that match the level.
|
|
*
|
|
* @param [in] level Level required.
|
|
* @param [out] params Parameter set.
|
|
* @return 0 on success.
|
|
* @return NOT_COMPILED_IN when parameters at level are not compiled in.
|
|
*/
|
|
static int dilithium_get_params(int level, const wc_dilithium_params** params)
|
|
{
|
|
unsigned int i;
|
|
int ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
|
|
|
|
for (i = 0; i < DILITHIUM_PARAMS_CNT; i++) {
|
|
if (dilithium_params[i].level == level) {
|
|
*params = &dilithium_params[i];
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Hash operations
|
|
******************************************************************************/
|
|
|
|
/* 256-bit hash using SHAKE-256.
|
|
*
|
|
* FIPS 204. 8.3: H(v,d) <- SHAKE256(v,d)
|
|
*
|
|
* @param [in, out] shake256 SHAKE-256 object.
|
|
* @param [in] data Buffer holding data to hash.
|
|
* @param [in] dataLen Length of data to hash in bytes.
|
|
* @param [out] hash Buffer to hold hash result.
|
|
* @param [in] hashLen Number of bytes of hash to return.
|
|
* @return 0 on success.
|
|
* @return Negative on error.
|
|
*/
|
|
static int dilithium_shake256(wc_Shake* shake256, const byte* data,
|
|
word32 dataLen, byte* hash, word32 hashLen)
|
|
{
|
|
int ret;
|
|
|
|
/* Initialize SHAKE-256 operation. */
|
|
ret = wc_InitShake256(shake256, NULL, INVALID_DEVID);
|
|
if (ret == 0) {
|
|
/* Update with data. */
|
|
ret = wc_Shake256_Update(shake256, data, dataLen);
|
|
}
|
|
if (ret == 0) {
|
|
/* Compute hash of data. */
|
|
ret = wc_Shake256_Final(shake256, hash, hashLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* 256-bit hash using SHAKE-256.
|
|
*
|
|
* FIPS 204. 8.3: H(v,d) <- SHAKE256(v,d)
|
|
*
|
|
* @param [in, out] shake256 SHAKE-256 object.
|
|
* @param [in] data1 First block of data to hash.
|
|
* @param [in] data1Len Length of first block in bytes.
|
|
* @param [in] data2 Second block of data to hash.
|
|
* @param [in] data2Len Length of second block in bytes.
|
|
* @param [out] hash Buffer to hold hash result.
|
|
* @param [in] hashLen Number of bytes of hash to return.
|
|
* @return 0 on success.
|
|
* @return Negative on error.
|
|
*/
|
|
static int dilithium_hash256(wc_Shake* shake256, const byte* data1,
|
|
word32 data1Len, const byte* data2, word32 data2Len, byte* hash,
|
|
word32 hashLen)
|
|
{
|
|
int ret;
|
|
|
|
/* Initialize SHAKE-256 operation. */
|
|
ret = wc_InitShake256(shake256, NULL, INVALID_DEVID);
|
|
if (ret == 0) {
|
|
/* Update with first data. */
|
|
ret = wc_Shake256_Update(shake256, data1, data1Len);
|
|
}
|
|
if (ret == 0) {
|
|
/* Update with second data. */
|
|
ret = wc_Shake256_Update(shake256, data2, data2Len);
|
|
}
|
|
if (ret == 0) {
|
|
/* Compute hash of data. */
|
|
ret = wc_Shake256_Final(shake256, hash, hashLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || !defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
|
/* 256-bit hash of context and message using SHAKE-256.
|
|
*
|
|
* FIPS 204. 5.2: Algorithm 2 ML-DSA.Sign(sk, M, ctx)
|
|
* ...
|
|
* 10: M' <- BytesToBits(IntegerToBytes(0, 1) || IntegerToBytes(|ctx|, 1) ||
|
|
* ctx) || M
|
|
* ...
|
|
*
|
|
* FIPS 204. 6.2: Algorithm 7 ML-DSA.Sign_internal(sk, M', rnd)
|
|
* ...
|
|
* 6: mu <- H(BytesToBits(tr)||M', 64))
|
|
* ...
|
|
*
|
|
* @param [in, out] shake256 SHAKE-256 object.
|
|
* @param [in] tr Public key hash.
|
|
* @param [in] trLen Length of public key hash in bytes.
|
|
* @param [in] preHash 0 when message was not hashed,
|
|
* 1 when message was hashed.
|
|
* @param [in] ctx Context of signature.
|
|
* @param [in] ctxLen Length of context of signature in bytes.
|
|
* @param [in] ctx Message to sign.
|
|
* @param [in] ctxLen Length of message to sign in bytes.
|
|
* @param [out] hash Buffer to hold hash result.
|
|
* @param [in] hashLen Number of bytes of hash to return.
|
|
* @return 0 on success.
|
|
* @return Negative on error.
|
|
*/
|
|
static int dilithium_hash256_ctx_msg(wc_Shake* shake256, const byte* tr,
|
|
byte trLen, byte preHash, const byte* ctx, byte ctxLen, const byte* msg,
|
|
word32 msgLen, byte* hash, word32 hashLen)
|
|
{
|
|
int ret;
|
|
byte prefix[2];
|
|
|
|
prefix[0] = preHash;
|
|
prefix[1] = ctxLen;
|
|
|
|
/* Initialize SHAKE-256 operation. */
|
|
ret = wc_InitShake256(shake256, NULL, INVALID_DEVID);
|
|
if (ret == 0) {
|
|
/* Update with public key hash. */
|
|
ret = wc_Shake256_Update(shake256, tr, trLen);
|
|
}
|
|
if (ret == 0) {
|
|
/* Update with context prefix - 0 | ctxLen. */
|
|
ret = wc_Shake256_Update(shake256, prefix, (word32)sizeof(prefix));
|
|
}
|
|
if (ret == 0) {
|
|
/* Update with context. */
|
|
ret = wc_Shake256_Update(shake256, ctx, ctxLen);
|
|
}
|
|
if (ret == 0) {
|
|
/* Update with message. */
|
|
ret = wc_Shake256_Update(shake256, msg, msgLen);
|
|
}
|
|
if (ret == 0) {
|
|
/* Compute hash of data. */
|
|
ret = wc_Shake256_Final(shake256, hash, hashLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Get the OID for the digest hash.
|
|
*
|
|
* @param [in] hash Hash algorithm.
|
|
* @param [out] oidBuffer Buffer to hold OID.
|
|
* @param [out] oidLen Length of OID in buffer.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG if hash algorithm not known.
|
|
*/
|
|
static int dilithium_get_hash_oid(int hash, byte* oidBuffer, word32* oidLen)
|
|
{
|
|
int ret = 0;
|
|
const byte* oid;
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
|
|
|
|
oid = OidFromId((word32)wc_HashGetOID((enum wc_HashType)hash), oidHashType,
|
|
oidLen);
|
|
if ((oid != NULL) && (*oidLen <= DILITHIUM_HASH_OID_LEN - 2)) {
|
|
#ifndef WOLFSSL_DILITHIUM_REVERSE_HASH_OID
|
|
oidBuffer[0] = 0x06; /* ObjectID */
|
|
oidBuffer[1] = (byte)*oidLen; /* ObjectID */
|
|
oidBuffer += 2;
|
|
XMEMCPY(oidBuffer, oid, *oidLen);
|
|
#else
|
|
int i;
|
|
for (i = (int)*oidLen - 1; i >= 0; i--) {
|
|
*(oidBuffer++) = oid[i];
|
|
}
|
|
*(oidBuffer++) = *oidLen; /* ObjectID */
|
|
* oidBuffer = 0x06; /* ObjectID */
|
|
#endif
|
|
*oidLen += 2;
|
|
}
|
|
else {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
#else
|
|
|
|
*oidLen = DILITHIUM_HASH_OID_LEN;
|
|
#ifndef NO_SHA256
|
|
if (hash == WC_HASH_TYPE_SHA256) {
|
|
static byte sha256Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
|
|
};
|
|
oid = sha256Oid;
|
|
}
|
|
else
|
|
#endif
|
|
#ifdef WOLFSSL_SHA384
|
|
if (hash == WC_HASH_TYPE_SHA384) {
|
|
static byte sha384Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
|
|
};
|
|
oid = sha384Oid;
|
|
}
|
|
else
|
|
#endif
|
|
#ifdef WOLFSSL_SHA512
|
|
if (hash == WC_HASH_TYPE_SHA512) {
|
|
static byte sha512Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
|
|
};
|
|
oid = sha512Oid;
|
|
}
|
|
else
|
|
#ifndef WOLFSSL_NOSHA512_256
|
|
if (hash == WC_HASH_TYPE_SHA512_256) {
|
|
static byte sha512_256Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06
|
|
};
|
|
oid = sha512_256Oid;
|
|
}
|
|
else
|
|
#endif
|
|
#endif
|
|
if (hash == WC_HASH_TYPE_SHAKE128) {
|
|
static byte shake128Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B
|
|
};
|
|
oid = shake128Oid;
|
|
}
|
|
else if (hash == WC_HASH_TYPE_SHAKE256) {
|
|
static byte shake256Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C
|
|
};
|
|
oid = shake256Oid;
|
|
}
|
|
else if (hash == WC_HASH_TYPE_SHA3_256) {
|
|
static byte sha3_256Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08
|
|
};
|
|
oid = sha3_256Oid;
|
|
}
|
|
else if (hash == WC_HASH_TYPE_SHA3_384) {
|
|
static byte sha3_384Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09
|
|
};
|
|
oid = sha3_384Oid;
|
|
}
|
|
else if (hash == WC_HASH_TYPE_SHA3_512) {
|
|
static byte sha3_512Oid[DILITHIUM_HASH_OID_LEN] = {
|
|
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A
|
|
};
|
|
oid = sha3_512Oid;
|
|
}
|
|
else {
|
|
oid = NULL;
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if ((oid != NULL) && (*oidLen <= DILITHIUM_HASH_OID_LEN)) {
|
|
#ifndef WOLFSSL_DILITHIUM_REVERSE_HASH_OID
|
|
XMEMCPY(oidBuffer, oid, *oidLen);
|
|
#else
|
|
int i;
|
|
for (i = (int)*oidLen - 1; i >= 0; i--) {
|
|
*(oidBuffer++) = oid[i];
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_SMALL
|
|
/* 128-bit hash using SHAKE-128.
|
|
*
|
|
* FIPS 204. 8.3: H128(v,d) <- SHAKE128(v,d)
|
|
*
|
|
* @param [in, out] shake128 SHAKE-128 object.
|
|
* @param [in] in Block of data to hash.
|
|
* @param [in] inLen Length of data in bytes.
|
|
* @param [out] out Buffer to hold hash result.
|
|
* @param [in] outLen Number of hash blocks to return.
|
|
* @return 0 on success.
|
|
* @return Negative on error.
|
|
*/
|
|
static int dilithium_squeeze128(wc_Shake* shake128, const byte* in,
|
|
word32 inLen, byte* out, word32 outBlocks)
|
|
{
|
|
int ret;
|
|
|
|
/* Initialize SHAKE-128 operation. */
|
|
ret = wc_InitShake128(shake128, NULL, INVALID_DEVID);
|
|
if (ret == 0) {
|
|
/* Absorb data - update plus final. */
|
|
ret = wc_Shake128_Absorb(shake128, in, inLen);
|
|
}
|
|
if (ret == 0) {
|
|
/* Squeeze out hash data. */
|
|
ret = wc_Shake128_SqueezeBlocks(shake128, out, outBlocks);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_SMALL */
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || \
|
|
(!defined(WOLFSSL_DILITHIUM_SMALL) && \
|
|
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY))
|
|
/* 256-bit hash using SHAKE-256.
|
|
*
|
|
* FIPS 204. 8.3: H(v,d) <- SHAKE256(v,d)
|
|
* Using SqueezeBlocks interface to get larger amounts of output.
|
|
*
|
|
* @param [in, out] shake256 SHAKE-256 object.
|
|
* @param [in] in Block of data to hash.
|
|
* @param [in] inLen Length of data in bytes.
|
|
* @param [out] out Buffer to hold hash result.
|
|
* @param [in] outLen Number of hash blocks to return.
|
|
* @return 0 on success.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_squeeze256(wc_Shake* shake256, const byte* in,
|
|
word32 inLen, byte* out, word32 outBlocks)
|
|
{
|
|
int ret;
|
|
|
|
/* Initialize SHAKE-256 operation. */
|
|
ret = wc_InitShake256(shake256, NULL, INVALID_DEVID);
|
|
if (ret == 0) {
|
|
/* Absorb data - update plus final. */
|
|
ret = wc_Shake256_Absorb(shake256, in, inLen);
|
|
}
|
|
if (ret == 0) {
|
|
/* Squeeze out hash data. */
|
|
ret = wc_Shake256_SqueezeBlocks(shake256, out, outBlocks);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* Encode/Decode operations
|
|
******************************************************************************/
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY
|
|
/* Encode vector of polynomials with range -ETA..ETA.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 18 skEncode(rho, K, tr, s1, s2, t0)
|
|
* ...
|
|
* 2: for i from 0 to l - 1 do
|
|
* 3: sk <- sk || BitPack(s1[i], eta, eta)
|
|
* 4: end for
|
|
* ...
|
|
* OR
|
|
* ...
|
|
* 5: for i from 0 to k - 1 do
|
|
* 6: sk <- sk || BitPack(s2[i], eta, eta)
|
|
* 7: end for
|
|
* ...
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 11 BitPack(w, a, b)
|
|
* 1: z <- ()
|
|
* 2: for i from 0 to 255 do
|
|
* 3: z <- z||IntegerToBits(b - wi, bitlen(a + b))
|
|
* 4: end for
|
|
* 5: return BitsToBytes(z)
|
|
*
|
|
* IntegerToBits makes bit array with width specified from integer.
|
|
* BitToBytes make a byte array from a bit array.
|
|
*
|
|
* @param [in] s Vector of polynomials to encode.
|
|
* @param [in] d Dimension of vector.
|
|
* @param [in] eta Range specifier of each value.
|
|
* @param [out] p Buffer to encode into.
|
|
*/
|
|
static void dilthium_vec_encode_eta_bits(const sword32* s, byte d, byte eta,
|
|
byte* p)
|
|
{
|
|
unsigned int i;
|
|
unsigned int j;
|
|
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* -2..2 */
|
|
if (eta == DILITHIUM_ETA_2) {
|
|
/* Setp 2 or 5: For each polynomial of vector. */
|
|
for (i = 0; i < d; i++) {
|
|
/* Step 3 or 6.
|
|
* 3 bits to encode each number.
|
|
* 8 numbers become 3 bytes. (8 * 3 bits = 3 * 8 bits) */
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
/* Make value a positive integer. */
|
|
byte s0 = (byte)(2 - s[j + 0]);
|
|
byte s1 = (byte)(2 - s[j + 1]);
|
|
byte s2 = (byte)(2 - s[j + 2]);
|
|
byte s3 = (byte)(2 - s[j + 3]);
|
|
byte s4 = (byte)(2 - s[j + 4]);
|
|
byte s5 = (byte)(2 - s[j + 5]);
|
|
byte s6 = (byte)(2 - s[j + 6]);
|
|
byte s7 = (byte)(2 - s[j + 7]);
|
|
|
|
/* Pack 8 3-bit values into 3 bytes. */
|
|
p[0] = (byte)((s0 >> 0) | (s1 << 3) | (s2 << 6));
|
|
p[1] = (byte)((s2 >> 2) | (s3 << 1) | (s4 << 4) | (s5 << 7));
|
|
p[2] = (byte)((s5 >> 1) | (s6 << 2) | (s7 << 5));
|
|
/* Move to next place to encode into. */
|
|
p += DILITHIUM_ETA_2_BITS;
|
|
}
|
|
/* Next polynomial. */
|
|
s += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
/* -4..4 */
|
|
if (eta == DILITHIUM_ETA_4) {
|
|
for (i = 0; i < d; i++) {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
/* Step 3 or 6.
|
|
* 4 bits to encode each number.
|
|
* 2 numbers become 1 bytes. (2 * 4 bits = 1 * 8 bits) */
|
|
for (j = 0; j < DILITHIUM_N / 2; j++) {
|
|
/* Make values positive and pack 2 4-bit values into 1 byte. */
|
|
p[j] = (((byte)(4 - s[j * 2 + 0])) << 0) |
|
|
(((byte)(4 - s[j * 2 + 1])) << 4);
|
|
}
|
|
#else
|
|
/* Step 3 or 6.
|
|
* 4 bits to encode each number.
|
|
* 8 numbers become 4 bytes. (8 * 4 bits = 4 * 8 bits) */
|
|
for (j = 0; j < DILITHIUM_N / 2; j += 4) {
|
|
/* Make values positive and pack 2 4-bit values into 1 byte. */
|
|
p[j + 0] = (byte)((((byte)(4 - s[j * 2 + 0])) << 0) |
|
|
(((byte)(4 - s[j * 2 + 1])) << 4));
|
|
p[j + 1] = (byte)((((byte)(4 - s[j * 2 + 2])) << 0) |
|
|
(((byte)(4 - s[j * 2 + 3])) << 4));
|
|
p[j + 2] = (byte)((((byte)(4 - s[j * 2 + 4])) << 0) |
|
|
(((byte)(4 - s[j * 2 + 5])) << 4));
|
|
p[j + 3] = (byte)((((byte)(4 - s[j * 2 + 6])) << 0) |
|
|
(((byte)(4 - s[j * 2 + 7])) << 4));
|
|
}
|
|
#endif
|
|
/* Move to next place to encode into. */
|
|
p += DILITHIUM_N / 2;
|
|
/* Next polynomial. */
|
|
s += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
}
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_MAKE_KEY */
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || defined(WOLFSSL_DILITHIUM_CHECK_KEY)
|
|
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* Decode polynomial with range -2..2.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 19 skDecode(sk)
|
|
* ...
|
|
* 5: for i from 0 to l - 1 do
|
|
* 6: s1[i] <- BitUnpack(yi, eta, eta)
|
|
* 7: end for
|
|
* ...
|
|
* OR
|
|
* ...
|
|
* 8: for i from 0 to k - 1 do
|
|
* 9: s2[i] <- BitUnpack(zi, eta, eta)
|
|
* 10: end for
|
|
* ...
|
|
* Where y and z are arrays of bit arrays.
|
|
*
|
|
* @param [in] p Buffer of data to decode.
|
|
* @param [in] s Vector of decoded polynomials.
|
|
*/
|
|
static void dilithium_decode_eta_2_bits(const byte* p, sword32* s)
|
|
{
|
|
unsigned int j;
|
|
|
|
/* Step 6 or 9.
|
|
* 3 bits to encode each number.
|
|
* 8 numbers from 3 bytes. (8 * 3 bits = 3 * 8 bits) */
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
/* Get 3 bits and put in range of -2..2. */
|
|
s[j + 0] = 2 - ((p[0] >> 0) & 0x7 );
|
|
s[j + 1] = 2 - ((p[0] >> 3) & 0x7 );
|
|
s[j + 2] = 2 - ((p[0] >> 6) | ((p[1] << 2) & 0x7));
|
|
s[j + 3] = 2 - ((p[1] >> 1) & 0x7 );
|
|
s[j + 4] = 2 - ((p[1] >> 4) & 0x7 );
|
|
s[j + 5] = 2 - ((p[1] >> 7) | ((p[2] << 1) & 0x7));
|
|
s[j + 6] = 2 - ((p[2] >> 2) & 0x7 );
|
|
s[j + 7] = 2 - ((p[2] >> 5) & 0x7 );
|
|
/* Move to next place to decode from. */
|
|
p += DILITHIUM_ETA_2_BITS;
|
|
}
|
|
}
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
/* Decode polynomial with range -4..4.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 19 skDecode(sk)
|
|
* ...
|
|
* 5: for i from 0 to l - 1 do
|
|
* 6: s1[i] <- BitUnpack(yi, eta, eta)
|
|
* 7: end for
|
|
* ...
|
|
* OR
|
|
* ...
|
|
* 8: for i from 0 to k - 1 do
|
|
* 9: s2[i] <- BitUnpack(zi, eta, eta)
|
|
* 10: end for
|
|
* ...
|
|
* Where y and z are arrays of bit arrays.
|
|
*
|
|
* @param [in] p Buffer of data to decode.
|
|
* @param [in] s Vector of decoded polynomials.
|
|
*/
|
|
static void dilithium_decode_eta_4_bits(const byte* p, sword32* s)
|
|
{
|
|
unsigned int j;
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
/* Step 6 or 9.
|
|
* 4 bits to encode each number.
|
|
* 2 numbers from 1 bytes. (2 * 4 bits = 1 * 8 bits) */
|
|
for (j = 0; j < DILITHIUM_N / 2; j++) {
|
|
/* Get 4 bits and put in range of -4..4. */
|
|
s[j * 2 + 0] = 4 - (p[j] & 0xf);
|
|
s[j * 2 + 1] = 4 - (p[j] >> 4);
|
|
}
|
|
#else
|
|
/* Step 6 or 9.
|
|
* 4 bits to encode each number.
|
|
* 8 numbers from 4 bytes. (8 * 4 bits = 4 * 8 bits) */
|
|
for (j = 0; j < DILITHIUM_N / 2; j += 4) {
|
|
/* Get 4 bits and put in range of -4..4. */
|
|
s[j * 2 + 0] = 4 - (p[j + 0] & 0xf);
|
|
s[j * 2 + 1] = 4 - (p[j + 0] >> 4);
|
|
s[j * 2 + 2] = 4 - (p[j + 1] & 0xf);
|
|
s[j * 2 + 3] = 4 - (p[j + 1] >> 4);
|
|
s[j * 2 + 4] = 4 - (p[j + 2] & 0xf);
|
|
s[j * 2 + 5] = 4 - (p[j + 2] >> 4);
|
|
s[j * 2 + 6] = 4 - (p[j + 3] & 0xf);
|
|
s[j * 2 + 7] = 4 - (p[j + 3] >> 4);
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_SMALL */
|
|
}
|
|
#endif
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
(defined(WC_DILITHIUM_CACHE_PRIV_VECTORS) || \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)))
|
|
/* Decode vector of polynomials with range -ETA..ETA.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 19 skDecode(sk)
|
|
* ...
|
|
* 5: for i from 0 to l - 1 do
|
|
* 6: s1[i] <- BitUnpack(yi, eta, eta)
|
|
* 7: end for
|
|
* ...
|
|
* OR
|
|
* ...
|
|
* 8: for i from 0 to k - 1 do
|
|
* 9: s2[i] <- BitUnpack(zi, eta, eta)
|
|
* 10: end for
|
|
* ...
|
|
* Where y and z are arrays of bit arrays.
|
|
*
|
|
* @param [in] p Buffer of data to decode.
|
|
* @param [in] eta Range specifier of each value.
|
|
* @param [in] s Vector of decoded polynomials.
|
|
* @param [in] d Dimension of vector.
|
|
*/
|
|
static void dilithium_vec_decode_eta_bits(const byte* p, byte eta, sword32* s,
|
|
byte d)
|
|
{
|
|
unsigned int i;
|
|
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* -2..2 */
|
|
if (eta == DILITHIUM_ETA_2) {
|
|
/* Step 5 or 8: For each polynomial of vector */
|
|
for (i = 0; i < d; i++) {
|
|
dilithium_decode_eta_2_bits(p, s);
|
|
/* Move to next place to decode from. */
|
|
p += DILITHIUM_ETA_2_BITS * DILITHIUM_N / 8;
|
|
/* Next polynomial. */
|
|
s += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
/* -4..4 */
|
|
if (eta == DILITHIUM_ETA_4) {
|
|
/* Step 5 or 8: For each polynomial of vector */
|
|
for (i = 0; i < d; i++) {
|
|
dilithium_decode_eta_4_bits(p, s);
|
|
/* Move to next place to decode from. */
|
|
p += DILITHIUM_N / 2;
|
|
/* Next polynomial. */
|
|
s += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN || WOLFSSL_DILITHIUM_CHECK_KEY */
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY
|
|
/* Encode t into t0 and t1.
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 29 Power2Round(r)
|
|
* 1: r+ <- r mod q
|
|
* 2: r0 <- r+ mod +/- 2^d
|
|
* 3: return ((r+ - r0) / 2^d, r0)
|
|
*
|
|
* FIPS 204. 7.2: Algorithm 24 skEncode(rho, K, tr, s1, s2, t0)
|
|
* ...
|
|
* 8: for i form 0 to k - 1 do
|
|
* 9: sk <- sk || BitPack(t0[i], s^(d-1) - 1, 2^(d-1))
|
|
* 10: end for
|
|
*
|
|
* FIPS 204. 7.2: Algorithm 22 pkEncode(rho, t1)
|
|
* ...
|
|
* 2: for i from 0 to k - 1 do
|
|
* 3: pk <- pk || SimpleBitPack(t1[i], 2^bitlen(q-1) - d - 1)
|
|
* 4: end for
|
|
*
|
|
* @param [in] t Vector of polynomials.
|
|
* @param [in] d Dimension of vector.
|
|
* @param [out] t0 Buffer to encode bottom part of value of t into.
|
|
* @param [out] t1 Buffer to encode top part of value of t into.
|
|
*/
|
|
static void dilithium_vec_encode_t0_t1(sword32* t, byte d, byte* t0, byte* t1)
|
|
{
|
|
unsigned int i;
|
|
unsigned int j;
|
|
|
|
/* Alg 24, Step 8 and Alg 22, Step 2. For each polynomial of vector. */
|
|
for (i = 0; i < d; i++) {
|
|
/* Alg 24, Step 9 and Alg 22, Step 3.
|
|
* Do all polynomial values - 8 at a time. */
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
/* Take 8 values of t and take top bits and make positive. */
|
|
word16 n1_0 = (word16)((t[j + 0] + DILITHIUM_D_MAX_HALF - 1) >>
|
|
DILITHIUM_D);
|
|
word16 n1_1 = (word16)((t[j + 1] + DILITHIUM_D_MAX_HALF - 1) >>
|
|
DILITHIUM_D);
|
|
word16 n1_2 = (word16)((t[j + 2] + DILITHIUM_D_MAX_HALF - 1) >>
|
|
DILITHIUM_D);
|
|
word16 n1_3 = (word16)((t[j + 3] + DILITHIUM_D_MAX_HALF - 1) >>
|
|
DILITHIUM_D);
|
|
word16 n1_4 = (word16)((t[j + 4] + DILITHIUM_D_MAX_HALF - 1) >>
|
|
DILITHIUM_D);
|
|
word16 n1_5 = (word16)((t[j + 5] + DILITHIUM_D_MAX_HALF - 1) >>
|
|
DILITHIUM_D);
|
|
word16 n1_6 = (word16)((t[j + 6] + DILITHIUM_D_MAX_HALF - 1) >>
|
|
DILITHIUM_D);
|
|
word16 n1_7 = (word16)((t[j + 7] + DILITHIUM_D_MAX_HALF - 1) >>
|
|
DILITHIUM_D);
|
|
/* Take 8 values of t and take bottom bits and make positive. */
|
|
word16 n0_0 = (word16)(DILITHIUM_D_MAX_HALF -
|
|
(t[j + 0] - (n1_0 << DILITHIUM_D)));
|
|
word16 n0_1 = (word16)(DILITHIUM_D_MAX_HALF -
|
|
(t[j + 1] - (n1_1 << DILITHIUM_D)));
|
|
word16 n0_2 = (word16)(DILITHIUM_D_MAX_HALF -
|
|
(t[j + 2] - (n1_2 << DILITHIUM_D)));
|
|
word16 n0_3 = (word16)(DILITHIUM_D_MAX_HALF -
|
|
(t[j + 3] - (n1_3 << DILITHIUM_D)));
|
|
word16 n0_4 = (word16)(DILITHIUM_D_MAX_HALF -
|
|
(t[j + 4] - (n1_4 << DILITHIUM_D)));
|
|
word16 n0_5 = (word16)(DILITHIUM_D_MAX_HALF -
|
|
(t[j + 5] - (n1_5 << DILITHIUM_D)));
|
|
word16 n0_6 = (word16)(DILITHIUM_D_MAX_HALF -
|
|
(t[j + 6] - (n1_6 << DILITHIUM_D)));
|
|
word16 n0_7 = (word16)(DILITHIUM_D_MAX_HALF -
|
|
(t[j + 7] - (n1_7 << DILITHIUM_D)));
|
|
|
|
/* 13 bits per number.
|
|
* 8 numbers become 13 bytes. (8 * 13 bits = 13 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT <= 2)
|
|
word32* tp;
|
|
#endif
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
tp = (word32*)t0;
|
|
tp[0] = (n0_0 ) | ((word32)n0_1 << 13) | ((word32)n0_2 << 26);
|
|
tp[1] = (n0_2 >> 6) | ((word32)n0_3 << 7) | ((word32)n0_4 << 20);
|
|
tp[2] = (n0_4 >> 12) | ((word32)n0_5 << 1) |
|
|
((word32)n0_6 << 14) | ((word32)n0_7 << 27);
|
|
#else
|
|
t0[ 0] = (byte)( (n0_0 << 0));
|
|
t0[ 1] = (byte)((n0_0 >> 8) | (n0_1 << 5));
|
|
t0[ 2] = (byte)((n0_1 >> 3) );
|
|
t0[ 3] = (byte)((n0_1 >> 11) | (n0_2 << 2));
|
|
t0[ 4] = (byte)((n0_2 >> 6) | (n0_3 << 7));
|
|
t0[ 5] = (byte)((n0_3 >> 1) );
|
|
t0[ 6] = (byte)((n0_3 >> 9) | (n0_4 << 4));
|
|
t0[ 7] = (byte)((n0_4 >> 4) );
|
|
t0[ 8] = (byte)((n0_4 >> 12) | (n0_5 << 1));
|
|
t0[ 9] = (byte)((n0_5 >> 7) | (n0_6 << 6));
|
|
t0[10] = (byte)((n0_6 >> 2) );
|
|
t0[11] = (byte)((n0_6 >> 10) | (n0_7 << 3));
|
|
#endif
|
|
t0[12] = (byte)((n0_7 >> 5) );
|
|
|
|
/* 10 bits per number.
|
|
* 8 bytes become 10 bytes. (8 * 10 bits = 10 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT <= 2)
|
|
tp = (word32*)t1;
|
|
tp[0] = (n1_0 ) | ((word32)n1_1 << 10) |
|
|
((word32)n1_2 << 20) | ((word32)n1_3 << 30);
|
|
tp[1] = (n1_3 >> 2) | ((word32)n1_4 << 8) |
|
|
((word32)n1_5 << 18) | ((word32)n1_6 << 28);
|
|
#else
|
|
t1[0] = (byte)( (n1_0 << 0));
|
|
t1[1] = (byte)((n1_0 >> 8) | (n1_1 << 2));
|
|
t1[2] = (byte)((n1_1 >> 6) | (n1_2 << 4));
|
|
t1[3] = (byte)((n1_2 >> 4) | (n1_3 << 6));
|
|
t1[4] = (byte)((n1_3 >> 2) );
|
|
t1[5] = (byte)( (n1_4 << 0));
|
|
t1[6] = (byte)((n1_4 >> 8) | (n1_5 << 2));
|
|
t1[7] = (byte)((n1_5 >> 6) | (n1_6 << 4));
|
|
#endif
|
|
t1[8] = (byte)((n1_6 >> 4) | (n1_7 << 6));
|
|
t1[9] = (byte)((n1_7 >> 2) );
|
|
|
|
/* Move to next place to encode bottom bits to. */
|
|
t0 += DILITHIUM_D;
|
|
/* Move to next place to encode top bits to. */
|
|
t1 += DILITHIUM_U;
|
|
}
|
|
/* Next polynomial. */
|
|
t += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_MAKE_KEY */
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || defined(WOLFSSL_DILITHIUM_CHECK_KEY)
|
|
/* Decode bottom D bits of t as t0.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 19 skDecode(sk)
|
|
* ...
|
|
* 12: t0[i] <- BitUnpack(wi, 2^(d-1) - 1, 2^(d-1)
|
|
* ...
|
|
*
|
|
* @param [in] t0 Encoded values of t0.
|
|
* @param [in] d Dimensions of vector t0.
|
|
* @param [out] t Vector of polynomials.
|
|
*/
|
|
static void dilithium_decode_t0(const byte* t0, sword32* t)
|
|
{
|
|
unsigned int j;
|
|
|
|
/* Step 12. Get 13 bits and convert to range (2^(d-1)-1)..2^(d-1). */
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
/* 13 bits used per number.
|
|
* 8 numbers from 13 bytes. (8 * 13 bits = 13 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
word32 t32_2 = ((const word32*)t0)[2];
|
|
#ifdef WC_64BIT_CPU
|
|
word64 t64 = *(const word64*)t0;
|
|
t[j + 0] = DILITHIUM_D_MAX_HALF - ( t64 & 0x1fff);
|
|
t[j + 1] = DILITHIUM_D_MAX_HALF - ((t64 >> 13) & 0x1fff);
|
|
t[j + 2] = DILITHIUM_D_MAX_HALF - ((t64 >> 26) & 0x1fff);
|
|
t[j + 3] = DILITHIUM_D_MAX_HALF - ((t64 >> 39) & 0x1fff);
|
|
t[j + 4] = DILITHIUM_D_MAX_HALF - (sword32)
|
|
((t64 >> 52) | ((t32_2 & 0x0001) << 12));
|
|
#else
|
|
word32 t32_0 = ((const word32*)t0)[0];
|
|
word32 t32_1 = ((const word32*)t0)[1];
|
|
t[j + 0] = DILITHIUM_D_MAX_HALF -
|
|
( t32_0 & 0x1fff);
|
|
t[j + 1] = DILITHIUM_D_MAX_HALF -
|
|
((t32_0 >> 13) & 0x1fff);
|
|
t[j + 2] = DILITHIUM_D_MAX_HALF - (sword32)
|
|
(( t32_0 >> 26 ) | ((t32_1 & 0x007f) << 6));
|
|
t[j + 3] = DILITHIUM_D_MAX_HALF -
|
|
((t32_1 >> 7) & 0x1fff);
|
|
t[j + 4] = DILITHIUM_D_MAX_HALF - (sword32)
|
|
(( t32_1 >> 20 ) | ((t32_2 & 0x0001) << 12));
|
|
#endif
|
|
t[j + 5] = DILITHIUM_D_MAX_HALF -
|
|
((t32_2 >> 1) & 0x1fff);
|
|
t[j + 6] = DILITHIUM_D_MAX_HALF -
|
|
((t32_2 >> 14) & 0x1fff);
|
|
t[j + 7] = DILITHIUM_D_MAX_HALF - (sword32)
|
|
(( t32_2 >> 27 ) | ((word32)t0[12] ) << 5 );
|
|
#else
|
|
t[j + 0] = DILITHIUM_D_MAX_HALF -
|
|
((t0[ 0] ) | (((word16)(t0[ 1] & 0x1f)) << 8));
|
|
t[j + 1] = DILITHIUM_D_MAX_HALF -
|
|
((t0[ 1] >> 5) | (((word16)(t0[ 2] )) << 3) |
|
|
(((word16)(t0[ 3] & 0x03)) << 11));
|
|
t[j + 2] = DILITHIUM_D_MAX_HALF -
|
|
((t0[ 3] >> 2) | (((word16)(t0[ 4] & 0x7f)) << 6));
|
|
t[j + 3] = DILITHIUM_D_MAX_HALF -
|
|
((t0[ 4] >> 7) | (((word16)(t0[ 5] )) << 1) |
|
|
(((word16)(t0[ 6] & 0x0f)) << 9));
|
|
t[j + 4] = DILITHIUM_D_MAX_HALF -
|
|
((t0[ 6] >> 4) | (((word16)(t0[ 7] )) << 4) |
|
|
(((word16)(t0[ 8] & 0x01)) << 12));
|
|
t[j + 5] = DILITHIUM_D_MAX_HALF -
|
|
((t0[ 8] >> 1) | (((word16)(t0[ 9] & 0x3f)) << 7));
|
|
t[j + 6] = DILITHIUM_D_MAX_HALF -
|
|
((t0[ 9] >> 6) | (((word16)(t0[10] )) << 2) |
|
|
(((word16)(t0[11] & 0x07)) << 10));
|
|
t[j + 7] = DILITHIUM_D_MAX_HALF -
|
|
((t0[11] >> 3) | (((word16)(t0[12] )) << 5));
|
|
#endif
|
|
/* Move to next place to decode from. */
|
|
t0 += DILITHIUM_D;
|
|
}
|
|
}
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
(defined(WC_DILITHIUM_CACHE_PRIV_VECTORS) || \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)))
|
|
/* Decode bottom D bits of t as t0.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 19 skDecode(sk)
|
|
* ...
|
|
* 11: for i from 0 to k - 1 do
|
|
* 12: t0[i] <- BitUnpack(wi, 2^(d-1) - 1, 2^(d-1)
|
|
* 13: end for
|
|
* ...
|
|
*
|
|
* @param [in] t0 Encoded values of t0.
|
|
* @param [in] d Dimensions of vector t0.
|
|
* @param [out] t Vector of polynomials.
|
|
*/
|
|
static void dilithium_vec_decode_t0(const byte* t0, byte d, sword32* t)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* Step 11. For each polynomial of vector. */
|
|
for (i = 0; i < d; i++) {
|
|
dilithium_decode_t0(t0, t);
|
|
t0 += DILITHIUM_D * DILITHIUM_N / 8;
|
|
/* Next polynomial. */
|
|
t += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN || WOLFSSL_DILITHIUM_CHECK_KEY */
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_VERIFY) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY)
|
|
/* Decode top bits of t as t1.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 17 pkDecode(pk)
|
|
* ...
|
|
* 4: t1[i] <- SimpleBitUnpack(zi, 2^(bitlen(q-1)-d) - 1)
|
|
* ...
|
|
*
|
|
* @param [in] t1 Encoded values of t1.
|
|
* @param [out] t Polynomials.
|
|
*/
|
|
static void dilithium_decode_t1(const byte* t1, sword32* t)
|
|
{
|
|
unsigned int j;
|
|
/* Step 4. Get 10 bits as a number. */
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
/* 10 bits used per number.
|
|
* 8 numbers from 10 bytes. (8 * 10 bits = 10 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
#ifdef WC_64BIT_CPU
|
|
word64 t64 = *(const word64*) t1;
|
|
word16 t16 = *(const word16*)(t1 + 8);
|
|
t[j+0] = (sword32)( ( t64 & 0x03ff) << DILITHIUM_D);
|
|
t[j+1] = (sword32)( ((t64 >> 10) & 0x03ff) << DILITHIUM_D);
|
|
t[j+2] = (sword32)( ((t64 >> 20) & 0x03ff) << DILITHIUM_D);
|
|
t[j+3] = (sword32)( ((t64 >> 30) & 0x03ff) << DILITHIUM_D);
|
|
t[j+4] = (sword32)( ((t64 >> 40) & 0x03ff) << DILITHIUM_D);
|
|
t[j+5] = (sword32)( ((t64 >> 50) & 0x03ff) << DILITHIUM_D);
|
|
t[j+6] = (sword32)((((t64 >> 60) |
|
|
(word64)(t16 << 4)) & 0x03ff) << DILITHIUM_D);
|
|
t[j+7] = (sword32)( ((t16 >> 6) & 0x03ff) << DILITHIUM_D);
|
|
#else
|
|
word32 t32 = *((const word32*)t1);
|
|
t[j + 0] = ( t32 & 0x03ff ) <<
|
|
DILITHIUM_D;
|
|
t[j + 1] = ((t32 >> 10) & 0x03ff ) <<
|
|
DILITHIUM_D;
|
|
t[j + 2] = ((t32 >> 20) & 0x03ff ) <<
|
|
DILITHIUM_D;
|
|
t[j + 3] = ((t32 >> 30) | (((word16)t1[4]) << 2)) <<
|
|
DILITHIUM_D;
|
|
t32 = *((const word32*)(t1 + 5));
|
|
t[j + 4] = ( t32 & 0x03ff ) <<
|
|
DILITHIUM_D;
|
|
t[j + 5] = ((t32 >> 10) & 0x03ff ) <<
|
|
DILITHIUM_D;
|
|
t[j + 6] = ((t32 >> 20) & 0x03ff ) <<
|
|
DILITHIUM_D;
|
|
t[j + 7] = ((t32 >> 30) | (((word16)t1[9]) << 2)) <<
|
|
DILITHIUM_D;
|
|
#endif
|
|
#else
|
|
t[j + 0] = (sword32)((t1[0] >> 0) | (((word16)(t1[1] & 0x03)) << 8))
|
|
<< DILITHIUM_D;
|
|
t[j + 1] = (sword32)((t1[1] >> 2) | (((word16)(t1[2] & 0x0f)) << 6))
|
|
<< DILITHIUM_D;
|
|
t[j + 2] = (sword32)((t1[2] >> 4) | (((word16)(t1[3] & 0x3f)) << 4))
|
|
<< DILITHIUM_D;
|
|
t[j + 3] = (sword32)((t1[3] >> 6) | (((word16)(t1[4] )) << 2))
|
|
<< DILITHIUM_D;
|
|
t[j + 4] = (sword32)((t1[5] >> 0) | (((word16)(t1[6] & 0x03)) << 8))
|
|
<< DILITHIUM_D;
|
|
t[j + 5] = (sword32)((t1[6] >> 2) | (((word16)(t1[7] & 0x0f)) << 6))
|
|
<< DILITHIUM_D;
|
|
t[j + 6] = (sword32)((t1[7] >> 4) | (((word16)(t1[8] & 0x3f)) << 4))
|
|
<< DILITHIUM_D;
|
|
t[j + 7] = (sword32)((t1[8] >> 6) | (((word16)(t1[9] )) << 2))
|
|
<< DILITHIUM_D;
|
|
#endif
|
|
/* Move to next place to decode from. */
|
|
t1 += DILITHIUM_U;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if (!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM)) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY)
|
|
/* Decode top bits of t as t1.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 17 pkDecode(pk)
|
|
* ...
|
|
* 3: for i from 0 to k - 1 do
|
|
* 4: t1[i] <- SimpleBitUnpack(zi, 2^(bitlen(q-1)-d) - 1)
|
|
* 5: end for
|
|
* ...
|
|
*
|
|
* @param [in] t1 Encoded values of t1.
|
|
* @param [in] d Dimensions of vector t1.
|
|
* @param [out] t Vector of polynomials.
|
|
*/
|
|
static void dilithium_vec_decode_t1(const byte* t1, byte d, sword32* t)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* Step 3. For each polynomial of vector. */
|
|
for (i = 0; i < d; i++) {
|
|
dilithium_decode_t1(t1, t);
|
|
/* Next polynomial. */
|
|
t1 += DILITHIUM_U * DILITHIUM_N / 8;
|
|
t += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_SIGN
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
/* Encode z with range of -(GAMMA1-1)...GAMMA1
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 20 sigEncode(c_tilde, z, h)
|
|
* ...
|
|
* 3: sigma <- sigma || BitPack(z[i], GAMMA1 - 1, GAMMA1)
|
|
* ...
|
|
*
|
|
* @param [in] z Polynomial to encode.
|
|
* @param [out] s Buffer to encode into.
|
|
*/
|
|
static void dilithium_encode_gamma1_17_bits(const sword32* z, byte* s)
|
|
{
|
|
unsigned int j;
|
|
|
|
/* Step 3. Get 18 bits as a number. */
|
|
for (j = 0; j < DILITHIUM_N; j += 4) {
|
|
word32 z0 = (word32)(DILITHIUM_GAMMA1_17 - z[j + 0]);
|
|
word32 z1 = (word32)(DILITHIUM_GAMMA1_17 - z[j + 1]);
|
|
word32 z2 = (word32)(DILITHIUM_GAMMA1_17 - z[j + 2]);
|
|
word32 z3 = (word32)(DILITHIUM_GAMMA1_17 - z[j + 3]);
|
|
|
|
/* 18 bits per number.
|
|
* 8 numbers become 9 bytes. (8 * 9 bits = 9 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
#ifdef WC_64BIT_CPU
|
|
word64* s64p = (word64*)s;
|
|
s64p[0] = z0 | ((word64)z1 << 18) |
|
|
((word64)z2 << 36) | ((word64)z3 << 54);
|
|
#else
|
|
word32* s32p = (word32*)s;
|
|
s32p[0] = z0 | (z1 << 18) ;
|
|
s32p[1] = (z1 >> 14) | (z2 << 4) | (z3 << 22);
|
|
#endif
|
|
#else
|
|
s[0] = (byte)( z0 );
|
|
s[1] = (byte)( z0 >> 8 );
|
|
s[2] = (byte)((z0 >> 16) | (z1 << 2));
|
|
s[3] = (byte)( z1 >> 6 );
|
|
s[4] = (byte)((z1 >> 14) | (z2 << 4));
|
|
s[5] = (byte)( z2 >> 4 );
|
|
s[6] = (byte)((z2 >> 12) | (z3 << 6));
|
|
s[7] = (byte)( z3 >> 2 );
|
|
#endif
|
|
s[8] = (byte)( z3 >> 10 );
|
|
/* Move to next place to encode to. */
|
|
s += DILITHIUM_GAMMA1_17_ENC_BITS / 2;
|
|
}
|
|
}
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* Encode z with range of -(GAMMA1-1)...GAMMA1
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 20 sigEncode(c_tilde, z, h)
|
|
* ...
|
|
* 3: sigma <- sigma || BitPack(z[i], GAMMA1 - 1, GAMMA1)
|
|
* ...
|
|
*
|
|
* @param [in] z Polynomial to encode.
|
|
* @param [out] s Buffer to encode into.
|
|
*/
|
|
static void dilithium_encode_gamma1_19_bits(const sword32* z, byte* s)
|
|
{
|
|
unsigned int j;
|
|
|
|
/* Step 3. Get 20 bits as a number. */
|
|
for (j = 0; j < DILITHIUM_N; j += 4) {
|
|
sword32 z0 = DILITHIUM_GAMMA1_19 - z[j + 0];
|
|
sword32 z1 = DILITHIUM_GAMMA1_19 - z[j + 1];
|
|
sword32 z2 = DILITHIUM_GAMMA1_19 - z[j + 2];
|
|
sword32 z3 = DILITHIUM_GAMMA1_19 - z[j + 3];
|
|
|
|
/* 20 bits per number.
|
|
* 4 numbers become 10 bytes. (4 * 20 bits = 10 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT <= 2)
|
|
word16* s16p = (word16*)s;
|
|
#ifdef WC_64BIT_CPU
|
|
word64* s64p = (word64*)s;
|
|
s64p[0] = (word64)z0 | ((word64)z1 << 20) |
|
|
((word64)z2 << 40) | ((word64)z3 << 60);
|
|
#else
|
|
word32* s32p = (word32*)s;
|
|
s32p[0] = (word16)( z0 | (z1 << 20) );
|
|
s32p[1] = (word16)((z1 >> 12) | (z2 << 8) | (z3 << 28));
|
|
#endif
|
|
s16p[4] = (word16)((z3 >> 4) );
|
|
#else
|
|
s[0] = z0 ;
|
|
s[1] = (z0 >> 8) ;
|
|
s[2] = (z0 >> 16) | (z1 << 4);
|
|
s[3] = (z1 >> 4) ;
|
|
s[4] = (z1 >> 12) ;
|
|
s[5] = z2 ;
|
|
s[6] = (z2 >> 8) ;
|
|
s[7] = (z2 >> 16) | (z3 << 4);
|
|
s[8] = (z3 >> 4) ;
|
|
s[9] = (z3 >> 12) ;
|
|
#endif
|
|
/* Move to next place to encode to. */
|
|
s += DILITHIUM_GAMMA1_19_ENC_BITS / 2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM
|
|
/* Encode z with range of -(GAMMA1-1)...GAMMA1
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 20 sigEncode(c_tilde, z, h)
|
|
* ...
|
|
* 2: for i form 0 to l - 1 do
|
|
* 3: sigma <- sigma || BitPack(z[i], GAMMA1 - 1, GAMMA1)
|
|
* 4: end for
|
|
* ...
|
|
*
|
|
* @param [in] z Vector of polynomials to encode.
|
|
* @param [in] l Dimension of vector.
|
|
* @param [in] bits Number of bits used in encoding - GAMMA1 bits.
|
|
* @param [out] s Buffer to encode into.
|
|
*/
|
|
static void dilithium_vec_encode_gamma1(const sword32* z, byte l, int bits,
|
|
byte* s)
|
|
{
|
|
unsigned int i;
|
|
|
|
(void)l;
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (bits == DILITHIUM_GAMMA1_BITS_17) {
|
|
/* Step 2. For each polynomial of vector. */
|
|
for (i = 0; i < PARAMS_ML_DSA_44_L; i++) {
|
|
dilithium_encode_gamma1_17_bits(z, s);
|
|
/* Move to next place to encode to. */
|
|
s += DILITHIUM_GAMMA1_17_ENC_BITS / 2 * DILITHIUM_N / 4;
|
|
/* Next polynomial. */
|
|
z += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (bits == DILITHIUM_GAMMA1_BITS_19) {
|
|
/* Step 2. For each polynomial of vector. */
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_encode_gamma1_19_bits(z, s);
|
|
/* Move to next place to encode to. */
|
|
s += DILITHIUM_GAMMA1_19_ENC_BITS / 2 * DILITHIUM_N / 4;
|
|
/* Next polynomial. */
|
|
z += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_SIGN_SMALL_MEM */
|
|
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN */
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || !defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
|
/* Decode polynomial with range -(GAMMA1-1)..GAMMA1.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 21 sigDecode(sigma)
|
|
* ...
|
|
* 4: z[i] <- BitUnpack(xi, GAMMA1 - 1, GAMMA1)
|
|
* ...
|
|
*
|
|
* @param [in] s Encoded values of z.
|
|
* @param [in] bits Number of bits used in encoding - GAMMA1 bits.
|
|
* @param [out] z Polynomial to fill.
|
|
*/
|
|
static void dilithium_decode_gamma1(const byte* s, int bits, sword32* z)
|
|
{
|
|
unsigned int i;
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (bits == DILITHIUM_GAMMA1_BITS_17) {
|
|
#if defined(WOLFSSL_DILITHIUM_NO_LARGE_CODE) || defined(WOLFSSL_DILITHIUM_SMALL)
|
|
/* Step 4: Get 18 bits as a number. */
|
|
for (i = 0; i < DILITHIUM_N; i += 4) {
|
|
/* 18 bits per number.
|
|
* 4 numbers from 9 bytes. (4 * 18 bits = 9 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
#ifdef WC_64BIT_CPU
|
|
word64 s64_0 = *(const word64*)(s+0);
|
|
z[i+0] = (word32)DILITHIUM_GAMMA1_17 -
|
|
( s64_0 & 0x3ffff );
|
|
z[i+1] = (word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_0 >> 18) & 0x3ffff );
|
|
z[i+2] = (word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_0 >> 36) & 0x3ffff );
|
|
z[i+3] = (word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_0 >> 54) | (((word32)s[8]) << 10));
|
|
#else
|
|
word32 s32_0 = ((const word32*)(s+0))[0];
|
|
word32 s32_1 = ((const word32*)(s+0))[1];
|
|
z[i+0] = (word32)DILITHIUM_GAMMA1_17 -
|
|
( s32_0 & 0x3ffff );
|
|
z[i+1] = (word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_0 >> 18) | (((s32_1 & 0x0000f) << 14)));
|
|
z[i+2] = (word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_1 >> 4) & 0x3ffff);
|
|
z[i+3] = (word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_1 >> 22) | (((word32)s[8]) << 10 ));
|
|
#endif
|
|
#else
|
|
z[i+0] = DILITHIUM_GAMMA1_17 -
|
|
( s[ 0] | ((sword32)(s[ 1] << 8) |
|
|
(sword32)(s[ 2] & 0x03) << 16));
|
|
z[i+1] = DILITHIUM_GAMMA1_17 -
|
|
((s[ 2] >> 2) | ((sword32)(s[ 3] << 6) |
|
|
(sword32)(s[ 4] & 0x0f) << 14));
|
|
z[i+2] = DILITHIUM_GAMMA1_17 -
|
|
((s[ 4] >> 4) | ((sword32)(s[ 5] << 4) |
|
|
(sword32)(s[ 6] & 0x3f) << 12));
|
|
z[i+3] = DILITHIUM_GAMMA1_17 -
|
|
((s[ 6] >> 6) | ((sword32)(s[ 7] << 2) |
|
|
(sword32)(s[ 8] ) << 10));
|
|
#endif
|
|
/* Move to next place to decode from. */
|
|
s += DILITHIUM_GAMMA1_17_ENC_BITS / 2;
|
|
}
|
|
#else
|
|
/* Step 4: Get 18 bits as a number. */
|
|
for (i = 0; i < DILITHIUM_N; i += 8) {
|
|
/* 18 bits per number.
|
|
* 8 numbers from 9 bytes. (8 * 18 bits = 18 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
#ifdef WC_64BIT_CPU
|
|
word64 s64_0 = *(const word64*)(s+0);
|
|
word64 s64_1 = *(const word64*)(s+9);
|
|
z[i+0] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
( s64_0 & 0x3ffff ));
|
|
z[i+1] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_0 >> 18) & 0x3ffff ));
|
|
z[i+2] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_0 >> 36) & 0x3ffff ));
|
|
z[i+3] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_0 >> 54) | (((word32)s[8]) << 10)));
|
|
z[i+4] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
( s64_1 & 0x3ffff ));
|
|
z[i+5] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_1 >> 18) & 0x3ffff ));
|
|
z[i+6] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_1 >> 36) & 0x3ffff ));
|
|
z[i+7] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s64_1 >> 54) | (((word32)s[17]) << 10)));
|
|
#else
|
|
word32 s32_0 = ((const word32*)(s+0))[0];
|
|
word32 s32_1 = ((const word32*)(s+0))[1];
|
|
word32 s32_2 = ((const word32*)(s+9))[0];
|
|
word32 s32_3 = ((const word32*)(s+9))[1];
|
|
z[i+0] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
( s32_0 & 0x3ffff ));
|
|
z[i+1] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_0 >> 18) | (((s32_1 & 0x0000f) << 14))));
|
|
z[i+2] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_1 >> 4) & 0x3ffff ));
|
|
z[i+3] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_1 >> 22) | (((word32)s[8]) << 10 )));
|
|
z[i+4] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
( s32_2 & 0x3ffff ));
|
|
z[i+5] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_2 >> 18) | (((s32_3 & 0x0000f) << 14))));
|
|
z[i+6] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_3 >> 4) & 0x3ffff ));
|
|
z[i+7] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s32_3 >> 22) | (((word32)s[17]) << 10 )));
|
|
#endif
|
|
#else
|
|
z[i+0] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
( s[ 0] | ((sword32)(s[ 1] << 8) |
|
|
(sword32)(s[ 2] & 0x03) << 16)));
|
|
z[i+1] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s[ 2] >> 2) | ((sword32)(s[ 3] << 6) |
|
|
(sword32)(s[ 4] & 0x0f) << 14)));
|
|
z[i+2] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s[ 4] >> 4) | ((sword32)(s[ 5] << 4) |
|
|
(sword32)(s[ 6] & 0x3f) << 12)));
|
|
z[i+3] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s[ 6] >> 6) | ((sword32)(s[ 7] << 2) |
|
|
(sword32)(s[ 8] ) << 10)));
|
|
z[i+4] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
( s[ 9] | ((sword32)(s[10] << 8) |
|
|
(sword32)(s[11] & 0x03) << 16)));
|
|
z[i+5] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s[11] >> 2) | ((sword32)(s[12] << 6) |
|
|
(sword32)(s[13] & 0x0f) << 14)));
|
|
z[i+6] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s[13] >> 4) | ((sword32)(s[14] << 4) |
|
|
(sword32)(s[15] & 0x3f) << 12)));
|
|
z[i+7] = (sword32)((word32)DILITHIUM_GAMMA1_17 -
|
|
((s[15] >> 6) | ((sword32)(s[16] << 2) |
|
|
(sword32)(s[17] ) << 10)));
|
|
#endif
|
|
/* Move to next place to decode from. */
|
|
s += DILITHIUM_GAMMA1_17_ENC_BITS;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (bits == DILITHIUM_GAMMA1_BITS_19) {
|
|
#if defined(WOLFSSL_DILITHIUM_NO_LARGE_CODE) || defined(WOLFSSL_DILITHIUM_SMALL)
|
|
/* Step 4: Get 20 bits as a number. */
|
|
for (i = 0; i < DILITHIUM_N; i += 4) {
|
|
/* 20 bits per number.
|
|
* 4 numbers from 10 bytes. (4 * 20 bits = 10 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT <= 2)
|
|
word16 s16_0 = ((const word16*)s)[4];
|
|
#ifdef WC_64BIT_CPU
|
|
word64 s64_0 = *(const word64*)s;
|
|
z[i+0] = DILITHIUM_GAMMA1_19 - ( s64_0 & 0xfffff) ;
|
|
z[i+1] = DILITHIUM_GAMMA1_19 - ( (s64_0 >> 20) & 0xfffff) ;
|
|
z[i+2] = DILITHIUM_GAMMA1_19 - ( (s64_0 >> 40) & 0xfffff) ;
|
|
z[i+3] = DILITHIUM_GAMMA1_19 - (((s64_0 >> 60) & 0xfffff) |
|
|
((sword32)s16_0 << 4));
|
|
#else
|
|
word32 s32_0 = ((const word32*)s)[0];
|
|
word32 s32_1 = ((const word32*)s)[1];
|
|
z[i+0] = DILITHIUM_GAMMA1_19 - ( s32_0 & 0xfffff);
|
|
z[i+1] = DILITHIUM_GAMMA1_19 - (( s32_0 >> 20) |
|
|
((s32_1 & 0x000ff) << 12));
|
|
z[i+2] = DILITHIUM_GAMMA1_19 - ( (s32_1 >> 8) & 0xfffff);
|
|
z[i+3] = DILITHIUM_GAMMA1_19 - (( s32_1 >> 28) |
|
|
((sword32)s16_0 << 4));
|
|
#endif
|
|
#else
|
|
z[i+0] = DILITHIUM_GAMMA1_19 - ( s[0] | ((sword32)s[1] << 8) |
|
|
((sword32)(s[2] & 0x0f) << 16));
|
|
z[i+1] = DILITHIUM_GAMMA1_19 - ((s[2] >> 4) | ((sword32)s[3] << 4) |
|
|
((sword32)(s[4] ) << 12));
|
|
z[i+2] = DILITHIUM_GAMMA1_19 - ( s[5] | ((sword32)s[6] << 8) |
|
|
((sword32)(s[7] & 0x0f) << 16));
|
|
z[i+3] = DILITHIUM_GAMMA1_19 - ((s[7] >> 4) | ((sword32)s[8] << 4) |
|
|
((sword32)(s[9] ) << 12));
|
|
#endif
|
|
/* Move to next place to decode from. */
|
|
s += DILITHIUM_GAMMA1_19_ENC_BITS / 2;
|
|
}
|
|
#else
|
|
/* Step 4: Get 20 bits as a number. */
|
|
for (i = 0; i < DILITHIUM_N; i += 8) {
|
|
/* 20 bits per number.
|
|
* 8 numbers from 10 bytes. (8 * 20 bits = 20 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT <= 2)
|
|
word16 s16_0 = ((const word16*)s)[4];
|
|
word16 s16_1 = ((const word16*)s)[9];
|
|
#ifdef WC_64BIT_CPU
|
|
word64 s64_0 = *(const word64*)(s+0);
|
|
word64 s64_1 = *(const word64*)(s+10);
|
|
z[i+0] = DILITHIUM_GAMMA1_19 -
|
|
((sword32)( s64_0 & 0xfffff)) ;
|
|
z[i+1] = DILITHIUM_GAMMA1_19 -
|
|
((sword32)( (s64_0 >> 20) & 0xfffff)) ;
|
|
z[i+2] = DILITHIUM_GAMMA1_19 -
|
|
((sword32)( (s64_0 >> 40) & 0xfffff)) ;
|
|
z[i+3] = DILITHIUM_GAMMA1_19 -
|
|
((sword32)(((s64_0 >> 60) & 0xfffff)) |
|
|
((sword32)s16_0 << 4));
|
|
z[i+4] = DILITHIUM_GAMMA1_19 -
|
|
((sword32)( s64_1 & 0xfffff)) ;
|
|
z[i+5] = DILITHIUM_GAMMA1_19 -
|
|
((sword32)( (s64_1 >> 20) & 0xfffff)) ;
|
|
z[i+6] = DILITHIUM_GAMMA1_19 -
|
|
((sword32)( (s64_1 >> 40) & 0xfffff)) ;
|
|
z[i+7] = DILITHIUM_GAMMA1_19 -
|
|
((sword32)(((s64_1 >> 60) & 0xfffff)) |
|
|
((sword32)s16_1 << 4));
|
|
#else
|
|
word32 s32_0 = ((const word32*)(s+ 0))[0];
|
|
word32 s32_1 = ((const word32*)(s+ 0))[1];
|
|
word32 s32_2 = ((const word32*)(s+10))[0];
|
|
word32 s32_3 = ((const word32*)(s+10))[1];
|
|
z[i+0] = DILITHIUM_GAMMA1_19 - ( s32_0 & 0xfffff);
|
|
z[i+1] = DILITHIUM_GAMMA1_19 - (( s32_0 >> 20) |
|
|
((s32_1 & 0x000ff) << 12));
|
|
z[i+2] = DILITHIUM_GAMMA1_19 - ( (s32_1 >> 8) & 0xfffff);
|
|
z[i+3] = DILITHIUM_GAMMA1_19 - (( s32_1 >> 28) |
|
|
((sword32)s16_0 << 4));
|
|
z[i+4] = DILITHIUM_GAMMA1_19 - ( s32_2 & 0xfffff);
|
|
z[i+5] = DILITHIUM_GAMMA1_19 - (( s32_2 >> 20) |
|
|
((s32_3 & 0x000ff) << 12));
|
|
z[i+6] = DILITHIUM_GAMMA1_19 - ( (s32_3 >> 8) & 0xfffff);
|
|
z[i+7] = DILITHIUM_GAMMA1_19 - (( s32_3 >> 28) |
|
|
((sword32)s16_1 << 4));
|
|
#endif
|
|
#else
|
|
z[i+0] = DILITHIUM_GAMMA1_19 - ( s[ 0] |
|
|
((sword32)s[ 1] << 8) |
|
|
((sword32)(s[ 2] & 0x0f) << 16));
|
|
z[i+1] = DILITHIUM_GAMMA1_19 - ((s[ 2] >> 4) |
|
|
((sword32) s[ 3] << 4) |
|
|
((sword32)(s[ 4] ) << 12));
|
|
z[i+2] = DILITHIUM_GAMMA1_19 - ( s[ 5] |
|
|
((sword32) s[ 6] << 8) |
|
|
((sword32)(s[ 7] & 0x0f) << 16));
|
|
z[i+3] = DILITHIUM_GAMMA1_19 - ((s[ 7] >> 4) |
|
|
((sword32) s[ 8] << 4) |
|
|
((sword32)(s[ 9] ) << 12));
|
|
z[i+4] = DILITHIUM_GAMMA1_19 - ( s[10] |
|
|
((sword32) s[11] << 8) |
|
|
((sword32)(s[12] & 0x0f) << 16));
|
|
z[i+5] = DILITHIUM_GAMMA1_19 - ((s[12] >> 4) |
|
|
((sword32) s[13] << 4) |
|
|
((sword32)(s[14] ) << 12));
|
|
z[i+6] = DILITHIUM_GAMMA1_19 - ( s[15] |
|
|
((sword32) s[16] << 8) |
|
|
((sword32)(s[17] & 0x0f) << 16));
|
|
z[i+7] = DILITHIUM_GAMMA1_19 - ((s[17] >> 4) |
|
|
((sword32) s[18] << 4) |
|
|
((sword32)(s[19] ) << 12));
|
|
#endif
|
|
/* Move to next place to decode from. */
|
|
s += DILITHIUM_GAMMA1_19_ENC_BITS;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_VERIFY
|
|
/* Decode polynomial with range -(GAMMA1-1)..GAMMA1.
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 21 sigDecode(sigma)
|
|
* ...
|
|
* 3: for i from 0 to l - 1 do
|
|
* 4: z[i] <- BitUnpack(xi, GAMMA1 - 1, GAMMA1)
|
|
* 5: end for
|
|
* ...
|
|
*
|
|
* @param [in] x Encoded values of t0.
|
|
* @param [in] l Dimensions of vector z.
|
|
* @param [in] bits Number of bits used in encoding - GAMMA1 bits.
|
|
* @param [out] z Vector of polynomials.
|
|
*/
|
|
static void dilithium_vec_decode_gamma1(const byte* x, byte l, int bits,
|
|
sword32* z)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* Step 3: For each polynomial of vector. */
|
|
for (i = 0; i < l; i++) {
|
|
/* Step 4: Unpack a polynomial. */
|
|
dilithium_decode_gamma1(x, bits, z);
|
|
/* Move pointers on to next polynomial. */
|
|
x += DILITHIUM_N / 8 * (bits + 1);
|
|
z += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || !defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
/* Encode w1 with range of 0..((q-1)/(2*GAMMA2)-1).
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 22 w1Encode(w1)
|
|
* ...
|
|
* 3: w1_tilde <- w1_tilde ||
|
|
* ByteToBits(SimpleBitPack(w1[i], (q-1)/(2*GAMMA2)-1))
|
|
* ...
|
|
*
|
|
* @param [in] w1 Vector of polynomials to encode.
|
|
* @param [in] gamma2 Maximum value in range.
|
|
* @param [out] w1e Buffer to encode into.
|
|
*/
|
|
static void dilithium_encode_w1_88(const sword32* w1, byte* w1e)
|
|
{
|
|
unsigned int j;
|
|
|
|
/* Step 3: Encode a polynomial values 6 bits at a time. */
|
|
for (j = 0; j < DILITHIUM_N; j += 16) {
|
|
/* 6 bits per number.
|
|
* 16 numbers in 12 bytes. (16 * 6 bits = 12 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT <= 4)
|
|
word32* w1e32 = (word32*)w1e;
|
|
w1e32[0] = (word32)( w1[j+ 0] | (w1[j+ 1] << 6) |
|
|
(w1[j+ 2] << 12) | (w1[j+ 3] << 18) |
|
|
(w1[j+ 4] << 24) | (w1[j+ 5] << 30));
|
|
w1e32[1] = (word32)((w1[j+ 5] >> 2) | (w1[j+ 6] << 4) |
|
|
(w1[j+ 7] << 10) | (w1[j+ 8] << 16) |
|
|
(w1[j+ 9] << 22) | (w1[j+10] << 28));
|
|
w1e32[2] = (word32)((w1[j+10] >> 4) | (w1[j+11] << 2) |
|
|
(w1[j+12] << 8) | (w1[j+13] << 14) |
|
|
(w1[j+14] << 20) | (w1[j+15] << 26));
|
|
#else
|
|
w1e[ 0] = (byte)( w1[j+ 0] | (w1[j+ 1] << 6));
|
|
w1e[ 1] = (byte)((w1[j+ 1] >> 2) | (w1[j+ 2] << 4));
|
|
w1e[ 2] = (byte)((w1[j+ 2] >> 4) | (w1[j+ 3] << 2));
|
|
w1e[ 3] = (byte)( w1[j+ 4] | (w1[j+ 5] << 6));
|
|
w1e[ 4] = (byte)((w1[j+ 5] >> 2) | (w1[j+ 6] << 4));
|
|
w1e[ 5] = (byte)((w1[j+ 6] >> 4) | (w1[j+ 7] << 2));
|
|
w1e[ 6] = (byte)( w1[j+ 8] | (w1[j+ 9] << 6));
|
|
w1e[ 7] = (byte)((w1[j+ 9] >> 2) | (w1[j+10] << 4));
|
|
w1e[ 8] = (byte)((w1[j+10] >> 4) | (w1[j+11] << 2));
|
|
w1e[ 9] = (byte)( w1[j+12] | (w1[j+13] << 6));
|
|
w1e[10] = (byte)((w1[j+13] >> 2) | (w1[j+14] << 4));
|
|
w1e[11] = (byte)((w1[j+14] >> 4) | (w1[j+15] << 2));
|
|
#endif
|
|
/* Move to next place to encode to. */
|
|
w1e += DILITHIUM_Q_HI_88_ENC_BITS * 2;
|
|
}
|
|
}
|
|
#endif /* !WOLFSSL_NO_ML_DSA_44 */
|
|
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* Encode w1 with range of 0..((q-1)/(2*GAMMA2)-1).
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 22 w1Encode(w1)
|
|
* ...
|
|
* 3: w1_tilde <- w1_tilde ||
|
|
* ByteToBits(SimpleBitPack(w1[i], (q-1)/(2*GAMMA2)-1))
|
|
* ...
|
|
*
|
|
* @param [in] w1 Vector of polynomials to encode.
|
|
* @param [in] gamma2 Maximum value in range.
|
|
* @param [out] w1e Buffer to encode into.
|
|
*/
|
|
static void dilithium_encode_w1_32(const sword32* w1, byte* w1e)
|
|
{
|
|
unsigned int j;
|
|
|
|
/* Step 3: Encode a polynomial values 4 bits at a time. */
|
|
for (j = 0; j < DILITHIUM_N; j += 16) {
|
|
/* 4 bits per number.
|
|
* 16 numbers in 8 bytes. (16 * 4 bits = 8 * 8 bits) */
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT <= 8)
|
|
word32* w1e32 = (word32*)w1e;
|
|
w1e32[0] = (word32)((w1[j + 0] << 0) | (w1[j + 1] << 4) |
|
|
(w1[j + 2] << 8) | (w1[j + 3] << 12) |
|
|
(w1[j + 4] << 16) | (w1[j + 5] << 20) |
|
|
(w1[j + 6] << 24) | (w1[j + 7] << 28));
|
|
w1e32[1] = (word32)((w1[j + 8] << 0) | (w1[j + 9] << 4) |
|
|
(w1[j + 10] << 8) | (w1[j + 11] << 12) |
|
|
(w1[j + 12] << 16) | (w1[j + 13] << 20) |
|
|
(w1[j + 14] << 24) | (w1[j + 15] << 28));
|
|
#else
|
|
w1e[0] = (byte)(w1[j + 0] | (w1[j + 1] << 4));
|
|
w1e[1] = (byte)(w1[j + 2] | (w1[j + 3] << 4));
|
|
w1e[2] = (byte)(w1[j + 4] | (w1[j + 5] << 4));
|
|
w1e[3] = (byte)(w1[j + 6] | (w1[j + 7] << 4));
|
|
w1e[4] = (byte)(w1[j + 8] | (w1[j + 9] << 4));
|
|
w1e[5] = (byte)(w1[j + 10] | (w1[j + 11] << 4));
|
|
w1e[6] = (byte)(w1[j + 12] | (w1[j + 13] << 4));
|
|
w1e[7] = (byte)(w1[j + 14] | (w1[j + 15] << 4));
|
|
#endif
|
|
/* Move to next place to encode to. */
|
|
w1e += DILITHIUM_Q_HI_32_ENC_BITS * 2;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM))
|
|
/* Encode w1 with range of 0..((q-1)/(2*GAMMA2)-1).
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 22 w1Encode(w1)
|
|
* 1: w1_tilde = ()
|
|
* 2: for i form 0 to k - 1 do
|
|
* 3: w1_tilde <- w1_tilde ||
|
|
* ByteToBits(SimpleBitPack(w1[i], (q-1)/(2*GAMMA2)-1))
|
|
* 4: end for
|
|
* 5: return w1_tilde
|
|
*
|
|
* @param [in] w1 Vector of polynomials to encode.
|
|
* @param [in] k Dimension of vector.
|
|
* @param [in] gamma2 Maximum value in range.
|
|
* @param [out] w1e Buffer to encode into.
|
|
*/
|
|
static void dilithium_vec_encode_w1(const sword32* w1, byte k, sword32 gamma2,
|
|
byte* w1e)
|
|
{
|
|
unsigned int i;
|
|
|
|
(void)k;
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (gamma2 == DILITHIUM_Q_LOW_88) {
|
|
/* Step 2. For each polynomial of vector. */
|
|
for (i = 0; i < PARAMS_ML_DSA_44_K; i++) {
|
|
dilithium_encode_w1_88(w1, w1e);
|
|
/* Next polynomial. */
|
|
w1 += DILITHIUM_N;
|
|
w1e += DILITHIUM_Q_HI_88_ENC_BITS * 2 * DILITHIUM_N / 16;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (gamma2 == DILITHIUM_Q_LOW_32) {
|
|
/* Step 2. For each polynomial of vector. */
|
|
for (i = 0; i < k; i++) {
|
|
dilithium_encode_w1_32(w1, w1e);
|
|
/* Next polynomial. */
|
|
w1 += DILITHIUM_N;
|
|
w1e += DILITHIUM_Q_HI_32_ENC_BITS * 2 * DILITHIUM_N / 16;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* Expand operations
|
|
******************************************************************************/
|
|
|
|
/* Generate a random polynomial by rejection.
|
|
*
|
|
* FIPS 204. 8.3: Algorithm 24 RejNTTPoly(rho)
|
|
* 1: j <- 0
|
|
* 2: c <- 0
|
|
* 3: while j < 256 do
|
|
* 4: a_hat[j] <- CoeffFromThreeBytes(H128(rho)[[c]], H128(rho)[[c+1]],
|
|
* H128(rho)[[c+2]])
|
|
* 5: c <- c + 3
|
|
* 6: if a_hat[j] != falsam then
|
|
* 7: j <- j + 1
|
|
* 8: end if
|
|
* 9: end while
|
|
* 10: return a_hat
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 8 CoeffFromThreeBytes(b0,b1,b2)
|
|
* 1: if b2 > 127 then
|
|
* 2: b2 <- b2 - 128
|
|
* 3. end if
|
|
* 4. z <- 2^16.b2 + s^8.b1 + b0
|
|
* 5. if z < q then return z
|
|
* 6. else return falsam
|
|
* 7. end if
|
|
*
|
|
* @param [in, out] shake128 SHAKE-128 object.
|
|
* @param [in] seed Seed to hash to generate values.
|
|
* @param [out] a Polynomial.
|
|
* @param [in] h Buffer to hold hashes.
|
|
* @return 0 on success.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_rej_ntt_poly_ex(wc_Shake* shake128, byte* seed, sword32* a,
|
|
byte* h)
|
|
{
|
|
int ret = 0;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
int j = 0;
|
|
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
/* Reading 4 bytes for 3 so need to set 1 past for last read. */
|
|
h[DILITHIUM_GEN_A_BLOCK_BYTES] = 0;
|
|
#endif
|
|
|
|
/* Initialize SHAKE-128 object for new hash. */
|
|
ret = wc_InitShake128(shake128, NULL, INVALID_DEVID);
|
|
if (ret == 0) {
|
|
/* Absorb the seed. */
|
|
ret = wc_Shake128_Absorb(shake128, seed, DILITHIUM_GEN_A_SEED_SZ);
|
|
}
|
|
/* Keep generating more blocks and using triplets until we have enough.
|
|
*/
|
|
while ((ret == 0) && (j < DILITHIUM_N)) {
|
|
/* Squeeze out a block - 168 bytes = 56 values. */
|
|
ret = wc_Shake128_SqueezeBlocks(shake128, h, 1);
|
|
if (ret == 0) {
|
|
int c;
|
|
/* Use triplets until run out or have enough for polynomial. */
|
|
for (c = 0; c < DILITHIUM_GEN_A_BLOCK_BYTES; c += 3) {
|
|
#if defined(LITTLE_ENDIAN_ORDER) && \
|
|
(WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
/* Load 32-bit value and mask out 23 bits. */
|
|
sword32 t = *((sword32*)(h + c)) & 0x7fffff;
|
|
#else
|
|
/* Load 24-bit value and mask out 23 bits. */
|
|
sword32 t = (h[c] + ((sword32)h[c+1] << 8) +
|
|
((sword32)h[c+2] << 16)) & 0x7fffff;
|
|
#endif
|
|
/* Check if value is in valid range. */
|
|
if (t < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values.
|
|
*/
|
|
a[j++] = t;
|
|
/* Check we whether we have enough yet. */
|
|
if (j == DILITHIUM_N) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
unsigned int j = 0;
|
|
unsigned int c;
|
|
|
|
/* Generate enough SHAKE-128 output blocks to give high probability of
|
|
* being able to get 256 valid 3-byte, 23-bit values from it. */
|
|
ret = dilithium_squeeze128(shake128, seed, DILITHIUM_GEN_A_SEED_SZ, h,
|
|
DILITHIUM_GEN_A_NBLOCKS);
|
|
if (ret == 0) {
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
/* Reading 4 bytes for 3 so need to set 1 past for last read. */
|
|
h[DILITHIUM_GEN_A_BYTES] = 0;
|
|
#endif
|
|
|
|
/* Use the first 256 triplets and know we won't exceed required. */
|
|
#ifdef WOLFSSL_DILITHIUM_NO_LARGE_CODE
|
|
for (c = 0; c < (DILITHIUM_N - 1) * 3; c += 3) {
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
/* Load 32-bit value and mask out 23 bits. */
|
|
sword32 t = *((sword32*)(h + c)) & 0x7fffff;
|
|
#else
|
|
/* Load 24-bit value and mask out 23 bits. */
|
|
sword32 t = (h[c] + ((sword32)h[c+1] << 8) +
|
|
((sword32)h[c+2] << 16)) & 0x7fffff;
|
|
#endif
|
|
/* Check if value is in valid range. */
|
|
if (t < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t;
|
|
}
|
|
}
|
|
/* Use the remaining triplets, checking we have enough. */
|
|
for (; c < DILITHIUM_GEN_A_BYTES; c += 3) {
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
/* Load 32-bit value and mask out 23 bits. */
|
|
sword32 t = *((sword32*)(h + c)) & 0x7fffff;
|
|
#else
|
|
/* Load 24-bit value and mask out 23 bits. */
|
|
sword32 t = (h[c] + ((sword32)h[c+1] << 8) +
|
|
((sword32)h[c+2] << 16)) & 0x7fffff;
|
|
#endif
|
|
/* Check if value is in valid range. */
|
|
if (t < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t;
|
|
/* Check we whether we have enough yet. */
|
|
if (j == DILITHIUM_N) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
/* Do 15 bytes at a time: 255 * 3 / 15 = 51 */
|
|
for (c = 0; c < DILITHIUM_N * 3; c += 24) {
|
|
#if defined(LITTLE_ENDIAN_ORDER) && (WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
/* Load 32-bit value and mask out 23 bits. */
|
|
sword32 t0 = *((sword32*)(h + c + 0)) & 0x7fffff;
|
|
sword32 t1 = *((sword32*)(h + c + 3)) & 0x7fffff;
|
|
sword32 t2 = *((sword32*)(h + c + 6)) & 0x7fffff;
|
|
sword32 t3 = *((sword32*)(h + c + 9)) & 0x7fffff;
|
|
sword32 t4 = *((sword32*)(h + c + 12)) & 0x7fffff;
|
|
sword32 t5 = *((sword32*)(h + c + 15)) & 0x7fffff;
|
|
sword32 t6 = *((sword32*)(h + c + 18)) & 0x7fffff;
|
|
sword32 t7 = *((sword32*)(h + c + 21)) & 0x7fffff;
|
|
#else
|
|
/* Load 24-bit value and mask out 23 bits. */
|
|
sword32 t0 = (h[c + 0] + ((sword32)h[c + 1] << 8) +
|
|
((sword32)h[c + 2] << 16)) & 0x7fffff;
|
|
sword32 t1 = (h[c + 3] + ((sword32)h[c + 4] << 8) +
|
|
((sword32)h[c + 5] << 16)) & 0x7fffff;
|
|
sword32 t2 = (h[c + 6] + ((sword32)h[c + 7] << 8) +
|
|
((sword32)h[c + 8] << 16)) & 0x7fffff;
|
|
sword32 t3 = (h[c + 9] + ((sword32)h[c + 10] << 8) +
|
|
((sword32)h[c + 11] << 16)) & 0x7fffff;
|
|
sword32 t4 = (h[c + 12] + ((sword32)h[c + 13] << 8) +
|
|
((sword32)h[c + 14] << 16)) & 0x7fffff;
|
|
sword32 t5 = (h[c + 15] + ((sword32)h[c + 16] << 8) +
|
|
((sword32)h[c + 17] << 16)) & 0x7fffff;
|
|
sword32 t6 = (h[c + 18] + ((sword32)h[c + 19] << 8) +
|
|
((sword32)h[c + 20] << 16)) & 0x7fffff;
|
|
sword32 t7 = (h[c + 21] + ((sword32)h[c + 22] << 8) +
|
|
((sword32)h[c + 23] << 16)) & 0x7fffff;
|
|
#endif
|
|
/* Check if value is in valid range. */
|
|
if (t0 < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t0;
|
|
}
|
|
/* Check if value is in valid range. */
|
|
if (t1 < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t1;
|
|
}
|
|
/* Check if value is in valid range. */
|
|
if (t2 < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t2;
|
|
}
|
|
/* Check if value is in valid range. */
|
|
if (t3 < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t3;
|
|
}
|
|
/* Check if value is in valid range. */
|
|
if (t4 < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t4;
|
|
}
|
|
/* Check if value is in valid range. */
|
|
if (t5 < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t5;
|
|
}
|
|
/* Check if value is in valid range. */
|
|
if (t6 < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t6;
|
|
}
|
|
/* Check if value is in valid range. */
|
|
if (t7 < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values. */
|
|
a[j++] = t7;
|
|
}
|
|
}
|
|
if (j < DILITHIUM_N) {
|
|
/* Use the remaining triplets, checking we have enough. */
|
|
for (; c < DILITHIUM_GEN_A_BYTES; c += 3) {
|
|
#if defined(LITTLE_ENDIAN_ORDER) && \
|
|
(WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
/* Load 32-bit value and mask out 23 bits. */
|
|
sword32 t = *((sword32*)(h + c)) & 0x7fffff;
|
|
#else
|
|
/* Load 24-bit value and mask out 23 bits. */
|
|
sword32 t = (h[c] + ((sword32)h[c+1] << 8) +
|
|
((sword32)h[c+2] << 16)) & 0x7fffff;
|
|
#endif
|
|
/* Check if value is in valid range. */
|
|
if (t < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values.
|
|
*/
|
|
a[j++] = t;
|
|
/* Check we whether we have enough yet. */
|
|
if (j == DILITHIUM_N) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/* Keep generating more blocks and using triplets until we have enough.
|
|
*/
|
|
while (j < DILITHIUM_N) {
|
|
/* Squeeze out a block - 168 bytes = 56 values. */
|
|
ret = wc_Shake128_SqueezeBlocks(shake128, h, 1);
|
|
if (ret != 0) {
|
|
break;
|
|
}
|
|
/* Use triplets until run out or have enough for polynomial. */
|
|
for (c = 0; c < DILITHIUM_GEN_A_BLOCK_BYTES; c += 3) {
|
|
#if defined(LITTLE_ENDIAN_ORDER) && \
|
|
(WOLFSSL_DILITHIUM_ALIGNMENT == 0)
|
|
/* Load 32-bit value and mask out 23 bits. */
|
|
sword32 t = *((sword32*)(h + c)) & 0x7fffff;
|
|
#else
|
|
/* Load 24-bit value and mask out 23 bits. */
|
|
sword32 t = (h[c] + ((sword32)h[c+1] << 8) +
|
|
((sword32)h[c+2] << 16)) & 0x7fffff;
|
|
#endif
|
|
/* Check if value is in valid range. */
|
|
if (t < DILITHIUM_Q) {
|
|
/* Store value in polynomial and increment count of values.
|
|
*/
|
|
a[j++] = t;
|
|
/* Check we whether we have enough yet. */
|
|
if (j == DILITHIUM_N) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if (!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
|
|
!defined(WOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM)) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM))
|
|
/* Generate a random polynomial by rejection.
|
|
*
|
|
* @param [in, out] shake128 SHAKE-128 object.
|
|
* @param [in] seed Seed to hash to generate values.
|
|
* @param [out] a Polynomial.
|
|
* @param [in] heap Dynamic memory hint.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_rej_ntt_poly(wc_Shake* shake128, byte* seed, sword32* a,
|
|
void* heap)
|
|
{
|
|
int ret = 0;
|
|
#if defined(WOLFSSL_SMALL_STACK)
|
|
byte* h = NULL;
|
|
#else
|
|
byte h[DILITHIUM_REJ_NTT_POLY_H_SIZE];
|
|
#endif
|
|
|
|
(void)heap;
|
|
|
|
#if defined(WOLFSSL_SMALL_STACK)
|
|
h = (byte*)XMALLOC(DILITHIUM_REJ_NTT_POLY_H_SIZE, heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (h == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0)
|
|
ret = dilithium_rej_ntt_poly_ex(shake128, seed, a, h);
|
|
|
|
#if defined(WOLFSSL_SMALL_STACK)
|
|
XFREE(h, heap, DYNAMIC_TYPE_DILITHIUM);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if (!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
|
|
!defined(WOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM)) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM)) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
(!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM) || \
|
|
defined(WC_DILITHIUM_CACHE_MATRIX_A)))
|
|
/* Expand the seed to create matrix a.
|
|
*
|
|
* FIPS 204. 8.3: Algorithm 26 ExpandA(rho)
|
|
* 1: for r from 0 to k - 1 do
|
|
* 2: for s from 0 to l - 1 do
|
|
* 3: A_hat[r,s] <- RejNTTPoly(rho||IntegerToBits(s,8)||
|
|
* IntegerToBits(r,8))
|
|
* 4: end for
|
|
* 5: end for
|
|
* 6: return A_hat
|
|
*
|
|
* @param [in, out] shake128 SHAKE-128 object.
|
|
* @param [in] pub_seed Seed to generate stream of data.
|
|
* @param [in] k First dimension of matrix a.
|
|
* @param [in] l Second dimension of matrix a.
|
|
* @param [out] a Matrix of polynomials.
|
|
* @param [in] heap Dynamic memory hint.
|
|
* @return 0 on success.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_expand_a(wc_Shake* shake128, const byte* pub_seed, byte k,
|
|
byte l, sword32* a, void* heap)
|
|
{
|
|
int ret = 0;
|
|
byte r;
|
|
byte s;
|
|
byte seed[DILITHIUM_GEN_A_SEED_SZ];
|
|
|
|
/* Copy the seed into a buffer that has space for s and r. */
|
|
XMEMCPY(seed, pub_seed, DILITHIUM_PUB_SEED_SZ);
|
|
/* Step 1: Loop over first dimension of matrix. */
|
|
for (r = 0; (ret == 0) && (r < k); r++) {
|
|
/* Put r into buffer to be hashed. */
|
|
seed[DILITHIUM_PUB_SEED_SZ + 1] = r;
|
|
/* Step 2: Loop over second dimension of matrix. */
|
|
for (s = 0; (ret == 0) && (s < l); s++) {
|
|
/* Put s into buffer to be hashed. */
|
|
seed[DILITHIUM_PUB_SEED_SZ + 0] = s;
|
|
/* Step 3: Create polynomial from hashing seed. */
|
|
ret = dilithium_rej_ntt_poly(shake128, seed, a, heap);
|
|
/* Next polynomial. */
|
|
a += DILITHIUM_N;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY
|
|
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* Check random value is in valid range.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 1: if b < 15
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result. Will always be 2 - unused.
|
|
* @return 1 when value less than 9.
|
|
* @return 0 when value greater than or equal to 9.
|
|
*/
|
|
#define DILITHIUM_COEFF_S_VALID_ETA2(b) \
|
|
((b) < DILITHIUM_ETA_2_MOD)
|
|
|
|
static const char dilithium_coeff_eta2[] = {
|
|
2, 1, 0, -1, -2,
|
|
2, 1, 0, -1, -2,
|
|
2, 1, 0, -1, -2
|
|
};
|
|
/* Convert random value 0..15 to a value in range of -2..2.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 1: return 2 - (b mod 5)
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @return Value in range of -2..2 on success.
|
|
*/
|
|
#define DILITHIUM_COEFF_S_ETA2(b) \
|
|
(dilithium_coeff_eta2[b])
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
/* Check random value is in valid range.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 3: if b < 9
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result. Will always be 4 - unused.
|
|
* @return 1 when value less than 9.
|
|
* @return 0 when value greater than or equal to 9.
|
|
*/
|
|
#define DILITHIUM_COEFF_S_VALID_ETA4(b) \
|
|
((b) < DILITHIUM_ETA_4_MOD)
|
|
|
|
/* Convert random value 0..15 to a value in range of -4..4.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 3: return 4 - b
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result. Will always be 4 - unused.
|
|
* @return Value in range of -4..4 on success.
|
|
*/
|
|
#define DILITHIUM_COEFF_S_ETA4(b) \
|
|
(4 - (b))
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
|
|
/* Check random value is in valid range.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 1: if eta = 2 and b < 15
|
|
* 2: else
|
|
* 3: if eta = 4 and b < 9
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result.
|
|
* @return Value in range of -ETA..ETA on success.
|
|
*/
|
|
#define DILITHIUM_COEFF_S_VALID(b, eta) \
|
|
(((eta) == DILITHIUM_ETA_2) ? DILITHIUM_COEFF_S_VALID_ETA2(b) : \
|
|
DILITHIUM_COEFF_S_VALID_ETA4(b))
|
|
|
|
/* Convert random value 0..15 to a value in range of -ETA..ETA.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 1: if eta = 2 then return 2 - (b mod 5)
|
|
* 2: else
|
|
* 3: if eta = 4 then return 4 - b
|
|
* ...
|
|
* 6: end if
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result.
|
|
* @return Value in range of -ETA..ETA on success.
|
|
*/
|
|
#define DILITHIUM_COEFF_S(b, eta) \
|
|
(((eta) == DILITHIUM_ETA_2) ? DILITHIUM_COEFF_S_ETA2(b) \
|
|
: DILITHIUM_COEFF_S_ETA4(b))
|
|
|
|
#else
|
|
|
|
/* Check random value is in valid range.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 1: if b < 15
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result. Will always be 2 - unused.
|
|
* @return 1 when value less than 9.
|
|
* @return 0 when value greater than or equal to 9.
|
|
*/
|
|
#define DILITHIUM_COEFF_S_VALID(b, eta) \
|
|
DILITHIUM_COEFF_S_VALID_ETA2(b)
|
|
|
|
/* Convert random value 0..15 to a value in range of -2..2.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 1: return 2 - (b mod 5)
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result. Will always be 2 - unused.
|
|
* @return Value in range of -2..2 on success.
|
|
*/
|
|
#define DILITHIUM_COEFF_S(b, eta) \
|
|
DILITHIUM_COEFF_S_ETA2(b)
|
|
|
|
#endif /* WOLFSSL_NO_ML_DSA_65 */
|
|
|
|
#else
|
|
|
|
/* Check random value is in valid range.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 3: if b < 9
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result. Will always be 4 - unused.
|
|
* @return 1 when value less than 9.
|
|
* @return 0 when value greater than or equal to 9.
|
|
*/
|
|
#define DILITHIUM_COEFF_S_VALID(b, eta) \
|
|
DILITHIUM_COEFF_S_VALID_ETA4(b)
|
|
|
|
/* Convert random value 0..15 to a value in range of -4..4.
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 9 CoeffFromHalfByte(b)
|
|
* 3: return 4 - b
|
|
*
|
|
* @param [in] b Random half-byte (nibble) value.
|
|
* @param [in] eta Range specifier of result. Will always be 4 - unused.
|
|
* @return Value in range of -4..4 on success.
|
|
*/
|
|
#define DILITHIUM_COEFF_S(b, eta) \
|
|
DILITHIUM_COEFF_S_ETA4(b)
|
|
|
|
#endif /* !WOLFSSL_NO_ML_DSA_44 || !WOLFSSL_NO_ML_DSA_87 */
|
|
|
|
/* Extract a coefficient from a nibble of z.
|
|
*
|
|
* Breaks out of loop when we have enough coefficients.
|
|
*
|
|
* @param [in] z A random value.
|
|
* @param [in] rs Amount to shift right.
|
|
* @param [in] t Temporary result.
|
|
* @param [in] eta ETA value from parameters.
|
|
* @return Value in range -eta..eta on success.
|
|
* @return Falsam (0x10) when random value out of range.
|
|
*/
|
|
#define EXTRACT_COEFF_NIBBLE_CHECK_J(z, rs, t, eta) \
|
|
(t) = (sword8)(((z) >> (rs)) & 0xf); \
|
|
/* Step 7: Check we have a valid coefficient. */ \
|
|
if (DILITHIUM_COEFF_S_VALID(t, eta)) { \
|
|
(t) = DILITHIUM_COEFF_S(t, eta); \
|
|
/* Step 8: Store coefficient as next polynomial value. \
|
|
* Step 9: Increment count of polynomial values set. */ \
|
|
s[j++] = (sword32)(t); \
|
|
if (j == DILITHIUM_N) { \
|
|
break; \
|
|
} \
|
|
}
|
|
|
|
/* Extract a coefficient from a nibble of z.
|
|
*
|
|
* @param [in] z A random value.
|
|
* @param [in] rs Amount to shift right.
|
|
* @param [in] t Temporary result.
|
|
* @param [in] eta ETA value from parameters.
|
|
* @return Value in range -eta..eta on success.
|
|
* @return Falsam (0x10) when random value out of range.
|
|
*/
|
|
#define EXTRACT_COEFF_NIBBLE(z, rs, t, eta) \
|
|
(t) = (sword8)(((z) >> (rs)) & 0xf); \
|
|
/* Step 7: Check we have a valid coefficient. */ \
|
|
if (DILITHIUM_COEFF_S_VALID(t, eta)) { \
|
|
(t) = DILITHIUM_COEFF_S(t, eta); \
|
|
/* Step 8: Store coefficient as next polynomial value. \
|
|
* Step 9: Increment count of polynomial values set. */ \
|
|
s[j++] = (sword32)(t); \
|
|
}
|
|
|
|
|
|
/* Extract coefficients from hash - z.
|
|
*
|
|
* FIPS 204. 8.3: Algorithm 25 RejBoundedPoly(rho)
|
|
* 2: c <- 0
|
|
* 5: z0 <- CoeffFromHalfByte(z mod 16, eta)
|
|
* 6: z1 <- CoeffFromHalfByte(lower(z / 16), eta)
|
|
* 7: if z0 != falsam then
|
|
* 8: aj <- z0
|
|
* 9: j <- j + 1
|
|
* 10: end if
|
|
* 11: if z1 != falsam then
|
|
* 12: aj <- z1
|
|
* 13: j <- j + 1
|
|
* 14: end if
|
|
* 15: c <- c + 1
|
|
*
|
|
* @param [in] z Hash data to extract coefficients from.
|
|
* @param [in] zLen Length of z in bytes.
|
|
* @param [in] eta Range specifier of each value.
|
|
* @param [out] s Polynomial to fill with coefficients.
|
|
* @param [in, out] cnt Current count of coefficients in polynomial.
|
|
*/
|
|
static void dilithium_extract_coeffs(byte* z, unsigned int zLen, byte eta,
|
|
sword32* s, unsigned int* cnt)
|
|
{
|
|
#ifdef WOLFSSL_DILITHIUM_NO_LARGE_CODE
|
|
unsigned int j = *cnt;
|
|
unsigned int c;
|
|
|
|
(void)eta;
|
|
|
|
/* Extract values from the squeezed data. */
|
|
for (c = 0; c < zLen; c++) {
|
|
sword8 t;
|
|
|
|
/* Step 5: Get coefficient from bottom nibble. */
|
|
EXTRACT_COEFF_NIBBLE_CHECK_J(z[c], 0, t, eta);
|
|
/* Step 6: Get coefficient from top nibble. */
|
|
EXTRACT_COEFF_NIBBLE_CHECK_J(z[c], 4, t, eta);
|
|
}
|
|
|
|
*cnt = j;
|
|
#else
|
|
unsigned int j = *cnt;
|
|
unsigned int c;
|
|
unsigned int min = (DILITHIUM_N - j) / 2;
|
|
|
|
(void)eta;
|
|
|
|
#if defined(LITTLE_ENDIAN_ORDER)
|
|
#ifdef WC_64BIT_CPU
|
|
min &= ~(unsigned int)7;
|
|
/* Extract values from the squeezed data. */
|
|
for (c = 0; c < min; c += 8) {
|
|
word64 z64 = *(word64*)(z + c);
|
|
sword8 t;
|
|
|
|
/* Do each nibble from lowest to highest 16 at a time. */
|
|
EXTRACT_COEFF_NIBBLE(z64, 0, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 4, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 8, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 12, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 16, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 20, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 24, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 28, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 32, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 36, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 40, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 44, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 48, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 52, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 56, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z64, 60, t, eta);
|
|
}
|
|
#else
|
|
min &= ~(unsigned int)3;
|
|
/* Extract values from the squeezed data. */
|
|
for (c = 0; c < min; c += 4) {
|
|
word32 z32 = *(word32*)(z + c);
|
|
sword8 t;
|
|
|
|
/* Do each nibble from lowest to highest 8 at a time. */
|
|
EXTRACT_COEFF_NIBBLE(z32, 0, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z32, 4, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z32, 8, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z32, 12, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z32, 16, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z32, 20, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z32, 24, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z32, 28, t, eta);
|
|
}
|
|
#endif
|
|
#else
|
|
/* Extract values from the squeezed data. */
|
|
for (c = 0; c < min; c++) {
|
|
sword8 t;
|
|
|
|
/* Step 5: Get coefficient from bottom nibble. */
|
|
EXTRACT_COEFF_NIBBLE(z[c], 0, t, eta);
|
|
EXTRACT_COEFF_NIBBLE(z[c], 4, t, eta);
|
|
}
|
|
#endif
|
|
if (j != DILITHIUM_N) {
|
|
/* Extract values from the squeezed data. */
|
|
for (; c < zLen; c++) {
|
|
sword8 t;
|
|
|
|
EXTRACT_COEFF_NIBBLE_CHECK_J(z[c], 0, t, eta);
|
|
EXTRACT_COEFF_NIBBLE_CHECK_J(z[c], 4, t, eta);
|
|
}
|
|
}
|
|
|
|
*cnt = j;
|
|
#endif
|
|
}
|
|
|
|
/* Create polynomial from hashing the seed with bounded values.
|
|
*
|
|
* FIPS 204. 8.3: Algorithm 25 RejBoundedPoly(rho)
|
|
* 1: j <- 0
|
|
* ...
|
|
* 3: while j < 256 do
|
|
* 4: z <- H(rho)[[c]]
|
|
* ... [Extract coefficients into polynomial from z]
|
|
* 16: end while
|
|
* 17: return a
|
|
*
|
|
* @param [in, out] shake256 SHAKE-256 object.
|
|
* @param [in] seed Seed, rho, to hash to generate values.
|
|
* @param [in] eta Range specifier of each value.
|
|
* @return 0 on success.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_rej_bound_poly(wc_Shake* shake256, byte* seed, sword32* s,
|
|
byte eta)
|
|
{
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
int ret;
|
|
unsigned int j = 0;
|
|
byte z[DILITHIUM_GEN_S_BLOCK_BYTES];
|
|
|
|
/* Initialize SHAKE-256 object for new hash. */
|
|
ret = wc_InitShake256(shake256, NULL, INVALID_DEVID);
|
|
if (ret == 0) {
|
|
/* Absorb the seed. */
|
|
ret = wc_Shake256_Absorb(shake256, seed, DILITHIUM_GEN_S_SEED_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
do {
|
|
/* Squeeze out another block. */
|
|
ret = wc_Shake256_SqueezeBlocks(shake256, z, 1);
|
|
if (ret != 0) {
|
|
break;
|
|
}
|
|
/* Extract up to the 256 valid coefficients for polynomial. */
|
|
dilithium_extract_coeffs(z, DILITHIUM_GEN_S_BLOCK_BYTES, eta, s,
|
|
&j);
|
|
}
|
|
/* Check we got enough values to fill polynomial. */
|
|
while (j < DILITHIUM_N);
|
|
}
|
|
|
|
return ret;
|
|
#else
|
|
int ret;
|
|
unsigned int j = 0;
|
|
byte z[DILITHIUM_GEN_S_BYTES];
|
|
|
|
/* Absorb seed and squeeze out some blocks. */
|
|
ret = dilithium_squeeze256(shake256, seed, DILITHIUM_GEN_S_SEED_SZ, z,
|
|
DILITHIUM_GEN_S_NBLOCKS);
|
|
if (ret == 0) {
|
|
/* Extract up to 256 valid coefficients for polynomial. */
|
|
dilithium_extract_coeffs(z, DILITHIUM_GEN_S_BYTES, eta, s, &j);
|
|
/* Check we got enough values to fill polynomial. */
|
|
while (j < DILITHIUM_N) {
|
|
/* Squeeze out another block. */
|
|
ret = wc_Shake256_SqueezeBlocks(shake256, z, 1);
|
|
if (ret != 0) {
|
|
break;
|
|
}
|
|
/* Extract up to the 256 valid coefficients for polynomial. */
|
|
dilithium_extract_coeffs(z, DILITHIUM_GEN_S_BLOCK_BYTES, eta, s,
|
|
&j);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
/* Expand private seed into vectors s1 and s2.
|
|
*
|
|
* FIPS 204. 8.3: Algorithm 27 ExpandS(rho)
|
|
* 1: for r from 0 to l - 1 do
|
|
* 2: s1[r] <- RejBoundedPoly(rho||IntegerToBits(r,16))
|
|
* 3: end for
|
|
* 4: for r from 0 to k - 1 do
|
|
* 5: s2[r] <- RejBoundedPoly(rho||IntegerToBits(r + l,16))
|
|
* 6: end for
|
|
* 7: return (s1,s2)
|
|
*
|
|
* @param [in, out] shake256 SHAKE-256 object.
|
|
* @param [in] priv_seed Private seed, rho, to expand.
|
|
* @param [in] eta Range specifier of each value.
|
|
* @param [out] s1 First vector of polynomials.
|
|
* @param [in] s1Len Dimension of first vector.
|
|
* @param [out] s2 Second vector of polynomials.
|
|
* @param [in] s2Len Dimension of second vector.
|
|
* @return 0 on success.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_expand_s(wc_Shake* shake256, byte* priv_seed, byte eta,
|
|
sword32* s1, byte s1Len, sword32* s2, byte s2Len)
|
|
{
|
|
int ret = 0;
|
|
byte r;
|
|
byte seed[DILITHIUM_GEN_S_SEED_SZ];
|
|
|
|
/* Copy the seed into a buffer that has space for r. */
|
|
XMEMCPY(seed, priv_seed, DILITHIUM_PRIV_SEED_SZ);
|
|
/* Set top 8-bits of r in buffer to 0. */
|
|
seed[DILITHIUM_PRIV_SEED_SZ + 1] = 0;
|
|
/* Step 1: Each polynomial in s1. */
|
|
for (r = 0; (ret == 0) && (r < s1Len); r++) {
|
|
/* Set bottom 8-bits of r into buffer - little endian. */
|
|
seed[DILITHIUM_PRIV_SEED_SZ] = r;
|
|
|
|
/* Step 2: Generate polynomial for s1. */
|
|
ret = dilithium_rej_bound_poly(shake256, seed, s1, eta);
|
|
/* Next polynomial in s1. */
|
|
s1 += DILITHIUM_N;
|
|
}
|
|
/* Step 4: Each polynomial in s2. */
|
|
for (r = 0; (ret == 0) && (r < s2Len); r++) {
|
|
/* Set bottom 8-bits of r + l into buffer - little endian. */
|
|
seed[DILITHIUM_PRIV_SEED_SZ] = r + s1Len;
|
|
/* Step 5: Generate polynomial for s1. */
|
|
ret = dilithium_rej_bound_poly(shake256, seed, s2, eta);
|
|
/* Next polynomial in s2. */
|
|
s2 += DILITHIUM_N;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_MAKE_KEY */
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_SIGN
|
|
/* Expand the private random seed into vector y.
|
|
*
|
|
* FIPS 204. 8.3: Algorithm 28 ExpandMask(rho, mu)
|
|
* 1: c <- 1 + bitlen(GAMMA1 - 1)
|
|
* 2: for r from 0 to l - 1 do
|
|
* 3: n <- IntegerToBits(mu + r, 16)
|
|
* 4: v <- (H(rho||n)[[32rc]], H(rho||n)[[32rc + 1]], ...,
|
|
* H(rho||n)[[32rc + 32c - 1]])
|
|
* 5: s[r] <- BitUnpack(v, GAMMA-1, GAMMA1)
|
|
* 6: end for
|
|
* 7: return s
|
|
*
|
|
* @param [in, out] shake256 SHAKE-256 object.
|
|
* @param [in, out] seed Buffer containing seed to expand.
|
|
* Has space for two bytes to be appended.
|
|
* @param [in] kappa Base value to append to seed.
|
|
* @param [in] gamma1_bits Number of bits per value.
|
|
* @param [out] y Vector of polynomials.
|
|
* @param [in] l Dimension of vector.
|
|
* @return 0 on success.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_vec_expand_mask(wc_Shake* shake256, byte* seed,
|
|
word16 kappa, byte gamma1_bits, sword32* y, byte l)
|
|
{
|
|
int ret = 0;
|
|
byte r;
|
|
byte v[DILITHIUM_MAX_V];
|
|
|
|
/* Step 2: For each polynomial of vector. */
|
|
for (r = 0; (ret == 0) && (r < l); r++) {
|
|
/* Step 3: Calculate value to append to seed. */
|
|
word16 n = kappa + r;
|
|
|
|
/* Step 4: Append to seed and squeeze out data. */
|
|
seed[DILITHIUM_PRIV_RAND_SEED_SZ + 0] = (byte)n;
|
|
seed[DILITHIUM_PRIV_RAND_SEED_SZ + 1] = (byte)(n >> 8);
|
|
ret = dilithium_squeeze256(shake256, seed, DILITHIUM_Y_SEED_SZ, v,
|
|
DILITHIUM_MAX_V_BLOCKS);
|
|
if (ret == 0) {
|
|
/* Decode v into polynomial. */
|
|
dilithium_decode_gamma1(v, gamma1_bits, y);
|
|
/* Next polynomial. */
|
|
y += DILITHIUM_N;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || !defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
|
|
|
/* Expand commit to a polynomial.
|
|
*
|
|
* FIPS 204. 8.3: Algorithm 23 SampleInBall(rho)
|
|
* 1: c <- 0
|
|
* 2: k <- 8
|
|
* 3: for i from 256 - TAU to 255 do
|
|
* 4: while H(rho)[[k]] > i do
|
|
* 5: k <- k + 1
|
|
* 6: end while
|
|
* 7: j <- H(rho)[[k]]
|
|
* 8: c[i] <- c[j]
|
|
* 9: c[j] <- (-1)^H(rho)[i+TAU-256]
|
|
* 10: k <- k + 1
|
|
* 11: end for
|
|
* 12: return c
|
|
*
|
|
* @param [in] shake256 SHAKE-256 object.
|
|
* @param [in] seed Buffer containing seed to expand.
|
|
* @param [in] seedLen Length of seed in bytes.
|
|
* @param [in] tau Number of +/- 1s in polynomial.
|
|
* @param [out] c Commit polynomial.
|
|
* @param [in] block Memory to use for block from key.
|
|
* @return 0 on success.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_sample_in_ball_ex(int level, wc_Shake* shake256,
|
|
const byte* seed, word32 seedLen, byte tau, sword32* c, byte* block)
|
|
{
|
|
int ret = 0;
|
|
byte signs[DILITHIUM_SIGN_BYTES];
|
|
unsigned int i;
|
|
/* Step 1: Initialize sign bit index. */
|
|
unsigned int s = 0;
|
|
/* Step 2: First 8 bytes are used for sign. */
|
|
unsigned int k = DILITHIUM_SIGN_BYTES;
|
|
|
|
if (ret == 0) {
|
|
/* Set polynomial to all zeros. */
|
|
XMEMSET(c, 0, DILITHIUM_POLY_SIZE);
|
|
|
|
/* Generate a block of data from seed. */
|
|
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
|
if (level >= WC_ML_DSA_DRAFT) {
|
|
ret = dilithium_shake256(shake256, seed, DILITHIUM_SEED_SZ, block,
|
|
DILITHIUM_GEN_C_BLOCK_BYTES);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
(void)level;
|
|
ret = dilithium_shake256(shake256, seed, seedLen, block,
|
|
DILITHIUM_GEN_C_BLOCK_BYTES);
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
/* Copy first 8 bytes of first hash block as random sign bits. */
|
|
XMEMCPY(signs, block, DILITHIUM_SIGN_BYTES);
|
|
}
|
|
|
|
/* Step 3: Put in TAU +/- 1s. */
|
|
for (i = DILITHIUM_N - tau; (ret == 0) && (i < DILITHIUM_N); i++) {
|
|
unsigned int j;
|
|
do {
|
|
/* Check whether block is exhausted. */
|
|
if (k == DILITHIUM_GEN_C_BLOCK_BYTES) {
|
|
/* Generate a new block. */
|
|
ret = wc_Shake256_SqueezeBlocks(shake256, block, 1);
|
|
/* Restart hash block index. */
|
|
k = 0;
|
|
}
|
|
/* Step 7: Get random byte from block as index.
|
|
* Step 5 and 10: Increment hash block index.
|
|
*/
|
|
j = block[k++];
|
|
}
|
|
/* Step 4: Get another random if random index is a future swap index. */
|
|
while ((ret == 0) && (j > i));
|
|
|
|
/* Step 8: Move value from random index to current index. */
|
|
c[i] = c[j];
|
|
/* Step 9: Set value at random index to +/- 1. */
|
|
c[j] = 1 - ((((signs[s >> 3]) >> (s & 0x7)) & 0x1) << 1);
|
|
/* Next sign bit index. */
|
|
s++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if (!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM))
|
|
/* Expand commit to a polynomial.
|
|
*
|
|
* @param [in] shake256 SHAKE-256 object.
|
|
* @param [in] seed Buffer containing seed to expand.
|
|
* @param [in] seedLen Length of seed in bytes.
|
|
* @param [in] tau Number of +/- 1s in polynomial.
|
|
* @param [out] c Commit polynomial.
|
|
* @param [in] heap Dynamic memory hint.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Negative on hash error.
|
|
*/
|
|
static int dilithium_sample_in_ball(int level, wc_Shake* shake256,
|
|
const byte* seed, word32 seedLen, byte tau, sword32* c, void* heap)
|
|
{
|
|
int ret = 0;
|
|
#if defined(WOLFSSL_SMALL_STACK)
|
|
byte* block = NULL;
|
|
#else
|
|
byte block[DILITHIUM_GEN_C_BLOCK_BYTES];
|
|
#endif
|
|
|
|
(void)heap;
|
|
|
|
#if defined(WOLFSSL_SMALL_STACK)
|
|
block = (byte*)XMALLOC(DILITHIUM_GEN_C_BLOCK_BYTES, heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (block == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
ret = dilithium_sample_in_ball_ex(level, shake256, seed, seedLen, tau,
|
|
c, block);
|
|
}
|
|
|
|
#if defined(WOLFSSL_SMALL_STACK)
|
|
XFREE(block, heap, DYNAMIC_TYPE_DILITHIUM);
|
|
#endif
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* Decompose operations
|
|
******************************************************************************/
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || !defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
/* Decompose value into high and low based on GAMMA2 being ((q-1) / 88).
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 30 Decompose(r)
|
|
* 1: r+ <- r mod q
|
|
* 2: r0 <- r+ mod+/- (2 * GAMMA2)
|
|
* 3: if r+ - r0 = q - 1 then
|
|
* 4: r1 <- 0
|
|
* 5: r0 <- r0 - 1
|
|
* 6: else r1 <- (r+ - r0) / (2 * GAMMA2)
|
|
* 7: end if
|
|
* 8: return (r1, r0)
|
|
*
|
|
* DILITHIUM_Q_LOW_88_2 = 0x2e800 = 0b101110100000000000
|
|
* t1 * DILITHIUM_Q_LOW_88_2 = (t1 << 18) - (t1 << 16) - (t1 << 12) - (t1 << 11)
|
|
* = ((93 * t1) << 11)
|
|
* Nothing faster than straight multiply.
|
|
*
|
|
* Implementation using Barrett Reduction.
|
|
*
|
|
* @param [in] r Value to decompose.
|
|
* @param [out] r0 Low bits.
|
|
* @param [out] r1 High bits.
|
|
*/
|
|
static void dilithium_decompose_q88(sword32 r, sword32* r0, sword32* r1)
|
|
{
|
|
sword32 t0;
|
|
sword32 t1;
|
|
#ifdef DILITHIUM_MUL_SLOW
|
|
sword32 t2;
|
|
#endif
|
|
|
|
/* Roundup r and calculate approx high value. */
|
|
#if !defined(DILITHIUM_MUL_44_SLOW)
|
|
t1 = ((r * 44) + ((DILITHIUM_Q_LOW_88 - 1) * 44)) >> 23;
|
|
#elif !defined(DILITHIUM_MUL_11_SLOW)
|
|
t1 = ((r * 11) + ((DILITHIUM_Q_LOW_88 - 1) * 11)) >> 21;
|
|
#else
|
|
t0 = r + DILITHIUM_Q_LOW_88 - 1;
|
|
t1 = ((t0 << 3) + (t0 << 1) + t0) >> 21;
|
|
#endif
|
|
/* Calculate approx low value. */
|
|
t0 = r - (t1 * DILITHIUM_Q_LOW_88_2);
|
|
#ifndef DILITHIUM_MUL_SLOW
|
|
/* Calculate real high value, When t0 > modulus, +1 to approx high value. */
|
|
t1 += ((word32)(DILITHIUM_Q_LOW_88 - t0)) >> 31;
|
|
/* Calculate real low value. */
|
|
t0 = r - (t1 * DILITHIUM_Q_LOW_88_2);
|
|
#else
|
|
/* Calculate real high value, When t0 > modulus, +1 to approx high value. */
|
|
t2 = ((word32)(DILITHIUM_Q_LOW_88 - t0)) >> 31;
|
|
t1 += t2;
|
|
/* Calculate real low value. */
|
|
t0 -= (0 - t2) & DILITHIUM_Q_LOW_88_2;
|
|
#endif
|
|
/* -1 from low value if high value is 44. Was 43 but low is negative. */
|
|
t0 -= ((word32)(43 - t1)) >> 31;
|
|
/* When high value is 44, too large, set to 0. */
|
|
t1 &= 0 - (((word32)(t1 - 44)) >> 31);
|
|
|
|
*r0 = t0;
|
|
*r1 = t1;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* Decompose value into high and low based on GAMMA2 being ((q-1) / 32).
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 30 Decompose(r)
|
|
* 1: r+ <- r mod q
|
|
* 2: r0 <- r+ mod+/- (2 * GAMMA2)
|
|
* 3: if r+ - r0 = q - 1 then
|
|
* 4: r1 <- 0
|
|
* 5: r0 <- r0 - 1
|
|
* 6: else r1 <- (r+ - r0) / (2 * GAMMA2)
|
|
* 7: end if
|
|
* 8: return (r1, r0)
|
|
*
|
|
* DILITHIUM_Q_LOW_32_2 = 0x7fe00 = 0b1111111111000000000
|
|
* t1 * DILITHIUM_Q_LOW_32_2 = (t1 << 19) - (t1 << 9)
|
|
*
|
|
* Implementation using Barrett Reduction.
|
|
*
|
|
* @param [in] r Value to decompose.
|
|
* @param [out] r0 Low bits.
|
|
* @param [out] r1 High bits.
|
|
*/
|
|
static void dilithium_decompose_q32(sword32 r, sword32* r0, sword32* r1)
|
|
{
|
|
sword32 t0;
|
|
sword32 t1;
|
|
|
|
/* Roundup r and calculate approx high value. */
|
|
t1 = (r + DILITHIUM_Q_LOW_32 - 1) >> 19;
|
|
/* Calculate approx low value. */
|
|
t0 = r - (t1 << 19) + (t1 << 9);
|
|
/* Calculate real high value, When t0 > modulus, +1 to approx high value. */
|
|
t1 += ((word32)(DILITHIUM_Q_LOW_32 - t0)) >> 31;
|
|
/* Calculate real low value. */
|
|
t0 = r - (t1 << 19) + (t1 << 9);
|
|
/* -1 from low value if high value is 16. Was 15 but low is negative. */
|
|
t0 -= t1 >> 4;
|
|
/* When high value is 16, too large, set to 0. */
|
|
t1 &= 0xf;
|
|
|
|
*r0 = t0;
|
|
*r1 = t1;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_SIGN
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM) || \
|
|
defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A)
|
|
/* Decompose vector of polynomials into high and low based on GAMMA2.
|
|
*
|
|
* @param [in] r Vector of polynomials to decompose.
|
|
* @param [in] k Dimension of vector.
|
|
* @param [in] gamma2 Low-order rounding range, GAMMA2.
|
|
* @param [out] r0 Low parts in vector of polynomials.
|
|
* @param [out] r1 High parts in vector of polynomials.
|
|
*/
|
|
static void dilithium_vec_decompose(const sword32* r, byte k, sword32 gamma2,
|
|
sword32* r0, sword32* r1)
|
|
{
|
|
unsigned int i;
|
|
unsigned int j;
|
|
|
|
(void)k;
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (gamma2 == DILITHIUM_Q_LOW_88) {
|
|
/* For each polynomial of vector. */
|
|
for (i = 0; i < PARAMS_ML_DSA_44_K; i++) {
|
|
/* For each value of polynomial. */
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
/* Decompose value into two vectors. */
|
|
dilithium_decompose_q88(r[j], &r0[j], &r1[j]);
|
|
}
|
|
/* Next polynomial of vectors. */
|
|
r += DILITHIUM_N;
|
|
r0 += DILITHIUM_N;
|
|
r1 += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (gamma2 == DILITHIUM_Q_LOW_32) {
|
|
/* For each polynomial of vector. */
|
|
for (i = 0; i < k; i++) {
|
|
/* For each value of polynomial. */
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
/* Decompose value into two vectors. */
|
|
dilithium_decompose_q32(r[j], &r0[j], &r1[j]);
|
|
}
|
|
/* Next polynomial of vectors. */
|
|
r += DILITHIUM_N;
|
|
r0 += DILITHIUM_N;
|
|
r1 += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN */
|
|
|
|
/******************************************************************************
|
|
* Range check operation
|
|
******************************************************************************/
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || !defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
|
/* Check that the values of the polynomial are in range.
|
|
*
|
|
* Many places in FIPS 204. One example from Algorithm 2:
|
|
* 23: if ||z||inf >= GAMMA1 - BETA or ..., then (z, h) = falsam
|
|
*
|
|
* @param [in] a Polynomial.
|
|
* @param [in] hi Largest value in range.
|
|
*/
|
|
static int dilithium_check_low(const sword32* a, sword32 hi)
|
|
{
|
|
int ret = 1;
|
|
unsigned int j;
|
|
/* Calculate lowest range value. */
|
|
sword32 nhi = -hi;
|
|
|
|
/* For each value of polynomial. */
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
/* Check range is -(hi-1)..(hi-1). */
|
|
if ((a[j] <= nhi) || (a[j] >= hi)) {
|
|
/* Check failed. */
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_VERIFY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM))
|
|
/* Check that the values of the vector are in range.
|
|
*
|
|
* Many places in FIPS 204. One example from Algorithm 2:
|
|
* 23: if ||z||inf >= GAMMA1 - BETA or ..., then (z, h) = falsam
|
|
*
|
|
* @param [in] a Vector of polynomials.
|
|
* @param [in] l Dimension of vector.
|
|
* @param [in] hi Largest value in range.
|
|
*/
|
|
static int dilithium_vec_check_low(const sword32* a, byte l, sword32 hi)
|
|
{
|
|
int ret = 1;
|
|
unsigned int i;
|
|
|
|
/* For each polynomial of vector. */
|
|
for (i = 0; (ret == 1) && (i < l); i++) {
|
|
ret = dilithium_check_low(a, hi);
|
|
if (ret == 0) {
|
|
break;
|
|
}
|
|
/* Next polynomial. */
|
|
a += DILITHIUM_N;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* Hint operations
|
|
******************************************************************************/
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_SIGN
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
/* Compute hints indicating whether adding ct0 to w alters high bits of w.
|
|
*
|
|
* FIPS 204. 6: Algorithm 2 ML-DSA.Sign(sk, M)
|
|
* ...
|
|
* 26: h <- MakeHint(-<<ct0>>, w - <<sc2>> + <<ct0>>)
|
|
* 27: if ... or the number of 1's in h is greater than OMEGA, then
|
|
* (z, h) <- falsam
|
|
* ...
|
|
* 32: sigma <- sigEncode(c_tilda, z mod+/- q, h)
|
|
* ...
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 33 MakeHint(z, r)
|
|
* 1: r1 <- HighBits(r)
|
|
* 2: v1 <- HightBits(r+z)
|
|
* 3: return [[r1 != v1]]
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 20 sigEncode(c_tilde, z, h)
|
|
* ...
|
|
* 5: sigma <- sigma || HintBitPack(h)
|
|
* ...
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 14 HintBitPack(h)
|
|
* ...
|
|
* 4: for j from 0 to 255 do
|
|
* 5: if h[i]j != 0 then
|
|
* 6: y[Index] <- j
|
|
* 7: Index <- Index + 1
|
|
* 8: end if
|
|
* 9: end for
|
|
* ...
|
|
*
|
|
* @param [in] s Vector of polynomials that is sum of ct0 and w0.
|
|
* @param [in] w1 Vector of polynomials that is high part of w.
|
|
* @param [out] h Encoded hints.
|
|
* @param [in, out] idxp Index to write next hint into.
|
|
* return Number of hints on success.
|
|
* return Falsam of -1 when too many hints.
|
|
*/
|
|
static int dilithium_make_hint_88(const sword32* s, const sword32* w1, byte* h,
|
|
byte *idxp)
|
|
{
|
|
unsigned int j;
|
|
byte idx = *idxp;
|
|
|
|
/* Alg 14, Step 3: For each value of polynomial. */
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
/* Alg 14, Step 4: Check whether hint is required.
|
|
* Did sum end up greater than low modulus or
|
|
* sum end up less than the negative of low modulus or
|
|
* sum is the negative of the low modulus and w1 is not zero,
|
|
* then w1 will be modified.
|
|
*/
|
|
if ((s[j] > (sword32)DILITHIUM_Q_LOW_88) ||
|
|
(s[j] < -(sword32)DILITHIUM_Q_LOW_88) ||
|
|
((s[j] == -(sword32)DILITHIUM_Q_LOW_88) &&
|
|
(w1[j] != 0))) {
|
|
/* Alg 14, Step 6, 7: Put index as hint modifier. */
|
|
h[idx++] = (byte)j;
|
|
/* Alg 2, Step 27: If there are too many hints, return
|
|
* falsam of -1. */
|
|
if (idx > PARAMS_ML_DSA_44_OMEGA) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
*idxp = idx;
|
|
return 0;
|
|
}
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* Compute hints indicating whether adding ct0 to w alters high bits of w.
|
|
*
|
|
* FIPS 204. 6: Algorithm 2 ML-DSA.Sign(sk, M)
|
|
* ...
|
|
* 26: h <- MakeHint(-<<ct0>>, w - <<sc2>> + <<ct0>>)
|
|
* 27: if ... or the number of 1's in h is greater than OMEGA, then
|
|
* (z, h) <- falsam
|
|
* ...
|
|
* 32: sigma <- sigEncode(c_tilda, z mod+/- q, h)
|
|
* ...
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 33 MakeHint(z, r)
|
|
* 1: r1 <- HighBits(r)
|
|
* 2: v1 <- HightBits(r+z)
|
|
* 3: return [[r1 != v1]]
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 20 sigEncode(c_tilde, z, h)
|
|
* ...
|
|
* 5: sigma <- sigma || HintBitPack(h)
|
|
* ...
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 14 HintBitPack(h)
|
|
* ...
|
|
* 4: for j from 0 to 255 do
|
|
* 5: if h[i]j != 0 then
|
|
* 6: y[Index] <- j
|
|
* 7: Index <- Index + 1
|
|
* 8: end if
|
|
* 9: end for
|
|
* ...
|
|
*
|
|
* @param [in] s Vector of polynomials that is sum of ct0 and w0.
|
|
* @param [in] w1 Vector of polynomials that is high part of w.
|
|
* @param [in] omega Maximum number of hints allowed.
|
|
* @param [out] h Encoded hints.
|
|
* @param [in, out] idxp Index to write next hint into.
|
|
* return Number of hints on success.
|
|
* return Falsam of -1 when too many hints.
|
|
*/
|
|
static int dilithium_make_hint_32(const sword32* s, const sword32* w1,
|
|
byte omega, byte* h, byte *idxp)
|
|
{
|
|
unsigned int j;
|
|
byte idx = *idxp;
|
|
|
|
(void)omega;
|
|
|
|
/* Alg 14, Step 3: For each value of polynomial. */
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
/* Alg 14, Step 4: Check whether hint is required.
|
|
* Did sum end up greater than low modulus or
|
|
* sum end up less than the negative of low modulus or
|
|
* sum is the negative of the low modulus and w1 is not zero,
|
|
* then w1 will be modified.
|
|
*/
|
|
if ((s[j] > (sword32)DILITHIUM_Q_LOW_32) ||
|
|
(s[j] < -(sword32)DILITHIUM_Q_LOW_32) ||
|
|
((s[j] == -(sword32)DILITHIUM_Q_LOW_32) &&
|
|
(w1[j] != 0))) {
|
|
/* Alg 14, Step 6, 7: Put index as hint modifier. */
|
|
h[idx++] = (byte)j;
|
|
/* Alg 2, Step 27: If there are too many hints, return
|
|
* falsam of -1. */
|
|
if (idx > omega) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
*idxp = idx;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM
|
|
/* Compute hints indicating whether adding ct0 to w alters high bits of w.
|
|
*
|
|
* FIPS 204. 6: Algorithm 2 ML-DSA.Sign(sk, M)
|
|
* ...
|
|
* 26: h <- MakeHint(-<<ct0>>, w - <<sc2>> + <<ct0>>)
|
|
* 27: if ... or the number of 1's in h is greater than OMEGA, then
|
|
* (z, h) <- falsam
|
|
* ...
|
|
* 32: sigma <- sigEncode(c_tilda, z mod+/- q, h)
|
|
* ...
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 33 MakeHint(z, r)
|
|
* 1: r1 <- HighBits(r)
|
|
* 2: v1 <- HightBits(r+z)
|
|
* 3: return [[r1 != v1]]
|
|
*
|
|
* FIPS 204. 8.2: Algorithm 20 sigEncode(c_tilde, z, h)
|
|
* ...
|
|
* 5: sigma <- sigma || HintBitPack(h)
|
|
* ...
|
|
*
|
|
* FIPS 204. 8.1: Algorithm 14 HintBitPack(h)
|
|
* ...
|
|
* 2: Index <- 0
|
|
* 3. for i from 0 to k - 1 do
|
|
* 4: for j from 0 to 255 do
|
|
* 5: if h[i]j != 0 then
|
|
* 6: y[Index] <- j
|
|
* 7: Index <- Index + 1
|
|
* 8: end if
|
|
* 9: end for
|
|
* 10: y[OMEGA + i] <- Index
|
|
* 11: end for
|
|
* 12: return y
|
|
*
|
|
* @param [in] s Vector of polynomials that is sum of ct0 and w0.
|
|
* @param [in] w1 Vector of polynomials that is high part of w.
|
|
* @param [in] k Dimension of vectors.
|
|
* @param [in] gamma2 Low-order rounding range, GAMMA2.
|
|
* @param [in] omega Maximum number of hints allowed.
|
|
* @param [out] h Encoded hints.
|
|
* return Number of hints on success.
|
|
* return Falsam of -1 when too many hints.
|
|
*/
|
|
static int dilithium_make_hint(const sword32* s, const sword32* w1, byte k,
|
|
sword32 gamma2, byte omega, byte* h)
|
|
{
|
|
unsigned int i;
|
|
byte idx = 0;
|
|
|
|
(void)k;
|
|
(void)omega;
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (gamma2 == DILITHIUM_Q_LOW_88) {
|
|
/* Alg 14, Step 2: For each polynomial of vector. */
|
|
for (i = 0; i < PARAMS_ML_DSA_44_K; i++) {
|
|
if (dilithium_make_hint_88(s, w1, h, &idx) == -1) {
|
|
return -1;
|
|
}
|
|
/* Alg 14, Step 10: Store count of hints for polynomial at end of
|
|
* list. */
|
|
h[PARAMS_ML_DSA_44_OMEGA + i] = idx;
|
|
/* Next polynomial. */
|
|
s += DILITHIUM_N;
|
|
w1 += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (gamma2 == DILITHIUM_Q_LOW_32) {
|
|
/* Alg 14, Step 2: For each polynomial of vector. */
|
|
for (i = 0; i < k; i++) {
|
|
if (dilithium_make_hint_32(s, w1, omega, h, &idx) == -1) {
|
|
return -1;
|
|
}
|
|
/* Alg 14, Step 10: Store count of hints for polynomial at end of
|
|
* list. */
|
|
h[omega + i] = idx;
|
|
/* Next polynomial. */
|
|
s += DILITHIUM_N;
|
|
w1 += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
|
|
/* Set remaining hints to zero. */
|
|
XMEMSET(h + idx, 0, omega - idx);
|
|
return idx;
|
|
}
|
|
#endif /* !WOLFSSL_DILITHIUM_SIGN_SMALL_MEM */
|
|
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN */
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_VERIFY
|
|
/* Check that the hints are valid.
|
|
*
|
|
* @param [in] h Hints to check
|
|
* @param [in] k Dimension of vector.
|
|
* @param [in] omega Maximum number of hints. Hint counts after this index.
|
|
* @return 0 when hints valid.
|
|
* @return SIG_VERIFY_E when hints invalid.
|
|
*/
|
|
static int dilithium_check_hint(const byte* h, byte k, byte omega)
|
|
{
|
|
int ret = 0;
|
|
unsigned int o = 0;
|
|
unsigned int i;
|
|
|
|
/* Skip polynomial index while count is 0. */
|
|
while ((o < k) && (h[omega + o] == 0)) {
|
|
o++;
|
|
}
|
|
/* Check all possible hints. */
|
|
for (i = 1; (o < k) && (i < omega); i++) {
|
|
/* Done with polynomial if index equals count of hints. */
|
|
if (i == h[omega + o]) {
|
|
/* Next polynomial index while count is index. */
|
|
do {
|
|
o++;
|
|
}
|
|
while ((o < k) && (i == h[omega + o]));
|
|
/* Stop if hints for all polynomials checked. */
|
|
if (o == k) {
|
|
break;
|
|
}
|
|
}
|
|
/* Ensure the last hint is less than the current hint. */
|
|
else if (h[i - 1] >= h[i]) {
|
|
ret = SIG_VERIFY_E;
|
|
break;
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
/* Use up any sizes that are the last element. */
|
|
while ((o < k) && (i == h[omega + o])) {
|
|
o++;
|
|
}
|
|
/* Ensure all sizes were used. */
|
|
if (o != k) {
|
|
ret = SIG_VERIFY_E;
|
|
}
|
|
}
|
|
/* Check remaining hints are 0. */
|
|
for (; (ret == 0) && (i < omega); i++) {
|
|
if (h[i] != 0) {
|
|
ret = SIG_VERIFY_E;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
/* Use hints to modify w1.
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 34 UseHint(h, r)
|
|
* 1: m <- (q - 1) / (2 * GAMMA2)
|
|
* 2: (r1, r0) <- Decompose(r)
|
|
* 3: if h == 1 and r0 > 0 return (r1 + 1) mod m
|
|
* 4: if h == 1 and r0 <= 0 return (r1 - 1) mod m
|
|
* 5: return r1
|
|
*
|
|
* @param [in, out] w1 Vector of polynomials needing hints applied to.
|
|
* @param [in] h Hints to apply. In signature encoding.
|
|
* @param [in] i Dimension index.
|
|
* @param [in, out] op Pointer to current offset into hints.
|
|
*/
|
|
static void dilithium_use_hint_88(sword32* w1, const byte* h, unsigned int i,
|
|
byte* op)
|
|
{
|
|
byte o = *op;
|
|
unsigned int j;
|
|
|
|
/* For each value of polynomial. */
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
sword32 r;
|
|
sword32 r0;
|
|
sword32 r1;
|
|
#ifdef DILITHIUM_USE_HINT_CT
|
|
/* Hint is 1 when index is next in hint list. */
|
|
sword32 hint = ((o < h[PARAMS_ML_DSA_44_OMEGA + i]) &
|
|
(h[o] == (byte)j));
|
|
|
|
/* Increment hint offset if this index has hint. */
|
|
o += hint;
|
|
/* Convert value to positive only range. */
|
|
r = w1[j] + ((0 - (((word32)w1[j]) >> 31)) & DILITHIUM_Q);
|
|
/* Decompose value into low and high parts. */
|
|
dilithium_decompose_q88(r, &r0, &r1);
|
|
/* Make hint positive or negative based on sign of r0. */
|
|
hint = (1 - (2 * (((word32)r0) >> 31))) & (0 - hint);
|
|
/* Make w1 only the top part plus the hint. */
|
|
w1[j] = r1 + hint;
|
|
|
|
/* Fix up w1 to not be 44 but 0. */
|
|
w1[j] &= (sword32)(0 - (((word32)(w1[j] - 44)) >> 31));
|
|
/* Hint may have reduced 0 to -1 which is actually 43. */
|
|
w1[j] += (sword32)((0 - (((word32)w1[j]) >> 31)) & 44);
|
|
#else
|
|
/* Convert value to positive only range. */
|
|
r = w1[j] + (sword32)((0 - (((word32)w1[j]) >> 31)) & DILITHIUM_Q);
|
|
/* Decompose value into low and high parts. */
|
|
dilithium_decompose_q88(r, &r0, &r1);
|
|
/* Check for hint. */
|
|
if ((o < h[PARAMS_ML_DSA_44_OMEGA + i]) && (h[o] == (byte)j)) {
|
|
/* Add or subtrac hint based on sign of r0. */
|
|
r1 += 1 - (2 * (((word32)r0) >> 31));
|
|
/* Go to next hint offset. */
|
|
o++;
|
|
}
|
|
/* Fix up w1 to not be 44 but 0. */
|
|
r1 &= 0 - (((word32)(r1 - 44)) >> 31);
|
|
/* Hint may have reduced 0 to -1 which is actually 43. */
|
|
r1 += (0 - (((word32)r1) >> 31)) & 44;
|
|
/* Make w1 only the top part plus any hint. */
|
|
w1[j] = r1;
|
|
#endif
|
|
}
|
|
*op = o;
|
|
}
|
|
#endif /* !WOLFSSL_NO_ML_DSA_44 */
|
|
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* Use hints to modify w1.
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 34 UseHint(h, r)
|
|
* 1: m <- (q - 1) / (2 * GAMMA2)
|
|
* 2: (r1, r0) <- Decompose(r)
|
|
* 3: if h == 1 and r0 > 0 return (r1 + 1) mod m
|
|
* 4: if h == 1 and r0 <= 0 return (r1 - 1) mod m
|
|
* 5: return r1
|
|
*
|
|
* @param [in, out] w1 Vector of polynomials needing hints applied to.
|
|
* @param [in] h Hints to apply. In signature encoding.
|
|
* @param [in] omega Max number of hints. Hint counts after this index.
|
|
* @param [in] i Dimension index.
|
|
* @param [in, out] op Pointer to current offset into hints.
|
|
*/
|
|
static void dilithium_use_hint_32(sword32* w1, const byte* h, byte omega,
|
|
unsigned int i, byte* op)
|
|
{
|
|
byte o = *op;
|
|
unsigned int j;
|
|
|
|
/* For each value of polynomial. */
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
sword32 r;
|
|
sword32 r0;
|
|
sword32 r1;
|
|
#ifdef DILITHIUM_USE_HINT_CT
|
|
/* Hint is 1 when index is next in hint list. */
|
|
sword32 hint = ((o < h[omega + i]) & (h[o] == (byte)j));
|
|
|
|
/* Increment hint offset if this index has hint. */
|
|
o += hint;
|
|
/* Convert value to positive only range. */
|
|
r = w1[j] + (sword32)((0 - (((word32)w1[j]) >> 31)) & DILITHIUM_Q);
|
|
/* Decompose value into low and high parts. */
|
|
dilithium_decompose_q32(r, &r0, &r1);
|
|
/* Make hint positive or negative based on sign of r0. */
|
|
hint = (sword32)((1 - (2 * (((word32)r0) >> 31))) & (0 - hint));
|
|
/* Make w1 only the top part plus the hint. */
|
|
w1[j] = r1 + hint;
|
|
|
|
/* Fix up w1 not be 16 (-> 0) or -1 (-> 15). */
|
|
w1[j] &= 0xf;
|
|
#else
|
|
/* Convert value to positive only range. */
|
|
r = w1[j] + (sword32)((0 - (((word32)w1[j]) >> 31)) & DILITHIUM_Q);
|
|
/* Decompose value into low and high parts. */
|
|
dilithium_decompose_q32(r, &r0, &r1);
|
|
/* Check for hint. */
|
|
if ((o < h[omega + i]) && (h[o] == (byte)j)) {
|
|
/* Add or subtract hint based on sign of r0. */
|
|
r1 += (sword32)(1 - (2 * (((word32)r0) >> 31)));
|
|
/* Go to next hint offset. */
|
|
o++;
|
|
}
|
|
/* Fix up w1 not be 16 (-> 0) or -1 (-> 15). */
|
|
w1[j] = r1 & 0xf;
|
|
#endif
|
|
}
|
|
*op = o;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM
|
|
/* Use hints to modify w1.
|
|
*
|
|
* FIPS 204. 8.4: Algorithm 34 UseHint(h, r)
|
|
* 1: m <- (q - 1) / (2 * GAMMA2)
|
|
* 2: (r1, r0) <- Decompose(r)
|
|
* 3: if h == 1 and r0 > 0 return (r1 + 1) mod m
|
|
* 4: if h == 1 and r0 <= 0 return (r1 - 1) mod m
|
|
* 5: return r1
|
|
*
|
|
* @param [in, out] w1 Vector of polynomials needing hints applied to.
|
|
* @param [in] k Dimension of vector.
|
|
* @param [in] gamma2 Low-order rounding range, GAMMA2.
|
|
* @param [in] omega Max number of hints. Hint counts after this index.
|
|
* @param [in] h Hints to apply. In signature encoding.
|
|
*/
|
|
static void dilithium_vec_use_hint(sword32* w1, byte k, sword32 gamma2,
|
|
byte omega, const byte* h)
|
|
{
|
|
unsigned int i;
|
|
byte o = 0;
|
|
|
|
(void)k;
|
|
(void)omega;
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (gamma2 == DILITHIUM_Q_LOW_88) {
|
|
/* For each polynomial of vector. */
|
|
for (i = 0; i < PARAMS_ML_DSA_44_K; i++) {
|
|
dilithium_use_hint_88(w1, h, i, &o);
|
|
w1 += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (gamma2 == DILITHIUM_Q_LOW_32) {
|
|
/* For each polynomial of vector. */
|
|
for (i = 0; i < k; i++) {
|
|
dilithium_use_hint_32(w1, h, omega, i, &o);
|
|
w1 += DILITHIUM_N;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_VERIFY */
|
|
|
|
/******************************************************************************
|
|
* Maths operations
|
|
******************************************************************************/
|
|
|
|
/* q^-1 mod 2^32 (inverse of 8380417 mod 2^32 = 58728449 = 0x3802001) */
|
|
#define DILITHIUM_QINV 58728449
|
|
|
|
/* Montgomery reduce a.
|
|
*
|
|
* @param [in] a 64-bit value to be reduced.
|
|
* @return Montgomery reduction result.
|
|
*/
|
|
static sword32 dilithium_mont_red(sword64 a)
|
|
{
|
|
#ifndef DILITHIUM_MUL_QINV_SLOW
|
|
sword64 t = (sword32)((sword32)a * (sword32)DILITHIUM_QINV);
|
|
#else
|
|
sword64 t = (sword32)((sword32)a + (sword32)((sword32)a << 13) -
|
|
(sword32)((sword32)a << 23) + (sword32)((sword32)a << 26));
|
|
#endif
|
|
#ifndef DILITHIUM_MUL_Q_SLOW
|
|
return (sword32)((a - ((sword32)t * (sword64)DILITHIUM_Q)) >> 32);
|
|
#else
|
|
return (sword32)((a - (t << 23) + (t << 13) - t) >> 32);
|
|
#endif
|
|
}
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_SMALL) || !defined(WOLFSSL_DILITHIUM_NO_SIGN)
|
|
|
|
/* Reduce 32-bit a modulo q. r = a mod q.
|
|
*
|
|
* @param [in] a 32-bit value to be reduced to range of q.
|
|
* @return Modulo result.
|
|
*/
|
|
static sword32 dilithium_red(sword32 a)
|
|
{
|
|
sword32 t = (sword32)((a + (1 << 22)) >> 23);
|
|
#ifndef DILITHIUM_MUL_Q_SLOW
|
|
return (sword32)(a - (t * DILITHIUM_Q));
|
|
#else
|
|
return (sword32)(a - (t << 23) + (t << 13) - t);
|
|
#endif
|
|
}
|
|
|
|
#endif /* !WOLFSSL_DILITHIUM_SMALL || !WOLFSSL_DILITHIUM_NO_SIGN */
|
|
|
|
/* Zetas for NTT. */
|
|
static const sword32 zetas[DILITHIUM_N] = {
|
|
-41978, 25847, -2608894, -518909, 237124, -777960, -876248, 466468,
|
|
1826347, 2353451, -359251, -2091905, 3119733, -2884855, 3111497, 2680103,
|
|
2725464, 1024112, -1079900, 3585928, -549488, -1119584, 2619752, -2108549,
|
|
-2118186, -3859737, -1399561, -3277672, 1757237, -19422, 4010497, 280005,
|
|
2706023, 95776, 3077325, 3530437, -1661693, -3592148, -2537516, 3915439,
|
|
-3861115, -3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299,
|
|
-1699267, -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596,
|
|
811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, -2797779,
|
|
-3930395, -1528703, -3677745, -3041255, -1452451, 3475950, 2176455, -1585221,
|
|
-1257611, 1939314, -4083598, -1000202, -3190144, -3157330, -3632928, 126922,
|
|
3412210, -983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047,
|
|
-671102, -1228525, -22981, -1308169, -381987, 1349076, 1852771, -1430430,
|
|
-3343383, 264944, 508951, 3097992, 44288, -1100098, 904516, 3958618,
|
|
-3724342, -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856,
|
|
189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, 1341330,
|
|
1285669, -1584928, -812732, -1439742, -3019102, -3881060, -3628969, 3839961,
|
|
2091667, 3407706, 2316500, 3817976, -3342478, 2244091, -2446433, -3562462,
|
|
266997, 2434439, -1235728, 3513181, -3520352, -3759364, -1197226, -3193378,
|
|
900702, 1859098, 909542, 819034, 495491, -1613174, -43260, -522500,
|
|
-655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838,
|
|
342297, 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044,
|
|
2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, 1595974,
|
|
-3767016, 1250494, 2635921, -3548272, -2994039, 1869119, 1903435, -1050970,
|
|
-1333058, 1237275, -3318210, -1430225, -451100, 1312455, 3306115, -1962642,
|
|
-1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031,
|
|
-542412, -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993,
|
|
-2013608, 2432395, 2454455, -164721, 1957272, 3369112, 185531, -1207385,
|
|
-3183426, 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107,
|
|
-3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, 472078,
|
|
-426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893,
|
|
-2939036, -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687,
|
|
-554416, 3919660, -48306, -1362209, 3937738, 1400424, -846154, 1976782
|
|
};
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_SMALL
|
|
/* Zetas for inverse NTT. */
|
|
static const sword32 zetas_inv[DILITHIUM_N] = {
|
|
-1976782, 846154, -1400424, -3937738, 1362209, 48306, -3919660, 554416,
|
|
3545687, -1612842, 976891, -183443, 2286327, 420899, 2235985, 2939036,
|
|
3833893, 260646, 1104333, 1667432, -1910376, 1803090, -1723600, 426683,
|
|
-472078, -1717735, 975884, -2213111, -269760, -3866901, -3523897, 3038916,
|
|
1799107, 3694233, -1652634, -810149, -3014001, -1616392, -162844, 3183426,
|
|
1207385, -185531, -3369112, -1957272, 164721, -2454455, -2432395, 2013608,
|
|
3776993, -594136, 3724270, 2584293, 1846953, 1671176, 2831860, 542412,
|
|
-3406031, -2235880, -777191, -1500165, 1374803, 2546312, -1917081, 1279661,
|
|
1962642, -3306115, -1312455, 451100, 1430225, 3318210, -1237275, 1333058,
|
|
1050970, -1903435, -1869119, 2994039, 3548272, -2635921, -1250494, 3767016,
|
|
-1595974, -2486353, -1247620, -4055324, -1265009, 2590150, -2691481, -2842341,
|
|
-203044, -1735879, 3342277, -3437287, -4108315, 2437823, -286988, -342297,
|
|
3595838, 768622, 525098, 3556995, -3207046, -2031748, 3122442, 655327,
|
|
522500, 43260, 1613174, -495491, -819034, -909542, -1859098, -900702,
|
|
3193378, 1197226, 3759364, 3520352, -3513181, 1235728, -2434439, -266997,
|
|
3562462, 2446433, -2244091, 3342478, -3817976, -2316500, -3407706, -2091667,
|
|
-3839961, 3628969, 3881060, 3019102, 1439742, 812732, 1584928, -1285669,
|
|
-1341330, -1315589, 177440, 2409325, 1851402, -3159746, 3553272, -189548,
|
|
1316856, -759969, 210977, -2389356, 3249728, -1653064, 8578, 3724342,
|
|
-3958618, -904516, 1100098, -44288, -3097992, -508951, -264944, 3343383,
|
|
1430430, -1852771, -1349076, 381987, 1308169, 22981, 1228525, 671102,
|
|
2477047, 411027, 3693493, 2967645, -2715295, -2147896, 983419, -3412210,
|
|
-126922, 3632928, 3157330, 3190144, 1000202, 4083598, -1939314, 1257611,
|
|
1585221, -2176455, -3475950, 1452451, 3041255, 3677745, 1528703, 3930395,
|
|
2797779, -2071892, 2556880, -3900724, -3881043, -954230, -531354, -811944,
|
|
-3699596, 1600420, 2140649, -3507263, 3821735, -3505694, 1643818, 1699267,
|
|
539299, -2348700, 300467, -3539968, 2867647, -3574422, 3043716, 3861115,
|
|
-3915439, 2537516, 3592148, 1661693, -3530437, -3077325, -95776, -2706023,
|
|
-280005, -4010497, 19422, -1757237, 3277672, 1399561, 3859737, 2118186,
|
|
2108549, -2619752, 1119584, 549488, -3585928, 1079900, -1024112, -2725464,
|
|
-2680103, -3111497, 2884855, -3119733, 2091905, 359251, -2353451, -1826347,
|
|
-466468, 876248, 777960, -237124, 518909, 2608894, -25847, 41978
|
|
};
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || \
|
|
!defined(WOLFSSL_DILITHIUM_NO_VERIFY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_MAKE) && defined(WOLFSSL_DILITHIUM_SMALL))
|
|
|
|
/* One iteration of Number-Theoretic Transform.
|
|
*
|
|
* @param [in] len Length of sequence.
|
|
*/
|
|
#define NTT(len) \
|
|
do { \
|
|
for (start = 0; start < DILITHIUM_N; start += 2 * (len)) { \
|
|
zeta = zetas[++k]; \
|
|
for (j = 0; j < (len); ++j) { \
|
|
sword32 t = \
|
|
dilithium_mont_red((sword64)zeta * r[start + j + (len)]); \
|
|
sword32 rj = r[start + j]; \
|
|
r[start + j + (len)] = rj - t; \
|
|
r[start + j] = rj + t; \
|
|
} \
|
|
} \
|
|
} \
|
|
while (0)
|
|
|
|
/* Number-Theoretic Transform.
|
|
*
|
|
* @param [in, out] r Polynomial to transform.
|
|
*/
|
|
static void dilithium_ntt(sword32* r)
|
|
{
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
unsigned int len;
|
|
unsigned int k;
|
|
unsigned int j;
|
|
|
|
k = 0;
|
|
for (len = DILITHIUM_N / 2; len >= 1; len >>= 1) {
|
|
unsigned int start;
|
|
for (start = 0; start < DILITHIUM_N; start = j + len) {
|
|
sword32 zeta = zetas[++k];
|
|
for (j = start; j < start + len; ++j) {
|
|
sword32 t = dilithium_mont_red((sword64)zeta * r[j + len]);
|
|
sword32 rj = r[j];
|
|
r[j + len] = rj - t;
|
|
r[j] = rj + t;
|
|
}
|
|
}
|
|
}
|
|
#elif defined(WOLFSSL_DILITHIUM_NO_LARGE_CODE)
|
|
unsigned int j;
|
|
unsigned int k;
|
|
unsigned int start;
|
|
sword32 zeta;
|
|
|
|
zeta = zetas[1];
|
|
for (j = 0; j < DILITHIUM_N / 2; j++) {
|
|
sword32 t =
|
|
dilithium_mont_red((sword64)zeta * r[j + DILITHIUM_N / 2]);
|
|
sword32 rj = r[j];
|
|
r[j + DILITHIUM_N / 2] = rj - t;
|
|
r[j] = rj + t;
|
|
}
|
|
|
|
k = 1;
|
|
NTT(64);
|
|
NTT(32);
|
|
NTT(16);
|
|
NTT(8);
|
|
NTT(4);
|
|
NTT(2);
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 2) {
|
|
sword32 t = dilithium_mont_red((sword64)zetas[++k] * r[j + 1]);
|
|
sword32 rj = r[j];
|
|
r[j + 1] = rj - t;
|
|
r[j] = rj + t;
|
|
}
|
|
#elif defined(WC_32BIT_CPU)
|
|
unsigned int j;
|
|
unsigned int k;
|
|
sword32 t0;
|
|
sword32 t2;
|
|
|
|
sword32 zeta128 = zetas[1];
|
|
sword32 zeta640 = zetas[2];
|
|
sword32 zeta641 = zetas[3];
|
|
for (j = 0; j < DILITHIUM_N / 4; j++) {
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r2 = r[j + 64];
|
|
sword32 r4 = r[j + 128];
|
|
sword32 r6 = r[j + 192];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta128 * r4);
|
|
t2 = dilithium_mont_red((sword64)zeta128 * r6);
|
|
r4 = r0 - t0;
|
|
r6 = r2 - t2;
|
|
r0 += t0;
|
|
r2 += t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta640 * r2);
|
|
t2 = dilithium_mont_red((sword64)zeta641 * r6);
|
|
r2 = r0 - t0;
|
|
r6 = r4 - t2;
|
|
r0 += t0;
|
|
r4 += t2;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 64] = r2;
|
|
r[j + 128] = r4;
|
|
r[j + 192] = r6;
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 64) {
|
|
unsigned int i;
|
|
sword32 zeta32 = zetas[ 4 + j / 64 + 0];
|
|
sword32 zeta160 = zetas[ 8 + j / 32 + 0];
|
|
sword32 zeta161 = zetas[ 8 + j / 32 + 1];
|
|
for (i = 0; i < 16; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r2 = r[j + i + 16];
|
|
sword32 r4 = r[j + i + 32];
|
|
sword32 r6 = r[j + i + 48];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta32 * r4);
|
|
t2 = dilithium_mont_red((sword64)zeta32 * r6);
|
|
r4 = r0 - t0;
|
|
r6 = r2 - t2;
|
|
r0 += t0;
|
|
r2 += t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta160 * r2);
|
|
t2 = dilithium_mont_red((sword64)zeta161 * r6);
|
|
r2 = r0 - t0;
|
|
r6 = r4 - t2;
|
|
r0 += t0;
|
|
r4 += t2;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 16] = r2;
|
|
r[j + i + 32] = r4;
|
|
r[j + i + 48] = r6;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 16) {
|
|
unsigned int i;
|
|
sword32 zeta8 = zetas[16 + j / 16];
|
|
sword32 zeta40 = zetas[32 + j / 8 + 0];
|
|
sword32 zeta41 = zetas[32 + j / 8 + 1];
|
|
for (i = 0; i < 4; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r2 = r[j + i + 4];
|
|
sword32 r4 = r[j + i + 8];
|
|
sword32 r6 = r[j + i + 12];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta8 * r4);
|
|
t2 = dilithium_mont_red((sword64)zeta8 * r6);
|
|
r4 = r0 - t0;
|
|
r6 = r2 - t2;
|
|
r0 += t0;
|
|
r2 += t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta40 * r2);
|
|
t2 = dilithium_mont_red((sword64)zeta41 * r6);
|
|
r2 = r0 - t0;
|
|
r6 = r4 - t2;
|
|
r0 += t0;
|
|
r4 += t2;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 4] = r2;
|
|
r[j + i + 8] = r4;
|
|
r[j + i + 12] = r6;
|
|
}
|
|
}
|
|
|
|
k = 128;
|
|
for (j = 0; j < DILITHIUM_N; j += 4) {
|
|
sword32 zeta2 = zetas[64 + j / 4];
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r2 = r[j + 1];
|
|
sword32 r4 = r[j + 2];
|
|
sword32 r6 = r[j + 3];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta2 * r4);
|
|
t2 = dilithium_mont_red((sword64)zeta2 * r6);
|
|
r4 = r0 - t0;
|
|
r6 = r2 - t2;
|
|
r0 += t0;
|
|
r2 += t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zetas[k++] * r2);
|
|
t2 = dilithium_mont_red((sword64)zetas[k++] * r6);
|
|
r2 = r0 - t0;
|
|
r6 = r4 - t2;
|
|
r0 += t0;
|
|
r4 += t2;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 1] = r2;
|
|
r[j + 2] = r4;
|
|
r[j + 3] = r6;
|
|
}
|
|
#else
|
|
unsigned int j;
|
|
unsigned int k;
|
|
sword32 t0;
|
|
sword32 t1;
|
|
sword32 t2;
|
|
sword32 t3;
|
|
|
|
sword32 zeta128 = zetas[1];
|
|
sword32 zeta640 = zetas[2];
|
|
sword32 zeta641 = zetas[3];
|
|
for (j = 0; j < DILITHIUM_N / 8; j++) {
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r1 = r[j + 32];
|
|
sword32 r2 = r[j + 64];
|
|
sword32 r3 = r[j + 96];
|
|
sword32 r4 = r[j + 128];
|
|
sword32 r5 = r[j + 160];
|
|
sword32 r6 = r[j + 192];
|
|
sword32 r7 = r[j + 224];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta128 * r4);
|
|
t1 = dilithium_mont_red((sword64)zeta128 * r5);
|
|
t2 = dilithium_mont_red((sword64)zeta128 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta128 * r7);
|
|
r4 = r0 - t0;
|
|
r5 = r1 - t1;
|
|
r6 = r2 - t2;
|
|
r7 = r3 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r2 += t2;
|
|
r3 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta640 * r2);
|
|
t1 = dilithium_mont_red((sword64)zeta640 * r3);
|
|
t2 = dilithium_mont_red((sword64)zeta641 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta641 * r7);
|
|
r2 = r0 - t0;
|
|
r3 = r1 - t1;
|
|
r6 = r4 - t2;
|
|
r7 = r5 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r4 += t2;
|
|
r5 += t3;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 32] = r1;
|
|
r[j + 64] = r2;
|
|
r[j + 96] = r3;
|
|
r[j + 128] = r4;
|
|
r[j + 160] = r5;
|
|
r[j + 192] = r6;
|
|
r[j + 224] = r7;
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 64) {
|
|
unsigned int i;
|
|
sword32 zeta32 = zetas[ 4 + j / 64 + 0];
|
|
sword32 zeta160 = zetas[ 8 + j / 32 + 0];
|
|
sword32 zeta161 = zetas[ 8 + j / 32 + 1];
|
|
sword32 zeta80 = zetas[16 + j / 16 + 0];
|
|
sword32 zeta81 = zetas[16 + j / 16 + 1];
|
|
sword32 zeta82 = zetas[16 + j / 16 + 2];
|
|
sword32 zeta83 = zetas[16 + j / 16 + 3];
|
|
for (i = 0; i < 8; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r1 = r[j + i + 8];
|
|
sword32 r2 = r[j + i + 16];
|
|
sword32 r3 = r[j + i + 24];
|
|
sword32 r4 = r[j + i + 32];
|
|
sword32 r5 = r[j + i + 40];
|
|
sword32 r6 = r[j + i + 48];
|
|
sword32 r7 = r[j + i + 56];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta32 * r4);
|
|
t1 = dilithium_mont_red((sword64)zeta32 * r5);
|
|
t2 = dilithium_mont_red((sword64)zeta32 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta32 * r7);
|
|
r4 = r0 - t0;
|
|
r5 = r1 - t1;
|
|
r6 = r2 - t2;
|
|
r7 = r3 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r2 += t2;
|
|
r3 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta160 * r2);
|
|
t1 = dilithium_mont_red((sword64)zeta160 * r3);
|
|
t2 = dilithium_mont_red((sword64)zeta161 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta161 * r7);
|
|
r2 = r0 - t0;
|
|
r3 = r1 - t1;
|
|
r6 = r4 - t2;
|
|
r7 = r5 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r4 += t2;
|
|
r5 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta80 * r1);
|
|
t1 = dilithium_mont_red((sword64)zeta81 * r3);
|
|
t2 = dilithium_mont_red((sword64)zeta82 * r5);
|
|
t3 = dilithium_mont_red((sword64)zeta83 * r7);
|
|
r1 = r0 - t0;
|
|
r3 = r2 - t1;
|
|
r5 = r4 - t2;
|
|
r7 = r6 - t3;
|
|
r0 += t0;
|
|
r2 += t1;
|
|
r4 += t2;
|
|
r6 += t3;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 8] = r1;
|
|
r[j + i + 16] = r2;
|
|
r[j + i + 24] = r3;
|
|
r[j + i + 32] = r4;
|
|
r[j + i + 40] = r5;
|
|
r[j + i + 48] = r6;
|
|
r[j + i + 56] = r7;
|
|
}
|
|
}
|
|
|
|
k = 128;
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
sword32 zeta4 = zetas[32 + j / 8 + 0];
|
|
sword32 zeta20 = zetas[64 + j / 4 + 0];
|
|
sword32 zeta21 = zetas[64 + j / 4 + 1];
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r1 = r[j + 1];
|
|
sword32 r2 = r[j + 2];
|
|
sword32 r3 = r[j + 3];
|
|
sword32 r4 = r[j + 4];
|
|
sword32 r5 = r[j + 5];
|
|
sword32 r6 = r[j + 6];
|
|
sword32 r7 = r[j + 7];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta4 * r4);
|
|
t1 = dilithium_mont_red((sword64)zeta4 * r5);
|
|
t2 = dilithium_mont_red((sword64)zeta4 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta4 * r7);
|
|
r4 = r0 - t0;
|
|
r5 = r1 - t1;
|
|
r6 = r2 - t2;
|
|
r7 = r3 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r2 += t2;
|
|
r3 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta20 * r2);
|
|
t1 = dilithium_mont_red((sword64)zeta20 * r3);
|
|
t2 = dilithium_mont_red((sword64)zeta21 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta21 * r7);
|
|
r2 = r0 - t0;
|
|
r3 = r1 - t1;
|
|
r6 = r4 - t2;
|
|
r7 = r5 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r4 += t2;
|
|
r5 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zetas[k++] * r1);
|
|
t1 = dilithium_mont_red((sword64)zetas[k++] * r3);
|
|
t2 = dilithium_mont_red((sword64)zetas[k++] * r5);
|
|
t3 = dilithium_mont_red((sword64)zetas[k++] * r7);
|
|
r1 = r0 - t0;
|
|
r3 = r2 - t1;
|
|
r5 = r4 - t2;
|
|
r7 = r6 - t3;
|
|
r0 += t0;
|
|
r2 += t1;
|
|
r4 += t2;
|
|
r6 += t3;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 1] = r1;
|
|
r[j + 2] = r2;
|
|
r[j + 3] = r3;
|
|
r[j + 4] = r4;
|
|
r[j + 5] = r5;
|
|
r[j + 6] = r6;
|
|
r[j + 7] = r7;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_VERIFY) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
(defined(WC_DILITHIUM_CACHE_PRIV_VECTORS) || \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)))
|
|
/* Number-Theoretic Transform.
|
|
*
|
|
* @param [in, out] r Vector of polynomials to transform.
|
|
* @param [in] l Dimension of polynomial.
|
|
*/
|
|
static void dilithium_vec_ntt(sword32* r, byte l)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_ntt(r);
|
|
r += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_SMALL
|
|
|
|
/* Number-Theoretic Transform with small initial values.
|
|
*
|
|
* @param [in, out] r Polynomial to transform.
|
|
*/
|
|
static void dilithium_ntt_small(sword32* r)
|
|
{
|
|
unsigned int k;
|
|
unsigned int j;
|
|
#ifdef WOLFSSL_DILITHIUM_NO_LARGE_CODE
|
|
unsigned int start;
|
|
sword32 zeta;
|
|
|
|
for (j = 0; j < DILITHIUM_N / 2; ++j) {
|
|
sword32 t = dilithium_red((sword32)-3572223 * r[j + DILITHIUM_N / 2]);
|
|
sword32 rj = r[j];
|
|
r[j + DILITHIUM_N / 2] = rj - t;
|
|
r[j] = rj + t;
|
|
}
|
|
|
|
k = 1;
|
|
NTT(64);
|
|
NTT(32);
|
|
NTT(16);
|
|
NTT(8);
|
|
NTT(4);
|
|
NTT(2);
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 2) {
|
|
sword32 t = dilithium_mont_red((sword64)zetas[++k] * r[j + 1]);
|
|
sword32 rj = r[j];
|
|
r[j + 1] = rj - t;
|
|
r[j] = rj + t;
|
|
}
|
|
#elif defined(WC_32BIT_CPU)
|
|
sword32 t0;
|
|
sword32 t2;
|
|
|
|
sword32 zeta640 = zetas[2];
|
|
sword32 zeta641 = zetas[3];
|
|
for (j = 0; j < DILITHIUM_N / 4; j++) {
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r2 = r[j + 64];
|
|
sword32 r4 = r[j + 128];
|
|
sword32 r6 = r[j + 192];
|
|
|
|
t0 = dilithium_red((sword32)-3572223 * r4);
|
|
t2 = dilithium_red((sword32)-3572223 * r6);
|
|
r4 = r0 - t0;
|
|
r6 = r2 - t2;
|
|
r0 += t0;
|
|
r2 += t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta640 * r2);
|
|
t2 = dilithium_mont_red((sword64)zeta641 * r6);
|
|
r2 = r0 - t0;
|
|
r6 = r4 - t2;
|
|
r0 += t0;
|
|
r4 += t2;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 64] = r2;
|
|
r[j + 128] = r4;
|
|
r[j + 192] = r6;
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 64) {
|
|
unsigned int i;
|
|
sword32 zeta32 = zetas[ 4 + j / 64 + 0];
|
|
sword32 zeta160 = zetas[ 8 + j / 32 + 0];
|
|
sword32 zeta161 = zetas[ 8 + j / 32 + 1];
|
|
for (i = 0; i < 16; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r2 = r[j + i + 16];
|
|
sword32 r4 = r[j + i + 32];
|
|
sword32 r6 = r[j + i + 48];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta32 * r4);
|
|
t2 = dilithium_mont_red((sword64)zeta32 * r6);
|
|
r4 = r0 - t0;
|
|
r6 = r2 - t2;
|
|
r0 += t0;
|
|
r2 += t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta160 * r2);
|
|
t2 = dilithium_mont_red((sword64)zeta161 * r6);
|
|
r2 = r0 - t0;
|
|
r6 = r4 - t2;
|
|
r0 += t0;
|
|
r4 += t2;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 16] = r2;
|
|
r[j + i + 32] = r4;
|
|
r[j + i + 48] = r6;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 16) {
|
|
unsigned int i;
|
|
sword32 zeta8 = zetas[16 + j / 16];
|
|
sword32 zeta40 = zetas[32 + j / 8 + 0];
|
|
sword32 zeta41 = zetas[32 + j / 8 + 1];
|
|
for (i = 0; i < 4; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r2 = r[j + i + 4];
|
|
sword32 r4 = r[j + i + 8];
|
|
sword32 r6 = r[j + i + 12];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta8 * r4);
|
|
t2 = dilithium_mont_red((sword64)zeta8 * r6);
|
|
r4 = r0 - t0;
|
|
r6 = r2 - t2;
|
|
r0 += t0;
|
|
r2 += t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta40 * r2);
|
|
t2 = dilithium_mont_red((sword64)zeta41 * r6);
|
|
r2 = r0 - t0;
|
|
r6 = r4 - t2;
|
|
r0 += t0;
|
|
r4 += t2;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 4] = r2;
|
|
r[j + i + 8] = r4;
|
|
r[j + i + 12] = r6;
|
|
}
|
|
}
|
|
|
|
k = 128;
|
|
for (j = 0; j < DILITHIUM_N; j += 4) {
|
|
sword32 zeta2 = zetas[64 + j / 4];
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r2 = r[j + 1];
|
|
sword32 r4 = r[j + 2];
|
|
sword32 r6 = r[j + 3];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta2 * r4);
|
|
t2 = dilithium_mont_red((sword64)zeta2 * r6);
|
|
r4 = r0 - t0;
|
|
r6 = r2 - t2;
|
|
r0 += t0;
|
|
r2 += t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zetas[k++] * r2);
|
|
t2 = dilithium_mont_red((sword64)zetas[k++] * r6);
|
|
r2 = r0 - t0;
|
|
r6 = r4 - t2;
|
|
r0 += t0;
|
|
r4 += t2;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 1] = r2;
|
|
r[j + 2] = r4;
|
|
r[j + 3] = r6;
|
|
}
|
|
#else
|
|
sword32 t0;
|
|
sword32 t1;
|
|
sword32 t2;
|
|
sword32 t3;
|
|
sword32 zeta640 = zetas[2];
|
|
sword32 zeta641 = zetas[3];
|
|
for (j = 0; j < DILITHIUM_N / 8; j++) {
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r1 = r[j + 32];
|
|
sword32 r2 = r[j + 64];
|
|
sword32 r3 = r[j + 96];
|
|
sword32 r4 = r[j + 128];
|
|
sword32 r5 = r[j + 160];
|
|
sword32 r6 = r[j + 192];
|
|
sword32 r7 = r[j + 224];
|
|
|
|
t0 = dilithium_red((sword32)-3572223 * r4);
|
|
t1 = dilithium_red((sword32)-3572223 * r5);
|
|
t2 = dilithium_red((sword32)-3572223 * r6);
|
|
t3 = dilithium_red((sword32)-3572223 * r7);
|
|
r4 = r0 - t0;
|
|
r5 = r1 - t1;
|
|
r6 = r2 - t2;
|
|
r7 = r3 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r2 += t2;
|
|
r3 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta640 * r2);
|
|
t1 = dilithium_mont_red((sword64)zeta640 * r3);
|
|
t2 = dilithium_mont_red((sword64)zeta641 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta641 * r7);
|
|
r2 = r0 - t0;
|
|
r3 = r1 - t1;
|
|
r6 = r4 - t2;
|
|
r7 = r5 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r4 += t2;
|
|
r5 += t3;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 32] = r1;
|
|
r[j + 64] = r2;
|
|
r[j + 96] = r3;
|
|
r[j + 128] = r4;
|
|
r[j + 160] = r5;
|
|
r[j + 192] = r6;
|
|
r[j + 224] = r7;
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 64) {
|
|
unsigned int i;
|
|
sword32 zeta32 = zetas[ 4 + j / 64 + 0];
|
|
sword32 zeta160 = zetas[ 8 + j / 32 + 0];
|
|
sword32 zeta161 = zetas[ 8 + j / 32 + 1];
|
|
sword32 zeta80 = zetas[16 + j / 16 + 0];
|
|
sword32 zeta81 = zetas[16 + j / 16 + 1];
|
|
sword32 zeta82 = zetas[16 + j / 16 + 2];
|
|
sword32 zeta83 = zetas[16 + j / 16 + 3];
|
|
for (i = 0; i < 8; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r1 = r[j + i + 8];
|
|
sword32 r2 = r[j + i + 16];
|
|
sword32 r3 = r[j + i + 24];
|
|
sword32 r4 = r[j + i + 32];
|
|
sword32 r5 = r[j + i + 40];
|
|
sword32 r6 = r[j + i + 48];
|
|
sword32 r7 = r[j + i + 56];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta32 * r4);
|
|
t1 = dilithium_mont_red((sword64)zeta32 * r5);
|
|
t2 = dilithium_mont_red((sword64)zeta32 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta32 * r7);
|
|
r4 = r0 - t0;
|
|
r5 = r1 - t1;
|
|
r6 = r2 - t2;
|
|
r7 = r3 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r2 += t2;
|
|
r3 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta160 * r2);
|
|
t1 = dilithium_mont_red((sword64)zeta160 * r3);
|
|
t2 = dilithium_mont_red((sword64)zeta161 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta161 * r7);
|
|
r2 = r0 - t0;
|
|
r3 = r1 - t1;
|
|
r6 = r4 - t2;
|
|
r7 = r5 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r4 += t2;
|
|
r5 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta80 * r1);
|
|
t1 = dilithium_mont_red((sword64)zeta81 * r3);
|
|
t2 = dilithium_mont_red((sword64)zeta82 * r5);
|
|
t3 = dilithium_mont_red((sword64)zeta83 * r7);
|
|
r1 = r0 - t0;
|
|
r3 = r2 - t1;
|
|
r5 = r4 - t2;
|
|
r7 = r6 - t3;
|
|
r0 += t0;
|
|
r2 += t1;
|
|
r4 += t2;
|
|
r6 += t3;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 8] = r1;
|
|
r[j + i + 16] = r2;
|
|
r[j + i + 24] = r3;
|
|
r[j + i + 32] = r4;
|
|
r[j + i + 40] = r5;
|
|
r[j + i + 48] = r6;
|
|
r[j + i + 56] = r7;
|
|
}
|
|
}
|
|
|
|
k = 128;
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
sword32 zeta4 = zetas[32 + j / 8 + 0];
|
|
sword32 zeta20 = zetas[64 + j / 4 + 0];
|
|
sword32 zeta21 = zetas[64 + j / 4 + 1];
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r1 = r[j + 1];
|
|
sword32 r2 = r[j + 2];
|
|
sword32 r3 = r[j + 3];
|
|
sword32 r4 = r[j + 4];
|
|
sword32 r5 = r[j + 5];
|
|
sword32 r6 = r[j + 6];
|
|
sword32 r7 = r[j + 7];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta4 * r4);
|
|
t1 = dilithium_mont_red((sword64)zeta4 * r5);
|
|
t2 = dilithium_mont_red((sword64)zeta4 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta4 * r7);
|
|
r4 = r0 - t0;
|
|
r5 = r1 - t1;
|
|
r6 = r2 - t2;
|
|
r7 = r3 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r2 += t2;
|
|
r3 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta20 * r2);
|
|
t1 = dilithium_mont_red((sword64)zeta20 * r3);
|
|
t2 = dilithium_mont_red((sword64)zeta21 * r6);
|
|
t3 = dilithium_mont_red((sword64)zeta21 * r7);
|
|
r2 = r0 - t0;
|
|
r3 = r1 - t1;
|
|
r6 = r4 - t2;
|
|
r7 = r5 - t3;
|
|
r0 += t0;
|
|
r1 += t1;
|
|
r4 += t2;
|
|
r5 += t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zetas[k++] * r1);
|
|
t1 = dilithium_mont_red((sword64)zetas[k++] * r3);
|
|
t2 = dilithium_mont_red((sword64)zetas[k++] * r5);
|
|
t3 = dilithium_mont_red((sword64)zetas[k++] * r7);
|
|
r1 = r0 - t0;
|
|
r3 = r2 - t1;
|
|
r5 = r4 - t2;
|
|
r7 = r6 - t3;
|
|
r0 += t0;
|
|
r2 += t1;
|
|
r4 += t2;
|
|
r6 += t3;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 1] = r1;
|
|
r[j + 2] = r2;
|
|
r[j + 3] = r3;
|
|
r[j + 4] = r4;
|
|
r[j + 5] = r5;
|
|
r[j + 6] = r6;
|
|
r[j + 7] = r7;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
(defined(WC_DILITHIUM_CACHE_PRIV_VECTORS) || \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)))
|
|
/* Number-Theoretic Transform with small initial values.
|
|
*
|
|
* @param [in, out] r Vector of polynomials to transform.
|
|
* @param [in] l Dimension of polynomial.
|
|
*/
|
|
static void dilithium_vec_ntt_small(sword32* r, byte l)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_ntt_small(r);
|
|
r += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif /* !WOLFSSL_DILITHIUM_VERIFY_ONLY */
|
|
|
|
#else
|
|
|
|
/* Number-Theoretic Transform with small initial values.
|
|
*
|
|
* @param [in, out] r Polynomial to transform.
|
|
*/
|
|
#define dilithium_ntt_small dilithium_ntt
|
|
/* Number-Theoretic Transform with small initial values.
|
|
*
|
|
* @param [in, out] r Vector of polynomials to transform.
|
|
* @param [in] l Dimension of polynomial.
|
|
*/
|
|
#define dilithium_vec_ntt_small dilithium_vec_ntt
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_SMALL */
|
|
|
|
|
|
/* One iteration of Inverse Number-Theoretic Transform.
|
|
*
|
|
* @param [in] len Length of sequence.
|
|
*/
|
|
#define INVNTT(len) \
|
|
do { \
|
|
for (start = 0; start < DILITHIUM_N; start += 2 * (len)) { \
|
|
zeta = zetas_inv[k++]; \
|
|
for (j = 0; j < (len); ++j) { \
|
|
sword32 rj = r[start + j]; \
|
|
sword32 rjl = r[start + j + (len)]; \
|
|
sword32 t = rj + rjl; \
|
|
r[start + j] = t; \
|
|
rjl = rj - rjl; \
|
|
r[start + j + (len)] = dilithium_mont_red((sword64)zeta * rjl); \
|
|
} \
|
|
} \
|
|
} \
|
|
while (0)
|
|
|
|
/* Inverse Number-Theoretic Transform.
|
|
*
|
|
* @param [in, out] r Polynomial to transform.
|
|
*/
|
|
static void dilithium_invntt(sword32* r)
|
|
{
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
unsigned int len;
|
|
unsigned int k;
|
|
unsigned int j;
|
|
sword32 zeta;
|
|
|
|
k = 256;
|
|
for (len = 1; len <= DILITHIUM_N / 2; len <<= 1) {
|
|
unsigned int start;
|
|
for (start = 0; start < DILITHIUM_N; start = j + len) {
|
|
zeta = -zetas[--k];
|
|
for (j = start; j < start + len; ++j) {
|
|
sword32 rj = r[j];
|
|
sword32 rjl = r[j + len];
|
|
sword32 t = rj + rjl;
|
|
r[j] = t;
|
|
rjl = rj - rjl;
|
|
r[j + len] = dilithium_mont_red((sword64)zeta * rjl);
|
|
}
|
|
}
|
|
}
|
|
|
|
zeta = -zetas[0];
|
|
for (j = 0; j < DILITHIUM_N; ++j) {
|
|
r[j] = dilithium_mont_red((sword64)zeta * r[j]);
|
|
}
|
|
#elif defined(WOLFSSL_DILITHIUM_NO_LARGE_CODE)
|
|
unsigned int j;
|
|
unsigned int k = 0;
|
|
unsigned int start;
|
|
sword32 zeta;
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 2) {
|
|
sword32 rj = r[j];
|
|
sword32 rjl = r[j + 1];
|
|
sword32 t = rj + rjl;
|
|
r[j] = t;
|
|
rjl = rj - rjl;
|
|
r[j + 1] = dilithium_mont_red((sword64)zetas_inv[k++] * rjl);
|
|
}
|
|
|
|
INVNTT(2);
|
|
INVNTT(4);
|
|
INVNTT(8);
|
|
INVNTT(16);
|
|
INVNTT(32);
|
|
INVNTT(64);
|
|
INVNTT(128);
|
|
|
|
zeta = zetas_inv[255];
|
|
for (j = 0; j < DILITHIUM_N; ++j) {
|
|
r[j] = dilithium_mont_red((sword64)zeta * r[j]);
|
|
}
|
|
#elif defined(WC_32BIT_CPU)
|
|
unsigned int j;
|
|
unsigned int k = 0;
|
|
sword32 t0;
|
|
sword32 t2;
|
|
|
|
sword32 zeta640;
|
|
sword32 zeta641;
|
|
sword32 zeta128;
|
|
sword32 zeta256;
|
|
for (j = 0; j < DILITHIUM_N; j += 4) {
|
|
sword32 zeta2 = zetas_inv[128 + j / 4];
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r2 = r[j + 1];
|
|
sword32 r4 = r[j + 2];
|
|
sword32 r6 = r[j + 3];
|
|
|
|
t0 = dilithium_mont_red((sword64)zetas_inv[k++] * (r0 - r2));
|
|
t2 = dilithium_mont_red((sword64)zetas_inv[k++] * (r4 - r6));
|
|
r0 += r2;
|
|
r4 += r6;
|
|
r2 = t0;
|
|
r6 = t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta2 * (r0 - r4));
|
|
t2 = dilithium_mont_red((sword64)zeta2 * (r2 - r6));
|
|
r0 += r4;
|
|
r2 += r6;
|
|
r4 = t0;
|
|
r6 = t2;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 1] = r2;
|
|
r[j + 2] = r4;
|
|
r[j + 3] = r6;
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 16) {
|
|
unsigned int i;
|
|
sword32 zeta40 = zetas_inv[192 + j / 8 + 0];
|
|
sword32 zeta41 = zetas_inv[192 + j / 8 + 1];
|
|
sword32 zeta8 = zetas_inv[224 + j / 16 + 0];
|
|
for (i = 0; i < 4; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r2 = r[j + i + 4];
|
|
sword32 r4 = r[j + i + 8];
|
|
sword32 r6 = r[j + i + 12];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta40 * (r0 - r2));
|
|
t2 = dilithium_mont_red((sword64)zeta41 * (r4 - r6));
|
|
r0 += r2;
|
|
r4 += r6;
|
|
r2 = t0;
|
|
r6 = t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta8 * (r0 - r4));
|
|
t2 = dilithium_mont_red((sword64)zeta8 * (r2 - r6));
|
|
r0 += r4;
|
|
r2 += r6;
|
|
r4 = t0;
|
|
r6 = t2;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 4] = r2;
|
|
r[j + i + 8] = r4;
|
|
r[j + i + 12] = r6;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 64) {
|
|
unsigned int i;
|
|
sword32 zeta160 = zetas_inv[240 + j / 32 + 0];
|
|
sword32 zeta161 = zetas_inv[240 + j / 32 + 1];
|
|
sword32 zeta32 = zetas_inv[248 + j / 64 + 0];
|
|
for (i = 0; i < 16; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r2 = r[j + i + 16];
|
|
sword32 r4 = r[j + i + 32];
|
|
sword32 r6 = r[j + i + 48];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta160 * (r0 - r2));
|
|
t2 = dilithium_mont_red((sword64)zeta161 * (r4 - r6));
|
|
r0 += r2;
|
|
r4 += r6;
|
|
r2 = t0;
|
|
r6 = t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta32 * (r0 - r4));
|
|
t2 = dilithium_mont_red((sword64)zeta32 * (r2 - r6));
|
|
r0 += r4;
|
|
r2 += r6;
|
|
r4 = t0;
|
|
r6 = t2;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 16] = r2;
|
|
r[j + i + 32] = r4;
|
|
r[j + i + 48] = r6;
|
|
}
|
|
}
|
|
|
|
zeta640 = zetas_inv[252];
|
|
zeta641 = zetas_inv[253];
|
|
zeta128 = zetas_inv[254];
|
|
zeta256 = zetas_inv[255];
|
|
for (j = 0; j < DILITHIUM_N / 4; j++) {
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r2 = r[j + 64];
|
|
sword32 r4 = r[j + 128];
|
|
sword32 r6 = r[j + 192];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta640 * (r0 - r2));
|
|
t2 = dilithium_mont_red((sword64)zeta641 * (r4 - r6));
|
|
r0 += r2;
|
|
r4 += r6;
|
|
r2 = t0;
|
|
r6 = t2;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta128 * (r0 - r4));
|
|
t2 = dilithium_mont_red((sword64)zeta128 * (r2 - r6));
|
|
r0 += r4;
|
|
r2 += r6;
|
|
r4 = t0;
|
|
r6 = t2;
|
|
|
|
r0 = dilithium_mont_red((sword64)zeta256 * r0);
|
|
r2 = dilithium_mont_red((sword64)zeta256 * r2);
|
|
r4 = dilithium_mont_red((sword64)zeta256 * r4);
|
|
r6 = dilithium_mont_red((sword64)zeta256 * r6);
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 64] = r2;
|
|
r[j + 128] = r4;
|
|
r[j + 192] = r6;
|
|
}
|
|
#else
|
|
unsigned int j;
|
|
unsigned int k = 0;
|
|
sword32 t0;
|
|
sword32 t1;
|
|
sword32 t2;
|
|
sword32 t3;
|
|
|
|
sword32 zeta640;
|
|
sword32 zeta641;
|
|
sword32 zeta128;
|
|
sword32 zeta256;
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
sword32 zeta20 = zetas_inv[128 + j / 4 + 0];
|
|
sword32 zeta21 = zetas_inv[128 + j / 4 + 1];
|
|
sword32 zeta4 = zetas_inv[192 + j / 8 + 0];
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r1 = r[j + 1];
|
|
sword32 r2 = r[j + 2];
|
|
sword32 r3 = r[j + 3];
|
|
sword32 r4 = r[j + 4];
|
|
sword32 r5 = r[j + 5];
|
|
sword32 r6 = r[j + 6];
|
|
sword32 r7 = r[j + 7];
|
|
|
|
t0 = dilithium_mont_red((sword64)zetas_inv[k++] * (r0 - r1));
|
|
t1 = dilithium_mont_red((sword64)zetas_inv[k++] * (r2 - r3));
|
|
t2 = dilithium_mont_red((sword64)zetas_inv[k++] * (r4 - r5));
|
|
t3 = dilithium_mont_red((sword64)zetas_inv[k++] * (r6 - r7));
|
|
r0 += r1;
|
|
r2 += r3;
|
|
r4 += r5;
|
|
r6 += r7;
|
|
r1 = t0;
|
|
r3 = t1;
|
|
r5 = t2;
|
|
r7 = t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta20 * (r0 - r2));
|
|
t1 = dilithium_mont_red((sword64)zeta20 * (r1 - r3));
|
|
t2 = dilithium_mont_red((sword64)zeta21 * (r4 - r6));
|
|
t3 = dilithium_mont_red((sword64)zeta21 * (r5 - r7));
|
|
r0 += r2;
|
|
r1 += r3;
|
|
r4 += r6;
|
|
r5 += r7;
|
|
r2 = t0;
|
|
r3 = t1;
|
|
r6 = t2;
|
|
r7 = t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta4 * (r0 - r4));
|
|
t1 = dilithium_mont_red((sword64)zeta4 * (r1 - r5));
|
|
t2 = dilithium_mont_red((sword64)zeta4 * (r2 - r6));
|
|
t3 = dilithium_mont_red((sword64)zeta4 * (r3 - r7));
|
|
r0 += r4;
|
|
r1 += r5;
|
|
r2 += r6;
|
|
r3 += r7;
|
|
r4 = t0;
|
|
r5 = t1;
|
|
r6 = t2;
|
|
r7 = t3;
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 1] = r1;
|
|
r[j + 2] = r2;
|
|
r[j + 3] = r3;
|
|
r[j + 4] = r4;
|
|
r[j + 5] = r5;
|
|
r[j + 6] = r6;
|
|
r[j + 7] = r7;
|
|
}
|
|
|
|
for (j = 0; j < DILITHIUM_N; j += 64) {
|
|
unsigned int i;
|
|
sword32 zeta80 = zetas_inv[224 + j / 16 + 0];
|
|
sword32 zeta81 = zetas_inv[224 + j / 16 + 1];
|
|
sword32 zeta82 = zetas_inv[224 + j / 16 + 2];
|
|
sword32 zeta83 = zetas_inv[224 + j / 16 + 3];
|
|
sword32 zeta160 = zetas_inv[240 + j / 32 + 0];
|
|
sword32 zeta161 = zetas_inv[240 + j / 32 + 1];
|
|
sword32 zeta32 = zetas_inv[248 + j / 64 + 0];
|
|
for (i = 0; i < 8; i++) {
|
|
sword32 r0 = r[j + i + 0];
|
|
sword32 r1 = r[j + i + 8];
|
|
sword32 r2 = r[j + i + 16];
|
|
sword32 r3 = r[j + i + 24];
|
|
sword32 r4 = r[j + i + 32];
|
|
sword32 r5 = r[j + i + 40];
|
|
sword32 r6 = r[j + i + 48];
|
|
sword32 r7 = r[j + i + 56];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta80 * (r0 - r1));
|
|
t1 = dilithium_mont_red((sword64)zeta81 * (r2 - r3));
|
|
t2 = dilithium_mont_red((sword64)zeta82 * (r4 - r5));
|
|
t3 = dilithium_mont_red((sword64)zeta83 * (r6 - r7));
|
|
r0 += r1;
|
|
r2 += r3;
|
|
r4 += r5;
|
|
r6 += r7;
|
|
r1 = t0;
|
|
r3 = t1;
|
|
r5 = t2;
|
|
r7 = t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta160 * (r0 - r2));
|
|
t1 = dilithium_mont_red((sword64)zeta160 * (r1 - r3));
|
|
t2 = dilithium_mont_red((sword64)zeta161 * (r4 - r6));
|
|
t3 = dilithium_mont_red((sword64)zeta161 * (r5 - r7));
|
|
r0 += r2;
|
|
r1 += r3;
|
|
r4 += r6;
|
|
r5 += r7;
|
|
r2 = t0;
|
|
r3 = t1;
|
|
r6 = t2;
|
|
r7 = t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta32 * (r0 - r4));
|
|
t1 = dilithium_mont_red((sword64)zeta32 * (r1 - r5));
|
|
t2 = dilithium_mont_red((sword64)zeta32 * (r2 - r6));
|
|
t3 = dilithium_mont_red((sword64)zeta32 * (r3 - r7));
|
|
r0 += r4;
|
|
r1 += r5;
|
|
r2 += r6;
|
|
r3 += r7;
|
|
r4 = t0;
|
|
r5 = t1;
|
|
r6 = t2;
|
|
r7 = t3;
|
|
|
|
r[j + i + 0] = r0;
|
|
r[j + i + 8] = r1;
|
|
r[j + i + 16] = r2;
|
|
r[j + i + 24] = r3;
|
|
r[j + i + 32] = r4;
|
|
r[j + i + 40] = r5;
|
|
r[j + i + 48] = r6;
|
|
r[j + i + 56] = r7;
|
|
}
|
|
}
|
|
|
|
zeta640 = zetas_inv[252];
|
|
zeta641 = zetas_inv[253];
|
|
zeta128 = zetas_inv[254];
|
|
zeta256 = zetas_inv[255];
|
|
for (j = 0; j < DILITHIUM_N / 8; j++) {
|
|
sword32 r0 = r[j + 0];
|
|
sword32 r1 = r[j + 32];
|
|
sword32 r2 = r[j + 64];
|
|
sword32 r3 = r[j + 96];
|
|
sword32 r4 = r[j + 128];
|
|
sword32 r5 = r[j + 160];
|
|
sword32 r6 = r[j + 192];
|
|
sword32 r7 = r[j + 224];
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta640 * (r0 - r2));
|
|
t1 = dilithium_mont_red((sword64)zeta640 * (r1 - r3));
|
|
t2 = dilithium_mont_red((sword64)zeta641 * (r4 - r6));
|
|
t3 = dilithium_mont_red((sword64)zeta641 * (r5 - r7));
|
|
r0 += r2;
|
|
r1 += r3;
|
|
r4 += r6;
|
|
r5 += r7;
|
|
r2 = t0;
|
|
r3 = t1;
|
|
r6 = t2;
|
|
r7 = t3;
|
|
|
|
t0 = dilithium_mont_red((sword64)zeta128 * (r0 - r4));
|
|
t1 = dilithium_mont_red((sword64)zeta128 * (r1 - r5));
|
|
t2 = dilithium_mont_red((sword64)zeta128 * (r2 - r6));
|
|
t3 = dilithium_mont_red((sword64)zeta128 * (r3 - r7));
|
|
r0 += r4;
|
|
r1 += r5;
|
|
r2 += r6;
|
|
r3 += r7;
|
|
r4 = t0;
|
|
r5 = t1;
|
|
r6 = t2;
|
|
r7 = t3;
|
|
|
|
r0 = dilithium_mont_red((sword64)zeta256 * r0);
|
|
r1 = dilithium_mont_red((sword64)zeta256 * r1);
|
|
r2 = dilithium_mont_red((sword64)zeta256 * r2);
|
|
r3 = dilithium_mont_red((sword64)zeta256 * r3);
|
|
r4 = dilithium_mont_red((sword64)zeta256 * r4);
|
|
r5 = dilithium_mont_red((sword64)zeta256 * r5);
|
|
r6 = dilithium_mont_red((sword64)zeta256 * r6);
|
|
r7 = dilithium_mont_red((sword64)zeta256 * r7);
|
|
|
|
r[j + 0] = r0;
|
|
r[j + 32] = r1;
|
|
r[j + 64] = r2;
|
|
r[j + 96] = r3;
|
|
r[j + 128] = r4;
|
|
r[j + 160] = r5;
|
|
r[j + 192] = r6;
|
|
r[j + 224] = r7;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM)) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM))
|
|
/* Inverse Number-Theoretic Transform.
|
|
*
|
|
* @param [in, out] r Vector of polynomials to transform.
|
|
* @param [in] l Dimension of polynomial.
|
|
*/
|
|
static void dilithium_vec_invntt(sword32* r, byte l)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_invntt(r);
|
|
r += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM)) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM))
|
|
/* Matrix multiplication.
|
|
*
|
|
* @param [out] r Vector of polynomials that is result.
|
|
* @param [in] m Matrix of polynomials.
|
|
* @param [in] v Vector of polynomials.
|
|
* @param [in] k First dimension of matrix and dimension of result.
|
|
* @param [in] l Second dimension of matrix and dimension of v.
|
|
*/
|
|
static void dilithium_matrix_mul(sword32* r, const sword32* m, const sword32* v,
|
|
byte k, byte l)
|
|
{
|
|
byte i;
|
|
|
|
for (i = 0; i < k; i++) {
|
|
byte j;
|
|
unsigned int e;
|
|
const sword32* vt = v;
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
r[e] = dilithium_mont_red((sword64)m[e] * vt[e]);
|
|
}
|
|
m += DILITHIUM_N;
|
|
vt += DILITHIUM_N;
|
|
for (j = 1; j < l; j++) {
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
r[e] += dilithium_mont_red((sword64)m[e] * vt[e]);
|
|
}
|
|
m += DILITHIUM_N;
|
|
vt += DILITHIUM_N;
|
|
}
|
|
#elif defined(WOLFSSL_DILITHIUM_NO_LARGE_CODE)
|
|
(void)j;
|
|
if (l == 4) {
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
sword64 t = ((sword64)m[e + 0 * 256] * vt[e + 0 * 256]) +
|
|
((sword64)m[e + 1 * 256] * vt[e + 1 * 256]) +
|
|
((sword64)m[e + 2 * 256] * vt[e + 2 * 256]) +
|
|
((sword64)m[e + 3 * 256] * vt[e + 3 * 256]);
|
|
r[e] = dilithium_mont_red(t);
|
|
}
|
|
m += DILITHIUM_N * 4;
|
|
}
|
|
else if (l == 5) {
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
sword64 t = ((sword64)m[e + 0 * 256] * vt[e + 0 * 256]) +
|
|
((sword64)m[e + 1 * 256] * vt[e + 1 * 256]) +
|
|
((sword64)m[e + 2 * 256] * vt[e + 2 * 256]) +
|
|
((sword64)m[e + 3 * 256] * vt[e + 3 * 256]) +
|
|
((sword64)m[e + 4 * 256] * vt[e + 4 * 256]);
|
|
r[e] = dilithium_mont_red(t);
|
|
}
|
|
m += DILITHIUM_N * 5;
|
|
}
|
|
else if (l == 7) {
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
sword64 t = ((sword64)m[e + 0 * 256] * vt[e + 0 * 256]) +
|
|
((sword64)m[e + 1 * 256] * vt[e + 1 * 256]) +
|
|
((sword64)m[e + 2 * 256] * vt[e + 2 * 256]) +
|
|
((sword64)m[e + 3 * 256] * vt[e + 3 * 256]) +
|
|
((sword64)m[e + 4 * 256] * vt[e + 4 * 256]) +
|
|
((sword64)m[e + 5 * 256] * vt[e + 5 * 256]) +
|
|
((sword64)m[e + 6 * 256] * vt[e + 6 * 256]);
|
|
r[e] = dilithium_mont_red(t);
|
|
}
|
|
m += DILITHIUM_N * 7;
|
|
}
|
|
#else
|
|
sword64 t0;
|
|
sword64 t1;
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_65)
|
|
sword64 t2;
|
|
sword64 t3;
|
|
#endif
|
|
|
|
(void)j;
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (l == 4) {
|
|
for (e = 0; e < DILITHIUM_N; e += 4) {
|
|
t0 = ((sword64)m[e + 0 + 0 * 256] * vt[e + 0 + 0 * 256]) +
|
|
((sword64)m[e + 0 + 1 * 256] * vt[e + 0 + 1 * 256]) +
|
|
((sword64)m[e + 0 + 2 * 256] * vt[e + 0 + 2 * 256]) +
|
|
((sword64)m[e + 0 + 3 * 256] * vt[e + 0 + 3 * 256]);
|
|
t1 = ((sword64)m[e + 1 + 0 * 256] * vt[e + 1 + 0 * 256]) +
|
|
((sword64)m[e + 1 + 1 * 256] * vt[e + 1 + 1 * 256]) +
|
|
((sword64)m[e + 1 + 2 * 256] * vt[e + 1 + 2 * 256]) +
|
|
((sword64)m[e + 1 + 3 * 256] * vt[e + 1 + 3 * 256]);
|
|
t2 = ((sword64)m[e + 2 + 0 * 256] * vt[e + 2 + 0 * 256]) +
|
|
((sword64)m[e + 2 + 1 * 256] * vt[e + 2 + 1 * 256]) +
|
|
((sword64)m[e + 2 + 2 * 256] * vt[e + 2 + 2 * 256]) +
|
|
((sword64)m[e + 2 + 3 * 256] * vt[e + 2 + 3 * 256]);
|
|
t3 = ((sword64)m[e + 3 + 0 * 256] * vt[e + 3 + 0 * 256]) +
|
|
((sword64)m[e + 3 + 1 * 256] * vt[e + 3 + 1 * 256]) +
|
|
((sword64)m[e + 3 + 2 * 256] * vt[e + 3 + 2 * 256]) +
|
|
((sword64)m[e + 3 + 3 * 256] * vt[e + 3 + 3 * 256]);
|
|
r[e + 0] = dilithium_mont_red(t0);
|
|
r[e + 1] = dilithium_mont_red(t1);
|
|
r[e + 2] = dilithium_mont_red(t2);
|
|
r[e + 3] = dilithium_mont_red(t3);
|
|
}
|
|
m += DILITHIUM_N * 4;
|
|
}
|
|
else
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
if (l == 5) {
|
|
for (e = 0; e < DILITHIUM_N; e += 4) {
|
|
t0 = ((sword64)m[e + 0 + 0 * 256] * vt[e + 0 + 0 * 256]) +
|
|
((sword64)m[e + 0 + 1 * 256] * vt[e + 0 + 1 * 256]) +
|
|
((sword64)m[e + 0 + 2 * 256] * vt[e + 0 + 2 * 256]) +
|
|
((sword64)m[e + 0 + 3 * 256] * vt[e + 0 + 3 * 256]) +
|
|
((sword64)m[e + 0 + 4 * 256] * vt[e + 0 + 4 * 256]);
|
|
t1 = ((sword64)m[e + 1 + 0 * 256] * vt[e + 1 + 0 * 256]) +
|
|
((sword64)m[e + 1 + 1 * 256] * vt[e + 1 + 1 * 256]) +
|
|
((sword64)m[e + 1 + 2 * 256] * vt[e + 1 + 2 * 256]) +
|
|
((sword64)m[e + 1 + 3 * 256] * vt[e + 1 + 3 * 256]) +
|
|
((sword64)m[e + 1 + 4 * 256] * vt[e + 1 + 4 * 256]);
|
|
t2 = ((sword64)m[e + 2 + 0 * 256] * vt[e + 2 + 0 * 256]) +
|
|
((sword64)m[e + 2 + 1 * 256] * vt[e + 2 + 1 * 256]) +
|
|
((sword64)m[e + 2 + 2 * 256] * vt[e + 2 + 2 * 256]) +
|
|
((sword64)m[e + 2 + 3 * 256] * vt[e + 2 + 3 * 256]) +
|
|
((sword64)m[e + 2 + 4 * 256] * vt[e + 2 + 4 * 256]);
|
|
t3 = ((sword64)m[e + 3 + 0 * 256] * vt[e + 3 + 0 * 256]) +
|
|
((sword64)m[e + 3 + 1 * 256] * vt[e + 3 + 1 * 256]) +
|
|
((sword64)m[e + 3 + 2 * 256] * vt[e + 3 + 2 * 256]) +
|
|
((sword64)m[e + 3 + 3 * 256] * vt[e + 3 + 3 * 256]) +
|
|
((sword64)m[e + 3 + 4 * 256] * vt[e + 3 + 4 * 256]);
|
|
r[e + 0] = dilithium_mont_red(t0);
|
|
r[e + 1] = dilithium_mont_red(t1);
|
|
r[e + 2] = dilithium_mont_red(t2);
|
|
r[e + 3] = dilithium_mont_red(t3);
|
|
}
|
|
m += DILITHIUM_N * 5;
|
|
}
|
|
else
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_87
|
|
if (l == 7) {
|
|
for (e = 0; e < DILITHIUM_N; e += 2) {
|
|
t0 = ((sword64)m[e + 0 + 0 * 256] * vt[e + 0 + 0 * 256]) +
|
|
((sword64)m[e + 0 + 1 * 256] * vt[e + 0 + 1 * 256]) +
|
|
((sword64)m[e + 0 + 2 * 256] * vt[e + 0 + 2 * 256]) +
|
|
((sword64)m[e + 0 + 3 * 256] * vt[e + 0 + 3 * 256]) +
|
|
((sword64)m[e + 0 + 4 * 256] * vt[e + 0 + 4 * 256]) +
|
|
((sword64)m[e + 0 + 5 * 256] * vt[e + 0 + 5 * 256]) +
|
|
((sword64)m[e + 0 + 6 * 256] * vt[e + 0 + 6 * 256]);
|
|
t1 = ((sword64)m[e + 1 + 0 * 256] * vt[e + 1 + 0 * 256]) +
|
|
((sword64)m[e + 1 + 1 * 256] * vt[e + 1 + 1 * 256]) +
|
|
((sword64)m[e + 1 + 2 * 256] * vt[e + 1 + 2 * 256]) +
|
|
((sword64)m[e + 1 + 3 * 256] * vt[e + 1 + 3 * 256]) +
|
|
((sword64)m[e + 1 + 4 * 256] * vt[e + 1 + 4 * 256]) +
|
|
((sword64)m[e + 1 + 5 * 256] * vt[e + 1 + 5 * 256]) +
|
|
((sword64)m[e + 1 + 6 * 256] * vt[e + 1 + 6 * 256]);
|
|
r[e + 0] = dilithium_mont_red(t0);
|
|
r[e + 1] = dilithium_mont_red(t1);
|
|
}
|
|
m += DILITHIUM_N * 7;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
#endif
|
|
r += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM))
|
|
/* Polynomial multiplication.
|
|
*
|
|
* @param [out] r Polynomial result.
|
|
* @param [in] a Polynomial
|
|
* @param [in] b Polynomial.
|
|
*/
|
|
static void dilithium_mul(sword32* r, sword32* a, sword32* b)
|
|
{
|
|
unsigned int e;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
r[e] = dilithium_mont_red((sword64)a[e] * b[e]);
|
|
}
|
|
#elif defined(WOLFSSL_DILITHIUM_NO_LARGE_CODE)
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
r[e+0] = dilithium_mont_red((sword64)a[e+0] * b[e+0]);
|
|
r[e+1] = dilithium_mont_red((sword64)a[e+1] * b[e+1]);
|
|
r[e+2] = dilithium_mont_red((sword64)a[e+2] * b[e+2]);
|
|
r[e+3] = dilithium_mont_red((sword64)a[e+3] * b[e+3]);
|
|
r[e+4] = dilithium_mont_red((sword64)a[e+4] * b[e+4]);
|
|
r[e+5] = dilithium_mont_red((sword64)a[e+5] * b[e+5]);
|
|
r[e+6] = dilithium_mont_red((sword64)a[e+6] * b[e+6]);
|
|
r[e+7] = dilithium_mont_red((sword64)a[e+7] * b[e+7]);
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 16) {
|
|
r[e+ 0] = dilithium_mont_red((sword64)a[e+ 0] * b[e+ 0]);
|
|
r[e+ 1] = dilithium_mont_red((sword64)a[e+ 1] * b[e+ 1]);
|
|
r[e+ 2] = dilithium_mont_red((sword64)a[e+ 2] * b[e+ 2]);
|
|
r[e+ 3] = dilithium_mont_red((sword64)a[e+ 3] * b[e+ 3]);
|
|
r[e+ 4] = dilithium_mont_red((sword64)a[e+ 4] * b[e+ 4]);
|
|
r[e+ 5] = dilithium_mont_red((sword64)a[e+ 5] * b[e+ 5]);
|
|
r[e+ 6] = dilithium_mont_red((sword64)a[e+ 6] * b[e+ 6]);
|
|
r[e+ 7] = dilithium_mont_red((sword64)a[e+ 7] * b[e+ 7]);
|
|
r[e+ 8] = dilithium_mont_red((sword64)a[e+ 8] * b[e+ 8]);
|
|
r[e+ 9] = dilithium_mont_red((sword64)a[e+ 9] * b[e+ 9]);
|
|
r[e+10] = dilithium_mont_red((sword64)a[e+10] * b[e+10]);
|
|
r[e+11] = dilithium_mont_red((sword64)a[e+11] * b[e+11]);
|
|
r[e+12] = dilithium_mont_red((sword64)a[e+12] * b[e+12]);
|
|
r[e+13] = dilithium_mont_red((sword64)a[e+13] * b[e+13]);
|
|
r[e+14] = dilithium_mont_red((sword64)a[e+14] * b[e+14]);
|
|
r[e+15] = dilithium_mont_red((sword64)a[e+15] * b[e+15]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if (!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM)) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM))
|
|
/* Vector multiplication.
|
|
*
|
|
* @param [out] r Vector of polynomials that is result.
|
|
* @param [in] a Polynomials
|
|
* @param [in] b Vector of polynomials.
|
|
* @param [in] l Dimension of vectors.
|
|
*/
|
|
static void dilithium_vec_mul(sword32* r, sword32* a, sword32* b, byte l)
|
|
{
|
|
byte i;
|
|
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_mul(r, a, b);
|
|
r += DILITHIUM_N;
|
|
b += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_SIGN
|
|
/* Modulo reduce values in polynomial. Range (-2^31)..(2^31-1).
|
|
*
|
|
* @param [in, out] a Polynomial.
|
|
*/
|
|
static void dilithium_poly_red(sword32* a)
|
|
{
|
|
word16 j;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
a[j] = dilithium_red(a[j]);
|
|
}
|
|
#else
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
a[j+0] = dilithium_red(a[j+0]);
|
|
a[j+1] = dilithium_red(a[j+1]);
|
|
a[j+2] = dilithium_red(a[j+2]);
|
|
a[j+3] = dilithium_red(a[j+3]);
|
|
a[j+4] = dilithium_red(a[j+4]);
|
|
a[j+5] = dilithium_red(a[j+5]);
|
|
a[j+6] = dilithium_red(a[j+6]);
|
|
a[j+7] = dilithium_red(a[j+7]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM
|
|
/* Modulo reduce values in polynomials of vector. Range (-2^31)..(2^31-1).
|
|
*
|
|
* @param [in, out] a Vector of polynomials.
|
|
* @param [in] l Dimension of vector.
|
|
*/
|
|
static void dilithium_vec_red(sword32* a, byte l)
|
|
{
|
|
byte i;
|
|
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_poly_red(a);
|
|
a += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_SIGN_SMALL_MEM*/
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN */
|
|
|
|
#if (!defined(WOLFSSL_DILITHIUM_NO_SIGN) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM))) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY)
|
|
/* Subtract polynomials a from r. r -= a.
|
|
*
|
|
* @param [out] r Polynomial to subtract from.
|
|
* @param [in] a Polynomial to subtract.
|
|
*/
|
|
static void dilithium_sub(sword32* r, const sword32* a)
|
|
{
|
|
word16 j;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
r[j] -= a[j];
|
|
}
|
|
#else
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
r[j+0] -= a[j+0];
|
|
r[j+1] -= a[j+1];
|
|
r[j+2] -= a[j+2];
|
|
r[j+3] -= a[j+3];
|
|
r[j+4] -= a[j+4];
|
|
r[j+5] -= a[j+5];
|
|
r[j+6] -= a[j+6];
|
|
r[j+7] -= a[j+7];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
|
!defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM)) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM))
|
|
/* Subtract vector a from r. r -= a.
|
|
*
|
|
* @param [out] r Vector of polynomials that is result.
|
|
* @param [in] a Vector of polynomials to subtract.
|
|
* @param [in] l Dimension of vectors.
|
|
*/
|
|
static void dilithium_vec_sub(sword32* r, const sword32* a, byte l)
|
|
{
|
|
byte i;
|
|
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_sub(r, a);
|
|
r += DILITHIUM_N;
|
|
a += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_VERIFY_ONLY
|
|
/* Add polynomials a to r. r += a.
|
|
*
|
|
* @param [out] r Polynomial to add to.
|
|
* @param [in] a Polynomial to add.
|
|
*/
|
|
static void dilithium_add(sword32* r, const sword32* a)
|
|
{
|
|
word16 j;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
r[j] += a[j];
|
|
}
|
|
#else
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
r[j+0] += a[j+0];
|
|
r[j+1] += a[j+1];
|
|
r[j+2] += a[j+2];
|
|
r[j+3] += a[j+3];
|
|
r[j+4] += a[j+4];
|
|
r[j+5] += a[j+5];
|
|
r[j+6] += a[j+6];
|
|
r[j+7] += a[j+7];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM))
|
|
/* Add vector a to r. r += a.
|
|
*
|
|
* @param [out] r Vector of polynomials that is result.
|
|
* @param [in] a Vector of polynomials to add.
|
|
* @param [in] l Dimension of vectors.
|
|
*/
|
|
static void dilithium_vec_add(sword32* r, const sword32* a, byte l)
|
|
{
|
|
byte i;
|
|
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_add(r, a);
|
|
r += DILITHIUM_N;
|
|
a += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Make values in polynomial be in positive range.
|
|
*
|
|
* @param [in, out] a Polynomial.
|
|
*/
|
|
static void dilithium_make_pos(sword32* a)
|
|
{
|
|
word16 j;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
a[j] += (0 - (((word32)a[j]) >> 31)) & DILITHIUM_Q;
|
|
}
|
|
#else
|
|
for (j = 0; j < DILITHIUM_N; j += 8) {
|
|
a[j+0] += (0 - (((word32)a[j+0]) >> 31)) & DILITHIUM_Q;
|
|
a[j+1] += (0 - (((word32)a[j+1]) >> 31)) & DILITHIUM_Q;
|
|
a[j+2] += (0 - (((word32)a[j+2]) >> 31)) & DILITHIUM_Q;
|
|
a[j+3] += (0 - (((word32)a[j+3]) >> 31)) & DILITHIUM_Q;
|
|
a[j+4] += (0 - (((word32)a[j+4]) >> 31)) & DILITHIUM_Q;
|
|
a[j+5] += (0 - (((word32)a[j+5]) >> 31)) & DILITHIUM_Q;
|
|
a[j+6] += (0 - (((word32)a[j+6]) >> 31)) & DILITHIUM_Q;
|
|
a[j+7] += (0 - (((word32)a[j+7]) >> 31)) & DILITHIUM_Q;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \
|
|
defined(WOLFSSL_DILITHIUM_CHECK_KEY) || \
|
|
(!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
|
!defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM))
|
|
/* Make values in polynomials of vector be in positive range.
|
|
*
|
|
* @param [in, out] a Vector of polynomials.
|
|
* @param [in] l Dimension of vector.
|
|
*/
|
|
static void dilithium_vec_make_pos(sword32* a, byte l)
|
|
{
|
|
byte i;
|
|
|
|
for (i = 0; i < l; i++) {
|
|
dilithium_make_pos(a);
|
|
a += DILITHIUM_N;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif /* !WOLFSSL_DILITHIUM_VERIFY_ONLY */
|
|
|
|
/******************************************************************************/
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY
|
|
|
|
/* Make a key from a random seed.
|
|
*
|
|
* xi is seed passed in.
|
|
* FIPS 204. 6.1: Algorithm 6 ML-DSA.KeyGen_internal(xi)
|
|
* 1: (rho, rho', K) E B32 x B64 x B32 <- H(xi||k||l, 1024)
|
|
* 2:
|
|
* 3: A_circum <- ExpandA(rho)
|
|
* 4: (s1,s2) <- ExpandS(rho')
|
|
* 5: t <- NTT-1(A_circum o NTT(s1)) + s2
|
|
* 6: (t1, t0) <- Power2Round(t, d)
|
|
* 7: pk <- pkEncode(rho, t1)
|
|
* 8: tr <- H(pk, 64)
|
|
* 9: sk <- skEncode(rho, K, tr, s1, s2, t0)
|
|
* 10: return (pk, sk)
|
|
*
|
|
* FIPS 204. 7.2: Algorithm 22 pkEncode(rho, t1)
|
|
* 1: pk <- rho
|
|
* 2: for i from 0 to k - 1 do
|
|
* 3: pk <- pk || SimpleBitPack(t1[i], 2^(bitlen(q-1)-d) - 1)
|
|
* 4: end for
|
|
* 5: return pk
|
|
*
|
|
* FIPS 204. 7.2: Algorithm 24 skEncode(rho, K, tr, s, s2, t0)
|
|
* 1: sk <- rho || K || tr
|
|
* 2: for i from 0 to l - 1 do
|
|
* 3: sk <- sk || BitPack(s1[i], eta, eta)
|
|
* 4: end for
|
|
* 5: for i from 0 to k - 1 do
|
|
* 6: sk <- sk || BitPack(s2[i], eta, eta)
|
|
* 7: end for
|
|
* 8: for i from 0 to k - 1 do
|
|
* 9: sk <- sk || BitPack(t0[i], 2^(d-1)-1, 2^(d-1))
|
|
* 10: end for
|
|
* 11: return sk
|
|
*
|
|
* Public and private key store in key.
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] seed Seed to hash to generate values.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_make_key_from_seed(dilithium_key* key, const byte* seed)
|
|
{
|
|
#ifndef WOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM
|
|
int ret = 0;
|
|
const wc_dilithium_params* params = key->params;
|
|
sword32* a = NULL;
|
|
sword32* s1 = NULL;
|
|
sword32* s2 = NULL;
|
|
sword32* t = NULL;
|
|
byte* pub_seed = key->k;
|
|
byte kl[2];
|
|
|
|
/* Allocate memory for large intermediates. */
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
if (key->a == NULL) {
|
|
key->a = (sword32*)XMALLOC(params->aSz, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->a == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
a = key->a;
|
|
}
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
if ((ret == 0) && (key->s1 == NULL)) {
|
|
key->s1 = (sword32*)XMALLOC(params->aSz, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->s1 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
key->s2 = key->s1 + params->s1Sz / sizeof(*s1);
|
|
key->t0 = key->s2 + params->s2Sz / sizeof(*s2);
|
|
}
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
s1 = key->s1;
|
|
s2 = key->s2;
|
|
t = key->t0;
|
|
}
|
|
#else
|
|
if (ret == 0) {
|
|
unsigned int allocSz;
|
|
|
|
allocSz = params->s1Sz + params->s2Sz + params->s2Sz;
|
|
#ifndef WC_DILITHIUM_CACHE_MATRIX_A
|
|
allocSz += params->aSz;
|
|
#endif
|
|
|
|
/* s1, s2, t, a */
|
|
s1 = (sword32*)XMALLOC(allocSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (s1 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
s2 = s1 + params->s1Sz / sizeof(*s1);
|
|
t = s2 + params->s2Sz / sizeof(*s2);
|
|
#ifndef WC_DILITHIUM_CACHE_MATRIX_A
|
|
a = t + params->s2Sz / sizeof(*t);
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
|
if (key->params->level >= WC_ML_DSA_DRAFT) {
|
|
/* Step 2: Create public seed, private seed and K from seed.
|
|
* Step 9; Alg 18, Step 1: Public seed is placed into private key.
|
|
*/
|
|
ret = dilithium_shake256(&key->shake, seed, DILITHIUM_SEED_SZ,
|
|
pub_seed, DILITHIUM_SEEDS_SZ);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
kl[0] = params->k;
|
|
kl[1] = params->l;
|
|
/* Step 1: Create public seed, private seed and K from seed.
|
|
* Step 9; Alg 24, Step 1: Public seed is placed into private key.
|
|
*/
|
|
ret = dilithium_hash256(&key->shake, seed, DILITHIUM_SEED_SZ, kl, 2,
|
|
pub_seed, DILITHIUM_SEEDS_SZ);
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 7; Alg 22 Step 1: Copy public seed into public key. */
|
|
XMEMCPY(key->p, pub_seed, DILITHIUM_PUB_SEED_SZ);
|
|
|
|
/* Step 3: Expand public seed into a matrix of polynomials. */
|
|
ret = dilithium_expand_a(&key->shake, pub_seed, params->k, params->l,
|
|
a, key->heap);
|
|
}
|
|
if (ret == 0) {
|
|
byte* priv_seed = key->k + DILITHIUM_PUB_SEED_SZ;
|
|
|
|
/* Step 4: Expand private seed into to vectors of polynomials. */
|
|
ret = dilithium_expand_s(&key->shake, priv_seed, params->eta, s1,
|
|
params->l, s2, params->k);
|
|
}
|
|
if (ret == 0) {
|
|
byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
byte* tr = k + DILITHIUM_K_SZ;
|
|
byte* s1p = tr + DILITHIUM_TR_SZ;
|
|
byte* s2p = s1p + params->s1EncSz;
|
|
byte* t0 = s2p + params->s2EncSz;
|
|
byte* t1 = key->p + DILITHIUM_PUB_SEED_SZ;
|
|
|
|
/* Step 9: Move k down to after public seed. */
|
|
XMEMCPY(k, k + DILITHIUM_PRIV_SEED_SZ, DILITHIUM_K_SZ);
|
|
/* Step 9. Alg 24 Steps 2-4: Encode s1 into private key. */
|
|
dilthium_vec_encode_eta_bits(s1, params->l, params->eta, s1p);
|
|
/* Step 9. Alg 24 Steps 5-7: Encode s2 into private key. */
|
|
dilthium_vec_encode_eta_bits(s2, params->k, params->eta, s2p);
|
|
|
|
/* Step 5: t <- NTT-1(A_circum o NTT(s1)) + s2 */
|
|
dilithium_vec_ntt_small(s1, params->l);
|
|
dilithium_matrix_mul(t, a, s1, params->k, params->l);
|
|
dilithium_vec_invntt(t, params->k);
|
|
dilithium_vec_add(t, s2, params->k);
|
|
|
|
/* Make positive for decomposing. */
|
|
dilithium_vec_make_pos(t, params->k);
|
|
/* Step 6, Step 7, Step 9. Alg 22 Steps 2-4, Alg 24 Steps 8-10.
|
|
* Decompose t in t0 and t1 and encode into public and private key.
|
|
*/
|
|
dilithium_vec_encode_t0_t1(t, params->k, t0, t1);
|
|
/* Step 8. Alg 24, Step 1: Hash public key into private key. */
|
|
ret = dilithium_shake256(&key->shake, key->p, params->pkSz, tr,
|
|
DILITHIUM_TR_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
/* Public key and private key are available. */
|
|
key->prvKeySet = 1;
|
|
key->pubKeySet = 1;
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
/* Matrix A is available. */
|
|
key->aSet = 1;
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
/* Private vectors are not available as they were overwritten. */
|
|
key->privVecsSet = 0;
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PUB_VECTORS
|
|
/* Public vector, t1, is not available as it was not created. */
|
|
key->pubVecSet = 0;
|
|
#endif
|
|
}
|
|
|
|
#ifndef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
XFREE(s1, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
#endif
|
|
return ret;
|
|
#else
|
|
int ret = 0;
|
|
const wc_dilithium_params* params = key->params;
|
|
sword32* a = NULL;
|
|
sword32* s1 = NULL;
|
|
sword32* s2 = NULL;
|
|
sword32* t = NULL;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
sword64* t64 = NULL;
|
|
#endif
|
|
byte* h = NULL;
|
|
byte* pub_seed = key->k;
|
|
unsigned int r;
|
|
unsigned int s;
|
|
byte kl[2];
|
|
|
|
/* Allocate memory for large intermediates. */
|
|
if (ret == 0) {
|
|
unsigned int allocSz;
|
|
|
|
/* s1-l, s2-k, t-k, a-1 */
|
|
allocSz = params->s1Sz + params->s2Sz + params->s2Sz +
|
|
DILITHIUM_REJ_NTT_POLY_H_SIZE + DILITHIUM_POLY_SIZE;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
/* t64 */
|
|
allocSz += DILITHIUM_POLY_SIZE * 2;
|
|
#endif
|
|
s1 = (sword32*)XMALLOC(allocSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (s1 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
s2 = s1 + params->s1Sz / sizeof(*s1);
|
|
t = s2 + params->s2Sz / sizeof(*s2);
|
|
h = (byte*)(t + params->s2Sz / sizeof(*t));
|
|
a = (sword32*)(h + DILITHIUM_REJ_NTT_POLY_H_SIZE);
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
t64 = (sword64*)(a + DILITHIUM_N);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
|
if (key->params->level >= WC_ML_DSA_DRAFT) {
|
|
/* Step 2: Create public seed, private seed and K from seed.
|
|
* Step 9; Alg 18, Step 1: Public seed is placed into private key.
|
|
*/
|
|
ret = dilithium_shake256(&key->shake, seed, DILITHIUM_SEED_SZ,
|
|
pub_seed, DILITHIUM_SEEDS_SZ);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
kl[0] = params->k;
|
|
kl[1] = params->l;
|
|
/* Step 1: Create public seed, private seed and K from seed.
|
|
* Step 9; Alg 24, Step 1: Public seed is placed into private key.
|
|
*/
|
|
ret = dilithium_hash256(&key->shake, seed, DILITHIUM_SEED_SZ, kl, 2,
|
|
pub_seed, DILITHIUM_SEEDS_SZ);
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
byte* priv_seed = key->k + DILITHIUM_PUB_SEED_SZ;
|
|
|
|
/* Step 7; Alg 22 Step 1: Copy public seed into public key. */
|
|
XMEMCPY(key->p, pub_seed, DILITHIUM_PUB_SEED_SZ);
|
|
|
|
/* Step 4: Expand private seed into to vectors of polynomials. */
|
|
ret = dilithium_expand_s(&key->shake, priv_seed, params->eta, s1,
|
|
params->l, s2, params->k);
|
|
}
|
|
if (ret == 0) {
|
|
byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
byte* tr = k + DILITHIUM_K_SZ;
|
|
byte* s1p = tr + DILITHIUM_TR_SZ;
|
|
byte* s2p = s1p + params->s1EncSz;
|
|
byte* t0 = s2p + params->s2EncSz;
|
|
byte* t1 = key->p + DILITHIUM_PUB_SEED_SZ;
|
|
byte aseed[DILITHIUM_GEN_A_SEED_SZ];
|
|
sword32* s2t = s2;
|
|
sword32* tt = t;
|
|
|
|
/* Step 9: Move k down to after public seed. */
|
|
XMEMCPY(k, k + DILITHIUM_PRIV_SEED_SZ, DILITHIUM_K_SZ);
|
|
/* Step 9. Alg 24 Steps 2-4: Encode s1 into private key. */
|
|
dilthium_vec_encode_eta_bits(s1, params->l, params->eta, s1p);
|
|
/* Step 9. Alg 24 Steps 5-7: Encode s2 into private key. */
|
|
dilthium_vec_encode_eta_bits(s2, params->k, params->eta, s2p);
|
|
|
|
/* Step 5: NTT(s1) */
|
|
dilithium_vec_ntt_small(s1, params->l);
|
|
/* Step 5: t <- NTT-1(A_circum o NTT(s1)) + s2 */
|
|
XMEMCPY(aseed, pub_seed, DILITHIUM_PUB_SEED_SZ);
|
|
for (r = 0; (ret == 0) && (r < params->k); r++) {
|
|
sword32* s1t = s1;
|
|
unsigned int e;
|
|
|
|
/* Put r/i into buffer to be hashed. */
|
|
aseed[DILITHIUM_PUB_SEED_SZ + 1] = r;
|
|
for (s = 0; (ret == 0) && (s < params->l); s++) {
|
|
|
|
/* Put s into buffer to be hashed. */
|
|
aseed[DILITHIUM_PUB_SEED_SZ + 0] = s;
|
|
/* Step 3: Expand public seed into a matrix of polynomials. */
|
|
ret = dilithium_rej_ntt_poly_ex(&key->shake, aseed, a, h);
|
|
if (ret != 0) {
|
|
break;
|
|
}
|
|
/* Matrix multiply. */
|
|
#ifndef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
if (s == 0) {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
tt[e] = dilithium_mont_red((sword64)a[e] * s1t[e]);
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
tt[e+0] = dilithium_mont_red((sword64)a[e+0]*s1t[e+0]);
|
|
tt[e+1] = dilithium_mont_red((sword64)a[e+1]*s1t[e+1]);
|
|
tt[e+2] = dilithium_mont_red((sword64)a[e+2]*s1t[e+2]);
|
|
tt[e+3] = dilithium_mont_red((sword64)a[e+3]*s1t[e+3]);
|
|
tt[e+4] = dilithium_mont_red((sword64)a[e+4]*s1t[e+4]);
|
|
tt[e+5] = dilithium_mont_red((sword64)a[e+5]*s1t[e+5]);
|
|
tt[e+6] = dilithium_mont_red((sword64)a[e+6]*s1t[e+6]);
|
|
tt[e+7] = dilithium_mont_red((sword64)a[e+7]*s1t[e+7]);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
tt[e] += dilithium_mont_red((sword64)a[e] * s1t[e]);
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
tt[e+0] += dilithium_mont_red((sword64)a[e+0]*s1t[e+0]);
|
|
tt[e+1] += dilithium_mont_red((sword64)a[e+1]*s1t[e+1]);
|
|
tt[e+2] += dilithium_mont_red((sword64)a[e+2]*s1t[e+2]);
|
|
tt[e+3] += dilithium_mont_red((sword64)a[e+3]*s1t[e+3]);
|
|
tt[e+4] += dilithium_mont_red((sword64)a[e+4]*s1t[e+4]);
|
|
tt[e+5] += dilithium_mont_red((sword64)a[e+5]*s1t[e+5]);
|
|
tt[e+6] += dilithium_mont_red((sword64)a[e+6]*s1t[e+6]);
|
|
tt[e+7] += dilithium_mont_red((sword64)a[e+7]*s1t[e+7]);
|
|
}
|
|
#endif
|
|
}
|
|
#else
|
|
if (s == 0) {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
t64[e] = (sword64)a[e] * s1t[e];
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
t64[e+0] = (sword64)a[e+0] * s1t[e+0];
|
|
t64[e+1] = (sword64)a[e+1] * s1t[e+1];
|
|
t64[e+2] = (sword64)a[e+2] * s1t[e+2];
|
|
t64[e+3] = (sword64)a[e+3] * s1t[e+3];
|
|
t64[e+4] = (sword64)a[e+4] * s1t[e+4];
|
|
t64[e+5] = (sword64)a[e+5] * s1t[e+5];
|
|
t64[e+6] = (sword64)a[e+6] * s1t[e+6];
|
|
t64[e+7] = (sword64)a[e+7] * s1t[e+7];
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
t64[e] += (sword64)a[e] * s1t[e];
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
t64[e+0] += (sword64)a[e+0] * s1t[e+0];
|
|
t64[e+1] += (sword64)a[e+1] * s1t[e+1];
|
|
t64[e+2] += (sword64)a[e+2] * s1t[e+2];
|
|
t64[e+3] += (sword64)a[e+3] * s1t[e+3];
|
|
t64[e+4] += (sword64)a[e+4] * s1t[e+4];
|
|
t64[e+5] += (sword64)a[e+5] * s1t[e+5];
|
|
t64[e+6] += (sword64)a[e+6] * s1t[e+6];
|
|
t64[e+7] += (sword64)a[e+7] * s1t[e+7];
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
/* Next polynomial. */
|
|
s1t += DILITHIUM_N;
|
|
}
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
tt[e] = dilithium_mont_red(t64[e]);
|
|
}
|
|
#endif
|
|
dilithium_invntt(tt);
|
|
dilithium_add(tt, s2t);
|
|
/* Make positive for decomposing. */
|
|
dilithium_make_pos(tt);
|
|
|
|
tt += DILITHIUM_N;
|
|
s2t += DILITHIUM_N;
|
|
}
|
|
|
|
/* Step 6, Step 7, Step 9. Alg 22 Steps 2-4, Alg 24 Steps 8-10.
|
|
* Decompose t in t0 and t1 and encode into public and private key.
|
|
*/
|
|
dilithium_vec_encode_t0_t1(t, params->k, t0, t1);
|
|
/* Step 8. Alg 24, Step 1: Hash public key into private key. */
|
|
ret = dilithium_shake256(&key->shake, key->p, params->pkSz, tr,
|
|
DILITHIUM_TR_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
/* Public key and private key are available. */
|
|
key->prvKeySet = 1;
|
|
key->pubKeySet = 1;
|
|
}
|
|
|
|
XFREE(s1, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
/* Make a key from a random seed.
|
|
*
|
|
* FIPS 204. 5.1: Algorithm 1 ML-DSA.KeyGen()
|
|
* 1: xi <- B32 [Choose random seed]
|
|
* 2: if xi = NULL then
|
|
* 3: return falsam
|
|
* 4: end if
|
|
* 5: return ML-DSA.KeyGen_internal(xi)
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] rng Random number generator.
|
|
* @return 0 on success.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_make_key(dilithium_key* key, WC_RNG* rng)
|
|
{
|
|
int ret;
|
|
byte seed[DILITHIUM_SEED_SZ];
|
|
|
|
/* Step 1: Generate a 32 byte random seed. */
|
|
ret = wc_RNG_GenerateBlock(rng, seed, DILITHIUM_SEED_SZ);
|
|
/* Step 2: Check for error. */
|
|
if (ret == 0) {
|
|
/* Step 5: Make key with random seed. */
|
|
ret = wc_dilithium_make_key_from_seed(key, seed);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_MAKE_KEY */
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_SIGN
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM) || \
|
|
defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC) || \
|
|
defined(WC_DILITHIUM_CACHE_PRIV_VECTORS)
|
|
/* Decode, from private key, and NTT private key vectors s1, s2, and t0.
|
|
*
|
|
* FIPS 204. 6: Algorithm 2 ML-DSA.Sign(sk, M)
|
|
* 1: (rho, K, tr, s1, s2, t0) <- skDecode(sk)
|
|
* 2: s1_circum <- NTT(s1)
|
|
* 3: s2_circum <- NTT(s2)
|
|
* 4: t0_circum <- NTT(t0)
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [out] s1 Vector of polynomials s1.
|
|
* @param [out] s2 Vector of polynomials s2.
|
|
* @param [out] t0 Vector of polynomials t0.
|
|
*/
|
|
static void dilithium_make_priv_vecs(dilithium_key* key, sword32* s1,
|
|
sword32* s2, sword32* t0)
|
|
{
|
|
const wc_dilithium_params* params = key->params;
|
|
const byte* pubSeed = key->k;
|
|
const byte* k = pubSeed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* tr = k + DILITHIUM_K_SZ;
|
|
const byte* s1p = tr + DILITHIUM_TR_SZ;
|
|
const byte* s2p = s1p + params->s1EncSz;
|
|
const byte* t0p = s2p + params->s2EncSz;
|
|
|
|
/* Step 1: Decode s1, s2, t0. */
|
|
dilithium_vec_decode_eta_bits(s1p, params->eta, s1, params->l);
|
|
dilithium_vec_decode_eta_bits(s2p, params->eta, s2, params->k);
|
|
dilithium_vec_decode_t0(t0p, params->k, t0);
|
|
|
|
/* Step 2: NTT s1. */
|
|
dilithium_vec_ntt_small(s1, params->l);
|
|
/* Step 3: NTT s2. */
|
|
dilithium_vec_ntt_small(s2, params->k);
|
|
/* Step 4: NTT t0. */
|
|
dilithium_vec_ntt(t0, params->k);
|
|
|
|
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
/* Private key vectors have been created. */
|
|
key->privVecsSet = 1;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/* Sign a message with the key and a seed.
|
|
*
|
|
* FIPS 204. 5.2: Algorithm 2 ML-DSA.sign(sk, M, ctx)
|
|
* ...
|
|
* 10: M' <- ByyesToBits(IntegerToBytes(0, 1) || IntegerToBytes(|ctx|, 1) ||
|
|
* ctx) || M
|
|
* ...
|
|
*
|
|
* FIPS 204. 6: Algorithm 2 ML-DSA.Sign(sk, M)
|
|
* 1: (rho, K, tr, s1, s2, t0) <- skDecode(sk)
|
|
* 2: s1_circum <- NTT(s1)
|
|
* 3: s2_circum <- NTT(s2)
|
|
* 4: t0_circum <- NTT(t0)
|
|
* 5: A_circum <- ExpandA(rho)
|
|
* 6: mu <- H(tr||M, 512)
|
|
* 7: rnd <- {0,1}256
|
|
* 8: rho' <- H(K||rnd||mu, 512)
|
|
* 9: kappa <- 0
|
|
* 10: (z, h) <- falsam
|
|
* 11: while (z, h) = falsam do
|
|
* 12: y <- ExpandMask(rho', kappa)
|
|
* 13: w <- NTT-1(A_circum o NTT(y))
|
|
* 14: w1 <- HighBits(w)
|
|
* 15: c_tilde E {0,1}2*lambda <- H(mu|w1Encode(w1), 2 * lambda)
|
|
* 16: (c1_tilde, c2_tilde) E {0,1}256 x {0,1}2*lambda-256 <- c_tilde
|
|
* 17: c < SampleInBall(c1_tilde)
|
|
* 18: c_circum <- NTT(c)
|
|
* 19: <<cs1>> <- NTT-1(c_circum o s1_circum)
|
|
* 20: <<cs2>> <- NTT-1(c_circum o s2_circum)
|
|
* 21: z <- y + <<cs1>>
|
|
* 22: r0 <- LowBits(w - <<cs2>>
|
|
* 23: if ||z||inf >= GAMMA1 - BETA or ||r0||inf GAMMA2 - BETA then
|
|
* (z, h) <- falsam
|
|
* 24: else
|
|
* 25: <<ct0>> <- NTT-1(c_circum o t0_circum)
|
|
* 26: h < MakeHint(-<<ct0>>, w - <<sc2>> + <<ct0>>)
|
|
* 27: if (||<<ct>>||inf >= GAMMMA1 or
|
|
* the number of 1's in h is greater than OMEGA, then
|
|
* (z, h) <- falsam
|
|
* 28: end if
|
|
* 29: end if
|
|
* 30: kappa <- kappa + l
|
|
* 31: end while
|
|
* 32: sigma <- sigEncode(c_tilde, z mod +/- q, h)
|
|
* 33: return sigma
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] seedMu Random seed || mu.
|
|
* @param [out] sig Buffer to hold signature.
|
|
* @param [in, out] sigLen On in, length of buffer in bytes.
|
|
* On out, the length of the signature in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when context length is greater than 255.
|
|
* @return BUFFER_E when the signature buffer is too small.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_sign_with_seed_mu(dilithium_key* key,
|
|
const byte* seedMu, byte* sig, word32 *sigLen)
|
|
{
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM
|
|
int ret = 0;
|
|
const wc_dilithium_params* params = key->params;
|
|
const byte* pub_seed = key->k;
|
|
const byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* mu = seedMu + DILITHIUM_RND_SZ;
|
|
sword32* a = NULL;
|
|
sword32* s1 = NULL;
|
|
sword32* s2 = NULL;
|
|
sword32* t0 = NULL;
|
|
sword32* y = NULL;
|
|
sword32* w0 = NULL;
|
|
sword32* w1 = NULL;
|
|
sword32* c = NULL;
|
|
sword32* z = NULL;
|
|
sword32* ct0 = NULL;
|
|
byte priv_rand_seed[DILITHIUM_Y_SEED_SZ];
|
|
byte* h = sig + params->lambda / 4 + params->zEncSz;
|
|
|
|
/* Check the signature buffer isn't too small. */
|
|
if (*sigLen < params->sigSz) {
|
|
ret = BUFFER_E;
|
|
}
|
|
if (ret == 0) {
|
|
/* Return the size of the signature. */
|
|
*sigLen = params->sigSz;
|
|
}
|
|
|
|
/* Allocate memory for large intermediates. */
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
if ((ret == 0) && (key->a == NULL)) {
|
|
a = (sword32*)XMALLOC(params->aSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (a == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
a = key->a;
|
|
}
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
if ((ret == 0) && (key->s1 == NULL)) {
|
|
key->s1 = (sword32*)XMALLOC(params->aSz, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->s1 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(key->s1, 0, params->aSz);
|
|
key->s2 = key->s1 + params->s1Sz / sizeof(*s1);
|
|
key->t0 = key->s2 + params->s2Sz / sizeof(*s2);
|
|
}
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
s1 = key->s1;
|
|
s2 = key->s2;
|
|
t0 = key->t0;
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
unsigned int allocSz;
|
|
|
|
/* y-l, w0-k, w1-k, c-1, z-l, ct0-k */
|
|
allocSz = params->s1Sz + params->s2Sz + params->s2Sz +
|
|
DILITHIUM_POLY_SIZE + params->s1Sz + params->s2Sz;
|
|
#ifndef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
/* s1-l, s2-k, t0-k */
|
|
allocSz += params->s1Sz + params->s2Sz + params->s2Sz;
|
|
#endif
|
|
#ifndef WC_DILITHIUM_CACHE_MATRIX_A
|
|
/* A */
|
|
allocSz += params->aSz;
|
|
#endif
|
|
y = (sword32*)XMALLOC(allocSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (y == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
w0 = y + params->s1Sz / sizeof(*y);
|
|
w1 = w0 + params->s2Sz / sizeof(*w0);
|
|
c = w1 + params->s2Sz / sizeof(*w1);
|
|
z = c + DILITHIUM_N;
|
|
ct0 = z + params->s1Sz / sizeof(*z);
|
|
#ifndef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
s1 = ct0 + params->s2Sz / sizeof(*ct0);
|
|
s2 = s1 + params->s1Sz / sizeof(*s1);
|
|
t0 = s2 + params->s2Sz / sizeof(*s2);
|
|
#endif
|
|
#ifndef WC_DILITHIUM_CACHE_MATRIX_A
|
|
a = t0 + params->s2Sz / sizeof(*s2);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
/* Check that we haven't already cached the private vectors. */
|
|
if (!key->privVecsSet)
|
|
#endif
|
|
{
|
|
/* Steps 1-4: Decode and NTT vectors s1, s2, and t0. */
|
|
dilithium_make_priv_vecs(key, s1, s2, t0);
|
|
}
|
|
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
/* Check that we haven't already cached the matrix A. */
|
|
if (!key->aSet)
|
|
#endif
|
|
{
|
|
/* Step 5: Create the matrix A from the public seed. */
|
|
ret = dilithium_expand_a(&key->shake, pub_seed, params->k,
|
|
params->l, a, key->heap);
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
key->aSet = (ret == 0);
|
|
#endif
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 9: Compute private random using hash. */
|
|
ret = dilithium_hash256(&key->shake, k, DILITHIUM_K_SZ, seedMu,
|
|
DILITHIUM_RND_SZ + DILITHIUM_MU_SZ, priv_rand_seed,
|
|
DILITHIUM_PRIV_RAND_SEED_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
word16 kappa = 0;
|
|
int valid = 0;
|
|
|
|
/* Step 11: Start rejection sampling loop */
|
|
do {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte *w1e = NULL;
|
|
#else
|
|
byte w1e[DILITHIUM_MAX_W1_ENC_SZ];
|
|
#endif
|
|
sword32* w = w1;
|
|
sword32* y_ntt = z;
|
|
sword32* cs2 = ct0;
|
|
byte* commit = sig;
|
|
|
|
/* Step 12: Compute vector y from private random seed and kappa. */
|
|
dilithium_vec_expand_mask(&key->shake, priv_rand_seed, kappa,
|
|
params->gamma1_bits, y, params->l);
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_CHECK_Y
|
|
valid = dilithium_vec_check_low(y, params->l,
|
|
(1 << params->gamma1_bits) - params->beta);
|
|
if (valid)
|
|
#endif
|
|
{
|
|
/* Step 13: NTT-1(A o NTT(y)) */
|
|
XMEMCPY(y_ntt, y, params->s1Sz);
|
|
dilithium_vec_ntt(y_ntt, params->l);
|
|
dilithium_matrix_mul(w, a, y_ntt, params->k, params->l);
|
|
dilithium_vec_invntt(w, params->k);
|
|
/* Step 14, Step 22: Make values positive and decompose. */
|
|
dilithium_vec_make_pos(w, params->k);
|
|
dilithium_vec_decompose(w, params->k, params->gamma2, w0, w1);
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_CHECK_W0
|
|
valid = dilithium_vec_check_low(w0, params->k,
|
|
params->gamma2 - params->beta);
|
|
}
|
|
if (valid) {
|
|
#endif
|
|
/* Step 15: Encode w1. */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
w1e = (byte *)XMALLOC(DILITHIUM_MAX_W1_ENC_SZ, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (w1e == NULL)
|
|
ret = MEMORY_E;
|
|
if (ret == 0)
|
|
#endif
|
|
{
|
|
dilithium_vec_encode_w1(w1, params->k, params->gamma2, w1e);
|
|
/* Step 15: Hash mu and encoded w1.
|
|
* Step 32: Hash is stored in signature. */
|
|
ret = dilithium_hash256(&key->shake, mu, DILITHIUM_MU_SZ,
|
|
w1e, params->w1EncSz, commit, params->lambda / 4);
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 17: Compute c from first 256 bits of commit. */
|
|
ret = dilithium_sample_in_ball(params->level, &key->shake,
|
|
commit, params->lambda / 4, params->tau, c, key->heap);
|
|
}
|
|
if (ret == 0) {
|
|
sword32 hi;
|
|
|
|
/* Step 18: NTT(c). */
|
|
dilithium_ntt_small(c);
|
|
/* Step 20: cs2 = NTT-1(c o s2) */
|
|
dilithium_vec_mul(cs2, c, s2, params->k);
|
|
dilithium_vec_invntt(cs2, params->k);
|
|
/* Step 22: w0 - cs2 */
|
|
dilithium_vec_sub(w0, cs2, params->k);
|
|
dilithium_vec_red(w0, params->k);
|
|
/* Step 23: Check w0 - cs2 has low enough values. */
|
|
hi = params->gamma2 - params->beta;
|
|
valid = dilithium_vec_check_low(w0, params->k, hi);
|
|
if (valid) {
|
|
/* Step 19: cs1 = NTT-1(c o s1) */
|
|
dilithium_vec_mul(z, c, s1, params->l);
|
|
dilithium_vec_invntt(z, params->l);
|
|
/* Step 21: z = y + cs1 */
|
|
dilithium_vec_add(z, y, params->l);
|
|
dilithium_vec_red(z, params->l);
|
|
/* Step 23: Check z has low enough values. */
|
|
hi = (1 << params->gamma1_bits) - params->beta;
|
|
valid = dilithium_vec_check_low(z, params->l, hi);
|
|
}
|
|
if (valid) {
|
|
/* Step 25: ct0 = NTT-1(c o t0) */
|
|
dilithium_vec_mul(ct0, c, t0, params->k);
|
|
dilithium_vec_invntt(ct0, params->k);
|
|
/* Step 27: Check ct0 has low enough values. */
|
|
hi = params->gamma2;
|
|
valid = dilithium_vec_check_low(ct0, params->k, hi);
|
|
}
|
|
if (valid) {
|
|
/* Step 26: ct0 = ct0 + w0 */
|
|
dilithium_vec_add(ct0, w0, params->k);
|
|
dilithium_vec_red(ct0, params->k);
|
|
/* Step 26, 27: Make hint from ct0 and w1 and check
|
|
* number of hints is valid.
|
|
* Step 32: h is encoded into signature.
|
|
*/
|
|
valid = (dilithium_make_hint(ct0, w1, params->k,
|
|
params->gamma2, params->omega, h) >= 0);
|
|
}
|
|
}
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(w1e, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
#endif
|
|
}
|
|
|
|
if (!valid) {
|
|
/* Too many attempts - something wrong with implementation. */
|
|
if ((kappa > (word16)(kappa + params->l))) {
|
|
ret = BAD_COND_E;
|
|
}
|
|
|
|
/* Step 30: increment value to append to seed to unique value.
|
|
*/
|
|
kappa += params->l;
|
|
}
|
|
}
|
|
/* Step 11: Check we have a valid signature. */
|
|
while ((ret == 0) && (!valid));
|
|
}
|
|
if (ret == 0) {
|
|
byte* ze = sig + params->lambda / 4;
|
|
/* Step 32: Encode z into signature.
|
|
* Commit (c) and h already encoded into signature. */
|
|
dilithium_vec_encode_gamma1(z, params->l, params->gamma1_bits, ze);
|
|
}
|
|
|
|
XFREE(y, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
return ret;
|
|
#else
|
|
int ret = 0;
|
|
const wc_dilithium_params* params = key->params;
|
|
const byte* pub_seed = key->k;
|
|
const byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* tr = k + DILITHIUM_K_SZ;
|
|
const byte* s1p = tr + DILITHIUM_TR_SZ;
|
|
const byte* s2p = s1p + params->s1EncSz;
|
|
const byte* t0p = s2p + params->s2EncSz;
|
|
const byte* mu = seedMu + DILITHIUM_RND_SZ;
|
|
sword32* a = NULL;
|
|
sword32* s1 = NULL;
|
|
sword32* s2 = NULL;
|
|
sword32* t0 = NULL;
|
|
sword32* y = NULL;
|
|
sword32* y_ntt = NULL;
|
|
sword32* w0 = NULL;
|
|
sword32* w1 = NULL;
|
|
sword32* c = NULL;
|
|
sword32* z = NULL;
|
|
sword32* ct0 = NULL;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
sword64* t64 = NULL;
|
|
#endif
|
|
byte* blocks = NULL;
|
|
byte priv_rand_seed[DILITHIUM_Y_SEED_SZ];
|
|
byte* h = sig + params->lambda / 4 + params->zEncSz;
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A
|
|
byte maxK = (byte)min(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A,
|
|
params->k);
|
|
#endif
|
|
|
|
/* Check the signature buffer isn't too small. */
|
|
if ((ret == 0) && (*sigLen < params->sigSz)) {
|
|
ret = BUFFER_E;
|
|
}
|
|
if (ret == 0) {
|
|
/* Return the size of the signature. */
|
|
*sigLen = params->sigSz;
|
|
}
|
|
|
|
/* Allocate memory for large intermediates. */
|
|
if (ret == 0) {
|
|
unsigned int allocSz;
|
|
|
|
/* y-l, w0-k, w1-k, blocks, c-1, z-1, A-1 */
|
|
allocSz = params->s1Sz + params->s2Sz + params->s2Sz +
|
|
DILITHIUM_REJ_NTT_POLY_H_SIZE +
|
|
DILITHIUM_POLY_SIZE + DILITHIUM_POLY_SIZE + DILITHIUM_POLY_SIZE;
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
|
|
allocSz += params->s1Sz + params->s2Sz + params->s2Sz;
|
|
#elif defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A)
|
|
allocSz += maxK * params->l * DILITHIUM_POLY_SIZE;
|
|
#endif
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
allocSz += DILITHIUM_POLY_SIZE * 2;
|
|
#endif
|
|
y = (sword32*)XMALLOC(allocSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (y == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
w0 = y + params->s1Sz / sizeof(*y_ntt);
|
|
w1 = w0 + params->s2Sz / sizeof(*w0);
|
|
blocks = (byte*)(w1 + params->s2Sz / sizeof(*w1));
|
|
c = (sword32*)(blocks + DILITHIUM_REJ_NTT_POLY_H_SIZE);
|
|
z = c + DILITHIUM_N;
|
|
a = z + DILITHIUM_N;
|
|
ct0 = z;
|
|
#if defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A)
|
|
y_ntt = w0;
|
|
s1 = z;
|
|
s2 = z;
|
|
t0 = z;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
t64 = (sword64*)(a + (1 + maxK * params->l) * DILITHIUM_N);
|
|
#endif
|
|
#elif defined(WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC)
|
|
y_ntt = z;
|
|
s1 = a + DILITHIUM_N;
|
|
s2 = s1 + params->s1Sz / sizeof(*s1);
|
|
t0 = s2 + params->s2Sz / sizeof(*s2);
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
t64 = (sword64*)(t0 + params->s2Sz / sizeof(*t0));
|
|
#endif
|
|
#else
|
|
y_ntt = z;
|
|
s1 = z;
|
|
s2 = z;
|
|
t0 = z;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
t64 = (sword64*)(a + DILITHIUM_N);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Step 9: Compute private random using hash. */
|
|
ret = dilithium_hash256(&key->shake, k, DILITHIUM_K_SZ, seedMu,
|
|
DILITHIUM_RND_SZ + DILITHIUM_MU_SZ, priv_rand_seed,
|
|
DILITHIUM_PRIV_RAND_SEED_SZ);
|
|
}
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
|
|
if (ret == 0) {
|
|
dilithium_make_priv_vecs(key, s1, s2, t0);
|
|
}
|
|
#endif
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A
|
|
if (ret == 0) {
|
|
/* Step 5: Create the matrix A from the public seed. */
|
|
ret = dilithium_expand_a(&key->shake, pub_seed, maxK, params->l, a,
|
|
key->heap);
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
word16 kappa = 0;
|
|
int valid;
|
|
|
|
/* Step 11: Start rejection sampling loop */
|
|
do {
|
|
byte aseed[DILITHIUM_GEN_A_SEED_SZ];
|
|
byte w1e[DILITHIUM_MAX_W1_ENC_SZ];
|
|
sword32* w = w1;
|
|
byte* commit = sig;
|
|
byte r;
|
|
byte s;
|
|
sword32 hi;
|
|
sword32* wt = w;
|
|
sword32* w0t = w0;
|
|
sword32* w1t = w1;
|
|
sword32* at = a;
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A
|
|
w0t += WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A * DILITHIUM_N;
|
|
w1t += WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A * DILITHIUM_N;
|
|
wt += WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A * DILITHIUM_N;
|
|
at += WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A * params->l *
|
|
DILITHIUM_N;
|
|
#endif
|
|
|
|
valid = 1;
|
|
/* Step 12: Compute vector y from private random seed and kappa. */
|
|
dilithium_vec_expand_mask(&key->shake, priv_rand_seed, kappa,
|
|
params->gamma1_bits, y, params->l);
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_CHECK_Y
|
|
valid = dilithium_vec_check_low(y, params->l,
|
|
(1 << params->gamma1_bits) - params->beta);
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A
|
|
/* Step 13: NTT-1(A o NTT(y)) */
|
|
XMEMCPY(y_ntt, y, params->s1Sz);
|
|
dilithium_vec_ntt(y_ntt, params->l);
|
|
dilithium_matrix_mul(w, a, y_ntt, maxK, params->l);
|
|
dilithium_vec_invntt(w, maxK);
|
|
/* Step 14, Step 22: Make values positive and decompose. */
|
|
dilithium_vec_make_pos(w, maxK);
|
|
dilithium_vec_decompose(w, maxK, params->gamma2, w0, w1);
|
|
#endif
|
|
/* Step 5: Create the matrix A from the public seed. */
|
|
/* Copy the seed into a buffer that has space for s and r. */
|
|
XMEMCPY(aseed, pub_seed, DILITHIUM_PUB_SEED_SZ);
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A
|
|
r = WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A;
|
|
#else
|
|
r = 0;
|
|
#endif
|
|
/* Alg 26. Step 1: Loop over first dimension of matrix. */
|
|
for (; (ret == 0) && valid && (r < params->k); r++) {
|
|
unsigned int e;
|
|
sword32* yt = y;
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A
|
|
sword32* y_ntt_t = z;
|
|
#else
|
|
sword32* y_ntt_t = y_ntt;
|
|
#endif
|
|
|
|
/* Put r/i into buffer to be hashed. */
|
|
aseed[DILITHIUM_PUB_SEED_SZ + 1] = r;
|
|
/* Alg 26. Step 2: Loop over second dimension of matrix. */
|
|
for (s = 0; (ret == 0) && (s < params->l); s++) {
|
|
/* Put s into buffer to be hashed. */
|
|
aseed[DILITHIUM_PUB_SEED_SZ + 0] = s;
|
|
/* Alg 26. Step 3: Create polynomial from hashing seed. */
|
|
ret = dilithium_rej_ntt_poly_ex(&key->shake, aseed, at,
|
|
blocks);
|
|
if (ret != 0) {
|
|
break;
|
|
}
|
|
XMEMCPY(y_ntt_t, yt, DILITHIUM_POLY_SIZE);
|
|
dilithium_ntt(y_ntt_t);
|
|
/* Matrix multiply. */
|
|
#ifndef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
if (s == 0) {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
wt[e] = dilithium_mont_red((sword64)at[e] *
|
|
y_ntt_t[e]);
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
wt[e + 0] = dilithium_mont_red((sword64)at[e + 0] *
|
|
y_ntt_t[e + 0]);
|
|
wt[e + 1] = dilithium_mont_red((sword64)at[e + 1] *
|
|
y_ntt_t[e + 1]);
|
|
wt[e + 2] = dilithium_mont_red((sword64)at[e + 2] *
|
|
y_ntt_t[e + 2]);
|
|
wt[e + 3] = dilithium_mont_red((sword64)at[e + 3] *
|
|
y_ntt_t[e + 3]);
|
|
wt[e + 4] = dilithium_mont_red((sword64)at[e + 4] *
|
|
y_ntt_t[e + 4]);
|
|
wt[e + 5] = dilithium_mont_red((sword64)at[e + 5] *
|
|
y_ntt_t[e + 5]);
|
|
wt[e + 6] = dilithium_mont_red((sword64)at[e + 6] *
|
|
y_ntt_t[e + 6]);
|
|
wt[e + 7] = dilithium_mont_red((sword64)at[e + 7] *
|
|
y_ntt_t[e + 7]);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
wt[e] += dilithium_mont_red((sword64)at[e] *
|
|
y_ntt_t[e]);
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
wt[e + 0] += dilithium_mont_red((sword64)at[e + 0] *
|
|
y_ntt_t[e + 0]);
|
|
wt[e + 1] += dilithium_mont_red((sword64)at[e + 1] *
|
|
y_ntt_t[e + 1]);
|
|
wt[e + 2] += dilithium_mont_red((sword64)at[e + 2] *
|
|
y_ntt_t[e + 2]);
|
|
wt[e + 3] += dilithium_mont_red((sword64)at[e + 3] *
|
|
y_ntt_t[e + 3]);
|
|
wt[e + 4] += dilithium_mont_red((sword64)at[e + 4] *
|
|
y_ntt_t[e + 4]);
|
|
wt[e + 5] += dilithium_mont_red((sword64)at[e + 5] *
|
|
y_ntt_t[e + 5]);
|
|
wt[e + 6] += dilithium_mont_red((sword64)at[e + 6] *
|
|
y_ntt_t[e + 6]);
|
|
wt[e + 7] += dilithium_mont_red((sword64)at[e + 7] *
|
|
y_ntt_t[e + 7]);
|
|
}
|
|
#endif
|
|
}
|
|
#else
|
|
if (s == 0) {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
t64[e] = (sword64)at[e] * y_ntt_t[e];
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
t64[e+0] = (sword64)at[e+0] * y_ntt_t[e+0];
|
|
t64[e+1] = (sword64)at[e+1] * y_ntt_t[e+1];
|
|
t64[e+2] = (sword64)at[e+2] * y_ntt_t[e+2];
|
|
t64[e+3] = (sword64)at[e+3] * y_ntt_t[e+3];
|
|
t64[e+4] = (sword64)at[e+4] * y_ntt_t[e+4];
|
|
t64[e+5] = (sword64)at[e+5] * y_ntt_t[e+5];
|
|
t64[e+6] = (sword64)at[e+6] * y_ntt_t[e+6];
|
|
t64[e+7] = (sword64)at[e+7] * y_ntt_t[e+7];
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
t64[e] += (sword64)at[e] * y_ntt_t[e];
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
t64[e+0] += (sword64)at[e+0] * y_ntt_t[e+0];
|
|
t64[e+1] += (sword64)at[e+1] * y_ntt_t[e+1];
|
|
t64[e+2] += (sword64)at[e+2] * y_ntt_t[e+2];
|
|
t64[e+3] += (sword64)at[e+3] * y_ntt_t[e+3];
|
|
t64[e+4] += (sword64)at[e+4] * y_ntt_t[e+4];
|
|
t64[e+5] += (sword64)at[e+5] * y_ntt_t[e+5];
|
|
t64[e+6] += (sword64)at[e+6] * y_ntt_t[e+6];
|
|
t64[e+7] += (sword64)at[e+7] * y_ntt_t[e+7];
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
/* Next polynomial. */
|
|
yt += DILITHIUM_N;
|
|
}
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
wt[e] = dilithium_mont_red(t64[e]);
|
|
}
|
|
#endif
|
|
dilithium_invntt(wt);
|
|
/* Step 14, Step 22: Make values positive and decompose. */
|
|
dilithium_make_pos(wt);
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (params->gamma2 == DILITHIUM_Q_LOW_88) {
|
|
/* For each value of polynomial. */
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
/* Decompose value into two vectors. */
|
|
dilithium_decompose_q88(wt[e], &w0t[e], &w1t[e]);
|
|
}
|
|
}
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (params->gamma2 == DILITHIUM_Q_LOW_32) {
|
|
/* For each value of polynomial. */
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
/* Decompose value into two vectors. */
|
|
dilithium_decompose_q32(wt[e], &w0t[e], &w1t[e]);
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef WOLFSSL_DILITHIUM_SIGN_CHECK_W0
|
|
valid = dilithium_vec_check_low(w0t,
|
|
params->gamma2 - params->beta);
|
|
#endif
|
|
wt += DILITHIUM_N;
|
|
w0t += DILITHIUM_N;
|
|
w1t += DILITHIUM_N;
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
sword32* yt = y;
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
|
|
const byte* s1pt = s1p;
|
|
#endif
|
|
byte* ze = sig + params->lambda / 4;
|
|
|
|
/* Step 15: Encode w1. */
|
|
dilithium_vec_encode_w1(w1, params->k, params->gamma2, w1e);
|
|
/* Step 15: Hash mu and encoded w1.
|
|
* Step 32: Hash is stored in signature. */
|
|
ret = dilithium_hash256(&key->shake, mu, DILITHIUM_MU_SZ,
|
|
w1e, params->w1EncSz, commit, params->lambda / 4);
|
|
if (ret == 0) {
|
|
/* Step 17: Compute c from first 256 bits of commit. */
|
|
ret = dilithium_sample_in_ball_ex(params->level,
|
|
&key->shake, commit, params->lambda / 4, params->tau, c,
|
|
blocks);
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 18: NTT(c). */
|
|
dilithium_ntt_small(c);
|
|
}
|
|
|
|
for (s = 0; (ret == 0) && valid && (s < params->l); s++) {
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44) || \
|
|
!defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* -2..2 */
|
|
if (params->eta == DILITHIUM_ETA_2) {
|
|
dilithium_decode_eta_2_bits(s1pt, s1);
|
|
s1pt += DILITHIUM_ETA_2_BITS * DILITHIUM_N / 8;
|
|
}
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
/* -4..4 */
|
|
if (params->eta == DILITHIUM_ETA_4) {
|
|
dilithium_decode_eta_4_bits(s1pt, s1);
|
|
s1pt += DILITHIUM_N / 2;
|
|
}
|
|
#endif
|
|
dilithium_ntt_small(s1);
|
|
dilithium_mul(z, c, s1);
|
|
#else
|
|
dilithium_mul(z, c, s1 + s * DILITHIUM_N);
|
|
#endif
|
|
/* Step 19: cs1 = NTT-1(c o s1) */
|
|
dilithium_invntt(z);
|
|
/* Step 21: z = y + cs1 */
|
|
dilithium_add(z, yt);
|
|
dilithium_poly_red(z);
|
|
/* Step 23: Check z has low enough values. */
|
|
hi = (1 << params->gamma1_bits) - params->beta;
|
|
valid = dilithium_check_low(z, hi);
|
|
if (valid) {
|
|
/* Step 32: Encode z into signature.
|
|
* Commit (c) and h already encoded into signature. */
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44)
|
|
if (params->gamma1_bits == DILITHIUM_GAMMA1_BITS_17) {
|
|
dilithium_encode_gamma1_17_bits(z, ze);
|
|
/* Move to next place to encode to. */
|
|
ze += DILITHIUM_GAMMA1_17_ENC_BITS / 2 *
|
|
DILITHIUM_N / 4;
|
|
}
|
|
else
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || \
|
|
!defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (params->gamma1_bits == DILITHIUM_GAMMA1_BITS_19) {
|
|
dilithium_encode_gamma1_19_bits(z, ze);
|
|
/* Move to next place to encode to. */
|
|
ze += DILITHIUM_GAMMA1_19_ENC_BITS / 2 *
|
|
DILITHIUM_N / 4;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
yt += DILITHIUM_N;
|
|
}
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
const byte* t0pt = t0p;
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
|
|
const byte* s2pt = s2p;
|
|
#endif
|
|
sword32* cs2 = ct0;
|
|
w0t = w0;
|
|
w1t = w1;
|
|
byte idx = 0;
|
|
|
|
for (r = 0; valid && (r < params->k); r++) {
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
|
|
#if !defined(WOLFSSL_NO_ML_DSA_44) || \
|
|
!defined(WOLFSSL_NO_ML_DSA_87)
|
|
/* -2..2 */
|
|
if (params->eta == DILITHIUM_ETA_2) {
|
|
dilithium_decode_eta_2_bits(s2pt, s2);
|
|
s2pt += DILITHIUM_ETA_2_BITS * DILITHIUM_N / 8;
|
|
}
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
/* -4..4 */
|
|
if (params->eta == DILITHIUM_ETA_4) {
|
|
dilithium_decode_eta_4_bits(s2pt, s2);
|
|
s2pt += DILITHIUM_N / 2;
|
|
}
|
|
#endif
|
|
dilithium_ntt_small(s2);
|
|
/* Step 20: cs2 = NTT-1(c o s2) */
|
|
dilithium_mul(cs2, c, s2);
|
|
#else
|
|
/* Step 20: cs2 = NTT-1(c o s2) */
|
|
dilithium_mul(cs2, c, s2 + r * DILITHIUM_N);
|
|
#endif
|
|
dilithium_invntt(cs2);
|
|
/* Step 22: w0 - cs2 */
|
|
dilithium_sub(w0t, cs2);
|
|
dilithium_poly_red(w0t);
|
|
/* Step 23: Check w0 - cs2 has low enough values. */
|
|
hi = params->gamma2 - params->beta;
|
|
valid = dilithium_check_low(w0t, hi);
|
|
if (valid) {
|
|
#ifndef WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC
|
|
dilithium_decode_t0(t0pt, t0);
|
|
dilithium_ntt(t0);
|
|
|
|
/* Step 25: ct0 = NTT-1(c o t0) */
|
|
dilithium_mul(ct0, c, t0);
|
|
#else
|
|
/* Step 25: ct0 = NTT-1(c o t0) */
|
|
dilithium_mul(ct0, c, t0 + r * DILITHIUM_N);
|
|
#endif
|
|
dilithium_invntt(ct0);
|
|
/* Step 27: Check ct0 has low enough values. */
|
|
valid = dilithium_check_low(ct0, params->gamma2);
|
|
}
|
|
if (valid) {
|
|
/* Step 26: ct0 = ct0 + w0 */
|
|
dilithium_add(ct0, w0t);
|
|
dilithium_poly_red(ct0);
|
|
|
|
/* Step 26, 27: Make hint from ct0 and w1 and check
|
|
* number of hints is valid.
|
|
* Step 32: h is encoded into signature.
|
|
*/
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (params->gamma2 == DILITHIUM_Q_LOW_88) {
|
|
valid = (dilithium_make_hint_88(ct0, w1t, h,
|
|
&idx) == 0);
|
|
/* Alg 14, Step 10: Store count of hints for
|
|
* polynomial at end of list. */
|
|
h[PARAMS_ML_DSA_44_OMEGA + r] = idx;
|
|
}
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || \
|
|
!defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (params->gamma2 == DILITHIUM_Q_LOW_32) {
|
|
valid = (dilithium_make_hint_32(ct0, w1t,
|
|
params->omega, h, &idx) == 0);
|
|
/* Alg 14, Step 10: Store count of hints for
|
|
* polynomial at end of list. */
|
|
h[params->omega + r] = idx;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
t0pt += DILITHIUM_D * DILITHIUM_N / 8;
|
|
w0t += DILITHIUM_N;
|
|
w1t += DILITHIUM_N;
|
|
}
|
|
/* Set remaining hints to zero. */
|
|
XMEMSET(h + idx, 0, params->omega - idx);
|
|
}
|
|
|
|
if (!valid) {
|
|
/* Too many attempts - something wrong with implementation. */
|
|
if ((kappa > (word16)(kappa + params->l))) {
|
|
ret = BAD_COND_E;
|
|
}
|
|
|
|
/* Step 30: increment value to append to seed to unique value.
|
|
*/
|
|
kappa += params->l;
|
|
}
|
|
}
|
|
/* Step 11: Check we have a valid signature. */
|
|
while ((ret == 0) && (!valid));
|
|
}
|
|
|
|
XFREE(y, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
/* Sign a message with the key and a seed.
|
|
*
|
|
* FIPS 204. 5.2: Algorithm 2 ML-DSA.Sign(sk, M, ctx)
|
|
* ...
|
|
* 10: M' <- BytesToBits(IntegerToBytes(0, 1) || IntegerToBytes(|ctx|, 1) ||
|
|
* ctx || M)
|
|
* 11: sigma <- ML-DSA.Sign_internal(sk, M', rnd)
|
|
* 12: return sigma
|
|
*
|
|
* FIPS 204. 6.2: Algorithm 7 ML-DSA.SignInternal(sk, M', rnd)
|
|
* ...
|
|
* 6: mu <- H(BytesToBits(tr)||M', 64)
|
|
* ...
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] seed Random seed.
|
|
* @param [in] ctx Context of signature.
|
|
* @param [in] ctxLen Length of context in bytes.
|
|
* @param [in] msg Message data to sign.
|
|
* @param [in] msgLen Length of message data in bytes.
|
|
* @param [out] sig Buffer to hold signature.
|
|
* @param [in, out] sigLen On in, length of buffer in bytes.
|
|
* On out, the length of the signature in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when context length is greater than 255.
|
|
* @return BUFFER_E when the signature buffer is too small.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_sign_ctx_msg_with_seed(dilithium_key* key,
|
|
const byte* seed, const byte* ctx, byte ctxLen, const byte* msg,
|
|
word32 msgLen, byte* sig, word32 *sigLen)
|
|
{
|
|
int ret;
|
|
const byte* pub_seed = key->k;
|
|
const byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* tr = k + DILITHIUM_K_SZ;
|
|
byte seedMu[DILITHIUM_RND_SZ + DILITHIUM_MU_SZ];
|
|
byte* mu = seedMu + DILITHIUM_RND_SZ;
|
|
|
|
XMEMCPY(seedMu, seed, DILITHIUM_RND_SZ);
|
|
/* Step 6. Calculate mu. */
|
|
ret = dilithium_hash256_ctx_msg(&key->shake, tr, DILITHIUM_TR_SZ, 0,
|
|
ctx, ctxLen, msg, msgLen, mu, DILITHIUM_MU_SZ);
|
|
if (ret == 0) {
|
|
ret = dilithium_sign_with_seed_mu(key, seedMu, sig, sigLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign a message with the key and a seed.
|
|
*
|
|
* FIPS 204. 5.2: Algorithm 2 ML-DSA.Sign(sk, M, ctx)
|
|
* ...
|
|
* 10: M' <- BytesToBits(IntegerToBytes(0, 1) || IntegerToBytes(|ctx|, 1) ||
|
|
* ctx || M)
|
|
* 11: sigma <- ML-DSA.Sign_internal(sk, M', rnd)
|
|
* 12: return sigma
|
|
*
|
|
* FIPS 204. 6.2: Algorithm 7 ML-DSA.SignInternal(sk, M', rnd)
|
|
* ...
|
|
* 6: mu <- H(BytesToBits(tr)||M', 64)
|
|
* ...
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] seed Random seed.
|
|
* @param [in] msg Message data to sign.
|
|
* @param [in] msgLen Length of message data in bytes.
|
|
* @param [out] sig Buffer to hold signature.
|
|
* @param [in, out] sigLen On in, length of buffer in bytes.
|
|
* On out, the length of the signature in bytes.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when context length is greater than 255.
|
|
* @return BUFFER_E when the signature buffer is too small.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_sign_msg_with_seed(dilithium_key* key, const byte* seed,
|
|
const byte* msg, word32 msgLen, byte* sig, word32 *sigLen)
|
|
{
|
|
int ret;
|
|
const byte* pub_seed = key->k;
|
|
const byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* tr = k + DILITHIUM_K_SZ;
|
|
byte seedMu[DILITHIUM_RND_SZ + DILITHIUM_MU_SZ];
|
|
byte* mu = seedMu + DILITHIUM_RND_SZ;
|
|
|
|
XMEMCPY(seedMu, seed, DILITHIUM_RND_SZ);
|
|
/* Step 6. Calculate mu. */
|
|
ret = dilithium_hash256(&key->shake, tr, DILITHIUM_TR_SZ, msg, msgLen, mu,
|
|
DILITHIUM_MU_SZ);
|
|
if (ret == 0) {
|
|
ret = dilithium_sign_with_seed_mu(key, seedMu, sig, sigLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign a message with the key and a random number generator.
|
|
*
|
|
* FIPS 204. 5.2: Algorithm 2 ML-DSA.Sign(sk, M, ctx)
|
|
* ...
|
|
* 5: rnd <- B32 [Randomly generated.]
|
|
* 6: if rnd = NULL then
|
|
* 7: return falsam
|
|
* 8: end if
|
|
* 9:
|
|
* 10: M' <- BytesToBits(IntegerToBytes(0, 1) || IntegerToBytes(|ctx|, 1) ||
|
|
* ctx || M)
|
|
* ...
|
|
*
|
|
* FIPS 204. 6.2: Algorithm 7 ML-DSA.SignInternal(sk, M', rnd)
|
|
* ...
|
|
* 6: mu <- H(BytesToBits(tr)||M', 64)
|
|
* ...
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in, out] rng Random number generator.
|
|
* @param [in] ctx Context of signature.
|
|
* @param [in] ctxLen Length of context.
|
|
* @param [in] msg Message data to sign.
|
|
* @param [in] msgLen Length of message data in bytes.
|
|
* @param [out] sig Buffer to hold signature.
|
|
* @param [in, out] sigLen On in, length of buffer in bytes.
|
|
* On out, the length of the signature in bytes.
|
|
* @return 0 on success.
|
|
* @return BUFFER_E when the signature buffer is too small.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_sign_ctx_msg(dilithium_key* key, WC_RNG* rng,
|
|
const byte* ctx, byte ctxLen, const byte* msg, word32 msgLen, byte* sig,
|
|
word32 *sigLen)
|
|
{
|
|
int ret = 0;
|
|
const byte* pub_seed = key->k;
|
|
const byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* tr = k + DILITHIUM_K_SZ;
|
|
byte seedMu[DILITHIUM_RND_SZ + DILITHIUM_MU_SZ];
|
|
byte* mu = seedMu + DILITHIUM_RND_SZ;
|
|
|
|
/* Must have a random number generator. */
|
|
if (rng == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Step 7: Generate random seed. */
|
|
ret = wc_RNG_GenerateBlock(rng, seedMu, DILITHIUM_RND_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 6. Calculate mu. */
|
|
ret = dilithium_hash256_ctx_msg(&key->shake, tr, DILITHIUM_TR_SZ, 0,
|
|
ctx, ctxLen, msg, msgLen, mu, DILITHIUM_MU_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_sign_with_seed_mu(key, seedMu, sig, sigLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign a message with the key and a random number generator.
|
|
*
|
|
* FIPS 204. 5.2: Algorithm 2 ML-DSA.Sign(sk, M, ctx)
|
|
* ...
|
|
* 5: rnd <- B32 [Randomly generated.]
|
|
* 6: if rnd = NULL then
|
|
* 7: return falsam
|
|
* 8: end if
|
|
* 9:
|
|
* 10: M' <- BytesToBits(IntegerToBytes(0, 1) || IntegerToBytes(|ctx|, 1) ||
|
|
* ctx || M)
|
|
* ...
|
|
*
|
|
* FIPS 204. 6.2: Algorithm 7 ML-DSA.SignInternal(sk, M', rnd)
|
|
* ...
|
|
* 6: mu <- H(BytesToBits(tr)||M', 64)
|
|
* ...
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in, out] rng Random number generator.
|
|
* @param [in] msg Message data to sign.
|
|
* @param [in] msgLen Length of message data in bytes.
|
|
* @param [out] sig Buffer to hold signature.
|
|
* @param [in, out] sigLen On in, length of buffer in bytes.
|
|
* On out, the length of the signature in bytes.
|
|
* @return 0 on success.
|
|
* @return BUFFER_E when the signature buffer is too small.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_sign_msg(dilithium_key* key, WC_RNG* rng,
|
|
const byte* msg, word32 msgLen, byte* sig, word32 *sigLen)
|
|
{
|
|
int ret = 0;
|
|
const byte* pub_seed = key->k;
|
|
const byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* tr = k + DILITHIUM_K_SZ;
|
|
byte seedMu[DILITHIUM_RND_SZ + DILITHIUM_MU_SZ];
|
|
byte* mu = seedMu + DILITHIUM_RND_SZ;
|
|
|
|
/* Must have a random number generator. */
|
|
if (rng == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Step 7: Generate random seed. */
|
|
ret = wc_RNG_GenerateBlock(rng, seedMu, DILITHIUM_RND_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 6. Calculate mu. */
|
|
ret = dilithium_hash256(&key->shake, tr, DILITHIUM_TR_SZ, msg, msgLen,
|
|
mu, DILITHIUM_MU_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_sign_with_seed_mu(key, seedMu, sig, sigLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign a pre-hashed message with the key and a seed.
|
|
*
|
|
* FIPS 204. 5.4.1: Algorithm 4 HashML-DSA.Sign(sk, M, ctx, PH)
|
|
* ...
|
|
* 10: switch PH do
|
|
* 11: case SHA-256:
|
|
* 12: OID <- IntegerToBytes(0x0609608648016503040201, 11)
|
|
* 13: PHm <- SHA256(M) (not done here as hash is passed in)
|
|
* ...
|
|
* 22: end switch
|
|
* 23: M' <- BytesToBits(IntegerToBytes(1, 1) || IntegerToBytes(|ctx|, 1) ||
|
|
* ctx || OID || PHm)
|
|
* 24: sigma <- ML-DSA.Sign_internal(sk, M', rnd)
|
|
* 25: return sigma
|
|
*
|
|
* FIPS 204. 6.2: Algorithm 7 ML-DSA.SignInternal(sk, M', rnd)
|
|
* ...
|
|
* 6: mu <- H(BytesToBits(tr)||M', 64)
|
|
* ...
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] seed Random seed.
|
|
* @param [in] ctx Context of signature.
|
|
* @param [in] ctxLen Length of context.
|
|
* @param [in] hashAlg Hash algorithm used on message.
|
|
* @param [in] hash Message hash to sign.
|
|
* @param [in] hashLen Length of message hash in bytes.
|
|
* @param [out] sig Buffer to hold signature.
|
|
* @param [in, out] sigLen On in, length of buffer in bytes.
|
|
* On out, the length of the signature in bytes.
|
|
* @return 0 on success.
|
|
* @return BUFFER_E when the signature buffer is too small.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_sign_ctx_hash_with_seed(dilithium_key* key,
|
|
const byte* seed, const byte* ctx, byte ctxLen, int hashAlg,
|
|
const byte* hash, word32 hashLen, byte* sig, word32 *sigLen)
|
|
{
|
|
int ret = 0;
|
|
const byte* pub_seed = key->k;
|
|
const byte* k = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* tr = k + DILITHIUM_K_SZ;
|
|
byte seedMu[DILITHIUM_RND_SZ + DILITHIUM_MU_SZ];
|
|
byte* mu = seedMu + DILITHIUM_RND_SZ;
|
|
byte oidMsgHash[DILITHIUM_HASH_OID_LEN + WC_MAX_DIGEST_SIZE];
|
|
word32 oidMsgHashLen = 0;
|
|
|
|
if ((ret == 0) && (hashLen > WC_MAX_DIGEST_SIZE)) {
|
|
ret = BUFFER_E;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
XMEMCPY(seedMu, seed, DILITHIUM_RND_SZ);
|
|
|
|
ret = dilithium_get_hash_oid(hashAlg, oidMsgHash, &oidMsgHashLen);
|
|
}
|
|
if (ret == 0) {
|
|
XMEMCPY(oidMsgHash + oidMsgHashLen, hash, hashLen);
|
|
oidMsgHashLen += hashLen;
|
|
|
|
/* Step 6. Calculate mu. */
|
|
ret = dilithium_hash256_ctx_msg(&key->shake, tr, DILITHIUM_TR_SZ, 1,
|
|
ctx, ctxLen, oidMsgHash, oidMsgHashLen, mu, DILITHIUM_MU_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_sign_with_seed_mu(key, seedMu, sig, sigLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign a pre-hashed message with the key and a random number generator.
|
|
*
|
|
* FIPS 204. 5.4.1: Algorithm 4 HashML-DSA.Sign(sk, M, ctx, PH)
|
|
* ...
|
|
* 5: rnd <- B32 [Randomly generated.]
|
|
* 6: if rnd = NULL then
|
|
* 7: return falsam
|
|
* 8: end if
|
|
* ...
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in, out] rng Random number generator.
|
|
* @param [in] ctx Context of signature.
|
|
* @param [in] ctxLen Length of context.
|
|
* @param [in] hashAlg Hash algorithm used on message.
|
|
* @param [in] hash Message hash to sign.
|
|
* @param [in] hashLen Length of message hash in bytes.
|
|
* @param [out] sig Buffer to hold signature.
|
|
* @param [in, out] sigLen On in, length of buffer in bytes.
|
|
* On out, the length of the signature in bytes.
|
|
* @return 0 on success.
|
|
* @return BUFFER_E when the signature buffer is too small.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_sign_ctx_hash(dilithium_key* key, WC_RNG* rng,
|
|
const byte* ctx, byte ctxLen, int hashAlg, const byte* hash, word32 hashLen,
|
|
byte* sig, word32 *sigLen)
|
|
{
|
|
int ret = 0;
|
|
byte seed[DILITHIUM_RND_SZ];
|
|
|
|
/* Must have a random number generator. */
|
|
if (rng == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 7: Generate random seed. */
|
|
ret = wc_RNG_GenerateBlock(rng, seed, DILITHIUM_RND_SZ);
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = dilithium_sign_ctx_hash_with_seed(key, seed, ctx, ctxLen, hashAlg,
|
|
hash, hashLen, sig, sigLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN */
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_VERIFY
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM) || \
|
|
defined(WC_DILITHIUM_CACHE_PUB_VECTORS)
|
|
/* Make public vector from public key data.
|
|
*
|
|
* @param [in, out] key Key with public key data.
|
|
* @param [out] t1 Vector in NTT form.
|
|
*/
|
|
static void dilithium_make_pub_vec(dilithium_key* key, sword32* t1)
|
|
{
|
|
const wc_dilithium_params* params = key->params;
|
|
const byte* t1p = key->p + DILITHIUM_PUB_SEED_SZ;
|
|
|
|
dilithium_vec_decode_t1(t1p, params->k, t1);
|
|
dilithium_vec_ntt(t1, params->k);
|
|
|
|
#ifdef WC_DILITHIUM_CACHE_PUB_VECTORS
|
|
key->pubVecSet = 1;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/* Verify signature of message using public key.
|
|
*
|
|
* FIPS 204. 6: Algorithm 3 ML-DSA.Verify(pk, M, sigma)
|
|
* 1: (rho, t1) <- pkDecode(pk)
|
|
* 2: (c_tilde, z, h) <- sigDecode(sigma)
|
|
* 3: if h = falsam then return false
|
|
* 4: end if
|
|
* 5: A_circum <- ExpandS(rho)
|
|
* 6: tr <- H(BytesToBits(pk), 512)
|
|
* 7: mu <- H(tr||M, 512)
|
|
* 8: (c1_tilde, c2_tilde) E {0,1}256 x {0,1)2*lambda-256 <- c_tilde
|
|
* 9: c <- SampleInBall(c1_tilde)
|
|
* 10: w'approx <- NTT-1(A_circum o NTT(z) - NTT(c) o NTT(t1.2^d))
|
|
* 11: w1' <- UseHint(h, w'approx)
|
|
* 12: c'_tilde < H(mu||w1Encode(w1'), 2*lambda)
|
|
* 13: return [[ ||z||inf < GAMMA1 - BETA]] and [[c_tilde = c'_tilde]] and
|
|
* [[number of 1's in h is <= OMEGA
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] mu Data to verify.
|
|
* @param [in] sig Signature to verify message.
|
|
* @param [in] sigLen Length of message in bytes.
|
|
* @param [out] res Result of verification.
|
|
* @return 0 on success.
|
|
* @return SIG_VERIFY_E when hint is malformed.
|
|
* @return BUFFER_E when the length of the signature does not match
|
|
* parameters.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_verify_mu(dilithium_key* key, const byte* mu,
|
|
const byte* sig, word32 sigLen, int* res)
|
|
{
|
|
#ifndef WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM
|
|
int ret = 0;
|
|
const wc_dilithium_params* params = key->params;
|
|
const byte* pub_seed = key->p;
|
|
const byte* commit = sig;
|
|
const byte* ze = sig + params->lambda / 4;
|
|
const byte* h = ze + params->zEncSz;
|
|
sword32* a = NULL;
|
|
sword32* t1 = NULL;
|
|
sword32* c = NULL;
|
|
sword32* z = NULL;
|
|
sword32* w = NULL;
|
|
sword32* t1c = NULL;
|
|
byte commit_calc[DILITHIUM_TR_SZ];
|
|
byte* w1e = NULL;
|
|
int valid = 0;
|
|
sword32 hi;
|
|
|
|
/* Ensure the signature is the right size for the parameters. */
|
|
if (sigLen != params->sigSz) {
|
|
ret = BUFFER_E;
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 13: Verify the hint is well-formed. */
|
|
ret = dilithium_check_hint(h, params->k, params->omega);
|
|
}
|
|
|
|
/* Allocate memory for large intermediates. */
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
if ((ret == 0) && (key->a == NULL)) {
|
|
key->a = (sword32*)XMALLOC(params->aSz, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->a == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(key->a, 0, params->aSz);
|
|
}
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
a = key->a;
|
|
}
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PUB_VECTORS
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
if ((ret == 0) && (key->t1 == NULL)) {
|
|
key->t1 = (sword32*)XMALLOC(params->s2Sz, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->t1 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(key->t1, 0, params->s2Sz);
|
|
}
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
t1 = key->t1;
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
unsigned int allocSz;
|
|
|
|
/* z, c, w, t1/t1c */
|
|
allocSz = DILITHIUM_POLY_SIZE + params->s1Sz + params->s2Sz +
|
|
params->s2Sz;
|
|
#ifndef WC_DILITHIUM_CACHE_MATRIX_A
|
|
/* a */
|
|
allocSz += params->aSz;
|
|
#endif
|
|
|
|
z = (sword32*)XMALLOC(allocSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (z == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(z, 0, allocSz);
|
|
c = z + params->s1Sz / sizeof(*z);
|
|
w = c + DILITHIUM_N;
|
|
#ifndef WC_DILITHIUM_CACHE_PUB_VECTORS
|
|
t1 = w + params->s2Sz / sizeof(*w);
|
|
t1c = t1;
|
|
#else
|
|
t1c = w + params->s2Sz / sizeof(*w);
|
|
#endif
|
|
#ifndef WC_DILITHIUM_CACHE_MATRIX_A
|
|
a = t1 + params->s2Sz / sizeof(*t1);
|
|
#endif
|
|
w1e = (byte*)c;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Step 2: Decode z from signature. */
|
|
dilithium_vec_decode_gamma1(ze, params->l, params->gamma1_bits, z);
|
|
/* Step 13: Check z is valid - values are low enough. */
|
|
hi = (1 << params->gamma1_bits) - params->beta;
|
|
valid = dilithium_vec_check_low(z, params->l, hi);
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
#ifdef WC_DILITHIUM_CACHE_PUB_VECTORS
|
|
/* Check that we haven't already cached the public vector. */
|
|
if (!key->pubVecSet)
|
|
#endif
|
|
{
|
|
/* Step 1: Decode and NTT vector t1. */
|
|
dilithium_make_pub_vec(key, t1);
|
|
}
|
|
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
/* Check that we haven't already cached the matrix A. */
|
|
if (!key->aSet)
|
|
#endif
|
|
{
|
|
/* Step 5: Expand pub seed to compute matrix A. */
|
|
ret = dilithium_expand_a(&key->shake, pub_seed, params->k,
|
|
params->l, a, key->heap);
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
/* Whether we have cached A is dependent on success of operation. */
|
|
key->aSet = (ret == 0);
|
|
#endif
|
|
}
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
/* Step 9: Compute c from commit. */
|
|
ret = dilithium_sample_in_ball(params->level, &key->shake, commit,
|
|
params->lambda / 4, params->tau, c, key->heap);
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
/* Step 10: w = NTT-1(A o NTT(z) - NTT(c) o NTT(t1)) */
|
|
dilithium_vec_ntt(z, params->l);
|
|
dilithium_matrix_mul(w, a, z, params->k, params->l);
|
|
dilithium_ntt_small(c);
|
|
dilithium_vec_mul(t1c, c, t1, params->k);
|
|
dilithium_vec_sub(w, t1c, params->k);
|
|
dilithium_vec_invntt(w, params->k);
|
|
/* Step 11: Use hint to give full w1. */
|
|
dilithium_vec_use_hint(w, params->k, params->gamma2, params->omega, h);
|
|
/* Step 12: Encode w1. */
|
|
dilithium_vec_encode_w1(w, params->k, params->gamma2, w1e);
|
|
/* Step 12: Hash mu and encoded w1. */
|
|
ret = dilithium_hash256(&key->shake, mu, DILITHIUM_MU_SZ, w1e,
|
|
params->w1EncSz, commit_calc, params->lambda / 4);
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
/* Step 13: Compare commit. */
|
|
valid = (XMEMCMP(commit, commit_calc, params->lambda / 4) == 0);
|
|
}
|
|
|
|
*res = valid;
|
|
XFREE(z, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
return ret;
|
|
#else
|
|
int ret = 0;
|
|
const wc_dilithium_params* params = key->params;
|
|
const byte* pub_seed = key->p;
|
|
const byte* t1p = pub_seed + DILITHIUM_PUB_SEED_SZ;
|
|
const byte* commit = sig;
|
|
const byte* ze = sig + params->lambda / 4;
|
|
const byte* h = ze + params->zEncSz;
|
|
sword32* t1 = NULL;
|
|
sword32* a = NULL;
|
|
sword32* c = NULL;
|
|
sword32* z = NULL;
|
|
sword32* w = NULL;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
sword64* t64 = NULL;
|
|
#endif
|
|
#ifndef WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC
|
|
byte* block = NULL;
|
|
#endif
|
|
byte* w1e = NULL;
|
|
byte commit_calc[DILITHIUM_TR_SZ];
|
|
int valid = 0;
|
|
sword32 hi;
|
|
unsigned int r;
|
|
byte o;
|
|
byte* encW1;
|
|
byte* seed = commit_calc;
|
|
|
|
/* Ensure the signature is the right size for the parameters. */
|
|
if (sigLen != params->sigSz) {
|
|
ret = BUFFER_E;
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 13: Verify the hint is well-formed. */
|
|
ret = dilithium_check_hint(h, params->k, params->omega);
|
|
}
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC
|
|
/* Allocate memory for large intermediates. */
|
|
if (ret == 0) {
|
|
/* z, c, w, t1, w1e. */
|
|
unsigned int allocSz;
|
|
|
|
allocSz = params->s1Sz + 3 * DILITHIUM_POLY_SIZE +
|
|
DILITHIUM_REJ_NTT_POLY_H_SIZE + params->w1EncSz;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
allocSz += DILITHIUM_POLY_SIZE * 2;
|
|
#endif
|
|
z = (sword32*)XMALLOC(allocSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (z == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(z, 0, allocSz);
|
|
c = z + params->s1Sz / sizeof(*t1);
|
|
w = c + DILITHIUM_N;
|
|
t1 = w + DILITHIUM_N;
|
|
block = (byte*)(t1 + DILITHIUM_N);
|
|
w1e = block + DILITHIUM_REJ_NTT_POLY_H_SIZE;
|
|
a = t1;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
t64 = (sword64*)(w1e + params->w1EncSz);
|
|
#endif
|
|
}
|
|
}
|
|
#else
|
|
if (ret == 0) {
|
|
z = key->z;
|
|
c = key->c;
|
|
w = key->w;
|
|
t1 = key->t1;
|
|
w1e = key->w1e;
|
|
a = t1;
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
t64 = key->t64;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
/* Step 2: Decode z from signature. */
|
|
dilithium_vec_decode_gamma1(ze, params->l, params->gamma1_bits, z);
|
|
/* Step 13: Check z is valid - values are low enough. */
|
|
hi = (1 << params->gamma1_bits) - params->beta;
|
|
valid = dilithium_vec_check_low(z, params->l, hi);
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
/* Step 10: NTT(z) */
|
|
dilithium_vec_ntt(z, params->l);
|
|
|
|
/* Step 9: Compute c from first 256 bits of commit. */
|
|
#ifdef WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC
|
|
ret = dilithium_sample_in_ball_ex(params->level, &key->shake, commit,
|
|
params->lambda / 4, params->tau, c, key->block);
|
|
#else
|
|
ret = dilithium_sample_in_ball_ex(params->level, &key->shake, commit,
|
|
params->lambda / 4, params->tau, c, block);
|
|
#endif
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
dilithium_ntt_small(c);
|
|
|
|
o = 0;
|
|
encW1 = w1e;
|
|
|
|
/* Copy the seed into a buffer that has space for s and r. */
|
|
XMEMCPY(seed, pub_seed, DILITHIUM_PUB_SEED_SZ);
|
|
/* Step 1: Loop over first dimension of matrix. */
|
|
for (r = 0; (ret == 0) && (r < params->k); r++) {
|
|
unsigned int s;
|
|
unsigned int e;
|
|
const sword32* zt = z;
|
|
|
|
/* Step 1: Decode and NTT vector t1. */
|
|
dilithium_decode_t1(t1p, w);
|
|
/* Next polynomial. */
|
|
t1p += DILITHIUM_U * DILITHIUM_N / 8;
|
|
|
|
/* Step 10: - NTT(c) o NTT(t1)) */
|
|
dilithium_ntt(w);
|
|
#ifndef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
w[e] = -dilithium_mont_red((sword64)c[e] * w[e]);
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
w[e+0] = -dilithium_mont_red((sword64)c[e+0] * w[e+0]);
|
|
w[e+1] = -dilithium_mont_red((sword64)c[e+1] * w[e+1]);
|
|
w[e+2] = -dilithium_mont_red((sword64)c[e+2] * w[e+2]);
|
|
w[e+3] = -dilithium_mont_red((sword64)c[e+3] * w[e+3]);
|
|
w[e+4] = -dilithium_mont_red((sword64)c[e+4] * w[e+4]);
|
|
w[e+5] = -dilithium_mont_red((sword64)c[e+5] * w[e+5]);
|
|
w[e+6] = -dilithium_mont_red((sword64)c[e+6] * w[e+6]);
|
|
w[e+7] = -dilithium_mont_red((sword64)c[e+7] * w[e+7]);
|
|
}
|
|
#endif
|
|
#else
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
t64[e] = -(sword64)c[e] * w[e];
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
t64[e+0] = -(sword64)c[e+0] * w[e+0];
|
|
t64[e+1] = -(sword64)c[e+1] * w[e+1];
|
|
t64[e+2] = -(sword64)c[e+2] * w[e+2];
|
|
t64[e+3] = -(sword64)c[e+3] * w[e+3];
|
|
t64[e+4] = -(sword64)c[e+4] * w[e+4];
|
|
t64[e+5] = -(sword64)c[e+5] * w[e+5];
|
|
t64[e+6] = -(sword64)c[e+6] * w[e+6];
|
|
t64[e+7] = -(sword64)c[e+7] * w[e+7];
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/* Step 5: Expand pub seed to compute matrix A. */
|
|
/* Put r into buffer to be hashed. */
|
|
seed[DILITHIUM_PUB_SEED_SZ + 1] = r;
|
|
for (s = 0; (ret == 0) && (s < params->l); s++) {
|
|
/* Put s into buffer to be hashed. */
|
|
seed[DILITHIUM_PUB_SEED_SZ + 0] = s;
|
|
/* Step 3: Create polynomial from hashing seed. */
|
|
#ifdef WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC
|
|
ret = dilithium_rej_ntt_poly_ex(&key->shake, seed, a, key->h);
|
|
#else
|
|
ret = dilithium_rej_ntt_poly_ex(&key->shake, seed, a, block);
|
|
#endif
|
|
|
|
/* Step 10: w = A o NTT(z) - NTT(c) o NTT(t1) */
|
|
#ifndef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
w[e] += dilithium_mont_red((sword64)a[e] * zt[e]);
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
w[e+0] += dilithium_mont_red((sword64)a[e+0] * zt[e+0]);
|
|
w[e+1] += dilithium_mont_red((sword64)a[e+1] * zt[e+1]);
|
|
w[e+2] += dilithium_mont_red((sword64)a[e+2] * zt[e+2]);
|
|
w[e+3] += dilithium_mont_red((sword64)a[e+3] * zt[e+3]);
|
|
w[e+4] += dilithium_mont_red((sword64)a[e+4] * zt[e+4]);
|
|
w[e+5] += dilithium_mont_red((sword64)a[e+5] * zt[e+5]);
|
|
w[e+6] += dilithium_mont_red((sword64)a[e+6] * zt[e+6]);
|
|
w[e+7] += dilithium_mont_red((sword64)a[e+7] * zt[e+7]);
|
|
}
|
|
#endif
|
|
#else
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
t64[e] += (sword64)a[e] * zt[e];
|
|
}
|
|
#else
|
|
for (e = 0; e < DILITHIUM_N; e += 8) {
|
|
t64[e+0] += (sword64)a[e+0] * zt[e+0];
|
|
t64[e+1] += (sword64)a[e+1] * zt[e+1];
|
|
t64[e+2] += (sword64)a[e+2] * zt[e+2];
|
|
t64[e+3] += (sword64)a[e+3] * zt[e+3];
|
|
t64[e+4] += (sword64)a[e+4] * zt[e+4];
|
|
t64[e+5] += (sword64)a[e+5] * zt[e+5];
|
|
t64[e+6] += (sword64)a[e+6] * zt[e+6];
|
|
t64[e+7] += (sword64)a[e+7] * zt[e+7];
|
|
}
|
|
#endif
|
|
#endif
|
|
/* Next polynomial. */
|
|
zt += DILITHIUM_N;
|
|
}
|
|
#ifdef WOLFSSL_DILITHIUM_SMALL_MEM_POLY64
|
|
for (e = 0; e < DILITHIUM_N; e++) {
|
|
w[e] = dilithium_mont_red(t64[e]);
|
|
}
|
|
#endif
|
|
|
|
/* Step 10: w = NTT-1(A o NTT(z) - NTT(c) o NTT(t1)) */
|
|
dilithium_invntt(w);
|
|
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (params->gamma2 == DILITHIUM_Q_LOW_88) {
|
|
/* Step 11: Use hint to give full w1. */
|
|
dilithium_use_hint_88(w, h, r, &o);
|
|
/* Step 12: Encode w1. */
|
|
dilithium_encode_w1_88(w, encW1);
|
|
encW1 += DILITHIUM_Q_HI_88_ENC_BITS * 2 * DILITHIUM_N / 16;
|
|
}
|
|
else
|
|
#endif
|
|
#if !defined(WOLFSSL_NO_ML_DSA_65) || !defined(WOLFSSL_NO_ML_DSA_87)
|
|
if (params->gamma2 == DILITHIUM_Q_LOW_32) {
|
|
/* Step 11: Use hint to give full w1. */
|
|
dilithium_use_hint_32(w, h, params->omega, r, &o);
|
|
/* Step 12: Encode w1. */
|
|
dilithium_encode_w1_32(w, encW1);
|
|
encW1 += DILITHIUM_Q_HI_32_ENC_BITS * 2 * DILITHIUM_N / 16;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
}
|
|
}
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
/* Step 12: Hash mu and encoded w1. */
|
|
ret = dilithium_hash256(&key->shake, mu, DILITHIUM_MU_SZ, w1e,
|
|
params->w1EncSz, commit_calc, params->lambda / 4);
|
|
}
|
|
if ((ret == 0) && valid) {
|
|
/* Step 13: Compare commit. */
|
|
valid = (XMEMCMP(commit, commit_calc, params->lambda / 4) == 0);
|
|
}
|
|
|
|
*res = valid;
|
|
#ifndef WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC
|
|
XFREE(z, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
#endif
|
|
return ret;
|
|
#endif /* !WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM */
|
|
}
|
|
|
|
/* Verify signature of message using public key.
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] ctx Context of verification.
|
|
* @param [in] ctxLen Length of context in bytes.
|
|
* @param [in] msg Message to verify.
|
|
* @param [in] msgLen Length of message in bytes.
|
|
* @param [in] sig Signature to verify message.
|
|
* @param [in] sigLen Length of message in bytes.
|
|
* @param [out] res Result of verification.
|
|
* @return 0 on success.
|
|
* @return SIG_VERIFY_E when hint is malformed.
|
|
* @return BUFFER_E when the length of the signature does not match
|
|
* parameters.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_verify_ctx_msg(dilithium_key* key, const byte* ctx,
|
|
word32 ctxLen, const byte* msg, word32 msgLen, const byte* sig,
|
|
word32 sigLen, int* res)
|
|
{
|
|
int ret = 0;
|
|
byte tr[DILITHIUM_TR_SZ];
|
|
byte* mu = tr;
|
|
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Step 6: Hash public key. */
|
|
ret = dilithium_shake256(&key->shake, key->p, key->params->pkSz, tr,
|
|
DILITHIUM_TR_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 6. Calculate mu. */
|
|
ret = dilithium_hash256_ctx_msg(&key->shake, tr, DILITHIUM_TR_SZ, 0,
|
|
ctx, (byte)ctxLen, msg, msgLen, mu, DILITHIUM_MU_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_verify_mu(key, mu, sig, sigLen, res);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Verify signature of message using public key.
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] msg Message to verify.
|
|
* @param [in] msgLen Length of message in bytes.
|
|
* @param [in] sig Signature to verify message.
|
|
* @param [in] sigLen Length of message in bytes.
|
|
* @param [out] res Result of verification.
|
|
* @return 0 on success.
|
|
* @return SIG_VERIFY_E when hint is malformed.
|
|
* @return BUFFER_E when the length of the signature does not match
|
|
* parameters.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_verify_msg(dilithium_key* key, const byte* msg,
|
|
word32 msgLen, const byte* sig, word32 sigLen, int* res)
|
|
{
|
|
int ret = 0;
|
|
byte tr[DILITHIUM_TR_SZ];
|
|
byte* mu = tr;
|
|
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Step 6: Hash public key. */
|
|
ret = dilithium_shake256(&key->shake, key->p, key->params->pkSz, tr,
|
|
DILITHIUM_TR_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
/* Step 6. Calculate mu. */
|
|
ret = dilithium_hash256(&key->shake, tr, DILITHIUM_TR_SZ, msg, msgLen,
|
|
mu, DILITHIUM_MU_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_verify_mu(key, mu, sig, sigLen, res);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Verify signature of message using public key.
|
|
*
|
|
* @param [in, out] key Dilithium key.
|
|
* @param [in] ctx Context of verification.
|
|
* @param [in] ctxLen Length of context in bytes.
|
|
* @param [iu] hashAlg Hash algorithm used on message.
|
|
* @param [in] hash Hash of message to verify.
|
|
* @param [in] hashLen Length of message hash in bytes.
|
|
* @param [in] sig Signature to verify message.
|
|
* @param [in] sigLen Length of message in bytes.
|
|
* @param [out] res Result of verification.
|
|
* @return 0 on success.
|
|
* @return SIG_VERIFY_E when hint is malformed.
|
|
* @return BUFFER_E when the length of the signature does not match
|
|
* parameters.
|
|
* @return MEMORY_E when memory allocation fails.
|
|
* @return Other negative when an error occurs.
|
|
*/
|
|
static int dilithium_verify_ctx_hash(dilithium_key* key, const byte* ctx,
|
|
word32 ctxLen, int hashAlg, const byte* hash, word32 hashLen,
|
|
const byte* sig, word32 sigLen, int* res)
|
|
{
|
|
int ret = 0;
|
|
byte tr[DILITHIUM_TR_SZ];
|
|
byte* mu = tr;
|
|
byte oidMsgHash[DILITHIUM_HASH_OID_LEN + WC_MAX_DIGEST_SIZE];
|
|
word32 oidMsgHashLen = 0;
|
|
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Step 6: Hash public key. */
|
|
ret = dilithium_shake256(&key->shake, key->p, key->params->pkSz, tr,
|
|
DILITHIUM_TR_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_get_hash_oid(hashAlg, oidMsgHash, &oidMsgHashLen);
|
|
}
|
|
if (ret == 0) {
|
|
XMEMCPY(oidMsgHash + oidMsgHashLen, hash, hashLen);
|
|
oidMsgHashLen += hashLen;
|
|
|
|
/* Step 6. Calculate mu. */
|
|
ret = dilithium_hash256_ctx_msg(&key->shake, tr, DILITHIUM_TR_SZ, 1,
|
|
ctx, (byte)ctxLen, oidMsgHash, oidMsgHashLen, mu, DILITHIUM_MU_SZ);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_verify_mu(key, mu, sig, sigLen, res);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_NO_VERIFY */
|
|
|
|
#elif defined(HAVE_LIBOQS)
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY
|
|
static int oqs_dilithium_make_key(dilithium_key* key, WC_RNG* rng)
|
|
{
|
|
int ret = 0;
|
|
OQS_SIG *oqssig = NULL;
|
|
|
|
if (key->level == WC_ML_DSA_44) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_44_ipd);
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_65_ipd);
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_87_ipd);
|
|
}
|
|
else {
|
|
ret = SIG_TYPE_E;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wolfSSL_liboqsRngMutexLock(rng);
|
|
if (ret == 0) {
|
|
if (OQS_SIG_keypair(oqssig, key->p, key->k) != OQS_SUCCESS) {
|
|
ret = BUFFER_E;
|
|
}
|
|
}
|
|
wolfSSL_liboqsRngMutexUnlock();
|
|
}
|
|
if (ret == 0) {
|
|
key->prvKeySet = 1;
|
|
key->pubKeySet = 1;
|
|
}
|
|
|
|
if (oqssig != NULL) {
|
|
OQS_SIG_free(oqssig);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_NO_MAKE_KEY */
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_SIGN
|
|
static int oqs_dilithium_sign_msg(const byte* msg, word32 msgLen, byte* sig,
|
|
word32 *sigLen, dilithium_key* key, WC_RNG* rng)
|
|
{
|
|
int ret = 0;
|
|
OQS_SIG *oqssig = NULL;
|
|
size_t localOutLen = 0;
|
|
|
|
if (!key->prvKeySet) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
if (key->level == WC_ML_DSA_44) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_44_ipd);
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_65_ipd);
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_87_ipd);
|
|
}
|
|
else {
|
|
ret = SIG_TYPE_E;
|
|
}
|
|
}
|
|
|
|
if ((ret == 0) && (oqssig == NULL)) {
|
|
ret = BUFFER_E;
|
|
}
|
|
|
|
/* check and set up out length */
|
|
if (ret == 0) {
|
|
if ((key->level == WC_ML_DSA_44) &&
|
|
(*sigLen < ML_DSA_LEVEL2_SIG_SIZE)) {
|
|
*sigLen = ML_DSA_LEVEL2_SIG_SIZE;
|
|
ret = BUFFER_E;
|
|
}
|
|
else if ((key->level == WC_ML_DSA_65) &&
|
|
(*sigLen < ML_DSA_LEVEL3_SIG_SIZE)) {
|
|
*sigLen = ML_DSA_LEVEL3_SIG_SIZE;
|
|
ret = BUFFER_E;
|
|
}
|
|
else if ((key->level == WC_ML_DSA_87) &&
|
|
(*sigLen < ML_DSA_LEVEL5_SIG_SIZE)) {
|
|
*sigLen = ML_DSA_LEVEL5_SIG_SIZE;
|
|
ret = BUFFER_E;
|
|
}
|
|
localOutLen = *sigLen;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wolfSSL_liboqsRngMutexLock(rng);
|
|
}
|
|
|
|
if ((ret == 0) &&
|
|
(OQS_SIG_sign(oqssig, sig, &localOutLen, msg, msgLen, key->k)
|
|
== OQS_ERROR)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
*sigLen = (word32)localOutLen;
|
|
}
|
|
|
|
wolfSSL_liboqsRngMutexUnlock();
|
|
|
|
if (oqssig != NULL) {
|
|
OQS_SIG_free(oqssig);
|
|
}
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_VERIFY
|
|
static int oqs_dilithium_verify_msg(const byte* sig, word32 sigLen,
|
|
const byte* msg, word32 msgLen, int* res, dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
OQS_SIG *oqssig = NULL;
|
|
|
|
if (!key->pubKeySet) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
if (key->level == WC_ML_DSA_44) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_44_ipd);
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_65_ipd);
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_87_ipd);
|
|
}
|
|
else {
|
|
ret = SIG_TYPE_E;
|
|
}
|
|
}
|
|
|
|
if ((ret == 0) && (oqssig == NULL)) {
|
|
ret = BUFFER_E;
|
|
}
|
|
|
|
if ((ret == 0) &&
|
|
(OQS_SIG_verify(oqssig, msg, msgLen, sig, sigLen, key->p)
|
|
== OQS_ERROR)) {
|
|
ret = SIG_VERIFY_E;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
*res = 1;
|
|
}
|
|
|
|
if (oqssig != NULL) {
|
|
OQS_SIG_free(oqssig);
|
|
}
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_NO_VERIFY */
|
|
|
|
#else
|
|
#error "No dilithium implementation chosen."
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY
|
|
int wc_dilithium_make_key(dilithium_key* key, WC_RNG* rng)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((key == NULL) || (rng == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
#ifdef WOLF_CRYPTO_CB
|
|
if (ret == 0) {
|
|
#ifndef WOLF_CRYPTO_CB_FIND
|
|
if (key->devId != INVALID_DEVID)
|
|
#endif
|
|
{
|
|
ret = wc_CryptoCb_MakePqcSignatureKey(rng,
|
|
WC_PQC_SIG_TYPE_DILITHIUM, key->level, key);
|
|
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
|
return ret;
|
|
/* fall-through when unavailable */
|
|
ret = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
/* Check the level or parameters have been set. */
|
|
if (key->params == NULL) {
|
|
ret = BAD_STATE_E;
|
|
}
|
|
else {
|
|
/* Make the key. */
|
|
ret = dilithium_make_key(key, rng);
|
|
}
|
|
#elif defined(HAVE_LIBOQS)
|
|
/* Make the key. */
|
|
ret = oqs_dilithium_make_key(key, rng);
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wc_dilithium_make_key_from_seed(dilithium_key* key, const byte* seed)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((key == NULL) || (seed == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
/* Check the level or parameters have been set. */
|
|
if (key->params == NULL) {
|
|
ret = BAD_STATE_E;
|
|
}
|
|
else {
|
|
/* Make the key. */
|
|
ret = dilithium_make_key_from_seed(key, seed);
|
|
}
|
|
#elif defined(HAVE_LIBOQS)
|
|
/* Make the key. */
|
|
ret = NOT_COMPILED_IN;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_SIGN
|
|
/* Sign the message using the dilithium private key.
|
|
*
|
|
* ctx [in] Context of signature.
|
|
* ctxLen [in] Length of context in bytes.
|
|
* msg [in] Message to sign.
|
|
* msgLen [in] Length of the message in bytes.
|
|
* sig [out] Buffer to write signature into.
|
|
* sigLen [in/out] On in, size of buffer.
|
|
* On out, the length of the signature in bytes.
|
|
* key [in] Dilithium key to use when signing
|
|
* returns BAD_FUNC_ARG when a parameter is NULL, public key not set
|
|
* or ctx is NULL and ctxLen is not 0,
|
|
* BUFFER_E when outLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_sign_ctx_msg(const byte* ctx, byte ctxLen, const byte* msg,
|
|
word32 msgLen, byte* sig, word32 *sigLen, dilithium_key* key, WC_RNG* rng)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((msg == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (ctx == NULL) && (ctxLen > 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
#ifdef WOLF_CRYPTO_CB
|
|
if (ret == 0) {
|
|
#ifndef WOLF_CRYPTO_CB_FIND
|
|
if (key->devId != INVALID_DEVID)
|
|
#endif
|
|
{
|
|
ret = wc_CryptoCb_PqcSign(msg, msgLen, sig, sigLen, ctx, ctxLen,
|
|
WC_HASH_TYPE_NONE, rng, WC_PQC_SIG_TYPE_DILITHIUM, key);
|
|
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
|
return ret;
|
|
/* fall-through when unavailable */
|
|
ret = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
/* Sign message. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_sign_ctx_msg(key, rng, ctx, ctxLen, msg, msgLen, sig,
|
|
sigLen);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = oqs_dilithium_sign_msg(msg, msgLen, sig, sigLen, key, rng);
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign the message using the dilithium private key.
|
|
*
|
|
* msg [in] Message to sign.
|
|
* msgLen [in] Length of the message in bytes.
|
|
* sig [out] Buffer to write signature into.
|
|
* sigLen [in/out] On in, size of buffer.
|
|
* On out, the length of the signature in bytes.
|
|
* key [in] Dilithium key to use when signing
|
|
* returns BAD_FUNC_ARG when a parameter is NULL or public key not set,
|
|
* BUFFER_E when outLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_sign_msg(const byte* msg, word32 msgLen, byte* sig,
|
|
word32 *sigLen, dilithium_key* key, WC_RNG* rng)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((msg == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
#ifdef WOLF_CRYPTO_CB
|
|
if (ret == 0) {
|
|
#ifndef WOLF_CRYPTO_CB_FIND
|
|
if (key->devId != INVALID_DEVID)
|
|
#endif
|
|
{
|
|
ret = wc_CryptoCb_PqcSign(msg, msgLen, sig, sigLen, NULL, 0,
|
|
WC_HASH_TYPE_NONE, rng, WC_PQC_SIG_TYPE_DILITHIUM, key);
|
|
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
|
return ret;
|
|
/* fall-through when unavailable */
|
|
ret = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
/* Sign message. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_sign_msg(key, rng, msg, msgLen, sig, sigLen);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = oqs_dilithium_sign_msg(msg, msgLen, sig, sigLen, key, rng);
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign the message hash using the dilithium private key.
|
|
*
|
|
* ctx [in] Context of signature.
|
|
* ctxLen [in] Length of context in bytes.
|
|
* hashAlg [in] Hash algorithm used on message.
|
|
* hash [in] Hash of message to sign.
|
|
* hashLen [in] Length of the message hash in bytes.
|
|
* sig [out] Buffer to write signature into.
|
|
* sigLen [in/out] On in, size of buffer.
|
|
* On out, the length of the signature in bytes.
|
|
* key [in] Dilithium key to use when signing
|
|
* returns BAD_FUNC_ARG when a parameter is NULL, public key not set
|
|
* or ctx is NULL and ctxLen is not 0,
|
|
* BUFFER_E when outLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_sign_ctx_hash(const byte* ctx, byte ctxLen, int hashAlg,
|
|
const byte* hash, word32 hashLen, byte* sig, word32 *sigLen,
|
|
dilithium_key* key, WC_RNG* rng)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((hash == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (ctx == NULL) && (ctxLen > 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
#ifdef WOLF_CRYPTO_CB
|
|
if (ret == 0) {
|
|
#ifndef WOLF_CRYPTO_CB_FIND
|
|
if (key->devId != INVALID_DEVID)
|
|
#endif
|
|
{
|
|
ret = wc_CryptoCb_PqcSign(hash, hashLen, sig, sigLen, ctx, ctxLen,
|
|
hashAlg, rng, WC_PQC_SIG_TYPE_DILITHIUM, key);
|
|
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
|
return ret;
|
|
/* fall-through when unavailable */
|
|
ret = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
/* Sign message. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_sign_ctx_hash(key, rng, ctx, ctxLen, hashAlg, hash,
|
|
hashLen, sig, sigLen);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = NOT_COMPILED_IN;
|
|
(void)hashAlg;
|
|
(void)hash;
|
|
(void)hashLen;
|
|
(void)rng;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign the message using the dilithium private key.
|
|
*
|
|
* ctx [in] Context of signature.
|
|
* ctxLen [in] Length of context in bytes.
|
|
* msg [in] Message to sign.
|
|
* msgLen [in] Length of the message in bytes.
|
|
* sig [out] Buffer to write signature into.
|
|
* sigLen [in/out] On in, size of buffer.
|
|
* On out, the length of the signature in bytes.
|
|
* key [in] Dilithium key to use when signing
|
|
* returns BAD_FUNC_ARG when a parameter is NULL, public key not set
|
|
* or ctx is NULL and ctxLen is not 0,
|
|
* BUFFER_E when outLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_sign_ctx_msg_with_seed(const byte* ctx, byte ctxLen,
|
|
const byte* msg, word32 msgLen, byte* sig, word32 *sigLen,
|
|
dilithium_key* key, const byte* seed)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((msg == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (ctx == NULL) && (ctxLen > 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Sign message. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_sign_ctx_msg_with_seed(key, seed, ctx, ctxLen, msg,
|
|
msgLen, sig, sigLen);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = NOT_COMPILED_IN;
|
|
(void)msgLen;
|
|
(void)seed;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign the message using the dilithium private key.
|
|
*
|
|
* msg [in] Message to sign.
|
|
* msgLen [in] Length of the message in bytes.
|
|
* sig [out] Buffer to write signature into.
|
|
* sigLen [in/out] On in, size of buffer.
|
|
* On out, the length of the signature in bytes.
|
|
* key [in] Dilithium key to use when signing
|
|
* returns BAD_FUNC_ARG when a parameter is NULL or public key not set,
|
|
* BUFFER_E when outLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_sign_msg_with_seed(const byte* msg, word32 msgLen, byte* sig,
|
|
word32 *sigLen, dilithium_key* key, const byte* seed)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((msg == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Sign message. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_sign_msg_with_seed(key, seed, msg, msgLen, sig, sigLen);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = NOT_COMPILED_IN;
|
|
(void)msgLen;
|
|
(void)seed;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Sign the message using the dilithium private key.
|
|
*
|
|
* ctx [in] Context of signature.
|
|
* ctxLen [in] Length of context in bytes.
|
|
* hashAlg [in] Hash algorithm used on message.
|
|
* hash [in] Hash of message to sign.
|
|
* hashLen [in] Length of the message hash in bytes.
|
|
* sig [out] Buffer to write signature into.
|
|
* sigLen [in/out] On in, size of buffer.
|
|
* On out, the length of the signature in bytes.
|
|
* key [in] Dilithium key to use when signing
|
|
* returns BAD_FUNC_ARG when a parameter is NULL, public key not set
|
|
* or ctx is NULL and ctxLen is not 0,
|
|
* BUFFER_E when outLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen,
|
|
int hashAlg, const byte* hash, word32 hashLen, byte* sig, word32 *sigLen,
|
|
dilithium_key* key, const byte* seed)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((hash == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (ctx == NULL) && (ctxLen > 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Sign message. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_sign_ctx_hash_with_seed(key, seed, ctx, ctxLen,
|
|
hashAlg, hash, hashLen, sig, sigLen);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = NOT_COMPILED_IN;
|
|
(void)hashAlg;
|
|
(void)hash;
|
|
(void)hashLen;
|
|
(void)seed;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_SIGN */
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_VERIFY
|
|
/* Verify the message using the dilithium public key.
|
|
*
|
|
* sig [in] Signature to verify.
|
|
* sigLen [in] Size of signature in bytes.
|
|
* ctx [in] Context of signature.
|
|
* ctxLen [in] Length of context in bytes.
|
|
* msg [in] Message to verify.
|
|
* msgLen [in] Length of the message in bytes.
|
|
* res [out] *res is set to 1 on successful verification.
|
|
* key [in] Dilithium key to use to verify.
|
|
* returns BAD_FUNC_ARG when a parameter is NULL, public key not set
|
|
* or ctx is NULL and ctxLen is not 0,
|
|
* BUFFER_E when sigLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_verify_ctx_msg(const byte* sig, word32 sigLen, const byte* ctx,
|
|
word32 ctxLen, const byte* msg, word32 msgLen, int* res, dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((key == NULL) || (sig == NULL) || (msg == NULL) || (res == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (ctx == NULL) && (ctxLen > 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
#ifdef WOLF_CRYPTO_CB
|
|
if (ret == 0) {
|
|
#ifndef WOLF_CRYPTO_CB_FIND
|
|
if (key->devId != INVALID_DEVID)
|
|
#endif
|
|
{
|
|
ret = wc_CryptoCb_PqcVerify(sig, sigLen, msg, msgLen, ctx, ctxLen,
|
|
WC_HASH_TYPE_NONE, res, WC_PQC_SIG_TYPE_DILITHIUM, key);
|
|
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
|
return ret;
|
|
/* fall-through when unavailable */
|
|
ret = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
/* Verify message with signature. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_verify_ctx_msg(key, ctx, ctxLen, msg, msgLen, sig,
|
|
sigLen, res);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = NOT_COMPILED_IN;
|
|
(void)sigLen;
|
|
(void)msgLen;
|
|
(void)res;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Verify the message using the dilithium public key.
|
|
*
|
|
* sig [in] Signature to verify.
|
|
* sigLen [in] Size of signature in bytes.
|
|
* msg [in] Message to verify.
|
|
* msgLen [in] Length of the message in bytes.
|
|
* res [out] *res is set to 1 on successful verification.
|
|
* key [in] Dilithium key to use to verify.
|
|
* returns BAD_FUNC_ARG when a parameter is NULL or contextLen is zero when and
|
|
* BUFFER_E when sigLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
|
|
word32 msgLen, int* res, dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((key == NULL) || (sig == NULL) || (msg == NULL) || (res == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
#ifdef WOLF_CRYPTO_CB
|
|
if (ret == 0) {
|
|
#ifndef WOLF_CRYPTO_CB_FIND
|
|
if (key->devId != INVALID_DEVID)
|
|
#endif
|
|
{
|
|
ret = wc_CryptoCb_PqcVerify(sig, sigLen, msg, msgLen, NULL, 0,
|
|
WC_HASH_TYPE_NONE, res, WC_PQC_SIG_TYPE_DILITHIUM, key);
|
|
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
|
return ret;
|
|
/* fall-through when unavailable */
|
|
ret = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
/* Verify message with signature. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_verify_msg(key, msg, msgLen, sig, sigLen, res);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = oqs_dilithium_verify_msg(sig, sigLen, msg, msgLen, res, key);
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Verify the message using the dilithium public key.
|
|
*
|
|
* sig [in] Signature to verify.
|
|
* sigLen [in] Size of signature in bytes.
|
|
* ctx [in] Context of signature.
|
|
* ctxLen [in] Length of context in bytes.
|
|
* hashAlg [in] Hash algorithm used on message.
|
|
* hash [in] Hash of message to verify.
|
|
* hashLen [in] Length of the message hash in bytes.
|
|
* res [out] *res is set to 1 on successful verification.
|
|
* key [in] Dilithium key to use to verify.
|
|
* returns BAD_FUNC_ARG when a parameter is NULL, public key not set
|
|
* or ctx is NULL and ctxLen is not 0,
|
|
* BUFFER_E when sigLen is less than DILITHIUM_LEVEL2_SIG_SIZE,
|
|
* 0 otherwise.
|
|
*/
|
|
int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen,
|
|
const byte* ctx, word32 ctxLen, int hashAlg, const byte* hash,
|
|
word32 hashLen, int* res, dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((key == NULL) || (sig == NULL) || (hash == NULL) || (res == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (ctx == NULL) && (ctxLen > 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
#ifdef WOLF_CRYPTO_CB
|
|
if (ret == 0) {
|
|
#ifndef WOLF_CRYPTO_CB_FIND
|
|
if (key->devId != INVALID_DEVID)
|
|
#endif
|
|
{
|
|
ret = wc_CryptoCb_PqcVerify(sig, sigLen, hash, hashLen, ctx, ctxLen,
|
|
hashAlg, res, WC_PQC_SIG_TYPE_DILITHIUM, key);
|
|
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
|
return ret;
|
|
/* fall-through when unavailable */
|
|
ret = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ret == 0) {
|
|
/* Verify message with signature. */
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
ret = dilithium_verify_ctx_hash(key, ctx, ctxLen, hashAlg, hash,
|
|
hashLen, sig, sigLen, res);
|
|
#elif defined(HAVE_LIBOQS)
|
|
ret = NOT_COMPILED_IN;
|
|
(void)sigLen;
|
|
(void)hashAlg;
|
|
(void)hash;
|
|
(void)hashLen;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_NO_VERIFY */
|
|
|
|
/* Initialize the dilithium private/public key.
|
|
*
|
|
* key [in] Dilithium key.
|
|
* returns BAD_FUNC_ARG when key is NULL
|
|
*/
|
|
int wc_dilithium_init(dilithium_key* key)
|
|
{
|
|
return wc_dilithium_init_ex(key, NULL, INVALID_DEVID);
|
|
}
|
|
|
|
/* Initialize the dilithium private/public key.
|
|
*
|
|
* key [in] Dilithium key.
|
|
* heap [in] Heap hint.
|
|
* devId[in] Device ID.
|
|
* returns BAD_FUNC_ARG when key is NULL
|
|
*/
|
|
int wc_dilithium_init_ex(dilithium_key* key, void* heap, int devId)
|
|
{
|
|
int ret = 0;
|
|
|
|
(void)devId;
|
|
|
|
/* Validate parameters. */
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Ensure all fields reset. */
|
|
XMEMSET(key, 0, sizeof(*key));
|
|
|
|
#ifdef WOLF_CRYPTO_CB
|
|
key->devCtx = NULL;
|
|
key->devId = devId;
|
|
#endif
|
|
#ifdef WOLF_PRIVATE_KEY_ID
|
|
key->idLen = 0;
|
|
key->labelLen = 0;
|
|
#endif
|
|
key->heap = heap;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WOLF_PRIVATE_KEY_ID
|
|
int wc_dilithium_init_id(dilithium_key* key, const unsigned char* id, int len,
|
|
void* heap, int devId)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && ((len < 0) || (len > DILITHIUM_MAX_ID_LEN))) {
|
|
ret = BUFFER_E;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_dilithium_init_ex(key, heap, devId);
|
|
}
|
|
if ((ret == 0) && (id != NULL) && (len != 0)) {
|
|
XMEMCPY(key->id, id, (size_t)len);
|
|
key->idLen = len;
|
|
}
|
|
|
|
/* Set the maximum level here */
|
|
wc_dilithium_set_level(key, WC_ML_DSA_87);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wc_dilithium_init_label(dilithium_key* key, const char* label, void* heap,
|
|
int devId)
|
|
{
|
|
int ret = 0;
|
|
int labelLen = 0;
|
|
|
|
if ((key == NULL) || (label == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if (ret == 0) {
|
|
labelLen = (int)XSTRLEN(label);
|
|
if ((labelLen == 0) || (labelLen > DILITHIUM_MAX_LABEL_LEN)) {
|
|
ret = BUFFER_E;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = wc_dilithium_init_ex(key, heap, devId);
|
|
}
|
|
if (ret == 0) {
|
|
XMEMCPY(key->label, label, (size_t)labelLen);
|
|
key->labelLen = labelLen;
|
|
}
|
|
|
|
/* Set the maximum level here */
|
|
wc_dilithium_set_level(key, WC_ML_DSA_87);
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/* Set the level of the dilithium private/public key.
|
|
*
|
|
* key [out] Dilithium key.
|
|
* level [in] Either 2,3 or 5.
|
|
* returns BAD_FUNC_ARG when key is NULL or level is a bad values.
|
|
*/
|
|
int wc_dilithium_set_level(dilithium_key* key, byte level)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && ((level == WC_ML_DSA_44) || (level == WC_ML_DSA_65) ||
|
|
(level == WC_ML_DSA_87))) {
|
|
/* Nothing to do. */
|
|
}
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
else if ((ret == 0) && ((level == WC_ML_DSA_44_DRAFT) ||
|
|
(level == WC_ML_DSA_65_DRAFT) || (level == WC_ML_DSA_87_DRAFT))) {
|
|
/* Nothing to do. */
|
|
}
|
|
#endif
|
|
else {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
/* Get the parameters for level into key. */
|
|
ret = dilithium_get_params(level, &key->params);
|
|
}
|
|
if (ret == 0) {
|
|
/* Clear any cached items. */
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
XFREE(key->a, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
key->a = NULL;
|
|
key->aSet = 0;
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
XFREE(key->s1, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
key->s1 = NULL;
|
|
key->s2 = NULL;
|
|
key->t0 = NULL;
|
|
key->privVecsSet = 0;
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PUB_VECTORS
|
|
XFREE(key->t1, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
key->t1 = NULL;
|
|
key->pubVecSet = 0;
|
|
#endif
|
|
#endif
|
|
#endif /* WOLFSSL_WC_DILITHIUM */
|
|
|
|
/* Store level and indicate public and private key are not set. */
|
|
key->level = level % WC_ML_DSA_DRAFT;
|
|
key->pubKeySet = 0;
|
|
key->prvKeySet = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Get the level of the dilithium private/public key.
|
|
*
|
|
* key [in] Dilithium key.
|
|
* level [out] The level.
|
|
* returns BAD_FUNC_ARG when key is NULL or level has not been set.
|
|
*/
|
|
int wc_dilithium_get_level(dilithium_key* key, byte* level)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((key == NULL) || (level == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (key->level != WC_ML_DSA_44) &&
|
|
(key->level != WC_ML_DSA_65) && (key->level != WC_ML_DSA_87)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Return level. */
|
|
*level = key->level;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Clears the dilithium key data
|
|
*
|
|
* key [in] Dilithium key.
|
|
*/
|
|
void wc_dilithium_free(dilithium_key* key)
|
|
{
|
|
if (key != NULL) {
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
/* Dispose of cached items. */
|
|
#ifdef WC_DILITHIUM_CACHE_PUB_VECTORS
|
|
XFREE(key->t1, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
XFREE(key->s1, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
XFREE(key->a, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
#endif
|
|
#endif
|
|
/* Free the SHAKE-128/256 object. */
|
|
wc_Shake256_Free(&key->shake);
|
|
#endif
|
|
/* Ensure all private data is zeroized. */
|
|
ForceZero(key, sizeof(*key));
|
|
}
|
|
}
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PRIVATE_KEY
|
|
/* Returns the size of a dilithium private key.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @return Private key size on success for set level.
|
|
* @return BAD_FUNC_ARG when key is NULL or level not set,
|
|
*/
|
|
int wc_dilithium_size(dilithium_key* key)
|
|
{
|
|
int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
|
|
|
|
if (key != NULL) {
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
ret = DILITHIUM_LEVEL2_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
ret = DILITHIUM_LEVEL3_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
ret = DILITHIUM_LEVEL5_KEY_SIZE;
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
ret = ML_DSA_LEVEL2_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
ret = ML_DSA_LEVEL3_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
ret = ML_DSA_LEVEL5_KEY_SIZE;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PUBLIC_KEY
|
|
/* Returns the size of a dilithium private plus public key.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @return Private key size on success for set level.
|
|
* @return BAD_FUNC_ARG when key is NULL or level not set,
|
|
*/
|
|
int wc_dilithium_priv_size(dilithium_key* key)
|
|
{
|
|
int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
|
|
|
|
if (key != NULL) {
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
ret = DILITHIUM_LEVEL2_PRV_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
ret = DILITHIUM_LEVEL3_PRV_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
ret = DILITHIUM_LEVEL5_PRV_KEY_SIZE;
|
|
}
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
ret = ML_DSA_LEVEL2_PRV_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
ret = ML_DSA_LEVEL3_PRV_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
ret = ML_DSA_LEVEL5_PRV_KEY_SIZE;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Returns the size of a dilithium private plus public key.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @param [out] len Private key size for set level.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key is NULL or level not set,
|
|
*/
|
|
int wc_MlDsaKey_GetPrivLen(MlDsaKey* key, int* len)
|
|
{
|
|
int ret = 0;
|
|
|
|
*len = wc_dilithium_priv_size(key);
|
|
if (*len < 0) {
|
|
ret = *len;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_PUBLIC_KEY */
|
|
#endif /* WOLFSSL_DILITHIUM_PRIVATE_KEY */
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PUBLIC_KEY
|
|
/* Returns the size of a dilithium public key.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @return Public key size on success for set level.
|
|
* @return BAD_FUNC_ARG when key is NULL or level not set,
|
|
*/
|
|
int wc_dilithium_pub_size(dilithium_key* key)
|
|
{
|
|
int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
|
|
|
|
if (key != NULL) {
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
ret = DILITHIUM_LEVEL2_PUB_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
ret = DILITHIUM_LEVEL3_PUB_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
ret = DILITHIUM_LEVEL5_PUB_KEY_SIZE;
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
ret = ML_DSA_LEVEL2_PUB_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
ret = ML_DSA_LEVEL3_PUB_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
ret = ML_DSA_LEVEL5_PUB_KEY_SIZE;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Returns the size of a dilithium public key.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @param [out] len Public key size for set level.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key is NULL or level not set,
|
|
*/
|
|
int wc_MlDsaKey_GetPubLen(MlDsaKey* key, int* len)
|
|
{
|
|
int ret = 0;
|
|
|
|
*len = wc_dilithium_pub_size(key);
|
|
if (*len < 0) {
|
|
ret = *len;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_SIGN) || !defined(WOLFSSL_DILITHIUM_NO_VERIFY)
|
|
/* Returns the size of a dilithium signature.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @return Signature size on success for set level.
|
|
* @return BAD_FUNC_ARG when key is NULL or level not set,
|
|
*/
|
|
int wc_dilithium_sig_size(dilithium_key* key)
|
|
{
|
|
int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
|
|
|
|
if (key != NULL) {
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
ret = DILITHIUM_LEVEL2_SIG_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
ret = DILITHIUM_LEVEL3_SIG_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
ret = DILITHIUM_LEVEL5_SIG_SIZE;
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
ret = ML_DSA_LEVEL2_SIG_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
ret = ML_DSA_LEVEL3_SIG_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
ret = ML_DSA_LEVEL5_SIG_SIZE;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Returns the size of a dilithium signature.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @param [out] len Signature size for set level.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key is NULL or level not set,
|
|
*/
|
|
int wc_MlDsaKey_GetSigLen(MlDsaKey* key, int* len)
|
|
{
|
|
int ret = 0;
|
|
|
|
*len = wc_dilithium_sig_size(key);
|
|
if (*len < 0) {
|
|
ret = *len;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_CHECK_KEY
|
|
/* Check the public key of the dilithium key matches the private key.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when key is NULL or no private key available,
|
|
* @return PUBLIC_KEY_E when the public key is not set or doesn't match,
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
*/
|
|
int wc_dilithium_check_key(dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
const wc_dilithium_params* params = NULL;
|
|
sword32* a = NULL;
|
|
sword32* s1 = NULL;
|
|
sword32* s2 = NULL;
|
|
sword32* t = NULL;
|
|
sword32* t0 = NULL;
|
|
sword32* t1 = NULL;
|
|
|
|
/* Validate parameter. */
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (!key->prvKeySet)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (!key->pubKeySet)) {
|
|
ret = PUBLIC_KEY_E;
|
|
}
|
|
|
|
/* Any value in public key are valid.
|
|
* Public seed is hashed to generate matrix A.
|
|
* t1 is the top 10 bits of a number in range of 0..(Q-1).
|
|
* Q >> 13 = 0x3ff so all encoded values are valid.
|
|
*/
|
|
|
|
if (ret == 0) {
|
|
unsigned int allocSz;
|
|
|
|
params = key->params;
|
|
|
|
/* s1-L, s2-K, t0-K, t-K, t1-K */
|
|
allocSz = params->s1Sz + 4 * params->s2Sz;
|
|
#if !defined(WC_DILITHIUM_CACHE_MATRIX_A)
|
|
/* A-KxL */
|
|
allocSz += params->aSz;
|
|
#endif
|
|
|
|
/* Allocate memory for large intermediates. */
|
|
s1 = (sword32*)XMALLOC(allocSz, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (s1 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(s1, 0, allocSz);
|
|
s2 = s1 + params->s1Sz / sizeof(*s1);
|
|
t0 = s2 + params->s2Sz / sizeof(*s2);
|
|
t = t0 + params->s2Sz / sizeof(*t0);
|
|
t1 = t + params->s2Sz / sizeof(*t);
|
|
#if !defined(WC_DILITHIUM_CACHE_MATRIX_A)
|
|
a = t1 + params->s2Sz / sizeof(*t1);
|
|
#else
|
|
a = key->a;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
/* Check that we haven't already cached the matrix A. */
|
|
if (!key->aSet)
|
|
#endif
|
|
{
|
|
const byte* pub_seed = key->p;
|
|
|
|
ret = dilithium_expand_a(&key->shake, pub_seed, params->k,
|
|
params->l, a, key->heap);
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
key->aSet = (ret == 0);
|
|
#endif
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
const byte* s1p = key->k + DILITHIUM_PUB_SEED_SZ + DILITHIUM_K_SZ +
|
|
DILITHIUM_TR_SZ;
|
|
const byte* s2p = s1p + params->s1EncSz;
|
|
const byte* t0p = s2p + params->s2EncSz;
|
|
const byte* t1p = key->p + DILITHIUM_PUB_SEED_SZ;
|
|
sword32* tt = t;
|
|
unsigned int i;
|
|
unsigned int j;
|
|
sword32 x = 0;
|
|
|
|
/* Get s1, s2 and t0 from private key. */
|
|
dilithium_vec_decode_eta_bits(s1p, params->eta, s1, params->l);
|
|
dilithium_vec_decode_eta_bits(s2p, params->eta, s2, params->k);
|
|
dilithium_vec_decode_t0(t0p, params->k, t0);
|
|
|
|
/* Get t1 from public key. */
|
|
dilithium_vec_decode_t1(t1p, params->k, t1);
|
|
|
|
/* Calcaluate t = NTT-1(A o NTT(s1)) + s2 */
|
|
dilithium_vec_ntt_small(s1, params->l);
|
|
dilithium_matrix_mul(t, a, s1, params->k, params->l);
|
|
dilithium_vec_invntt(t, params->k);
|
|
dilithium_vec_add(t, s2, params->k);
|
|
/* Subtract t0 from t. */
|
|
dilithium_vec_sub(t, t0, params->k);
|
|
/* Make t positive to match t1. */
|
|
dilithium_vec_make_pos(t, params->k);
|
|
|
|
/* Check t - t0 and t1 are the same. */
|
|
for (i = 0; i < params->k; i++) {
|
|
for (j = 0; j < DILITHIUM_N; j++) {
|
|
x |= tt[j] ^ t1[j];
|
|
}
|
|
tt += DILITHIUM_N;
|
|
t1 += DILITHIUM_N;
|
|
}
|
|
/* Check the public seed is the same in private and public key. */
|
|
for (i = 0; i < DILITHIUM_PUB_SEED_SZ; i++) {
|
|
x |= key->p[i] ^ key->k[i];
|
|
}
|
|
|
|
if ((ret == 0) && (x != 0)) {
|
|
ret = PUBLIC_KEY_E;
|
|
}
|
|
}
|
|
|
|
if (key != NULL) {
|
|
/* Dispose of allocated memory. */
|
|
XFREE(s1, key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
}
|
|
#else
|
|
/* Validate parameter. */
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (!key->prvKeySet)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (!key->pubKeySet)) {
|
|
ret = PUBLIC_KEY_E;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
int i;
|
|
sword32 x = 0;
|
|
|
|
/* Check the public seed is the same in private and public key. */
|
|
for (i = 0; i < 32; i++) {
|
|
x |= key->p[i] ^ key->k[i];
|
|
}
|
|
|
|
if (x != 0) {
|
|
ret = PUBLIC_KEY_E;
|
|
}
|
|
}
|
|
#endif /* WOLFSSL_WC_DILITHIUM */
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_CHECK_KEY */
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PUBLIC_KEY
|
|
|
|
/* Export the dilithium public key.
|
|
*
|
|
* @param [in] key Dilithium public key.
|
|
* @param [out] out Array to hold public key.
|
|
* @param [in, out] outLen On in, the number of bytes in array.
|
|
* On out, the number bytes put into array.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when a parameter is NULL.
|
|
* @return BUFFER_E when outLen is less than DILITHIUM_LEVEL2_PUB_KEY_SIZE.
|
|
*/
|
|
int wc_dilithium_export_public(dilithium_key* key, byte* out, word32* outLen)
|
|
{
|
|
int ret = 0;
|
|
word32 inLen;
|
|
|
|
/* Validate parameters */
|
|
if ((key == NULL) || (out == NULL) || (outLen == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if (ret == 0) {
|
|
/* Get length passed in for checking. */
|
|
inLen = *outLen;
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
/* Set out length. */
|
|
*outLen = DILITHIUM_LEVEL2_PUB_KEY_SIZE;
|
|
/* Validate length passed in. */
|
|
if (inLen < DILITHIUM_LEVEL2_PUB_KEY_SIZE) {
|
|
ret = BUFFER_E;
|
|
}
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
/* Set out length. */
|
|
*outLen = DILITHIUM_LEVEL3_PUB_KEY_SIZE;
|
|
/* Validate length passed in. */
|
|
if (inLen < DILITHIUM_LEVEL3_PUB_KEY_SIZE) {
|
|
ret = BUFFER_E;
|
|
}
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
/* Set out length. */
|
|
*outLen = DILITHIUM_LEVEL5_PUB_KEY_SIZE;
|
|
/* Validate length passed in. */
|
|
if (inLen < DILITHIUM_LEVEL5_PUB_KEY_SIZE) {
|
|
ret = BUFFER_E;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
/* Set out length. */
|
|
*outLen = ML_DSA_LEVEL2_PUB_KEY_SIZE;
|
|
/* Validate length passed in. */
|
|
if (inLen < ML_DSA_LEVEL2_PUB_KEY_SIZE) {
|
|
ret = BUFFER_E;
|
|
}
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
/* Set out length. */
|
|
*outLen = ML_DSA_LEVEL3_PUB_KEY_SIZE;
|
|
/* Validate length passed in. */
|
|
if (inLen < ML_DSA_LEVEL3_PUB_KEY_SIZE) {
|
|
ret = BUFFER_E;
|
|
}
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
/* Set out length. */
|
|
*outLen = ML_DSA_LEVEL5_PUB_KEY_SIZE;
|
|
/* Validate length passed in. */
|
|
if (inLen < ML_DSA_LEVEL5_PUB_KEY_SIZE) {
|
|
ret = BUFFER_E;
|
|
}
|
|
}
|
|
else {
|
|
/* Level not set. */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
|
|
/* Check public key available. */
|
|
if ((ret == 0) && (!key->pubKeySet)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Copy public key out. */
|
|
XMEMCPY(out, key->p, *outLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Import a dilithium public key from a byte array.
|
|
*
|
|
* Public key encoded in big-endian.
|
|
*
|
|
* @param [in] in Array holding public key.
|
|
* @param [in] inLen Number of bytes of data in array.
|
|
* @param [in, out] key Dilithium public key.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when in or key is NULL or key format is not supported.
|
|
*/
|
|
int wc_dilithium_import_public(const byte* in, word32 inLen, dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((in == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if (ret == 0) {
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
/* Check length. */
|
|
if (inLen != DILITHIUM_LEVEL2_PUB_KEY_SIZE) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
/* Check length. */
|
|
if (inLen != DILITHIUM_LEVEL3_PUB_KEY_SIZE) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
/* Check length. */
|
|
if (inLen != DILITHIUM_LEVEL5_PUB_KEY_SIZE) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
/* Check length. */
|
|
if (inLen != ML_DSA_LEVEL2_PUB_KEY_SIZE) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
/* Check length. */
|
|
if (inLen != ML_DSA_LEVEL3_PUB_KEY_SIZE) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
/* Check length. */
|
|
if (inLen != ML_DSA_LEVEL5_PUB_KEY_SIZE) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
else {
|
|
/* Level not set. */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Copy the private key data in or copy pointer. */
|
|
#ifndef WOLFSSL_DILITHIUM_ASSIGN_KEY
|
|
XMEMCPY(key->p, in, inLen);
|
|
#else
|
|
key->p = in;
|
|
#endif
|
|
|
|
#ifdef WC_DILITHIUM_CACHE_PUB_VECTORS
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
/* Allocate t1 if required. */
|
|
if (key->t1 == NULL) {
|
|
key->t1 = (sword32*)XMALLOC(key->params->s2Sz, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->t1 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(key->t1, 0, key->params->s2Sz);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (ret == 0) {
|
|
/* Compute t1 from public key data. */
|
|
dilithium_make_pub_vec(key, key->t1);
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
/* Allocate matrix a if required. */
|
|
if (key->a == NULL) {
|
|
key->a = (sword32*)XMALLOC(key->params->aSz, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->a == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(key->a, 0, key->params->aSz);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (ret == 0) {
|
|
/* Compute matrix a from public key data. */
|
|
ret = dilithium_expand_a(&key->shake, key->p, key->params->k,
|
|
key->params->l, key->a, key->heap);
|
|
if (ret == 0) {
|
|
key->aSet = 1;
|
|
}
|
|
}
|
|
if (ret == 0) {
|
|
#endif
|
|
/* Public key is set. */
|
|
key->pubKeySet = 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_PUBLIC_KEY */
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PRIVATE_KEY
|
|
|
|
/* Set the private key data into key.
|
|
*
|
|
* @param [in] priv Private key data.
|
|
* @param [in] privSz Size of private key data in bytes.
|
|
* @param in, out] key Dilithium key to set into.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when private key size is invalid.
|
|
* @return MEMORY_E when dynamic memory allocation fails.
|
|
* @return Other negative on hash error.
|
|
*/
|
|
static int dilithium_set_priv_key(const byte* priv, word32 privSz,
|
|
dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
const wc_dilithium_params* params = key->params;
|
|
#endif
|
|
|
|
/* Validate parameters. */
|
|
if ((privSz != ML_DSA_LEVEL2_KEY_SIZE) &&
|
|
(privSz != ML_DSA_LEVEL3_KEY_SIZE) &&
|
|
(privSz != ML_DSA_LEVEL5_KEY_SIZE)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Copy the private key data in or copy pointer. */
|
|
#ifndef WOLFSSL_DILITHIUM_ASSIGN_KEY
|
|
XMEMCPY(key->k, priv, privSz);
|
|
#else
|
|
key->k = priv;
|
|
#endif
|
|
}
|
|
|
|
/* Allocate and create cached values. */
|
|
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
if (ret == 0) {
|
|
/* Allocate matrix a if required. */
|
|
if (key->a == NULL) {
|
|
key->a = (sword32*)XMALLOC(params->aSz, key->heap,
|
|
DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->a == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(key->a, 0, params->aSz);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
/* Compute matrix a from private key data. */
|
|
ret = dilithium_expand_a(&key->shake, key->k, params->k, params->l,
|
|
key->a, key->heap);
|
|
if (ret == 0) {
|
|
key->aSet = 1;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef WC_DILITHIUM_CACHE_PRIV_VECTORS
|
|
#ifndef WC_DILITHIUM_FIXED_ARRAY
|
|
if ((ret == 0) && (key->s1 == NULL)) {
|
|
/* Allocate L vector s1, K vector s2 and K vector t0 if required. */
|
|
key->s1 = (sword32*)XMALLOC(params->s1Sz + params->s2Sz + params->s2Sz,
|
|
key->heap, DYNAMIC_TYPE_DILITHIUM);
|
|
if (key->s1 == NULL) {
|
|
ret = MEMORY_E;
|
|
}
|
|
else {
|
|
XMEMSET(key->s1, 0, params->s1Sz + params->s2Sz + params->s2Sz);
|
|
}
|
|
if (ret == 0) {
|
|
/* Set pointers into allocated memory. */
|
|
key->s2 = key->s1 + params->s1Sz / sizeof(*key->s1);
|
|
key->t0 = key->s2 + params->s2Sz / sizeof(*key->s2);
|
|
}
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
/* Compute vectors from private key. */
|
|
dilithium_make_priv_vecs(key, key->s1, key->s2, key->t0);
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
/* Private key is set. */
|
|
key->prvKeySet = 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Import a dilithium private key from a byte array.
|
|
*
|
|
* @param [in] priv Array holding private key.
|
|
* @param [in] privSz Number of bytes of data in array.
|
|
* @param [in, out] key Dilithium private key.
|
|
* @return 0 otherwise.
|
|
* @return BAD_FUNC_ARG when a parameter is NULL or privSz is less than size
|
|
* required for level,
|
|
*/
|
|
int wc_dilithium_import_private(const byte* priv, word32 privSz,
|
|
dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((priv == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (key->level != WC_ML_DSA_44) &&
|
|
(key->level != WC_ML_DSA_65) && (key->level != WC_ML_DSA_87)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Set the private key data. */
|
|
ret = dilithium_set_priv_key(priv, privSz, key);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_PUBLIC_KEY)
|
|
/* Import a dilithium private and public keys from byte array(s).
|
|
*
|
|
* @param [in] priv Array holding private key or private+public keys
|
|
* @param [in] privSz Number of bytes of data in private key array.
|
|
* @param [in] pub Array holding public key (or NULL).
|
|
* @param [in] pubSz Number of bytes of data in public key array (or 0).
|
|
* @param [in] key Dilithium private/public key.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when a required parameter is NULL an invalid
|
|
* combination of keys/lengths is supplied.
|
|
*/
|
|
int wc_dilithium_import_key(const byte* priv, word32 privSz,
|
|
const byte* pub, word32 pubSz, dilithium_key* key)
|
|
{
|
|
int ret = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((priv == NULL) || (key == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((pub == NULL) && (pubSz != 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if ((ret == 0) && (key->level != WC_ML_DSA_44) &&
|
|
(key->level != WC_ML_DSA_65) && (key->level != WC_ML_DSA_87)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if ((ret == 0) && (pub != NULL)) {
|
|
/* Import public key. */
|
|
ret = wc_dilithium_import_public(pub, pubSz, key);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_set_priv_key(priv, privSz, key);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_PUBLIC_KEY */
|
|
|
|
/* Export the dilithium private key.
|
|
*
|
|
* @param [in] key Dilithium private key.
|
|
* @param [out] out Array to hold private key.
|
|
* @param [in, out] outLen On in, the number of bytes in array.
|
|
* On out, the number bytes put into array.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when a parameter is NULL.
|
|
* @return BUFFER_E when outLen is less than DILITHIUM_LEVEL2_KEY_SIZE.
|
|
*/
|
|
int wc_dilithium_export_private(dilithium_key* key, byte* out,
|
|
word32* outLen)
|
|
{
|
|
int ret = 0;
|
|
word32 inLen = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((key == NULL) || (out == NULL) || (outLen == NULL)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* Check private key available. */
|
|
if ((ret == 0) && (!key->prvKeySet)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
inLen = *outLen;
|
|
/* check and set up out length */
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
*outLen = DILITHIUM_LEVEL2_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
*outLen = DILITHIUM_LEVEL3_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
*outLen = DILITHIUM_LEVEL5_KEY_SIZE;
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
*outLen = ML_DSA_LEVEL2_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
*outLen = ML_DSA_LEVEL3_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
*outLen = ML_DSA_LEVEL5_KEY_SIZE;
|
|
}
|
|
else {
|
|
/* Level not set. */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
|
|
/* Check array length. */
|
|
if ((ret == 0) && (inLen < *outLen)) {
|
|
ret = BUFFER_E;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Copy private key out key. */
|
|
XMEMCPY(out, key->k, *outLen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PUBLIC_KEY
|
|
/* Export the dilithium private and public key.
|
|
*
|
|
* @param [in] key Dilithium private/public key.
|
|
* @param [out] priv Array to hold private key.
|
|
* @param [in, out] privSz On in, the number of bytes in private key array.
|
|
* On out, the number bytes put into private key.
|
|
* @param [out] pub Array to hold public key.
|
|
* @param [in, out] pubSz On in, the number of bytes in public key array.
|
|
* On out, the number bytes put into public key.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when a key, priv, privSz, pub or pubSz is NULL.
|
|
* @return BUFFER_E when privSz or pubSz is less than required size.
|
|
*/
|
|
int wc_dilithium_export_key(dilithium_key* key, byte* priv, word32 *privSz,
|
|
byte* pub, word32 *pubSz)
|
|
{
|
|
int ret;
|
|
|
|
/* Export private key only. */
|
|
ret = wc_dilithium_export_private(key, priv, privSz);
|
|
if (ret == 0) {
|
|
/* Export public key. */
|
|
ret = wc_dilithium_export_public(key, pub, pubSz);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_PUBLIC_KEY */
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_PRIVATE_KEY */
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
|
|
|
|
/* Maps ASN.1 OID to wolfCrypt security level macros */
|
|
static int mapOidToSecLevel(int oid)
|
|
{
|
|
switch (oid) {
|
|
case ML_DSA_LEVEL2k:
|
|
return WC_ML_DSA_44;
|
|
case ML_DSA_LEVEL3k:
|
|
return WC_ML_DSA_65;
|
|
case ML_DSA_LEVEL5k:
|
|
return WC_ML_DSA_87;
|
|
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
|
case DILITHIUM_LEVEL2k:
|
|
return WC_ML_DSA_44_DRAFT;
|
|
case DILITHIUM_LEVEL3k:
|
|
return WC_ML_DSA_65_DRAFT;
|
|
case DILITHIUM_LEVEL5k:
|
|
return WC_ML_DSA_87_DRAFT;
|
|
#endif
|
|
default:
|
|
return ASN_UNKNOWN_OID_E;
|
|
}
|
|
}
|
|
|
|
/* Get OID sum from dilithium key */
|
|
int dilithium_get_oid_sum(dilithium_key* key, int* keyFormat) {
|
|
int ret = 0;
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
*keyFormat = DILITHIUM_LEVEL2k;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
*keyFormat = DILITHIUM_LEVEL3k;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
*keyFormat = DILITHIUM_LEVEL5k;
|
|
}
|
|
else
|
|
#endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */
|
|
if (key->level == WC_ML_DSA_44) {
|
|
*keyFormat = ML_DSA_LEVEL2k;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
*keyFormat = ML_DSA_LEVEL3k;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
*keyFormat = ML_DSA_LEVEL5k;
|
|
}
|
|
else {
|
|
/* Level is not set */
|
|
ret = ALGO_ID_E;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_PRIVATE_KEY)
|
|
|
|
/* Decode the DER encoded Dilithium key.
|
|
*
|
|
* @param [in] input Array holding DER encoded data.
|
|
* @param [in, out] inOutIdx On in, index into array of start of DER encoding.
|
|
* On out, index into array after DER encoding.
|
|
* @param [in, out] key Dilithium key structure to hold the decoded key.
|
|
* If the security level is set in the key structure
|
|
* on input, the DER key will be decoded as such and
|
|
* will fail if there is a mismatch. If the level
|
|
* and parameters are not set in the key structure on
|
|
* input, the level will be detected from the DER
|
|
* file based on the algorithm OID, appropriately
|
|
* decoded, then updated in the key structure on
|
|
* output. Auto-detection of the security level is
|
|
* not supported if compiled for FIPS 204 draft mode.
|
|
* @param [in] inSz Total size of the input DER buffer array.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when input, inOutIdx or key is NULL or inSz is 0.
|
|
* @return Other negative on parse error.
|
|
*/
|
|
int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
|
|
dilithium_key* key, word32 inSz)
|
|
{
|
|
int ret = 0;
|
|
const byte* privKey = NULL;
|
|
const byte* pubKey = NULL;
|
|
word32 privKeyLen = 0;
|
|
word32 pubKeyLen = 0;
|
|
int keyType = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((input == NULL) || (inOutIdx == NULL) || (key == NULL) || (inSz == 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Get OID sum for level. */
|
|
if (key->level == 0) { /* Check first, because key->params will be NULL
|
|
* when key->level = 0 */
|
|
/* Level not set by caller, decode from DER */
|
|
keyType = ANONk;
|
|
}
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
else if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL2k;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL3k;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL5k;
|
|
}
|
|
#endif
|
|
else if (key->level == WC_ML_DSA_44) {
|
|
keyType = ML_DSA_LEVEL2k;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
keyType = ML_DSA_LEVEL3k;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
keyType = ML_DSA_LEVEL5k;
|
|
}
|
|
else {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Decode the asymmetric key and get out private and public key data. */
|
|
ret = DecodeAsymKey_Assign(input, inOutIdx, inSz,
|
|
&privKey, &privKeyLen,
|
|
&pubKey, &pubKeyLen, &keyType);
|
|
if (ret == 0
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
&& key->params == NULL
|
|
#endif
|
|
) {
|
|
/* Set the security level based on the decoded key. */
|
|
ret = mapOidToSecLevel(keyType);
|
|
if (ret > 0) {
|
|
ret = wc_dilithium_set_level(key, (byte)ret);
|
|
}
|
|
}
|
|
}
|
|
if ((ret == 0) && (pubKey == NULL) && (pubKeyLen == 0)) {
|
|
/* Check if the public key is included in the private key. */
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if ((key->params->level == WC_ML_DSA_44_DRAFT) &&
|
|
(privKeyLen == DILITHIUM_LEVEL2_PRV_KEY_SIZE)) {
|
|
pubKey = privKey + DILITHIUM_LEVEL2_KEY_SIZE;
|
|
pubKeyLen = DILITHIUM_LEVEL2_PUB_KEY_SIZE;
|
|
privKeyLen -= DILITHIUM_LEVEL2_PUB_KEY_SIZE;
|
|
}
|
|
else if ((key->params->level == WC_ML_DSA_65_DRAFT) &&
|
|
(privKeyLen == DILITHIUM_LEVEL3_PRV_KEY_SIZE)) {
|
|
pubKey = privKey + DILITHIUM_LEVEL3_KEY_SIZE;
|
|
pubKeyLen = DILITHIUM_LEVEL3_PUB_KEY_SIZE;
|
|
privKeyLen -= DILITHIUM_LEVEL3_PUB_KEY_SIZE;
|
|
}
|
|
else if ((key->params->level == WC_ML_DSA_87_DRAFT) &&
|
|
(privKeyLen == DILITHIUM_LEVEL5_PRV_KEY_SIZE)) {
|
|
pubKey = privKey + DILITHIUM_LEVEL5_KEY_SIZE;
|
|
pubKeyLen = DILITHIUM_LEVEL5_PUB_KEY_SIZE;
|
|
privKeyLen -= DILITHIUM_LEVEL5_PUB_KEY_SIZE;
|
|
}
|
|
else
|
|
#endif
|
|
if ((key->level == WC_ML_DSA_44) &&
|
|
(privKeyLen == ML_DSA_LEVEL2_PRV_KEY_SIZE)) {
|
|
pubKey = privKey + ML_DSA_LEVEL2_KEY_SIZE;
|
|
pubKeyLen = ML_DSA_LEVEL2_PUB_KEY_SIZE;
|
|
privKeyLen -= ML_DSA_LEVEL2_PUB_KEY_SIZE;
|
|
}
|
|
else if ((key->level == WC_ML_DSA_65) &&
|
|
(privKeyLen == ML_DSA_LEVEL3_PRV_KEY_SIZE)) {
|
|
pubKey = privKey + ML_DSA_LEVEL3_KEY_SIZE;
|
|
pubKeyLen = ML_DSA_LEVEL3_PUB_KEY_SIZE;
|
|
privKeyLen -= ML_DSA_LEVEL3_PUB_KEY_SIZE;
|
|
}
|
|
else if ((key->level == WC_ML_DSA_87) &&
|
|
(privKeyLen == ML_DSA_LEVEL5_PRV_KEY_SIZE)) {
|
|
pubKey = privKey + ML_DSA_LEVEL5_KEY_SIZE;
|
|
pubKeyLen = ML_DSA_LEVEL5_PUB_KEY_SIZE;
|
|
privKeyLen -= ML_DSA_LEVEL5_PUB_KEY_SIZE;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Check whether public key data was found. */
|
|
#if defined(WOLFSSL_DILITHIUM_PUBLIC_KEY)
|
|
if (pubKeyLen == 0)
|
|
#endif
|
|
{
|
|
/* No public key data, only import private key data. */
|
|
ret = wc_dilithium_import_private(privKey, privKeyLen, key);
|
|
}
|
|
#if defined(WOLFSSL_DILITHIUM_PUBLIC_KEY)
|
|
else {
|
|
/* Import private and public key data. */
|
|
ret = wc_dilithium_import_key(privKey, privKeyLen, pubKey,
|
|
pubKeyLen, key);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
(void)pubKey;
|
|
(void)pubKeyLen;
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_PRIVATE_KEY */
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_NO_ASN1 */
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PUBLIC_KEY
|
|
|
|
#if defined(WOLFSSL_DILITHIUM_NO_ASN1)
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
static unsigned char ml_dsa_oid_44[] = {
|
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11
|
|
};
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
static unsigned char dilithium_oid_44[] = {
|
|
0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b,
|
|
0x0c, 0x04, 0x04
|
|
};
|
|
#endif
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
static unsigned char ml_dsa_oid_65[] = {
|
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12
|
|
};
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
static unsigned char dilithium_oid_65[] = {
|
|
0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b,
|
|
0x0c, 0x06, 0x05
|
|
};
|
|
#endif
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_87
|
|
static unsigned char ml_dsa_oid_87[] = {
|
|
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13
|
|
};
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
static unsigned char dilithium_oid_87[] = {
|
|
0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0b,
|
|
0x0c, 0x08, 0x07
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
static int dilitihium_get_der_length(const byte* input, word32* inOutIdx,
|
|
int *length, word32 inSz)
|
|
{
|
|
int ret = 0;
|
|
word32 idx = *inOutIdx;
|
|
word32 len = 0;
|
|
|
|
if (idx >= inSz) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
else if (input[idx] < 0x80) {
|
|
len = input[idx];
|
|
idx++;
|
|
}
|
|
else if ((input[idx] == 0x80) || (input[idx] >= 0x83)) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
else if (input[idx] == 0x81) {
|
|
if (idx + 1 >= inSz) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
else if (input[idx + 1] < 0x80) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
else {
|
|
len = input[idx + 1];
|
|
idx += 2;
|
|
}
|
|
}
|
|
else if (input[idx] == 0x82) {
|
|
if (idx + 2 >= inSz) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
else {
|
|
len = ((word16)input[idx + 1] << 8) + input[idx + 2];
|
|
idx += 3;
|
|
if (len < 0x100) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((ret == 0) && ((idx + len) > inSz)) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
|
|
*length = (int)len;
|
|
*inOutIdx = idx;
|
|
return ret;
|
|
}
|
|
|
|
static int dilithium_check_type(const byte* input, word32* inOutIdx, byte type,
|
|
word32 inSz)
|
|
{
|
|
int ret = 0;
|
|
word32 idx = *inOutIdx;
|
|
|
|
if (idx >= inSz) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
else if (input[idx] != type){
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
else {
|
|
idx++;
|
|
}
|
|
|
|
*inOutIdx = idx;
|
|
return ret;
|
|
}
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_NO_ASN1 */
|
|
|
|
/* Decode the DER encoded Dilithium public key.
|
|
*
|
|
* @param [in] input Array holding DER encoded data.
|
|
* @param [in, out] inOutIdx On in, index into array of start of DER encoding.
|
|
* On out, index into array after DER encoding.
|
|
* @param [in, out] key Dilithium key structure to hold the decoded key.
|
|
* If the security level is set in the key structure
|
|
* on input, the DER key will be decoded as such
|
|
* and will fail if there is a mismatch. If the level
|
|
* and parameters are not set in the key structure on
|
|
* input, the level will be detected from the DER
|
|
* file based on the algorithm OID, appropriately
|
|
* decoded, then updated in the key structure on
|
|
* output. Auto-detection of the security level is
|
|
* not supported if compiled for FIPS 204
|
|
* draft mode.
|
|
* @param [in] inSz Total size of data in array.
|
|
* @return 0 on success.
|
|
* @return BAD_FUNC_ARG when input, inOutIdx or key is NULL or inSz is 0.
|
|
* @return BAD_FUNC_ARG when level not set.
|
|
* @return Other negative on parse error.
|
|
*/
|
|
int wc_Dilithium_PublicKeyDecode(const byte* input, word32* inOutIdx,
|
|
dilithium_key* key, word32 inSz)
|
|
{
|
|
int ret = 0;
|
|
const byte* pubKey = NULL;
|
|
word32 pubKeyLen = 0;
|
|
|
|
/* Validate parameters. */
|
|
if ((input == NULL) || (inOutIdx == NULL) || (key == NULL) || (inSz == 0)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Try to import the key directly. */
|
|
ret = wc_dilithium_import_public(input, inSz, key);
|
|
if (ret != 0) {
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_ASN1)
|
|
int keyType = 0;
|
|
#else
|
|
int length;
|
|
unsigned char* oid;
|
|
int oidLen;
|
|
word32 idx = 0;
|
|
#endif
|
|
|
|
/* Start again. */
|
|
ret = 0;
|
|
|
|
#if !defined(WOLFSSL_DILITHIUM_NO_ASN1)
|
|
/* Get OID sum for level. */
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL2k;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL3k;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL5k;
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
keyType = ML_DSA_LEVEL2k;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
keyType = ML_DSA_LEVEL3k;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
keyType = ML_DSA_LEVEL5k;
|
|
}
|
|
else {
|
|
/* Level not set by caller, decode from DER */
|
|
keyType = ANONk; /* 0, not a valid key type in this situation*/
|
|
}
|
|
if (ret == 0) {
|
|
/* Decode the asymmetric key and get out public key data. */
|
|
ret = DecodeAsymKeyPublic_Assign(input, inOutIdx, inSz,
|
|
&pubKey, &pubKeyLen,
|
|
&keyType);
|
|
if (ret == 0
|
|
#ifdef WOLFSSL_WC_DILITHIUM
|
|
&& key->params == NULL
|
|
#endif
|
|
) {
|
|
/* Set the security level based on the decoded key. */
|
|
ret = mapOidToSecLevel(keyType);
|
|
if (ret > 0) {
|
|
ret = wc_dilithium_set_level(key, (byte)ret);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
/* Get OID sum for level. */
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
oid = dilithium_oid_44;
|
|
oidLen = (int)sizeof(dilithium_oid_44);
|
|
}
|
|
else
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
oid = dilithium_oid_65;
|
|
oidLen = (int)sizeof(dilithium_oid_65);
|
|
}
|
|
else
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_87
|
|
if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
oid = dilithium_oid_87;
|
|
oidLen = (int)sizeof(dilithium_oid_87);
|
|
}
|
|
else
|
|
#endif
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_44
|
|
if (key->level == WC_ML_DSA_44) {
|
|
oid = ml_dsa_oid_44;
|
|
oidLen = (int)sizeof(ml_dsa_oid_44);
|
|
}
|
|
else
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_65
|
|
if (key->level == WC_ML_DSA_65) {
|
|
oid = ml_dsa_oid_65;
|
|
oidLen = (int)sizeof(ml_dsa_oid_65);
|
|
}
|
|
else
|
|
#endif
|
|
#ifndef WOLFSSL_NO_ML_DSA_87
|
|
if (key->level == WC_ML_DSA_87) {
|
|
oid = ml_dsa_oid_87;
|
|
oidLen = (int)sizeof(ml_dsa_oid_87);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
/* Level not set. */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_check_type(input, &idx, 0x30, inSz);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilitihium_get_der_length(input, &idx, &length, inSz);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_check_type(input, &idx, 0x30, inSz);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilitihium_get_der_length(input, &idx, &length, inSz);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_check_type(input, &idx, 0x06, inSz);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilitihium_get_der_length(input, &idx, &length, inSz);
|
|
}
|
|
if (ret == 0) {
|
|
if ((length != oidLen) ||
|
|
(XMEMCMP(input + idx, oid, oidLen) != 0)) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
idx += oidLen;
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilithium_check_type(input, &idx, 0x03, inSz);
|
|
}
|
|
if (ret == 0) {
|
|
ret = dilitihium_get_der_length(input, &idx, &length, inSz);
|
|
}
|
|
if (ret == 0) {
|
|
if ((input[idx] != 0) || (length == 0)) {
|
|
ret = ASN_PARSE_E;
|
|
}
|
|
idx++;
|
|
length--;
|
|
}
|
|
if (ret == 0) {
|
|
/* This is the raw point data compressed or uncompressed. */
|
|
pubKeyLen = (word32)length;
|
|
pubKey = input + idx;
|
|
|
|
*inOutIdx += idx;
|
|
}
|
|
#endif
|
|
if (ret == 0) {
|
|
/* Import public key data. */
|
|
ret = wc_dilithium_import_public(pubKey, pubKeyLen, key);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
|
|
|
|
#ifdef WC_ENABLE_ASYM_KEY_EXPORT
|
|
/* Encode the public part of a Dilithium key in DER.
|
|
*
|
|
* Pass NULL for output to get the size of the encoding.
|
|
*
|
|
* @param [in] key Dilithium key object.
|
|
* @param [out] output Buffer to put encoded data in.
|
|
* @param [in] len Size of buffer in bytes.
|
|
* @param [in] withAlg Whether to use SubjectPublicKeyInfo format.
|
|
* @return Size of encoded data in bytes on success.
|
|
* @return BAD_FUNC_ARG when key is NULL.
|
|
* @return MEMORY_E when dynamic memory allocation failed.
|
|
*/
|
|
int wc_Dilithium_PublicKeyToDer(dilithium_key* key, byte* output, word32 len,
|
|
int withAlg)
|
|
{
|
|
int ret = 0;
|
|
int keyType = 0;
|
|
word32 pubKeyLen = 0;
|
|
|
|
/* Validate parameters. */
|
|
if (key == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
/* Check we have a public key to encode. */
|
|
if ((ret == 0) && (!key->pubKeySet)) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
/* Get OID and length for level. */
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL2k;
|
|
pubKeyLen = DILITHIUM_LEVEL2_PUB_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL3k;
|
|
pubKeyLen = DILITHIUM_LEVEL3_PUB_KEY_SIZE;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
keyType = DILITHIUM_LEVEL5k;
|
|
pubKeyLen = DILITHIUM_LEVEL5_PUB_KEY_SIZE;
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
keyType = ML_DSA_LEVEL2k;
|
|
pubKeyLen = ML_DSA_LEVEL2_PUB_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
keyType = ML_DSA_LEVEL3k;
|
|
pubKeyLen = ML_DSA_LEVEL3_PUB_KEY_SIZE;
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
keyType = ML_DSA_LEVEL5k;
|
|
pubKeyLen = ML_DSA_LEVEL5_PUB_KEY_SIZE;
|
|
}
|
|
else {
|
|
/* Level not set. */
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
|
|
if (ret == 0) {
|
|
ret = SetAsymKeyDerPublic(key->p, pubKeyLen, output, len, keyType,
|
|
withAlg);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WC_ENABLE_ASYM_KEY_EXPORT */
|
|
|
|
#endif /* !WOLFSSL_DILITHIUM_NO_ASN1 */
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_PUBLIC_KEY */
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PRIVATE_KEY
|
|
|
|
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
|
|
|
|
#ifdef WOLFSSL_DILITHIUM_PUBLIC_KEY
|
|
/* Encode the private and public data of a Dilithium key in DER.
|
|
*
|
|
* Pass NULL for output to get the size of the encoding.
|
|
*
|
|
* @param [in] key Dilithium key object.
|
|
* @param [out] output Buffer to put encoded data in.
|
|
* @param [in] len Size of buffer in bytes.
|
|
* @return Size of encoded data in bytes on success.
|
|
* @return BAD_FUNC_ARG when key is NULL.
|
|
* @return MEMORY_E when dynamic memory allocation failed.
|
|
*/
|
|
int wc_Dilithium_KeyToDer(dilithium_key* key, byte* output, word32 len)
|
|
{
|
|
int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
|
|
|
|
/* Validate parameters and check public and private key set. */
|
|
if ((key != NULL) && key->prvKeySet && key->pubKeySet) {
|
|
/* Create DER for level. */
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
ret = SetAsymKeyDer(key->k, DILITHIUM_LEVEL2_KEY_SIZE, key->p,
|
|
DILITHIUM_LEVEL2_PUB_KEY_SIZE, output, len, DILITHIUM_LEVEL2k);
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
ret = SetAsymKeyDer(key->k, DILITHIUM_LEVEL3_KEY_SIZE, key->p,
|
|
DILITHIUM_LEVEL3_PUB_KEY_SIZE, output, len, DILITHIUM_LEVEL3k);
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
ret = SetAsymKeyDer(key->k, DILITHIUM_LEVEL5_KEY_SIZE, key->p,
|
|
DILITHIUM_LEVEL5_PUB_KEY_SIZE, output, len, DILITHIUM_LEVEL5k);
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
ret = SetAsymKeyDer(key->k, ML_DSA_LEVEL2_KEY_SIZE, key->p,
|
|
ML_DSA_LEVEL2_PUB_KEY_SIZE, output, len, ML_DSA_LEVEL2k);
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
ret = SetAsymKeyDer(key->k, ML_DSA_LEVEL3_KEY_SIZE, key->p,
|
|
ML_DSA_LEVEL3_PUB_KEY_SIZE, output, len, ML_DSA_LEVEL3k);
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
ret = SetAsymKeyDer(key->k, ML_DSA_LEVEL5_KEY_SIZE, key->p,
|
|
ML_DSA_LEVEL5_PUB_KEY_SIZE, output, len, ML_DSA_LEVEL5k);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* WOLFSSL_DILITHIUM_PUBLIC_KEY */
|
|
|
|
/* Encode the private data of a Dilithium key in DER.
|
|
*
|
|
* Pass NULL for output to get the size of the encoding.
|
|
*
|
|
* @param [in] key Dilithium key object.
|
|
* @param [out] output Buffer to put encoded data in.
|
|
* @param [in] len Size of buffer in bytes.
|
|
* @return Size of encoded data in bytes on success.
|
|
* @return BAD_FUNC_ARG when key is NULL.
|
|
* @return MEMORY_E when dynamic memory allocation failed.
|
|
*/
|
|
int wc_Dilithium_PrivateKeyToDer(dilithium_key* key, byte* output, word32 len)
|
|
{
|
|
int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
|
|
|
|
/* Validate parameters and check private key set. */
|
|
if ((key != NULL) && key->prvKeySet) {
|
|
/* Create DER for level. */
|
|
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
|
|
if (key->params == NULL) {
|
|
ret = BAD_FUNC_ARG;
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_44_DRAFT) {
|
|
ret = SetAsymKeyDer(key->k, DILITHIUM_LEVEL2_KEY_SIZE, NULL, 0,
|
|
output, len, DILITHIUM_LEVEL2k);
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_65_DRAFT) {
|
|
ret = SetAsymKeyDer(key->k, DILITHIUM_LEVEL3_KEY_SIZE, NULL, 0,
|
|
output, len, DILITHIUM_LEVEL3k);
|
|
}
|
|
else if (key->params->level == WC_ML_DSA_87_DRAFT) {
|
|
ret = SetAsymKeyDer(key->k, DILITHIUM_LEVEL5_KEY_SIZE, NULL, 0,
|
|
output, len, DILITHIUM_LEVEL5k);
|
|
}
|
|
else
|
|
#endif
|
|
if (key->level == WC_ML_DSA_44) {
|
|
ret = SetAsymKeyDer(key->k, ML_DSA_LEVEL2_KEY_SIZE, NULL, 0, output,
|
|
len, ML_DSA_LEVEL2k);
|
|
}
|
|
else if (key->level == WC_ML_DSA_65) {
|
|
ret = SetAsymKeyDer(key->k, ML_DSA_LEVEL3_KEY_SIZE, NULL, 0, output,
|
|
len, ML_DSA_LEVEL3k);
|
|
}
|
|
else if (key->level == WC_ML_DSA_87) {
|
|
ret = SetAsymKeyDer(key->k, ML_DSA_LEVEL5_KEY_SIZE, NULL, 0, output,
|
|
len, ML_DSA_LEVEL5k);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_NO_ASN1 */
|
|
|
|
#endif /* WOLFSSL_DILITHIUM_PRIVATE_KEY */
|
|
|
|
#endif /* HAVE_DILITHIUM */
|