crypto/fipsmodule/ml_dsa/ml_dsa_ref/sign.c (366 lines of code) (raw):
#include "sign.h"
#include <stdint.h>
#include "../../../internal.h"
#include "openssl/rand.h"
#include "packing.h"
#include "params.h"
#include "poly.h"
#include "polyvec.h"
#if defined(AWSLC_FIPS)
/*************************************************
* [FIPS 140-3 IG](https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf)
*
* VE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs
*
* Purpose: Validates that a generated public/private key pair can correctly
* sign and verify data. Test performs signature generation using the private
* key (sk), followed by signature verification using the public key (pk).
* Returns 1 if the signature was successfully verified, 0 if it cannot.
*
* Note: FIPS 204 requires that public/private key pairs are to be used only for
* the calculation and/of verification of digital signatures.
**************************************************/
static int ml_dsa_keypair_pct(ml_dsa_params *params,
uint8_t *pk,
uint8_t *sk) {
uint8_t message[1] = {0};
uint8_t signature[MLDSA87_SIGNATURE_BYTES];
int ret = ml_dsa_sign(params, signature, ¶ms->bytes, message, sizeof(message), NULL, 0, sk);
if (ret < 0) {
return 0;
}
if (boringssl_fips_break_test("MLDSA_PWCT")) {
message[0] = ~message[0];
}
return ml_dsa_verify(params, signature, params->bytes, message, sizeof(message), NULL, 0, pk) == 0;
}
#endif
/*************************************************
* Name: ml_dsa_keypair_internal
*
* Description: FIPS 204: Algorithm 6 ML-DSA.KeyGen_internal.
* Generates public and private key. Internal API.
*
* Arguments: - ml_dsa_params: parameter struct
* - uint8_t *pk: pointer to output public key (allocated
* array of CRYPTO_PUBLICKEYBYTES bytes)
* - uint8_t *sk: pointer to output private key (allocated
* array of CRYPTO_SECRETKEYBYTES bytes)
* - const uint8_t *rnd: pointer to random seed
*
* Returns 0 (success) -1 on failure or abort depending on FIPS mode
**************************************************/
int ml_dsa_keypair_internal(ml_dsa_params *params,
uint8_t *pk,
uint8_t *sk,
const uint8_t *seed) {
uint8_t seedbuf[2 * ML_DSA_SEEDBYTES + ML_DSA_CRHBYTES];
uint8_t tr[ML_DSA_TRBYTES];
const uint8_t *rho, *rhoprime, *key;
polyvecl mat[ML_DSA_K_MAX];
polyvecl s1 = {{{{0}}}};
polyvecl s1hat;
polyveck s2, t1, t0;
OPENSSL_memcpy(seedbuf, seed, ML_DSA_SEEDBYTES);
seedbuf[ML_DSA_SEEDBYTES + 0] = params->k;
seedbuf[ML_DSA_SEEDBYTES + 1] = params->l;
SHAKE256(seedbuf, ML_DSA_SEEDBYTES + 2, seedbuf, 2 * ML_DSA_SEEDBYTES + ML_DSA_CRHBYTES);
rho = seedbuf;
rhoprime = rho + ML_DSA_SEEDBYTES;
key = rhoprime + ML_DSA_CRHBYTES;
/* FIPS 204: line 3 Expand matrix */
ml_dsa_polyvec_matrix_expand(params, mat, rho);
/* FIPS 204: line 4 Sample short vectors s1 and s2 */
ml_dsa_polyvecl_uniform_eta(params, &s1, rhoprime, 0);
ml_dsa_polyveck_uniform_eta(params, &s2, rhoprime, params->l);
/* FIPS 204: line 5 Matrix-vector multiplication */
s1hat = s1;
ml_dsa_polyvecl_ntt(params, &s1hat);
ml_dsa_polyvec_matrix_pointwise_montgomery(params, &t1, mat, &s1hat);
ml_dsa_polyveck_reduce(params, &t1);
ml_dsa_polyveck_invntt_tomont(params, &t1);
/* Add error vector s2 */
ml_dsa_polyveck_add(params, &t1, &t1, &s2);
/* FIPS 204: line 6 Extract t1 and write public key */
ml_dsa_polyveck_caddq(params, &t1);
ml_dsa_polyveck_power2round(params, &t1, &t0, &t1);
/* FIPS 204: line 8 */
ml_dsa_pack_pk(params, pk, rho, &t1);
/* FIPS 204: line 9 Compute H(rho, t1) and line 10 write secret key */
SHAKE256(pk, params->public_key_bytes, tr, ML_DSA_TRBYTES);
ml_dsa_pack_sk(params, sk, rho, tr, key, &t0, &s1, &s2);
/* FIPS 204. Section 3.6.3 Destruction of intermediate values. */
OPENSSL_cleanse(seedbuf, sizeof(seedbuf));
OPENSSL_cleanse(tr, sizeof(tr));
OPENSSL_cleanse(mat, sizeof(mat));
OPENSSL_cleanse(&s1, sizeof(s1));
OPENSSL_cleanse(&s1hat, sizeof(s1hat));
OPENSSL_cleanse(&s2, sizeof(s2));
OPENSSL_cleanse(&t1, sizeof(t1));
OPENSSL_cleanse(&t0, sizeof(t0));
#if defined(AWSLC_FIPS)
// Abort in case of PCT failure.
if (!ml_dsa_keypair_pct(params, pk, sk)) {
AWS_LC_FIPS_failure("ML-DSA keygen PCT failed");
return -1;
}
#endif
return 0;
}
/*************************************************
* Name: ml_dsa_keypair
*
* Description: FIPS 204: Algorithm 1 ML-DSA.KeyGen
* Generates public and private key.
*
* Arguments: - ml_dsa_params: parameter struct
* - uint8_t *pk: pointer to output public key (allocated
* array of CRYPTO_PUBLICKEYBYTES bytes)
* - uint8_t *sk: pointer to output private key (allocated
* array of CRYPTO_SECRETKEYBYTES bytes)
* - uint8_t *seed: pointer to output keygen seed (allocated
* array of ML_DSA_SEEDBYTES bytes)
*
* Returns 0 (success) -1 on failure
**************************************************/
int ml_dsa_keypair(ml_dsa_params *params, uint8_t *pk, uint8_t *sk, uint8_t *seed) {
if (!RAND_bytes(seed, ML_DSA_SEEDBYTES)) {
return -1;
}
int result = ml_dsa_keypair_internal(params, pk, sk, seed);
return result;
}
/*************************************************
* Name: ml_dsa_sign_internal
*
* Description: FIPS 204: Algorithm 7 ML-DSA.Sign_internal.
* Computes signature. Internal API.
*
* Arguments: - ml_dsa_params: parameter struct
* - uint8_t *sig: pointer to output signature (of length CRYPTO_BYTES)
* - size_t *siglen: pointer to output length of signature
* - uint8_t *m: pointer to message to be signed
* - size_t mlen: length of message
* - uint8_t *pre: pointer to prefix string
* - size_t prelen: length of prefix string
* - uint8_t *rnd: pointer to random seed
* - uint8_t *sk: pointer to bit-packed secret key
* - int external_mu: indicates input message m is to be processed as mu
*
* Returns 0 (success) or -1 (context string too long)
**************************************************/
int ml_dsa_sign_internal(ml_dsa_params *params,
uint8_t *sig,
size_t *siglen,
const uint8_t *m,
size_t mlen,
const uint8_t *pre,
size_t prelen,
const uint8_t *rnd,
const uint8_t *sk,
int external_mu)
{
unsigned int n;
uint8_t seedbuf[2*ML_DSA_SEEDBYTES + ML_DSA_TRBYTES + 2*ML_DSA_CRHBYTES];
uint8_t *rho, *tr, *key, *mu, *rhoprime;
uint16_t nonce = 0;
polyvecl mat[ML_DSA_K_MAX], s1, y, z;
polyveck t0, s2, w1, w0, h;
ml_dsa_poly cp;
KECCAK1600_CTX state;
rho = seedbuf;
tr = rho + ML_DSA_SEEDBYTES;
key = tr + ML_DSA_TRBYTES;
mu = key + ML_DSA_SEEDBYTES;
rhoprime = mu + ML_DSA_CRHBYTES;
/* FIPS 204: line 1 */
ml_dsa_unpack_sk(params, rho, tr, key, &t0, &s1, &s2, sk);
/* FIPS 204: line 6 Compute mu = CRH(tr, pre, msg) */
// This differs from FIPS 204 line 6 that performs mu = CRH(tr, M') and the
// processing of M' in the external function. However, as M' = (pre, msg),
// mu = CRH(tr, M') = CRH(tr, pre, msg).
if (!external_mu) {
//constuct mu = h(tr | m') when not in prehash mode
SHAKE_Init(&state, SHAKE256_BLOCKSIZE);
SHAKE_Absorb(&state, tr, ML_DSA_TRBYTES);
SHAKE_Absorb(&state, pre, prelen);
SHAKE_Absorb(&state, m, mlen);
SHAKE_Final(mu, &state, ML_DSA_CRHBYTES);
}
else {
OPENSSL_memcpy(mu, m, mlen);
}
/* FIPS 204: line 7 Compute rhoprime = CRH(key, rnd, mu) */
SHAKE_Init(&state, SHAKE256_BLOCKSIZE);
SHAKE_Absorb(&state, key, ML_DSA_SEEDBYTES);
SHAKE_Absorb(&state, rnd, ML_DSA_RNDBYTES);
SHAKE_Absorb(&state, mu, ML_DSA_CRHBYTES);
SHAKE_Final(rhoprime, &state, ML_DSA_CRHBYTES);
/* FIPS 204: line 5 Expand matrix and transform vectors */
ml_dsa_polyvec_matrix_expand(params, mat, rho);
ml_dsa_polyvecl_ntt(params, &s1);
ml_dsa_polyveck_ntt(params, &s2);
ml_dsa_polyveck_ntt(params, &t0);
rej:
/* FIPS 204: line 11 Sample intermediate vector y */
ml_dsa_polyvecl_uniform_gamma1(params, &y, rhoprime, nonce++);
/* FIPS 204: line 12 Matrix-vector multiplication */
z = y;
ml_dsa_polyvecl_ntt(params, &z);
ml_dsa_polyvec_matrix_pointwise_montgomery(params, &w1, mat, &z);
ml_dsa_polyveck_reduce(params, &w1);
ml_dsa_polyveck_invntt_tomont(params, &w1);
/* FIPS 204: line 13 - 14 Decompose w and call the random oracle */
ml_dsa_polyveck_caddq(params, &w1);
ml_dsa_polyveck_decompose(params, &w1, &w0, &w1);
ml_dsa_polyveck_pack_w1(params, sig, &w1);
SHAKE_Init(&state, SHAKE256_BLOCKSIZE);
SHAKE_Absorb(&state, mu, ML_DSA_CRHBYTES);
SHAKE_Absorb(&state, sig, params->k * params->poly_w1_packed_bytes);
SHAKE_Final(sig, &state, params->c_tilde_bytes);
ml_dsa_poly_challenge(params, &cp, sig);
ml_dsa_poly_ntt(&cp);
/* FIPS 204: line 20 Compute z, reject if it reveals secret */
ml_dsa_polyvecl_pointwise_poly_montgomery(params, &z, &cp, &s1);
ml_dsa_polyvecl_invntt_tomont(params, &z);
ml_dsa_polyvecl_add(params, &z, &z, &y);
ml_dsa_polyvecl_reduce(params, &z);
if(ml_dsa_polyvecl_chknorm(params, &z, params->gamma1 - params->beta)) {
goto rej;
}
/* FIPS 204: line 21 Check that subtracting cs2 does not change high bits of w and low bits
* do not reveal secret information */
ml_dsa_polyveck_pointwise_poly_montgomery(params, &h, &cp, &s2);
ml_dsa_polyveck_invntt_tomont(params, &h);
ml_dsa_polyveck_sub(params, &w0, &w0, &h);
ml_dsa_polyveck_reduce(params, &w0);
if(ml_dsa_polyveck_chknorm(params, &w0, params->gamma2 - params->beta)) {
goto rej;
}
/* FIPS 204: line 25 */
ml_dsa_polyveck_pointwise_poly_montgomery(params, &h, &cp, &t0);
ml_dsa_polyveck_invntt_tomont(params, &h);
ml_dsa_polyveck_reduce(params, &h);
if(ml_dsa_polyveck_chknorm(params, &h, params->gamma2)) {
goto rej;
}
/* FIPS 204: line 26 Compute signer's hint */
ml_dsa_polyveck_add(params, &w0, &w0, &h);
n = ml_dsa_polyveck_make_hint(params, &h, &w0, &w1);
if(n > params->omega) {
goto rej;
}
/* FIPS 204: line 33 Write signature */
ml_dsa_pack_sig(params, sig, sig, &z, &h);
*siglen = params->bytes;
/* FIPS 204. Section 3.6.3 Destruction of intermediate values. */
OPENSSL_cleanse(seedbuf, sizeof(seedbuf));
OPENSSL_cleanse(&nonce, sizeof(nonce));
OPENSSL_cleanse(mat, sizeof(mat));
OPENSSL_cleanse(&s1, sizeof(s1));
OPENSSL_cleanse(&y, sizeof(y));
OPENSSL_cleanse(&z, sizeof(z));
OPENSSL_cleanse(&t0, sizeof(t0));
OPENSSL_cleanse(&s2, sizeof(s2));
OPENSSL_cleanse(&w1, sizeof(w1));
OPENSSL_cleanse(&w0, sizeof(w0));
OPENSSL_cleanse(&h, sizeof(h));
OPENSSL_cleanse(&cp, sizeof(cp));
OPENSSL_cleanse(&state, sizeof(state));
return 0;
}
/*************************************************
* Name: ml_dsa_sign
*
* Description: FIPS 204: Algorithm 2 ML-DSA.Sign.
* Computes signature in hedged mode.
*
* Arguments: - uint8_t *sig: pointer to output signature (of length CRYPTO_BYTES)
* - size_t *siglen: pointer to output length of signature
* - uint8_t *m: pointer to message to be signed
* - size_t mlen: length of message
* - uint8_t *ctx: pointer to contex string
* - size_t ctxlen: length of contex string
* - uint8_t *sk: pointer to bit-packed secret key
*
* Returns 0 (success) or -1 (context string too long)
**************************************************/
int ml_dsa_sign(ml_dsa_params *params,
uint8_t *sig,
size_t *siglen,
const uint8_t *m,
size_t mlen,
const uint8_t *ctx,
size_t ctxlen,
const uint8_t *sk)
{
uint8_t pre[257];
uint8_t rnd[ML_DSA_RNDBYTES];
if(ctxlen > 255) {
return -1;
}
/* Prepare pre = (0, ctxlen, ctx) */
pre[0] = 0;
pre[1] = ctxlen;
OPENSSL_memcpy(pre + 2 , ctx, ctxlen);
if (!RAND_bytes(rnd, ML_DSA_RNDBYTES)) {
return -1;
}
ml_dsa_sign_internal(params, sig, siglen, m, mlen, pre, 2 + ctxlen, rnd, sk, 0);
/* FIPS 204. Section 3.6.3 Destruction of intermediate values. */
OPENSSL_cleanse(pre, sizeof(pre));
OPENSSL_cleanse(rnd, sizeof(rnd));
return 0;
}
/*************************************************
* Name: ml_dsa_extmu_sign
*
* Description: FIPS 204: Algorithm 2 ML-DSA.Sign external mu variant.
* Computes signature in hedged mode.
*
* Arguments: - uint8_t *sig: pointer to output signature (of length CRYPTO_BYTES)
* - size_t *siglen: pointer to output length of signature
* - uint8_t *mu: pointer to input mu to be signed
* - size_t mulen: length of mu
* - uint8_t *sk: pointer to bit-packed secret key
*
* Returns 0 (success) or -1 (context string too long)
**************************************************/
int ml_dsa_extmu_sign(ml_dsa_params *params,
uint8_t *sig,
size_t *siglen,
const uint8_t *mu,
size_t mulen,
const uint8_t *sk)
{
uint8_t rnd[ML_DSA_RNDBYTES];
if (!RAND_bytes(rnd, ML_DSA_RNDBYTES)) {
return -1;
}
ml_dsa_sign_internal(params, sig, siglen, mu, mulen, NULL, 0, rnd, sk, 1);
/* FIPS 204. Section 3.6.3 Destruction of intermediate values. */
OPENSSL_cleanse(rnd, sizeof(rnd));
return 0;
}
/*************************************************
* Name: ml_dsa_sign_message
*
* Description: Compute signed message.
*
* Arguments: - ml_dsa_params: parameter struct
* - uint8_t *sm: pointer to output signed message (allocated
* array with CRYPTO_BYTES + mlen bytes),
* can be equal to m
* - size_t *smlen: pointer to output length of signed
* message
* - const uint8_t *m: pointer to message to be signed
* - size_t mlen: length of message
* - const uint8_t *ctx: pointer to context string
* - size_t ctxlen: length of context string
* - const uint8_t *sk: pointer to bit-packed secret key
*
* Returns 0 (success) or -1 (context string too long)
**************************************************/
int ml_dsa_sign_message(ml_dsa_params *params,
uint8_t *sm,
size_t *smlen,
const uint8_t *m,
size_t mlen,
const uint8_t *ctx,
size_t ctxlen,
const uint8_t *sk)
{
int ret;
size_t i;
for(i = 0; i < mlen; ++i) {
sm[params->bytes + mlen - 1 - i] = m[mlen - 1 - i];
}
ret = ml_dsa_sign(params, sm, smlen, sm + params->bytes, mlen, ctx, ctxlen, sk);
*smlen += mlen;
return ret;
}
/*************************************************
* Name: ml_dsa_verify_internal
*
* Description: FIPS 204: Algorithm 8 ML-DSA.Verify_internal.
* Verifies signature. Internal API.
*
* Arguments: - ml_dsa_params: parameter struct
* - uint8_t *m: pointer to input signature
* - size_t siglen: length of signature
* - const uint8_t *m: pointer to message
* - size_t mlen: length of message
* - const uint8_t *pre: pointer to prefix string
* - size_t prelen: length of prefix string
* - const uint8_t *pk: pointer to bit-packed public key
* - int external_mu: indicates input message m is to be processed as mu
*
* Returns 0 if signature could be verified correctly and -1 otherwise
**************************************************/
int ml_dsa_verify_internal(ml_dsa_params *params,
const uint8_t *sig,
size_t siglen,
const uint8_t *m,
size_t mlen,
const uint8_t *pre,
size_t prelen,
const uint8_t *pk,
int external_mu)
{
unsigned int i;
uint8_t buf[ML_DSA_K_MAX*ML_DSA_POLYW1_PACKEDBYTES_MAX];
uint8_t rho[ML_DSA_SEEDBYTES];
uint8_t mu[ML_DSA_CRHBYTES];
uint8_t tr[ML_DSA_TRBYTES];
uint8_t c[ML_DSA_C_TILDE_BYTES_MAX];
uint8_t c2[ML_DSA_C_TILDE_BYTES_MAX];
ml_dsa_poly cp;
polyvecl mat[ML_DSA_K_MAX], z;
polyveck t1, w1, h;
KECCAK1600_CTX state;
if(siglen != params->bytes) {
return -1;
}
/* FIPS 204: line 1 */
ml_dsa_unpack_pk(params, rho, &t1, pk);
/* FIPS 204: line 2 */
if(ml_dsa_unpack_sig(params, c, &z, &h, sig)) {
return -1;
}
if(ml_dsa_polyvecl_chknorm(params, &z, params->gamma1 - params->beta)) {
return -1;
}
if(!external_mu) {
/* FIPS 204: line 6 Compute tr */
SHAKE256(pk, params->public_key_bytes, tr, ML_DSA_TRBYTES);
/* FIPS 204: line 7 Compute mu = H(BytesToBits(tr) || M', 64) */
// Like crypto_sign_signature_internal, the processing of M' is performed
// here, as opposed to within the external function.
SHAKE_Init(&state, SHAKE256_BLOCKSIZE);
SHAKE_Absorb(&state, tr, ML_DSA_TRBYTES);
SHAKE_Absorb(&state, pre, prelen);
SHAKE_Absorb(&state, m, mlen);
SHAKE_Final(mu, &state, ML_DSA_CRHBYTES);
}
else {
OPENSSL_memcpy(mu, m, mlen);
}
/* FIPS 204: line 9 Matrix-vector multiplication; compute Az - c2^dt1 */
ml_dsa_poly_challenge(params, &cp, c);
ml_dsa_polyvec_matrix_expand(params, mat, rho);
ml_dsa_polyvecl_ntt(params, &z);
ml_dsa_polyvec_matrix_pointwise_montgomery(params, &w1, mat, &z);
ml_dsa_poly_ntt(&cp);
ml_dsa_polyveck_shiftl(params, &t1);
ml_dsa_polyveck_ntt(params, &t1);
ml_dsa_polyveck_pointwise_poly_montgomery(params, &t1, &cp, &t1);
ml_dsa_polyveck_sub(params, &w1, &w1, &t1);
ml_dsa_polyveck_reduce(params, &w1);
ml_dsa_polyveck_invntt_tomont(params, &w1);
/* FIPS 204: line 10 Reconstruct w1 */
ml_dsa_polyveck_caddq(params, &w1);
ml_dsa_polyveck_use_hint(params, &w1, &w1, &h);
ml_dsa_polyveck_pack_w1(params, buf, &w1);
/* FIPS 204: line 12 Call random oracle and verify challenge */
SHAKE_Init(&state, SHAKE256_BLOCKSIZE);
SHAKE_Absorb(&state, mu, ML_DSA_CRHBYTES);
SHAKE_Absorb(&state, buf, params->k * params->poly_w1_packed_bytes);
SHAKE_Final(c2, &state, params->c_tilde_bytes);
for(i = 0; i < params->c_tilde_bytes; ++i) {
if(c[i] != c2[i]) {
return -1;
}
}
/* FIPS 204. Section 3.6.3 Destruction of intermediate values. */
OPENSSL_cleanse(buf, sizeof(buf));
OPENSSL_cleanse(rho, sizeof(rho));
OPENSSL_cleanse(mu, sizeof(mu));
OPENSSL_cleanse(tr, sizeof(tr));
OPENSSL_cleanse(c, sizeof(c));
OPENSSL_cleanse(c2, sizeof(c2));
OPENSSL_cleanse(&cp, sizeof(cp));
OPENSSL_cleanse(mat, sizeof(mat));
OPENSSL_cleanse(&z, sizeof(z));
OPENSSL_cleanse(&t1, sizeof(t1));
OPENSSL_cleanse(&w1, sizeof(w1));
OPENSSL_cleanse(&h, sizeof(h));
OPENSSL_cleanse(&state, sizeof(state));
return 0;
}
/*************************************************
* Name: ml_dsa_verify
*
* Description: FIPS 204: Algorithm 3 ML-DSA.Verify.
* Verifies signature.
*
* Arguments: - ml_dsa_params: parameter struct
* - uint8_t *m: pointer to input signature
* - size_t siglen: length of signature
* - const uint8_t *m: pointer to message
* - size_t mlen: length of message
* - const uint8_t *ctx: pointer to context string
* - size_t ctxlen: length of context string
* - const uint8_t *pk: pointer to bit-packed public key
*
* Returns 0 if signature could be verified correctly and -1 otherwise
**************************************************/
int ml_dsa_verify(ml_dsa_params *params,
const uint8_t *sig,
size_t siglen,
const uint8_t *m,
size_t mlen,
const uint8_t *ctx,
size_t ctxlen,
const uint8_t *pk)
{
uint8_t pre[257];
if(ctxlen > 255) {
return -1;
}
pre[0] = 0;
pre[1] = ctxlen;
OPENSSL_memcpy(pre + 2 , ctx, ctxlen);
return ml_dsa_verify_internal(params, sig, siglen, m, mlen, pre, 2 + ctxlen, pk, 0);
}
/*************************************************
* Name: ml_dsa_verify_message
*
* Description: Verify signed message.
*
* Arguments: - ml_dsa_params: parameter struct
* - uint8_t *m: pointer to output message (allocated
* array with smlen bytes), can be equal to sm
* - size_t *mlen: pointer to output length of message
* - const uint8_t *sm: pointer to signed message
* - size_t smlen: length of signed message
* - const uint8_t *ctx: pointer to context tring
* - size_t ctxlen: length of context string
* - const uint8_t *pk: pointer to bit-packed public key
*
* Returns 0 if signed message could be verified correctly and -1 otherwise
**************************************************/
int ml_dsa_verify_message(ml_dsa_params *params,
uint8_t *m,
size_t *mlen,
const uint8_t *sm,
size_t smlen,
const uint8_t *ctx,
size_t ctxlen,
const uint8_t *pk)
{
if(smlen < params->bytes) {
goto badsig;
}
*mlen = smlen - params->bytes;
if(ml_dsa_verify(params,sm, params->bytes, sm + params->bytes, *mlen, ctx, ctxlen, pk)) {
goto badsig;
}
else {
/* All good, copy msg, return 0 */
for(size_t i = 0; i < *mlen; ++i) {
m[i] = sm[params->bytes + i];
}
return 0;
}
badsig:
/* Signature verification failed */
*mlen = 0;
for(size_t i = 0; i < smlen; ++i) {
m[i] = 0;
}
return -1;
}