15#include <botan/dilithium.h>
17#include <botan/exceptn.h>
20#include <botan/internal/dilithium_algos.h>
21#include <botan/internal/dilithium_keys.h>
22#include <botan/internal/dilithium_symmetric_primitives.h>
23#include <botan/internal/dilithium_types.h>
24#include <botan/internal/fmt.h>
25#include <botan/internal/pk_ops_impl.h>
26#include <botan/internal/stl_util.h>
32 if(str ==
"Dilithium-4x4-r3") {
35 if(str ==
"Dilithium-4x4-AES-r3") {
38 if(str ==
"Dilithium-6x5-r3") {
41 if(str ==
"Dilithium-6x5-AES-r3") {
44 if(str ==
"Dilithium-8x7-r3") {
47 if(str ==
"Dilithium-8x7-AES-r3") {
50 if(str ==
"ML-DSA-4x4") {
53 if(str ==
"ML-DSA-6x5") {
56 if(str ==
"ML-DSA-8x7") {
60 throw Invalid_Argument(
fmt(
"'{}' is not a valid Dilithium mode name", str));
76 return "Dilithium-4x4-r3";
78 return "Dilithium-4x4-AES-r3";
80 return "Dilithium-6x5-r3";
82 return "Dilithium-6x5-AES-r3";
84 return "Dilithium-8x7-r3";
86 return "Dilithium-8x7-AES-r3";
111#if defined(BOTAN_HAS_DILITHIUM_AES)
116#if defined(BOTAN_HAS_DILITHIUM)
121#if defined(BOTAN_HAS_ML_DSA)
132 m_keypair(std::move(keypair)),
133 m_randomized(randomized),
134 m_h(m_keypair.second->mode().symmetric_primitives().get_message_hash(m_keypair.first->tr())),
135 m_s1(ntt(m_keypair.second->s1().clone())),
136 m_s2(ntt(m_keypair.second->s2().clone())),
137 m_t0(ntt(m_keypair.second->t0().clone())),
138 m_A(Dilithium_Algos::expand_A(m_keypair.first->
rho(), m_keypair.second->mode())) {}
140 void update(std::span<const uint8_t> input)
override { m_h->update(input); }
153 std::vector<uint8_t> sign(RandomNumberGenerator& rng)
override {
156 const auto mu = m_h->final();
157 const auto& mode = m_keypair.second->mode();
158 const auto& sympri = mode.symmetric_primitives();
160 const auto rhoprime = sympri.H_maybe_randomized(m_keypair.second->signing_seed(), mu, maybe(rng));
166 auto w_ntt = m_A *
ntt(y.clone());
169 w.conditional_add_q();
205 w0.conditional_add_q();
206 const auto& w0cs2ct0 = w0;
217 throw Internal_Error(
"ML-DSA/Dilithium signature loop did not terminate");
220 size_t signature_length()
const override {
return m_keypair.second->mode().signature_bytes(); }
222 AlgorithmIdentifier algorithm_identifier()
const override {
223 return AlgorithmIdentifier(m_keypair.second->mode().mode().object_identifier(),
227 std::string hash_function()
const override {
return m_h->name(); }
230 std::optional<std::reference_wrapper<RandomNumberGenerator>> maybe(RandomNumberGenerator& rng)
const {
241 std::unique_ptr<DilithiumMessageHash> m_h;
249class Dilithium_Verification_Operation
final :
public PK_Ops::Verification {
251 Dilithium_Verification_Operation(std::shared_ptr<Dilithium_PublicKeyInternal> pubkey) :
252 m_pub_key(std::move(pubkey)),
253 m_A(Dilithium_Algos::
expand_A(m_pub_key->
rho(), m_pub_key->mode())),
254 m_t1_ntt_shifted(
ntt(m_pub_key->t1() << DilithiumConstants::D)),
255 m_h(m_pub_key->mode().symmetric_primitives().get_message_hash(m_pub_key->tr())) {}
257 void update(std::span<const uint8_t> input)
override { m_h->update(input); }
269 bool is_valid_signature(std::span<const uint8_t> sig)
override {
270 const auto& mode = m_pub_key->mode();
271 const auto& sympri = mode.symmetric_primitives();
272 StrongSpan<const DilithiumSerializedSignature> sig_bytes(sig);
274 if(sig_bytes.size() != mode.signature_bytes()) {
278 const auto mu = m_h->final();
281 if(!signature.has_value()) {
284 auto [ch, z, h] = std::move(signature.value());
287 if(h.hamming_weight() > mode.omega() ||
293 auto w_approx = m_A *
ntt(std::move(z));
294 w_approx -= c_hat * m_t1_ntt_shifted;
297 w1.conditional_add_q();
303 return std::equal(ch.begin(), ch.end(), chprime.begin());
306 std::string hash_function()
const override {
return m_h->name(); }
309 std::shared_ptr<Dilithium_PublicKeyInternal> m_pub_key;
312 std::unique_ptr<DilithiumMessageHash> m_h;
322 "dilithium public key does not have the correct byte count");
344 return m_public->mode().mode().object_identifier();
348 return m_public->mode().canonical_parameter_set_identifier();
370 return std::make_unique<Dilithium_PrivateKey>(rng,
m_public->mode().mode());
374 std::string_view provider)
const {
375 BOTAN_ARG_CHECK(params.empty() || params ==
"Pure",
"Unexpected parameters for verifying with Dilithium");
376 if(provider.empty() || provider ==
"base") {
377 return std::make_unique<Dilithium_Verification_Operation>(
m_public);
384 if(provider.empty() || provider ==
"base") {
386 throw Decoding_Error(
"Unexpected AlgorithmIdentifier for Dilithium X.509 signature");
388 return std::make_unique<Dilithium_Verification_Operation>(
m_public);
424 return m_private->mode().keypair_codec().encode_keypair({
m_public, m_private});
428 std::string_view params,
429 std::string_view provider)
const {
432 BOTAN_ARG_CHECK(params.empty() || params ==
"Deterministic" || params ==
"Randomized",
433 "Unexpected parameters for signing with ML-DSA/Dilithium");
439 const bool randomized = (params.empty() || params ==
"Randomized");
440 if(provider.empty() || provider ==
"base") {
447 return std::make_unique<Dilithium_PublicKey>(*
this);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT_UNREACHABLE()
ThisPolynomialVector & reduce()
size_t public_key_bytes() const
byte length of the encoded public key
static constexpr size_t SEED_RANDOMNESS_BYTES
DilithiumMode mode() const
Dilithium_Keypair_Codec & keypair_codec() const
static constexpr uint16_t SIGNING_LOOP_BOUND
OID object_identifier() const
std::string to_string() const
bool is_dilithium_round3() const
bool is_available() const
virtual DilithiumInternalKeypair decode_keypair(std::span< const uint8_t > private_key, DilithiumConstants mode) const =0
Dilithium_PrivateKey(RandomNumberGenerator &rng, DilithiumMode mode)
secure_vector< uint8_t > raw_private_key_bits() const override
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &, std::string_view params, std::string_view provider) const override
secure_vector< uint8_t > private_key_bits() const override
std::unique_ptr< Public_Key > public_key() const override
static std::shared_ptr< Dilithium_PublicKeyInternal > decode(DilithiumConstants mode, StrongSpan< const DilithiumSerializedPublicKey > raw_pk)
AlgorithmIdentifier algorithm_identifier() const override
std::vector< uint8_t > public_key_bits() const override
OID object_identifier() const override
bool check_key(RandomNumberGenerator &, bool) const override
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
std::unique_ptr< PK_Ops::Verification > create_x509_verification_op(const AlgorithmIdentifier &signature_algorithm, std::string_view provider) const override
size_t key_length() const override
std::string algo_name() const override
size_t estimated_strength() const override
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
Dilithium_PublicKey()=default
std::vector< uint8_t > raw_public_key_bits() const override
std::shared_ptr< Dilithium_PublicKeyInternal > m_public
std::string to_formatted_string() const
static OID from_string(std::string_view str)
void random_vec(std::span< uint8_t > v)
int(* update)(CTX *, const void *, CC_LONG len)
int(* final)(unsigned char *, CTX *)
Polynomial< Trait, Domain::NTT > ntt(Polynomial< Trait, Domain::Normal > p)
Polynomial< Trait, Domain::Normal > inverse_ntt(Polynomial< Trait, Domain::NTT > p_ntt)
decltype(auto) driveby_unpoison(T &&v)
constexpr auto scoped_poison(const Ts &... xs)
constexpr void unpoison(const T *p, size_t n)
constexpr void poison(const T *p, size_t n)
DilithiumInternalKeypair expand_keypair(DilithiumSeedRandomness xi, DilithiumConstants mode)
DilithiumSerializedSignature encode_signature(StrongSpan< const DilithiumCommitmentHash > c, const DilithiumPolyVec &response, const DilithiumPolyVec &hint, const DilithiumConstants &mode)
DilithiumSerializedCommitment encode_commitment(const DilithiumPolyVec &w1, const DilithiumConstants &mode)
bool infinity_norm_within_bound(const DilithiumPolyVec &vec, size_t bound)
std::pair< DilithiumPolyVec, DilithiumPolyVec > decompose(const DilithiumPolyVec &vec, const DilithiumConstants &mode)
DilithiumPolyVec expand_mask(StrongSpan< const DilithiumSeedRhoPrime > rhoprime, uint16_t nonce, const DilithiumConstants &mode)
DilithiumPolyMatNTT expand_A(StrongSpan< const DilithiumSeedRho > rho, const DilithiumConstants &mode)
void use_hint(DilithiumPolyVec &vec, const DilithiumPolyVec &hints, const DilithiumConstants &mode)
std::optional< std::tuple< DilithiumCommitmentHash, DilithiumPolyVec, DilithiumPolyVec > > decode_signature(StrongSpan< const DilithiumSerializedSignature > sig, const DilithiumConstants &mode)
DilithiumPolyVec make_hint(const DilithiumPolyVec &z, const DilithiumPolyVec &r, const DilithiumConstants &mode)
DilithiumPoly sample_in_ball(StrongSpan< const DilithiumCommitmentHash > seed, const DilithiumConstants &mode)
Botan::CRYSTALS::PolynomialVector< DilithiumPolyTraits, Botan::CRYSTALS::Domain::NTT > DilithiumPolyVecNTT
std::string fmt(std::string_view format, const T &... args)
std::vector< T, secure_allocator< T > > secure_vector
Botan::CRYSTALS::PolynomialMatrix< DilithiumPolyTraits > DilithiumPolyMatNTT
auto to_underlying(T e) noexcept
std::pair< std::shared_ptr< Dilithium_PublicKeyInternal >, std::shared_ptr< Dilithium_PrivateKeyInternal > > DilithiumInternalKeypair
Internal representation of a Dilithium key pair.