* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "hitls_build.h"
#ifdef HITLS_CRYPTO_MLDSA
#include <string.h>
#include "bsl_errno.h"
#include "bsl_sal.h"
#include "crypt_utils.h"
#include "crypt_sha3.h"
#include "crypt_errno.h"
#include "crypt_util_rand.h"
#include "bsl_err_internal.h"
#include "ml_dsa_local.h"
#include "eal_md_local.h"
#ifdef HITLS_CRYPTO_MLDSA_X2
#include "asm_sha3.h"
#endif
#define BITS_OF_BYTE 8
#define MLDSA_SET_VECTOR_MEM(ptr, buf) {ptr = buf; buf += MLDSA_N;}
static int32_t MLDSAInitHashCtx(int32_t mdId, const EAL_MdMethod **hashMethod, void **mdCtx)
{
const EAL_MdMethod *method = EAL_MdFindDefaultMethod(mdId);
if (method == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_EAL_ALG_NOT_SUPPORT);
return CRYPT_EAL_ALG_NOT_SUPPORT;
}
void *ctx = method->newCtx(NULL, method->id);
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return CRYPT_MEM_ALLOC_FAIL;
}
int32_t ret = method->init(ctx, NULL);
if (ret != CRYPT_SUCCESS) {
method->freeCtx(ctx);
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
*hashMethod = method;
*mdCtx = ctx;
return CRYPT_SUCCESS;
}
static int32_t HashFuncH(const uint8_t *inPutA, uint32_t lenA, const uint8_t *inPutB, uint32_t lenB,
uint8_t *out, uint32_t outLen)
{
uint32_t len = outLen;
int32_t ret = 0;
const EAL_MdMethod *hashMethod = NULL;
void *mdCtx = NULL;
RETURN_RET_IF_ERR_EX(MLDSAInitHashCtx(CRYPT_MD_SHAKE256, &hashMethod, &mdCtx), ret);
GOTO_ERR_IF(hashMethod->update(mdCtx, inPutA, lenA), ret);
if (inPutB != NULL) {
GOTO_ERR_IF(hashMethod->update(mdCtx, inPutB, lenB), ret);
}
GOTO_ERR_IF(hashMethod->final(mdCtx, out, &len), ret);
ERR:
hashMethod->freeCtx(mdCtx);
return ret;
}
typedef struct {
int32_t *bufAddr;
uint32_t bufSize;
int32_t *matrix[MLDSA_L_MAX];
int32_t *s2[MLDSA_K_MAX];
int32_t *t0[MLDSA_K_MAX];
int32_t *t1[MLDSA_K_MAX];
int32_t *s1[MLDSA_L_MAX];
int32_t *s1Ntt[MLDSA_L_MAX];
} MLDSA_KeyGenMatrixSt;
static void MLDSASetMatrixMem(uint8_t k, uint8_t l, int32_t *matrix[MLDSA_K_MAX][MLDSA_L_MAX], int32_t *buf)
{
for (uint8_t i = 0; i < k; i++) {
for (uint8_t j = 0; j < l; j++) {
matrix[i][j] = buf;
buf += MLDSA_N;
}
}
}
static int32_t MLDSAKeyGenCreateMatrix(uint8_t k, uint8_t l, MLDSA_KeyGenMatrixSt *st)
{
st->bufSize = (3 * k + 3 * l) * MLDSA_N * sizeof(int32_t);
int32_t *buf = BSL_SAL_Malloc(st->bufSize);
if (buf == NULL) {
return BSL_MALLOC_FAIL;
}
st->bufAddr = buf;
for (uint8_t i = 0; i < k; i++) {
MLDSA_SET_VECTOR_MEM(st->t0[i], buf);
MLDSA_SET_VECTOR_MEM(st->t1[i], buf);
MLDSA_SET_VECTOR_MEM(st->s2[i], buf);
}
for (uint8_t i = 0; i < l; i++) {
MLDSA_SET_VECTOR_MEM(st->matrix[i], buf);
}
for (uint8_t i = 0; i < l; i++) {
MLDSA_SET_VECTOR_MEM(st->s1[i], buf);
}
for (uint8_t i = 0; i < l; i++) {
MLDSA_SET_VECTOR_MEM(st->s1Ntt[i], buf);
}
return CRYPT_SUCCESS;
}
typedef struct {
int32_t *bufAddr;
uint32_t bufSize;
int32_t *matrix[MLDSA_K_MAX][MLDSA_L_MAX];
int32_t *t0[MLDSA_K_MAX];
int32_t *r0[MLDSA_K_MAX];
int32_t *s2[MLDSA_K_MAX];
int32_t *w[MLDSA_K_MAX];
int32_t *w1[MLDSA_K_MAX];
int32_t *y[MLDSA_K_MAX];
int32_t *s1[MLDSA_L_MAX];
int32_t *z[MLDSA_L_MAX];
} MLDSA_SignMatrixSt;
static int32_t MLDSASignCreateMatrix(uint8_t k, uint8_t l, MLDSA_SignMatrixSt *st)
{
st->bufSize = (k * l + 6 * k + 2 * l) * MLDSA_N * sizeof(int32_t);
int32_t *buf = BSL_SAL_Malloc(st->bufSize);
if (buf == NULL) {
return BSL_MALLOC_FAIL;
}
st->bufAddr = buf;
MLDSASetMatrixMem(k, l, st->matrix, buf);
buf += k * l * MLDSA_N;
for (uint8_t i = 0; i < k; i++) {
MLDSA_SET_VECTOR_MEM(st->r0[i], buf);
MLDSA_SET_VECTOR_MEM(st->t0[i], buf);
MLDSA_SET_VECTOR_MEM(st->s2[i], buf);
MLDSA_SET_VECTOR_MEM(st->w[i], buf);
MLDSA_SET_VECTOR_MEM(st->w1[i], buf);
}
for (uint8_t i = 0; i < k; i++) {
MLDSA_SET_VECTOR_MEM(st->y[i], buf);
}
for (uint8_t i = 0; i < l; i++) {
MLDSA_SET_VECTOR_MEM(st->s1[i], buf);
}
for (uint8_t i = 0; i < l; i++) {
MLDSA_SET_VECTOR_MEM(st->z[i], buf);
}
return CRYPT_SUCCESS;
}
typedef struct {
int32_t *bufAddr;
uint32_t bufSize;
int32_t *matrix[MLDSA_L_MAX];
int32_t *t1[MLDSA_K_MAX];
int32_t *h[MLDSA_K_MAX];
int32_t *w[MLDSA_K_MAX];
int32_t *z[MLDSA_L_MAX];
} MLDSA_VerifyMatrixSt;
static int32_t MLDSAVerifyCreateMatrix(uint8_t k, uint8_t l, MLDSA_VerifyMatrixSt *st)
{
st->bufSize = (3 * k + 2 * l) * MLDSA_N * sizeof(int32_t);
int32_t *buf = BSL_SAL_Malloc(st->bufSize);
if (buf == NULL) {
return BSL_MALLOC_FAIL;
}
st->bufAddr = buf;
for (uint8_t i = 0; i < k; i++) {
MLDSA_SET_VECTOR_MEM(st->t1[i], buf);
MLDSA_SET_VECTOR_MEM(st->h[i], buf);
MLDSA_SET_VECTOR_MEM(st->w[i], buf);
}
for (uint8_t i = 0; i < l; i++) {
MLDSA_SET_VECTOR_MEM(st->matrix[i], buf);
}
for (uint8_t i = 0; i < l; i++) {
MLDSA_SET_VECTOR_MEM(st->z[i], buf);
}
return CRYPT_SUCCESS;
}
static int32_t ExpandA(const CRYPT_ML_DSA_Ctx *ctx, const uint8_t *pubSeed, int32_t *matrix[MLDSA_K_MAX][MLDSA_L_MAX])
{
uint8_t k = ctx->info->k;
uint8_t l = ctx->info->l;
uint8_t seed[MLDSA_SEED_EXTEND_BYTES_LEN];
memcpy(seed, pubSeed, MLDSA_PUBLIC_SEED_LEN);
for (uint8_t i = 0; i < k; i++) {
uint8_t j = 0;
#ifdef HITLS_CRYPTO_MLDSA_X2
* (j, i) differ. Reuse a second stack buffer for the pair seed. */
uint8_t seed1[MLDSA_SEED_EXTEND_BYTES_LEN];
memcpy(seed1, pubSeed, MLDSA_PUBLIC_SEED_LEN);
seed1[MLDSA_PUBLIC_SEED_LEN + 1] = i;
for (; j + 1 < l; j += 2) {
seed[MLDSA_PUBLIC_SEED_LEN] = j;
seed[MLDSA_PUBLIC_SEED_LEN + 1] = i;
seed1[MLDSA_PUBLIC_SEED_LEN] = j + 1;
int32_t ret = MLDSA_RejNTTPolyPair(matrix[i][j], matrix[i][j + 1], seed, seed1);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
#endif
for (; j < l; j++) {
seed[MLDSA_PUBLIC_SEED_LEN] = j;
seed[MLDSA_PUBLIC_SEED_LEN + 1] = i;
int32_t ret = MLDSA_RejNTTPoly(matrix[i][j], seed);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
}
return CRYPT_SUCCESS;
}
static int32_t ExpandS(const CRYPT_ML_DSA_Ctx *ctx, const uint8_t *prvSeed,
int32_t *s1[MLDSA_L_MAX], int32_t *s2[MLDSA_K_MAX])
{
int32_t ret;
uint8_t k = ctx->info->k;
uint8_t l = ctx->info->l;
uint8_t seed[MLDSA_PRIVATE_SEED_LEN + 2];
memcpy(seed, prvSeed, MLDSA_PRIVATE_SEED_LEN);
seed[MLDSA_PRIVATE_SEED_LEN + 1] = 0;
int32_t (*rejBoundedPoly)(int32_t *a, const uint8_t *s);
if (ctx->info->eta == 2) {
rejBoundedPoly = MLDSA_RejBoundedPolyEta2;
} else {
rejBoundedPoly = MLDSA_RejBoundedPolyEta4;
}
#ifdef HITLS_CRYPTO_MLDSA_X2
int32_t (*rejBoundedPolyPair)(int32_t *, int32_t *, const uint8_t *, const uint8_t *);
rejBoundedPolyPair = (ctx->info->eta == 2) ?
MLDSA_RejBoundedPolyEta2Pair : MLDSA_RejBoundedPolyEta4Pair;
uint8_t seed1[MLDSA_PRIVATE_SEED_LEN + 2];
memcpy(seed1, prvSeed, MLDSA_PRIVATE_SEED_LEN);
seed1[MLDSA_PRIVATE_SEED_LEN + 1] = 0;
uint8_t i = 0;
for (; i + 1 < l; i += 2) {
seed[MLDSA_PRIVATE_SEED_LEN] = i;
seed1[MLDSA_PRIVATE_SEED_LEN] = i + 1;
ret = rejBoundedPolyPair(s1[i], s1[i + 1], seed, seed1);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
for (; i < l; i++) {
seed[MLDSA_PRIVATE_SEED_LEN] = i;
ret = rejBoundedPoly(s1[i], seed);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
uint8_t j = 0;
for (; j + 1 < k; j += 2) {
seed[MLDSA_PRIVATE_SEED_LEN] = l + j;
seed1[MLDSA_PRIVATE_SEED_LEN] = l + j + 1;
ret = rejBoundedPolyPair(s2[j], s2[j + 1], seed, seed1);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
for (; j < k; j++) {
seed[MLDSA_PRIVATE_SEED_LEN] = l + j;
ret = rejBoundedPoly(s2[j], seed);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
#else
for (uint8_t i = 0; i < l; i++) {
seed[MLDSA_PRIVATE_SEED_LEN] = i;
ret = rejBoundedPoly(s1[i], seed);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
for (uint8_t i = 0; i < k; i++) {
seed[MLDSA_PRIVATE_SEED_LEN] = l + i;
ret = rejBoundedPoly(s2[i], seed);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
#endif
return CRYPT_SUCCESS;
}
static void ComputesNTT(const CRYPT_ML_DSA_Ctx *ctx, int32_t *const s[MLDSA_L_MAX], int32_t *sOut[MLDSA_L_MAX])
{
for (uint8_t i = 0; i < ctx->info->l; i++) {
memcpy(sOut[i], s[i], sizeof(int32_t) * MLDSA_N);
MLDSA_ComputesNTT(sOut[i]);
}
}
static int32_t ComputesT(const CRYPT_ML_DSA_Ctx *ctx, int32_t *t[MLDSA_K_MAX], MLDSA_KeyGenMatrixSt *st, uint8_t*pub)
{
uint8_t seed[MLDSA_SEED_EXTEND_BYTES_LEN];
(void)memcpy(seed, pub, MLDSA_PUBLIC_SEED_LEN);
for (uint8_t i = 0; i < ctx->info->k; i++) {
uint8_t j = 0;
#ifdef HITLS_CRYPTO_MLDSA_X2
* prefix with seed; only the column index byte differs. */
uint8_t seed1[MLDSA_SEED_EXTEND_BYTES_LEN];
memcpy(seed1, pub, MLDSA_PUBLIC_SEED_LEN);
seed1[MLDSA_PUBLIC_SEED_LEN + 1] = i;
for (; j + 1 < ctx->info->l; j += 2) {
seed[MLDSA_PUBLIC_SEED_LEN] = j;
seed[MLDSA_PUBLIC_SEED_LEN + 1] = i;
seed1[MLDSA_PUBLIC_SEED_LEN] = j + 1;
int32_t ret = MLDSA_RejNTTPolyPair(st->matrix[j], st->matrix[j + 1], seed, seed1);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
#endif
for (; j < ctx->info->l; j++) {
seed[MLDSA_PUBLIC_SEED_LEN] = j;
seed[MLDSA_PUBLIC_SEED_LEN + 1] = i;
int32_t ret = MLDSA_RejNTTPoly(st->matrix[j], seed);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
MLDSA_MatrixMul(ctx, t[i], st->matrix, st->s1Ntt);
MLDSA_ComputesINVNTT(t[i]);
MLDSA_VectorsAddQ(t[i], t[i], st->s2[i]);
}
return CRYPT_SUCCESS;
}
static void ByteEncode(uint8_t *buf, const uint32_t *t, uint32_t bits)
{
if (bits == 10u) {
for (uint32_t i = 0; i < MLDSA_N / 4; i++) {
buf[5 * i + 0] = (uint8_t)(t[4 * i + 0] >> 0);
buf[5 * i + 1u] = (uint8_t)((t[4 * i + 0] >> 8u) | (t[4 * i + 1u] << 2u));
buf[5 * i + 2u] = (uint8_t)((t[4 * i + 1u] >> 6u) | (t[4 * i + 2u] << 4u));
buf[5 * i + 3u] = (uint8_t)((t[4 * i + 2u] >> 4u) | (t[4 * i + 3u] << 6u));
buf[5 * i + 4u] = (uint8_t)(t[4 * i + 3u] >> 2u);
}
} else if (bits == 6u) {
for (uint32_t i = 0; i < MLDSA_N / 4; i++) {
buf[3 * i + 0] = (uint8_t)(t[4 * i] | (t[4 * i + 1] << 6u));
buf[3 * i + 1u] = (uint8_t)(t[4 * i + 1u] >> 2 | (t[4 * i + 2u] << 4u));
buf[3 * i + 2u] = (uint8_t)(t[4 * i + 2u] >> 4 | (t[4 * i + 3u] << 2u));
}
} else if (bits == 4u) {
for (uint32_t i = 0; i < MLDSA_N / 2; i++) {
buf[i] = (uint8_t)(t[2 * i] | (t[2 * i + 1] << 4u));
}
}
}
static void ByteDecode(const uint8_t *buf, uint32_t *t, uint32_t bits)
{
if (bits == 10u) {
for (uint32_t i = 0; i < MLDSA_N / 4; i++) {
t[4 * i + 0] = (buf[5 * i + 0] | ((uint32_t)buf[5 * i + 1] << 8)) & 0x03ff;
t[4 * i + 1u] = ((buf[5 * i + 1u] >> 2u) | ((uint32_t)buf[5 * i + 2u] << 6u)) & 0x03ff;
t[4 * i + 2u] = ((buf[5 * i + 2u] >> 4u) | ((uint32_t)buf[5 * i + 3u] << 4u)) & 0x03ff;
t[4 * i + 3u] = ((buf[5 * i + 3u] >> 6u) | ((uint32_t)buf[5 * i + 4u] << 2u)) & 0x03ff;
}
}
}
static void BitPack(uint8_t *buf, const uint32_t w[MLDSA_N], uint32_t bits, uint32_t b)
{
uint32_t t[8] = {0};
uint32_t i;
uint32_t n;
if (bits == 3u) {
for (i = 0; i < MLDSA_N / 8; i++) {
for (uint32_t j = 0; j < 8; j++) {
t[j] = b - (uint32_t)w[i * 8 + j];
}
n = bits * i;
buf[n + 0] = (uint8_t)((t[0]) | (t[1] << 3u) | (t[2] << 6u));
buf[n + 1u] = (uint8_t)((t[2] >> 2u) | (t[3] << 1u) | (t[4] << 4u) | (t[5] << 7u));
buf[n + 2u] = (uint8_t)((t[5] >> 1u) | (t[6] << 2u) | (t[7] << 5u));
}
} else if (bits == 4u) {
for (i = 0; i < MLDSA_N / 2; i++) {
t[0] = (int32_t)b - w[i * 2];
t[1] = (int32_t)b - w[i * 2 + 1];
buf[i] = (uint8_t)(t[0] | (t[1] << 4u));
}
} else if (bits == MLDSA_D) {
for (i = 0; i < MLDSA_N / 8; i++) {
for (uint32_t j = 0; j < 8; j++) {
t[j] = b - w[i * 8 + j];
}
n = bits * i;
buf[n + 0] = (uint8_t)t[0];
buf[n + 1] = (uint8_t)(t[0] >> 8u);
buf[n + 1] |= (uint8_t)(t[1] << 5u);
buf[n + 2] = (uint8_t)(t[1] >> 3u);
buf[n + 3] = (uint8_t)(t[1] >> 11u);
buf[n + 3] |= (uint8_t)(t[2] << 2u);
buf[n + 4] = (uint8_t)(t[2] >> 6u);
buf[n + 4] |= (uint8_t)(t[3] << 7u);
buf[n + 5] = (uint8_t)(t[3] >> 1u);
buf[n + 6] = (uint8_t)(t[3] >> 9u);
buf[n + 6] |= (uint8_t)(t[4] << 4u);
buf[n + 7] = (uint8_t)(t[4] >> 4u);
buf[n + 8] = (uint8_t)(t[4] >> 12u);
buf[n + 8] |= (uint8_t)(t[5] << 1u);
buf[n + 9] = (uint8_t)(t[5] >> 7u);
buf[n + 9] |= (uint8_t)(t[6] << 6u);
buf[n + 10] = (uint8_t)(t[6] >> 2u);
buf[n + 11] = (uint8_t)(t[6] >> 10u);
buf[n + 11] |= (uint8_t)(t[7] << 3u);
buf[n + 12] = (uint8_t)(t[7] >> 5u);
}
}
}
static void BitUnPake(const uint8_t *v, uint32_t w[MLDSA_N], uint32_t bits, uint32_t b)
{
uint32_t t[8] = {0};
uint32_t i;
uint32_t n;
if (bits == 3u) {
for (i = 0; i < MLDSA_N / 8; i++) {
n = bits * i;
t[0] = (v[n + 0]) & 0x07;
t[1] = (v[n + 0] >> 3u) & 0x07;
t[2] = ((v[n + 0] >> 6u) | (v[n + 1] << 2u)) & 0x07;
t[3] = (v[n + 1u] >> 1u) & 0x07;
t[4] = (v[n + 1u] >> 4u) & 0x07;
t[5] = ((v[n + 1u] >> 7u) | (v[n + 2] << 1u)) & 0x07;
t[6] = (v[n + 2u] >> 2u) & 0x07;
t[7] = (v[n + 2u] >> 5u) & 0x07;
for (uint32_t j = 0; j < 8; j++) {
w[i * 8 + j] = b - t[j];
}
}
} else if (bits == 4u) {
for (i = 0; i < MLDSA_N / 2; i++) {
t[0] = v[i] & 0x0f;
t[1] = (v[i] >> 4u) & 0x0f;
w[i * 2] = b - t[0];
w[i * 2 + 1] = b - t[1];
}
} else if (bits == MLDSA_D) {
for (i = 0; i < MLDSA_N / 8; i++) {
n = bits * i;
t[0] = (v[n + 0] | ((uint32_t)v[n + 1] << 8u)) & 0x1fff;
t[1] = (v[n + 1] >> 5u | ((uint32_t)v[n + 2u] << 3u) |
((uint32_t)v[n + 3u] << 11u)) & 0x1fff;
t[2] = (v[n + 3u] >> 2u | ((uint32_t)v[n + 4u] << 6u)) & 0x1fff;
t[3] = (v[n + 4u] >> 7u | ((uint32_t)v[n + 5u] << 1u) |
((uint32_t)v[n + 6u] << 9u)) & 0x1fff;
t[4] = (v[n + 6u] >> 4u | ((uint32_t)v[n + 7u] << 4u) |
((uint32_t)v[n + 8u] << 12u)) & 0x1fff;
t[5] = (v[n + 8u] >> 1u | ((uint32_t)v[n + 9u] << 7u)) & 0x1fff;
t[6] = (v[n + 9u] >> 6u | ((uint32_t)v[n + 10u] << 2u) |
((uint32_t)v[n + 11u] << 10u)) & 0x1fff;
t[7] = (v[n + 11u] >> 3u | ((uint32_t)v[n + 12u] << 5u)) & 0x1fff;
for (uint32_t j = 0; j < 8; j++) {
w[i * 8 + j] = b - t[j];
}
}
}
}
static void SignBitPack(uint8_t *buf, const uint32_t w[MLDSA_N], uint32_t bits, uint32_t b)
{
uint32_t t[4] = {0};
uint32_t i;
uint32_t n;
if (bits == GAMMA_BITS_OF_MLDSA_44) {
for (i = 0; i < MLDSA_N / 4; i++) {
for (uint32_t j = 0; j < 4; j++) {
t[j] = b - w[i * 4 + j];
}
n = 9 * i;
buf[n + 0] = (uint8_t)t[0];
buf[n + 1u] = (uint8_t)(t[0] >> 8u);
buf[n + 2u] = (uint8_t)(t[0] >> 16u | t[1] << 2u);
buf[n + 3u] = (uint8_t)(t[1] >> 6u);
buf[n + 4u] = (uint8_t)(t[1] >> 14u | t[2] << 4u);
buf[n + 5u] = (uint8_t)(t[2] >> 4u);
buf[n + 6u] = (uint8_t)(t[2] >> 12u | t[3] << 6u);
buf[n + 7u] = (uint8_t)(t[3] >> 2u);
buf[n + 8u] = (uint8_t)(t[3] >> 10u);
}
} else if (bits == GAMMA_BITS_OF_MLDSA_65_87) {
for (i = 0; i < MLDSA_N / 2; i++) {
t[0] = b - w[i * 2];
t[1] = b - w[i * 2 + 1u];
n = 5 * i;
buf[n + 0] = (uint8_t)t[0];
buf[n + 1u] = (uint8_t)(t[0] >> 8u);
buf[n + 2u] = (uint8_t)(t[0] >> 16u | t[1] << 4u);
buf[n + 3u] = (uint8_t)(t[1] >> 4u);
buf[n + 4u] = (uint8_t)(t[1] >> 12u);
}
}
}
static void PkEncode(const CRYPT_ML_DSA_Ctx *ctx, const uint8_t *seed, int32_t *const t[MLDSA_K_MAX])
{
memcpy(ctx->pubKey, seed, MLDSA_PUBLIC_SEED_LEN);
for (int32_t i = 0; i < ctx->info->k; i++) {
ByteEncode(ctx->pubKey + MLDSA_PUBLIC_SEED_LEN + i * MLDSA_PUBKEY_POLYT_PACKEDBYTES, (uint32_t *)t[i], 10);
}
}
static void PkDecode(const CRYPT_ML_DSA_Ctx *ctx, uint8_t *seed, int32_t *t[MLDSA_K_MAX])
{
memcpy(seed, ctx->pubKey, MLDSA_PUBLIC_SEED_LEN);
for (int32_t i = 0; i < ctx->info->k; i++) {
ByteDecode(ctx->pubKey + MLDSA_PUBLIC_SEED_LEN + i * MLDSA_PUBKEY_POLYT_PACKEDBYTES, (uint32_t *)t[i], 10);
}
}
static void SkEncode(const CRYPT_ML_DSA_Ctx *ctx, const uint8_t *pubSeed, const uint8_t *signSeed, const uint8_t *tr,
const MLDSA_KeyGenMatrixSt *st)
{
uint32_t i;
uint32_t bitLen = ctx->info->eta == 2 ? 3 : 4;
uint32_t index = MLDSA_PUBLIC_SEED_LEN;
memcpy(ctx->prvKey, pubSeed, MLDSA_PUBLIC_SEED_LEN);
memcpy(ctx->prvKey + index, signSeed, MLDSA_SIGNING_SEED_LEN);
index += MLDSA_SIGNING_SEED_LEN;
memcpy(ctx->prvKey + index, tr, MLDSA_TR_MSG_LEN);
index += MLDSA_TR_MSG_LEN;
for (i = 0; i < ctx->info->l; i++) {
BitPack(ctx->prvKey + index, (uint32_t *)st->s1[i], bitLen, ctx->info->eta);
index += MLDSA_N_BYTE * bitLen;
}
for (i = 0; i < ctx->info->k; i++) {
BitPack(ctx->prvKey + index, (uint32_t *)st->s2[i], bitLen, ctx->info->eta);
index += MLDSA_N_BYTE * bitLen;
}
for (i = 0; i < ctx->info->k; i++) {
BitPack(ctx->prvKey + index, (uint32_t *)st->t0[i], MLDSA_D, 4096);
index += MLDSA_N_BYTE * MLDSA_D;
}
}
static void SkDecode(const CRYPT_ML_DSA_Ctx *ctx, uint8_t *pubSeed, uint8_t *signSeed, uint8_t *tr,
MLDSA_SignMatrixSt *st)
{
uint32_t i;
uint32_t bitLen = ctx->info->eta == 2 ? 3 : 4;
uint32_t index = MLDSA_PUBLIC_SEED_LEN;
memcpy(pubSeed, ctx->prvKey, MLDSA_PUBLIC_SEED_LEN);
memcpy(signSeed, ctx->prvKey + index, MLDSA_SIGNING_SEED_LEN);
index += MLDSA_SIGNING_SEED_LEN;
memcpy(tr, ctx->prvKey + index, MLDSA_PRIVATE_SEED_LEN);
index += MLDSA_PRIVATE_SEED_LEN;
for (i = 0; i < ctx->info->l; i++) {
BitUnPake(ctx->prvKey + index, (uint32_t *)st->s1[i], bitLen, ctx->info->eta);
index += MLDSA_N_BYTE * bitLen;
}
for (i = 0; i < ctx->info->k; i++) {
BitUnPake(ctx->prvKey + index, (uint32_t *)st->s2[i], bitLen, ctx->info->eta);
index += MLDSA_N_BYTE * bitLen;
}
for (i = 0; i < ctx->info->k; i++) {
BitUnPake(ctx->prvKey + index, (uint32_t *)st->t0[i], MLDSA_D, 4096);
index += MLDSA_N_BYTE * MLDSA_D;
}
}
static void SignCalNtt(const CRYPT_ML_DSA_Ctx *ctx, MLDSA_SignMatrixSt *st)
{
uint32_t i;
for (i = 0; i < ctx->info->l; i++) {
MLDSA_ComputesNTT(st->s1[i]);
}
for (i = 0; i < ctx->info->k; i++) {
MLDSA_ComputesNTT(st->s2[i]);
}
for (i = 0; i < ctx->info->k; i++) {
MLDSA_ComputesNTT(st->t0[i]);
}
}
static int32_t ExpandMask(const CRYPT_ML_DSA_Ctx *ctx, int32_t *y[MLDSA_L_MAX], uint8_t *p, uint16_t u)
{
uint16_t n = 0;
uint32_t bits = (ctx->info->k == K_VALUE_OF_MLDSA_44) ? GAMMA_BITS_OF_MLDSA_44 : GAMMA_BITS_OF_MLDSA_65_87;
uint16_t i = 0;
#ifdef HITLS_CRYPTO_MLDSA_X2
uint32_t outLen = 32u * bits;
uint8_t p1[MLDSA_PRIVATE_SEED_LEN + 2];
memcpy(p1, p, MLDSA_PRIVATE_SEED_LEN);
uint8_t v0[640];
uint8_t v1[640];
for (; i + 1 < ctx->info->l; i += 2) {
uint16_t n0 = u + i;
uint16_t n1 = u + (uint16_t)(i + 1);
p[MLDSA_PRIVATE_SEED_LEN] = (uint8_t)n0;
p[MLDSA_PRIVATE_SEED_LEN + 1] = (uint8_t)(n0 >> BITS_OF_BYTE);
p1[MLDSA_PRIVATE_SEED_LEN] = (uint8_t)n1;
p1[MLDSA_PRIVATE_SEED_LEN + 1] = (uint8_t)(n1 >> BITS_OF_BYTE);
Shake256x2(v0, v1, outLen, p, p1, MLDSA_PRIVATE_SEED_LEN + 2);
MLDSA_SignBitUnPack(v0, (uint32_t *)y[i], bits, ctx->info->gamma1);
MLDSA_SignBitUnPack(v1, (uint32_t *)y[i + 1], bits, ctx->info->gamma1);
}
uint8_t v[640];
for (; i < ctx->info->l; i++) {
n = u + i;
p[MLDSA_PRIVATE_SEED_LEN] = (uint8_t)n;
p[MLDSA_PRIVATE_SEED_LEN + 1] = (uint8_t)(n >> BITS_OF_BYTE);
int32_t ret = HashFuncH(p, MLDSA_PRIVATE_SEED_LEN + 2, NULL, 0, v, outLen);
if (ret != CRYPT_SUCCESS) {
return ret;
}
MLDSA_SignBitUnPack(v, (uint32_t *)y[i], bits, ctx->info->gamma1);
}
#else
uint8_t v[640];
for (; i < ctx->info->l; i++) {
n = u + i;
p[MLDSA_PRIVATE_SEED_LEN] = (uint8_t)n;
p[MLDSA_PRIVATE_SEED_LEN + 1] = (uint8_t)(n >> BITS_OF_BYTE);
int32_t ret = HashFuncH(p, MLDSA_PRIVATE_SEED_LEN + 2, NULL, 0, v, 32 * bits);
if (ret != CRYPT_SUCCESS) {
return ret;
}
MLDSA_SignBitUnPack(v, (uint32_t *)y[i], bits, ctx->info->gamma1);
}
#endif
return CRYPT_SUCCESS;
}
static void ComputesW(const CRYPT_ML_DSA_Ctx *ctx, int32_t *w[MLDSA_L_MAX], int32_t *w1[MLDSA_L_MAX],
int32_t *const matrix[MLDSA_K_MAX][MLDSA_L_MAX], int32_t *const y[MLDSA_L_MAX])
{
for (uint8_t i = 0; i < ctx->info->k; i++) {
MLDSA_MatrixMul(ctx, w[i], matrix[i], y);
MLDSA_ComputesINVNTT(w[i]);
MLDSA_Batch_Decompose(ctx, w[i], w1[i]);
}
}
static void W1Encode(const CRYPT_ML_DSA_Ctx *ctx, uint8_t *buf, int32_t *const w[MLDSA_K_MAX])
{
uint32_t bitLen = ctx->info->k == K_VALUE_OF_MLDSA_44 ? 6 : 4;
uint32_t blockSize = ctx->info->k == K_VALUE_OF_MLDSA_44 ? 192 : 128;
for (uint32_t i = 0; i < ctx->info->k; i++) {
ByteEncode(buf + i * blockSize, (const uint32_t *)w[i], bitLen);
}
}
static int32_t SampleInBall(const CRYPT_ML_DSA_Ctx *ctx, const uint8_t *p, uint32_t pLen, int32_t c[MLDSA_N])
{
uint8_t s[CRYPT_SHAKE256_BLOCKSIZE] = {0};
uint32_t sLen = CRYPT_SHAKE256_BLOCKSIZE;
uint64_t h = 0;
uint32_t index = 0;
uint8_t j = 0;
int32_t ret;
const EAL_MdMethod *hashMethod = NULL;
void *mdCtx = NULL;
RETURN_RET_IF_ERR_EX(MLDSAInitHashCtx(CRYPT_MD_SHAKE256, &hashMethod, &mdCtx), ret);
GOTO_ERR_IF(hashMethod->update(mdCtx, p, pLen), ret);
GOTO_ERR_IF(hashMethod->squeeze(mdCtx, s, sLen), ret);
for (index = 0; index < 8; index++) {
h = h | ((uint64_t)s[index] << (8 * index));
}
for (uint32_t i = MLDSA_N - ctx->info->tau; i < MLDSA_N; i++) {
do {
if (index == CRYPT_SHAKE256_BLOCKSIZE) {
GOTO_ERR_IF(hashMethod->squeeze(mdCtx, s, sLen), ret);
index = 0;
}
j = s[index];
index++;
} while (j > i);
c[i] = c[j];
c[j] = 1 - ((h & 1) << 1);
h >>= 1;
}
ERR:
hashMethod->freeCtx(mdCtx);
return ret;
}
static void ComputesZ(const CRYPT_ML_DSA_Ctx *ctx, int32_t *y[MLDSA_L_MAX], const int32_t *c,
int32_t *const s[MLDSA_L_MAX], int32_t *const z[MLDSA_L_MAX])
{
for (uint8_t i = 0; i < ctx->info->l; i++) {
MLDSA_VectorsMul(z[i], c, s[i]);
MLDSA_ComputesINVNTT(z[i]);
MLDSA_VectorsAdd(z[i], y[i], z[i]);
}
}
static bool ValidityChecksL(const CRYPT_ML_DSA_Ctx *ctx, int32_t *const z[MLDSA_L_MAX], uint32_t t)
{
bool valid = true;
for (uint8_t i = 0; i < ctx->info->l; i++) {
valid &= MLDSA_ValidityChecks(z[i], t);
}
return valid;
}
static bool ValidityChecksK(const CRYPT_ML_DSA_Ctx *ctx, int32_t *const z[MLDSA_K_MAX], uint32_t t)
{
bool valid = true;
for (uint8_t i = 0; i < ctx->info->k; i++) {
valid &= MLDSA_ValidityChecks(z[i], t);
}
return valid;
}
static void ComputesR(const CRYPT_ML_DSA_Ctx *ctx, const int32_t *c, MLDSA_SignMatrixSt *st)
{
for (uint8_t i = 0; i < ctx->info->k; i++) {
MLDSA_VectorsMul(st->y[i], c, st->s2[i]);
MLDSA_ComputesINVNTT(st->y[i]);
MLDSA_VectorsSub(st->r0[i], st->w[i], st->y[i]);
}
}
static void ComputesCT(const CRYPT_ML_DSA_Ctx *ctx, const int32_t *c,
int32_t *const t[MLDSA_K_MAX], int32_t *ct[MLDSA_K_MAX])
{
for (uint8_t i = 0; i < ctx->info->k; i++) {
MLDSA_VectorsMul(ct[i], c, t[i]);
MLDSA_ComputesINVNTT(ct[i]);
}
}
static uint32_t MakeHint(const CRYPT_ML_DSA_Ctx *ctx, MLDSA_SignMatrixSt *st)
{
uint32_t num = 0;
int32_t g = (int32_t)ctx->info->gamma2;
for (uint32_t i = 0; i < ctx->info->k; i++) {
for (uint32_t j = 0; j < MLDSA_N; j++) {
int32_t v = st->w[i][j] + st->r0[i][j] - st->y[i][j];
MLDSA_MOD_Q(v);
uint32_t x = (uint32_t)(v + g);
uint32_t c1 = ((uint32_t)(g - v) >> 31) & 1;
uint32_t c2 = (x >> 31) & 1;
uint32_t isZero = ((x | (0 - x)) >> 31) ^ 1;
uint32_t y = (uint32_t)st->w1[i][j];
uint32_t isNonZero = ((y | (0 - y)) >> 31) & 1;
uint32_t bit = c1 | c2 | (isZero & isNonZero);
st->w[i][j] = (int32_t)bit;
num += bit;
}
}
return num;
}
static void SigEncode(const CRYPT_ML_DSA_Ctx *ctx, uint8_t *out, uint32_t outLen, int32_t *const z[MLDSA_L_MAX],
int32_t *const h[MLDSA_K_MAX])
{
uint32_t bits = (ctx->info->k == K_VALUE_OF_MLDSA_44) ? GAMMA_BITS_OF_MLDSA_44 : GAMMA_BITS_OF_MLDSA_65_87;
uint32_t blockSize = MLDSA_N / BITS_OF_BYTE * bits;
uint8_t *ptr = out;
uint32_t index = 0;
for (uint32_t i = 0; i < ctx->info->l; i++) {
SignBitPack(ptr, (const uint32_t *)z[i], bits, ctx->info->gamma1);
ptr += blockSize;
}
memset(ptr, 0, outLen - blockSize * ctx->info->l);
for (uint32_t i = 0; i < ctx->info->k; i++) {
for (uint32_t j = 0; j < MLDSA_N; j++) {
if (h[i][j] != 0) {
ptr[index] = j;
index++;
}
}
ptr[ctx->info->omega + i] = index;
}
}
static int32_t SigDecode(const CRYPT_ML_DSA_Ctx *ctx, const uint8_t *in, int32_t *z[MLDSA_L_MAX],
int32_t *h[MLDSA_K_MAX])
{
uint32_t bits = (ctx->info->k == K_VALUE_OF_MLDSA_44) ? GAMMA_BITS_OF_MLDSA_44 : GAMMA_BITS_OF_MLDSA_65_87;
uint32_t blockSize = MLDSA_N / BITS_OF_BYTE * bits;
const uint8_t *ptr = in;
uint32_t index = 0;
for (int32_t i = 0; i < ctx->info->l; i++) {
MLDSA_SignBitUnPack(ptr, (uint32_t *)z[i], bits, ctx->info->gamma1);
ptr += blockSize;
}
for (int32_t i = 0; i < ctx->info->k; i++) {
if (ptr[ctx->info->omega + i] < index || ptr[ctx->info->omega + i] > ctx->info->omega) {
BSL_ERR_PUSH_ERROR(CRYPT_MLDSA_SIGN_DATA_ERROR);
return CRYPT_MLDSA_SIGN_DATA_ERROR;
}
uint32_t first = index;
memset(h[i], 0, sizeof(int32_t) * MLDSA_N);
while (index < ptr[ctx->info->omega + i]) {
if (index > first && (ptr[index - 1] >= ptr[index])) {
BSL_ERR_PUSH_ERROR(CRYPT_MLDSA_SIGN_DATA_ERROR);
return CRYPT_MLDSA_SIGN_DATA_ERROR;
}
h[i][ptr[index]] = 1;
index++;
}
}
for (int32_t i = index; i <= (ctx->info->omega - 1); i++) {
RETURN_RET_IF(ptr[i] != 0, CRYPT_MLDSA_SIGN_DATA_ERROR);
}
return CRYPT_SUCCESS;
}
static int32_t ComputesApproxW(const CRYPT_ML_DSA_Ctx *ctx, MLDSA_VerifyMatrixSt *st, const uint8_t *pubSeed,
int32_t *c, int32_t *w[MLDSA_K_MAX])
{
uint8_t seed[MLDSA_SEED_EXTEND_BYTES_LEN];
(void)memcpy(seed, pubSeed, MLDSA_PUBLIC_SEED_LEN);
MLDSA_ComputesNTT(c);
for (uint8_t i = 0; i < ctx->info->l; i++) {
MLDSA_ComputesNTT(st->z[i]);
}
for (uint8_t i = 0; i < ctx->info->k; i++) {
uint8_t j = 0;
#ifdef HITLS_CRYPTO_MLDSA_X2
* prefix with seed; only the column index byte differs. */
uint8_t seed1[MLDSA_SEED_EXTEND_BYTES_LEN];
memcpy(seed1, pubSeed, MLDSA_PUBLIC_SEED_LEN);
seed1[MLDSA_PUBLIC_SEED_LEN + 1] = i;
for (; j + 1 < ctx->info->l; j += 2) {
seed[MLDSA_PUBLIC_SEED_LEN] = j;
seed[MLDSA_PUBLIC_SEED_LEN + 1] = i;
seed1[MLDSA_PUBLIC_SEED_LEN] = j + 1;
int32_t ret = MLDSA_RejNTTPolyPair(st->matrix[j], st->matrix[j + 1], seed, seed1);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
#endif
for (; j < ctx->info->l; j++) {
seed[MLDSA_PUBLIC_SEED_LEN] = j;
seed[MLDSA_PUBLIC_SEED_LEN + 1] = i;
int32_t ret = MLDSA_RejNTTPoly(st->matrix[j], seed);
RETURN_RET_IF(ret != CRYPT_SUCCESS, ret);
}
for (int32_t m = 0; m < MLDSA_N; m++) {
st->t1[i][m] = (int32_t)((uint32_t)st->t1[i][m] << MLDSA_D);
}
MLDSA_ComputesNTT(st->t1[i]);
MLDSA_VectorsMul(st->t1[i], st->t1[i], c);
MLDSA_MatrixMul(ctx, w[i], st->matrix, st->z);
MLDSA_VectorsSub(w[i], w[i], st->t1[i]);
MLDSA_ComputesINVNTT(w[i]);
}
return CRYPT_SUCCESS;
}
int32_t MLDSA_KeyGenInternal(CRYPT_ML_DSA_Ctx *ctx, const uint8_t *d)
{
uint8_t k = ctx->info->k;
uint8_t l = ctx->info->l;
uint8_t seed[MLDSA_SEED_EXTEND_BYTES_LEN] = { 0 };
uint8_t digest[MLDSA_EXPANDED_SEED_BYTES_LEN] = { 0 };
uint8_t tr[MLDSA_TR_MSG_LEN] = { 0 };
MLDSA_KeyGenMatrixSt st = { 0 };
int32_t ret;
GOTO_ERR_IF(MLDSAKeyGenCreateMatrix(k, l, &st), ret);
memcpy(seed, d, MLDSA_SEED_BYTES_LEN);
seed[MLDSA_SEED_BYTES_LEN] = k;
seed[MLDSA_SEED_BYTES_LEN + 1] = l;
GOTO_ERR_IF(HashFuncH(seed, sizeof(seed), NULL, 0, digest, MLDSA_EXPANDED_SEED_BYTES_LEN), ret);
uint8_t *pubSeed = digest;
uint8_t *prvSeed = digest + MLDSA_PUBLIC_SEED_LEN;
uint8_t *signSeed = digest + MLDSA_PUBLIC_SEED_LEN + MLDSA_PRIVATE_SEED_LEN;
GOTO_ERR_IF(ExpandS(ctx, prvSeed, st.s1, st.s2), ret);
ComputesNTT(ctx, st.s1, st.s1Ntt);
GOTO_ERR_IF(ComputesT(ctx, st.t1, &st, pubSeed), ret);
MLDSA_ComputesPower2Round(ctx, st.t0, st.t1);
PkEncode(ctx, pubSeed, st.t1);
GOTO_ERR_IF(HashFuncH(ctx->pubKey, ctx->pubLen, NULL, 0, tr, MLDSA_TR_MSG_LEN), ret);
SkEncode(ctx, pubSeed, signSeed, tr, &st);
ctx->hasSeed = true;
memcpy(ctx->seed, d, MLDSA_SEED_BYTES_LEN);
ERR:
BSL_SAL_ClearFree(st.bufAddr, st.bufSize);
BSL_SAL_CleanseData(seed, sizeof(seed));
BSL_SAL_CleanseData(digest, sizeof(digest));
return ret;
}
int32_t MLDSA_SignInternal(const CRYPT_ML_DSA_Ctx *ctx, const CRYPT_Data *msg, uint8_t *out, uint32_t *outLen,
const uint8_t *rand)
{
int32_t ret = CRYPT_SUCCESS;
uint8_t pubSeed[MLDSA_PUBLIC_SEED_LEN];
uint8_t uBuf[MLDSA_XOF_MSG_LEN];
uint8_t tr[MLDSA_TR_MSG_LEN];
uint8_t signSeed[MLDSA_SIGNING_SEED_LEN + MLDSA_SEED_BYTES_LEN];
memcpy(signSeed + MLDSA_SIGNING_SEED_LEN, rand, MLDSA_SEED_BYTES_LEN);
uint32_t w1Len = (ctx->info->k == 4 || ctx->info->k == 6) ? 768 : 1024;
uint8_t *w1Buf = BSL_SAL_Malloc(w1Len);
RETURN_RET_IF(w1Buf == NULL, CRYPT_MEM_ALLOC_FAIL);
MLDSA_SignMatrixSt st = { 0 };
GOTO_ERR_IF(MLDSASignCreateMatrix(ctx->info->k, ctx->info->l, &st), ret);
SkDecode(ctx, pubSeed, signSeed, tr, &st);
SignCalNtt(ctx, &st);
GOTO_ERR_IF(ExpandA(ctx, pubSeed, st.matrix), ret);
if (ctx->isMuMsg) {
memcpy(uBuf, msg->data, msg->len);
} else {
GOTO_ERR_IF(HashFuncH(tr, MLDSA_TR_MSG_LEN, msg->data, msg->len, uBuf, MLDSA_XOF_MSG_LEN), ret);
}
uint8_t p[MLDSA_XOF_MSG_LEN + 2];
GOTO_ERR_IF(HashFuncH(signSeed, sizeof(signSeed), uBuf, MLDSA_XOF_MSG_LEN, p, MLDSA_XOF_MSG_LEN), ret);
uint16_t u = 0;
uint32_t cBufLen = ctx->info->secBits / 4;
int32_t c[MLDSA_N];
do {
GOTO_ERR_IF(ExpandMask(ctx, st.y, p, u), ret);
u = u + ctx->info->l;
ComputesNTT(ctx, st.y, st.z);
ComputesW(ctx, st.w, st.w1, st.matrix, st.z);
W1Encode(ctx, w1Buf, st.w1);
GOTO_ERR_IF(HashFuncH(uBuf, MLDSA_XOF_MSG_LEN, w1Buf, w1Len, out, cBufLen), ret);
memset(c, 0, sizeof(c));
GOTO_ERR_IF(SampleInBall(ctx, out, cBufLen, c), ret);
MLDSA_ComputesNTT(c);
ComputesZ(ctx, st.y, c, st.s1, st.z);
if (ValidityChecksL(ctx, st.z, ctx->info->gamma1 - ctx->info->beta) == false) {
continue;
}
ComputesR(ctx, c, &st);
if (ValidityChecksK(ctx, st.r0, ctx->info->gamma2 - ctx->info->beta) == false) {
continue;
}
ComputesCT(ctx, c, st.t0, st.r0);
if (ValidityChecksK(ctx, st.r0, ctx->info->gamma2) == false) {
continue;
}
if (MakeHint(ctx, &st) > ctx->info->omega) {
continue;
}
break;
} while (true);
*outLen = ctx->info->signatureLen;
SigEncode(ctx, out + cBufLen, *outLen - cBufLen, st.z, st.w);
ERR:
BSL_SAL_ClearFree(st.bufAddr, st.bufSize);
BSL_SAL_ClearFree(w1Buf, w1Len);
BSL_SAL_CleanseData(signSeed, sizeof(signSeed));
return ret;
}
int32_t MLDSA_VerifyInternal(const CRYPT_ML_DSA_Ctx *ctx, const CRYPT_Data *msg, const uint8_t *sign, uint32_t signLen)
{
(void)signLen;
uint8_t k = ctx->info->k;
uint8_t l = ctx->info->l;
uint8_t pubSeed[MLDSA_PUBLIC_SEED_LEN];
uint8_t uBuf[MLDSA_XOF_MSG_LEN];
uint8_t cBuf[MLDSA_XOF_MSG_LEN];
uint8_t tr[MLDSA_TR_MSG_LEN];
uint32_t cBufLen = ctx->info->secBits / 4;
MLDSA_VerifyMatrixSt st = { 0 };
int32_t c[MLDSA_N] = { 0 };
int32_t ret;
uint32_t w1Len = (k == 4 || k == 6) ? 768 : 1024;
uint8_t *w1Buf = BSL_SAL_Malloc(w1Len);
RETURN_RET_IF(w1Buf == NULL, CRYPT_MEM_ALLOC_FAIL);
GOTO_ERR_IF(MLDSAVerifyCreateMatrix(k, l, &st), ret);
PkDecode(ctx, pubSeed, st.t1);
GOTO_ERR_IF(SigDecode(ctx, sign + cBufLen, st.z, st.h), ret);
if (ValidityChecksL(ctx, st.z, ctx->info->gamma1 - ctx->info->beta) == false) {
ret = CRYPT_MLDSA_SIGN_DATA_ERROR;
goto ERR;
}
if (ctx->isMuMsg) {
memcpy(uBuf, msg->data, msg->len);
} else {
GOTO_ERR_IF(HashFuncH(ctx->pubKey, ctx->pubLen, NULL, 0, tr, MLDSA_TR_MSG_LEN), ret);
GOTO_ERR_IF(HashFuncH(tr, MLDSA_TR_MSG_LEN, msg->data, msg->len, uBuf, MLDSA_XOF_MSG_LEN), ret);
}
GOTO_ERR_IF(SampleInBall(ctx, sign, cBufLen, c), ret);
GOTO_ERR_IF(ComputesApproxW(ctx, &st, pubSeed, c, st.w), ret);
MLDSA_UseHint(ctx, st.h, st.w);
W1Encode(ctx, w1Buf, st.w);
GOTO_ERR_IF(HashFuncH(uBuf, MLDSA_XOF_MSG_LEN, w1Buf, w1Len, cBuf, cBufLen), ret);
if (memcmp(sign, cBuf, cBufLen) != 0) {
BSL_ERR_PUSH_ERROR(CRYPT_MLDSA_VERIFY_FAIL);
ret = CRYPT_MLDSA_VERIFY_FAIL;
goto ERR;
}
ERR:
BSL_SAL_Free(st.bufAddr);
BSL_SAL_Free(w1Buf);
return ret;
}
static void DecodePrvKey(const CRYPT_ML_DSA_Ctx *ctx, uint8_t *pubSeed, MLDSA_KeyGenMatrixSt *st)
{
uint32_t bitLen = ctx->info->eta == 2 ? 3 : 4;
uint32_t index = MLDSA_PUBLIC_SEED_LEN + MLDSA_SIGNING_SEED_LEN + MLDSA_PRIVATE_SEED_LEN;
(void)memcpy(pubSeed, ctx->prvKey, MLDSA_PUBLIC_SEED_LEN);
uint32_t i = 0;
for (i = 0; i < ctx->info->l; i++) {
BitUnPake(ctx->prvKey + index, (uint32_t *)st->s1[i], bitLen, ctx->info->eta);
index += MLDSA_N_BYTE * bitLen;
}
for (i = 0; i < ctx->info->k; i++) {
BitUnPake(ctx->prvKey + index, (uint32_t *)st->s2[i], bitLen, ctx->info->eta);
index += MLDSA_N_BYTE * bitLen;
}
for (i = 0; i < ctx->info->k; i++) {
BitUnPake(ctx->prvKey + index, (uint32_t *)st->t0[i], MLDSA_D, 4096);
index += MLDSA_N_BYTE * MLDSA_D;
}
}
int32_t MLDSA_CalPub(const CRYPT_ML_DSA_Ctx *ctx, uint8_t *pub, uint32_t pubLen)
{
int32_t ret;
MLDSA_KeyGenMatrixSt st = { 0 };
uint8_t pubSeed[MLDSA_PUBLIC_SEED_LEN];
GOTO_ERR_IF(MLDSAKeyGenCreateMatrix(ctx->info->k, ctx->info->l, &st), ret);
DecodePrvKey(ctx, pubSeed, &st);
ComputesNTT(ctx, st.s1, st.s1Ntt);
GOTO_ERR_IF(ComputesT(ctx, st.t1, &st, pubSeed), ret);
MLDSA_ComputesPower2Round(ctx, st.s2, st.t1);
for (int32_t i = 0; i < ctx->info->k; i++) {
if (memcmp(st.s2[i], st.t0[i], MLDSA_N * sizeof(int32_t)) != 0) {
BSL_ERR_PUSH_ERROR(CRYPT_MLDSA_PAIRWISE_CHECK_FAIL);
ret = CRYPT_MLDSA_PAIRWISE_CHECK_FAIL;
goto ERR;
}
}
if (MLDSA_PUBLIC_SEED_LEN > pubLen) {
BSL_ERR_PUSH_ERROR(CRYPT_MLDSA_LEN_NOT_ENOUGH);
ret = CRYPT_MLDSA_LEN_NOT_ENOUGH;
goto ERR;
}
memcpy(pub, pubSeed, MLDSA_PUBLIC_SEED_LEN);
for (int32_t i = 0; i < ctx->info->k; i++) {
ByteEncode(pub + MLDSA_PUBLIC_SEED_LEN + i * MLDSA_PUBKEY_POLYT_PACKEDBYTES, (uint32_t *)st.t1[i], 10);
}
ERR:
BSL_SAL_ClearFree(st.bufAddr, st.bufSize);
BSL_SAL_CleanseData(pubSeed, sizeof(pubSeed));
return ret;
}
int32_t MLDSA_KeyConsistenceCheck(CRYPT_ML_DSA_Ctx *ctx)
{
int32_t ret = CRYPT_SUCCESS;
uint8_t *pubKey = BSL_SAL_Malloc(ctx->info->publicKeyLen);
if (pubKey == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return CRYPT_MEM_ALLOC_FAIL;
}
ret = MLDSA_CalPub(ctx, pubKey, ctx->info->publicKeyLen);
if (ret != CRYPT_SUCCESS) {
BSL_SAL_FREE(pubKey);
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
uint8_t tr[MLDSA_TR_MSG_LEN] = {0};
ret = HashFuncH(pubKey, ctx->info->publicKeyLen, NULL, 0, tr, MLDSA_TR_MSG_LEN);
if (ret != CRYPT_SUCCESS) {
BSL_SAL_FREE(pubKey);
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
if (memcmp(tr, ctx->prvKey + MLDSA_PUBLIC_SEED_LEN + MLDSA_SIGNING_SEED_LEN, MLDSA_TR_MSG_LEN) != 0) {
BSL_SAL_FREE(pubKey);
BSL_ERR_PUSH_ERROR(CRYPT_MLDSA_PAIRWISE_CHECK_FAIL);
return CRYPT_MLDSA_PAIRWISE_CHECK_FAIL;
}
if (ctx->pubKey == NULL) {
ctx->pubKey = pubKey;
ctx->pubLen = ctx->info->publicKeyLen;
} else {
if (memcmp(pubKey, ctx->pubKey, ctx->info->publicKeyLen) != 0) {
BSL_SAL_FREE(pubKey);
BSL_ERR_PUSH_ERROR(CRYPT_MLDSA_PAIRWISE_CHECK_FAIL);
return CRYPT_MLDSA_PAIRWISE_CHECK_FAIL;
}
BSL_SAL_FREE(pubKey);
}
return CRYPT_SUCCESS;
}
#endif