chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,122 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#ifndef MLD_AWSLC_FIPS202_GLUE_H
#define MLD_AWSLC_FIPS202_GLUE_H
#include <stddef.h>
#include <stdint.h>
#include "../sha/internal.h"
#define SHAKE128_RATE 168
#define SHAKE256_RATE 136
#define SHA3_256_RATE 136
#define SHA3_512_RATE 72
#define mld_shake128ctx KECCAK1600_CTX
#define mld_shake256ctx KECCAK1600_CTX
static MLD_INLINE void mld_shake128_init(mld_shake128ctx *state) {
// Return code checks can be omitted
// SHAKE_Init always returns 1 when called with correct block size value.
(void) SHAKE_Init(state, SHAKE128_BLOCKSIZE);
}
static MLD_INLINE void mld_shake128_release(mld_shake128ctx *state) {
(void) state;
}
static MLD_INLINE void mld_shake128_absorb_once(mld_shake128ctx *state,
const uint8_t *input, size_t inlen) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE_Absorb(state, input, inlen);
}
static MLD_INLINE void mld_shake128_absorb(mld_shake128ctx *state,
const uint8_t *input, size_t inlen) {
(void) SHAKE_Absorb(state, input, inlen);
}
static MLD_INLINE void mld_shake128_finalize(mld_shake128ctx *state) {
// Finalization is implicit in AWS-LC's implementation
// The state is ready for squeezing after absorb
(void) state;
}
static MLD_INLINE void mld_shake128_squeeze(uint8_t *output, size_t outlen,
mld_shake128ctx *state) {
(void) SHAKE_Squeeze(output, state, outlen);
}
static MLD_INLINE void mld_shake128_squeezeblocks(uint8_t *output, size_t nblocks,
mld_shake128ctx *state) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE_Squeeze(output, state, nblocks * SHAKE128_RATE);
}
static MLD_INLINE void mld_shake256_init(mld_shake256ctx *state) {
// Return code checks can be omitted
// SHAKE_Init always returns 1 when called with correct block size value.
(void) SHAKE_Init(state, SHAKE256_BLOCKSIZE);
}
static MLD_INLINE void mld_shake256_release(mld_shake256ctx *state) {
(void) state;
}
static MLD_INLINE void mld_shake256_absorb_once(mld_shake256ctx *state,
const uint8_t *input, size_t inlen) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE_Absorb(state, input, inlen);
}
static MLD_INLINE void mld_shake256_absorb(mld_shake256ctx *state,
const uint8_t *input, size_t inlen) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE_Absorb(state, input, inlen);
}
static MLD_INLINE void mld_shake256_finalize(mld_shake256ctx *state) {
// Finalization is implicit in AWS-LC's implementation
// The state is ready for squeezing after absorb
(void) state;
}
static MLD_INLINE void mld_shake256_squeeze(uint8_t *output, size_t outlen,
mld_shake256ctx *state) {
(void) SHAKE_Squeeze(output, state, outlen);
}
static MLD_INLINE void mld_shake256_squeezeblocks(uint8_t *output, size_t nblocks,
mld_shake256ctx *state) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE_Squeeze(output, state, nblocks * SHAKE256_RATE);
}
static MLD_INLINE void mld_shake256(uint8_t *output, size_t outlen,
const uint8_t *input, size_t inlen) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE256(input, inlen, output, outlen);
}
static MLD_INLINE void mld_sha3_256(uint8_t *output, const uint8_t *input,
size_t inlen) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHA3_256(input, inlen, output);
}
static MLD_INLINE void mld_sha3_512(uint8_t *output, const uint8_t *input,
size_t inlen) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHA3_512(input, inlen, output);
}
#endif // MLD_AWSLC_FIPS202_GLUE_H

View File

@@ -0,0 +1,106 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
//
// This is a shim establishing the FIPS-202 API required by
// mldsa-native from the API exposed by AWS-LC.
//
#ifndef MLD_AWSLC_FIPS202X4_GLUE_H
#define MLD_AWSLC_FIPS202X4_GLUE_H
#include <stddef.h>
#include <stdint.h>
#include "fips202_glue.h"
// Use AWS-LC's existing KECCAK1600_CTX_x4 structure for SHAKE128
#define mld_shake128x4ctx KECCAK1600_CTX_x4
// For SHAKE256 x4, we need a custom structure since AWS-LC only has batched SHAKE128
typedef struct mld_shake256x4ctx_s {
KECCAK1600_CTX s[4];
} mld_shake256x4ctx;
static MLD_INLINE void mld_shake128x4_absorb_once(mld_shake128x4ctx *state,
const uint8_t *in0,
const uint8_t *in1,
const uint8_t *in2,
const uint8_t *in3, size_t inlen) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE128_Absorb_once_x4(state, in0, in1, in2, in3, inlen);
}
static MLD_INLINE void mld_shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1,
uint8_t *out2, uint8_t *out3,
size_t nblocks,
mld_shake128x4ctx *state) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE128_Squeezeblocks_x4(out0, out1, out2, out3, state, nblocks);
}
static MLD_INLINE void mld_shake128x4_init(mld_shake128x4ctx *state) {
// Return code check can be omitted
// since mldsa-native adheres to call discipline
(void) SHAKE128_Init_x4(state);
}
static MLD_INLINE void mld_shake128x4_release(mld_shake128x4ctx *state) {
(void) state;
}
// AWS-LC doesn't have SHAKE256 x4 batched operations like it does for SHAKE128
// We provide serial implementations that process each instance separately
static MLD_INLINE void mld_shake256x4_absorb_once(mld_shake256x4ctx *state,
const uint8_t *in0,
const uint8_t *in1,
const uint8_t *in2,
const uint8_t *in3, size_t inlen) {
// Process four independent SHAKE256 operations serially
mld_shake256_init(&state->s[0]);
mld_shake256_absorb_once(&state->s[0], in0, inlen);
mld_shake256_init(&state->s[1]);
mld_shake256_absorb_once(&state->s[1], in1, inlen);
mld_shake256_init(&state->s[2]);
mld_shake256_absorb_once(&state->s[2], in2, inlen);
mld_shake256_init(&state->s[3]);
mld_shake256_absorb_once(&state->s[3], in3, inlen);
}
static MLD_INLINE void mld_shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1,
uint8_t *out2, uint8_t *out3,
size_t nblocks,
mld_shake256x4ctx *state) {
// Process four independent squeeze operations serially
mld_shake256_squeezeblocks(out0, nblocks, &state->s[0]);
mld_shake256_squeezeblocks(out1, nblocks, &state->s[1]);
mld_shake256_squeezeblocks(out2, nblocks, &state->s[2]);
mld_shake256_squeezeblocks(out3, nblocks, &state->s[3]);
}
static MLD_INLINE void mld_shake256x4_init(mld_shake256x4ctx *state) {
// Initialize four independent states
mld_shake256_init(&state->s[0]);
mld_shake256_init(&state->s[1]);
mld_shake256_init(&state->s[2]);
mld_shake256_init(&state->s[3]);
}
static MLD_INLINE void mld_shake256x4_release(mld_shake256x4ctx *state) {
(void) state;
}
static MLD_INLINE void mld_shake256x4(uint8_t *out0, uint8_t *out1, uint8_t *out2,
uint8_t *out3, size_t outlen, uint8_t *in0,
uint8_t *in1, uint8_t *in2, uint8_t *in3,
size_t inlen) {
// Process four independent SHAKE256 operations serially
mld_shake256(out0, outlen, in0, inlen);
mld_shake256(out1, outlen, in1, inlen);
mld_shake256(out2, outlen, in2, inlen);
mld_shake256(out3, outlen, in3, inlen);
}
#endif // MLD_AWSLC_FIPS202X4_GLUE_H

View File

@@ -0,0 +1,226 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
//
// Generates test vectors with intentionally corrupted ML-DSA private keys
//
// USAGE:
// cd crypto/fipsmodule/ml_dsa
// make generate
//
// This regenerates crypto/evp_extra/mldsa_corrupted_key_tests.txt
#include <openssl/evp.h>
#include <openssl/obj.h>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
#include <vector>
// Need ML-DSA internal headers to manipulate the expanded private key
extern "C" {
#include "./ml_dsa_ref/packing.h"
#include "./ml_dsa_ref/params.h"
#include "./ml_dsa_ref/polyvec.h"
}
static void PrintHex(const std::vector<uint8_t> &data) {
for (uint8_t byte : data) {
printf("%02x", byte);
}
}
struct MLDSAParamSet {
const char name[20];
const int nid;
};
static const struct MLDSAParamSet kMLDSAs[] = {{"MLDSA44", NID_MLDSA44},
{"MLDSA65", NID_MLDSA65},
{"MLDSA87", NID_MLDSA87}};
// Corruption function type: takes unpacked key components and corrupts them
using CorruptionFn =
std::function<void(polyvecl *s1, polyveck *s2, polyveck *t0)>;
// Generates a corrupted private key with the provided corruption
static bool GenerateCorruptedKey(const MLDSAParamSet &ps, ml_dsa_params *params,
const std::vector<uint8_t> &honest_key_bytes,
const CorruptionFn &corruption) {
polyvecl s1;
polyveck s2, t0;
uint8_t rho[ML_DSA_SEEDBYTES];
uint8_t tr[ML_DSA_TRBYTES];
uint8_t key[ML_DSA_SEEDBYTES];
// Unpack the honest key
ml_dsa_unpack_sk(params, rho, tr, key, &t0, &s1, &s2,
honest_key_bytes.data());
// Apply the corruption
corruption(&s1, &s2, &t0);
// Repack the corrupted key
std::vector<uint8_t> corrupted_key(params->secret_key_bytes);
ml_dsa_pack_sk(params, corrupted_key.data(), rho, tr, key, &t0, &s1, &s2);
// Verify the corrupted key differs from the honest key
assert(std::memcmp(corrupted_key.data(), honest_key_bytes.data(),
params->secret_key_bytes) != 0);
// Output the test vector
printf("# corrupted private key with invalid s1 or s2, inconsistent\n");
printf("CorruptedKey = ");
PrintHex(corrupted_key);
printf("\n\n");
// Create a consistent version by recomputing the public key and tr
std::vector<uint8_t> consistent_key = corrupted_key;
// Recompute the public key. We cannot use ml_dsa_pack_pk_from_sk since we
// fixed it to fail for invalid secret keys. Instead we adapt from
// https://github.com/aws/aws-lc/blob/0336dd78a0f2623c1f9b209a98cd497026d9c779/crypto/fipsmodule/ml_dsa/ml_dsa_ref/packing.c#L7-L61
ml_dsa_unpack_sk(params, rho, tr, key, &t0, &s1, &s2, consistent_key.data());
polyvecl mat[ML_DSA_K_MAX];
ml_dsa_polyvec_matrix_expand(params, mat, rho);
ml_dsa_polyvecl_ntt(params, &s1);
polyveck t1;
ml_dsa_polyvec_matrix_pointwise_montgomery(params, &t1, mat, &s1);
ml_dsa_polyveck_reduce(params, &t1);
ml_dsa_polyveck_invntt_tomont(params, &t1);
ml_dsa_polyveck_add(params, &t1, &t1, &s2);
ml_dsa_polyveck_caddq(params, &t1);
ml_dsa_polyveck_power2round(params, &t1, &t0, &t1);
std::vector<uint8_t> consistent_pk(params->public_key_bytes);
ml_dsa_pack_pk(params, consistent_pk.data(), rho, &t1);
// Recompute tr = SHAKE256(pk, 64)
std::vector<uint8_t> new_tr(ML_DSA_TRBYTES);
bssl::ScopedEVP_MD_CTX md_ctx;
if (!EVP_DigestInit_ex(md_ctx.get(), EVP_shake256(), nullptr) ||
!EVP_DigestUpdate(md_ctx.get(), consistent_pk.data(),
params->public_key_bytes) ||
!EVP_DigestFinalXOF(md_ctx.get(), new_tr.data(), new_tr.size())) {
return false;
}
// Repack the consistent corrupted key
ml_dsa_pack_sk(params, consistent_key.data(), rho, new_tr.data(),
consistent_pk.data(), &t0, &s1, &s2);
// Verify the consistent key differs from the inconsistent one
assert(std::memcmp(consistent_key.data(), corrupted_key.data(),
params->secret_key_bytes) != 0);
// Output the test vector
printf("# corrupted private key with invalid s1 or s2, consistent\n");
printf("CorruptedKey = ");
PrintHex(consistent_key);
printf("\n\n");
return true;
}
static bool InitializeParams(int nid, ml_dsa_params *params) {
if (nid == NID_MLDSA44) {
ml_dsa_44_params_init(params);
} else if (nid == NID_MLDSA65) {
ml_dsa_65_params_init(params);
} else if (nid == NID_MLDSA87) {
ml_dsa_87_params_init(params);
} else {
std::cerr << "Unexpected NID: " << nid << "\n";
return false;
}
return true;
}
static bool GenerateHonestKey(const MLDSAParamSet &ps,
const ml_dsa_params &params,
std::vector<uint8_t> *honest_key_bytes) {
// Generate an honest private key from a fixed seed
const std::vector<uint8_t> seed(32, 0x42);
bssl::UniquePtr<EVP_PKEY> honest_pkey(
EVP_PKEY_pqdsa_new_raw_private_key(ps.nid, seed.data(), seed.size()));
if (!honest_pkey) {
std::cerr << "Failed to generate honest key for " << ps.name << "\n";
return false;
}
// Export the honest private key to bytes
size_t key_len = params.secret_key_bytes;
honest_key_bytes->resize(key_len);
if (!EVP_PKEY_get_raw_private_key(honest_pkey.get(), honest_key_bytes->data(),
&key_len)) {
std::cerr << "Failed to export honest key for " << ps.name << "\n";
return false;
}
return true;
}
static std::vector<CorruptionFn> CreateCorruptionFunctions(
const ml_dsa_params &params, int vec_index, int coeff_index) {
return {
// Corrupt s1 with eta + 1
[&params, vec_index, coeff_index](polyvecl *s1, polyveck *, polyveck *) {
s1->vec[vec_index].coeffs[coeff_index] = params.eta + 1;
},
// Corrupt s1 with -(eta + 1)
[&params, vec_index, coeff_index](polyvecl *s1, polyveck *, polyveck *) {
s1->vec[vec_index].coeffs[coeff_index] = -(params.eta + 1);
},
// Corrupt s2 with eta + 1
[&params, vec_index, coeff_index](polyvecl *, polyveck *s2, polyveck *) {
s2->vec[vec_index].coeffs[coeff_index] = params.eta + 1;
},
// Corrupt s2 with -(eta + 1)
[&params, vec_index, coeff_index](polyvecl *, polyveck *s2, polyveck *) {
s2->vec[vec_index].coeffs[coeff_index] = -(params.eta + 1);
},
};
}
int main() {
printf(
"# Invalid ML-DSA extended private keys\n"
"# This file was generated by "
"crypto/fipsmodule/ml_dsa/make_corrupted_key_tests.cc\n\n");
for (const auto &ps : kMLDSAs) {
printf("[ParamSet = %s]\n", ps.name);
ml_dsa_params params;
if (!InitializeParams(ps.nid, &params)) {
return 1;
}
std::vector<uint8_t> honest_key_bytes;
if (!GenerateHonestKey(ps, params, &honest_key_bytes)) {
return 1;
}
// Test coefficient indices: first, last, and some random ones
const int coeff_indices[] = {0, 255, 127, 95, 42, 224};
for (int vec_index = 0; vec_index < params.l; vec_index++) {
for (int coeff_index : coeff_indices) {
const std::vector<CorruptionFn> corruptions =
CreateCorruptionFunctions(params, vec_index, coeff_index);
for (const auto &corruption : corruptions) {
if (!GenerateCorruptedKey(ps, &params, honest_key_bytes,
corruption)) {
return 1;
}
}
}
}
}
return 0;
}

View File

@@ -0,0 +1,603 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
// mldsa-native source code
// Include level-independent code
#define MLD_CONFIG_FILE "../mldsa_native_config.h"
#define MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS
// MLDSA-44
#define MLD_CONFIG_PARAMETER_SET 44
#define MLD_CONFIG_MULTILEVEL_WITH_SHARED // Include level-independent code
#include "mldsa/mldsa_native_bcm.c"
// MLDSA-65
#undef MLD_CONFIG_PARAMETER_SET
#define MLD_CONFIG_PARAMETER_SET 65
#define MLD_CONFIG_MULTILEVEL_NO_SHARED // Exclude level-independent code
#include "mldsa/mldsa_native_bcm.c"
// MLDSA-87
#undef MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS
#undef MLD_CONFIG_PARAMETER_SET
#define MLD_CONFIG_PARAMETER_SET 87
#include "mldsa/mldsa_native_bcm.c"
// End of mldsa-native source code
#include "./ml_dsa.h"
#include "../../evp_extra/internal.h"
#include "../evp/internal.h"
#include "../service_indicator/internal.h"
// Note: These methods provide AWS-LC-specific wrappers around mldsa-native.
int ml_dsa_44_keypair_internal(uint8_t *public_key /* OUT */,
uint8_t *private_key /* OUT */,
const uint8_t *seed /* IN */) {
boringssl_ensure_ml_dsa_self_test();
return ml_dsa_44_keypair_internal_no_self_test(public_key, private_key, seed);
}
int ml_dsa_44_keypair_internal_no_self_test(uint8_t *public_key /* OUT */,
uint8_t *private_key /* OUT */,
const uint8_t *seed /* IN */) {
int ret = mldsa44_keypair_internal(public_key, private_key, seed);
#if defined(AWSLC_FIPS)
/* PCT failure is the only failure condition for key generation. */
if (ret != 0) {
AWS_LC_FIPS_failure("ML-DSA keygen PCT failed");
}
#endif
return (ret == 0) ? 1 : 0; // Convert: mldsa 0=success -> AWS-LC 1=success
}
int ml_dsa_44_keypair(uint8_t *public_key /* OUT */,
uint8_t *private_key /* OUT */,
uint8_t *seed /* OUT */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
// Generate seed
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(seed, MLDSA44_KEYGEN_SEED_BYTES));
int ret = mldsa44_keypair_internal(public_key, private_key, seed);
#if defined(AWSLC_FIPS)
/* PCT failure is the only failure condition for key generation. */
if (ret != 0) {
AWS_LC_FIPS_failure("ML-DSA keygen PCT failed");
}
#endif
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_44_pack_pk_from_sk(uint8_t *public_key /* OUT */,
const uint8_t *private_key /* IN */) {
int ret = mldsa44_pk_from_sk(public_key, private_key);
return (ret == 0) ? 1 : 0; // Convert: mldsa 0=success, -1=failure -> AWS-LC 1=success, 0=failure
}
int ml_dsa_44_sign(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *ctx_string /* IN */,
size_t ctx_string_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa44_signature(sig, sig_len, message, message_len,
ctx_string, ctx_string_len, private_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_extmu_44_sign(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
// mu_len is ignored - extmu always uses MLDSA_CRHBYTES (64 bytes)
(void)mu_len;
int ret = mldsa44_signature_extmu(sig, sig_len, mu, private_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_44_sign_internal(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */,
const uint8_t *rnd /* IN */) {
boringssl_ensure_ml_dsa_self_test();
return ml_dsa_44_sign_internal_no_self_test(private_key, sig, sig_len, message,
message_len, pre, pre_len, rnd);
}
int ml_dsa_44_sign_internal_no_self_test(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */,
const uint8_t *rnd /* IN */) {
int ret = mldsa44_signature_internal(sig, sig_len, message, message_len,
pre, pre_len, rnd, private_key, 0);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_extmu_44_sign_internal(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */,
const uint8_t *rnd /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa44_signature_internal(sig, sig_len, mu, mu_len,
pre, pre_len, rnd, private_key, 1);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_44_verify(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *ctx_string /* IN */,
size_t ctx_string_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa44_verify(sig, sig_len, message, message_len,
ctx_string, ctx_string_len, public_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_extmu_44_verify(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
// mu_len is ignored - extmu always uses MLDSA_CRHBYTES (64 bytes)
(void)mu_len;
int ret = mldsa44_verify_extmu(sig, sig_len, mu, public_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_44_verify_internal(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */) {
boringssl_ensure_ml_dsa_self_test();
return ml_dsa_44_verify_internal_no_self_test(public_key, sig, sig_len, message,
message_len, pre, pre_len);
}
int ml_dsa_44_verify_internal_no_self_test(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */) {
int ret = mldsa44_verify_internal(sig, sig_len, message, message_len,
pre, pre_len, public_key, 0);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_extmu_44_verify_internal(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa44_verify_internal(sig, sig_len, mu, mu_len,
pre, pre_len, public_key, 1);
return (ret == 0) ? 1 : 0;
}
// ML-DSA-65 implementations
int ml_dsa_65_keypair(uint8_t *public_key /* OUT */,
uint8_t *private_key /* OUT */,
uint8_t *seed /* OUT */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(seed, MLDSA65_KEYGEN_SEED_BYTES));
int ret = mldsa65_keypair_internal(public_key, private_key, seed);
#if defined(AWSLC_FIPS)
/* PCT failure is the only failure condition for key generation. */
if (ret != 0) {
AWS_LC_FIPS_failure("ML-DSA keygen PCT failed");
}
#endif
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_65_pack_pk_from_sk(uint8_t *public_key /* OUT */,
const uint8_t *private_key /* IN */) {
int ret = mldsa65_pk_from_sk(public_key, private_key);
return (ret == 0) ? 1 : 0; // Convert: mldsa 0=success, -1=failure -> AWS-LC 1=success, 0=failure
}
int ml_dsa_65_keypair_internal(uint8_t *public_key /* OUT */,
uint8_t *private_key /* OUT */,
const uint8_t *seed /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa65_keypair_internal(public_key, private_key, seed);
#if defined(AWSLC_FIPS)
/* PCT failure is the only failure condition for key generation. */
if (ret != 0) {
AWS_LC_FIPS_failure("ML-DSA keygen PCT failed");
}
#endif
return (ret == 0) ? 1 : 0; // Convert: mldsa 0=success -> AWS-LC 1=success
}
int ml_dsa_65_sign(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *ctx_string /* IN */,
size_t ctx_string_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa65_signature(sig, sig_len, message, message_len,
ctx_string, ctx_string_len, private_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_extmu_65_sign(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
// mu_len is ignored - extmu always uses MLDSA_CRHBYTES (64 bytes)
(void)mu_len;
int ret = mldsa65_signature_extmu(sig, sig_len, mu, private_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_65_sign_internal(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */,
const uint8_t *rnd /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa65_signature_internal(sig, sig_len, message, message_len,
pre, pre_len, rnd, private_key, 0);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_extmu_65_sign_internal(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */,
const uint8_t *rnd /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa65_signature_internal(sig, sig_len, mu, mu_len,
pre, pre_len, rnd, private_key, 1);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_65_verify(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *ctx_string /* IN */,
size_t ctx_string_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa65_verify(sig, sig_len, message, message_len,
ctx_string, ctx_string_len, public_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_extmu_65_verify(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
// mu_len is ignored - extmu always uses MLDSA_CRHBYTES (64 bytes)
(void)mu_len;
int ret = mldsa65_verify_extmu(sig, sig_len, mu, public_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_65_verify_internal(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa65_verify_internal(sig, sig_len, message, message_len,
pre, pre_len, public_key, 0);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_extmu_65_verify_internal(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa65_verify_internal(sig, sig_len, mu, mu_len,
pre, pre_len, public_key, 1);
return (ret == 0) ? 1 : 0;
}
// ML-DSA-87 implementations
int ml_dsa_87_keypair(uint8_t *public_key /* OUT */,
uint8_t *private_key /* OUT */,
uint8_t *seed /* OUT */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(seed, MLDSA87_KEYGEN_SEED_BYTES));
int ret = mldsa87_keypair_internal(public_key, private_key, seed);
#if defined(AWSLC_FIPS)
/* PCT failure is the only failure condition for key generation. */
if (ret != 0) {
AWS_LC_FIPS_failure("ML-DSA keygen PCT failed");
}
#endif
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_87_pack_pk_from_sk(uint8_t *public_key /* OUT */,
const uint8_t *private_key /* IN */) {
int ret = mldsa87_pk_from_sk(public_key, private_key);
return (ret == 0) ? 1 : 0; // Convert: mldsa 0=success, -1=failure -> AWS-LC 1=success, 0=failure
}
int ml_dsa_87_keypair_internal(uint8_t *public_key /* OUT */,
uint8_t *private_key /* OUT */,
const uint8_t *seed /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa87_keypair_internal(public_key, private_key, seed);
#if defined(AWSLC_FIPS)
/* PCT failure is the only failure condition for key generation. */
if (ret != 0) {
AWS_LC_FIPS_failure("ML-DSA keygen PCT failed");
}
#endif
return (ret == 0) ? 1 : 0; // Convert: mldsa 0=success -> AWS-LC 1=success
}
int ml_dsa_87_sign(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *ctx_string /* IN */,
size_t ctx_string_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa87_signature(sig, sig_len, message, message_len,
ctx_string, ctx_string_len, private_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_extmu_87_sign(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
// mu_len is ignored - extmu always uses MLDSA_CRHBYTES (64 bytes)
(void)mu_len;
int ret = mldsa87_signature_extmu(sig, sig_len, mu, private_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_87_sign_internal(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */,
const uint8_t *rnd /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa87_signature_internal(sig, sig_len, message, message_len,
pre, pre_len, rnd, private_key, 0);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_extmu_87_sign_internal(const uint8_t *private_key /* IN */,
uint8_t *sig /* OUT */,
size_t *sig_len /* OUT */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */,
const uint8_t *rnd /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa87_signature_internal(sig, sig_len, mu, mu_len,
pre, pre_len, rnd, private_key, 1);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_87_verify(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *ctx_string /* IN */,
size_t ctx_string_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa87_verify(sig, sig_len, message, message_len,
ctx_string, ctx_string_len, public_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_extmu_87_verify(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */) {
FIPS_service_indicator_lock_state();
boringssl_ensure_ml_dsa_self_test();
// mu_len is ignored - extmu always uses MLDSA_CRHBYTES (64 bytes)
(void)mu_len;
int ret = mldsa87_verify_extmu(sig, sig_len, mu, public_key);
FIPS_service_indicator_unlock_state();
if (ret == 0) {
FIPS_service_indicator_update_state();
return 1;
}
return 0;
}
int ml_dsa_87_verify_internal(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *message /* IN */,
size_t message_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa87_verify_internal(sig, sig_len, message, message_len,
pre, pre_len, public_key, 0);
return (ret == 0) ? 1 : 0;
}
int ml_dsa_extmu_87_verify_internal(const uint8_t *public_key /* IN */,
const uint8_t *sig /* IN */,
size_t sig_len /* IN */,
const uint8_t *mu /* IN */,
size_t mu_len /* IN */,
const uint8_t *pre /* IN */,
size_t pre_len /* IN */) {
boringssl_ensure_ml_dsa_self_test();
int ret = mldsa87_verify_internal(sig, sig_len, mu, mu_len,
pre, pre_len, public_key, 1);
return (ret == 0) ? 1 : 0;
}

View File

@@ -0,0 +1,204 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#ifndef ML_DSA_H
#define ML_DSA_H
#include <stddef.h>
#include <stdint.h>
#include <openssl/base.h>
#include <openssl/evp.h>
#define MLDSA44_PUBLIC_KEY_BYTES 1312
#define MLDSA44_PRIVATE_KEY_BYTES 2560
#define MLDSA44_SIGNATURE_BYTES 2420
#define MLDSA44_KEYGEN_SEED_BYTES 32
#define MLDSA44_SIGNATURE_SEED_BYTES 32
#define MLDSA65_PUBLIC_KEY_BYTES 1952
#define MLDSA65_PRIVATE_KEY_BYTES 4032
#define MLDSA65_SIGNATURE_BYTES 3309
#define MLDSA65_KEYGEN_SEED_BYTES 32
#define MLDSA65_SIGNATURE_SEED_BYTES 32
#define MLDSA87_PUBLIC_KEY_BYTES 2592
#define MLDSA87_PRIVATE_KEY_BYTES 4896
#define MLDSA87_SIGNATURE_BYTES 4627
#define MLDSA87_KEYGEN_SEED_BYTES 32
#define MLDSA87_SIGNATURE_SEED_BYTES 32
#if defined(__cplusplus)
extern "C" {
#endif
OPENSSL_EXPORT int ml_dsa_44_keypair(uint8_t *public_key,
uint8_t *secret_key,
uint8_t *seed);
OPENSSL_EXPORT int ml_dsa_44_pack_pk_from_sk(uint8_t *public_key,
const uint8_t *private_key);
int ml_dsa_44_keypair_internal_no_self_test(uint8_t *public_key,
uint8_t *private_key,
const uint8_t *seed);
OPENSSL_EXPORT int ml_dsa_44_keypair_internal(uint8_t *public_key,
uint8_t *private_key,
const uint8_t *seed);
OPENSSL_EXPORT int ml_dsa_44_sign(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *ctx_string, size_t ctx_string_len);
OPENSSL_EXPORT int ml_dsa_extmu_44_sign(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *mu, size_t mu_len);
OPENSSL_EXPORT int ml_dsa_44_sign_internal(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *pre, size_t pre_len,
const uint8_t *rnd);
int ml_dsa_44_sign_internal_no_self_test(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *pre, size_t pre_len,
const uint8_t *rnd);
OPENSSL_EXPORT int ml_dsa_extmu_44_sign_internal(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *mu, size_t mu_len,
const uint8_t *pre, size_t pre_len,
const uint8_t *rnd);
OPENSSL_EXPORT int ml_dsa_44_verify(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *ctx_string, size_t ctx_string_len);
OPENSSL_EXPORT int ml_dsa_extmu_44_verify(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *mu, size_t mu_len);
OPENSSL_EXPORT int ml_dsa_44_verify_internal(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *pre, size_t pre_len);
int ml_dsa_44_verify_internal_no_self_test(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *pre, size_t pre_len);
OPENSSL_EXPORT int ml_dsa_extmu_44_verify_internal(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *mu, size_t mu_len,
const uint8_t *pre, size_t pre_len);
OPENSSL_EXPORT int ml_dsa_65_keypair(uint8_t *public_key,
uint8_t *secret_key,
uint8_t *seed);
OPENSSL_EXPORT int ml_dsa_65_pack_pk_from_sk(uint8_t *public_key,
const uint8_t *private_key);
OPENSSL_EXPORT int ml_dsa_65_keypair_internal(uint8_t *public_key,
uint8_t *private_key,
const uint8_t *seed);
OPENSSL_EXPORT int ml_dsa_65_sign(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *ctx_string, size_t ctx_string_len);
OPENSSL_EXPORT int ml_dsa_extmu_65_sign(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *mu, size_t mu_len);
OPENSSL_EXPORT int ml_dsa_65_sign_internal(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *pre, size_t pre_len,
const uint8_t *rnd);
OPENSSL_EXPORT int ml_dsa_extmu_65_sign_internal(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *mu, size_t mu_len,
const uint8_t *pre, size_t pre_len,
const uint8_t *rnd);
OPENSSL_EXPORT int ml_dsa_65_verify(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *ctx_string, size_t ctx_string_len);
OPENSSL_EXPORT int ml_dsa_extmu_65_verify(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *mu, size_t mu_len);
OPENSSL_EXPORT int ml_dsa_65_verify_internal(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *pre, size_t pre_len);
OPENSSL_EXPORT int ml_dsa_extmu_65_verify_internal(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *mu, size_t mu_len,
const uint8_t *pre, size_t pre_len);
OPENSSL_EXPORT int ml_dsa_87_keypair(uint8_t *public_key,
uint8_t *secret_key,
uint8_t *seed);
OPENSSL_EXPORT int ml_dsa_87_pack_pk_from_sk(uint8_t *public_key,
const uint8_t *private_key);
OPENSSL_EXPORT int ml_dsa_87_keypair_internal(uint8_t *public_key,
uint8_t *private_key,
const uint8_t *seed);
OPENSSL_EXPORT int ml_dsa_87_sign(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *ctx_string, size_t ctx_string_len);
OPENSSL_EXPORT int ml_dsa_extmu_87_sign(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *mu, size_t mu_len);
OPENSSL_EXPORT int ml_dsa_87_sign_internal(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *pre, size_t pre_len,
const uint8_t *rnd);
OPENSSL_EXPORT int ml_dsa_extmu_87_sign_internal(const uint8_t *private_key,
uint8_t *sig, size_t *sig_len,
const uint8_t *mu, size_t mu_len,
const uint8_t *pre, size_t pre_len,
const uint8_t *rnd);
OPENSSL_EXPORT int ml_dsa_87_verify(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *ctx_string, size_t ctx_string_len);
OPENSSL_EXPORT int ml_dsa_extmu_87_verify(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *mu, size_t mu_len);
OPENSSL_EXPORT int ml_dsa_87_verify_internal(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *message, size_t message_len,
const uint8_t *pre, size_t pre_len);
OPENSSL_EXPORT int ml_dsa_extmu_87_verify_internal(const uint8_t *public_key,
const uint8_t *sig, size_t sig_len,
const uint8_t *mu, size_t mu_len,
const uint8_t *pre, size_t pre_len);
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_CBMC_H
#define MLD_CBMC_H
/***************************************************
* Basic replacements for __CPROVER_XXX contracts
***************************************************/
#ifndef CBMC
#define __contract__(x)
#define __loop__(x)
#define cassert(x)
#else /* !CBMC */
#include <stdint.h>
#define __contract__(x) x
#define __loop__(x) x
/* https://diffblue.github.io/cbmc/contracts-assigns.html */
#define assigns(...) __CPROVER_assigns(__VA_ARGS__)
/* https://diffblue.github.io/cbmc/contracts-requires-ensures.html */
#define requires(...) __CPROVER_requires(__VA_ARGS__)
#define ensures(...) __CPROVER_ensures(__VA_ARGS__)
/* https://diffblue.github.io/cbmc/contracts-loops.html */
#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__)
#define decreases(...) __CPROVER_decreases(__VA_ARGS__)
/* cassert to avoid confusion with in-built assert */
#define cassert(x) __CPROVER_assert(x, "cbmc assertion failed")
#define assume(...) __CPROVER_assume(__VA_ARGS__)
/***************************************************
* Macros for "expression" forms that may appear
* _inside_ top-level contracts.
***************************************************/
/*
* function return value - useful inside ensures
* https://diffblue.github.io/cbmc/contracts-functions.html
*/
#define return_value (__CPROVER_return_value)
/*
* assigns l-value targets
* https://diffblue.github.io/cbmc/contracts-assigns.html
*/
#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__)
#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__)
#define same_object(...) __CPROVER_same_object(__VA_ARGS__)
/*
* Pointer-related predicates
* https://diffblue.github.io/cbmc/contracts-memory-predicates.html
*/
#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__)
#define readable(...) __CPROVER_r_ok(__VA_ARGS__)
#define writeable(...) __CPROVER_w_ok(__VA_ARGS__)
/* Maximum supported buffer size
*
* Larger buffers may be supported, but due to internal modeling constraints
* in CBMC, the proofs of memory- and type-safety won't be able to run.
*
* If you find yourself in need for a buffer size larger than this,
* please contact the maintainers, so we can prioritize work to relax
* this somewhat artificial bound.
*/
#define MLD_MAX_BUFFER_SIZE (SIZE_MAX >> 12)
/*
* History variables
* https://diffblue.github.io/cbmc/contracts-history-variables.html
*/
#define old(...) __CPROVER_old(__VA_ARGS__)
#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__)
/*
* Quantifiers
* Note that the range on qvar is _exclusive_ between qvar_lb .. qvar_ub
* https://diffblue.github.io/cbmc/contracts-quantifiers.html
*/
/*
* Prevent clang-format from corrupting CBMC's special ==> operator
*/
/* clang-format off */
#define forall(qvar, qvar_lb, qvar_ub, predicate) \
__CPROVER_forall \
{ \
unsigned qvar; \
((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> (predicate) \
}
#define exists(qvar, qvar_lb, qvar_ub, predicate) \
__CPROVER_exists \
{ \
unsigned qvar; \
((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) && (predicate) \
}
/* clang-format on */
/***************************************************
* Convenience macros for common contract patterns
***************************************************/
/*
* Prevent clang-format from corrupting CBMC's special ==> operator
*/
/* clang-format off */
#define CBMC_CONCAT_(left, right) left##right
#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right)
#define array_bound_core(qvar, qvar_lb, qvar_ub, array_var, \
value_lb, value_ub) \
__CPROVER_forall \
{ \
unsigned qvar; \
((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \
(((int)(value_lb) <= ((array_var)[(qvar)])) && \
(((array_var)[(qvar)]) < (int)(value_ub))) \
}
#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \
array_bound_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), (qvar_lb), \
(qvar_ub), (array_var), (value_lb), (value_ub))
#define array_unchanged_core(qvar, qvar_lb, qvar_ub, array_var) \
__CPROVER_forall \
{ \
unsigned qvar; \
((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \
((array_var)[(qvar)]) == (old(* (int32_t (*)[(qvar_ub)])(array_var)))[(qvar)] \
}
#define array_unchanged(array_var, N) \
array_unchanged_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var))
#define array_unchanged_u64_core(qvar, qvar_lb, qvar_ub, array_var) \
__CPROVER_forall \
{ \
unsigned qvar; \
((qvar_lb) <= (qvar) && (qvar) < (qvar_ub)) ==> \
((array_var)[(qvar)]) == (old(* (uint64_t (*)[(qvar_ub)])(array_var)))[(qvar)] \
}
#define array_unchanged_u64(array_var, N) \
array_unchanged_u64_core(CBMC_CONCAT(_cbmc_idx, __COUNTER__), 0, (N), (array_var))
/* clang-format on */
/* Wrapper around array_bound operating on absolute values.
*
* The absolute value bound `k` is exclusive.
*
* Note that since the lower bound in array_bound is inclusive, we have to
* raise it by 1 here.
*/
#define array_abs_bound(arr, lb, ub, k) \
array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k))
#endif /* CBMC */
#endif /* !MLD_CBMC_H */

View File

@@ -0,0 +1,300 @@
/*
* Copyright (c) The mldsa-native project authors
* Copyright (c) The mlkem-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_COMMON_H
#define MLD_COMMON_H
#define MLD_BUILD_INTERNAL
#if defined(MLD_CONFIG_FILE)
#include MLD_CONFIG_FILE
#else
#include "mldsa_native_config.h"
#endif
#include "params.h"
#include "sys.h"
/* Internal and public API have external linkage by default, but
* this can be overwritten by the user, e.g. for single-CU builds. */
#if !defined(MLD_CONFIG_INTERNAL_API_QUALIFIER)
#define MLD_INTERNAL_API
#else
#define MLD_INTERNAL_API MLD_CONFIG_INTERNAL_API_QUALIFIER
#endif
#if !defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER)
#define MLD_EXTERNAL_API
#else
#define MLD_EXTERNAL_API MLD_CONFIG_EXTERNAL_API_QUALIFIER
#endif
#if defined(MLD_CONFIG_MULTILEVEL_NO_SHARED) || \
defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED)
#define MLD_MULTILEVEL_BUILD
#endif
#define MLD_CONCAT_(x1, x2) x1##x2
#define MLD_CONCAT(x1, x2) MLD_CONCAT_(x1, x2)
#if defined(MLD_MULTILEVEL_BUILD)
#define MLD_ADD_PARAM_SET(s) MLD_CONCAT(s, MLD_CONFIG_PARAMETER_SET)
#else
#define MLD_ADD_PARAM_SET(s) s
#endif
#define MLD_NAMESPACE_PREFIX MLD_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, _)
#define MLD_NAMESPACE_PREFIX_KL \
MLD_CONCAT(MLD_ADD_PARAM_SET(MLD_CONFIG_NAMESPACE_PREFIX), _)
/* Functions are prefixed by MLD_CONFIG_NAMESPACE_PREFIX.
*
* If multiple parameter sets are used, functions depending on the parameter
* set are additionally prefixed with 44/65/87. See mldsa_native_config.h.
*
* Example: If MLD_CONFIG_NAMESPACE_PREFIX is PQCP_MLDSA_NATIVE, then
* MLD_NAMESPACE_KL(keypair) becomes PQCP_MLDSA_NATIVE44_keypair/
* PQCP_MLDSA_NATIVE65_keypair/PQCP_MLDSA_NATIVE87_keypair.
*/
#define MLD_NAMESPACE(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX, s)
#define MLD_NAMESPACE_KL(s) MLD_CONCAT(MLD_NAMESPACE_PREFIX_KL, s)
/* On Apple platforms, we need to emit leading underscore
* in front of assembly symbols. We thus introducee a separate
* namespace wrapper for ASM symbols. */
#if !defined(__APPLE__)
#define MLD_ASM_NAMESPACE(sym) MLD_NAMESPACE(sym)
#else
#define MLD_ASM_NAMESPACE(sym) MLD_CONCAT(_, MLD_NAMESPACE(sym))
#endif
/*
* On X86_64 if control-flow protections (CET) are enabled (through
* -fcf-protection=), we add an endbr64 instruction at every global function
* label. See sys.h for more details
*/
#if defined(MLD_SYS_X86_64)
#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) : MLD_CET_ENDBR
#else
#define MLD_ASM_FN_SYMBOL(sym) MLD_ASM_NAMESPACE(sym) :
#endif
/* We aim to simplify the user's life by supporting builds where
* all source files are included, even those that are not needed.
* Those files are appropriately guarded and will be empty when unneeded.
* The following is to avoid compilers complaining about this. */
#define MLD_EMPTY_CU(s) extern int MLD_NAMESPACE_KL(empty_cu_##s);
/* MLD_CONFIG_NO_ASM takes precedence over MLD_USE_NATIVE_XXX */
#if defined(MLD_CONFIG_NO_ASM)
#undef MLD_CONFIG_USE_NATIVE_BACKEND_ARITH
#undef MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202
#endif
#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH) && \
!defined(MLD_CONFIG_ARITH_BACKEND_FILE)
#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_ARITH is set, but MLD_CONFIG_ARITH_BACKEND_FILE is not.
#endif
#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202) && \
!defined(MLD_CONFIG_FIPS202_BACKEND_FILE)
#error Bad configuration: MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 is set, but MLD_CONFIG_FIPS202_BACKEND_FILE is not.
#endif
#if defined(MLD_CONFIG_NO_RANDOMIZED_API) && defined(MLD_CONFIG_KEYGEN_PCT)
#error Bad configuration: MLD_CONFIG_NO_RANDOMIZED_API is incompatible with MLD_CONFIG_KEYGEN_PCT as the current PCT implementation requires crypto_sign_signature()
#endif
#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)
#include MLD_CONFIG_ARITH_BACKEND_FILE
/* Include to enforce consistency of API and implementation,
* and conduct sanity checks on the backend.
*
* Keep this _after_ the inclusion of the backend; otherwise,
* the sanity checks won't have an effect. */
#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__)
#include "native/api.h"
#endif
#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */
#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202)
#include MLD_CONFIG_FIPS202_BACKEND_FILE
/* Include to enforce consistency of API and implementation,
* and conduct sanity checks on the backend.
*
* Keep this _after_ the inclusion of the backend; otherwise,
* the sanity checks won't have an effect. */
#if defined(MLD_CHECK_APIS) && !defined(__ASSEMBLER__)
#include "fips202/native/api.h"
#endif
#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202 */
#if !defined(MLD_CONFIG_FIPS202_CUSTOM_HEADER)
#define MLD_FIPS202_HEADER_FILE "fips202/fips202.h"
#else
#define MLD_FIPS202_HEADER_FILE MLD_CONFIG_FIPS202_CUSTOM_HEADER
#endif
#if !defined(MLD_CONFIG_FIPS202X4_CUSTOM_HEADER)
#define MLD_FIPS202X4_HEADER_FILE "fips202/fips202x4.h"
#else
#define MLD_FIPS202X4_HEADER_FILE MLD_CONFIG_FIPS202X4_CUSTOM_HEADER
#endif
/* Standard library function replacements */
#if !defined(__ASSEMBLER__)
#if !defined(MLD_CONFIG_CUSTOM_MEMCPY)
#include <string.h>
#define mld_memcpy memcpy
#endif
#if !defined(MLD_CONFIG_CUSTOM_MEMSET)
#include <string.h>
#define mld_memset memset
#endif
/* Allocation macros for large local structures
*
* MLD_ALLOC(v, T, N) declares T *v and attempts to point it to an T[N]
* MLD_FREE(v, T, N) zeroizes and frees the allocation
*
* Default implementation uses stack allocation.
* Can be overridden by setting the config option MLD_CONFIG_CUSTOM_ALLOC_FREE
* and defining MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE.
*/
#if defined(MLD_CONFIG_CUSTOM_ALLOC_FREE) != \
(defined(MLD_CUSTOM_ALLOC) && defined(MLD_CUSTOM_FREE))
#error Bad configuration: MLD_CONFIG_CUSTOM_ALLOC_FREE must be set together with MLD_CUSTOM_ALLOC and MLD_CUSTOM_FREE
#endif
/*
* If the integration wants to provide a context parameter for use in
* platform-specific hooks, then it should define this parameter.
*
* The MLD_CONTEXT_PARAMETERS_n macros are intended to be used with macros
* defining the function names and expand to either pass or discard the context
* argument as required by the current build. If there is no context parameter
* requested then these are removed from the prototypes and from all calls.
*/
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
#define MLD_CONTEXT_PARAMETERS_0(context) (context)
#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0, context)
#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1, context)
#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) \
(arg0, arg1, arg2, context)
#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \
(arg0, arg1, arg2, arg3, context)
#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \
(arg0, arg1, arg2, arg3, arg4, context)
#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \
(arg0, arg1, arg2, arg3, arg4, arg5, context)
#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \
context) \
(arg0, arg1, arg2, arg3, arg4, arg5, arg6, context)
#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \
arg7, context) \
(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, context)
#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \
arg7, arg8, context) \
(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, context)
#else /* MLD_CONFIG_CONTEXT_PARAMETER */
#define MLD_CONTEXT_PARAMETERS_0(context) ()
#define MLD_CONTEXT_PARAMETERS_1(arg0, context) (arg0)
#define MLD_CONTEXT_PARAMETERS_2(arg0, arg1, context) (arg0, arg1)
#define MLD_CONTEXT_PARAMETERS_3(arg0, arg1, arg2, context) (arg0, arg1, arg2)
#define MLD_CONTEXT_PARAMETERS_4(arg0, arg1, arg2, arg3, context) \
(arg0, arg1, arg2, arg3)
#define MLD_CONTEXT_PARAMETERS_5(arg0, arg1, arg2, arg3, arg4, context) \
(arg0, arg1, arg2, arg3, arg4)
#define MLD_CONTEXT_PARAMETERS_6(arg0, arg1, arg2, arg3, arg4, arg5, context) \
(arg0, arg1, arg2, arg3, arg4, arg5)
#define MLD_CONTEXT_PARAMETERS_7(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \
context) \
(arg0, arg1, arg2, arg3, arg4, arg5, arg6)
#define MLD_CONTEXT_PARAMETERS_8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \
arg7, context) \
(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define MLD_CONTEXT_PARAMETERS_9(arg0, arg1, arg2, arg3, arg4, arg5, arg6, \
arg7, arg8, context) \
(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#endif /* !MLD_CONFIG_CONTEXT_PARAMETER */
#if defined(MLD_CONFIG_CONTEXT_PARAMETER_TYPE) != \
defined(MLD_CONFIG_CONTEXT_PARAMETER)
#error MLD_CONFIG_CONTEXT_PARAMETER_TYPE must be defined if and only if MLD_CONFIG_CONTEXT_PARAMETER is defined
#endif
#if !defined(MLD_CONFIG_CUSTOM_ALLOC_FREE)
/* Default: stack allocation */
#define MLD_ALLOC(v, T, N, context) \
MLD_ALIGN T mld_alloc_##v[N]; \
T *v = mld_alloc_##v
/* TODO: This leads to a circular dependency between common and ct.h
* It just works out before we're at the end of the file, but it's still
* prone to issues in the future. */
#include "ct.h"
#define MLD_FREE(v, T, N, context) \
do \
{ \
mld_zeroize(mld_alloc_##v, sizeof(mld_alloc_##v)); \
(v) = NULL; \
} while (0)
#else /* !MLD_CONFIG_CUSTOM_ALLOC_FREE */
/* Custom allocation */
/*
* The indirection here is necessary to use MLD_CONTEXT_PARAMETERS_3 here.
*/
#define MLD_APPLY(f, args) f args
#define MLD_ALLOC(v, T, N, context) \
MLD_APPLY(MLD_CUSTOM_ALLOC, MLD_CONTEXT_PARAMETERS_3(v, T, N, context))
#define MLD_FREE(v, T, N, context) \
do \
{ \
if (v != NULL) \
{ \
mld_zeroize(v, sizeof(T) * (N)); \
MLD_APPLY(MLD_CUSTOM_FREE, MLD_CONTEXT_PARAMETERS_3(v, T, N, context)); \
v = NULL; \
} \
} while (0)
#endif /* MLD_CONFIG_CUSTOM_ALLOC_FREE */
/*
* We are facing severe CBMC performance issues when using unions.
* As a temporary workaround, we use unions only when MLD_CONFIG_REDUCE_RAM is
* set.
* TODO: Remove the workaround once
* https://github.com/diffblue/cbmc/issues/8813
* is resolved
*/
#if defined(MLD_CONFIG_REDUCE_RAM)
#define MLK_UNION_OR_STRUCT union
#else
#define MLK_UNION_OR_STRUCT struct
#endif
/****************************** Error codes ***********************************/
/* Generic failure condition */
#define MLD_ERR_FAIL -1
/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE
* is defined and the provided MLD_CUSTOM_ALLOC can fail. */
#define MLD_ERR_OUT_OF_MEMORY -2
/* An rng failure occured. Might be due to insufficient entropy or
* system misconfiguration. */
#define MLD_ERR_RNG_FAIL -3
#endif /* !__ASSEMBLER__ */
#endif /* !MLD_COMMON_H */

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) The mlkem-native project authors
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#include "ct.h"
#if !defined(MLD_USE_ASM_VALUE_BARRIER) && \
!defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)
/*
* Masking value used in constant-time functions from
* ct.h to block the compiler's range analysis and
* thereby reduce the risk of compiler-introduced branches.
*/
volatile uint64_t mld_ct_opt_blocker_u64 = 0;
#else /* !MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED */
MLD_EMPTY_CU(ct)
#endif /* !(!MLD_USE_ASM_VALUE_BARRIER && !MLD_CONFIG_MULTILEVEL_NO_SHARED) */

View File

@@ -0,0 +1,366 @@
/*
* Copyright (c) The mlkem-native project authors
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* References
* ==========
*
* - [FIPS204]
* FIPS 204 Module-Lattice-Based Digital Signature Standard
* National Institute of Standards and Technology
* https://csrc.nist.gov/pubs/fips/204/final
*
* - [libmceliece]
* libmceliece implementation of Classic McEliece
* Bernstein, Chou
* https://lib.mceliece.org/
*
* - [optblocker]
* PQC forum post on opt-blockers using volatile globals
* Daniel J. Bernstein
* https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/hqbtIGFKIpU/m/H14H0wOlBgAJ
*/
#ifndef MLD_CT_H
#define MLD_CT_H
#include <stdint.h>
#include "cbmc.h"
#include "common.h"
/* Constant-time comparisons and conditional operations
We reduce the risk for compilation into variable-time code
through the use of 'value barriers'.
Functionally, a value barrier is a no-op. To the compiler, however,
it constitutes an arbitrary modification of its input, and therefore
harden's value propagation and range analysis.
We consider two approaches to implement a value barrier:
- An empty inline asm block which marks the target value as clobbered.
- XOR'ing with the value of a volatile global that's set to 0;
see @[optblocker] for a discussion of this idea, and
@[libmceliece, inttypes/crypto_intN.h] for an implementation.
The first approach is cheap because it only prevents the compiler
from reasoning about the value of the variable past the barrier,
but does not directly generate additional instructions.
The second approach generates redundant loads and XOR operations
and therefore comes at a higher runtime cost. However, it appears
more robust towards optimization, as compilers should never drop
a volatile load.
We use the empty-ASM value barrier for GCC and clang, and fall
back to the global volatile barrier otherwise.
The global value barrier can be forced by setting
MLD_CONFIG_NO_ASM_VALUE_BARRIER.
*/
#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER)
#define MLD_USE_ASM_VALUE_BARRIER
#endif
#if !defined(MLD_USE_ASM_VALUE_BARRIER)
/*
* Declaration of global volatile that the global value barrier
* is loading from and masking with.
*/
#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64)
extern volatile uint64_t mld_ct_opt_blocker_u64;
/* Helper functions for obtaining global masks of various sizes */
/* This contract is not proved but treated as an axiom.
*
* Its validity relies on the assumption that the global opt-blocker
* constant mld_ct_opt_blocker_u64 is not modified.
*/
static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void)
__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; }
static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void)
__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); }
static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void)
__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); }
static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void)
__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); }
/* Opt-blocker based implementation of value barriers */
static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b)
__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); }
static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b)
__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); }
static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b)
__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); }
#else /* !MLD_USE_ASM_VALUE_BARRIER */
static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b)
__contract__(ensures(return_value == b))
{
__asm__ volatile("" : "+r"(b));
return b;
}
static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b)
__contract__(ensures(return_value == b))
{
__asm__ volatile("" : "+r"(b));
return b;
}
static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b)
__contract__(ensures(return_value == b))
{
__asm__ volatile("" : "+r"(b));
return b;
}
#endif /* MLD_USE_ASM_VALUE_BARRIER */
#ifdef CBMC
#pragma CPROVER check push
#pragma CPROVER check disable "conversion"
#endif
/*************************************************
* Name: mld_cast_uint32_to_int32
*
* Description: Cast uint32 value to int32
*
* Returns: For uint32_t x, the unique y in int32_t
* so that x == y mod 2^32.
*
* Concretely:
* - x < 2^31: returns x
* - x >= 2^31: returns x - 2^31
*
**************************************************/
static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x)
{
/*
* PORTABILITY: This relies on uint32_t -> int32_t
* being implemented as the inverse of int32_t -> uint32_t,
* which is implementation-defined (C99 6.3.1.3 (3))
* CBMC (correctly) fails to prove this conversion is OK,
* so we have to suppress that check here
*/
return (int32_t)x;
}
#ifdef CBMC
#pragma CPROVER check pop
#endif
/*************************************************
* Name: mld_cast_int64_to_uint32
*
* Description: Cast int64 value to uint32 as per C standard.
*
* Returns: For int64_t x, the unique y in uint32_t
* so that x == y mod 2^32.
**************************************************/
static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x)
{
return (uint32_t)(x & (int64_t)UINT32_MAX);
}
/*************************************************
* Name: mld_cast_int32_to_uint32
*
* Description: Cast int32 value to uint32 as per C standard.
*
* Returns: For int32_t x, the unique y in uint32_t
* so that x == y mod 2^32.
**************************************************/
static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x)
{
return mld_cast_int64_to_uint32((int64_t)x);
}
/*************************************************
* Name: mld_ct_sel_int32
*
* Description: Functionally equivalent to cond ? a : b,
* but implemented with guards against
* compiler-introduced branches.
*
* Arguments: int32_t a: First alternative
* int32_t b: Second alternative
* uint32_t cond: Condition variable.
*
*
**************************************************/
static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond)
__contract__(
requires(cond == 0x0 || cond == 0xFFFFFFFF)
ensures(return_value == (cond ? a : b))
)
{
uint32_t au = mld_cast_int32_to_uint32(a);
uint32_t bu = mld_cast_int32_to_uint32(b);
uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu));
return mld_cast_uint32_to_int32(res);
}
/*************************************************
* Name: mld_ct_cmask_nonzero_u32
*
* Description: Return 0 if input is zero, and -1 otherwise.
*
* Arguments: uint32_t x: Value to be converted into a mask
*
**************************************************/
static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x)
__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF)))
{
int64_t tmp = mld_value_barrier_i64(-((int64_t)x));
tmp >>= 32;
return mld_cast_int64_to_uint32(tmp);
}
/*************************************************
* Name: mld_ct_cmask_nonzero_u8
*
* Description: Return 0 if input is zero, and -1 otherwise.
*
* Arguments: uint8_t x: Value to be converted into a mask
*
**************************************************/
static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x)
__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF)))
{
uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x);
return (uint8_t)(mask & 0xFF);
}
/*************************************************
* Name: mld_ct_cmask_neg_i32
*
* Description: Return 0 if input is non-negative, and -1 otherwise.
*
* Arguments: int32_t x: Value to be converted into a mask
*
**************************************************/
static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x)
__contract__(
ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0))
)
{
int64_t tmp = mld_value_barrier_i64((int64_t)x);
tmp >>= 31;
return mld_cast_int64_to_uint32(tmp);
}
/*************************************************
* Name: mld_ct_abs_i32
*
* Description: Return -x if x<0, x otherwise
*
* Arguments: int32_t x: Input value
*
**************************************************/
static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x)
__contract__(
requires(x >= -INT32_MAX)
ensures(return_value == ((x < 0) ? -x : x))
)
{
return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x));
}
/*************************************************
* Name: mld_ct_memcmp
*
* Description: Compare two arrays for equality in constant time.
*
* Arguments: const uint8_t *a: pointer to first byte array
* const uint8_t *b: pointer to second byte array
* size_t len: length of the byte arrays, upper-bounded
* to UINT16_MAX to control proof complexity
* only.
*
* Returns 0 if the byte arrays are equal, 0xFF otherwise.
**************************************************/
static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b,
const size_t len)
__contract__(
requires(len <= UINT16_MAX)
requires(memory_no_alias(a, len))
requires(memory_no_alias(b, len))
ensures((return_value == 0) || (return_value == 0xFF))
ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i]))))
{
uint8_t r = 0, s = 0;
unsigned i;
for (i = 0; i < len; i++)
__loop__(
invariant(i <= len)
invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k])))))
{
r |= a[i] ^ b[i];
/* s is useless, but prevents the loop from being aborted once r=0xff. */
s ^= a[i] ^ b[i];
}
/*
* - Convert r into a mask; this may not be necessary, but is an additional
* safeguard
* towards leaking information about a and b.
* - XOR twice with s, separated by a value barrier, to prevent the compile
* from dropping the s computation in the loop.
*/
return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s);
}
/*************************************************
* Name: mld_zeroize
*
* Description: Force-zeroize a buffer.
* @[FIPS204, Section 3.6.3] Destruction of intermediate
* values.
*
* Arguments: void *ptr: pointer to buffer to be zeroed
* size_t len: Amount of bytes to be zeroed
**************************************************/
#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE)
#if defined(MLD_SYS_WINDOWS)
#include <windows.h>
static MLD_INLINE void mld_zeroize(void *ptr, size_t len)
__contract__(
requires(memory_no_alias(ptr, len))
assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); }
#elif defined(MLD_HAVE_INLINE_ASM)
#include <string.h>
static MLD_INLINE void mld_zeroize(void *ptr, size_t len)
__contract__(
requires(memory_no_alias(ptr, len))
assigns(memory_slice(ptr, len)))
{
memset(ptr, 0, len);
/* This follows OpenSSL and seems sufficient to prevent the compiler
* from optimizing away the memset.
*
* If there was a reliable way to detect availability of memset_s(),
* that would be preferred. */
__asm__ __volatile__("" : : "r"(ptr) : "memory");
}
#else /* !MLD_SYS_WINDOWS && MLD_HAVE_INLINE_ASM */
#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE.
#endif /* !MLD_SYS_WINDOWS && !MLD_HAVE_INLINE_ASM */
#endif /* !MLD_CONFIG_CUSTOM_ZEROIZE */
#endif /* !MLD_CT_H */

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) The mlkem-native project authors
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* NOTE: You can remove this file unless you compile with MLDSA_DEBUG. */
#include "common.h"
#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)
#if defined(MLDSA_DEBUG)
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
#define MLD_DEBUG_ERROR_HEADER "[ERROR:%s:%04d] "
void mld_debug_check_assert(const char *file, int line, const int val)
{
if (val == 0)
{
fprintf(stderr, MLD_DEBUG_ERROR_HEADER "Assertion failed (value %d)\n",
file, line, val);
exit(1);
}
}
void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr,
unsigned len, int64_t lower_bound_exclusive,
int64_t upper_bound_exclusive)
{
int err = 0;
unsigned i;
for (i = 0; i < len; i++)
{
int32_t val = ptr[i];
if (!(val > lower_bound_exclusive && val < upper_bound_exclusive))
{
fprintf(stderr,
MLD_DEBUG_ERROR_HEADER
"Bounds assertion failed: Index %u, value %d out of bounds "
"(%" PRId64 ",%" PRId64 ")\n",
file, line, i, (int)val, lower_bound_exclusive,
upper_bound_exclusive);
err = 1;
}
}
if (err == 1)
{
exit(1);
}
}
#else /* MLDSA_DEBUG */
MLD_EMPTY_CU(debug)
#endif /* !MLDSA_DEBUG */
#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */
MLD_EMPTY_CU(debug)
#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */
/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.
* Don't modify by hand -- this is auto-generated by scripts/autogen. */
#undef MLD_DEBUG_ERROR_HEADER

View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) The mlkem-native project authors
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_DEBUG_H
#define MLD_DEBUG_H
#include "common.h"
#if defined(MLDSA_DEBUG)
#include <stdint.h>
/*************************************************
* Name: mld_assert
*
* Description: Check debug assertion
*
* Prints an error message to stderr and calls
* exit(1) if not.
*
* Arguments: - file: filename
* - line: line number
* - val: Value asserted to be non-zero
**************************************************/
#define mld_debug_check_assert MLD_NAMESPACE(mldsa_debug_assert)
void mld_debug_check_assert(const char *file, int line, const int val);
/*************************************************
* Name: mld_debug_check_bounds
*
* Description: Check whether values in an array of int32_t
* are within specified bounds.
*
* Prints an error message to stderr and calls
* exit(1) if not.
*
* Arguments: - file: filename
* - line: line number
* - ptr: Base of array to be checked
* - len: Number of int32_t in ptr
* - lower_bound_exclusive: Exclusive lower bound
* - upper_bound_exclusive: Exclusive upper bound
**************************************************/
#define mld_debug_check_bounds MLD_NAMESPACE(mldsa_debug_check_bounds)
void mld_debug_check_bounds(const char *file, int line, const int32_t *ptr,
unsigned len, int64_t lower_bound_exclusive,
int64_t upper_bound_exclusive);
/* Check assertion, calling exit() upon failure
*
* val: Value that's asserted to be non-zero
*/
#define mld_assert(val) mld_debug_check_assert(__FILE__, __LINE__, (val))
/* Check bounds in array of int32_t's
* ptr: Base of int32_t array; will be explicitly cast to int32_t*,
* so you may pass a byte-compatible type such as mld_poly or mld_polyvec.
* len: Number of int32_t in array
* value_lb: Inclusive lower value bound
* value_ub: Exclusive upper value bound */
#define mld_assert_bound(ptr, len, value_lb, value_ub) \
mld_debug_check_bounds(__FILE__, __LINE__, (const int32_t *)(ptr), (len), \
((int64_t)(value_lb)) - 1, (value_ub))
/* Check absolute bounds in array of int32_t's
* ptr: Base of array, expression of type int32_t*
* len: Number of int32_t in array
* value_abs_bd: Exclusive absolute upper bound */
#define mld_assert_abs_bound(ptr, len, value_abs_bd) \
mld_assert_bound((ptr), (len), (-((int64_t)(value_abs_bd)) + 1), \
(value_abs_bd))
/* Version of bounds assertions for 2-dimensional arrays */
#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \
mld_assert_bound((ptr), ((len0) * (len1)), (value_lb), (value_ub))
#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \
mld_assert_abs_bound((ptr), ((len0) * (len1)), (value_abs_bd))
/* When running CBMC, convert debug assertions into proof obligations */
#elif defined(CBMC)
#include "cbmc.h"
#define mld_assert(val) cassert(val)
#define mld_assert_bound(ptr, len, value_lb, value_ub) \
cassert(array_bound(((int32_t *)(ptr)), 0, (len), (value_lb), (value_ub)))
#define mld_assert_abs_bound(ptr, len, value_abs_bd) \
cassert(array_abs_bound(((int32_t *)(ptr)), 0, (len), (value_abs_bd)))
/* Because of https://github.com/diffblue/cbmc/issues/8570, we can't
* just use a single flattened array_bound(...) here. */
#define mld_assert_bound_2d(ptr, M, N, value_lb, value_ub) \
cassert(forall(kN, 0, (M), \
array_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \
(value_lb), (value_ub))))
#define mld_assert_abs_bound_2d(ptr, M, N, value_abs_bd) \
cassert(forall(kN, 0, (M), \
array_abs_bound(&((int32_t(*)[(N)])(ptr))[kN][0], 0, (N), \
(value_abs_bd))))
#else /* !MLDSA_DEBUG && CBMC */
#define mld_assert(val) \
do \
{ \
} while (0)
#define mld_assert_bound(ptr, len, value_lb, value_ub) \
do \
{ \
} while (0)
#define mld_assert_abs_bound(ptr, len, value_abs_bd) \
do \
{ \
} while (0)
#define mld_assert_bound_2d(ptr, len0, len1, value_lb, value_ub) \
do \
{ \
} while (0)
#define mld_assert_abs_bound_2d(ptr, len0, len1, value_abs_bd) \
do \
{ \
} while (0)
#endif /* !MLDSA_DEBUG && !CBMC */
#endif /* !MLD_DEBUG_H */

View File

@@ -0,0 +1,975 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* References
* ==========
*
* - [FIPS204]
* FIPS 204 Module-Lattice-Based Digital Signature Standard
* National Institute of Standards and Technology
* https://csrc.nist.gov/pubs/fips/204/final
*/
#ifndef MLD_H
#define MLD_H
/*
* Public API for mldsa-native
*
* This header defines the public API of a single build of mldsa-native.
*
* Make sure the configuration file is in the include path
* (this is "mldsa_native_config.h" by default, or MLD_CONFIG_FILE if defined).
*
* # Multi-level builds
*
* This header specifies a build of mldsa-native for a fixed security level.
* If you need multiple security levels, leave the security level unspecified
* in the configuration file and include this header multiple times, setting
* MLD_CONFIG_PARAMETER_SET accordingly for each, and #undef'ing the MLD_H
* guard to allow multiple inclusions.
*
* # Legacy configuration (deprecated)
*
* Instead of providing the config file used for the build, you can
* alternatively set the following configuration options prior to
* including this header.
*
* This method of configuration is deprecated.
* It will be removed in mldsa-native-v2.
*
* - MLD_CONFIG_API_PARAMETER_SET [required]
*
* The parameter set used for the build; 44, 65, or 87.
*
* - MLD_CONFIG_API_NAMESPACE_PREFIX [required]
*
* The namespace prefix used for the build.
*
* NOTE:
* For a multi-level build, you must include the 44/65/87 suffixes
* in MLD_CONFIG_API_NAMESPACE_PREFIX.
*
* - MLD_CONFIG_API_NO_SUPERCOP [optional]
*
* By default, this header will also expose the mldsa-native API in the
* SUPERCOP naming convention crypto_sign_xxx. If you don't want/need this,
* set MLD_CONFIG_API_NO_SUPERCOP. You must set this for a multi-level build.
*
* - MLD_CONFIG_API_CONSTANTS_ONLY [optional]
*
* If you don't want this header to expose any function declarations,
* but only constants for the sizes of key material, set
* MLD_CONFIG_API_CONSTANTS_ONLY. In this case, you don't need to set
* MLD_CONFIG_API_PARAMETER_SET or MLD_CONFIG_API_NAMESPACE_PREFIX,
* nor include a configuration.
*
* - MLD_CONFIG_API_QUALIFIER [optional]
*
* Qualifier to apply to external API.
*
******************************************************************************/
/******************************* Key sizes ************************************/
/* Sizes of cryptographic material, per parameter set */
/* See mldsa/src/params.h for the arithmetic expressions giving rise to these */
/* check-magic: off */
#define MLDSA44_SECRETKEYBYTES 2560
#define MLDSA44_PUBLICKEYBYTES 1312
#define MLDSA44_BYTES 2420
#define MLDSA65_SECRETKEYBYTES 4032
#define MLDSA65_PUBLICKEYBYTES 1952
#define MLDSA65_BYTES 3309
#define MLDSA87_SECRETKEYBYTES 4896
#define MLDSA87_PUBLICKEYBYTES 2592
#define MLDSA87_BYTES 4627
/* check-magic: on */
/* Size of seed and randomness in bytes (level-independent) */
#define MLDSA_SEEDBYTES 32
#define MLDSA44_SEEDBYTES MLDSA_SEEDBYTES
#define MLDSA65_SEEDBYTES MLDSA_SEEDBYTES
#define MLDSA87_SEEDBYTES MLDSA_SEEDBYTES
/* Size of CRH output in bytes (level-independent) */
#define MLDSA_CRHBYTES 64
#define MLDSA44_CRHBYTES MLDSA_CRHBYTES
#define MLDSA65_CRHBYTES MLDSA_CRHBYTES
#define MLDSA87_CRHBYTES MLDSA_CRHBYTES
/* Size of TR output in bytes (level-independent) */
#define MLDSA_TRBYTES 64
#define MLDSA44_TRBYTES MLDSA_TRBYTES
#define MLDSA65_TRBYTES MLDSA_TRBYTES
#define MLDSA87_TRBYTES MLDSA_TRBYTES
/* Size of randomness for signing in bytes (level-independent) */
#define MLDSA_RNDBYTES 32
#define MLDSA44_RNDBYTES MLDSA_RNDBYTES
#define MLDSA65_RNDBYTES MLDSA_RNDBYTES
#define MLDSA87_RNDBYTES MLDSA_RNDBYTES
/* Sizes of cryptographic material, as a function of LVL=44,65,87 */
#define MLDSA_SECRETKEYBYTES_(LVL) MLDSA##LVL##_SECRETKEYBYTES
#define MLDSA_PUBLICKEYBYTES_(LVL) MLDSA##LVL##_PUBLICKEYBYTES
#define MLDSA_BYTES_(LVL) MLDSA##LVL##_BYTES
#define MLDSA_SECRETKEYBYTES(LVL) MLDSA_SECRETKEYBYTES_(LVL)
#define MLDSA_PUBLICKEYBYTES(LVL) MLDSA_PUBLICKEYBYTES_(LVL)
#define MLDSA_BYTES(LVL) MLDSA_BYTES_(LVL)
/****************************** Error codes ***********************************/
/* Generic failure condition */
#define MLD_ERR_FAIL -1
/* An allocation failed. This can only happen if MLD_CONFIG_CUSTOM_ALLOC_FREE
* is defined and the provided MLD_CUSTOM_ALLOC can fail. */
#define MLD_ERR_OUT_OF_MEMORY -2
/* An rng failure occured. Might be due to insufficient entropy or
* system misconfiguration. */
#define MLD_ERR_RNG_FAIL -3
/****************************** Function API **********************************/
#define MLD_API_CONCAT_(x, y) x##y
#define MLD_API_CONCAT(x, y) MLD_API_CONCAT_(x, y)
#define MLD_API_CONCAT_UNDERSCORE(x, y) MLD_API_CONCAT(MLD_API_CONCAT(x, _), y)
#if !defined(MLD_CONFIG_API_PARAMETER_SET)
/* Recommended configuration via same config file as used for the build. */
/* For now, we derive the legacy API configuration MLD_CONFIG_API_XXX from
* the config file. In mldsa-native-v2, this will be removed and we will
* exclusively work with MLD_CONFIG_XXX. */
/* You need to make sure the config file is in the include path. */
#if defined(MLD_CONFIG_FILE)
#include MLD_CONFIG_FILE
#else
#include "mldsa_native_config.h"
#endif
#define MLD_CONFIG_API_PARAMETER_SET MLD_CONFIG_PARAMETER_SET
#if defined(MLD_CONFIG_MULTILEVEL_BUILD)
#define MLD_CONFIG_API_NAMESPACE_PREFIX \
MLD_API_CONCAT(MLD_CONFIG_NAMESPACE_PREFIX, MLD_CONFIG_PARAMETER_SET)
#else
#define MLD_CONFIG_API_NAMESPACE_PREFIX MLD_CONFIG_NAMESPACE_PREFIX
#endif
#if defined(MLD_CONFIG_NO_SUPERCOP)
#define MLD_CONFIG_API_NO_SUPERCOP
#endif
#if defined(MLD_CONFIG_CONSTANTS_ONLY)
#define MLD_CONFIG_API_CONSTANTS_ONLY
#endif
#if defined(MLD_CONFIG_EXTERNAL_API_QUALIFIER)
#define MLD_CONFIG_API_QUALIFIER MLD_CONFIG_EXTERNAL_API_QUALIFIER
#endif
#else /* !MLD_CONFIG_API_PARAMETER_SET */
#define MLD_API_LEGACY_CONFIG
#endif /* MLD_CONFIG_API_PARAMETER_SET */
#define MLD_API_NAMESPACE(sym) \
MLD_API_CONCAT_UNDERSCORE(MLD_CONFIG_API_NAMESPACE_PREFIX, sym)
#if defined(__GNUC__) || defined(clang)
#define MLD_API_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result))
#else
#define MLD_API_MUST_CHECK_RETURN_VALUE
#endif
#if defined(MLD_CONFIG_API_QUALIFIER)
#define MLD_API_QUALIFIER MLD_CONFIG_API_QUALIFIER
#else
#define MLD_API_QUALIFIER
#endif
#if !defined(MLD_CONFIG_API_CONSTANTS_ONLY)
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*************************************************
* Name: crypto_sign_keypair_internal
*
* Description: Generates public and private key. Internal API.
* When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise
* Consistency Test (PCT) as required by FIPS 140-3 IG.
*
* Arguments:
* - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output public key
* - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output private key
* - const uint8_t seed[MLDSA_SEEDBYTES]:
* input random seed
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_RNG_FAIL: Random number generation failed.
* - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure
* if MLD_CONFIG_KEYGEN_PCT is enabled.
*
* Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)]
*
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(keypair_internal)(
uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)],
uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)],
const uint8_t seed[MLDSA_SEEDBYTES]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_keypair
*
* Description: Generates public and private key.
* When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise
* Consistency Test (PCT) as required by FIPS 140-3 IG.
*
* Arguments:
* - uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output public key
* - uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output private key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_RNG_FAIL: Random number generation failed.
* - MLD_ERR_FAIL: If MLD_CONFIG_KEYGEN_PCT is enabled and the
* PCT check failed.
*
* Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)]
*
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(keypair)(
uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)],
uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_signature_internal
*
* Description: Computes signature. Internal API.
*
* Arguments:
* - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output signature
* - size_t *siglen: pointer to output length of signature
* - const uint8_t *m: pointer to message to be signed
* - size_t mlen: length of message
* - const uint8_t *pre: pointer to prefix string
* - size_t prelen: length of prefix string
* - const uint8_t rnd[MLDSA_RNDBYTES]:
* random seed
* - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed secret key
* - int externalmu: indicates input message m is processed as mu
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Other kinds of failure
*
* If the returned value is non-zero, then the values of *sig and
* *siglen should not be referenced.
*
* Reference: This code differs from the reference implementation
* in that it adds an explicit check for nonce exhaustion
* and can return -1 in that case.
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(signature_internal)(
uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *pre, size_t prelen,
const uint8_t rnd[MLDSA_RNDBYTES],
const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)],
int externalmu
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_signature
*
* Description: Computes signature. This function implements the randomized
* variant of ML-DSA. If you require the deterministic variant,
* use crypto_sign_signature_internal directly.
*
* Arguments:
* - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output signature
* - size_t *siglen: pointer to output length of signature
* - const uint8_t *m: pointer to message to be signed
* - size_t mlen: length of message
* - const uint8_t *ctx: pointer to context string.
* May be NULL if ctxlen == 0.
* - size_t ctxlen: length of context string.
* Should be <= 255.
* - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed secret key
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_RNG_FAIL: Random number generation failed.
* - MLD_ERR_FAIL: Other kinds of failure.
*
* Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]
*
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(signature)(
uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen,
const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_signature_extmu
*
* Description: Computes signature.
*
* Arguments:
* - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output signature
* - size_t *siglen: pointer to output length of signature
* - const uint8_t mu[MLDSA_CRHBYTES]:
* input mu to be signed
* - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed secret key
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_RNG_FAIL: Random number generation failed.
* - MLD_ERR_FAIL: Other kinds of failure.
*
* Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu
* variant)]
*
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(signature_extmu)(
uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen,
const uint8_t mu[MLDSA_CRHBYTES],
const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign
*
* Description: Computes signature. This function implements the randomized
* variant of ML-DSA. If you require the deterministic variant,
* use crypto_sign_signature_internal directly.
*
* Arguments:
* - uint8_t *sm: pointer to output signed message (allocated array
* with MLDSA{44,65,87}_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[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed secret key
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Other kinds of failure
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(sign)(
uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen,
const uint8_t *ctx, size_t ctxlen,
const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_verify_internal
*
* Description: Verifies signature. Internal API.
*
* Arguments:
* - const uint8_t *sig: 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[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed public key
* - int externalmu: indicates input message m is processed as mu
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
* Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)]
*
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(verify_internal)(
const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen,
const uint8_t *pre, size_t prelen,
const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)],
int externalmu
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_verify
*
* Description: Verifies signature.
*
* Arguments:
* - const uint8_t *sig: 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.
* May be NULL if ctxlen == 0.
* - size_t ctxlen: length of context string
* - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed public key
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
* Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)]
*
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(verify)(
const uint8_t *sig, size_t siglen, const uint8_t *m, size_t mlen,
const uint8_t *ctx, size_t ctxlen,
const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_verify_extmu
*
* Description: Verifies signature.
*
* Arguments:
* - const uint8_t *sig: pointer to input signature
* - size_t siglen: length of signature
* - const uint8_t mu[MLDSA_CRHBYTES]:
* input mu
* - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed public key
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
* Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu
* variant)]
*
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(verify_extmu)(
const uint8_t *sig, size_t siglen, const uint8_t mu[MLDSA_CRHBYTES],
const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_open
*
* Description: Verify signed message.
*
* Arguments:
* - uint8_t *m: pointer to output message (allocated array with
* smlen bytes), can be equal to sm
* - size_t *mlen: pointer to output length of message
* - const uint8_t *sm: pointer to signed message
* - size_t smlen: length of signed message
* - const uint8_t *ctx: pointer to context string
* - size_t ctxlen: length of context string
* - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed public key
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(open)(
uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen,
const uint8_t *ctx, size_t ctxlen,
const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Hash algorithm constants for domain separation
**************************************************/
#define MLD_PREHASH_NONE 0
#define MLD_PREHASH_SHA2_224 1
#define MLD_PREHASH_SHA2_256 2
#define MLD_PREHASH_SHA2_384 3
#define MLD_PREHASH_SHA2_512 4
#define MLD_PREHASH_SHA2_512_224 5
#define MLD_PREHASH_SHA2_512_256 6
#define MLD_PREHASH_SHA3_224 7
#define MLD_PREHASH_SHA3_256 8
#define MLD_PREHASH_SHA3_384 9
#define MLD_PREHASH_SHA3_512 10
#define MLD_PREHASH_SHAKE_128 11
#define MLD_PREHASH_SHAKE_256 12
/*************************************************
* Name: crypto_sign_signature_pre_hash_internal
*
* Description: FIPS 204: Algorithm 4 HashML-DSA.Sign.
* Computes signature with pre-hashed message.
*
* Arguments:
* - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output signature
* - size_t *siglen: pointer to output length of signature
* - const uint8_t *ph: pointer to pre-hashed message
* - size_t phlen: length of pre-hashed message
* - const uint8_t *ctx: pointer to context string
* - size_t ctxlen: length of context string
* - const uint8_t rnd[MLDSA_RNDBYTES]:
* random seed
* - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed secret key
* - int hashalg: hash algorithm constant (one of MLD_PREHASH_*)
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Other kinds of failure
*
* Supported hash algorithm constants:
* MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384,
* MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256,
* MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384,
* MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256
*
* Warning: This is an unstable API that may change in the future. If you need
* a stable API use crypto_sign_signature_pre_hash_shake256.
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(signature_pre_hash_internal)(
uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen,
const uint8_t *ph, size_t phlen, const uint8_t *ctx, size_t ctxlen,
const uint8_t rnd[MLDSA_RNDBYTES],
const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)],
int hashalg
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_verify_pre_hash_internal
*
* Description: FIPS 204: Algorithm 5 HashML-DSA.Verify.
* Verifies signature with pre-hashed message.
*
* Arguments:
* - const uint8_t *sig: pointer to input signature
* - size_t siglen: length of signature
* - const uint8_t *ph: pointer to pre-hashed message
* - size_t phlen: length of pre-hashed message
* - const uint8_t *ctx: pointer to context string
* - size_t ctxlen: length of context string
* - const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed public key
* - int hashalg: hash algorithm constant (one of MLD_PREHASH_*)
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
* Supported hash algorithm constants:
* MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384,
* MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256,
* MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384,
* MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256
*
* Warning: This is an unstable API that may change in the future. If you need
* a stable API use crypto_sign_verify_pre_hash_shake256.
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(verify_pre_hash_internal)(
const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen,
const uint8_t *ctx, size_t ctxlen,
const uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)],
int hashalg
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_signature_pre_hash_shake256
*
* Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256.
* Computes signature with pre-hashed message using SHAKE256.
* This function computes the SHAKE256 hash of the message
* internally.
*
* Arguments:
* - uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* output signature
* - size_t *siglen: pointer to output length of signature
* - const uint8_t *m: pointer to message to be hashed and 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 rnd[MLDSA_RNDBYTES]:
* random seed
* - const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed secret key
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Other kinds of failure
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(signature_pre_hash_shake256)(
uint8_t sig[MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)], size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *ctx, size_t ctxlen,
const uint8_t rnd[MLDSA_RNDBYTES],
const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/*************************************************
* Name: crypto_sign_verify_pre_hash_shake256
*
* Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256.
* Verifies signature with pre-hashed message using SHAKE256.
* This function computes the SHAKE256 hash of the message
*internally.
*
* Arguments:
* - const uint8_t *sig: pointer to input signature
* - size_t siglen: length of signature
* - const uint8_t *m: pointer to message to be hashed and verified
* - 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[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]:
* bit-packed public key
*
* Returns:
* - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(verify_pre_hash_shake256)(
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[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
/* Maximum formatted domain separation message length */
#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64)
/*************************************************
* Name: mld_prepare_domain_separation_prefix
*
* Description: Prepares domain separation prefix for ML-DSA signing.
* For pure ML-DSA (hashalg == MLD_PREHASH_NONE):
* Format: 0x00 || ctxlen (1 byte) || ctx
* For HashML-DSA (hashalg != MLD_PREHASH_NONE):
* Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph
*
* Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]:
* output domain separation prefix buffer
* - const uint8_t *ph: pointer to pre-hashed message
* (ignored for pure ML-DSA)
* - size_t phlen: length of pre-hashed message
* (ignored for pure ML-DSA)
* - const uint8_t *ctx: pointer to context string (may be NULL)
* - size_t ctxlen: length of context string
* - int hashalg: hash algorithm constant
* (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for
* HashML-DSA)
*
* Returns the total length of the formatted prefix, or 0 on error.
*
* This function is useful for building incremental signing APIs.
*
* Specification:
* - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements
* @[FIPS204, Algorithm 4, L23]
* - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements
* ```
* M' <- BytesToBits(IntegerToBytes(0, 1)
* || IntegerToBytes(|ctx|, 1)
* || ctx
* ```
* which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and
* @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5].
*
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
size_t MLD_API_NAMESPACE(prepare_domain_separation_prefix)(
uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph,
size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg);
/*************************************************
* Name: crypto_sign_pk_from_sk
*
* Description: Performs basic validity checks on secret key, and derives
* public key.
*
* Referring to the decoding of the secret key
* `sk=(rho, K, tr, s1, s2, t0)`
* (cf. [@FIPS204, Algorithm 25 skDecode]),
* the following checks are performed:
* - Check that s1 and s2 have coefficients in
* [-MLDSA_ETA, MLDSA_ETA]
* - Check that t0 and tr stored in sk match recomputed values.
*
* Arguments: - uint8_t pk[CRYPTO_PUBLICKEYBYTES]: output public key
* - const uint8_t sk[CRYPTO_SECRETKEYBYTES]: input secret key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Secret key validation failed
*
* Note: This function leaks whether the secret key is valid or invalid
* through its return value and timing.
**************************************************/
MLD_API_QUALIFIER
MLD_API_MUST_CHECK_RETURN_VALUE
int MLD_API_NAMESPACE(pk_from_sk)(
uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)],
const uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)]
#ifdef MLD_CONFIG_CONTEXT_PARAMETER
,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context
#endif
);
#ifdef __cplusplus
}
#endif
/****************************** SUPERCOP API *********************************/
#if !defined(MLD_CONFIG_API_NO_SUPERCOP)
/* Export API in SUPERCOP naming scheme CRYPTO_xxx / crypto_sign_xxx */
#define CRYPTO_SECRETKEYBYTES MLDSA_SECRETKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)
#define CRYPTO_PUBLICKEYBYTES MLDSA_PUBLICKEYBYTES(MLD_CONFIG_API_PARAMETER_SET)
#define CRYPTO_BYTES MLDSA_BYTES(MLD_CONFIG_API_PARAMETER_SET)
#define crypto_sign_keypair MLD_API_NAMESPACE(keypair)
#define crypto_sign_signature MLD_API_NAMESPACE(signature)
#define crypto_sign MLD_API_NAMESPACE(sign)
#define crypto_sign_verify MLD_API_NAMESPACE(verify)
#define crypto_sign_open MLD_API_NAMESPACE(open)
#else /* !MLD_CONFIG_API_NO_SUPERCOP */
/* If the SUPERCOP API is not needed, we can undefine the various helper macros
* above. Otherwise, they are needed for lazy evaluation of crypto_sign_xxx. */
#if !defined(MLD_API_LEGACY_CONFIG)
#undef MLD_CONFIG_API_PARAMETER_SET
#undef MLD_CONFIG_API_NAMESPACE_PREFIX
#undef MLD_CONFIG_API_NO_SUPERCOP
#undef MLD_CONFIG_API_CONSTANTS_ONLY
#undef MLD_CONFIG_API_QUALIFIER
#endif /* !MLD_API_LEGACY_CONFIG */
#undef MLD_API_CONCAT
#undef MLD_API_CONCAT_
#undef MLD_API_CONCAT_UNDERSCORE
#undef MLD_API_NAMESPACE
#undef MLD_API_MUST_CHECK_RETURN_VALUE
#undef MLD_API_QUALIFIER
#undef MLD_API_LEGACY_CONFIG
#endif /* MLD_CONFIG_API_NO_SUPERCOP */
#endif /* !MLD_CONFIG_API_CONSTANTS_ONLY */
/***************************** Memory Usage **********************************/
/*
* By default mldsa-native performs all memory allocations on the stack.
* Alternatively, mldsa-native supports custom allocation of large structures
* through the `MLD_CONFIG_CUSTOM_ALLOC_FREE` configuration option.
* See mldsa_native_config.h for details.
*
* `MLD_TOTAL_ALLOC_{44,65,87}_{KEYPAIR,SIGN,VERIFY}` indicates the maximum
* (accumulative) allocation via MLD_ALLOC for each parameter set and operation.
* Note that some stack allocation remains even
* when using custom allocators, so these values are lower than total stack
* usage with the default stack-only allocation.
*
* These constants may be used to implement custom allocations using a
* fixed-sized buffer and a simple allocator (e.g., bump allocator).
*/
/* check-magic: off */
#if defined(MLD_API_LEGACY_CONFIG) || !defined(MLD_CONFIG_REDUCE_RAM)
#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 45248
#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 56640
#define MLD_TOTAL_ALLOC_44_SIGN 52896
#define MLD_TOTAL_ALLOC_44_VERIFY 38816
#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 71872
#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 85856
#define MLD_TOTAL_ALLOC_65_SIGN 80576
#define MLD_TOTAL_ALLOC_65_VERIFY 62432
#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 112832
#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 130816
#define MLD_TOTAL_ALLOC_87_SIGN 123584
#define MLD_TOTAL_ALLOC_87_VERIFY 99552
#else /* MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM */
#define MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT 32992
#define MLD_TOTAL_ALLOC_44_KEYPAIR_PCT 36192
#define MLD_TOTAL_ALLOC_44_SIGN 32448
#define MLD_TOTAL_ALLOC_44_VERIFY 22464
#define MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT 46304
#define MLD_TOTAL_ALLOC_65_KEYPAIR_PCT 50048
#define MLD_TOTAL_ALLOC_65_SIGN 44768
#define MLD_TOTAL_ALLOC_65_VERIFY 30720
#define MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT 62688
#define MLD_TOTAL_ALLOC_87_KEYPAIR_PCT 66336
#define MLD_TOTAL_ALLOC_87_SIGN 59104
#define MLD_TOTAL_ALLOC_87_VERIFY 41216
#endif /* !(MLD_API_LEGACY_CONFIG || !MLD_CONFIG_REDUCE_RAM) */
/* check-magic: on */
/*
* MLD_TOTAL_ALLOC_*_KEYPAIR adapts based on MLD_CONFIG_KEYGEN_PCT.
* For legacy config, we don't know which options are used, so assume
* the worst case (PCT enabled).
*/
#if defined(MLD_API_LEGACY_CONFIG) || defined(MLD_CONFIG_KEYGEN_PCT)
#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_PCT
#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_PCT
#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_PCT
#else
#define MLD_TOTAL_ALLOC_44_KEYPAIR MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT
#define MLD_TOTAL_ALLOC_65_KEYPAIR MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT
#define MLD_TOTAL_ALLOC_87_KEYPAIR MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT
#endif
#define MLD_MAX3_(a, b, c) \
((a) > (b) ? ((a) > (c) ? (a) : (c)) : ((b) > (c) ? (b) : (c)))
/*
* `MLD_TOTAL_ALLOC_{44,65,87}` is the maximum across all operations for each
* parameter set.
*/
#define MLD_TOTAL_ALLOC_44 \
MLD_MAX3_(MLD_TOTAL_ALLOC_44_KEYPAIR, MLD_TOTAL_ALLOC_44_SIGN, \
MLD_TOTAL_ALLOC_44_VERIFY)
#define MLD_TOTAL_ALLOC_65 \
MLD_MAX3_(MLD_TOTAL_ALLOC_65_KEYPAIR, MLD_TOTAL_ALLOC_65_SIGN, \
MLD_TOTAL_ALLOC_65_VERIFY)
#define MLD_TOTAL_ALLOC_87 \
MLD_MAX3_(MLD_TOTAL_ALLOC_87_KEYPAIR, MLD_TOTAL_ALLOC_87_SIGN, \
MLD_TOTAL_ALLOC_87_VERIFY)
#endif /* !MLD_H */

View File

@@ -0,0 +1,586 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/*
* WARNING: This file is auto-generated from scripts/autogen
* in the mldsa-native repository.
* Do not modify it directly.
*/
/******************************************************************************
*
* Single compilation unit (SCU) for fixed-level build of mldsa-native
*
* This compilation unit bundles together all source files for a build
* of mldsa-native for a fixed security level (MLDSA-44/65/87).
*
* # API
*
* The API exposed by this file is described in mldsa_native.h.
*
* # Multi-level build
*
* If you want an SCU build of mldsa-native with support for multiple security
* levels, you need to include this file multiple times, and set
* MLD_CONFIG_MULTILEVEL_WITH_SHARED and MLD_CONFIG_MULTILEVEL_NO_SHARED
* appropriately. This is exemplified in examples/monolithic_build_multilevel
* and examples/monolithic_build_multilevel_native.
*
* # Configuration
*
* The following options from the mldsa-native configuration are relevant:
*
* - MLD_CONFIG_FIPS202_CUSTOM_HEADER
* Set this option if you use a custom FIPS202 implementation.
*
* - MLD_CONFIG_USE_NATIVE_BACKEND_ARITH
* Set this option if you want to include the native arithmetic backends
* in your build.
*
* - MLD_CONFIG_USE_NATIVE_BACKEND_FIPS202
* Set this option if you want to include the native FIPS202 backends
* in your build.
*
* - MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS
* Set this option if you want to keep the directives defined in
* level-independent headers. This is needed for a multi-level build.
*/
/* If parts of the mldsa-native source tree are not used,
* consider reducing this header via `unifdef`.
*
* Example:
* ```bash
* unifdef -UMLD_CONFIG_USE_NATIVE_BACKEND_ARITH mldsa_native.c
* ```
*/
#include "common.h"
#include "ct.c"
#include "debug.c"
#include "packing.c"
#include "poly.c"
#include "poly_kl.c"
#include "polyvec.c"
#include "sign.c"
#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)
#if defined(MLD_SYS_AARCH64)
#include "native/aarch64/src/aarch64_zetas.c"
#include "native/aarch64/src/polyz_unpack_table.c"
#include "native/aarch64/src/rej_uniform_eta_table.c"
#include "native/aarch64/src/rej_uniform_table.c"
#endif /* MLD_SYS_AARCH64 */
#if defined(MLD_SYS_X86_64)
#include "native/x86_64/src/consts.c"
#include "native/x86_64/src/poly_caddq_avx2.c"
#include "native/x86_64/src/poly_chknorm_avx2.c"
#include "native/x86_64/src/poly_decompose_32_avx2.c"
#include "native/x86_64/src/poly_decompose_88_avx2.c"
#include "native/x86_64/src/poly_use_hint_32_avx2.c"
#include "native/x86_64/src/poly_use_hint_88_avx2.c"
#include "native/x86_64/src/polyz_unpack_17_avx2.c"
#include "native/x86_64/src/polyz_unpack_19_avx2.c"
#include "native/x86_64/src/rej_uniform_avx2.c"
#include "native/x86_64/src/rej_uniform_eta2_avx2.c"
#include "native/x86_64/src/rej_uniform_eta4_avx2.c"
#include "native/x86_64/src/rej_uniform_table.c"
#endif /* MLD_SYS_X86_64 */
#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */
/* Macro #undef's
*
* The following undefines macros from headers
* included by the source files imported above.
*
* This is to allow building and linking multiple builds
* of mldsa-native for varying parameter sets through concatenation
* of this file, as if the files had been compiled separately.
* If this is not relevant to you, you may remove the following.
*/
/*
* Undefine macros from MLD_CONFIG_PARAMETER_SET-specific files
*/
/* mldsa/mldsa_native.h */
#undef CRYPTO_BYTES
#undef CRYPTO_PUBLICKEYBYTES
#undef CRYPTO_SECRETKEYBYTES
#undef MLDSA44_BYTES
#undef MLDSA44_CRHBYTES
#undef MLDSA44_PUBLICKEYBYTES
#undef MLDSA44_RNDBYTES
#undef MLDSA44_SECRETKEYBYTES
#undef MLDSA44_SEEDBYTES
#undef MLDSA44_TRBYTES
#undef MLDSA65_BYTES
#undef MLDSA65_CRHBYTES
#undef MLDSA65_PUBLICKEYBYTES
#undef MLDSA65_RNDBYTES
#undef MLDSA65_SECRETKEYBYTES
#undef MLDSA65_SEEDBYTES
#undef MLDSA65_TRBYTES
#undef MLDSA87_BYTES
#undef MLDSA87_CRHBYTES
#undef MLDSA87_PUBLICKEYBYTES
#undef MLDSA87_RNDBYTES
#undef MLDSA87_SECRETKEYBYTES
#undef MLDSA87_SEEDBYTES
#undef MLDSA87_TRBYTES
#undef MLDSA_BYTES
#undef MLDSA_BYTES_
#undef MLDSA_CRHBYTES
#undef MLDSA_PUBLICKEYBYTES
#undef MLDSA_PUBLICKEYBYTES_
#undef MLDSA_RNDBYTES
#undef MLDSA_SECRETKEYBYTES
#undef MLDSA_SECRETKEYBYTES_
#undef MLDSA_SEEDBYTES
#undef MLDSA_TRBYTES
#undef MLD_API_CONCAT
#undef MLD_API_CONCAT_
#undef MLD_API_CONCAT_UNDERSCORE
#undef MLD_API_LEGACY_CONFIG
#undef MLD_API_MUST_CHECK_RETURN_VALUE
#undef MLD_API_NAMESPACE
#undef MLD_API_QUALIFIER
#undef MLD_CONFIG_API_CONSTANTS_ONLY
#undef MLD_CONFIG_API_NAMESPACE_PREFIX
#undef MLD_CONFIG_API_NO_SUPERCOP
#undef MLD_CONFIG_API_PARAMETER_SET
#undef MLD_CONFIG_API_QUALIFIER
#undef MLD_DOMAIN_SEPARATION_MAX_BYTES
#undef MLD_ERR_FAIL
#undef MLD_ERR_OUT_OF_MEMORY
#undef MLD_ERR_RNG_FAIL
#undef MLD_H
#undef MLD_MAX3_
#undef MLD_PREHASH_NONE
#undef MLD_PREHASH_SHA2_224
#undef MLD_PREHASH_SHA2_256
#undef MLD_PREHASH_SHA2_384
#undef MLD_PREHASH_SHA2_512
#undef MLD_PREHASH_SHA2_512_224
#undef MLD_PREHASH_SHA2_512_256
#undef MLD_PREHASH_SHA3_224
#undef MLD_PREHASH_SHA3_256
#undef MLD_PREHASH_SHA3_384
#undef MLD_PREHASH_SHA3_512
#undef MLD_PREHASH_SHAKE_128
#undef MLD_PREHASH_SHAKE_256
#undef MLD_TOTAL_ALLOC_44
#undef MLD_TOTAL_ALLOC_44_KEYPAIR
#undef MLD_TOTAL_ALLOC_44_KEYPAIR_NO_PCT
#undef MLD_TOTAL_ALLOC_44_KEYPAIR_PCT
#undef MLD_TOTAL_ALLOC_44_SIGN
#undef MLD_TOTAL_ALLOC_44_VERIFY
#undef MLD_TOTAL_ALLOC_65
#undef MLD_TOTAL_ALLOC_65_KEYPAIR
#undef MLD_TOTAL_ALLOC_65_KEYPAIR_NO_PCT
#undef MLD_TOTAL_ALLOC_65_KEYPAIR_PCT
#undef MLD_TOTAL_ALLOC_65_SIGN
#undef MLD_TOTAL_ALLOC_65_VERIFY
#undef MLD_TOTAL_ALLOC_87
#undef MLD_TOTAL_ALLOC_87_KEYPAIR
#undef MLD_TOTAL_ALLOC_87_KEYPAIR_NO_PCT
#undef MLD_TOTAL_ALLOC_87_KEYPAIR_PCT
#undef MLD_TOTAL_ALLOC_87_SIGN
#undef MLD_TOTAL_ALLOC_87_VERIFY
#undef crypto_sign
#undef crypto_sign_keypair
#undef crypto_sign_open
#undef crypto_sign_signature
#undef crypto_sign_verify
/* mldsa/src/common.h */
#undef MLD_ADD_PARAM_SET
#undef MLD_ALLOC
#undef MLD_APPLY
#undef MLD_ASM_FN_SYMBOL
#undef MLD_ASM_NAMESPACE
#undef MLD_BUILD_INTERNAL
#undef MLD_COMMON_H
#undef MLD_CONCAT
#undef MLD_CONCAT_
#undef MLD_CONTEXT_PARAMETERS_0
#undef MLD_CONTEXT_PARAMETERS_1
#undef MLD_CONTEXT_PARAMETERS_2
#undef MLD_CONTEXT_PARAMETERS_3
#undef MLD_CONTEXT_PARAMETERS_4
#undef MLD_CONTEXT_PARAMETERS_5
#undef MLD_CONTEXT_PARAMETERS_6
#undef MLD_CONTEXT_PARAMETERS_7
#undef MLD_CONTEXT_PARAMETERS_8
#undef MLD_CONTEXT_PARAMETERS_9
#undef MLD_EMPTY_CU
#undef MLD_ERR_FAIL
#undef MLD_ERR_OUT_OF_MEMORY
#undef MLD_ERR_RNG_FAIL
#undef MLD_EXTERNAL_API
#undef MLD_FIPS202X4_HEADER_FILE
#undef MLD_FIPS202_HEADER_FILE
#undef MLD_FREE
#undef MLD_INTERNAL_API
#undef MLD_MULTILEVEL_BUILD
#undef MLD_NAMESPACE
#undef MLD_NAMESPACE_KL
#undef MLD_NAMESPACE_PREFIX
#undef MLD_NAMESPACE_PREFIX_KL
#undef MLK_UNION_OR_STRUCT
#undef mld_memcpy
#undef mld_memset
/* mldsa/src/packing.h */
#undef MLD_PACKING_H
#undef mld_pack_pk
#undef mld_pack_sig_c_h
#undef mld_pack_sig_z
#undef mld_pack_sk
#undef mld_unpack_pk
#undef mld_unpack_sig
#undef mld_unpack_sk
/* mldsa/src/params.h */
#undef MLDSA_BETA
#undef MLDSA_CRHBYTES
#undef MLDSA_CRYPTO_BYTES
#undef MLDSA_CRYPTO_PUBLICKEYBYTES
#undef MLDSA_CRYPTO_SECRETKEYBYTES
#undef MLDSA_CTILDEBYTES
#undef MLDSA_D
#undef MLDSA_ETA
#undef MLDSA_GAMMA1
#undef MLDSA_GAMMA2
#undef MLDSA_K
#undef MLDSA_L
#undef MLDSA_N
#undef MLDSA_OMEGA
#undef MLDSA_POLYETA_PACKEDBYTES
#undef MLDSA_POLYT0_PACKEDBYTES
#undef MLDSA_POLYT1_PACKEDBYTES
#undef MLDSA_POLYVECH_PACKEDBYTES
#undef MLDSA_POLYW1_PACKEDBYTES
#undef MLDSA_POLYZ_PACKEDBYTES
#undef MLDSA_Q
#undef MLDSA_Q_HALF
#undef MLDSA_RNDBYTES
#undef MLDSA_SEEDBYTES
#undef MLDSA_TAU
#undef MLDSA_TRBYTES
#undef MLD_PARAMS_H
/* mldsa/src/poly_kl.h */
#undef MLD_POLYETA_UNPACK_LOWER_BOUND
#undef MLD_POLY_KL_H
#undef mld_poly_challenge
#undef mld_poly_decompose
#undef mld_poly_make_hint
#undef mld_poly_uniform_eta
#undef mld_poly_uniform_eta_4x
#undef mld_poly_uniform_gamma1
#undef mld_poly_uniform_gamma1_4x
#undef mld_poly_use_hint
#undef mld_polyeta_pack
#undef mld_polyeta_unpack
#undef mld_polyw1_pack
#undef mld_polyz_pack
#undef mld_polyz_unpack
/* mldsa/src/polyvec.h */
#undef MLD_POLYVEC_H
#undef mld_polymat
#undef mld_polymat_get_row
#undef mld_polyvec_matrix_expand
#undef mld_polyvec_matrix_pointwise_montgomery
#undef mld_polyveck
#undef mld_polyveck_add
#undef mld_polyveck_caddq
#undef mld_polyveck_chknorm
#undef mld_polyveck_decompose
#undef mld_polyveck_invntt_tomont
#undef mld_polyveck_make_hint
#undef mld_polyveck_ntt
#undef mld_polyveck_pack_eta
#undef mld_polyveck_pack_t0
#undef mld_polyveck_pack_w1
#undef mld_polyveck_pointwise_poly_montgomery
#undef mld_polyveck_power2round
#undef mld_polyveck_reduce
#undef mld_polyveck_shiftl
#undef mld_polyveck_sub
#undef mld_polyveck_unpack_eta
#undef mld_polyveck_unpack_t0
#undef mld_polyveck_use_hint
#undef mld_polyvecl
#undef mld_polyvecl_chknorm
#undef mld_polyvecl_ntt
#undef mld_polyvecl_pack_eta
#undef mld_polyvecl_pointwise_acc_montgomery
#undef mld_polyvecl_uniform_gamma1
#undef mld_polyvecl_unpack_eta
#undef mld_polyvecl_unpack_z
/* mldsa/src/rounding.h */
#undef MLD_2_POW_D
#undef MLD_ROUNDING_H
#undef mld_decompose
#undef mld_make_hint
#undef mld_power2round
#undef mld_use_hint
/* mldsa/src/sign.h */
#undef MLD_DOMAIN_SEPARATION_MAX_BYTES
#undef MLD_PREHASH_NONE
#undef MLD_PREHASH_SHA2_224
#undef MLD_PREHASH_SHA2_256
#undef MLD_PREHASH_SHA2_384
#undef MLD_PREHASH_SHA2_512
#undef MLD_PREHASH_SHA2_512_224
#undef MLD_PREHASH_SHA2_512_256
#undef MLD_PREHASH_SHA3_224
#undef MLD_PREHASH_SHA3_256
#undef MLD_PREHASH_SHA3_384
#undef MLD_PREHASH_SHA3_512
#undef MLD_PREHASH_SHAKE_128
#undef MLD_PREHASH_SHAKE_256
#undef MLD_SIGN_H
#undef mld_prepare_domain_separation_prefix
#undef mld_sign
#undef mld_sign_keypair
#undef mld_sign_keypair_internal
#undef mld_sign_open
#undef mld_sign_pk_from_sk
#undef mld_sign_signature
#undef mld_sign_signature_extmu
#undef mld_sign_signature_internal
#undef mld_sign_signature_pre_hash_internal
#undef mld_sign_signature_pre_hash_shake256
#undef mld_sign_verify
#undef mld_sign_verify_extmu
#undef mld_sign_verify_internal
#undef mld_sign_verify_pre_hash_internal
#undef mld_sign_verify_pre_hash_shake256
#if !defined(MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS)
/*
* Undefine macros from MLD_CONFIG_PARAMETER_SET-generic files
*/
/* mldsa/src/ct.h */
#undef MLD_CT_H
#undef MLD_USE_ASM_VALUE_BARRIER
#undef mld_ct_opt_blocker_u64
/* mldsa/src/debug.h */
#undef MLD_DEBUG_H
#undef mld_assert
#undef mld_assert_abs_bound
#undef mld_assert_abs_bound_2d
#undef mld_assert_bound
#undef mld_assert_bound_2d
#undef mld_debug_check_assert
#undef mld_debug_check_bounds
/* mldsa/src/poly.h */
#undef MLD_INTT_BOUND
#undef MLD_NTT_BOUND
#undef MLD_POLY_H
#undef mld_poly_add
#undef mld_poly_caddq
#undef mld_poly_chknorm
#undef mld_poly_invntt_tomont
#undef mld_poly_ntt
#undef mld_poly_pointwise_montgomery
#undef mld_poly_power2round
#undef mld_poly_reduce
#undef mld_poly_shiftl
#undef mld_poly_sub
#undef mld_poly_uniform
#undef mld_poly_uniform_4x
#undef mld_polyt0_pack
#undef mld_polyt0_unpack
#undef mld_polyt1_pack
#undef mld_polyt1_unpack
/* mldsa/src/randombytes.h */
#undef MLD_RANDOMBYTES_H
/* mldsa/src/reduce.h */
#undef MLD_MONT
#undef MLD_REDUCE32_DOMAIN_MAX
#undef MLD_REDUCE32_RANGE_MAX
#undef MLD_REDUCE_H
/* mldsa/src/symmetric.h */
#undef MLD_STREAM128_BLOCKBYTES
#undef MLD_STREAM256_BLOCKBYTES
#undef MLD_SYMMETRIC_H
#undef mld_xof128_absorb_once
#undef mld_xof128_ctx
#undef mld_xof128_init
#undef mld_xof128_release
#undef mld_xof128_squeezeblocks
#undef mld_xof128_x4_absorb
#undef mld_xof128_x4_ctx
#undef mld_xof128_x4_init
#undef mld_xof128_x4_release
#undef mld_xof128_x4_squeezeblocks
#undef mld_xof256_absorb_once
#undef mld_xof256_ctx
#undef mld_xof256_init
#undef mld_xof256_release
#undef mld_xof256_squeezeblocks
#undef mld_xof256_x4_absorb
#undef mld_xof256_x4_ctx
#undef mld_xof256_x4_init
#undef mld_xof256_x4_release
#undef mld_xof256_x4_squeezeblocks
/* mldsa/src/sys.h */
#undef MLD_ALIGN
#undef MLD_ALIGN_UP
#undef MLD_ALWAYS_INLINE
#undef MLD_CET_ENDBR
#undef MLD_CT_TESTING_DECLASSIFY
#undef MLD_CT_TESTING_SECRET
#undef MLD_DEFAULT_ALIGN
#undef MLD_HAVE_INLINE_ASM
#undef MLD_INLINE
#undef MLD_MUST_CHECK_RETURN_VALUE
#undef MLD_RESTRICT
#undef MLD_STATIC_TESTABLE
#undef MLD_SYS_AARCH64
#undef MLD_SYS_AARCH64_EB
#undef MLD_SYS_APPLE
#undef MLD_SYS_BIG_ENDIAN
#undef MLD_SYS_H
#undef MLD_SYS_LINUX
#undef MLD_SYS_LITTLE_ENDIAN
#undef MLD_SYS_PPC64LE
#undef MLD_SYS_RISCV32
#undef MLD_SYS_RISCV64
#undef MLD_SYS_WINDOWS
#undef MLD_SYS_X86_64
#undef MLD_SYS_X86_64_AVX2
/* mldsa/src/cbmc.h */
#undef MLD_CBMC_H
#undef __contract__
#undef __loop__
#if defined(MLD_CONFIG_USE_NATIVE_BACKEND_ARITH)
/* mldsa/src/native/api.h */
#undef MLD_INTT_BOUND
#undef MLD_NATIVE_API_H
#undef MLD_NATIVE_FUNC_FALLBACK
#undef MLD_NATIVE_FUNC_SUCCESS
#undef MLD_NTT_BOUND
#undef REDUCE32_RANGE_MAX
/* mldsa/src/native/meta.h */
#undef MLD_NATIVE_META_H
#if defined(MLD_SYS_AARCH64)
/*
* Undefine macros from native code (Arith, AArch64)
*/
/* mldsa/src/native/aarch64/meta.h */
#undef MLD_ARITH_BACKEND_AARCH64
#undef MLD_NATIVE_AARCH64_META_H
#undef MLD_USE_NATIVE_INTT
#undef MLD_USE_NATIVE_NTT
#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY
#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4
#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5
#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7
#undef MLD_USE_NATIVE_POLYZ_UNPACK_17
#undef MLD_USE_NATIVE_POLYZ_UNPACK_19
#undef MLD_USE_NATIVE_POLY_CADDQ
#undef MLD_USE_NATIVE_POLY_CHKNORM
#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32
#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88
#undef MLD_USE_NATIVE_POLY_USE_HINT_32
#undef MLD_USE_NATIVE_POLY_USE_HINT_88
#undef MLD_USE_NATIVE_REJ_UNIFORM
#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2
#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4
/* mldsa/src/native/aarch64/src/arith_native_aarch64.h */
#undef MLD_AARCH64_REJ_UNIFORM_ETA2_BUFLEN
#undef MLD_AARCH64_REJ_UNIFORM_ETA4_BUFLEN
#undef MLD_NATIVE_AARCH64_SRC_ARITH_NATIVE_AARCH64_H
#undef mld_aarch64_intt_zetas_layer123456
#undef mld_aarch64_intt_zetas_layer78
#undef mld_aarch64_ntt_zetas_layer123456
#undef mld_aarch64_ntt_zetas_layer78
#undef mld_intt_asm
#undef mld_ntt_asm
#undef mld_poly_caddq_asm
#undef mld_poly_chknorm_asm
#undef mld_poly_decompose_32_asm
#undef mld_poly_decompose_88_asm
#undef mld_poly_pointwise_montgomery_asm
#undef mld_poly_use_hint_32_asm
#undef mld_poly_use_hint_88_asm
#undef mld_polyvecl_pointwise_acc_montgomery_l4_asm
#undef mld_polyvecl_pointwise_acc_montgomery_l5_asm
#undef mld_polyvecl_pointwise_acc_montgomery_l7_asm
#undef mld_polyz_unpack_17_asm
#undef mld_polyz_unpack_17_indices
#undef mld_polyz_unpack_19_asm
#undef mld_polyz_unpack_19_indices
#undef mld_rej_uniform_asm
#undef mld_rej_uniform_eta2_asm
#undef mld_rej_uniform_eta4_asm
#undef mld_rej_uniform_eta_table
#undef mld_rej_uniform_table
#endif /* MLD_SYS_AARCH64 */
#if defined(MLD_SYS_X86_64)
/*
* Undefine macros from native code (Arith, X86_64)
*/
/* mldsa/src/native/x86_64/meta.h */
#undef MLD_ARITH_BACKEND_X86_64_DEFAULT
#undef MLD_NATIVE_X86_64_META_H
#undef MLD_USE_NATIVE_INTT
#undef MLD_USE_NATIVE_NTT
#undef MLD_USE_NATIVE_NTT_CUSTOM_ORDER
#undef MLD_USE_NATIVE_POINTWISE_MONTGOMERY
#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4
#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5
#undef MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7
#undef MLD_USE_NATIVE_POLYZ_UNPACK_17
#undef MLD_USE_NATIVE_POLYZ_UNPACK_19
#undef MLD_USE_NATIVE_POLY_CADDQ
#undef MLD_USE_NATIVE_POLY_CHKNORM
#undef MLD_USE_NATIVE_POLY_DECOMPOSE_32
#undef MLD_USE_NATIVE_POLY_DECOMPOSE_88
#undef MLD_USE_NATIVE_POLY_USE_HINT_32
#undef MLD_USE_NATIVE_POLY_USE_HINT_88
#undef MLD_USE_NATIVE_REJ_UNIFORM
#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA2
#undef MLD_USE_NATIVE_REJ_UNIFORM_ETA4
/* mldsa/src/native/x86_64/src/arith_native_x86_64.h */
#undef MLD_AVX2_REJ_UNIFORM_BUFLEN
#undef MLD_AVX2_REJ_UNIFORM_ETA2_BUFLEN
#undef MLD_AVX2_REJ_UNIFORM_ETA4_BUFLEN
#undef MLD_NATIVE_X86_64_SRC_ARITH_NATIVE_X86_64_H
#undef mld_invntt_avx2
#undef mld_ntt_avx2
#undef mld_nttunpack_avx2
#undef mld_pointwise_acc_l4_avx2
#undef mld_pointwise_acc_l5_avx2
#undef mld_pointwise_acc_l7_avx2
#undef mld_pointwise_avx2
#undef mld_poly_caddq_avx2
#undef mld_poly_chknorm_avx2
#undef mld_poly_decompose_32_avx2
#undef mld_poly_decompose_88_avx2
#undef mld_poly_use_hint_32_avx2
#undef mld_poly_use_hint_88_avx2
#undef mld_polyz_unpack_17_avx2
#undef mld_polyz_unpack_19_avx2
#undef mld_rej_uniform_avx2
#undef mld_rej_uniform_eta2_avx2
#undef mld_rej_uniform_eta4_avx2
#undef mld_rej_uniform_table
/* mldsa/src/native/x86_64/src/consts.h */
#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV
#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XDIV_QINV
#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQ
#undef MLD_AVX2_BACKEND_DATA_OFFSET_8XQINV
#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS
#undef MLD_AVX2_BACKEND_DATA_OFFSET_ZETAS_QINV
#undef MLD_NATIVE_X86_64_SRC_CONSTS_H
#undef mld_qdata
#endif /* MLD_SYS_X86_64 */
#endif /* MLD_CONFIG_USE_NATIVE_BACKEND_ARITH */
#endif /* !MLD_CONFIG_MONOBUILD_KEEP_SHARED_HEADERS */

View File

@@ -0,0 +1,286 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#include <string.h>
#include "common.h"
#include "packing.h"
#include "poly.h"
#include "polyvec.h"
/* Parameter set namespacing
* This is to facilitate building multiple instances
* of mldsa-native (e.g. with varying parameter sets)
* within a single compilation unit. */
#define mld_unpack_hints MLD_ADD_PARAM_SET(mld_unpack_hints)
/* End of parameter set namespacing */
MLD_INTERNAL_API
void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1)
{
unsigned int i;
mld_memcpy(pk, rho, MLDSA_SEEDBYTES);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
invariant(i <= MLDSA_K)
)
{
mld_polyt1_pack(pk + MLDSA_SEEDBYTES + i * MLDSA_POLYT1_PACKEDBYTES,
&t1->vec[i]);
}
}
MLD_INTERNAL_API
void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1,
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES])
{
unsigned int i;
mld_memcpy(rho, pk, MLDSA_SEEDBYTES);
pk += MLDSA_SEEDBYTES;
for (i = 0; i < MLDSA_K; ++i)
{
mld_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES);
}
}
MLD_INTERNAL_API
void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
const uint8_t rho[MLDSA_SEEDBYTES],
const uint8_t tr[MLDSA_TRBYTES],
const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0,
const mld_polyvecl *s1, const mld_polyveck *s2)
{
mld_memcpy(sk, rho, MLDSA_SEEDBYTES);
sk += MLDSA_SEEDBYTES;
mld_memcpy(sk, key, MLDSA_SEEDBYTES);
sk += MLDSA_SEEDBYTES;
mld_memcpy(sk, tr, MLDSA_TRBYTES);
sk += MLDSA_TRBYTES;
mld_polyvecl_pack_eta(sk, s1);
sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES;
mld_polyveck_pack_eta(sk, s2);
sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES;
mld_polyveck_pack_t0(sk, t0);
}
MLD_INTERNAL_API
void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES],
uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0,
mld_polyvecl *s1, mld_polyveck *s2,
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES])
{
mld_memcpy(rho, sk, MLDSA_SEEDBYTES);
sk += MLDSA_SEEDBYTES;
mld_memcpy(key, sk, MLDSA_SEEDBYTES);
sk += MLDSA_SEEDBYTES;
mld_memcpy(tr, sk, MLDSA_TRBYTES);
sk += MLDSA_TRBYTES;
mld_polyvecl_unpack_eta(s1, sk);
sk += MLDSA_L * MLDSA_POLYETA_PACKEDBYTES;
mld_polyveck_unpack_eta(s2, sk);
sk += MLDSA_K * MLDSA_POLYETA_PACKEDBYTES;
mld_polyveck_unpack_t0(t0, sk);
}
MLD_INTERNAL_API
void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES],
const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h,
const unsigned int number_of_hints)
{
unsigned int i, j, k;
mld_memcpy(sig, c, MLDSA_CTILDEBYTES);
sig += MLDSA_CTILDEBYTES;
/* skip z component - packed via mld_pack_sig_z */
sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES;
/* Encode hints h */
/* The final section of sig[] is MLDSA_POLYVECH_PACKEDBYTES long, where
* MLDSA_POLYVECH_PACKEDBYTES = MLDSA_OMEGA + MLDSA_K
*
* The first OMEGA bytes record the index numbers of the coefficients
* that are not equal to 0
*
* The final K bytes record a running tally of the number of hints
* coming from each of the K polynomials in h.
*
* The pre-condition tells us that number_of_hints <= OMEGA, so some
* bytes may not be written, so we initialize all of them to zero
* to start.
*/
mld_memset(sig, 0, MLDSA_POLYVECH_PACKEDBYTES);
k = 0;
/* For each polynomial in h... */
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES))
invariant(i <= MLDSA_K)
invariant(k <= number_of_hints)
invariant(number_of_hints <= MLDSA_OMEGA)
)
{
/* For each coefficient in that polynomial, record it as as hint */
/* if its value is not zero */
for (j = 0; j < MLDSA_N; ++j)
__loop__(
assigns(j, k, memory_slice(sig, MLDSA_POLYVECH_PACKEDBYTES))
invariant(i <= MLDSA_K)
invariant(j <= MLDSA_N)
invariant(k <= number_of_hints)
invariant(number_of_hints <= MLDSA_OMEGA)
)
{
/* The reference implementation implicitly relies on the total */
/* number of hints being less than OMEGA, assuming h is valid. */
/* In mldsa-native, we check this explicitly to ease proof of */
/* type safety. */
if (h->vec[i].coeffs[j] != 0 && k < number_of_hints)
{
/* The enclosing if condition AND the loop invariant infer */
/* that k < MLDSA_OMEGA, so writing to sig[k] is safe and k */
/* can be incremented. */
sig[k++] = (uint8_t)j;
}
}
/* Having recorded all the hints for this polynomial, also */
/* record the running tally into the correct "slot" for that */
/* coefficient in the final K bytes */
sig[MLDSA_OMEGA + i] = (uint8_t)k;
}
}
MLD_INTERNAL_API
void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi,
unsigned i)
{
sig += MLDSA_CTILDEBYTES;
sig += i * MLDSA_POLYZ_PACKEDBYTES;
mld_polyz_pack(sig, zi);
}
/*************************************************
* Name: mld_unpack_hints
*
* Description: Unpack raw hint bytes into a polyveck
* struct
*
* Arguments: - mld_polyveck *h: pointer to output hint vector h
* - const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES]:
* raw hint bytes
*
* Returns 1 in case of malformed hints; otherwise 0.
**************************************************/
static int mld_unpack_hints(
mld_polyveck *h, const uint8_t packed_hints[MLDSA_POLYVECH_PACKEDBYTES])
__contract__(
requires(memory_no_alias(packed_hints, MLDSA_POLYVECH_PACKEDBYTES))
requires(memory_no_alias(h, sizeof(mld_polyveck)))
assigns(memory_slice(h, sizeof(mld_polyveck)))
/* All returned coefficients are either 0 or 1 */
ensures(forall(k1, 0, MLDSA_K,
array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
ensures(return_value >= 0 && return_value <= 1)
)
{
unsigned int i, j;
unsigned int old_hint_count;
/* Set all coefficients of all polynomials to 0. */
/* Only those that are actually non-zero hints will */
/* be overwritten below. */
mld_memset(h, 0, sizeof(mld_polyveck));
old_hint_count = 0;
for (i = 0; i < MLDSA_K; ++i)
__loop__(
invariant(i <= MLDSA_K)
/* Maintain the post-condition */
invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
)
{
/* Grab the hint count for the i'th polynomial */
const unsigned int new_hint_count = packed_hints[MLDSA_OMEGA + i];
/* new_hint_count must increase or stay the same, but also remain */
/* less than or equal to MLDSA_OMEGA */
if (new_hint_count < old_hint_count || new_hint_count > MLDSA_OMEGA)
{
/* Error - new_hint_count is invalid */
return 1;
}
/* If new_hint_count == old_hint_count, then this polynomial has */
/* zero hints, so this loop executes zero times and we move */
/* straight on to the next polynomial. */
for (j = old_hint_count; j < new_hint_count; ++j)
__loop__(
invariant(i <= MLDSA_K)
/* Maintain the post-condition */
invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
)
{
const uint8_t this_hint_index = packed_hints[j];
/* Coefficients must be ordered for strong unforgeability */
if (j > old_hint_count && this_hint_index <= packed_hints[j - 1])
{
return 1;
}
h->vec[i].coeffs[this_hint_index] = 1;
}
old_hint_count = new_hint_count;
}
/* Extra indices must be zero for strong unforgeability */
for (j = old_hint_count; j < MLDSA_OMEGA; ++j)
__loop__(
invariant(j <= MLDSA_OMEGA)
/* Maintain the post-condition */
invariant(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
)
{
if (packed_hints[j] != 0)
{
return 1;
}
}
return 0;
}
MLD_INTERNAL_API
int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z,
mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES])
{
mld_memcpy(c, sig, MLDSA_CTILDEBYTES);
sig += MLDSA_CTILDEBYTES;
mld_polyvecl_unpack_z(z, sig);
sig += MLDSA_L * MLDSA_POLYZ_PACKEDBYTES;
return mld_unpack_hints(h, sig);
}
/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.
* Don't modify by hand -- this is auto-generated by scripts/autogen. */
#undef mld_unpack_hints

View File

@@ -0,0 +1,225 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_PACKING_H
#define MLD_PACKING_H
#include <stdint.h>
#include "polyvec.h"
#define mld_pack_pk MLD_NAMESPACE_KL(pack_pk)
/*************************************************
* Name: mld_pack_pk
*
* Description: Bit-pack public key pk = (rho, t1).
*
* Arguments: - uint8_t pk[]: output byte array
* - const uint8_t rho[]: byte array containing rho
* - const mld_polyveck *t1: pointer to vector t1
**************************************************/
MLD_INTERNAL_API
void mld_pack_pk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
const uint8_t rho[MLDSA_SEEDBYTES], const mld_polyveck *t1)
__contract__(
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
requires(memory_no_alias(rho, MLDSA_SEEDBYTES))
requires(memory_no_alias(t1, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K,
array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10)))
assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
);
#define mld_pack_sk MLD_NAMESPACE_KL(pack_sk)
/*************************************************
* Name: mld_pack_sk
*
* Description: Bit-pack secret key sk = (rho, tr, key, t0, s1, s2).
*
* Arguments: - uint8_t sk[]: output byte array
* - const uint8_t rho[]: byte array containing rho
* - const uint8_t tr[]: byte array containing tr
* - const uint8_t key[]: byte array containing key
* - const mld_polyveck *t0: pointer to vector t0
* - const mld_polyvecl *s1: pointer to vector s1
* - const mld_polyveck *s2: pointer to vector s2
**************************************************/
MLD_INTERNAL_API
void mld_pack_sk(uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
const uint8_t rho[MLDSA_SEEDBYTES],
const uint8_t tr[MLDSA_TRBYTES],
const uint8_t key[MLDSA_SEEDBYTES], const mld_polyveck *t0,
const mld_polyvecl *s1, const mld_polyveck *s2)
__contract__(
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
requires(memory_no_alias(rho, MLDSA_SEEDBYTES))
requires(memory_no_alias(tr, MLDSA_TRBYTES))
requires(memory_no_alias(key, MLDSA_SEEDBYTES))
requires(memory_no_alias(t0, sizeof(mld_polyveck)))
requires(memory_no_alias(s1, sizeof(mld_polyvecl)))
requires(memory_no_alias(s2, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K,
array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)))
requires(forall(k1, 0, MLDSA_L,
array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))
requires(forall(k2, 0, MLDSA_K,
array_abs_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))
assigns(memory_slice(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
);
#define mld_pack_sig_c_h MLD_NAMESPACE_KL(pack_sig_c_h)
/*************************************************
* Name: mld_pack_sig_c_h
*
* Description: Bit-pack c and h component of sig = (c, z, h).
* The z component is packed separately using mld_pack_sig_z.
*
* Arguments: - uint8_t sig[]: output byte array
* - const uint8_t *c: pointer to challenge hash length
* MLDSA_SEEDBYTES
* - const mld_polyveck *h: pointer to hint vector h
* - const unsigned int number_of_hints: total
* hints in *h
*
* Note that the number_of_hints argument is not present
* in the reference implementation. It is added here to ease
* proof of type safety.
**************************************************/
MLD_INTERNAL_API
void mld_pack_sig_c_h(uint8_t sig[MLDSA_CRYPTO_BYTES],
const uint8_t c[MLDSA_CTILDEBYTES], const mld_polyveck *h,
const unsigned int number_of_hints)
__contract__(
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
requires(memory_no_alias(c, MLDSA_CTILDEBYTES))
requires(memory_no_alias(h, sizeof(mld_polyveck)))
requires(forall(k1, 0, MLDSA_K,
array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
requires(number_of_hints <= MLDSA_OMEGA)
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
);
#define mld_pack_sig_z MLD_NAMESPACE_KL(pack_sig_z)
/*************************************************
* Name: mld_pack_sig_z
*
* Description: Bit-pack single polynomial of z component of sig = (c, z, h).
* The c and h components are packed separately using
* mld_pack_sig_c_h.
*
* Arguments: - uint8_t sig[]: output byte array
* - const mld_poly *zi: pointer to a single polynomial in z
* - const unsigned int i: index of zi in vector z
*
**************************************************/
MLD_INTERNAL_API
void mld_pack_sig_z(uint8_t sig[MLDSA_CRYPTO_BYTES], const mld_poly *zi,
unsigned i)
__contract__(
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
requires(memory_no_alias(zi, sizeof(mld_poly)))
requires(i < MLDSA_L)
requires(array_bound(zi->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
);
#define mld_unpack_pk MLD_NAMESPACE_KL(unpack_pk)
/*************************************************
* Name: mld_unpack_pk
*
* Description: Unpack public key pk = (rho, t1).
*
* Arguments: - const uint8_t rho[]: output byte array for rho
* - const mld_polyveck *t1: pointer to output vector t1
* - uint8_t pk[]: byte array containing bit-packed pk
**************************************************/
MLD_INTERNAL_API
void mld_unpack_pk(uint8_t rho[MLDSA_SEEDBYTES], mld_polyveck *t1,
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES])
__contract__(
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
requires(memory_no_alias(rho, MLDSA_SEEDBYTES))
requires(memory_no_alias(t1, sizeof(mld_polyveck)))
assigns(memory_slice(rho, MLDSA_SEEDBYTES))
assigns(memory_slice(t1, sizeof(mld_polyveck)))
ensures(forall(k0, 0, MLDSA_K,
array_bound(t1->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10)))
);
#define mld_unpack_sk MLD_NAMESPACE_KL(unpack_sk)
/*************************************************
* Name: mld_unpack_sk
*
* Description: Unpack secret key sk = (rho, tr, key, t0, s1, s2).
*
* Arguments: - const uint8_t rho[]: output byte array for rho
* - const uint8_t tr[]: output byte array for tr
* - const uint8_t key[]: output byte array for key
* - const mld_polyveck *t0: pointer to output vector t0
* - const mld_polyvecl *s1: pointer to output vector s1
* - const mld_polyveck *s2: pointer to output vector s2
* - uint8_t sk[]: byte array containing bit-packed sk
**************************************************/
MLD_INTERNAL_API
void mld_unpack_sk(uint8_t rho[MLDSA_SEEDBYTES], uint8_t tr[MLDSA_TRBYTES],
uint8_t key[MLDSA_SEEDBYTES], mld_polyveck *t0,
mld_polyvecl *s1, mld_polyveck *s2,
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES])
__contract__(
requires(memory_no_alias(rho, MLDSA_SEEDBYTES))
requires(memory_no_alias(tr, MLDSA_TRBYTES))
requires(memory_no_alias(key, MLDSA_SEEDBYTES))
requires(memory_no_alias(t0, sizeof(mld_polyveck)))
requires(memory_no_alias(s1, sizeof(mld_polyvecl)))
requires(memory_no_alias(s2, sizeof(mld_polyveck)))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(memory_slice(rho, MLDSA_SEEDBYTES))
assigns(memory_slice(tr, MLDSA_TRBYTES))
assigns(memory_slice(key, MLDSA_SEEDBYTES))
assigns(memory_slice(t0, sizeof(mld_polyveck)))
assigns(memory_slice(s1, sizeof(mld_polyvecl)))
assigns(memory_slice(s2, sizeof(mld_polyveck)))
ensures(forall(k0, 0, MLDSA_K,
array_bound(t0->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)))
ensures(forall(k1, 0, MLDSA_L,
array_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))
ensures(forall(k2, 0, MLDSA_K,
array_bound(s2->vec[k2].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))
);
#define mld_unpack_sig MLD_NAMESPACE_KL(unpack_sig)
/*************************************************
* Name: mld_unpack_sig
*
* Description: Unpack signature sig = (c, z, h).
*
* Arguments: - uint8_t *c: pointer to output challenge hash
* - mld_polyvecl *z: pointer to output vector z
* - mld_polyveck *h: pointer to output hint vector h
* - const uint8_t sig[]: byte array containing
* bit-packed signature
*
* Returns 1 in case of malformed signature; otherwise 0.
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_INTERNAL_API
int mld_unpack_sig(uint8_t c[MLDSA_CTILDEBYTES], mld_polyvecl *z,
mld_polyveck *h, const uint8_t sig[MLDSA_CRYPTO_BYTES])
__contract__(
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
requires(memory_no_alias(c, MLDSA_CTILDEBYTES))
requires(memory_no_alias(z, sizeof(mld_polyvecl)))
requires(memory_no_alias(h, sizeof(mld_polyveck)))
assigns(memory_slice(c, MLDSA_CTILDEBYTES))
assigns(memory_slice(z, sizeof(mld_polyvecl)))
assigns(memory_slice(h, sizeof(mld_polyveck)))
ensures(forall(k0, 0, MLDSA_L,
array_bound(z->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))
ensures(forall(k1, 0, MLDSA_K,
array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
ensures(return_value >= 0 && return_value <= 1)
);
#endif /* !MLD_PACKING_H */

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_PARAMS_H
#define MLD_PARAMS_H
#define MLDSA_SEEDBYTES 32
#define MLDSA_CRHBYTES 64
#define MLDSA_TRBYTES 64
#define MLDSA_RNDBYTES 32
#define MLDSA_N 256
#define MLDSA_Q 8380417
#define MLDSA_Q_HALF ((MLDSA_Q + 1) / 2)
#define MLDSA_D 13
#if MLD_CONFIG_PARAMETER_SET == 44
#define MLDSA_K 4
#define MLDSA_L 4
#define MLDSA_ETA 2
#define MLDSA_TAU 39
#define MLDSA_BETA 78
#define MLDSA_GAMMA1 (1 << 17)
#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 88)
#define MLDSA_OMEGA 80
#define MLDSA_CTILDEBYTES 32
#define MLDSA_POLYZ_PACKEDBYTES 576
#define MLDSA_POLYW1_PACKEDBYTES 192
#define MLDSA_POLYETA_PACKEDBYTES 96
#elif MLD_CONFIG_PARAMETER_SET == 65
#define MLDSA_K 6
#define MLDSA_L 5
#define MLDSA_ETA 4
#define MLDSA_TAU 49
#define MLDSA_BETA 196
#define MLDSA_GAMMA1 (1 << 19)
#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32)
#define MLDSA_OMEGA 55
#define MLDSA_CTILDEBYTES 48
#define MLDSA_POLYZ_PACKEDBYTES 640
#define MLDSA_POLYW1_PACKEDBYTES 128
#define MLDSA_POLYETA_PACKEDBYTES 128
#elif MLD_CONFIG_PARAMETER_SET == 87
#define MLDSA_K 8
#define MLDSA_L 7
#define MLDSA_ETA 2
#define MLDSA_TAU 60
#define MLDSA_BETA 120
#define MLDSA_GAMMA1 (1 << 19)
#define MLDSA_GAMMA2 ((MLDSA_Q - 1) / 32)
#define MLDSA_OMEGA 75
#define MLDSA_CTILDEBYTES 64
#define MLDSA_POLYZ_PACKEDBYTES 640
#define MLDSA_POLYW1_PACKEDBYTES 128
#define MLDSA_POLYETA_PACKEDBYTES 96
#endif /* MLD_CONFIG_PARAMETER_SET == 87 */
#define MLDSA_POLYT1_PACKEDBYTES 320
#define MLDSA_POLYT0_PACKEDBYTES 416
#define MLDSA_POLYVECH_PACKEDBYTES (MLDSA_OMEGA + MLDSA_K)
#define MLDSA_CRYPTO_PUBLICKEYBYTES \
(MLDSA_SEEDBYTES + MLDSA_K * MLDSA_POLYT1_PACKEDBYTES)
#define MLDSA_CRYPTO_SECRETKEYBYTES \
(2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + MLDSA_L * MLDSA_POLYETA_PACKEDBYTES + \
MLDSA_K * MLDSA_POLYETA_PACKEDBYTES + MLDSA_K * MLDSA_POLYT0_PACKEDBYTES)
#define MLDSA_CRYPTO_BYTES \
(MLDSA_CTILDEBYTES + MLDSA_L * MLDSA_POLYZ_PACKEDBYTES + \
MLDSA_POLYVECH_PACKEDBYTES)
#endif /* !MLD_PARAMS_H */

View File

@@ -0,0 +1,971 @@
/*
* Copyright (c) The mldsa-native project authors
* Copyright (c) The mlkem-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* References
* ==========
*
* - [FIPS204]
* FIPS 204 Module-Lattice-Based Digital Signature Standard
* National Institute of Standards and Technology
* https://csrc.nist.gov/pubs/fips/204/final
*
* - [REF]
* CRYSTALS-Dilithium reference implementation
* Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé
* https://github.com/pq-crystals/dilithium/tree/master/ref
*/
#include <stdint.h>
#include <string.h>
#include "common.h"
#include "ct.h"
#include "debug.h"
#include "poly.h"
#include "reduce.h"
#include "rounding.h"
#include "symmetric.h"
#if !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)
#include "zetas.inc"
MLD_INTERNAL_API
void mld_poly_reduce(mld_poly *a)
{
unsigned int i;
mld_assert_bound(a->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX);
for (i = 0; i < MLDSA_N; ++i)
__loop__(
invariant(i <= MLDSA_N)
invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))
invariant(array_bound(a->coeffs, 0, i, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))
{
a->coeffs[i] = mld_reduce32(a->coeffs[i]);
}
mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,
MLD_REDUCE32_RANGE_MAX);
}
MLD_STATIC_TESTABLE void mld_poly_caddq_c(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
)
{
unsigned int i;
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);
for (i = 0; i < MLDSA_N; ++i)
__loop__(
invariant(i <= MLDSA_N)
invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0]))
invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q))
)
{
a->coeffs[i] = mld_caddq(a->coeffs[i]);
}
mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);
}
MLD_INTERNAL_API
void mld_poly_caddq(mld_poly *a)
{
#if defined(MLD_USE_NATIVE_POLY_CADDQ)
int ret;
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);
ret = mld_poly_caddq_native(a->coeffs);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);
return;
}
#endif /* MLD_USE_NATIVE_POLY_CADDQ */
mld_poly_caddq_c(a);
}
/* Reference: We use destructive version (output=first input) to avoid
* reasoning about aliasing in the CBMC specification */
MLD_INTERNAL_API
void mld_poly_add(mld_poly *r, const mld_poly *b)
{
unsigned int i;
for (i = 0; i < MLDSA_N; ++i)
__loop__(
assigns(i, memory_slice(r, sizeof(mld_poly)))
invariant(i <= MLDSA_N)
invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0]))
invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1]))
invariant(forall(k2, 0, i, r->coeffs[k2] < MLD_REDUCE32_DOMAIN_MAX))
invariant(forall(k2, 0, i, r->coeffs[k2] >= INT32_MIN))
)
{
r->coeffs[i] = r->coeffs[i] + b->coeffs[i];
}
}
/* Reference: We use destructive version (output=first input) to avoid
* reasoning about aliasing in the CBMC specification */
MLD_INTERNAL_API
void mld_poly_sub(mld_poly *r, const mld_poly *b)
{
unsigned int i;
mld_assert_abs_bound(b->coeffs, MLDSA_N, MLDSA_Q);
mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_Q);
for (i = 0; i < MLDSA_N; ++i)
__loop__(
invariant(i <= MLDSA_N)
invariant(array_bound(r->coeffs, 0, i, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))
invariant(forall(k0, i, MLDSA_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0]))
)
{
r->coeffs[i] = r->coeffs[i] - b->coeffs[i];
}
mld_assert_bound(r->coeffs, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX);
}
MLD_INTERNAL_API
void mld_poly_shiftl(mld_poly *a)
{
unsigned int i;
mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10);
for (i = 0; i < MLDSA_N; i++)
__loop__(
invariant(i <= MLDSA_N)
invariant(array_bound(a->coeffs, 0, i, 0, MLDSA_Q))
invariant(forall(k0, i, MLDSA_N, a->coeffs[k0] == loop_entry(*a).coeffs[k0])))
{
/* Reference: uses a left shift by MLDSA_D which is undefined behaviour in
* C90/C99
*/
a->coeffs[i] *= (1 << MLDSA_D);
}
mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);
}
static MLD_INLINE int32_t mld_fqmul(int32_t a, int32_t b)
__contract__(
requires(b > -MLDSA_Q_HALF && b < MLDSA_Q_HALF)
ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q)
)
{
/* Bounds: We argue in mld_montgomery_reduce() that the reult
* of Montgomery reduction is < MLDSA_Q if the input is smaller
* than 2^31 * MLDSA_Q in absolute value. Indeed, we have:
*
* |a * b| = |a| * |b|
* < 2^31 * MLDSA_Q_HALF
* < 2^31 * MLDSA_Q
*/
return mld_montgomery_reduce((int64_t)a * (int64_t)b);
}
/* mld_ntt_butterfly_block()
*
* Computes a block CT butterflies with a fixed twiddle factor,
* using Montgomery multiplication.
*
* Parameters:
* - r: Pointer to base of polynomial (_not_ the base of butterfly block)
* - zeta: Twiddle factor to use for the butterfly. This must be in
* Montgomery form and signed canonical.
* - start: Offset to the beginning of the butterfly block
* - len: Index difference between coefficients subject to a butterfly
* - bound: Ghost variable describing coefficient bound: Prior to `start`,
* coefficients must be bound by `bound + MLDSA_Q`. Post `start`,
* they must be bound by `bound`.
* When this function returns, output coefficients in the index range
* [start, start+2*len) have bound bumped to `bound + MLDSA_Q`.
* Example:
* - start=8, len=4
* This would compute the following four butterflies
* 8 -- 12
* 9 -- 13
* 10 -- 14
* 11 -- 15
* - start=4, len=2
* This would compute the following two butterflies
* 4 -- 6
* 5 -- 7
*/
/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */
static MLD_INLINE void mld_ntt_butterfly_block(int32_t r[MLDSA_N],
const int32_t zeta,
const unsigned start,
const unsigned len,
const unsigned bound)
__contract__(
requires(start < MLDSA_N)
requires(1 <= len && len <= MLDSA_N / 2 && start + 2 * len <= MLDSA_N)
requires(0 <= bound && bound < INT32_MAX - MLDSA_Q)
requires(-MLDSA_Q_HALF < zeta && zeta < MLDSA_Q_HALF)
requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))
requires(array_abs_bound(r, 0, start, bound + MLDSA_Q))
requires(array_abs_bound(r, start, MLDSA_N, bound))
assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))
ensures(array_abs_bound(r, 0, start + 2*len, bound + MLDSA_Q))
ensures(array_abs_bound(r, start + 2 * len, MLDSA_N, bound)))
{
/* `bound` is a ghost variable only needed in the CBMC specification */
unsigned j;
((void)bound);
for (j = start; j < start + len; j++)
__loop__(
invariant(start <= j && j <= start + len)
/*
* Coefficients are updated in strided pairs, so the bounds for the
* intermediate states alternate twice between the old and new bound
*/
invariant(array_abs_bound(r, 0, j, bound + MLDSA_Q))
invariant(array_abs_bound(r, j, start + len, bound))
invariant(array_abs_bound(r, start + len, j + len, bound + MLDSA_Q))
invariant(array_abs_bound(r, j + len, MLDSA_N, bound)))
{
int32_t t;
t = mld_fqmul(r[j + len], zeta);
r[j + len] = r[j] - t;
r[j] = r[j] + t;
}
}
/* mld_ntt_layer()
*
* Compute one layer of forward NTT
*
* Parameters:
* - r: Pointer to base of polynomial
* - layer: Indicates which layer is being applied.
*/
/* Reference: Embedded in `ntt()` in the reference implementation @[REF]. */
static MLD_INLINE void mld_ntt_layer(int32_t r[MLDSA_N], const unsigned layer)
__contract__(
requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))
requires(1 <= layer && layer <= 8)
requires(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q))
assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))
ensures(array_abs_bound(r, 0, MLDSA_N, (layer + 1) * MLDSA_Q)))
{
unsigned start, k, len;
/* Twiddle factors for layer n are at indices 2^(n-1)..2^n-1. */
k = 1u << (layer - 1);
len = (unsigned)MLDSA_N >> layer;
for (start = 0; start < MLDSA_N; start += 2 * len)
__loop__(
invariant(start < MLDSA_N + 2 * len)
invariant(k <= MLDSA_N)
invariant(2 * len * k == start + MLDSA_N)
invariant(array_abs_bound(r, 0, start, layer * MLDSA_Q + MLDSA_Q))
invariant(array_abs_bound(r, start, MLDSA_N, layer * MLDSA_Q)))
{
int32_t zeta = mld_zetas[k++];
mld_ntt_butterfly_block(r, zeta, start, len, layer * MLDSA_Q);
}
}
MLD_STATIC_TESTABLE void mld_poly_ntt_c(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
)
{
unsigned int layer;
int32_t *r;
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);
r = a->coeffs;
for (layer = 1; layer < 9; layer++)
__loop__(
invariant(1 <= layer && layer <= 9)
invariant(array_abs_bound(r, 0, MLDSA_N, layer * MLDSA_Q))
)
{
mld_ntt_layer(r, layer);
}
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND);
}
MLD_INTERNAL_API
void mld_poly_ntt(mld_poly *a)
{
#if defined(MLD_USE_NATIVE_NTT)
int ret;
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);
ret = mld_ntt_native(a->coeffs);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND);
return;
}
#endif /* MLD_USE_NATIVE_NTT */
mld_poly_ntt_c(a);
}
/*************************************************
* Name: mld_fqscale
*
* Description: Scales a field element by mont/256 , i.e., performs Montgomery
* multiplication by mont^2/256.
* Input is expected to have absolute value smaller than
* 256 * MLDSA_Q.
* Output has absolute value smaller than MLD_INTT_BOUND.
*
* Arguments: - int32_t a: Field element to be scaled.
**************************************************/
static MLD_INLINE int32_t mld_fqscale(int32_t a)
__contract__(
requires(a > -256*MLDSA_Q && a < 256*MLDSA_Q)
ensures(return_value > -MLD_INTT_BOUND && return_value < MLD_INTT_BOUND)
)
{
/* check-magic: 41978 == pow(2,64-8,MLDSA_Q) */
const int32_t f = 41978;
/* Bounds: MLD_INTT_BOUND is MLDSA_Q, so the bounds reasoning is just
* a special case of that in mld_fqmul(). */
return mld_montgomery_reduce((int64_t)a * f);
}
/* Reference: Embedded into `invntt_tomont()` in the reference implementation
* @[REF] */
static MLD_INLINE void mld_invntt_layer(int32_t r[MLDSA_N], unsigned layer)
__contract__(
requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))
requires(1 <= layer && layer <= 8)
requires(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q))
assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))
ensures(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> (layer - 1)) * MLDSA_Q)))
{
unsigned start, k, len;
len = (unsigned)MLDSA_N >> layer;
k = (1u << layer) - 1;
for (start = 0; start < MLDSA_N; start += 2 * len)
__loop__(
invariant(start <= MLDSA_N && k <= 255)
invariant(2 * len * k + start == 2 * MLDSA_N - 2 * len)
invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q))
invariant(array_abs_bound(r, start, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)))
{
unsigned j;
int32_t zeta = -mld_zetas[k--];
for (j = start; j < start + len; j++)
__loop__(
invariant(start <= j && j <= start + len)
invariant(array_abs_bound(r, 0, start, (MLDSA_N >> (layer - 1)) * MLDSA_Q))
invariant(array_abs_bound(r, start, j, (MLDSA_N >> (layer - 1)) * MLDSA_Q))
invariant(array_abs_bound(r, j, start + len, (MLDSA_N >> layer) * MLDSA_Q))
invariant(array_abs_bound(r, start + len, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)))
{
int32_t t = r[j];
r[j] = t + r[j + len];
r[j + len] = t - r[j + len];
r[j + len] = mld_fqmul(r[j + len], zeta);
}
}
}
MLD_STATIC_TESTABLE void mld_poly_invntt_tomont_c(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND))
)
{
unsigned int layer, j;
int32_t *r;
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);
r = a->coeffs;
for (layer = 8; layer >= 1; layer--)
__loop__(
invariant(layer <= 8)
/* Absolute bounds increase from 1Q before layer 8 */
/* up to 256Q after layer 1 */
invariant(array_abs_bound(r, 0, MLDSA_N, (MLDSA_N >> layer) * MLDSA_Q)))
{
mld_invntt_layer(r, layer);
}
/* Coefficient bounds are now at 256Q. We now scale by mont / 256,
* i.e., compute the Montgomery multiplication by mont^2 / 256.
* mont corrects the mont^-1 factor introduced in the basemul.
* 1/256 performs that scaling of the inverse NTT.
* The reduced value is bounded by MLD_INTT_BOUND in absolute
* value.*/
for (j = 0; j < MLDSA_N; ++j)
__loop__(
invariant(j <= MLDSA_N)
invariant(array_abs_bound(r, 0, j, MLD_INTT_BOUND))
invariant(array_abs_bound(r, j, MLDSA_N, MLDSA_N * MLDSA_Q))
)
{
r[j] = mld_fqscale(r[j]);
}
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND);
}
MLD_INTERNAL_API
void mld_poly_invntt_tomont(mld_poly *a)
{
#if defined(MLD_USE_NATIVE_INTT)
int ret;
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_Q);
ret = mld_intt_native(a->coeffs);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_INTT_BOUND);
return;
}
#endif /* MLD_USE_NATIVE_INTT */
mld_poly_invntt_tomont_c(a);
}
MLD_STATIC_TESTABLE void mld_poly_pointwise_montgomery_c(mld_poly *c,
const mld_poly *a,
const mld_poly *b)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(memory_no_alias(c, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
assigns(memory_slice(c, sizeof(mld_poly)))
ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q))
)
{
unsigned int i;
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND);
mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND);
for (i = 0; i < MLDSA_N; ++i)
__loop__(
invariant(i <= MLDSA_N)
invariant(array_abs_bound(c->coeffs, 0, i, MLDSA_Q))
)
{
c->coeffs[i] = mld_montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]);
}
mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q);
}
MLD_INTERNAL_API
void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a,
const mld_poly *b)
{
#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY)
int ret;
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLD_NTT_BOUND);
mld_assert_abs_bound(b->coeffs, MLDSA_N, MLD_NTT_BOUND);
ret = mld_poly_pointwise_montgomery_native(c->coeffs, a->coeffs, b->coeffs);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_abs_bound(c->coeffs, MLDSA_N, MLDSA_Q);
return;
}
#endif /* MLD_USE_NATIVE_POINTWISE_MONTGOMERY */
mld_poly_pointwise_montgomery_c(c, a, b);
}
MLD_INTERNAL_API
void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a)
{
unsigned int i;
mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);
for (i = 0; i < MLDSA_N; ++i)
__loop__(
assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly)))
invariant(i <= MLDSA_N)
invariant(array_bound(a0->coeffs, 0, i, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))
invariant(array_bound(a1->coeffs, 0, i, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))
)
{
mld_power2round(&a0->coeffs[i], &a1->coeffs[i], a->coeffs[i]);
}
mld_assert_bound(a0->coeffs, MLDSA_N, -(MLD_2_POW_D / 2) + 1,
(MLD_2_POW_D / 2) + 1);
mld_assert_bound(a1->coeffs, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1);
}
#define MLD_POLY_UNIFORM_NBLOCKS \
((768 + MLD_STREAM128_BLOCKBYTES - 1) / MLD_STREAM128_BLOCKBYTES)
/* Reference: `mld_rej_uniform()` in the reference implementation @[REF].
* - Our signature differs from the reference implementation
* in that it adds the offset and always expects the base of the
* target buffer. This avoids shifting the buffer base in the
* caller, which appears tricky to reason about. */
MLD_STATIC_TESTABLE unsigned int mld_rej_uniform_c(int32_t *a,
unsigned int target,
unsigned int offset,
const uint8_t *buf,
unsigned int buflen)
__contract__(
requires(offset <= target && target <= MLDSA_N)
requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0)
requires(memory_no_alias(a, sizeof(int32_t) * target))
requires(memory_no_alias(buf, buflen))
requires(array_bound(a, 0, offset, 0, MLDSA_Q))
assigns(memory_slice(a, sizeof(int32_t) * target))
ensures(offset <= return_value && return_value <= target)
ensures(array_bound(a, 0, return_value, 0, MLDSA_Q))
)
{
unsigned int ctr, pos;
uint32_t t;
mld_assert_bound(a, offset, 0, MLDSA_Q);
ctr = offset;
pos = 0;
/* pos + 3 cannot overflow due to the assumption
buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) */
while (ctr < target && pos + 3 <= buflen)
__loop__(
invariant(offset <= ctr && ctr <= target && pos <= buflen)
invariant(array_bound(a, 0, ctr, 0, MLDSA_Q)))
{
t = buf[pos++];
t |= (uint32_t)buf[pos++] << 8;
t |= (uint32_t)buf[pos++] << 16;
t &= 0x7FFFFF;
if (t < MLDSA_Q)
{
a[ctr++] = (int32_t)t;
}
}
mld_assert_bound(a, ctr, 0, MLDSA_Q);
return ctr;
}
/*************************************************
* Name: mld_rej_uniform
*
* Description: Sample uniformly random coefficients in [0, MLDSA_Q-1] by
* performing rejection sampling on array of random bytes.
*
* Arguments: - int32_t *a: pointer to output array (allocated)
* - unsigned int target: requested number of coefficients to
*sample
* - unsigned int offset: number of coefficients already sampled
* - const uint8_t *buf: array of random bytes to sample from
* - unsigned int buflen: length of array of random bytes (must be
* multiple of 3)
*
* Returns number of sampled coefficients. Can be smaller than len if not enough
* random bytes were given.
**************************************************/
/* Reference: `mld_rej_uniform()` in the reference implementation @[REF].
* - Our signature differs from the reference implementation
* in that it adds the offset and always expects the base of the
* target buffer. This avoids shifting the buffer base in the
* caller, which appears tricky to reason about. */
static unsigned int mld_rej_uniform(int32_t *a, unsigned int target,
unsigned int offset, const uint8_t *buf,
unsigned int buflen)
__contract__(
requires(offset <= target && target <= MLDSA_N)
requires(buflen <= (MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES) && buflen % 3 == 0)
requires(memory_no_alias(a, sizeof(int32_t) * target))
requires(memory_no_alias(buf, buflen))
requires(array_bound(a, 0, offset, 0, MLDSA_Q))
assigns(memory_slice(a, sizeof(int32_t) * target))
ensures(offset <= return_value && return_value <= target)
ensures(array_bound(a, 0, return_value, 0, MLDSA_Q))
)
{
#if defined(MLD_USE_NATIVE_REJ_UNIFORM)
int ret;
mld_assert_bound(a, offset, 0, MLDSA_Q);
if (offset == 0)
{
ret = mld_rej_uniform_native(a, target, buf, buflen);
if (ret != MLD_NATIVE_FUNC_FALLBACK)
{
unsigned res = (unsigned)ret;
mld_assert_bound(a, res, 0, MLDSA_Q);
return res;
}
}
#endif /* MLD_USE_NATIVE_REJ_UNIFORM */
return mld_rej_uniform_c(a, target, offset, buf, buflen);
}
/* Reference: poly_uniform() in the reference implementation @[REF].
* - Simplified from reference by removing buffer tail handling
* since buflen % 3 = 0 always holds true (MLD_STREAM128_BLOCKBYTES
* = 168).
* - Modified rej_uniform interface to track offset directly.
* - Pass nonce packed in the extended seed array instead of a third
* argument.
* */
MLD_INTERNAL_API
void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2])
{
unsigned int ctr;
unsigned int buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES;
MLD_ALIGN uint8_t buf[MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES];
mld_xof128_ctx state;
mld_xof128_init(&state);
mld_xof128_absorb_once(&state, seed, MLDSA_SEEDBYTES + 2);
mld_xof128_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state);
ctr = mld_rej_uniform(a->coeffs, MLDSA_N, 0, buf, buflen);
buflen = MLD_STREAM128_BLOCKBYTES;
while (ctr < MLDSA_N)
__loop__(
assigns(ctr, state, memory_slice(a, sizeof(mld_poly)), object_whole(buf))
invariant(ctr <= MLDSA_N)
invariant(array_bound(a->coeffs, 0, ctr, 0, MLDSA_Q))
invariant(state.pos <= SHAKE128_RATE)
)
{
mld_xof128_squeezeblocks(buf, 1, &state);
ctr = mld_rej_uniform(a->coeffs, MLDSA_N, ctr, buf, buflen);
}
mld_xof128_release(&state);
mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(buf, sizeof(buf));
}
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM)
MLD_INTERNAL_API
void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2,
mld_poly *vec3,
uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)])
{
/* Temporary buffers for XOF output before rejection sampling */
MLD_ALIGN uint8_t
buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES)];
/* Tracks the number of coefficients we have already sampled */
unsigned ctr[4];
mld_xof128_x4_ctx state;
unsigned buflen;
mld_xof128_x4_init(&state);
mld_xof128_x4_absorb(&state, seed, MLDSA_SEEDBYTES + 2);
/*
* Initially, squeeze heuristic number of MLD_POLY_UNIFORM_NBLOCKS.
* This should generate the matrix entries with high probability.
*/
mld_xof128_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_NBLOCKS, &state);
buflen = MLD_POLY_UNIFORM_NBLOCKS * MLD_STREAM128_BLOCKBYTES;
ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, 0, buf[0], buflen);
ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, 0, buf[1], buflen);
ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, 0, buf[2], buflen);
ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, 0, buf[3], buflen);
/*
* So long as not all matrix entries have been generated, squeeze
* one more block a time until we're done.
*/
buflen = MLD_STREAM128_BLOCKBYTES;
while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N ||
ctr[3] < MLDSA_N)
__loop__(
assigns(ctr, state, object_whole(buf),
memory_slice(vec0, sizeof(mld_poly)), memory_slice(vec1, sizeof(mld_poly)),
memory_slice(vec2, sizeof(mld_poly)), memory_slice(vec3, sizeof(mld_poly)))
invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N)
invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N)
invariant(array_bound(vec0->coeffs, 0, ctr[0], 0, MLDSA_Q))
invariant(array_bound(vec1->coeffs, 0, ctr[1], 0, MLDSA_Q))
invariant(array_bound(vec2->coeffs, 0, ctr[2], 0, MLDSA_Q))
invariant(array_bound(vec3->coeffs, 0, ctr[3], 0, MLDSA_Q)))
{
mld_xof128_x4_squeezeblocks(buf, 1, &state);
ctr[0] = mld_rej_uniform(vec0->coeffs, MLDSA_N, ctr[0], buf[0], buflen);
ctr[1] = mld_rej_uniform(vec1->coeffs, MLDSA_N, ctr[1], buf[1], buflen);
ctr[2] = mld_rej_uniform(vec2->coeffs, MLDSA_N, ctr[2], buf[2], buflen);
ctr[3] = mld_rej_uniform(vec3->coeffs, MLDSA_N, ctr[3], buf[3], buflen);
}
mld_xof128_x4_release(&state);
mld_assert_bound(vec0->coeffs, MLDSA_N, 0, MLDSA_Q);
mld_assert_bound(vec1->coeffs, MLDSA_N, 0, MLDSA_Q);
mld_assert_bound(vec2->coeffs, MLDSA_N, 0, MLDSA_Q);
mld_assert_bound(vec3->coeffs, MLDSA_N, 0, MLDSA_Q);
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(buf, sizeof(buf));
}
#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */
MLD_INTERNAL_API
void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a)
{
unsigned int i;
mld_assert_bound(a->coeffs, MLDSA_N, 0, 1 << 10);
for (i = 0; i < MLDSA_N / 4; ++i)
__loop__(
invariant(i <= MLDSA_N/4))
{
r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0) & 0xFF);
r[5 * i + 1] =
(uint8_t)(((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2)) &
0xFF);
r[5 * i + 2] =
(uint8_t)(((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4)) &
0xFF);
r[5 * i + 3] =
(uint8_t)(((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6)) &
0xFF);
r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2) & 0xFF);
}
}
MLD_INTERNAL_API
void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES])
{
unsigned int i;
for (i = 0; i < MLDSA_N / 4; ++i)
__loop__(
invariant(i <= MLDSA_N/4)
invariant(array_bound(r->coeffs, 0, i*4, 0, 1 << 10)))
{
r->coeffs[4 * i + 0] =
((a[5 * i + 0] >> 0) | ((int32_t)a[5 * i + 1] << 8)) & 0x3FF;
r->coeffs[4 * i + 1] =
((a[5 * i + 1] >> 2) | ((int32_t)a[5 * i + 2] << 6)) & 0x3FF;
r->coeffs[4 * i + 2] =
((a[5 * i + 2] >> 4) | ((int32_t)a[5 * i + 3] << 4)) & 0x3FF;
r->coeffs[4 * i + 3] =
((a[5 * i + 3] >> 6) | ((int32_t)a[5 * i + 4] << 2)) & 0x3FF;
}
mld_assert_bound(r->coeffs, MLDSA_N, 0, 1 << 10);
}
MLD_INTERNAL_API
void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a)
{
unsigned int i;
uint32_t t[8];
mld_assert_bound(a->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1,
(1 << (MLDSA_D - 1)) + 1);
for (i = 0; i < MLDSA_N / 8; ++i)
__loop__(
invariant(i <= MLDSA_N/8))
{
/* Safety: a->coeffs[i] <= (1 << (MLDSA_D - 1) as they are output of
* power2round, hence, these casts are safe. */
t[0] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0]);
t[1] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1]);
t[2] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2]);
t[3] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3]);
t[4] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4]);
t[5] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5]);
t[6] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6]);
t[7] = (uint32_t)((1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7]);
r[13 * i + 0] = (uint8_t)((t[0]) & 0xFF);
r[13 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF);
r[13 * i + 1] |= (uint8_t)((t[1] << 5) & 0xFF);
r[13 * i + 2] = (uint8_t)((t[1] >> 3) & 0xFF);
r[13 * i + 3] = (uint8_t)((t[1] >> 11) & 0xFF);
r[13 * i + 3] |= (uint8_t)((t[2] << 2) & 0xFF);
r[13 * i + 4] = (uint8_t)((t[2] >> 6) & 0xFF);
r[13 * i + 4] |= (uint8_t)((t[3] << 7) & 0xFF);
r[13 * i + 5] = (uint8_t)((t[3] >> 1) & 0xFF);
r[13 * i + 6] = (uint8_t)((t[3] >> 9) & 0xFF);
r[13 * i + 6] |= (uint8_t)((t[4] << 4) & 0xFF);
r[13 * i + 7] = (uint8_t)((t[4] >> 4) & 0xFF);
r[13 * i + 8] = (uint8_t)((t[4] >> 12) & 0xFF);
r[13 * i + 8] |= (uint8_t)((t[5] << 1) & 0xFF);
r[13 * i + 9] = (uint8_t)((t[5] >> 7) & 0xFF);
r[13 * i + 9] |= (uint8_t)((t[6] << 6) & 0xFF);
r[13 * i + 10] = (uint8_t)((t[6] >> 2) & 0xFF);
r[13 * i + 11] = (uint8_t)((t[6] >> 10) & 0xFF);
r[13 * i + 11] |= (uint8_t)((t[7] << 3) & 0xFF);
r[13 * i + 12] = (uint8_t)((t[7] >> 5) & 0xFF);
}
}
MLD_INTERNAL_API
void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES])
{
unsigned int i;
for (i = 0; i < MLDSA_N / 8; ++i)
__loop__(
invariant(i <= MLDSA_N/8)
invariant(array_bound(r->coeffs, 0, i*8, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)))
{
r->coeffs[8 * i + 0] = a[13 * i + 0];
r->coeffs[8 * i + 0] |= (int32_t)a[13 * i + 1] << 8;
r->coeffs[8 * i + 0] &= 0x1FFF;
r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5;
r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 2] << 3;
r->coeffs[8 * i + 1] |= (int32_t)a[13 * i + 3] << 11;
r->coeffs[8 * i + 1] &= 0x1FFF;
r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2;
r->coeffs[8 * i + 2] |= (int32_t)a[13 * i + 4] << 6;
r->coeffs[8 * i + 2] &= 0x1FFF;
r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7;
r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 5] << 1;
r->coeffs[8 * i + 3] |= (int32_t)a[13 * i + 6] << 9;
r->coeffs[8 * i + 3] &= 0x1FFF;
r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4;
r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 7] << 4;
r->coeffs[8 * i + 4] |= (int32_t)a[13 * i + 8] << 12;
r->coeffs[8 * i + 4] &= 0x1FFF;
r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1;
r->coeffs[8 * i + 5] |= (int32_t)a[13 * i + 9] << 7;
r->coeffs[8 * i + 5] &= 0x1FFF;
r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6;
r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 10] << 2;
r->coeffs[8 * i + 6] |= (int32_t)a[13 * i + 11] << 10;
r->coeffs[8 * i + 6] &= 0x1FFF;
r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3;
r->coeffs[8 * i + 7] |= (int32_t)a[13 * i + 12] << 5;
r->coeffs[8 * i + 7] &= 0x1FFF;
r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0];
r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1];
r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2];
r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3];
r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4];
r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5];
r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6];
r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7];
}
mld_assert_bound(r->coeffs, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1,
(1 << (MLDSA_D - 1)) + 1);
}
MLD_STATIC_TESTABLE uint32_t mld_poly_chknorm_c(const mld_poly *a, int32_t B)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX)
requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))
ensures(return_value == 0 || return_value == 0xFFFFFFFF)
ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B))
)
{
unsigned int i;
uint32_t t = 0;
mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,
MLD_REDUCE32_RANGE_MAX);
for (i = 0; i < MLDSA_N; ++i)
__loop__(
invariant(i <= MLDSA_N)
invariant(t == 0 || t == 0xFFFFFFFF)
invariant((t == 0) == array_abs_bound(a->coeffs, 0, i, B))
)
{
/*
* Since we know that -MLD_REDUCE32_RANGE_MAX <= a < MLD_REDUCE32_RANGE_MAX,
* and B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX, to check if
* -B < (a mod± MLDSA_Q) < B, it suffices to check if -B < a < B.
*
* We prove this to be true using the following CBMC assertions.
* a ==> b expressed as !a || b to also allow run-time assertion.
*/
mld_assert(a->coeffs[i] < B || a->coeffs[i] - MLDSA_Q <= -B);
mld_assert(a->coeffs[i] > -B || a->coeffs[i] + MLDSA_Q >= B);
/* Reference: Leaks which coefficient violates the bound via a conditional.
* We are more conservative to reduce the number of declassifications in
* constant-time testing.
*/
/* if (abs(a[i]) >= B) */
t |= mld_ct_cmask_neg_i32(B - 1 - mld_ct_abs_i32(a->coeffs[i]));
}
return t;
}
/* Reference: explicitly checks the bound B to be <= (MLDSA_Q - 1) / 8).
* This is unnecessary as it's always a compile-time constant.
* We instead model it as a precondition.
* Checking the bound is performed using a conditional arguing
* that it is okay to leak which coefficient violates the bound (while the
* coefficient itself must remain secret).
* We instead perform everything in constant-time.
* Also it is sufficient to check that it is smaller than
* MLDSA_Q - MLD_REDUCE32_RANGE_MAX > (MLDSA_Q - 1) / 8).
*/
MLD_INTERNAL_API
uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B)
{
#if defined(MLD_USE_NATIVE_POLY_CHKNORM)
int ret;
int success;
mld_assert_bound(a->coeffs, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,
MLD_REDUCE32_RANGE_MAX);
/* The native backend returns 0 if all coefficients are within the bound,
* 1 if at least one coefficient exceeds the bound, and
* -1 (MLD_NATIVE_FUNC_FALLBACK) if the platform does not have the
* required capabilities to run the native function.
*/
ret = mld_poly_chknorm_native(a->coeffs, B);
success = (ret != MLD_NATIVE_FUNC_FALLBACK);
/* Constant-time: It would be fine to leak the return value of chknorm
* entirely (as it is fine to leak if any coefficient exceeded the bound or
* not). However, it is cleaner to perform declassification in sign.c.
* Hence, here we only declassify if the native function returned
* MLD_NATIVE_FUNC_FALLBACK or not (which solely depends on system
* capabilities).
*/
MLD_CT_TESTING_DECLASSIFY(&success, sizeof(int));
if (success)
{
/* Convert 0 / 1 to 0 / 0xFFFFFFFF here */
return 0U - (uint32_t)ret;
}
#endif /* MLD_USE_NATIVE_POLY_CHKNORM */
return mld_poly_chknorm_c(a, B);
}
#else /* !MLD_CONFIG_MULTILEVEL_NO_SHARED */
MLD_EMPTY_CU(mld_poly)
#endif /* MLD_CONFIG_MULTILEVEL_NO_SHARED */
/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.
* Don't modify by hand -- this is auto-generated by scripts/autogen. */
#undef MLD_POLY_UNIFORM_NBLOCKS

View File

@@ -0,0 +1,393 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_POLY_H
#define MLD_POLY_H
#include <stdint.h>
#include "cbmc.h"
#include "common.h"
#include "reduce.h"
#include "rounding.h"
/* Absolute exclusive upper bound for the output of the forward NTT */
#define MLD_NTT_BOUND (9 * MLDSA_Q)
/* Absolute exclusive upper bound for the output of the inverse NTT*/
#define MLD_INTT_BOUND MLDSA_Q
typedef struct
{
int32_t coeffs[MLDSA_N];
} MLD_ALIGN mld_poly;
#define mld_poly_reduce MLD_NAMESPACE(poly_reduce)
/*************************************************
* Name: mld_poly_reduce
*
* Description: Inplace reduction of all coefficients of polynomial to
* representative in
*[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX].
*
* Arguments: - mld_poly *a: pointer to input/output polynomial
**************************************************/
MLD_INTERNAL_API
void mld_poly_reduce(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))
);
#define mld_poly_caddq MLD_NAMESPACE(poly_caddq)
/*************************************************
* Name: mld_poly_caddq
*
* Description: For all coefficients of in/out polynomial add MLDSA_Q if
* coefficient is negative.
*
* Arguments: - mld_poly *a: pointer to input/output polynomial
**************************************************/
MLD_INTERNAL_API
void mld_poly_caddq(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
);
#define mld_poly_add MLD_NAMESPACE(poly_add)
/*************************************************
* Name: mld_poly_add
*
* Description: Add polynomials. No modular reduction is performed.
*
* Arguments: - r: Pointer to input-output polynomial to be added to.
* - b: Pointer to input polynomial that should be added
* to r. Must be disjoint from r.
**************************************************/
/*
* NOTE: The reference implementation uses a 3-argument poly_add.
* We specialize to the accumulator form to avoid reasoning about aliasing.
*/
MLD_INTERNAL_API
void mld_poly_add(mld_poly *r, const mld_poly *b)
__contract__(
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX))
requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2]))
ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX))
ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN))
);
#define mld_poly_sub MLD_NAMESPACE(poly_sub)
/*************************************************
* Name: mld_poly_sub
*
* Description: Subtract polynomials. No modular reduction is
* performed.
*
* Arguments: - mld_poly *r: Pointer to input-output polynomial.
* - const mld_poly *b: Pointer to input polynomial that should be
* subtracted from r. Must be disjoint from r.
**************************************************/
/*
* NOTE: The reference implementation uses a 3-argument poly_sub.
* We specialize to the accumulator form to avoid reasoning about aliasing.
*/
MLD_INTERNAL_API
void mld_poly_sub(mld_poly *r, const mld_poly *b)
__contract__(
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q))
requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))
);
#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl)
/*************************************************
* Name: mld_poly_shiftl
*
* Description: Multiply polynomial by 2^MLDSA_D without modular reduction.
*Assumes input coefficients to be less than 2^{31-MLDSA_D} in absolute value.
*
* Arguments: - mld_poly *a: pointer to input/output polynomial
**************************************************/
MLD_INTERNAL_API
void mld_poly_shiftl(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
);
#define mld_poly_ntt MLD_NAMESPACE(poly_ntt)
/*************************************************
* Name: mld_poly_ntt
*
* Description: Inplace forward NTT. Coefficients can grow by
* 8*MLDSA_Q in absolute value.
*
* Arguments: - mld_poly *a: pointer to input/output polynomial
**************************************************/
MLD_INTERNAL_API
void mld_poly_ntt(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
);
#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont)
/*************************************************
* Name: mld_poly_invntt_tomont
*
* Description: Inplace inverse NTT and multiplication by 2^{32}.
* Input coefficients need to be less than MLDSA_Q in absolute
* value and output coefficients are bounded by
* MLD_INTT_BOUND.
*
* Arguments: - mld_poly *a: pointer to input/output polynomial
**************************************************/
MLD_INTERNAL_API
void mld_poly_invntt_tomont(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND))
);
#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery)
/*************************************************
* Name: mld_poly_pointwise_montgomery
*
* Description: Pointwise multiplication of polynomials in NTT domain
* representation and multiplication of resulting polynomial
* by 2^{-32}.
*
* Arguments: - mld_poly *c: pointer to output polynomial
* - const mld_poly *a: pointer to first input polynomial
* - const mld_poly *b: pointer to second input polynomial
**************************************************/
MLD_INTERNAL_API
void mld_poly_pointwise_montgomery(mld_poly *c, const mld_poly *a,
const mld_poly *b)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(memory_no_alias(c, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
assigns(memory_slice(c, sizeof(mld_poly)))
ensures(array_abs_bound(c->coeffs, 0, MLDSA_N, MLDSA_Q))
);
#define mld_poly_power2round MLD_NAMESPACE(poly_power2round)
/*************************************************
* Name: mld_poly_power2round
*
* Description: For all coefficients c of the input polynomial,
* compute c0, c1 such that c mod MLDSA_Q = c1*2^MLDSA_D + c0
* with -2^{MLDSA_D-1} < c0 <= 2^{MLDSA_D-1}. Assumes coefficients
*to be standard representatives.
*
* Arguments: - mld_poly *a1: pointer to output polynomial with coefficients
*c1
* - mld_poly *a0: pointer to output polynomial with coefficients
*c0
* - const mld_poly *a: pointer to input polynomial
**************************************************/
MLD_INTERNAL_API
void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a)
__contract__(
requires(memory_no_alias(a0, sizeof(mld_poly)))
requires(memory_no_alias(a1, sizeof(mld_poly)))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
assigns(memory_slice(a1, sizeof(mld_poly)))
assigns(memory_slice(a0, sizeof(mld_poly)))
ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))
ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))
);
#define mld_poly_uniform MLD_NAMESPACE(poly_uniform)
/*************************************************
* Name: mld_poly_uniform
*
* Description: Sample polynomial with uniformly random coefficients
* in [0,MLDSA_Q-1] by performing rejection sampling on the
* output stream of SHAKE128(seed|nonce)
*
* Arguments: - mld_poly *a: pointer to output polynomial
* - const uint8_t seed[]: byte array with seed of length
* MLDSA_SEEDBYTES and the packed 2-byte nonce
**************************************************/
MLD_INTERNAL_API
void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2])
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
);
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && !defined(MLD_CONFIG_REDUCE_RAM)
#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x)
/*************************************************
* Name: mld_poly_uniform_x4
*
* Description: Generate four polynomials using rejection sampling
* on (pseudo-)uniformly random bytes sampled from a seed.
*
* Arguments: - mld_poly *vec0, *vec1, *vec2, *vec3:
* Pointers to 4 polynomials to be sampled.
* - uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)]:
* Pointer consecutive array of seed buffers of size
* MLDSA_SEEDBYTES + 2 each, plus padding for alignment.
*
**************************************************/
MLD_INTERNAL_API
void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2,
mld_poly *vec3,
uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)])
__contract__(
requires(memory_no_alias(vec0, sizeof(mld_poly)))
requires(memory_no_alias(vec1, sizeof(mld_poly)))
requires(memory_no_alias(vec2, sizeof(mld_poly)))
requires(memory_no_alias(vec3, sizeof(mld_poly)))
requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)))
assigns(memory_slice(vec0, sizeof(mld_poly)))
assigns(memory_slice(vec1, sizeof(mld_poly)))
assigns(memory_slice(vec2, sizeof(mld_poly)))
assigns(memory_slice(vec3, sizeof(mld_poly)))
ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
);
#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY && !MLD_CONFIG_REDUCE_RAM */
#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack)
/*************************************************
* Name: mld_polyt1_pack
*
* Description: Bit-pack polynomial t1 with coefficients fitting in 10 bits.
* Input coefficients are assumed to be standard representatives.
*
* Arguments: - uint8_t *r: pointer to output byte array with at least
* MLDSA_POLYT1_PACKEDBYTES bytes
* - const mld_poly *a: pointer to input polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10))
assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES))
);
#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack)
/*************************************************
* Name: mld_polyt1_unpack
*
* Description: Unpack polynomial t1 with 10-bit coefficients.
* Output coefficients are standard representatives.
*
* Arguments: - mld_poly *r: pointer to output polynomial
* - const uint8_t *a: byte array with bit-packed polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10))
);
#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack)
/*************************************************
* Name: mld_polyt0_pack
*
* Description: Bit-pack polynomial t0 with coefficients in ]-2^{MLDSA_D-1},
* 2^{MLDSA_D-1}].
*
* Arguments: - uint8_t *r: pointer to output byte array with at least
* MLDSA_POLYT0_PACKEDBYTES bytes
* - const mld_poly *a: pointer to input polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))
assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES))
);
#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack)
/*************************************************
* Name: mld_polyt0_unpack
*
* Description: Unpack polynomial t0 with coefficients in ]-2^{MLDSA_D-1},
*2^{MLDSA_D-1}].
*
* Arguments: - mld_poly *r: pointer to output polynomial
* - const uint8_t *a: byte array with bit-packed polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))
);
#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm)
/*************************************************
* Name: mld_poly_chknorm
*
* Description: Check infinity norm of polynomial against given bound.
* Assumes input coefficients were reduced by mld_reduce32().
*
* Arguments: - const mld_poly *a: pointer to polynomial
* - int32_t B: norm bound
*
* Returns 0 if norm is strictly smaller than
* B <= (MLDSA_Q - MLD_REDUCE32_RANGE_MAX) and 0xFFFFFFFF otherwise.
*
* Specification: The definition of this FIPS-204 requires signed canonical
* reduction prior to applying the bounds check.
* However, `-B < (a mod± MLDSA_Q) < B` is equivalent to
* `-B < a < B` under the assumption that
* `B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX` (cf. the assertion in
* the code). Hence, the present spec and implementation are
* correct without reduction.
*
**************************************************/
MLD_INTERNAL_API
uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX)
requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))
ensures(return_value == 0 || return_value == 0xFFFFFFFF)
ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B))
);
#endif /* !MLD_POLY_H */

View File

@@ -0,0 +1,931 @@
/*
* Copyright (c) The mldsa-native project authors
* Copyright (c) The mlkem-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* References
* ==========
*
* - [FIPS204]
* FIPS 204 Module-Lattice-Based Digital Signature Standard
* National Institute of Standards and Technology
* https://csrc.nist.gov/pubs/fips/204/final
*
* - [REF]
* CRYSTALS-Dilithium reference implementation
* Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé
* https://github.com/pq-crystals/dilithium/tree/master/ref
*/
#include <stdint.h>
#include <string.h>
#include "ct.h"
#include "debug.h"
#include "poly_kl.h"
#include "rounding.h"
#include "symmetric.h"
/* Parameter set namespacing
* This is to facilitate building multiple instances
* of mldsa-native (e.g. with varying parameter sets)
* within a single compilation unit. */
#define mld_rej_eta MLD_ADD_PARAM_SET(mld_rej_eta)
#define mld_rej_eta_c MLD_ADD_PARAM_SET(mld_rej_eta_c)
#define mld_poly_decompose_c MLD_ADD_PARAM_SET(mld_poly_decompose_c)
#define mld_poly_use_hint_c MLD_ADD_PARAM_SET(mld_poly_use_hint_c)
#define mld_polyz_unpack_c MLD_ADD_PARAM_SET(mld_polyz_unpack_c)
/* End of parameter set namespacing */
MLD_STATIC_TESTABLE
void mld_poly_decompose_c(mld_poly *a1, mld_poly *a0)
__contract__(
requires(memory_no_alias(a1, sizeof(mld_poly)))
requires(memory_no_alias(a0, sizeof(mld_poly)))
requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
assigns(memory_slice(a1, sizeof(mld_poly)))
assigns(memory_slice(a0, sizeof(mld_poly)))
ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))
)
{
unsigned int i;
mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q);
for (i = 0; i < MLDSA_N; ++i)
__loop__(
assigns(i, memory_slice(a0, sizeof(mld_poly)), memory_slice(a1, sizeof(mld_poly)))
invariant(i <= MLDSA_N)
invariant(array_bound(a0->coeffs, i, MLDSA_N, 0, MLDSA_Q))
invariant(array_bound(a1->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
invariant(array_abs_bound(a0->coeffs, 0, i, MLDSA_GAMMA2+1))
)
{
mld_decompose(&a0->coeffs[i], &a1->coeffs[i], a0->coeffs[i]);
}
mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1);
mld_assert_bound(a1->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
}
MLD_INTERNAL_API
void mld_poly_decompose(mld_poly *a1, mld_poly *a0)
{
#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88) && MLD_CONFIG_PARAMETER_SET == 44
int ret;
mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q);
ret = mld_poly_decompose_88_native(a1->coeffs, a0->coeffs);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1);
mld_assert_bound(a1->coeffs, MLDSA_N, 0,
(MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
return;
}
#elif defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32) && \
(MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)
int ret;
mld_assert_bound(a0->coeffs, MLDSA_N, 0, MLDSA_Q);
ret = mld_poly_decompose_32_native(a1->coeffs, a0->coeffs);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_abs_bound(a0->coeffs, MLDSA_N, MLDSA_GAMMA2 + 1);
mld_assert_bound(a1->coeffs, MLDSA_N, 0,
(MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
return;
}
#endif /* !(MLD_USE_NATIVE_POLY_DECOMPOSE_88 && MLD_CONFIG_PARAMETER_SET == \
44) && MLD_USE_NATIVE_POLY_DECOMPOSE_32 && (MLD_CONFIG_PARAMETER_SET \
== 65 || MLD_CONFIG_PARAMETER_SET == 87) */
mld_poly_decompose_c(a1, a0);
}
MLD_INTERNAL_API
unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0,
const mld_poly *a1)
{
unsigned int i, s = 0;
for (i = 0; i < MLDSA_N; ++i)
__loop__(
invariant(i <= MLDSA_N)
invariant(s <= i)
invariant(array_bound(h->coeffs, 0, i, 0, 2))
)
{
const unsigned int hint_bit = mld_make_hint(a0->coeffs[i], a1->coeffs[i]);
h->coeffs[i] = (int32_t)hint_bit;
s += hint_bit;
}
mld_assert(s <= MLDSA_N);
mld_assert_bound(h->coeffs, MLDSA_N, 0, 2);
return s;
}
MLD_STATIC_TESTABLE void mld_poly_use_hint_c(mld_poly *b, const mld_poly *a,
const mld_poly *h)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(memory_no_alias(h, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))
assigns(memory_slice(b, sizeof(mld_poly)))
ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
)
{
unsigned int i;
mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);
mld_assert_bound(h->coeffs, MLDSA_N, 0, 2);
for (i = 0; i < MLDSA_N; ++i)
__loop__(
invariant(i <= MLDSA_N)
invariant(array_bound(b->coeffs, 0, i, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
)
{
b->coeffs[i] = mld_use_hint(a->coeffs[i], h->coeffs[i]);
}
mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
}
MLD_INTERNAL_API
void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h)
{
#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88) && MLD_CONFIG_PARAMETER_SET == 44
int ret;
mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);
mld_assert_bound(h->coeffs, MLDSA_N, 0, 2);
ret = mld_poly_use_hint_88_native(b->coeffs, a->coeffs, h->coeffs);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
return;
}
#elif defined(MLD_USE_NATIVE_POLY_USE_HINT_32) && \
(MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)
int ret;
mld_assert_bound(a->coeffs, MLDSA_N, 0, MLDSA_Q);
mld_assert_bound(h->coeffs, MLDSA_N, 0, 2);
ret = mld_poly_use_hint_32_native(b->coeffs, a->coeffs, h->coeffs);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_bound(b->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
return;
}
#endif /* !(MLD_USE_NATIVE_POLY_USE_HINT_88 && MLD_CONFIG_PARAMETER_SET == 44) \
&& MLD_USE_NATIVE_POLY_USE_HINT_32 && (MLD_CONFIG_PARAMETER_SET == \
65 || MLD_CONFIG_PARAMETER_SET == 87) */
mld_poly_use_hint_c(b, a, h);
}
/*************************************************
* Name: mld_rej_eta
*
* Description: Sample uniformly random coefficients in [-MLDSA_ETA, MLDSA_ETA]
*by performing rejection sampling on array of random bytes.
*
* Arguments: - int32_t *a: pointer to output array (allocated)
* - unsigned int target: requested number of coefficients to
*sample
* - unsigned int offset: number of coefficients already sampled
* - const uint8_t *buf: array of random bytes to sample from
* - unsigned int buflen: length of array of random bytes
*
* Returns number of sampled coefficients. Can be smaller than target if not
*enough random bytes were given.
**************************************************/
/* Reference: `mld_rej_eta()` in the reference implementation @[REF].
* - Our signature differs from the reference implementation
* in that it adds the offset and always expects the base of the
* target buffer. This avoids shifting the buffer base in the
* caller, which appears tricky to reason about. */
#if MLDSA_ETA == 2
/*
* Sampling 256 coefficients mod 15 using rejection sampling from 4 bits.
* Expected number of required bytes: (256 * (16/15))/2 = 136.5 bytes.
* We sample 1 block (=136 bytes) of SHAKE256_RATE output initially.
* Sampling 2 blocks initially results in slightly worse performance.
*/
#define MLD_POLY_UNIFORM_ETA_NBLOCKS 1
#elif MLDSA_ETA == 4
/*
* Sampling 256 coefficients mod 9 using rejection sampling from 4 bits.
* Expected number of required bytes: (256 * (16/9))/2 = 227.5 bytes.
* We sample 2 blocks (=272 bytes) of SHAKE256_RATE output initially.
*/
#define MLD_POLY_UNIFORM_ETA_NBLOCKS 2
#else /* MLDSA_ETA == 4 */
#error "Invalid value of MLDSA_ETA"
#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */
MLD_STATIC_TESTABLE unsigned int mld_rej_eta_c(int32_t *a, unsigned int target,
unsigned int offset,
const uint8_t *buf,
unsigned int buflen)
__contract__(
requires(offset <= target && target <= MLDSA_N)
requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES))
requires(memory_no_alias(a, sizeof(int32_t) * target))
requires(memory_no_alias(buf, buflen))
requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1))
assigns(memory_slice(a, sizeof(int32_t) * target))
ensures(offset <= return_value && return_value <= target)
ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1))
)
{
unsigned int ctr, pos;
int t_valid;
uint32_t t0, t1;
mld_assert_abs_bound(a, offset, MLDSA_ETA + 1);
ctr = offset;
pos = 0;
while (ctr < target && pos < buflen)
__loop__(
invariant(offset <= ctr && ctr <= target && pos <= buflen)
invariant(array_abs_bound(a, 0, ctr, MLDSA_ETA + 1))
)
{
t0 = buf[pos] & 0x0F;
t1 = buf[pos++] >> 4;
/* Constant time: The inputs and outputs to the rejection sampling are
* secret. However, it is fine to leak which coefficients have been
* rejected. For constant-time testing, we declassify the result of
* the comparison.
*/
#if MLDSA_ETA == 2
t_valid = t0 < 15;
MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int));
if (t_valid) /* t0 < 15 */
{
t0 = t0 - (205 * t0 >> 10) * 5;
a[ctr++] = 2 - (int32_t)t0;
}
t_valid = t1 < 15;
MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int));
if (t_valid && ctr < target) /* t1 < 15 */
{
t1 = t1 - (205 * t1 >> 10) * 5;
a[ctr++] = 2 - (int32_t)t1;
}
#elif MLDSA_ETA == 4
t_valid = t0 < 9;
MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int));
if (t_valid) /* t0 < 9 */
{
a[ctr++] = 4 - (int32_t)t0;
}
t_valid = t1 < 9; /* t1 < 9 */
MLD_CT_TESTING_DECLASSIFY(&t_valid, sizeof(int));
if (t_valid && ctr < target)
{
a[ctr++] = 4 - (int32_t)t1;
}
#else /* MLDSA_ETA == 4 */
#error "Invalid value of MLDSA_ETA"
#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */
}
mld_assert_abs_bound(a, ctr, MLDSA_ETA + 1);
return ctr;
}
static unsigned int mld_rej_eta(int32_t *a, unsigned int target,
unsigned int offset, const uint8_t *buf,
unsigned int buflen)
__contract__(
requires(offset <= target && target <= MLDSA_N)
requires(buflen <= (MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES))
requires(memory_no_alias(a, sizeof(int32_t) * target))
requires(memory_no_alias(buf, buflen))
requires(array_abs_bound(a, 0, offset, MLDSA_ETA + 1))
assigns(memory_slice(a, sizeof(int32_t) * target))
ensures(offset <= return_value && return_value <= target)
ensures(array_abs_bound(a, 0, return_value, MLDSA_ETA + 1))
)
{
#if MLDSA_ETA == 2 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2)
int ret;
mld_assert_abs_bound(a, offset, MLDSA_ETA + 1);
if (offset == 0)
{
ret = mld_rej_uniform_eta2_native(a, target, buf, buflen);
if (ret != MLD_NATIVE_FUNC_FALLBACK)
{
unsigned res = (unsigned)ret;
mld_assert_abs_bound(a, res, MLDSA_ETA + 1);
return res;
}
}
#elif MLDSA_ETA == 4 && defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4)
int ret;
mld_assert_abs_bound(a, offset, MLDSA_ETA + 1);
if (offset == 0)
{
ret = mld_rej_uniform_eta4_native(a, target, buf, buflen);
if (ret != MLD_NATIVE_FUNC_FALLBACK)
{
unsigned res = (unsigned)ret;
mld_assert_abs_bound(a, res, MLDSA_ETA + 1);
return res;
}
}
#endif /* !(MLDSA_ETA == 2 && MLD_USE_NATIVE_REJ_UNIFORM_ETA2) && MLDSA_ETA == \
4 && MLD_USE_NATIVE_REJ_UNIFORM_ETA4 */
return mld_rej_eta_c(a, target, offset, buf, buflen);
}
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
MLD_INTERNAL_API
void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2,
mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES],
uint8_t nonce0, uint8_t nonce1, uint8_t nonce2,
uint8_t nonce3)
{
/* Temporary buffers for XOF output before rejection sampling */
MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_ETA_NBLOCKS *
MLD_STREAM256_BLOCKBYTES)];
MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)];
/* Tracks the number of coefficients we have already sampled */
unsigned ctr[4];
mld_xof256_x4_ctx state;
unsigned buflen;
mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES);
mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES);
mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES);
mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES);
extseed[0][MLDSA_CRHBYTES] = nonce0;
extseed[1][MLDSA_CRHBYTES] = nonce1;
extseed[2][MLDSA_CRHBYTES] = nonce2;
extseed[3][MLDSA_CRHBYTES] = nonce3;
extseed[0][MLDSA_CRHBYTES + 1] = 0;
extseed[1][MLDSA_CRHBYTES + 1] = 0;
extseed[2][MLDSA_CRHBYTES + 1] = 0;
extseed[3][MLDSA_CRHBYTES + 1] = 0;
mld_xof256_x4_init(&state);
mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2);
/*
* Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS.
* This should generate the coefficients with high probability.
*/
mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state);
buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES;
ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, 0, buf[0], buflen);
ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, 0, buf[1], buflen);
ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, 0, buf[2], buflen);
ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, 0, buf[3], buflen);
/*
* So long as not all entries have been generated, squeeze
* one more block at a time until we're done.
*/
buflen = MLD_STREAM256_BLOCKBYTES;
while (ctr[0] < MLDSA_N || ctr[1] < MLDSA_N || ctr[2] < MLDSA_N ||
ctr[3] < MLDSA_N)
__loop__(
assigns(ctr, state, memory_slice(r0, sizeof(mld_poly)),
memory_slice(r1, sizeof(mld_poly)), memory_slice(r2, sizeof(mld_poly)),
memory_slice(r3, sizeof(mld_poly)), object_whole(buf[0]),
object_whole(buf[1]), object_whole(buf[2]),
object_whole(buf[3]))
invariant(ctr[0] <= MLDSA_N && ctr[1] <= MLDSA_N)
invariant(ctr[2] <= MLDSA_N && ctr[3] <= MLDSA_N)
invariant(array_abs_bound(r0->coeffs, 0, ctr[0], MLDSA_ETA + 1))
invariant(array_abs_bound(r1->coeffs, 0, ctr[1], MLDSA_ETA + 1))
invariant(array_abs_bound(r2->coeffs, 0, ctr[2], MLDSA_ETA + 1))
invariant(array_abs_bound(r3->coeffs, 0, ctr[3], MLDSA_ETA + 1)))
{
mld_xof256_x4_squeezeblocks(buf, 1, &state);
ctr[0] = mld_rej_eta(r0->coeffs, MLDSA_N, ctr[0], buf[0], buflen);
ctr[1] = mld_rej_eta(r1->coeffs, MLDSA_N, ctr[1], buf[1], buflen);
ctr[2] = mld_rej_eta(r2->coeffs, MLDSA_N, ctr[2], buf[2], buflen);
ctr[3] = mld_rej_eta(r3->coeffs, MLDSA_N, ctr[3], buf[3], buflen);
}
mld_xof256_x4_release(&state);
mld_assert_abs_bound(r0->coeffs, MLDSA_N, MLDSA_ETA + 1);
mld_assert_abs_bound(r1->coeffs, MLDSA_N, MLDSA_ETA + 1);
mld_assert_abs_bound(r2->coeffs, MLDSA_N, MLDSA_ETA + 1);
mld_assert_abs_bound(r3->coeffs, MLDSA_N, MLDSA_ETA + 1);
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(buf, sizeof(buf));
mld_zeroize(extseed, sizeof(extseed));
}
#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */
MLD_INTERNAL_API
void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES],
uint8_t nonce)
{
/* Temporary buffer for XOF output before rejection sampling */
MLD_ALIGN uint8_t
buf[MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES];
MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2];
/* Tracks the number of coefficients we have already sampled */
unsigned ctr;
mld_xof256_ctx state;
unsigned buflen;
mld_memcpy(extseed, seed, MLDSA_CRHBYTES);
extseed[MLDSA_CRHBYTES] = nonce;
extseed[MLDSA_CRHBYTES + 1] = 0;
mld_xof256_init(&state);
mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2);
/*
* Initially, squeeze heuristic number of MLD_POLY_UNIFORM_ETA_NBLOCKS.
* This should generate the coefficients with high probability.
*/
mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_ETA_NBLOCKS, &state);
buflen = MLD_POLY_UNIFORM_ETA_NBLOCKS * MLD_STREAM256_BLOCKBYTES;
ctr = mld_rej_eta(r->coeffs, MLDSA_N, 0, buf, buflen);
/*
* So long as not all entries have been generated, squeeze
* one more block at a time until we're done.
*/
buflen = MLD_STREAM256_BLOCKBYTES;
while (ctr < MLDSA_N)
__loop__(
assigns(ctr, object_whole(&state),
object_whole(buf), memory_slice(r, sizeof(mld_poly)))
invariant(ctr <= MLDSA_N)
invariant(state.pos <= SHAKE256_RATE)
invariant(array_abs_bound(r->coeffs, 0, ctr, MLDSA_ETA + 1)))
{
mld_xof256_squeezeblocks(buf, 1, &state);
ctr = mld_rej_eta(r->coeffs, MLDSA_N, ctr, buf, buflen);
}
mld_xof256_release(&state);
mld_assert_abs_bound(r->coeffs, MLDSA_N, MLDSA_ETA + 1);
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(buf, sizeof(buf));
mld_zeroize(extseed, sizeof(extseed));
}
#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */
#define MLD_POLY_UNIFORM_GAMMA1_NBLOCKS \
((MLDSA_POLYZ_PACKEDBYTES + MLD_STREAM256_BLOCKBYTES - 1) / \
MLD_STREAM256_BLOCKBYTES)
#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
MLD_INTERNAL_API
void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES],
uint16_t nonce)
{
MLD_ALIGN uint8_t
buf[MLD_POLY_UNIFORM_GAMMA1_NBLOCKS * MLD_STREAM256_BLOCKBYTES];
MLD_ALIGN uint8_t extseed[MLDSA_CRHBYTES + 2];
mld_xof256_ctx state;
mld_memcpy(extseed, seed, MLDSA_CRHBYTES);
extseed[MLDSA_CRHBYTES] = (uint8_t)(nonce & 0xFF);
extseed[MLDSA_CRHBYTES + 1] = (uint8_t)(nonce >> 8);
mld_xof256_init(&state);
mld_xof256_absorb_once(&state, extseed, MLDSA_CRHBYTES + 2);
mld_xof256_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state);
mld_polyz_unpack(a, buf);
mld_xof256_release(&state);
mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(buf, sizeof(buf));
mld_zeroize(extseed, sizeof(extseed));
}
#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
MLD_INTERNAL_API
void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2,
mld_poly *r3,
const uint8_t seed[MLDSA_CRHBYTES],
uint16_t nonce0, uint16_t nonce1,
uint16_t nonce2, uint16_t nonce3)
{
/* Temporary buffers for XOF output before rejection sampling */
MLD_ALIGN uint8_t buf[4][MLD_ALIGN_UP(MLD_POLY_UNIFORM_GAMMA1_NBLOCKS *
MLD_STREAM256_BLOCKBYTES)];
MLD_ALIGN uint8_t extseed[4][MLD_ALIGN_UP(MLDSA_CRHBYTES + 2)];
/* Tracks the number of coefficients we have already sampled */
mld_xof256_x4_ctx state;
mld_memcpy(extseed[0], seed, MLDSA_CRHBYTES);
mld_memcpy(extseed[1], seed, MLDSA_CRHBYTES);
mld_memcpy(extseed[2], seed, MLDSA_CRHBYTES);
mld_memcpy(extseed[3], seed, MLDSA_CRHBYTES);
extseed[0][MLDSA_CRHBYTES] = (uint8_t)(nonce0 & 0xFF);
extseed[1][MLDSA_CRHBYTES] = (uint8_t)(nonce1 & 0xFF);
extseed[2][MLDSA_CRHBYTES] = (uint8_t)(nonce2 & 0xFF);
extseed[3][MLDSA_CRHBYTES] = (uint8_t)(nonce3 & 0xFF);
extseed[0][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce0 >> 8);
extseed[1][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce1 >> 8);
extseed[2][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce2 >> 8);
extseed[3][MLDSA_CRHBYTES + 1] = (uint8_t)(nonce3 >> 8);
mld_xof256_x4_init(&state);
mld_xof256_x4_absorb(&state, extseed, MLDSA_CRHBYTES + 2);
mld_xof256_x4_squeezeblocks(buf, MLD_POLY_UNIFORM_GAMMA1_NBLOCKS, &state);
mld_polyz_unpack(r0, buf[0]);
mld_polyz_unpack(r1, buf[1]);
mld_polyz_unpack(r2, buf[2]);
mld_polyz_unpack(r3, buf[3]);
mld_xof256_x4_release(&state);
mld_assert_bound(r0->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
mld_assert_bound(r1->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
mld_assert_bound(r2->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
mld_assert_bound(r3->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(buf, sizeof(buf));
mld_zeroize(extseed, sizeof(extseed));
}
#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */
MLD_INTERNAL_API
void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES])
{
unsigned int i, j, pos;
uint64_t signs;
uint64_t offset;
MLD_ALIGN uint8_t buf[SHAKE256_RATE];
mld_shake256ctx state;
mld_shake256_init(&state);
mld_shake256_absorb(&state, seed, MLDSA_CTILDEBYTES);
mld_shake256_finalize(&state);
mld_shake256_squeeze(buf, SHAKE256_RATE, &state);
/* Convert the first 8 bytes of buf[] into an unsigned 64-bit value. */
/* Each bit of that dictates the sign of the resulting challenge value */
signs = 0;
for (i = 0; i < 8; ++i)
__loop__(
assigns(i, signs)
invariant(i <= 8)
)
{
signs |= (uint64_t)buf[i] << 8 * i;
}
pos = 8;
mld_memset(c, 0, sizeof(mld_poly));
for (i = MLDSA_N - MLDSA_TAU; i < MLDSA_N; ++i)
__loop__(
assigns(i, j, object_whole(buf), state, pos, memory_slice(c, sizeof(mld_poly)), signs)
invariant(i >= MLDSA_N - MLDSA_TAU)
invariant(i <= MLDSA_N)
invariant(pos >= 1)
invariant(pos <= SHAKE256_RATE)
invariant(array_bound(c->coeffs, 0, MLDSA_N, -1, 2))
invariant(state.pos <= SHAKE256_RATE)
)
{
do
__loop__(
assigns(j, object_whole(buf), state, pos)
invariant(state.pos <= SHAKE256_RATE)
)
{
if (pos >= SHAKE256_RATE)
{
mld_shake256_squeeze(buf, SHAKE256_RATE, &state);
pos = 0;
}
j = buf[pos++];
} while (j > i);
c->coeffs[i] = c->coeffs[j];
/* Reference: Compute coefficent value here in two steps to */
/* mixinf unsigned and signed arithmetic with implicit */
/* conversions, and so that CBMC can keep track of ranges */
/* to complete type-safety proof here. */
/* The least-significant bit of signs tells us if we want -1 or +1 */
offset = 2 * (signs & 1);
/* offset has value 0 or 2 here, so (1 - (int32_t) offset) has
* value -1 or +1 */
c->coeffs[j] = 1 - (int32_t)offset;
/* Move to the next bit of signs for next time */
signs >>= 1;
}
mld_assert_bound(c->coeffs, MLDSA_N, -1, 2);
mld_shake256_release(&state);
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(buf, sizeof(buf));
mld_zeroize(&signs, sizeof(signs));
}
MLD_INTERNAL_API
void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a)
{
unsigned int i;
uint8_t t[8];
mld_assert_abs_bound(a->coeffs, MLDSA_N, MLDSA_ETA + 1);
#if MLDSA_ETA == 2
for (i = 0; i < MLDSA_N / 8; ++i)
__loop__(
invariant(i <= MLDSA_N/8))
{
/* The casts are safe since we assume that the coefficients
* of a are <= MLDSA_ETA in absolute value. */
t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 0]);
t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 1]);
t[2] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 2]);
t[3] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 3]);
t[4] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 4]);
t[5] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 5]);
t[6] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 6]);
t[7] = (uint8_t)(MLDSA_ETA - a->coeffs[8 * i + 7]);
r[3 * i + 0] = (uint8_t)(((t[0] >> 0) | (t[1] << 3) | (t[2] << 6)) & 0xFF);
r[3 * i + 1] =
(uint8_t)(((t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7)) &
0xFF);
r[3 * i + 2] = (uint8_t)(((t[5] >> 1) | (t[6] << 2) | (t[7] << 5)) & 0xFF);
}
#elif MLDSA_ETA == 4
for (i = 0; i < MLDSA_N / 2; ++i)
__loop__(
invariant(i <= MLDSA_N/2))
{
/* The casts are safe since we assume that the coefficients
* of a are <= MLDSA_ETA in absolute value. */
t[0] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 0]);
t[1] = (uint8_t)(MLDSA_ETA - a->coeffs[2 * i + 1]);
r[i] = (uint8_t)(t[0] | (t[1] << 4));
}
#else /* MLDSA_ETA == 4 */
#error "Invalid value of MLDSA_ETA"
#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */
}
void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES])
{
unsigned int i;
#if MLDSA_ETA == 2
for (i = 0; i < MLDSA_N / 8; ++i)
__loop__(
invariant(i <= MLDSA_N/8)
invariant(array_bound(r->coeffs, 0, i*8, -5, MLDSA_ETA + 1)))
{
r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7;
r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7;
r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7;
r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7;
r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7;
r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7;
r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7;
r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7;
r->coeffs[8 * i + 0] = MLDSA_ETA - r->coeffs[8 * i + 0];
r->coeffs[8 * i + 1] = MLDSA_ETA - r->coeffs[8 * i + 1];
r->coeffs[8 * i + 2] = MLDSA_ETA - r->coeffs[8 * i + 2];
r->coeffs[8 * i + 3] = MLDSA_ETA - r->coeffs[8 * i + 3];
r->coeffs[8 * i + 4] = MLDSA_ETA - r->coeffs[8 * i + 4];
r->coeffs[8 * i + 5] = MLDSA_ETA - r->coeffs[8 * i + 5];
r->coeffs[8 * i + 6] = MLDSA_ETA - r->coeffs[8 * i + 6];
r->coeffs[8 * i + 7] = MLDSA_ETA - r->coeffs[8 * i + 7];
}
#elif MLDSA_ETA == 4
for (i = 0; i < MLDSA_N / 2; ++i)
__loop__(
invariant(i <= MLDSA_N/2)
invariant(array_bound(r->coeffs, 0, i*2, -11, MLDSA_ETA + 1)))
{
r->coeffs[2 * i + 0] = a[i] & 0x0F;
r->coeffs[2 * i + 1] = a[i] >> 4;
r->coeffs[2 * i + 0] = MLDSA_ETA - r->coeffs[2 * i + 0];
r->coeffs[2 * i + 1] = MLDSA_ETA - r->coeffs[2 * i + 1];
}
#else /* MLDSA_ETA == 4 */
#error "Invalid value of MLDSA_ETA"
#endif /* MLDSA_ETA != 2 && MLDSA_ETA != 4 */
mld_assert_bound(r->coeffs, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND,
MLDSA_ETA + 1);
}
MLD_INTERNAL_API
void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a)
{
unsigned int i;
uint32_t t[4];
mld_assert_bound(a->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
#if MLD_CONFIG_PARAMETER_SET == 44
for (i = 0; i < MLDSA_N / 4; ++i)
__loop__(
invariant(i <= MLDSA_N/4))
{
/* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */
t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 0]);
t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 1]);
t[2] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 2]);
t[3] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[4 * i + 3]);
r[9 * i + 0] = (uint8_t)((t[0]) & 0xFF);
r[9 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF);
r[9 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF);
r[9 * i + 2] |= (uint8_t)((t[1] << 2) & 0xFF);
r[9 * i + 3] = (uint8_t)((t[1] >> 6) & 0xFF);
r[9 * i + 4] = (uint8_t)((t[1] >> 14) & 0xFF);
r[9 * i + 4] |= (uint8_t)((t[2] << 4) & 0xFF);
r[9 * i + 5] = (uint8_t)((t[2] >> 4) & 0xFF);
r[9 * i + 6] = (uint8_t)((t[2] >> 12) & 0xFF);
r[9 * i + 6] |= (uint8_t)((t[3] << 6) & 0xFF);
r[9 * i + 7] = (uint8_t)((t[3] >> 2) & 0xFF);
r[9 * i + 8] = (uint8_t)((t[3] >> 10) & 0xFF);
}
#else /* MLD_CONFIG_PARAMETER_SET == 44 */
for (i = 0; i < MLDSA_N / 2; ++i)
__loop__(
invariant(i <= MLDSA_N/2))
{
/* Safety: a->coeffs[i] <= MLDSA_GAMMA1, hence, these casts are safe. */
t[0] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 0]);
t[1] = (uint32_t)(MLDSA_GAMMA1 - a->coeffs[2 * i + 1]);
r[5 * i + 0] = (uint8_t)((t[0]) & 0xFF);
r[5 * i + 1] = (uint8_t)((t[0] >> 8) & 0xFF);
r[5 * i + 2] = (uint8_t)((t[0] >> 16) & 0xFF);
r[5 * i + 2] |= (uint8_t)((t[1] << 4) & 0xFF);
r[5 * i + 3] = (uint8_t)((t[1] >> 4) & 0xFF);
r[5 * i + 4] = (uint8_t)((t[1] >> 12) & 0xFF);
}
#endif /* MLD_CONFIG_PARAMETER_SET != 44 */
}
MLD_STATIC_TESTABLE void mld_polyz_unpack_c(
mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
)
{
unsigned int i;
#if MLD_CONFIG_PARAMETER_SET == 44
for (i = 0; i < MLDSA_N / 4; ++i)
__loop__(
invariant(i <= MLDSA_N/4)
invariant(array_bound(r->coeffs, 0, i*4, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))
{
r->coeffs[4 * i + 0] = a[9 * i + 0];
r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8;
r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 2] << 16;
r->coeffs[4 * i + 0] &= 0x3FFFF;
r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2;
r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 3] << 6;
r->coeffs[4 * i + 1] |= (int32_t)a[9 * i + 4] << 14;
r->coeffs[4 * i + 1] &= 0x3FFFF;
r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4;
r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 5] << 4;
r->coeffs[4 * i + 2] |= (int32_t)a[9 * i + 6] << 12;
r->coeffs[4 * i + 2] &= 0x3FFFF;
r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6;
r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 7] << 2;
r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10;
r->coeffs[4 * i + 3] &= 0x3FFFF;
r->coeffs[4 * i + 0] = MLDSA_GAMMA1 - r->coeffs[4 * i + 0];
r->coeffs[4 * i + 1] = MLDSA_GAMMA1 - r->coeffs[4 * i + 1];
r->coeffs[4 * i + 2] = MLDSA_GAMMA1 - r->coeffs[4 * i + 2];
r->coeffs[4 * i + 3] = MLDSA_GAMMA1 - r->coeffs[4 * i + 3];
}
#else /* MLD_CONFIG_PARAMETER_SET == 44 */
for (i = 0; i < MLDSA_N / 2; ++i)
__loop__(
invariant(i <= MLDSA_N/2)
invariant(array_bound(r->coeffs, 0, i*2, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))
{
r->coeffs[2 * i + 0] = a[5 * i + 0];
r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8;
r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 2] << 16;
r->coeffs[2 * i + 0] &= 0xFFFFF;
r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4;
r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 3] << 4;
r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12;
/* r->coeffs[2*i+1] &= 0xFFFFF; */ /* No effect, since we're anyway at 20
bits */
r->coeffs[2 * i + 0] = MLDSA_GAMMA1 - r->coeffs[2 * i + 0];
r->coeffs[2 * i + 1] = MLDSA_GAMMA1 - r->coeffs[2 * i + 1];
}
#endif /* MLD_CONFIG_PARAMETER_SET != 44 */
mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
}
MLD_INTERNAL_API
void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES])
{
#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17) && MLD_CONFIG_PARAMETER_SET == 44
int ret;
ret = mld_polyz_unpack_17_native(r->coeffs, a);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
return;
}
#elif defined(MLD_USE_NATIVE_POLYZ_UNPACK_19) && \
(MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)
int ret;
ret = mld_polyz_unpack_19_native(r->coeffs, a);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_bound(r->coeffs, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1);
return;
}
#endif /* !(MLD_USE_NATIVE_POLYZ_UNPACK_17 && MLD_CONFIG_PARAMETER_SET == 44) \
&& MLD_USE_NATIVE_POLYZ_UNPACK_19 && (MLD_CONFIG_PARAMETER_SET == 65 \
|| MLD_CONFIG_PARAMETER_SET == 87) */
mld_polyz_unpack_c(r, a);
}
MLD_INTERNAL_API
void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a)
{
unsigned int i;
mld_assert_bound(a->coeffs, MLDSA_N, 0, (MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
#if MLD_CONFIG_PARAMETER_SET == 44
for (i = 0; i < MLDSA_N / 4; ++i)
__loop__(
invariant(i <= MLDSA_N/4))
{
r[3 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0]) & 0xFF);
r[3 * i + 0] |= (uint8_t)((a->coeffs[4 * i + 1] << 6) & 0xFF);
r[3 * i + 1] = (uint8_t)((a->coeffs[4 * i + 1] >> 2) & 0xFF);
r[3 * i + 1] |= (uint8_t)((a->coeffs[4 * i + 2] << 4) & 0xFF);
r[3 * i + 2] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) & 0xFF);
r[3 * i + 2] |= (uint8_t)((a->coeffs[4 * i + 3] << 2) & 0xFF);
}
#else /* MLD_CONFIG_PARAMETER_SET == 44 */
for (i = 0; i < MLDSA_N / 2; ++i)
__loop__(
invariant(i <= MLDSA_N/2))
{
r[i] =
(uint8_t)((a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4)) & 0xFF);
}
#endif /* MLD_CONFIG_PARAMETER_SET != 44 */
}
/* To facilitate single-compilation-unit (SCU) builds, undefine all macros. */
/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.
* Don't modify by hand -- this is auto-generated by scripts/autogen. */
#undef mld_rej_eta
#undef mld_rej_eta_c
#undef mld_poly_decompose_c
#undef mld_poly_use_hint_c
#undef mld_polyz_unpack_c
#undef MLD_POLY_UNIFORM_ETA_NBLOCKS
#undef MLD_POLY_UNIFORM_ETA_NBLOCKS
#undef MLD_POLY_UNIFORM_GAMMA1_NBLOCKS

View File

@@ -0,0 +1,359 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_POLY_KL_H
#define MLD_POLY_KL_H
#include "cbmc.h"
#include "common.h"
#include "poly.h"
#define mld_poly_decompose MLD_NAMESPACE_KL(poly_decompose)
/*************************************************
* Name: mld_poly_decompose
*
* Description: For all coefficients c of the input polynomial,
* compute high and low bits c0, c1 such c mod MLDSA_Q = c1*ALPHA +
* c0 with -ALPHA/2 < c0 <= ALPHA/2 except
* c1 = (MLDSA_Q-1)/ALPHA where we set
* c1 = 0 and -ALPHA/2 <= c0 = c mod MLDSA_Q - MLDSA_Q < 0.
* Assumes coefficients to be standard representatives.
*
* Arguments: - mld_poly *a1: pointer to output polynomial with coefficients
* c1
* - mld_poly *a0: pointer to input/output polynomial. Output
* polynomial has coefficients c0
*
* Reference: The reference implementation has the input polynomial as a
* separate argument that may be aliased with either of the outputs.
* Removing the aliasing eases CBMC proofs.
*
**************************************************/
MLD_INTERNAL_API
void mld_poly_decompose(mld_poly *a1, mld_poly *a0)
__contract__(
requires(memory_no_alias(a1, sizeof(mld_poly)))
requires(memory_no_alias(a0, sizeof(mld_poly)))
requires(array_bound(a0->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
assigns(memory_slice(a1, sizeof(mld_poly)))
assigns(memory_slice(a0, sizeof(mld_poly)))
ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
ensures(array_abs_bound(a0->coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1))
);
#define mld_poly_make_hint MLD_NAMESPACE_KL(poly_make_hint)
/*************************************************
* Name: mld_poly_make_hint
*
* Description: Compute hint polynomial. The coefficients of which indicate
* whether the low bits of the corresponding coefficient of
* the input polynomial overflow into the high bits.
*
* Arguments: - mld_poly *h: pointer to output hint polynomial
* - const mld_poly *a0: pointer to low part of input polynomial
* - const mld_poly *a1: pointer to high part of input polynomial
*
* Returns number of 1 bits.
**************************************************/
MLD_INTERNAL_API
unsigned int mld_poly_make_hint(mld_poly *h, const mld_poly *a0,
const mld_poly *a1)
__contract__(
requires(memory_no_alias(h, sizeof(mld_poly)))
requires(memory_no_alias(a0, sizeof(mld_poly)))
requires(memory_no_alias(a1, sizeof(mld_poly)))
assigns(memory_slice(h, sizeof(mld_poly)))
ensures(return_value <= MLDSA_N)
ensures(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))
);
#define mld_poly_use_hint MLD_NAMESPACE_KL(poly_use_hint)
/*************************************************
* Name: mld_poly_use_hint
*
* Description: Use hint polynomial to correct the high bits of a polynomial.
*
* Arguments: - mld_poly *b: pointer to output polynomial with corrected high
*bits
* - const mld_poly *a: pointer to input polynomial
* - const mld_poly *h: pointer to input hint polynomial
**************************************************/
MLD_INTERNAL_API
void mld_poly_use_hint(mld_poly *b, const mld_poly *a, const mld_poly *h)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(memory_no_alias(h, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
requires(array_bound(h->coeffs, 0, MLDSA_N, 0, 2))
assigns(memory_slice(b, sizeof(mld_poly)))
ensures(array_bound(b->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
);
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
#define mld_poly_uniform_eta_4x MLD_NAMESPACE_KL(poly_uniform_eta_4x)
/*************************************************
* Name: mld_poly_uniform_eta
*
* Description: Sample four polynomials with uniformly random coefficients
* in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on
* the output stream from SHAKE256(seed|nonce_i)
*
* Arguments: - mld_poly *r0: pointer to first output polynomial
* - mld_poly *r1: pointer to second output polynomial
* - mld_poly *r2: pointer to third output polynomial
* - mld_poly *r3: pointer to fourth output polynomial
* - const uint8_t seed[]: byte array with seed of length
* MLDSA_CRHBYTES
* - uint8_t nonce0: first nonce
* - uint8_t nonce1: second nonce
* - uint8_t nonce2: third nonce
* - uint8_t nonce3: fourth nonce
**************************************************/
MLD_INTERNAL_API
void mld_poly_uniform_eta_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2,
mld_poly *r3, const uint8_t seed[MLDSA_CRHBYTES],
uint8_t nonce0, uint8_t nonce1, uint8_t nonce2,
uint8_t nonce3)
__contract__(
requires(memory_no_alias(r0, sizeof(mld_poly)))
requires(memory_no_alias(r1, sizeof(mld_poly)))
requires(memory_no_alias(r2, sizeof(mld_poly)))
requires(memory_no_alias(r3, sizeof(mld_poly)))
requires(memory_no_alias(seed, MLDSA_CRHBYTES))
assigns(memory_slice(r0, sizeof(mld_poly)))
assigns(memory_slice(r1, sizeof(mld_poly)))
assigns(memory_slice(r2, sizeof(mld_poly)))
assigns(memory_slice(r3, sizeof(mld_poly)))
ensures(array_abs_bound(r0->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))
ensures(array_abs_bound(r1->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))
ensures(array_abs_bound(r2->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))
ensures(array_abs_bound(r3->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))
);
#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */
#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
#define mld_poly_uniform_eta MLD_NAMESPACE_KL(poly_uniform_eta)
/*************************************************
* Name: mld_poly_uniform_eta
*
* Description: Sample polynomial with uniformly random coefficients
* in [-MLDSA_ETA,MLDSA_ETA] by performing rejection sampling on
* the output stream from SHAKE256(seed|nonce)
*
* Arguments: - mld_poly *r: pointer to output polynomial
* - const uint8_t seed[]: byte array with seed of length
* MLDSA_CRHBYTES
* - uint8_t nonce: nonce
**************************************************/
MLD_INTERNAL_API
void mld_poly_uniform_eta(mld_poly *r, const uint8_t seed[MLDSA_CRHBYTES],
uint8_t nonce)
__contract__(
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(memory_no_alias(seed, MLDSA_CRHBYTES))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))
);
#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */
#if MLD_CONFIG_PARAMETER_SET == 65 || defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
#define mld_poly_uniform_gamma1 MLD_NAMESPACE_KL(poly_uniform_gamma1)
/*************************************************
* Name: mld_poly_uniform_gamma1
*
* Description: Sample polynomial with uniformly random coefficients
* in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output
* stream of SHAKE256(seed|nonce)
*
* Arguments: - mld_poly *a: pointer to output polynomial
* - const uint8_t seed[]: byte array with seed of length
* MLDSA_CRHBYTES
* - uint16_t nonce: 16-bit nonce
**************************************************/
MLD_INTERNAL_API
void mld_poly_uniform_gamma1(mld_poly *a, const uint8_t seed[MLDSA_CRHBYTES],
uint16_t nonce)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(seed, MLDSA_CRHBYTES))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
);
#endif /* MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_SERIAL_FIPS202_ONLY */
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
#define mld_poly_uniform_gamma1_4x MLD_NAMESPACE_KL(poly_uniform_gamma1_4x)
/*************************************************
* Name: mld_poly_uniform_gamma1_4x
*
* Description: Sample polynomial with uniformly random coefficients
* in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output
* stream of SHAKE256(seed|nonce)
*
* Arguments: - mld_poly *a: pointer to output polynomial
* - const uint8_t seed[]: byte array with seed of length
* MLDSA_CRHBYTES
* - uint16_t nonce: 16-bit nonce
**************************************************/
MLD_INTERNAL_API
void mld_poly_uniform_gamma1_4x(mld_poly *r0, mld_poly *r1, mld_poly *r2,
mld_poly *r3,
const uint8_t seed[MLDSA_CRHBYTES],
uint16_t nonce0, uint16_t nonce1,
uint16_t nonce2, uint16_t nonce3)
__contract__(
requires(memory_no_alias(r0, sizeof(mld_poly)))
requires(memory_no_alias(r1, sizeof(mld_poly)))
requires(memory_no_alias(r2, sizeof(mld_poly)))
requires(memory_no_alias(r3, sizeof(mld_poly)))
requires(memory_no_alias(seed, MLDSA_CRHBYTES))
assigns(memory_slice(r0, sizeof(mld_poly)))
assigns(memory_slice(r1, sizeof(mld_poly)))
assigns(memory_slice(r2, sizeof(mld_poly)))
assigns(memory_slice(r3, sizeof(mld_poly)))
ensures(array_bound(r0->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
ensures(array_bound(r1->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
ensures(array_bound(r2->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
ensures(array_bound(r3->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
);
#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */
#define mld_poly_challenge MLD_NAMESPACE_KL(poly_challenge)
/*************************************************
* Name: mld_poly_challenge
*
* Description: Implementation of H. Samples polynomial with MLDSA_TAU nonzero
* coefficients in {-1,1} using the output stream of
* SHAKE256(seed).
*
* Arguments: - mld_poly *c: pointer to output polynomial
* - const uint8_t mu[]: byte array containing seed of length
* MLDSA_CTILDEBYTES
**************************************************/
MLD_INTERNAL_API
void mld_poly_challenge(mld_poly *c, const uint8_t seed[MLDSA_CTILDEBYTES])
__contract__(
requires(memory_no_alias(c, sizeof(mld_poly)))
requires(memory_no_alias(seed, MLDSA_CTILDEBYTES))
assigns(memory_slice(c, sizeof(mld_poly)))
/* All coefficients of c are -1, 0 or +1 */
ensures(array_bound(c->coeffs, 0, MLDSA_N, -1, 2))
);
#define mld_polyeta_pack MLD_NAMESPACE_KL(polyeta_pack)
/*************************************************
* Name: mld_polyeta_pack
*
* Description: Bit-pack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA].
*
* Arguments: - uint8_t *r: pointer to output byte array with at least
* MLDSA_POLYETA_PACKEDBYTES bytes
* - const mld_poly *a: pointer to input polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyeta_pack(uint8_t r[MLDSA_POLYETA_PACKEDBYTES], const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYETA_PACKEDBYTES))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_ETA + 1))
assigns(memory_slice(r, MLDSA_POLYETA_PACKEDBYTES))
);
/*
* polyeta_unpack produces coefficients in [-MLDSA_ETA,MLDSA_ETA] for
* well-formed inputs (i.e., those produced by polyeta_pack).
* However, when passed an arbitrary byte array, it may produce smaller values,
* i.e, values in [MLD_POLYETA_UNPACK_LOWER_BOUND,MLDSA_ETA]
* Even though this should never happen, we use use the bound for arbitrary
* inputs in the CBMC proofs.
*/
#if MLDSA_ETA == 2
#define MLD_POLYETA_UNPACK_LOWER_BOUND (-5)
#elif MLDSA_ETA == 4
#define MLD_POLYETA_UNPACK_LOWER_BOUND (-11)
#else
#error "Invalid value of MLDSA_ETA"
#endif
#define mld_polyeta_unpack MLD_NAMESPACE_KL(polyeta_unpack)
/*************************************************
* Name: mld_polyeta_unpack
*
* Description: Unpack polynomial with coefficients in [-MLDSA_ETA,MLDSA_ETA].
*
* Arguments: - mld_poly *r: pointer to output polynomial
* - const uint8_t *a: byte array with bit-packed polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyeta_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYETA_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(memory_no_alias(a, MLDSA_POLYETA_PACKEDBYTES))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1))
);
#define mld_polyz_pack MLD_NAMESPACE_KL(polyz_pack)
/*************************************************
* Name: mld_polyz_pack
*
* Description: Bit-pack polynomial with coefficients
* in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1].
*
* Arguments: - uint8_t *r: pointer to output byte array with at least
* MLDSA_POLYZ_PACKEDBYTES bytes
* - const mld_poly *a: pointer to input polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyz_pack(uint8_t r[MLDSA_POLYZ_PACKEDBYTES], const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYZ_PACKEDBYTES))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
assigns(memory_slice(r, MLDSA_POLYZ_PACKEDBYTES))
);
#define mld_polyz_unpack MLD_NAMESPACE_KL(polyz_unpack)
/*************************************************
* Name: mld_polyz_unpack
*
* Description: Unpack polynomial z with coefficients
* in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1].
*
* Arguments: - mld_poly *r: pointer to output polynomial
* - const uint8_t *a: byte array with bit-packed polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyz_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYZ_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
);
#define mld_polyw1_pack MLD_NAMESPACE_KL(polyw1_pack)
/*************************************************
* Name: mld_polyw1_pack
*
* Description: Bit-pack polynomial w1 with coefficients in [0,15] or [0,43].
* Input coefficients are assumed to be standard representatives.
*
* Arguments: - uint8_t *r: pointer to output byte array with at least
* MLDSA_POLYW1_PACKEDBYTES bytes
* - const mld_poly *a: pointer to input polynomial
**************************************************/
MLD_INTERNAL_API
void mld_polyw1_pack(uint8_t r[MLDSA_POLYW1_PACKEDBYTES], const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES))
);
#endif /* !MLD_POLY_KL_H */

View File

@@ -0,0 +1,854 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* References
* ==========
*
* - [FIPS204]
* FIPS 204 Module-Lattice-Based Digital Signature Standard
* National Institute of Standards and Technology
* https://csrc.nist.gov/pubs/fips/204/final
*/
#include <stdint.h>
#include <string.h>
#include "common.h"
#include "debug.h"
#include "poly.h"
#include "poly_kl.h"
#include "polyvec.h"
/* This namespacing is not done at the top to avoid a naming conflict
* with native backends, which are currently not yet namespaced. */
#define mld_polymat_permute_bitrev_to_custom \
MLD_ADD_PARAM_SET(mld_polymat_permute_bitrev_to_custom)
#define mld_polyvecl_permute_bitrev_to_custom \
MLD_ADD_PARAM_SET(mld_polyvecl_permute_bitrev_to_custom)
#define mld_polyvecl_pointwise_acc_montgomery_c \
MLD_ADD_PARAM_SET(mld_polyvecl_pointwise_acc_montgomery_c)
#if !defined(MLD_CONFIG_REDUCE_RAM)
/* Helper function to ensure that the polynomial entries in the output
* of mld_polyvec_matrix_expand use the standard (bitreversed) ordering
* of coefficients.
* No-op unless a native backend with a custom ordering is used.
*/
static void mld_polyvecl_permute_bitrev_to_custom(mld_polyvecl *v)
__contract__(
/* We don't specify that this should be a permutation, but only
* that it does not change the bound established at the end of
* mld_polyvec_matrix_expand.
*/
requires(memory_no_alias(v, sizeof(mld_polyvecl)))
requires(forall(x, 0, MLDSA_L,
array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
assigns(memory_slice(v, sizeof(mld_polyvecl)))
ensures(forall(x, 0, MLDSA_L,
array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
{
#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER)
unsigned i;
for (i = 0; i < MLDSA_L; i++)
__loop__(
assigns(i, memory_slice(v, sizeof(mld_polyvecl)))
invariant(i <= MLDSA_L)
invariant(forall(x, 0, MLDSA_L,
array_bound(v->vec[x].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
{
mld_poly_permute_bitrev_to_custom(v->vec[i].coeffs);
}
#else /* MLD_USE_NATIVE_NTT_CUSTOM_ORDER */
/* Nothing to do */
(void)v;
#endif /* !MLD_USE_NATIVE_NTT_CUSTOM_ORDER */
}
static void mld_polymat_permute_bitrev_to_custom(mld_polymat *mat)
__contract__(
/* We don't specify that this should be a permutation, but only
* that it does not change the bound established at the end of
* mld_polyvec_matrix_expand.
*/
requires(memory_no_alias(mat, sizeof(mld_polymat)))
requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
assigns(memory_slice(mat, sizeof(mld_polymat)))
ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
)
{
unsigned int i;
for (i = 0; i < MLDSA_K; i++)
__loop__(
assigns(i, memory_slice(mat, sizeof(mld_polymat)))
invariant(i <= MLDSA_K)
invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))))
{
mld_polyvecl_permute_bitrev_to_custom(&mat->vec[i]);
}
}
#endif /* !MLD_CONFIG_REDUCE_RAM */
MLD_INTERNAL_API
const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row)
{
#if defined(MLD_CONFIG_REDUCE_RAM)
unsigned int i;
MLD_ALIGN uint8_t seed_ext[MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)];
mld_memcpy(seed_ext, mat->rho, MLDSA_SEEDBYTES);
/* Generate row on-demand */
for (i = 0; i < MLDSA_L; i++)
{
uint8_t x = (uint8_t)row;
uint8_t y = (uint8_t)i;
seed_ext[MLDSA_SEEDBYTES + 0] = y;
seed_ext[MLDSA_SEEDBYTES + 1] = x;
mld_poly_uniform(&mat->row_buffer.vec[i], seed_ext);
#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER)
mld_poly_permute_bitrev_to_custom(mat->row_buffer.vec[i].coeffs);
#endif
}
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(seed_ext, sizeof(seed_ext));
return &mat->row_buffer;
#else /* MLD_CONFIG_REDUCE_RAM */
return &mat->vec[row];
#endif /* !MLD_CONFIG_REDUCE_RAM */
}
MLD_INTERNAL_API
void mld_polyvec_matrix_expand(mld_polymat *mat,
const uint8_t rho[MLDSA_SEEDBYTES])
{
#if defined(MLD_CONFIG_REDUCE_RAM)
/* In REDUCE_RAM mode, just copy the seed for later on-demand generation */
mld_memcpy(mat->rho, rho, MLDSA_SEEDBYTES);
#else
unsigned int i, j;
/*
* We generate four separate seed arrays rather than a single one to work
* around limitations in CBMC function contracts dealing with disjoint slices
* of the same parent object.
*/
MLD_ALIGN uint8_t seed_ext[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)];
for (j = 0; j < 4; j++)
__loop__(
assigns(j, object_whole(seed_ext))
invariant(j <= 4)
)
{
mld_memcpy(seed_ext[j], rho, MLDSA_SEEDBYTES);
}
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
/* Sample 4 matrix entries a time. */
for (i = 0; i < (MLDSA_K * MLDSA_L / 4) * 4; i += 4)
__loop__(
assigns(i, j, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat)))
invariant(i <= (MLDSA_K * MLDSA_L / 4) * 4 && i % 4 == 0)
/* vectors 0 .. i / MLDSA_L are completely sampled */
invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L,
array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
/* last vector is sampled up to i % MLDSA_L */
invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L,
array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
)
{
for (j = 0; j < 4; j++)
__loop__(
assigns(j, object_whole(seed_ext))
invariant(j <= 4)
)
{
uint8_t x = (uint8_t)((i + j) / MLDSA_L);
uint8_t y = (uint8_t)((i + j) % MLDSA_L);
seed_ext[j][MLDSA_SEEDBYTES + 0] = y;
seed_ext[j][MLDSA_SEEDBYTES + 1] = x;
}
mld_poly_uniform_4x(&mat->vec[i / MLDSA_L].vec[i % MLDSA_L],
&mat->vec[(i + 1) / MLDSA_L].vec[(i + 1) % MLDSA_L],
&mat->vec[(i + 2) / MLDSA_L].vec[(i + 2) % MLDSA_L],
&mat->vec[(i + 3) / MLDSA_L].vec[(i + 3) % MLDSA_L],
seed_ext);
}
#else /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */
i = 0;
#endif /* MLD_CONFIG_SERIAL_FIPS202_ONLY */
/* Entries omitted by the batch-sampling are sampled individually. */
while (i < MLDSA_K * MLDSA_L)
__loop__(
assigns(i, object_whole(seed_ext), memory_slice(mat, sizeof(mld_polymat)))
invariant(i <= MLDSA_K * MLDSA_L)
/* vectors 0 .. i / MLDSA_L are completely sampled */
invariant(forall(k1, 0, i / MLDSA_L, forall(l1, 0, MLDSA_L,
array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
/* last vector is sampled up to i % MLDSA_L */
invariant(forall(k2, i / MLDSA_L, i / MLDSA_L + 1, forall(l2, 0, i % MLDSA_L,
array_bound(mat->vec[k2].vec[l2].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
)
{
uint8_t x = (uint8_t)(i / MLDSA_L);
uint8_t y = (uint8_t)(i % MLDSA_L);
mld_poly *this_poly = &mat->vec[i / MLDSA_L].vec[i % MLDSA_L];
seed_ext[0][MLDSA_SEEDBYTES + 0] = y;
seed_ext[0][MLDSA_SEEDBYTES + 1] = x;
mld_poly_uniform(this_poly, seed_ext[0]);
i++;
}
mld_polymat_permute_bitrev_to_custom(mat);
/* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
mld_zeroize(seed_ext, sizeof(seed_ext));
#endif /* !MLD_CONFIG_REDUCE_RAM */
}
MLD_INTERNAL_API
void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat,
const mld_polyvecl *v)
{
unsigned int i;
mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(t, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k0, 0, i,
array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))
)
{
const mld_polyvecl *row = mld_polymat_get_row(mat, i);
mld_polyvecl_pointwise_acc_montgomery(&t->vec[i], row, v);
}
mld_assert_abs_bound_2d(t->vec, MLDSA_K, MLDSA_N, MLDSA_Q);
}
/**************************************************************/
/************ Vectors of polynomials of length MLDSA_L **************/
/**************************************************************/
MLD_INTERNAL_API
void mld_polyvecl_uniform_gamma1(mld_polyvecl *v,
const uint8_t seed[MLDSA_CRHBYTES],
uint16_t nonce)
{
#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
int i;
#endif
/* Safety: nonce is at most ((UINT16_MAX - MLDSA_L) / MLDSA_L), and, hence,
* this cast is safe. See MLD_NONCE_UB comment in sign.c. */
nonce = (uint16_t)(MLDSA_L * nonce);
/* Now, nonce <= UINT16_MAX - (MLDSA_L - 1), so the casts below are safe. */
#if defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
for (i = 0; i < MLDSA_L; i++)
{
mld_poly_uniform_gamma1(&v->vec[i], seed, (uint16_t)(nonce + i));
}
#else /* MLD_CONFIG_SERIAL_FIPS202_ONLY */
#if MLDSA_L == 4
mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3],
seed, nonce, (uint16_t)(nonce + 1),
(uint16_t)(nonce + 2), (uint16_t)(nonce + 3));
#elif MLDSA_L == 5
mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2], &v->vec[3],
seed, nonce, (uint16_t)(nonce + 1),
(uint16_t)(nonce + 2), (uint16_t)(nonce + 3));
mld_poly_uniform_gamma1(&v->vec[4], seed, (uint16_t)(nonce + 4));
#elif MLDSA_L == 7
mld_poly_uniform_gamma1_4x(&v->vec[0], &v->vec[1], &v->vec[2],
&v->vec[3 /* irrelevant */], seed, nonce,
(uint16_t)(nonce + 1), (uint16_t)(nonce + 2),
0xFF /* irrelevant */);
mld_poly_uniform_gamma1_4x(&v->vec[3], &v->vec[4], &v->vec[5], &v->vec[6],
seed, (uint16_t)(nonce + 3), (uint16_t)(nonce + 4),
(uint16_t)(nonce + 5), (uint16_t)(nonce + 6));
#endif /* MLDSA_L == 7 */
#endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */
mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1),
MLDSA_GAMMA1 + 1);
}
MLD_INTERNAL_API
void mld_polyvecl_ntt(mld_polyvecl *v)
{
unsigned int i;
mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLDSA_Q);
for (i = 0; i < MLDSA_L; ++i)
__loop__(
assigns(i, memory_slice(v, sizeof(mld_polyvecl)))
invariant(i <= MLDSA_L)
invariant(forall(k0, i, MLDSA_L, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))
invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))))
{
mld_poly_ntt(&v->vec[i]);
}
mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);
}
MLD_STATIC_TESTABLE void mld_polyvecl_pointwise_acc_montgomery_c(
mld_poly *w, const mld_polyvecl *u, const mld_polyvecl *v)
__contract__(
requires(memory_no_alias(w, sizeof(mld_poly)))
requires(memory_no_alias(u, sizeof(mld_polyvecl)))
requires(memory_no_alias(v, sizeof(mld_polyvecl)))
requires(forall(l0, 0, MLDSA_L,
array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
requires(forall(l1, 0, MLDSA_L,
array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
assigns(memory_slice(w, sizeof(mld_poly)))
ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q))
)
{
unsigned int i, j;
mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q);
mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);
for (i = 0; i < MLDSA_N; i++)
__loop__(
assigns(i, j, memory_slice(w, sizeof(mld_poly)))
invariant(i <= MLDSA_N)
invariant(array_abs_bound(w->coeffs, 0, i, MLDSA_Q))
)
{
int64_t t = 0;
int32_t r;
for (j = 0; j < MLDSA_L; j++)
__loop__(
assigns(j, t)
invariant(j <= MLDSA_L)
invariant(t >= -(int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1))
invariant(t <= (int64_t)j*(MLDSA_Q - 1)*(MLD_NTT_BOUND - 1))
)
{
t += (int64_t)u->vec[j].coeffs[i] * v->vec[j].coeffs[i];
}
r = mld_montgomery_reduce(t);
w->coeffs[i] = r;
}
mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q);
}
MLD_INTERNAL_API
void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u,
const mld_polyvecl *v)
{
#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4) && \
MLD_CONFIG_PARAMETER_SET == 44
int ret;
mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q);
mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);
ret = mld_polyvecl_pointwise_acc_montgomery_l4_native(
w->coeffs, (const int32_t(*)[MLDSA_N])u->vec,
(const int32_t(*)[MLDSA_N])v->vec);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q);
return;
}
#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5) && \
MLD_CONFIG_PARAMETER_SET == 65
int ret;
mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q);
mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);
ret = mld_polyvecl_pointwise_acc_montgomery_l5_native(
w->coeffs, (const int32_t(*)[MLDSA_N])u->vec,
(const int32_t(*)[MLDSA_N])v->vec);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q);
return;
}
#elif defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7) && \
MLD_CONFIG_PARAMETER_SET == 87
int ret;
mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, 0, MLDSA_Q);
mld_assert_abs_bound_2d(v->vec, MLDSA_L, MLDSA_N, MLD_NTT_BOUND);
ret = mld_polyvecl_pointwise_acc_montgomery_l7_native(
w->coeffs, (const int32_t(*)[MLDSA_N])u->vec,
(const int32_t(*)[MLDSA_N])v->vec);
if (ret == MLD_NATIVE_FUNC_SUCCESS)
{
mld_assert_abs_bound(w->coeffs, MLDSA_N, MLDSA_Q);
return;
}
#endif /* !(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4 && \
MLD_CONFIG_PARAMETER_SET == 44) && \
!(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5 && \
MLD_CONFIG_PARAMETER_SET == 65) && \
MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7 && \
MLD_CONFIG_PARAMETER_SET == 87 */
/* The first input is bounded by [0, Q-1] inclusive
* The second input is bounded by [-9Q+1, 9Q-1] inclusive . Hence, we can
* safely accumulate in 64-bits without intermediate reductions as
* MLDSA_L * (MLD_NTT_BOUND-1) * (Q-1) < INT64_MAX
*
* The worst case is ML-DSA-87: 7 * (9Q-1) * (Q-1) < 2**52
* (and likewise for negative values)
*/
mld_polyvecl_pointwise_acc_montgomery_c(w, u, v);
}
MLD_INTERNAL_API
uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t bound)
{
unsigned int i;
uint32_t t = 0;
mld_assert_bound_2d(v->vec, MLDSA_L, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,
MLD_REDUCE32_RANGE_MAX);
for (i = 0; i < MLDSA_L; ++i)
__loop__(
invariant(i <= MLDSA_L)
invariant(t == 0 || t == 0xFFFFFFFF)
invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound)))
)
{
/* Reference: Leaks which polynomial violates the bound via a conditional.
* We are more conservative to reduce the number of declassifications in
* constant-time testing.
*/
t |= mld_poly_chknorm(&v->vec[i], bound);
}
return t;
}
/**************************************************************/
/************ Vectors of polynomials of length MLDSA_K **************/
/**************************************************************/
MLD_INTERNAL_API
void mld_polyveck_reduce(mld_polyveck *v)
{
unsigned int i;
mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, INT32_MIN,
MLD_REDUCE32_DOMAIN_MAX);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(v, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))
invariant(forall(k2, 0, i,
array_bound(v->vec[k2].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))
)
{
mld_poly_reduce(&v->vec[i]);
}
mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,
MLD_REDUCE32_RANGE_MAX);
}
MLD_INTERNAL_API
void mld_polyveck_caddq(mld_polyveck *v)
{
unsigned int i;
mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(v, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))
invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
{
mld_poly_caddq(&v->vec[i]);
}
mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q);
}
/* Reference: We use destructive version (output=first input) to avoid
* reasoning about aliasing in the CBMC specification */
MLD_INTERNAL_API
void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v)
{
unsigned int i;
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(u, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k0, i, MLDSA_K,
forall(k1, 0, MLDSA_N, u->vec[k0].coeffs[k1] == loop_entry(*u).vec[k0].coeffs[k1])))
invariant(forall(k6, 0, i, array_bound(u->vec[k6].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)))
)
{
mld_poly_add(&u->vec[i], &v->vec[i]);
}
mld_assert_bound_2d(u->vec, MLDSA_L, MLDSA_N, INT32_MIN,
MLD_REDUCE32_DOMAIN_MAX);
}
MLD_INTERNAL_API
void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v)
{
unsigned int i;
mld_assert_abs_bound_2d(u->vec, MLDSA_K, MLDSA_N, MLDSA_Q);
mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(u, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k0, 0, i,
array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)))
invariant(forall(k1, i, MLDSA_K,
forall(n1, 0, MLDSA_N, u->vec[k1].coeffs[n1] == loop_entry(*u).vec[k1].coeffs[n1]))))
{
mld_poly_sub(&u->vec[i], &v->vec[i]);
}
mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, INT32_MIN,
MLD_REDUCE32_DOMAIN_MAX);
}
MLD_INTERNAL_API
void mld_polyveck_shiftl(mld_polyveck *v)
{
unsigned int i;
mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, 1 << 10);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(v, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k1, 0, i, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
invariant(forall(k1, i, MLDSA_K,
forall(n1, 0, MLDSA_N, v->vec[k1].coeffs[n1] == loop_entry(*v).vec[k1].coeffs[n1])))
)
{
mld_poly_shiftl(&v->vec[i]);
}
mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q);
}
MLD_INTERNAL_API
void mld_polyveck_ntt(mld_polyveck *v)
{
unsigned int i;
mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(v, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))
invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND))))
{
mld_poly_ntt(&v->vec[i]);
}
mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND);
}
MLD_INTERNAL_API
void mld_polyveck_invntt_tomont(mld_polyveck *v)
{
unsigned int i;
mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLDSA_Q);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(v, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k0, i, MLDSA_K, forall(k1, 0, MLDSA_N, v->vec[k0].coeffs[k1] == loop_entry(*v).vec[k0].coeffs[k1])))
invariant(forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND))))
{
mld_poly_invntt_tomont(&v->vec[i]);
}
mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_INTT_BOUND);
}
MLD_INTERNAL_API
void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a,
const mld_polyveck *v)
{
unsigned int i;
mld_assert_abs_bound_2d(v->vec, MLDSA_K, MLDSA_N, MLD_NTT_BOUND);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(r, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k2, 0, i, array_abs_bound(r->vec[k2].coeffs, 0, MLDSA_N, MLDSA_Q)))
)
{
mld_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]);
}
mld_assert_abs_bound_2d(r->vec, MLDSA_K, MLDSA_N, MLDSA_Q);
}
MLD_INTERNAL_API
uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t bound)
{
unsigned int i;
uint32_t t = 0;
mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, -MLD_REDUCE32_RANGE_MAX,
MLD_REDUCE32_RANGE_MAX);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
invariant(i <= MLDSA_K)
invariant(t == 0 || t == 0xFFFFFFFF)
invariant((t == 0) == forall(k1, 0, i, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, bound)))
)
{
/* Reference: Leaks which polynomial violates the bound via a conditional.
* We are more conservative to reduce the number of declassifications in
* constant-time testing.
*/
t |= mld_poly_chknorm(&v->vec[i], bound);
}
return t;
}
MLD_INTERNAL_API
void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0,
const mld_polyveck *v)
{
unsigned int i;
mld_assert_bound_2d(v->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k1, 0, i, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)))
invariant(forall(k2, 0, i, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)))
)
{
mld_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]);
}
mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, -(MLD_2_POW_D / 2) + 1,
(MLD_2_POW_D / 2) + 1);
mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0,
((MLDSA_Q - 1) / MLD_2_POW_D) + 1);
}
MLD_INTERNAL_API
void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0)
{
unsigned int i;
mld_assert_bound_2d(v0->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(v0, sizeof(mld_polyveck)), memory_slice(v1, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k1, 0, i,
array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))))
invariant(forall(k2, 0, i,
array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)))
invariant(forall(k3, i, MLDSA_K,
array_bound(v0->vec[k3].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
)
{
mld_poly_decompose(&v1->vec[i], &v0->vec[i]);
}
mld_assert_bound_2d(v1->vec, MLDSA_K, MLDSA_N, 0,
(MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
mld_assert_abs_bound_2d(v0->vec, MLDSA_K, MLDSA_N, MLDSA_GAMMA2 + 1);
}
MLD_INTERNAL_API
unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0,
const mld_polyveck *v1)
{
unsigned int i, s = 0;
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, s, memory_slice(h, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(s <= i * MLDSA_N)
invariant(forall(k1, 0, i, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
)
{
s += mld_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]);
}
mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2);
return s;
}
MLD_INTERNAL_API
void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *u,
const mld_polyveck *h)
{
unsigned int i;
mld_assert_bound_2d(u->vec, MLDSA_K, MLDSA_N, 0, MLDSA_Q);
mld_assert_bound_2d(h->vec, MLDSA_K, MLDSA_N, 0, 2);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(w, sizeof(mld_polyveck)))
invariant(i <= MLDSA_K)
invariant(forall(k2, 0, i,
array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0,
(MLDSA_Q - 1) / (2 * MLDSA_GAMMA2))))
)
{
mld_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]);
}
mld_assert_bound_2d(w->vec, MLDSA_K, MLDSA_N, 0,
(MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
}
MLD_INTERNAL_API
void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES],
const mld_polyveck *w1)
{
unsigned int i;
mld_assert_bound_2d(w1->vec, MLDSA_K, MLDSA_N, 0,
(MLDSA_Q - 1) / (2 * MLDSA_GAMMA2));
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES))
invariant(i <= MLDSA_K)
)
{
mld_polyw1_pack(&r[i * MLDSA_POLYW1_PACKEDBYTES], &w1->vec[i]);
}
}
MLD_INTERNAL_API
void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES],
const mld_polyveck *p)
{
unsigned int i;
mld_assert_abs_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLDSA_ETA + 1);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))
invariant(i <= MLDSA_K)
)
{
mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]);
}
}
MLD_INTERNAL_API
void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES],
const mld_polyvecl *p)
{
unsigned int i;
mld_assert_abs_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLDSA_ETA + 1);
for (i = 0; i < MLDSA_L; ++i)
__loop__(
assigns(i, memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))
invariant(i <= MLDSA_L)
)
{
mld_polyeta_pack(&r[i * MLDSA_POLYETA_PACKEDBYTES], &p->vec[i]);
}
}
MLD_INTERNAL_API
void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES],
const mld_polyveck *p)
{
unsigned int i;
mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1,
(1 << (MLDSA_D - 1)) + 1);
for (i = 0; i < MLDSA_K; ++i)
__loop__(
assigns(i, memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))
invariant(i <= MLDSA_K)
)
{
mld_polyt0_pack(&r[i * MLDSA_POLYT0_PACKEDBYTES], &p->vec[i]);
}
}
MLD_INTERNAL_API
void mld_polyvecl_unpack_eta(
mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES])
{
unsigned int i;
for (i = 0; i < MLDSA_L; ++i)
{
mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES);
}
mld_assert_bound_2d(p->vec, MLDSA_L, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND,
MLDSA_ETA + 1);
}
MLD_INTERNAL_API
void mld_polyvecl_unpack_z(mld_polyvecl *z,
const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES])
{
unsigned int i;
for (i = 0; i < MLDSA_L; ++i)
{
mld_polyz_unpack(&z->vec[i], r + i * MLDSA_POLYZ_PACKEDBYTES);
}
mld_assert_bound_2d(z->vec, MLDSA_L, MLDSA_N, -(MLDSA_GAMMA1 - 1),
MLDSA_GAMMA1 + 1);
}
MLD_INTERNAL_API
void mld_polyveck_unpack_eta(
mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES])
{
unsigned int i;
for (i = 0; i < MLDSA_K; ++i)
{
mld_polyeta_unpack(&p->vec[i], r + i * MLDSA_POLYETA_PACKEDBYTES);
}
mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND,
MLDSA_ETA + 1);
}
MLD_INTERNAL_API
void mld_polyveck_unpack_t0(mld_polyveck *p,
const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES])
{
unsigned int i;
for (i = 0; i < MLDSA_K; ++i)
{
mld_polyt0_unpack(&p->vec[i], r + i * MLDSA_POLYT0_PACKEDBYTES);
}
mld_assert_bound_2d(p->vec, MLDSA_K, MLDSA_N, -(1 << (MLDSA_D - 1)) + 1,
(1 << (MLDSA_D - 1)) + 1);
}
/* To facilitate single-compilation-unit (SCU) builds, undefine all macros.
* Don't modify by hand -- this is auto-generated by scripts/autogen. */
#undef mld_polymat_permute_bitrev_to_custom
#undef mld_polyvecl_permute_bitrev_to_custom
#undef mld_polyvecl_pointwise_acc_montgomery_c

View File

@@ -0,0 +1,725 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_POLYVEC_H
#define MLD_POLYVEC_H
#include <stdint.h>
#include "cbmc.h"
#include "common.h"
#include "poly.h"
#include "poly_kl.h"
/* Parameter set namespacing
* This is to facilitate building multiple instances
* of mldsa-native (e.g. with varying parameter sets)
* within a single compilation unit. */
#define mld_polyvecl MLD_ADD_PARAM_SET(mld_polyvecl)
#define mld_polyveck MLD_ADD_PARAM_SET(mld_polyveck)
#define mld_polymat MLD_ADD_PARAM_SET(mld_polymat)
/* End of parameter set namespacing */
/* Vectors of polynomials of length MLDSA_L */
typedef struct
{
mld_poly vec[MLDSA_L];
} mld_polyvecl;
#define mld_polyvecl_uniform_gamma1 MLD_NAMESPACE_KL(polyvecl_uniform_gamma1)
/*************************************************
* Name: mld_polyvecl_uniform_gamma1
*
* Description: Sample vector of polynomials with uniformly random coefficients
* in [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1] by unpacking output
* stream of SHAKE256(seed|nonce)
*
* Arguments: - mld_polyvecl *v: pointer to output vector
* - const uint8_t seed[]: byte array with seed of length
* MLDSA_CRHBYTES
* - uint16_t nonce: 16-bit nonce
*************************************************/
MLD_INTERNAL_API
void mld_polyvecl_uniform_gamma1(mld_polyvecl *v,
const uint8_t seed[MLDSA_CRHBYTES],
uint16_t nonce)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyvecl)))
requires(memory_no_alias(seed, MLDSA_CRHBYTES))
requires(nonce <= (UINT16_MAX - MLDSA_L) / MLDSA_L)
assigns(memory_slice(v, sizeof(mld_polyvecl)))
ensures(forall(k0, 0, MLDSA_L,
array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))
);
#define mld_polyvecl_ntt MLD_NAMESPACE_KL(polyvecl_ntt)
/*************************************************
* Name: mld_polyvecl_ntt
*
* Description: Forward NTT of all polynomials in vector of length MLDSA_L.
* Coefficients can grow by 8*MLDSA_Q in absolute value.
*
* Arguments: - mld_polyvecl *v: pointer to input/output vector
**************************************************/
MLD_INTERNAL_API
void mld_polyvecl_ntt(mld_polyvecl *v)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyvecl)))
requires(forall(k0, 0, MLDSA_L, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))
assigns(memory_slice(v, sizeof(mld_polyvecl)))
ensures(forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
);
#define mld_polyvecl_pointwise_acc_montgomery \
MLD_NAMESPACE_KL(polyvecl_pointwise_acc_montgomery)
/*************************************************
* Name: mld_polyvecl_pointwise_acc_montgomery
*
* Description: Pointwise multiply vectors of polynomials of length MLDSA_L,
* multiply resulting vector by 2^{-32} and add (accumulate)
* polynomials in it.
* Input/output vectors are in NTT domain representation.
*
* The first input "u" must be the output of
* polyvec_matrix_expand() and so have coefficients in [0, Q-1]
* inclusive.
*
* The second input "v" is assumed to be output of an NTT, and
* hence must have coefficients bounded by [-9q+1, +9q-1]
* inclusive.
*
*
* Arguments: - mld_poly *w: output polynomial
* - const mld_polyvecl *u: pointer to first input vector
* - const mld_polyvecl *v: pointer to second input vector
**************************************************/
MLD_INTERNAL_API
void mld_polyvecl_pointwise_acc_montgomery(mld_poly *w, const mld_polyvecl *u,
const mld_polyvecl *v)
__contract__(
requires(memory_no_alias(w, sizeof(mld_poly)))
requires(memory_no_alias(u, sizeof(mld_polyvecl)))
requires(memory_no_alias(v, sizeof(mld_polyvecl)))
requires(forall(l0, 0, MLDSA_L,
array_bound(u->vec[l0].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
requires(forall(l1, 0, MLDSA_L,
array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
assigns(memory_slice(w, sizeof(mld_poly)))
ensures(array_abs_bound(w->coeffs, 0, MLDSA_N, MLDSA_Q))
);
#define mld_polyvecl_chknorm MLD_NAMESPACE_KL(polyvecl_chknorm)
/*************************************************
* Name: mld_polyvecl_chknorm
*
* Description: Check infinity norm of polynomials in vector of length MLDSA_L.
* Assumes input mld_polyvecl to be reduced by polyvecl_reduce().
*
* Arguments: - const mld_polyvecl *v: pointer to vector
* - int32_t B: norm bound
*
* Returns 0 if norm of all polynomials is strictly smaller than B <=
* (MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise.
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_INTERNAL_API
uint32_t mld_polyvecl_chknorm(const mld_polyvecl *v, int32_t B)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyvecl)))
requires(0 <= B && B <= (MLDSA_Q - 1) / 8)
requires(forall(k0, 0, MLDSA_L,
array_bound(v->vec[k0].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))
ensures(return_value == 0 || return_value == 0xFFFFFFFF)
ensures((return_value == 0) == forall(k1, 0, MLDSA_L, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B)))
);
/* Vectors of polynomials of length MLDSA_K */
typedef struct
{
mld_poly vec[MLDSA_K];
} mld_polyveck;
/* Matrix of polynomials (K x L) */
typedef struct
{
#if defined(MLD_CONFIG_REDUCE_RAM)
mld_polyvecl row_buffer;
uint8_t rho[MLDSA_SEEDBYTES];
#else
mld_polyvecl vec[MLDSA_K];
#endif
} mld_polymat;
#define mld_polyveck_reduce MLD_NAMESPACE_KL(polyveck_reduce)
/*************************************************
* Name: polyveck_reduce
*
* Description: Reduce coefficients of polynomials in vector of length MLDSA_K
* to representatives in
*[-MLD_REDUCE32_RANGE_MAX,MLD_REDUCE32_RANGE_MAX].
*
* Arguments: - mld_polyveck *v: pointer to input/output vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_reduce(mld_polyveck *v)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K,
array_bound(v->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)))
assigns(memory_slice(v, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K,
array_bound(v->vec[k1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))
);
#define mld_polyveck_caddq MLD_NAMESPACE_KL(polyveck_caddq)
/*************************************************
* Name: mld_polyveck_caddq
*
* Description: For all coefficients of polynomials in vector of length MLDSA_K
* add MLDSA_Q if coefficient is negative.
*
* Arguments: - mld_polyveck *v: pointer to input/output vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_caddq(mld_polyveck *v)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K,
array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))
assigns(memory_slice(v, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K,
array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
);
#define mld_polyveck_add MLD_NAMESPACE_KL(polyveck_add)
/*************************************************
* Name: mld_polyveck_add
*
* Description: Add vectors of polynomials of length MLDSA_K.
* No modular reduction is performed.
*
* Arguments: - mld_polyveck *u: pointer to input-output vector of polynomials
* to be added to
* - const mld_polyveck *v: pointer to second input vector of
* polynomials
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_add(mld_polyveck *u, const mld_polyveck *v)
__contract__(
requires(memory_no_alias(u, sizeof(mld_polyveck)))
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(forall(p0, 0, MLDSA_K, array_abs_bound(u->vec[p0].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))
requires(forall(p1, 0, MLDSA_K,
array_bound(v->vec[p1].coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))
assigns(memory_slice(u, sizeof(mld_polyveck)))
ensures(forall(q2, 0, MLDSA_K,
array_bound(u->vec[q2].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)))
);
#define mld_polyveck_sub MLD_NAMESPACE_KL(polyveck_sub)
/*************************************************
* Name: mld_polyveck_sub
*
* Description: Subtract vectors of polynomials of length MLDSA_K.
* No modular reduction is performed.
*
* Arguments: - mld_polyveck *u: pointer to first input vector
* - const mld_polyveck *v: pointer to second input vector to be
* subtracted from first input vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_sub(mld_polyveck *u, const mld_polyveck *v)
__contract__(
requires(memory_no_alias(u, sizeof(mld_polyveck)))
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K, array_abs_bound(u->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))
requires(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q)))
assigns(memory_slice(u, sizeof(mld_polyveck)))
ensures(forall(k0, 0, MLDSA_K,
array_bound(u->vec[k0].coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX)))
);
#define mld_polyveck_shiftl MLD_NAMESPACE_KL(polyveck_shiftl)
/*************************************************
* Name: mld_polyveck_shiftl
*
* Description: Multiply vector of polynomials of Length MLDSA_K by 2^MLDSA_D
*without modular reduction. Assumes input coefficients to be less than
*2^{31-MLDSA_D}.
*
* Arguments: - mld_polyveck *v: pointer to input/output vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_shiftl(mld_polyveck *v)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, 1 << 10)))
assigns(memory_slice(v, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K, array_bound(v->vec[k1].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
);
#define mld_polyveck_ntt MLD_NAMESPACE_KL(polyveck_ntt)
/*************************************************
* Name: mld_polyveck_ntt
*
* Description: Forward NTT of all polynomials in vector of length MLDSA_K.
* Coefficients can grow by 8*MLDSA_Q in absolute value.
*
* Arguments: - mld_polyveck *v: pointer to input/output vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_ntt(mld_polyveck *v)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))
assigns(memory_slice(v, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
);
#define mld_polyveck_invntt_tomont MLD_NAMESPACE_KL(polyveck_invntt_tomont)
/*************************************************
* Name: mld_polyveck_invntt_tomont
*
* Description: Inverse NTT and multiplication by 2^{32} of polynomials
* in vector of length MLDSA_K.
* Input coefficients need to be less than MLDSA_Q, and
* Output coefficients are bounded by MLD_INTT_BOUND.
* Arguments: - mld_polyveck *v: pointer to input/output vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_invntt_tomont(mld_polyveck *v)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))
assigns(memory_slice(v, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, MLD_INTT_BOUND)))
);
#define mld_polyveck_pointwise_poly_montgomery \
MLD_NAMESPACE_KL(polyveck_pointwise_poly_montgomery)
/*************************************************
* Name: mld_polyveck_pointwise_poly_montgomery
*
* Description: Pointwise multiplication of a polynomial vector of length
* MLDSA_K by a single polynomial in NTT domain and multiplication
* of the resulting polynomial vector by 2^{-32}.
*
* Arguments: - mld_polyveck *r: pointer to output vector
* - mld_poly *a: pointer to input polynomial
* - mld_polyveck *v: pointer to input vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_pointwise_poly_montgomery(mld_polyveck *r, const mld_poly *a,
const mld_polyveck *v)
__contract__(
requires(memory_no_alias(r, sizeof(mld_polyveck)))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
requires(forall(k0, 0, MLDSA_K, array_abs_bound(v->vec[k0].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
assigns(memory_slice(r, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K, array_abs_bound(r->vec[k1].coeffs, 0, MLDSA_N, MLDSA_Q)))
);
#define mld_polyveck_chknorm MLD_NAMESPACE_KL(polyveck_chknorm)
/*************************************************
* Name: mld_polyveck_chknorm
*
* Description: Check infinity norm of polynomials in vector of length MLDSA_K.
* Assumes input mld_polyveck to be reduced by polyveck_reduce().
*
* Arguments: - const mld_polyveck *v: pointer to vector
* - int32_t B: norm bound
*
* Returns 0 if norm of all polynomials are strictly smaller than B <=
*(MLDSA_Q-1)/8 and 0xFFFFFFFF otherwise.
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_INTERNAL_API
uint32_t mld_polyveck_chknorm(const mld_polyveck *v, int32_t B)
__contract__(
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(0 <= B && B <= (MLDSA_Q - 1) / 8)
requires(forall(k0, 0, MLDSA_K,
array_bound(v->vec[k0].coeffs, 0, MLDSA_N,
-MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX)))
ensures(return_value == 0 || return_value == 0xFFFFFFFF)
ensures((return_value == 0) == forall(k1, 0, MLDSA_K, array_abs_bound(v->vec[k1].coeffs, 0, MLDSA_N, B)))
);
#define mld_polyveck_power2round MLD_NAMESPACE_KL(polyveck_power2round)
/*************************************************
* Name: mld_polyveck_power2round
*
* Description: For all coefficients a of polynomials in vector of length
*MLDSA_K, compute a0, a1 such that a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with
*-2^{MLDSA_D-1} < a0 <= 2^{MLDSA_D-1}. Assumes coefficients to be standard
*representatives.
*
* Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with
* coefficients a1
* - mld_polyveck *v0: pointer to output vector of polynomials with
* coefficients a0
* - const mld_polyveck *v: pointer to input vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_power2round(mld_polyveck *v1, mld_polyveck *v0,
const mld_polyveck *v)
__contract__(
requires(memory_no_alias(v1, sizeof(mld_polyveck)))
requires(memory_no_alias(v0, sizeof(mld_polyveck)))
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K, array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
assigns(memory_slice(v1, sizeof(mld_polyveck)))
assigns(memory_slice(v0, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K, array_bound(v0->vec[k1].coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1)))
ensures(forall(k2, 0, MLDSA_K, array_bound(v1->vec[k2].coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1)))
);
#define mld_polyveck_decompose MLD_NAMESPACE_KL(polyveck_decompose)
/*************************************************
* Name: mld_polyveck_decompose
*
* Description: For all coefficients a of polynomials in vector of length
* MLDSA_K, compute high and low bits a0, a1 such a mod^+ MLDSA_Q = a1*ALPHA
* + a0 with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (MLDSA_Q-1)/ALPHA where we set
* a1 = 0 and -ALPHA/2 <= a0 = a mod MLDSA_Q - MLDSA_Q < 0. Assumes coefficients
* to be standard representatives.
*
* Arguments: - mld_polyveck *v1: pointer to output vector of polynomials with
* coefficients a1
* - mld_polyveck *v0: pointer to input/output vector of
* polynomials with. Output polynomial has
* coefficients a0
*
* Reference: The reference implementation has the input polynomial as a
* separate argument that may be aliased with either of the outputs.
* Removing the aliasing eases CBMC proofs.
*
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_decompose(mld_polyveck *v1, mld_polyveck *v0)
__contract__(
requires(memory_no_alias(v1, sizeof(mld_polyveck)))
requires(memory_no_alias(v0, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K,
array_bound(v0->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
assigns(memory_slice(v1, sizeof(mld_polyveck)))
assigns(memory_slice(v0, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K,
array_bound(v1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))))
ensures(forall(k2, 0, MLDSA_K,
array_abs_bound(v0->vec[k2].coeffs, 0, MLDSA_N, MLDSA_GAMMA2+1)))
);
#define mld_polyveck_make_hint MLD_NAMESPACE_KL(polyveck_make_hint)
/*************************************************
* Name: mld_polyveck_make_hint
*
* Description: Compute hint vector.
*
* Arguments: - mld_polyveck *h: pointer to output vector
* - const mld_polyveck *v0: pointer to low part of input vector
* - const mld_polyveck *v1: pointer to high part of input vector
*
* Returns number of 1 bits.
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_INTERNAL_API
unsigned int mld_polyveck_make_hint(mld_polyveck *h, const mld_polyveck *v0,
const mld_polyveck *v1)
__contract__(
requires(memory_no_alias(h, sizeof(mld_polyveck)))
requires(memory_no_alias(v0, sizeof(mld_polyveck)))
requires(memory_no_alias(v1, sizeof(mld_polyveck)))
assigns(memory_slice(h, sizeof(mld_polyveck)))
ensures(return_value <= MLDSA_N * MLDSA_K)
ensures(forall(k1, 0, MLDSA_K, array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
);
#define mld_polyveck_use_hint MLD_NAMESPACE_KL(polyveck_use_hint)
/*************************************************
* Name: mld_polyveck_use_hint
*
* Description: Use hint vector to correct the high bits of input vector.
*
* Arguments: - mld_polyveck *w: pointer to output vector of polynomials with
* corrected high bits
* - const mld_polyveck *u: pointer to input vector
* - const mld_polyveck *h: pointer to input hint vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_use_hint(mld_polyveck *w, const mld_polyveck *v,
const mld_polyveck *h)
__contract__(
requires(memory_no_alias(w, sizeof(mld_polyveck)))
requires(memory_no_alias(v, sizeof(mld_polyveck)))
requires(memory_no_alias(h, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K,
array_bound(v->vec[k0].coeffs, 0, MLDSA_N, 0, MLDSA_Q)))
requires(forall(k1, 0, MLDSA_K,
array_bound(h->vec[k1].coeffs, 0, MLDSA_N, 0, 2)))
assigns(memory_slice(w, sizeof(mld_polyveck)))
ensures(forall(k2, 0, MLDSA_K,
array_bound(w->vec[k2].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))))
);
#define mld_polyveck_pack_w1 MLD_NAMESPACE_KL(polyveck_pack_w1)
/*************************************************
* Name: mld_polyveck_pack_w1
*
* Description: Bit-pack polynomial vector w1 with coefficients in [0,15] or
* [0,43].
* Input coefficients are assumed to be standard representatives.
*
* Arguments: - uint8_t *r: pointer to output byte array with at least
* MLDSA_K* MLDSA_POLYW1_PACKEDBYTES bytes
* - const mld_polyveck *a: pointer to input polynomial vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_pack_w1(uint8_t r[MLDSA_K * MLDSA_POLYW1_PACKEDBYTES],
const mld_polyveck *w1)
__contract__(
requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES))
requires(memory_no_alias(w1, sizeof(mld_polyveck)))
requires(forall(k1, 0, MLDSA_K,
array_bound(w1->vec[k1].coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2))))
assigns(memory_slice(r, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES))
);
#define mld_polyveck_pack_eta MLD_NAMESPACE_KL(polyveck_pack_eta)
/*************************************************
* Name: mld_polyveck_pack_eta
*
* Description: Bit-pack polynomial vector with coefficients
* in [-MLDSA_ETA,MLDSA_ETA].
*
* Arguments: - uint8_t *r: pointer to output byte array with
* MLDSA_K * MLDSA_POLYETA_PACKEDBYTES bytes
* - const polyveck *p: pointer to input polynomial vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_pack_eta(uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES],
const mld_polyveck *p)
__contract__(
requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))
requires(memory_no_alias(p, sizeof(mld_polyveck)))
requires(forall(k1, 0, MLDSA_K,
array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))
assigns(memory_slice(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))
);
#define mld_polyvecl_pack_eta MLD_NAMESPACE_KL(polyvecl_pack_eta)
/*************************************************
* Name: mld_polyvecl_pack_eta
*
* Description: Bit-pack polynomial vector with coefficients in
* [-MLDSA_ETA,MLDSA_ETA].
*
* Arguments: - uint8_t *r: pointer to output byte array with
* MLDSA_L * MLDSA_POLYETA_PACKEDBYTES bytes
* - const polyveck *p: pointer to input polynomial vector
**************************************************/
MLD_INTERNAL_API
void mld_polyvecl_pack_eta(uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES],
const mld_polyvecl *p)
__contract__(
requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))
requires(memory_no_alias(p, sizeof(mld_polyvecl)))
requires(forall(k1, 0, MLDSA_L,
array_abs_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLDSA_ETA + 1)))
assigns(memory_slice(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))
);
#define mld_polyveck_pack_t0 MLD_NAMESPACE_KL(polyveck_pack_t0)
/*************************************************
* Name: mld_polyveck_pack_t0
*
* Description: Bit-pack polynomial vector to with coefficients in
* ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}].
*
* Arguments: - uint8_t *r: pointer to output byte array with
* MLDSA_K * MLDSA_POLYT0_PACKEDBYTES bytes
* - const mld_poly *p: pointer to input polynomial vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_pack_t0(uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES],
const mld_polyveck *p)
__contract__(
requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))
requires(memory_no_alias(p, sizeof(mld_polyveck)))
requires(forall(k0, 0, MLDSA_K,
array_bound(p->vec[k0].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)))
assigns(memory_slice(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))
);
#define mld_polyvecl_unpack_eta MLD_NAMESPACE_KL(polyvecl_unpack_eta)
/*************************************************
* Name: mld_polyvecl_unpack_eta
*
* Description: Unpack polynomial vector with coefficients in
* [-MLDSA_ETA,MLDSA_ETA].
*
* Arguments: - mld_polyvecl *p: pointer to output polynomial vector
* - const uint8_t *r: input byte array with
* bit-packed polynomial vector
**************************************************/
MLD_INTERNAL_API
void mld_polyvecl_unpack_eta(
mld_polyvecl *p, const uint8_t r[MLDSA_L * MLDSA_POLYETA_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))
requires(memory_no_alias(p, sizeof(mld_polyvecl)))
assigns(memory_slice(p, sizeof(mld_polyvecl)))
ensures(forall(k1, 0, MLDSA_L,
array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))
);
#define mld_polyvecl_unpack_z MLD_NAMESPACE_KL(polyvecl_unpack_z)
/*************************************************
* Name: mld_polyvecl_unpack_z
*
* Description: Unpack polynomial vector with coefficients in
* [-(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1].
*
* Arguments: - mld_polyvecl *z: pointer to output polynomial vector
* - const uint8_t *r: input byte array with
* bit-packed polynomial vector
**************************************************/
MLD_INTERNAL_API
void mld_polyvecl_unpack_z(mld_polyvecl *z,
const uint8_t r[MLDSA_L * MLDSA_POLYZ_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, MLDSA_L * MLDSA_POLYZ_PACKEDBYTES))
requires(memory_no_alias(z, sizeof(mld_polyvecl)))
assigns(memory_slice(z, sizeof(mld_polyvecl)))
ensures(forall(k1, 0, MLDSA_L,
array_bound(z->vec[k1].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))
);
#define mld_polyveck_unpack_eta MLD_NAMESPACE_KL(polyveck_unpack_eta)
/*************************************************
* Name: mld_polyveck_unpack_eta
*
* Description: Unpack polynomial vector with coefficients in
* [-MLDSA_ETA,MLDSA_ETA].
*
* Arguments: - mld_polyveck *p: pointer to output polynomial vector
* - const uint8_t *r: input byte array with
* bit-packed polynomial vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_unpack_eta(
mld_polyveck *p, const uint8_t r[MLDSA_K * MLDSA_POLYETA_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))
requires(memory_no_alias(p, sizeof(mld_polyveck)))
assigns(memory_slice(p, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K,
array_bound(p->vec[k1].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))
);
#define mld_polyveck_unpack_t0 MLD_NAMESPACE_KL(polyveck_unpack_t0)
/*************************************************
* Name: mld_polyveck_unpack_t0
*
* Description: Unpack polynomial vector with coefficients in
* ]-2^{MLDSA_D-1}, 2^{MLDSA_D-1}].
*
* Arguments: - mld_polyveck *p: pointer to output polynomial vector
* - const uint8_t *r: input byte array with
* bit-packed polynomial vector
**************************************************/
MLD_INTERNAL_API
void mld_polyveck_unpack_t0(mld_polyveck *p,
const uint8_t r[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))
requires(memory_no_alias(p, sizeof(mld_polyveck)))
assigns(memory_slice(p, sizeof(mld_polyveck)))
ensures(forall(k1, 0, MLDSA_K,
array_bound(p->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)))
);
#define mld_polymat_get_row MLD_NAMESPACE_KL(polymat_get_row)
/*************************************************
* Name: mld_polymat_get_row
*
* Description: Retrieve a pointer to a specific row of the matrix.
* In MLD_CONFIG_REDUCE_RAM mode, generates the row on-demand.
*
* Arguments: - mld_polymat *mat: pointer to matrix
* - unsigned int row: row index (must be < MLDSA_K)
*
* Returns pointer to the row (mld_polyvecl)
**************************************************/
MLD_INTERNAL_API
const mld_polyvecl *mld_polymat_get_row(mld_polymat *mat, unsigned int row);
#define mld_polyvec_matrix_expand MLD_NAMESPACE_KL(polyvec_matrix_expand)
/*************************************************
* Name: mld_polyvec_matrix_expand
*
* Description: Implementation of ExpandA. Generates matrix A with uniformly
* random coefficients a_{i,j} by performing rejection
* sampling on the output stream of SHAKE128(rho|j|i)
*
* Arguments: - mld_polymat *mat: pointer to output matrix
* - const uint8_t rho[]: byte array containing seed rho
**************************************************/
MLD_INTERNAL_API
void mld_polyvec_matrix_expand(mld_polymat *mat,
const uint8_t rho[MLDSA_SEEDBYTES])
__contract__(
requires(memory_no_alias(mat, sizeof(mld_polymat)))
requires(memory_no_alias(rho, MLDSA_SEEDBYTES))
assigns(memory_slice(mat, sizeof(mld_polymat)))
ensures(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
);
#define mld_polyvec_matrix_pointwise_montgomery \
MLD_NAMESPACE_KL(polyvec_matrix_pointwise_montgomery)
/*************************************************
* Name: mld_polyvec_matrix_pointwise_montgomery
*
* Description: Compute matrix-vector multiplication in NTT domain with
* pointwise multiplication and multiplication by 2^{-32}.
* Input matrix and vector must be in NTT domain representation.
*
* The first input "mat" must be the output of
* polyvec_matrix_expand() and so have coefficients in [0, Q-1]
* inclusive.
*
* The second input "v" is assumed to be output of an NTT, and
* hence must have coefficients bounded by [-9q+1, +9q-1]
* inclusive.
*
* Note: In MLD_CONFIG_REDUCE_RAM mode, mat cannot be const
* as rows are generated on-demand.
*
* Arguments: - mld_polyveck *t: pointer to output vector t
* - mld_polymat *mat: pointer to input matrix
* - const mld_polyvecl *v: pointer to input vector v
**************************************************/
MLD_INTERNAL_API
void mld_polyvec_matrix_pointwise_montgomery(mld_polyveck *t, mld_polymat *mat,
const mld_polyvecl *v)
__contract__(
requires(memory_no_alias(t, sizeof(mld_polyveck)))
requires(memory_no_alias(mat, sizeof(mld_polymat)))
requires(memory_no_alias(v, sizeof(mld_polyvecl)))
requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
requires(forall(l1, 0, MLDSA_L,
array_abs_bound(v->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
assigns(memory_slice(t, sizeof(mld_polyveck)))
ensures(forall(k0, 0, MLDSA_K,
array_abs_bound(t->vec[k0].coeffs, 0, MLDSA_N, MLDSA_Q)))
);
#endif /* !MLD_POLYVEC_H */

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_RANDOMBYTES_H
#define MLD_RANDOMBYTES_H
#include <stddef.h>
#include <stdint.h>
#include "cbmc.h"
#include "common.h"
#if !defined(MLD_CONFIG_NO_RANDOMIZED_API)
#if !defined(MLD_CONFIG_CUSTOM_RANDOMBYTES)
MLD_MUST_CHECK_RETURN_VALUE
int randombytes(uint8_t *out, size_t outlen);
static MLD_INLINE int mld_randombytes(uint8_t *out, size_t outlen)
__contract__(
requires(memory_no_alias(out, outlen))
assigns(memory_slice(out, outlen))
) { return randombytes(out, outlen); }
#endif /* !MLD_CONFIG_CUSTOM_RANDOMBYTES */
#endif /* !MLD_CONFIG_NO_RANDOMIZED_API */
#endif /* !MLD_RANDOMBYTES_H */

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_REDUCE_H
#define MLD_REDUCE_H
#include <stdint.h>
#include "cbmc.h"
#include "common.h"
#include "ct.h"
#include "debug.h"
/* check-magic: -4186625 == pow(2,32,MLDSA_Q) */
#define MLD_MONT -4186625
/* Upper bound for domain of mld_reduce32() */
#define MLD_REDUCE32_DOMAIN_MAX (INT32_MAX - (1 << 22))
/* Absolute bound for range of mld_reduce32() */
/* check-magic: 6283009 == (MLD_REDUCE32_DOMAIN_MAX - 255 * MLDSA_Q + 1) */
#define MLD_REDUCE32_RANGE_MAX 6283009
/*************************************************
* Name: mld_montgomery_reduce
*
* Description: Generic Montgomery reduction; given a 64-bit integer a, computes
* 32-bit integer congruent to a * R^-1 mod q, where R=2^32
*
* Arguments: - int64_t a: input integer to be reduced, of absolute value
* smaller or equal to INT64_MAX - 2^31 * MLDSA_Q.
*
* Returns: Integer congruent to a * R^-1 modulo q, with absolute value
* <= |a| / 2^32 + MLDSA_Q / 2
*
* In particular, if |a| < 2^31 * MLDSA_Q, the absolute value
* of the return value is < MLDSA_Q.
**************************************************/
static MLD_INLINE int32_t mld_montgomery_reduce(int64_t a)
__contract__(
/* We don't attempt to express an input-dependent output bound
* as the post-condition here, as all call-sites satisfy the
* absolute input bound 2^31 * MLDSA_Q and higher-level
* reasoning can be conducted using |return_value| < MLDSA_Q. */
requires(a > -(((int64_t)1 << 31) * MLDSA_Q) &&
a < (((int64_t)1 << 31) * MLDSA_Q))
ensures(return_value > -MLDSA_Q && return_value < MLDSA_Q)
)
{
/* check-magic: 58728449 == unsigned_mod(pow(MLDSA_Q, -1, 2^32), 2^32) */
const uint64_t QINV = 58728449;
/* Compute a*q^{-1} mod 2^32 in unsigned representatives */
const uint32_t a_reduced = mld_cast_int64_to_uint32(a);
const uint32_t a_inverted = (a_reduced * QINV) & UINT32_MAX;
/* Lift to signed canonical representative mod 2^32. */
const int32_t t = mld_cast_uint32_to_int32(a_inverted);
int64_t r;
mld_assert(a < +(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)) &&
a > -(INT64_MAX - (((int64_t)1 << 31) * MLDSA_Q)));
r = a - (int64_t)t * MLDSA_Q;
/*
* PORTABILITY: Right-shift on a signed integer is, strictly-speaking,
* implementation-defined for negative left argument. Here,
* we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5))
*/
r = r >> 32;
/* Bounds:
*
* By construction of the Montgomery multiplication, by the time we
* compute r >> 32, r is divisible by 2^32, and hence
*
* |r >> 32| = |r| / 2^32
* <= |a| / 2^32 + MLDSA_Q / 2
*
* (In general, we would only have |x >> n| <= ceil(|x| / 2^n)).
*
* In particular, if |a| < 2^31 * MLDSA_Q, then |return_value| < MLDSA_Q.
*/
return (int32_t)r;
}
/*************************************************
* Name: mld_reduce32
*
* Description: For finite field element a with a <= 2^{31} - 2^{22} - 1,
* compute r \equiv a (mod MLDSA_Q) such that
* -MLD_REDUCE32_RANGE_MAX <= r < MLD_REDUCE32_RANGE_MAX.
*
* Arguments: - int32_t: finite field element a
*
* Returns r.
**************************************************/
static MLD_INLINE int32_t mld_reduce32(int32_t a)
__contract__(
requires(a <= MLD_REDUCE32_DOMAIN_MAX)
ensures(return_value >= -MLD_REDUCE32_RANGE_MAX)
ensures(return_value < MLD_REDUCE32_RANGE_MAX)
)
{
int32_t t;
t = (a + (1 << 22)) >> 23;
t = a - t * MLDSA_Q;
mld_assert((t - a) % MLDSA_Q == 0);
return t;
}
/*************************************************
* Name: mld_caddq
*
* Description: Add MLDSA_Q if input coefficient is negative.
*
* Arguments: - int32_t: finite field element a
*
* Returns r.
**************************************************/
static MLD_INLINE int32_t mld_caddq(int32_t a)
__contract__(
requires(a > -MLDSA_Q)
requires(a < MLDSA_Q)
ensures(return_value >= 0)
ensures(return_value < MLDSA_Q)
ensures(return_value == (a >= 0) ? a : (a + MLDSA_Q))
)
{
return mld_ct_sel_int32(a + MLDSA_Q, a, mld_ct_cmask_neg_i32(a));
}
#endif /* !MLD_REDUCE_H */

View File

@@ -0,0 +1,221 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* References
* ==========
*
* - [FIPS204]
* FIPS 204 Module-Lattice-Based Digital Signature Standard
* National Institute of Standards and Technology
* https://csrc.nist.gov/pubs/fips/204/final
*/
#ifndef MLD_ROUNDING_H
#define MLD_ROUNDING_H
#include <stdint.h>
#include "cbmc.h"
#include "common.h"
#include "ct.h"
#include "debug.h"
/* Parameter set namespacing
* This is to facilitate building multiple instances
* of mldsa-native (e.g. with varying parameter sets)
* within a single compilation unit. */
#define mld_power2round MLD_ADD_PARAM_SET(mld_power2round)
#define mld_decompose MLD_ADD_PARAM_SET(mld_decompose)
#define mld_make_hint MLD_ADD_PARAM_SET(mld_make_hint)
#define mld_use_hint MLD_ADD_PARAM_SET(mld_use_hint)
/* End of parameter set namespacing */
#define MLD_2_POW_D (1 << MLDSA_D)
/*************************************************
* Name: mld_power2round
*
* Description: For finite field element a, compute a0, a1 such that
* a mod^+ MLDSA_Q = a1*2^MLDSA_D + a0 with -2^{MLDSA_D-1} < a0 <=
* 2^{MLDSA_D-1}. Assumes a to be standard representative.
*
* Arguments: - int32_t a: input element
* - int32_t *a0: pointer to output element a0
* - int32_t *a1: pointer to output element a1
*
* Reference: In the reference implementation, a1 is passed as a
* return value instead.
**************************************************/
static MLD_INLINE void mld_power2round(int32_t *a0, int32_t *a1, int32_t a)
__contract__(
requires(memory_no_alias(a0, sizeof(int32_t)))
requires(memory_no_alias(a1, sizeof(int32_t)))
requires(a >= 0 && a < MLDSA_Q)
assigns(memory_slice(a0, sizeof(int32_t)))
assigns(memory_slice(a1, sizeof(int32_t)))
ensures(*a0 > -(MLD_2_POW_D/2) && *a0 <= (MLD_2_POW_D/2))
ensures(*a1 >= 0 && *a1 <= (MLDSA_Q - 1) / MLD_2_POW_D)
ensures((*a1 * MLD_2_POW_D + *a0 - a) % MLDSA_Q == 0)
)
{
*a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D;
*a0 = a - (*a1 << MLDSA_D);
}
/*************************************************
* Name: mld_decompose
*
* Description: For finite field element a, compute high and low bits a0, a1
* such that a mod^+ MLDSA_Q = a1* 2 * MLDSA_GAMMA2 + a0 with
* -MLDSA_GAMMA2 < a0 <= MLDSA_GAMMA2 except
* if a1 = (MLDSA_Q-1)/(MLDSA_GAMMA2*2) where we set a1 = 0 and
* -MLDSA_GAMMA2 <= a0 = a mod^+ MLDSA_Q - MLDSA_Q < 0.
* Assumes a to be standard representative.
*
* Arguments: - int32_t a: input element
* - int32_t *a0: pointer to output element a0
* - int32_t *a1: pointer to output element a1
*
* Reference: a1 is passed as a return value instead
**************************************************/
static MLD_INLINE void mld_decompose(int32_t *a0, int32_t *a1, int32_t a)
__contract__(
requires(memory_no_alias(a0, sizeof(int32_t)))
requires(memory_no_alias(a1, sizeof(int32_t)))
requires(a >= 0 && a < MLDSA_Q)
assigns(memory_slice(a0, sizeof(int32_t)))
assigns(memory_slice(a1, sizeof(int32_t)))
/* a0 = -MLDSA_GAMMA2 can only occur when (q-1) = a - (a mod MLDSA_GAMMA2),
* then a1=1; and a0 = a - (a mod MLDSA_GAMMA2) - 1 (@[FIPS204, Algorithm 36 (Decompose)]) */
ensures(*a0 >= -MLDSA_GAMMA2 && *a0 <= MLDSA_GAMMA2)
ensures(*a1 >= 0 && *a1 < (MLDSA_Q-1)/(2*MLDSA_GAMMA2))
ensures((*a1 * 2 * MLDSA_GAMMA2 + *a0 - a) % MLDSA_Q == 0)
)
{
/*
* The goal is to compute f1 = round-(f / (2*GAMMA2)), which can be computed
* alternatively as round-(f / (128B)) = round-(ceil(f / 128) / B) where
* B = 2*GAMMA2 / 128. Here round-() denotes "round half down".
*
* The equality round-(f / (128B)) = round-(ceil(f / 128) / B) can deduced
* as follows. Since changing f to align-up(f, 128) can move f onto but not
* across a rounding boundary for division by 128*B (note that we need B to be
* even for this to work), and round- rounds down on the boundary, we have
*
* round-(f / (128B)) = round-(align-up(f, 128) / (128B))
* = round-((align-up(f, 128) / 128) / B)
* = round-(ceil(f / 128) / B).
*/
*a1 = (a + 127) >> 7;
/* We know a >= 0 and a < MLDSA_Q, so... */
/* check-magic: 65472 == round((MLDSA_Q-1)/128) */
mld_assert(*a1 >= 0 && *a1 <= 65472);
#if MLD_CONFIG_PARAMETER_SET == 44
/* check-magic: 1488 == 2 * intdiv(intdiv(MLDSA_Q - 1, 88), 128) */
/* check-magic: 11275 == floor(2**24 / 1488) */
/*
* Compute f1 = round-(f1' / B) ≈ round(f1' * 11275 / 2^24). This is exact
* for 0 <= f1' < 2^16. Note that half is rounded down since 11275 / 2^24 ≲
* 1 / 1488.
*/
*a1 = (*a1 * 11275 + (1 << 23)) >> 24;
mld_assert(*a1 >= 0 && *a1 <= 44);
*a1 = mld_ct_sel_int32(0, *a1, mld_ct_cmask_neg_i32(43 - *a1));
mld_assert(*a1 >= 0 && *a1 <= 43);
#else /* MLD_CONFIG_PARAMETER_SET == 44 */
/* check-magic: 4092 == 2 * intdiv(intdiv(MLDSA_Q - 1, 32), 128) */
/* check-magic: 1025 == floor(2**22 / 4092) */
/*
* Compute f1 = round-(f1' / B) ≈ round(f1' * 1025 / 2^22). This is exact
* for 0 <= f1' < 2^16. Note that half is rounded down since 1025 / 2^22 ≲
* 1 / 4092.
*/
*a1 = (*a1 * 1025 + (1 << 21)) >> 22;
mld_assert(*a1 >= 0 && *a1 <= 16);
*a1 &= 15;
mld_assert(*a1 >= 0 && *a1 <= 15);
#endif /* MLD_CONFIG_PARAMETER_SET != 44 */
*a0 = a - *a1 * 2 * MLDSA_GAMMA2;
*a0 = mld_ct_sel_int32(*a0 - MLDSA_Q, *a0,
mld_ct_cmask_neg_i32((MLDSA_Q - 1) / 2 - *a0));
}
/*************************************************
* Name: mld_make_hint
*
* Description: Compute hint bit indicating whether the low bits of the
* input element overflow into the high bits.
*
* Arguments: - int32_t a0: low bits of input element
* - int32_t a1: high bits of input element
*
* Returns 1 if overflow, 0 otherwise
**************************************************/
static MLD_INLINE unsigned int mld_make_hint(int32_t a0, int32_t a1)
__contract__(
ensures(return_value >= 0 && return_value <= 1)
)
{
if (a0 > MLDSA_GAMMA2 || a0 < -MLDSA_GAMMA2 ||
(a0 == -MLDSA_GAMMA2 && a1 != 0))
{
return 1;
}
return 0;
}
/*************************************************
* Name: mld_use_hint
*
* Description: Correct high bits according to hint.
*
* Arguments: - int32_t a: input element
* - int32_t hint: hint bit
*
* Returns corrected high bits.
**************************************************/
static MLD_INLINE int32_t mld_use_hint(int32_t a, int32_t hint)
__contract__(
requires(hint >= 0 && hint <= 1)
requires(a >= 0 && a < MLDSA_Q)
ensures(return_value >= 0 && return_value < (MLDSA_Q-1)/(2*MLDSA_GAMMA2))
)
{
int32_t a0, a1;
mld_decompose(&a0, &a1, a);
if (hint == 0)
{
return a1;
}
#if MLD_CONFIG_PARAMETER_SET == 44
if (a0 > 0)
{
return (a1 == 43) ? 0 : a1 + 1;
}
else
{
return (a1 == 0) ? 43 : a1 - 1;
}
#else /* MLD_CONFIG_PARAMETER_SET == 44 */
if (a0 > 0)
{
return (a1 + 1) & 15;
}
else
{
return (a1 - 1) & 15;
}
#endif /* MLD_CONFIG_PARAMETER_SET != 44 */
}
#endif /* !MLD_ROUNDING_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,807 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* References
* ==========
*
* - [FIPS204]
* FIPS 204 Module-Lattice-Based Digital Signature Standard
* National Institute of Standards and Technology
* https://csrc.nist.gov/pubs/fips/204/final
*/
#ifndef MLD_SIGN_H
#define MLD_SIGN_H
#include <stddef.h>
#include <stdint.h>
#include "cbmc.h"
#include "common.h"
#include "poly.h"
#include "polyvec.h"
#include "sys.h"
#if defined(MLD_CHECK_APIS)
/* Include to ensure consistency between internal sign.h
* and external mldsa_native.h. */
#include "mldsa_native.h"
#if MLDSA_CRYPTO_SECRETKEYBYTES != \
MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)
#error Mismatch for SECRETKEYBYTES between sign.h and mldsa_native.h
#endif
#if MLDSA_CRYPTO_PUBLICKEYBYTES != \
MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)
#error Mismatch for PUBLICKEYBYTES between sign.h and mldsa_native.h
#endif
#if MLDSA_CRYPTO_BYTES != MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)
#error Mismatch for CRYPTO_BYTES between sign.h and mldsa_native.h
#endif
#endif /* MLD_CHECK_APIS */
#define mld_sign_keypair_internal \
MLD_NAMESPACE_KL(keypair_internal) MLD_CONTEXT_PARAMETERS_3
#define mld_sign_keypair MLD_NAMESPACE_KL(keypair) MLD_CONTEXT_PARAMETERS_2
#define mld_sign_signature_internal \
MLD_NAMESPACE_KL(signature_internal) MLD_CONTEXT_PARAMETERS_9
#define mld_sign_signature MLD_NAMESPACE_KL(signature) MLD_CONTEXT_PARAMETERS_7
#define mld_sign_signature_extmu \
MLD_NAMESPACE_KL(signature_extmu) MLD_CONTEXT_PARAMETERS_4
#define mld_sign MLD_NAMESPACE_KL(sign) MLD_CONTEXT_PARAMETERS_7
#define mld_sign_verify_internal \
MLD_NAMESPACE_KL(verify_internal) MLD_CONTEXT_PARAMETERS_8
#define mld_sign_verify MLD_NAMESPACE_KL(verify) MLD_CONTEXT_PARAMETERS_7
#define mld_sign_verify_extmu \
MLD_NAMESPACE_KL(verify_extmu) MLD_CONTEXT_PARAMETERS_4
#define mld_sign_open MLD_NAMESPACE_KL(open) MLD_CONTEXT_PARAMETERS_7
#define mld_sign_signature_pre_hash_internal \
MLD_NAMESPACE_KL(signature_pre_hash_internal) MLD_CONTEXT_PARAMETERS_9
#define mld_sign_verify_pre_hash_internal \
MLD_NAMESPACE_KL(verify_pre_hash_internal) MLD_CONTEXT_PARAMETERS_8
#define mld_sign_signature_pre_hash_shake256 \
MLD_NAMESPACE_KL(signature_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_8
#define mld_sign_verify_pre_hash_shake256 \
MLD_NAMESPACE_KL(verify_pre_hash_shake256) MLD_CONTEXT_PARAMETERS_7
#define mld_prepare_domain_separation_prefix \
MLD_NAMESPACE_KL(prepare_domain_separation_prefix)
#define mld_sign_pk_from_sk \
MLD_NAMESPACE_KL(pk_from_sk) MLD_CONTEXT_PARAMETERS_2
/*************************************************
* Hash algorithm constants for domain separation
**************************************************/
#define MLD_PREHASH_NONE 0
#define MLD_PREHASH_SHA2_224 1
#define MLD_PREHASH_SHA2_256 2
#define MLD_PREHASH_SHA2_384 3
#define MLD_PREHASH_SHA2_512 4
#define MLD_PREHASH_SHA2_512_224 5
#define MLD_PREHASH_SHA2_512_256 6
#define MLD_PREHASH_SHA3_224 7
#define MLD_PREHASH_SHA3_256 8
#define MLD_PREHASH_SHA3_384 9
#define MLD_PREHASH_SHA3_512 10
#define MLD_PREHASH_SHAKE_128 11
#define MLD_PREHASH_SHAKE_256 12
/*************************************************
* Name: mld_sign_keypair_internal
*
* Description: Generates public and private key. Internal API.
* When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise
* Consistency Test (PCT) as required by FIPS 140-3 IG.
*
* Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key
* - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key
* - const uint8_t seed[MLDSA_SEEDBYTES]: input random seed
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_RNG_FAIL: Random number generation failed.
* - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure
* if MLD_CONFIG_KEYGEN_PCT is enabled.
*
* Specification: Implements @[FIPS204 Algorithm 6 (ML-DSA.KeyGen_internal)]
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
const uint8_t seed[MLDSA_SEEDBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
requires(memory_no_alias(seed, MLDSA_SEEDBYTES))
assigns(object_whole(pk))
assigns(object_whole(sk))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL ||
return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL)
);
/*************************************************
* Name: mld_sign_keypair
*
* Description: Generates public and private key.
* When MLD_CONFIG_KEYGEN_PCT is set, performs a Pairwise
* Consistency Test (PCT) as required by FIPS 140-3 IG.
*
* Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key
* - uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: output private key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_RNG_FAIL: Random number generation failed.
* - MLD_ERR_FAIL: Other kinds of failure, incl. PCT failure
* if MLD_CONFIG_KEYGEN_PCT is enabled.
*
* Specification: Implements @[FIPS204 Algorithm 1 (ML-DSA.KeyGen)]
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(object_whole(pk))
assigns(object_whole(sk))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL ||
return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL)
);
/*************************************************
* Name: mld_sign_signature_internal
*
* Description: Computes signature. Internal API.
*
* Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature
* - size_t *siglen: pointer to output length of
* signature
* - const uint8_t *m: pointer to message to be signed
* - size_t mlen: length of message
* - const uint8_t *pre: pointer to prefix string
* - size_t prelen: length of prefix string
* - const uint8_t rnd[MLDSA_RNDBYTES]:
* random seed
* - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]:
* bit-packed secret key
* - int externalmu: indicates input message m is
* processed as mu
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Other kinds of failure
*
* If the returned value is non-zero, then the values of *sig and
* *siglen should not be referenced.
*
* Reference: This code differs from the reference implementation
* in that it adds an explicit check for nonce exhaustion
* and can return MLD_ERR_FAIL in that case.
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
const uint8_t *m, size_t mlen,
const uint8_t *pre, size_t prelen,
const uint8_t rnd[MLDSA_RNDBYTES],
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
int externalmu,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(mlen <= MLD_MAX_BUFFER_SIZE)
requires(prelen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
requires(memory_no_alias(siglen, sizeof(size_t)))
requires(memory_no_alias(m, mlen))
requires(memory_no_alias(rnd, MLDSA_RNDBYTES))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
requires((externalmu == 0 && (prelen == 0 || memory_no_alias(pre, prelen))) ||
(externalmu == 1 && mlen == MLDSA_CRHBYTES))
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
assigns(object_whole(siglen))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL ||
return_value == MLD_ERR_OUT_OF_MEMORY)
ensures(return_value == 0 ==> *siglen == MLDSA_CRYPTO_BYTES)
ensures(return_value != 0 ==> *siglen == 0)
);
/*************************************************
* Name: mld_sign_signature
*
* Description: Computes signature. This function implements the randomized
* variant of ML-DSA. If you require the deterministic variant,
* use mld_sign_signature_internal directly.
*
* Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature
* - size_t *siglen: pointer to output length of
* signature
* - const uint8_t *m: pointer to message to be signed
* - size_t mlen: length of message
* - uint8_t *ctx: pointer to context string.
* May be NULL if ctxlen == 0.
* - size_t ctxlen: length of context string.
* Should be <= 255.
* - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]:
* bit-packed secret key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_RNG_FAIL: Random number generation failed.
* - MLD_ERR_FAIL: Other kinds of failure.
*
* Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)].
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *ctx,
size_t ctxlen,
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(mlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
requires(memory_no_alias(siglen, sizeof(size_t)))
requires(memory_no_alias(m, mlen))
requires(ctxlen <= MLD_MAX_BUFFER_SIZE)
requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
assigns(object_whole(siglen))
ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) ||
((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0))
);
/*************************************************
* Name: mld_sign_signature_extmu
*
* Description: Computes signature. This function implements the randomized
* variant of ML-DSA. If you require the deterministic variant,
* use mld_sign_signature_internal directly.
*
* Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]: output signature
* - size_t *siglen: pointer to output length of
* signature
* - const uint8_t mu[MLDSA_CRHBYTES]:
* input mu to be signed
* - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]:
* bit-packed secret key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_RNG_FAIL: Random number generation failed.
* - MLD_ERR_FAIL: Other kinds of failure.
*
* Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign external mu
* variant)]
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
const uint8_t mu[MLDSA_CRHBYTES],
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
requires(memory_no_alias(siglen, sizeof(size_t)))
requires(memory_no_alias(mu, MLDSA_CRHBYTES))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
assigns(object_whole(siglen))
ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) ||
((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY || return_value == MLD_ERR_RNG_FAIL) && *siglen == 0))
);
/*************************************************
* Name: mld_sign
*
* Description: Compute signed message.
*
* Arguments: - uint8_t *sm: pointer to output signed message
* (allocated array with MLDSA_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[MLDSA_CRYPTO_SECRETKEYBYTES]:
* bit-packed secret key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Other kinds of failure
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen,
const uint8_t *ctx, size_t ctxlen,
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(mlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sm, MLDSA_CRYPTO_BYTES + mlen))
requires(memory_no_alias(smlen, sizeof(size_t)))
requires(m == sm || memory_no_alias(m, mlen))
requires(ctxlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(ctx, ctxlen))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(memory_slice(sm, MLDSA_CRYPTO_BYTES + mlen))
assigns(object_whole(smlen))
ensures((return_value == 0 && *smlen == MLDSA_CRYPTO_BYTES + mlen) ||
(return_value == MLD_ERR_FAIL
|| return_value == MLD_ERR_OUT_OF_MEMORY
|| return_value == MLD_ERR_RNG_FAIL))
);
/*************************************************
* Name: mld_sign_verify_internal
*
* Description: Verifies signature. Internal API.
*
* Arguments: - const uint8_t *sig: 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[MLDSA_CRYPTO_PUBLICKEYBYTES]:
* bit-packed public key
* - int externalmu: indicates input message m is processed as
* mu
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
* Specification: Implements @[FIPS204 Algorithm 8 (ML-DSA.Verify_internal)]
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_verify_internal(const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pre,
size_t prelen,
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
int externalmu,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(prelen <= MLD_MAX_BUFFER_SIZE)
requires(mlen <= MLD_MAX_BUFFER_SIZE)
requires(siglen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, siglen))
requires(memory_no_alias(m, mlen))
requires(externalmu == 0 || (externalmu == 1 && mlen == MLDSA_CRHBYTES))
requires(externalmu == 1 || prelen == 0 || memory_no_alias(pre, prelen))
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY)
);
/*************************************************
* Name: mld_sign_verify
*
* Description: Verifies signature.
*
* Arguments: - const uint8_t *sig: 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.
* May be NULL if ctxlen == 0.
* - size_t ctxlen: length of context string
* - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]:
* bit-packed public key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
* Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify)]
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m,
size_t mlen, const uint8_t *ctx, size_t ctxlen,
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(mlen <= MLD_MAX_BUFFER_SIZE)
requires(siglen <= MLD_MAX_BUFFER_SIZE)
requires(ctxlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, siglen))
requires(memory_no_alias(m, mlen))
requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY)
);
/*************************************************
* Name: mld_sign_verify_extmu
*
* Description: Verifies signature.
*
* Arguments: - const uint8_t *sig: pointer to input signature
* - size_t siglen: length of signature
* - const uint8_t mu[MLDSA_CRHBYTES]:
* input mu
* - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]:
* bit-packed public key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
* Specification: Implements @[FIPS204 Algorithm 3 (ML-DSA.Verify external mu
* variant)]
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_verify_extmu(const uint8_t *sig, size_t siglen,
const uint8_t mu[MLDSA_CRHBYTES],
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(siglen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, siglen))
requires(memory_no_alias(mu, MLDSA_CRHBYTES))
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY)
);
/*************************************************
* Name: mld_sign_open
*
* Description: Verify signed message.
*
* Arguments: - uint8_t *m: pointer to output message (allocated array
* with smlen bytes), can be equal to sm
* - size_t *mlen: pointer to output length of message
* - const uint8_t *sm: pointer to signed message
* - size_t smlen: length of signed message
* - const uint8_t *ctx: pointer to context tring
* - size_t ctxlen: length of context string
* - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]:
* bit-packed public key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen,
const uint8_t *ctx, size_t ctxlen,
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(smlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(m, smlen))
requires(memory_no_alias(mlen, sizeof(size_t)))
requires(m == sm || memory_no_alias(sm, smlen))
requires(ctxlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(ctx, ctxlen))
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
assigns(memory_slice(m, smlen))
assigns(memory_slice(mlen, sizeof(size_t)))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY)
);
/*************************************************
* Name: mld_sign_signature_pre_hash_internal
*
* Description: FIPS 204: Algorithm 4 HashML-DSA.Sign.
* Computes signature with pre-hashed message.
*
* Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]:
* output signature
* - size_t *siglen: pointer to output length of signature
* - const uint8_t *ph: pointer to pre-hashed message
* - size_t phlen: length of pre-hashed message
* - const uint8_t *ctx: pointer to context string
* - size_t ctxlen: length of context string
* - const uint8_t rnd[MLDSA_RNDBYTES]:
* random seed
* - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]:
* bit-packed secret key
* - int hashalg: hash algorithm constant (one of
* MLD_PREHASH_*)
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Other kinds of failure
*
* Supported hash algorithm constants:
* MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384,
* MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256,
* MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384,
* MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256
*
* Warning: This is an unstable API that may change in the future. If you need
* a stable API use mld_sign_signature_pre_hash_shake256.
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_signature_pre_hash_internal(
uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *ph,
size_t phlen, const uint8_t *ctx, size_t ctxlen,
const uint8_t rnd[MLDSA_RNDBYTES],
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES], int hashalg,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(ctxlen <= MLD_MAX_BUFFER_SIZE)
requires(phlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
requires(memory_no_alias(siglen, sizeof(size_t)))
requires(memory_no_alias(ph, phlen))
requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))
requires(memory_no_alias(rnd, MLDSA_RNDBYTES))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
assigns(object_whole(siglen))
ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) ||
((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0))
);
/*************************************************
* Name: mld_sign_verify_pre_hash_internal
*
* Description: FIPS 204: Algorithm 5 HashML-DSA.Verify.
* Verifies signature with pre-hashed message.
*
* Arguments: - const uint8_t *sig: pointer to input signature
* - size_t siglen: length of signature
* - const uint8_t *ph: pointer to pre-hashed message
* - size_t phlen: length of pre-hashed message
* - const uint8_t *ctx: pointer to context string
* - size_t ctxlen: length of context string
* - const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]:
* bit-packed public key
* - int hashalg: hash algorithm constant (one of
* MLD_PREHASH_*)
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
* Supported hash algorithm constants:
* MLD_PREHASH_SHA2_224, MLD_PREHASH_SHA2_256, MLD_PREHASH_SHA2_384,
* MLD_PREHASH_SHA2_512, MLD_PREHASH_SHA2_512_224, MLD_PREHASH_SHA2_512_256,
* MLD_PREHASH_SHA3_224, MLD_PREHASH_SHA3_256, MLD_PREHASH_SHA3_384,
* MLD_PREHASH_SHA3_512, MLD_PREHASH_SHAKE_128, MLD_PREHASH_SHAKE_256
*
* Warning: This is an unstable API that may change in the future. If you need
* a stable API use mld_sign_verify_pre_hash_shake256.
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_verify_pre_hash_internal(
const uint8_t *sig, size_t siglen, const uint8_t *ph, size_t phlen,
const uint8_t *ctx, size_t ctxlen,
const uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], int hashalg,
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(phlen <= MLD_MAX_BUFFER_SIZE)
requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77)
requires(siglen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, siglen))
requires(memory_no_alias(ph, phlen))
requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY)
);
/*************************************************
* Name: mld_sign_signature_pre_hash_shake256
*
* Description: FIPS 204: Algorithm 4 HashML-DSA.Sign with SHAKE256.
* Computes signature with pre-hashed message using SHAKE256.
* This function computes the SHAKE256 hash of the message
*internally.
*
* Arguments: - uint8_t sig[MLDSA_CRYPTO_BYTES]:
* output signature
* - size_t *siglen: pointer to output length of signature
* - const uint8_t *m: pointer to message to be hashed and 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 rnd[MLDSA_RNDBYTES]:
* random seed
* - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]:
* bit-packed secret key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Other kinds of failure
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_signature_pre_hash_shake256(
uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen, const uint8_t *m,
size_t mlen, const uint8_t *ctx, size_t ctxlen,
const uint8_t rnd[MLDSA_RNDBYTES],
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(mlen <= MLD_MAX_BUFFER_SIZE)
requires(ctxlen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
requires(memory_no_alias(siglen, sizeof(size_t)))
requires(memory_no_alias(m, mlen))
requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))
requires(memory_no_alias(rnd, MLDSA_RNDBYTES))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
assigns(object_whole(siglen))
ensures((return_value == 0 && *siglen == MLDSA_CRYPTO_BYTES) ||
((return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY) && *siglen == 0))
);
/*************************************************
* Name: mld_sign_verify_pre_hash_shake256
*
* Description: FIPS 204: Algorithm 5 HashML-DSA.Verify with SHAKE256.
* Verifies signature with pre-hashed message using SHAKE256.
* This function computes the SHAKE256 hash of the message
* internally.
*
* Arguments: - const uint8_t *sig: pointer to input signature
* - size_t siglen: length of signature
* - const uint8_t *m: pointer to message to be hashed and
* verified
* - 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[MLDSA_CRYPTO_PUBLICKEYBYTES]:
* bit-packed public key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Signature verification failed
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_verify_pre_hash_shake256(
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[MLDSA_CRYPTO_PUBLICKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(mlen <= MLD_MAX_BUFFER_SIZE)
requires(ctxlen <= MLD_MAX_BUFFER_SIZE - 77)
requires(siglen <= MLD_MAX_BUFFER_SIZE)
requires(memory_no_alias(sig, siglen))
requires(memory_no_alias(m, mlen))
requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY)
);
/* Maximum formatted domain separation message length:
* - Pure ML-DSA: 0x00 || ctxlen || ctx (max 255)
* - HashML-DSA: 0x01 || ctxlen || ctx (max 255) || oid (11) || ph (max 64) */
#define MLD_DOMAIN_SEPARATION_MAX_BYTES (2 + 255 + 11 + 64)
/*************************************************
* Name: mld_prepare_domain_separation_prefix
*
* Description: Prepares domain separation prefix for ML-DSA signing.
* For pure ML-DSA (hashalg == MLD_PREHASH_NONE):
* Format: 0x00 || ctxlen (1 byte) || ctx
* For HashML-DSA (hashalg != MLD_PREHASH_NONE):
* Format: 0x01 || ctxlen (1 byte) || ctx || oid (11 bytes) || ph
*
* Arguments: - uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES]:
* output domain separation prefix buffer
* - const uint8_t *ph: pointer to pre-hashed message
* (ignored for pure ML-DSA)
* - size_t phlen: length of pre-hashed message
* (ignored for pure ML-DSA)
* - const uint8_t *ctx: pointer to context string (may be NULL)
* - size_t ctxlen: length of context string
* - int hashalg: hash algorithm constant
* (MLD_PREHASH_NONE for pure ML-DSA, or MLD_PREHASH_* for
* HashML-DSA)
*
* Returns the total length of the formatted prefix, or 0 on error.
*
* This function is useful for building incremental signing APIs.
*
* Specification:
* - For HashML-DSA (hashalg != MLD_PREHASH_NONE), implements
* @[FIPS204, Algorithm 4, L23]
* - For Pure ML-DSA (hashalg == MLD_PREHASH_NONE), implements
* ```
* M' <- BytesToBits(IntegerToBytes(0, 1)
* || IntegerToBytes(|ctx|, 1)
* || ctx
* ```
* which is part of @[FIPS204, Algorithm 2 (ML-DSA.Sign), L10] and
* @[FIPS204, Algorithm 3 (ML-DSA.Verify), L5].
*
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
size_t mld_prepare_domain_separation_prefix(
uint8_t prefix[MLD_DOMAIN_SEPARATION_MAX_BYTES], const uint8_t *ph,
size_t phlen, const uint8_t *ctx, size_t ctxlen, int hashalg)
__contract__(
requires(ctxlen <= 255)
requires(phlen <= MLD_MAX_BUFFER_SIZE)
requires(ctxlen == 0 || memory_no_alias(ctx, ctxlen))
requires(hashalg == MLD_PREHASH_NONE || memory_no_alias(ph, phlen))
requires(memory_no_alias(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES))
assigns(memory_slice(prefix, MLD_DOMAIN_SEPARATION_MAX_BYTES))
ensures(return_value <= MLD_DOMAIN_SEPARATION_MAX_BYTES)
);
/*************************************************
* Name: mld_sign_pk_from_sk
*
* Description: Performs basic validity checks on secret key, and derives
* public key.
*
* Referring to the decoding of the secret key
* `sk=(rho, K, tr, s1, s2, t0)`
* (cf. [@FIPS204, Algorithm 25 skDecode]),
* the following checks are performed:
* - Check that s1 and s2 have coefficients in
* [-MLDSA_ETA, MLDSA_ETA]
* - Check that t0 and tr stored in sk match recomputed values.
*
* Arguments: - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key
* - const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES]: input secret
* key
*
* Returns: - 0: Success
* - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
* used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
* - MLD_ERR_FAIL: Secret key validation failed
*
* Note: This function leaks whether the secret key is valid or invalid
* through its return value and timing.
**************************************************/
MLD_MUST_CHECK_RETURN_VALUE
MLD_EXTERNAL_API
int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
__contract__(
requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
ensures(return_value == 0 || return_value == MLD_ERR_FAIL || return_value == MLD_ERR_OUT_OF_MEMORY)
);
#endif /* !MLD_SIGN_H */

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_SYMMETRIC_H
#define MLD_SYMMETRIC_H
#include <stdint.h>
#include "cbmc.h"
#include "common.h"
#include MLD_FIPS202_HEADER_FILE
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY)
#include MLD_FIPS202X4_HEADER_FILE
#endif
#define MLD_STREAM128_BLOCKBYTES SHAKE128_RATE
#define MLD_STREAM256_BLOCKBYTES SHAKE256_RATE
#define mld_xof256_ctx mld_shake256ctx
#define mld_xof256_init(CTX) mld_shake256_init(CTX)
#define mld_xof256_absorb_once(CTX, IN, INBYTES) \
do \
{ \
mld_shake256_absorb(CTX, IN, INBYTES); \
mld_shake256_finalize(CTX); \
} while (0)
#define mld_xof256_release(CTX) mld_shake256_release(CTX)
#define mld_xof256_squeezeblocks(OUT, OUTBLOCKS, STATE) \
mld_shake256_squeeze(OUT, (OUTBLOCKS) * SHAKE256_RATE, STATE)
#define mld_xof128_ctx mld_shake128ctx
#define mld_xof128_init(CTX) mld_shake128_init(CTX)
#define mld_xof128_absorb_once(CTX, IN, INBYTES) \
do \
{ \
mld_shake128_absorb(CTX, IN, INBYTES); \
mld_shake128_finalize(CTX); \
} while (0)
#define mld_xof128_release(CTX) mld_shake128_release(CTX)
#define mld_xof128_squeezeblocks(OUT, OUTBLOCKS, STATE) \
mld_shake128_squeeze(OUT, (OUTBLOCKS) * SHAKE128_RATE, STATE)
#define mld_xof256_x4_ctx mld_shake256x4ctx
#define mld_xof256_x4_init(CTX) mld_shake256x4_init((CTX))
#define mld_xof256_x4_absorb(CTX, IN, INBYTES) \
mld_shake256x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \
(INBYTES))
#define mld_xof256_x4_squeezeblocks(BUF, NBLOCKS, CTX) \
mld_shake256x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \
(NBLOCKS), (CTX))
#define mld_xof256_x4_release(CTX) mld_shake256x4_release((CTX))
#define mld_xof128_x4_ctx mld_shake128x4ctx
#define mld_xof128_x4_init(CTX) mld_shake128x4_init((CTX))
#define mld_xof128_x4_absorb(CTX, IN, INBYTES) \
mld_shake128x4_absorb_once((CTX), (IN)[0], (IN)[1], (IN)[2], (IN)[3], \
(INBYTES))
#define mld_xof128_x4_squeezeblocks(BUF, NBLOCKS, CTX) \
mld_shake128x4_squeezeblocks((BUF)[0], (BUF)[1], (BUF)[2], (BUF)[3], \
(NBLOCKS), (CTX))
#define mld_xof128_x4_release(CTX) mld_shake128x4_release((CTX))
#endif /* !MLD_SYMMETRIC_H */

View File

@@ -0,0 +1,257 @@
/*
* Copyright (c) The mlkem-native project authors
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
#ifndef MLD_SYS_H
#define MLD_SYS_H
#if !defined(MLD_CONFIG_NO_ASM) && (defined(__GNUC__) || defined(__clang__))
#define MLD_HAVE_INLINE_ASM
#endif
/* Try to find endianness, if not forced through CFLAGS already */
#if !defined(MLD_SYS_LITTLE_ENDIAN) && !defined(MLD_SYS_BIG_ENDIAN)
#if defined(__BYTE_ORDER__)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define MLD_SYS_LITTLE_ENDIAN
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define MLD_SYS_BIG_ENDIAN
#else
#error "__BYTE_ORDER__ defined, but don't recognize value."
#endif
#endif /* __BYTE_ORDER__ */
/* MSVC does not define __BYTE_ORDER__. However, MSVC only supports
* little endian x86, x86_64, and AArch64. It is, hence, safe to assume
* little endian. */
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_AMD64) || \
defined(_M_IX86) || defined(_M_ARM64))
#define MLD_SYS_LITTLE_ENDIAN
#endif
#endif /* !MLD_SYS_LITTLE_ENDIAN && !MLD_SYS_BIG_ENDIAN */
/* Check if we're running on an AArch64 little endian system. _M_ARM64 is set by
* MSVC. */
#if defined(__AARCH64EL__) || defined(_M_ARM64)
#define MLD_SYS_AARCH64
#endif
/* Check if we're running on an AArch64 big endian system. */
#if defined(__AARCH64EB__)
#define MLD_SYS_AARCH64_EB
#endif
#if defined(__x86_64__)
#define MLD_SYS_X86_64
#if defined(__AVX2__)
#define MLD_SYS_X86_64_AVX2
#endif
#endif /* __x86_64__ */
#if defined(MLD_SYS_LITTLE_ENDIAN) && defined(__powerpc64__)
#define MLD_SYS_PPC64LE
#endif
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64
#define MLD_SYS_RISCV64
#endif
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32
#define MLD_SYS_RISCV32
#endif
#if defined(_WIN64) || defined(_WIN32)
#define MLD_SYS_WINDOWS
#endif
#if defined(__linux__)
#define MLD_SYS_LINUX
#endif
#if defined(__APPLE__)
#define MLD_SYS_APPLE
#endif
/* If MLD_FORCE_AARCH64 is set, assert that we're indeed on an AArch64 system.
*/
#if defined(MLD_FORCE_AARCH64) && !defined(MLD_SYS_AARCH64)
#error "MLD_FORCE_AARCH64 is set, but we don't seem to be on an AArch64 system."
#endif
/* If MLD_FORCE_AARCH64_EB is set, assert that we're indeed on a big endian
* AArch64 system. */
#if defined(MLD_FORCE_AARCH64_EB) && !defined(MLD_SYS_AARCH64_EB)
#error \
"MLD_FORCE_AARCH64_EB is set, but we don't seem to be on an AArch64 system."
#endif
/* If MLD_FORCE_X86_64 is set, assert that we're indeed on an X86_64 system. */
#if defined(MLD_FORCE_X86_64) && !defined(MLD_SYS_X86_64)
#error "MLD_FORCE_X86_64 is set, but we don't seem to be on an X86_64 system."
#endif
#if defined(MLD_FORCE_PPC64LE) && !defined(MLD_SYS_PPC64LE)
#error "MLD_FORCE_PPC64LE is set, but we don't seem to be on a PPC64LE system."
#endif
#if defined(MLD_FORCE_RISCV64) && !defined(MLD_SYS_RISCV64)
#error "MLD_FORCE_RISCV64 is set, but we don't seem to be on a RISCV64 system."
#endif
#if defined(MLD_FORCE_RISCV32) && !defined(MLD_SYS_RISCV32)
#error "MLD_FORCE_RISCV32 is set, but we don't seem to be on a RISCV32 system."
#endif
/*
* MLD_INLINE: Hint for inlining.
* - MSVC: __inline
* - C99+: inline
* - GCC/Clang C90: __attribute__((unused)) to silence warnings
* - Other C90: empty
*/
#if !defined(MLD_INLINE)
#if defined(_MSC_VER)
#define MLD_INLINE __inline
#elif defined(inline) || \
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
#define MLD_INLINE inline
#elif defined(__GNUC__) || defined(__clang__)
#define MLD_INLINE __attribute__((unused))
#else
#define MLD_INLINE
#endif
#endif /* !MLD_INLINE */
/*
* MLD_ALWAYS_INLINE: Force inlining.
* - MSVC: __forceinline
* - GCC/Clang C99+: MLD_INLINE __attribute__((always_inline))
* - Other: MLD_INLINE (no forced inlining)
*/
#if !defined(MLD_ALWAYS_INLINE)
#if defined(_MSC_VER)
#define MLD_ALWAYS_INLINE __forceinline
#elif (defined(__GNUC__) || defined(__clang__)) && \
(defined(inline) || \
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L))
#define MLD_ALWAYS_INLINE MLD_INLINE __attribute__((always_inline))
#else
#define MLD_ALWAYS_INLINE MLD_INLINE
#endif
#endif /* !MLD_ALWAYS_INLINE */
#ifndef MLD_STATIC_TESTABLE
#define MLD_STATIC_TESTABLE static
#endif
/*
* C90 does not have the restrict compiler directive yet.
* We don't use it in C90 builds.
*/
#if !defined(restrict)
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define MLD_RESTRICT restrict
#else
#define MLD_RESTRICT
#endif
#else /* !restrict */
#define MLD_RESTRICT restrict
#endif /* restrict */
#define MLD_DEFAULT_ALIGN 32
#define MLD_ALIGN_UP(N) \
((((N) + (MLD_DEFAULT_ALIGN - 1)) / MLD_DEFAULT_ALIGN) * MLD_DEFAULT_ALIGN)
#if defined(__GNUC__)
#define MLD_ALIGN __attribute__((aligned(MLD_DEFAULT_ALIGN)))
#elif defined(_MSC_VER)
#define MLD_ALIGN __declspec(align(MLD_DEFAULT_ALIGN))
#else
#define MLD_ALIGN /* No known support for alignment constraints */
#endif
/* New X86_64 CPUs support Conflow-flow protection using the CET instructions.
* When enabled (through -fcf-protection=), all compilation units (including
* empty ones) need to support CET for this to work.
* For assembly, this means that source files need to signal support for
* CET by setting the appropriate note.gnu.property section.
* This can be achieved by including the <cet.h> header in all assembly file.
* This file also provides the _CET_ENDBR macro which needs to be placed at
* every potential target of an indirect branch.
* If CET is enabled _CET_ENDBR maps to the endbr64 instruction, otherwise
* it is empty.
* In case the compiler does not support CET (e.g., <gcc8, <clang11),
* the __CET__ macro is not set and we default to nothing.
* Note that we only issue _CET_ENDBR instructions through the MLD_ASM_FN_SYMBOL
* macro as the global symbols are the only possible targets of indirect
* branches in our code.
*/
#if defined(MLD_SYS_X86_64)
#if defined(__CET__)
#include <cet.h>
#define MLD_CET_ENDBR _CET_ENDBR
#else
#define MLD_CET_ENDBR
#endif
#endif /* MLD_SYS_X86_64 */
#if defined(MLD_CONFIG_CT_TESTING_ENABLED) && !defined(__ASSEMBLER__)
#include <valgrind/memcheck.h>
#define MLD_CT_TESTING_SECRET(ptr, len) \
VALGRIND_MAKE_MEM_UNDEFINED((ptr), (len))
#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \
VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
#else /* MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__ */
#define MLD_CT_TESTING_SECRET(ptr, len) \
do \
{ \
} while (0)
#define MLD_CT_TESTING_DECLASSIFY(ptr, len) \
do \
{ \
} while (0)
#endif /* !(MLD_CONFIG_CT_TESTING_ENABLED && !__ASSEMBLER__) */
#if defined(__GNUC__) || defined(__clang__)
#define MLD_MUST_CHECK_RETURN_VALUE __attribute__((warn_unused_result))
#else
#define MLD_MUST_CHECK_RETURN_VALUE
#endif
#if !defined(__ASSEMBLER__)
/* System capability enumeration */
typedef enum
{
/* x86_64 */
MLD_SYS_CAP_AVX2,
/* AArch64 */
MLD_SYS_CAP_SHA3
} mld_sys_cap;
#if !defined(MLD_CONFIG_CUSTOM_CAPABILITY_FUNC)
#include "cbmc.h"
static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap)
__contract__(
ensures(return_value == 0 || return_value == 1)
)
{
/* By default, we rely on compile-time feature detection/specification:
* If a feature is enabled at compile-time, we assume it is supported by
* the host that the resulting library/binary will be built on.
* If this assumption is not true, you MUST overwrite this function.
* See the documentation of MLD_CONFIG_CUSTOM_CAPABILITY_FUNC in
* mldsa_native_config.h for more information. */
(void)cap;
return 1;
}
#endif /* !MLD_CONFIG_CUSTOM_CAPABILITY_FUNC */
#endif /* !__ASSEMBLER__ */
#endif /* !MLD_SYS_H */

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/*
* WARNING: This file is auto-generated from scripts/autogen
* in the mldsa-native repository.
* Do not modify it directly.
*/
#include <stdint.h>
/*
* Table of zeta values used in the reference NTT and inverse NTT.
* See autogen for details.
*/
static const int32_t mld_zetas[MLDSA_N] = {
0, 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,
};

View File

@@ -0,0 +1,119 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#ifndef MLD_CONFIG_H
#define MLD_CONFIG_H
#if !defined(__ASSEMBLER__)
#include "../../internal.h"
#endif
// Namespacing: All symbols are of the form mldsa*. Level-specific
// symbols are further prefixed with their security level, e.g.
// mldsa44*, mldsa65*, mldsa87*.
#define MLD_CONFIG_NAMESPACE_PREFIX mldsa
// Replace mldsa-native's FIPS 202 headers with glue code to
// AWS-LC's own FIPS 202 implementation.
#define MLD_CONFIG_FIPS202_CUSTOM_HEADER "../fips202_glue.h"
#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER "../fips202x4_glue.h"
// Everything is built in a single CU, so both internal and external
// mldsa-native API can have internal linkage.
// Mark as unused to suppress warnings for functions we don't expose
#if defined(__GNUC__) || defined(__clang__)
#define MLD_CONFIG_INTERNAL_API_QUALIFIER static __attribute__((unused))
#define MLD_CONFIG_EXTERNAL_API_QUALIFIER static __attribute__((unused))
#else
#define MLD_CONFIG_INTERNAL_API_QUALIFIER static
#define MLD_CONFIG_EXTERNAL_API_QUALIFIER static
#endif
// Enable PCT if and only if AWS-LC is built in FIPS-mode.
#if defined(AWSLC_FIPS)
#define MLD_CONFIG_KEYGEN_PCT
#endif
// Map the CPU capability function to the ones used by AWS-LC
#define MLD_CONFIG_CUSTOM_CAPABILITY_FUNC
#if !defined(__ASSEMBLER__)
#include <stdint.h>
#include "mldsa/sys.h"
static MLD_INLINE int mld_sys_check_capability(mld_sys_cap cap)
{
#if defined(MLD_SYS_X86_64)
if (cap == MLD_SYS_CAP_AVX2)
{
return CRYPTO_is_AVX2_capable();
}
#endif
return 0;
}
#endif
#if defined(BORINGSSL_FIPS_BREAK_TESTS)
#define MLD_CONFIG_KEYGEN_PCT_BREAKAGE_TEST
#if !defined(__ASSEMBLER__) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)
#include "mldsa/sys.h"
static MLD_INLINE int mld_break_pct(void) {
return boringssl_fips_break_test("MLDSA_PWCT");
}
#endif // !__ASSEMBLER__
#endif // BORINGSSL_FIPS_BREAK_TESTS
// Enable valgrind-based assertions in mldsa-native through macro
// from AWS-LC/BoringSSL.
#if defined(BORINGSSL_CONSTANT_TIME_VALIDATION)
#define MLD_CONFIG_CT_TESTING_ENABLED
#endif
// Map zeroization function to the one used by AWS-LC
#define MLD_CONFIG_CUSTOM_ZEROIZE
#if !defined(__ASSEMBLER__) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)
#include <stdint.h>
#include "mldsa/sys.h"
#include <openssl/base.h>
static MLD_INLINE void mld_zeroize(void *ptr, size_t len) {
OPENSSL_cleanse(ptr, len);
}
#endif // !__ASSEMBLER__
// Map randombytes function to the one used by AWS-LC
// Note: mldsa-native expects int return (0 on success, non-zero on failure)
// unlike mlkem-native which expects void return
#define MLD_CONFIG_CUSTOM_RANDOMBYTES
#if !defined(__ASSEMBLER__) && !defined(MLD_CONFIG_MULTILEVEL_NO_SHARED)
#include <stdint.h>
#include "mldsa/sys.h"
#include <openssl/rand.h>
static MLD_INLINE int mld_randombytes(uint8_t *ptr, size_t len) {
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(ptr, len));
return 0;
}
#endif // !__ASSEMBLER__
// Map memcpy function to the one used by AWS-LC
#define MLD_CONFIG_CUSTOM_MEMCPY
#if !defined(__ASSEMBLER__)
#include <stdint.h>
#include "mldsa/sys.h"
static MLD_INLINE void *mld_memcpy(void *dest, const void *src, size_t n) {
return OPENSSL_memcpy(dest, src, n);
}
#endif // !__ASSEMBLER__
// Map memset function to the one used by AWS-LC
#define MLD_CONFIG_CUSTOM_MEMSET
#if !defined(__ASSEMBLER__)
#include <stdint.h>
#include "mldsa/sys.h"
static MLD_INLINE void *mld_memset(void *s, int c, size_t n) {
return OPENSSL_memset(s, c, n);
}
#endif // !__ASSEMBLER__
#if defined(OPENSSL_NO_ASM)
#define MLD_CONFIG_NO_ASM
#endif
#endif // MLD_CONFIG_H