Botan 3.11.0
Crypto and TLS for C&
dilithium_symmetric_primitives.h
Go to the documentation of this file.
1/*
2* Symmetric primitives for dilithium
3*
4* (C) 2022-2023 Jack Lloyd
5* (C) 2022-2023 Michael Boric, René Meusel - Rohde & Schwarz Cybersecurity
6* (C) 2022 Manuel Glaser - Rohde & Schwarz Cybersecurity
7*
8* Botan is released under the Simplified BSD License (see license.txt)
9*/
10
11#ifndef BOTAN_DILITHIUM_ASYM_PRIMITIVES_H_
12#define BOTAN_DILITHIUM_ASYM_PRIMITIVES_H_
13
14#include <botan/dilithium.h>
15#include <botan/xof.h>
16#include <botan/internal/dilithium_types.h>
17
18namespace Botan {
19
21
22/**
23 * Wrapper type for the H() function calculating the message representative for
24 * the Dilithium signature scheme. This wrapper may be used multiple times.
25 *
26 * Namely: mu = H(tr || M)
27 */
28class DilithiumMessageHash /* NOLINT(*-special-member-functions) */ {
29 public:
31
33
34 std::string name() const;
35
36 virtual bool is_valid_user_context(std::span<const uint8_t> user_context) const {
37 // Only ML-DSA supports user contexts, for all other modes it must be empty.
38 return user_context.empty();
39 }
40
41 virtual void start(std::span<const uint8_t> user_context) {
42 BOTAN_STATE_CHECK(!m_was_started);
43 BOTAN_ARG_CHECK(is_valid_user_context(user_context), "Invalid user context");
44 m_was_started = true;
45 update(m_tr); // see calculation of mu in FIPS 204, Algorithm 7, line 6
46 }
47
48 void update(std::span<const uint8_t> data) {
49 ensure_started();
50 m_shake->update(data);
51 }
52
54 ensure_started();
55 const scoped_cleanup clean([this]() { clear(); });
57 }
58
59 private:
60 void clear() {
61 m_shake->clear();
62 m_was_started = false;
63 }
64
65 void ensure_started() {
66 if(!m_was_started) {
67 // FIPS 204, page 17, footnote 4: By default, the context is the empty string [...]
68 start({});
69 }
70 }
71
72 private:
74 bool m_was_started = false;
75 std::unique_ptr<XOF> m_shake;
76};
77
78/**
79* Implemented by the derived classes to create the correct XOF instance. This is
80* a customization point to enable support for the AES variant of Dilithium. This
81* was not standardized in the FIPS 204; ML-DSA always uses SHAKE. Once we decide
82* to remove the AES variant, this can be removed.
83*/
84class DilithiumXOF /* NOLINT(*-special-member-functions) */ {
85 public:
86 virtual ~DilithiumXOF() = default;
87
88 virtual std::unique_ptr<XOF> XOF128(std::span<const uint8_t> seed, uint16_t nonce) const = 0;
89 virtual std::unique_ptr<XOF> XOF256(std::span<const uint8_t> seed, uint16_t nonce) const = 0;
90};
91
92/**
93* Adapter class that uses polymorphy to distinguish
94* Dilithium "common" from Dilithium "AES" modes.
95*/
97 protected:
98 Dilithium_Symmetric_Primitives_Base(const DilithiumConstants& mode, std::unique_ptr<DilithiumXOF> xof_adapter);
99
100 public:
101 static std::unique_ptr<Dilithium_Symmetric_Primitives_Base> create(const DilithiumConstants& mode);
102
108
109 virtual std::unique_ptr<DilithiumMessageHash> get_message_hash(DilithiumHashedPublicKey tr) const {
110 return std::make_unique<DilithiumMessageHash>(std::move(tr));
111 }
112
113 /// Computes the private random seed rho prime used for signing
114 /// if a @p rng is given, the seed is randomized
118 std::optional<std::reference_wrapper<RandomNumberGenerator>> rng) const = 0;
119
123
124 std::tuple<DilithiumSeedRho, DilithiumSeedRhoPrime, DilithiumSigningSeedK> H(
126 auto xof = XOF::create_or_throw("SHAKE-256");
127 xof->update(seed);
128 if(auto domsep = seed_expansion_domain_separator()) {
129 xof->update(domsep.value());
130 }
131
132 // Note: The order of invocations in an initializer list is not
133 // guaranteed by the C++ standard. Hence, we have to store the
134 // results in variables to ensure the correct order of execution.
138
139 return {std::move(rho), std::move(rhoprime), std::move(k)};
140 }
141
146
147 std::unique_ptr<XOF> H(StrongSpan<const DilithiumCommitmentHash> seed) const {
148 auto xof = XOF::create_or_throw("SHAKE-256");
149 xof->update(truncate_commitment_hash(seed));
150 return xof;
151 }
152
153 std::unique_ptr<XOF> H(StrongSpan<const DilithiumSeedRho> seed, uint16_t nonce) const {
154 return m_xof_adapter->XOF128(seed, nonce);
155 }
156
157 std::unique_ptr<XOF> H(StrongSpan<const DilithiumSeedRhoPrime> seed, uint16_t nonce) const {
158 return m_xof_adapter->XOF256(seed, nonce);
159 }
160
161 protected:
162 /**
163 * Implemented by the derived classes to truncate the commitment hash
164 * to the correct length. This is a customization point to enable support
165 * for the final ML-DSA standard.
166 */
169
170 /**
171 * Creates the domain separator for the initial seed expansion.
172 * The return value may be std::nullopt meaning that no domain separation
173 * is required (for Dilithium).
174 */
175 virtual std::optional<std::array<uint8_t, 2>> seed_expansion_domain_separator() const = 0;
176
178 OutT H_256(size_t outbytes, const InTs&... ins) const {
179 auto xof = XOF::create_or_throw("SHAKE-256");
180 (xof->update(ins), ...);
181 return xof->output<OutT>(outbytes);
182 }
183
184 private:
185 size_t m_commitment_hash_length_bytes;
186 size_t m_public_key_hash_bytes;
187 DilithiumMode m_mode;
188
189 std::unique_ptr<DilithiumXOF> m_xof_adapter;
190};
191
192} // namespace Botan
193
194#endif
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
static constexpr size_t MESSAGE_HASH_BYTES
static constexpr size_t SEED_SIGNING_KEY_BYTES
static constexpr size_t SEED_RHOPRIME_BYTES
static constexpr size_t SEED_RHO_BYTES
virtual void start(std::span< const uint8_t > user_context)
DilithiumMessageHash(DilithiumHashedPublicKey tr)
void update(std::span< const uint8_t > data)
virtual bool is_valid_user_context(std::span< const uint8_t > user_context) const
virtual ~DilithiumXOF()=default
virtual std::unique_ptr< XOF > XOF256(std::span< const uint8_t > seed, uint16_t nonce) const =0
virtual std::unique_ptr< XOF > XOF128(std::span< const uint8_t > seed, uint16_t nonce) const =0
Dilithium_Symmetric_Primitives_Base(Dilithium_Symmetric_Primitives_Base &&)=delete
std::unique_ptr< XOF > H(StrongSpan< const DilithiumSeedRhoPrime > seed, uint16_t nonce) const
Dilithium_Symmetric_Primitives_Base & operator=(const Dilithium_Symmetric_Primitives_Base &)=delete
static std::unique_ptr< Dilithium_Symmetric_Primitives_Base > create(const DilithiumConstants &mode)
Dilithium_Symmetric_Primitives_Base(const Dilithium_Symmetric_Primitives_Base &)=delete
std::unique_ptr< XOF > H(StrongSpan< const DilithiumCommitmentHash > seed) const
std::unique_ptr< XOF > H(StrongSpan< const DilithiumSeedRho > seed, uint16_t nonce) const
OutT H_256(size_t outbytes, const InTs &... ins) const
DilithiumHashedPublicKey H(StrongSpan< const DilithiumSerializedPublicKey > pk) const
virtual ~Dilithium_Symmetric_Primitives_Base()=default
virtual std::optional< std::array< uint8_t, 2 > > seed_expansion_domain_separator() const =0
std::tuple< DilithiumSeedRho, DilithiumSeedRhoPrime, DilithiumSigningSeedK > H(StrongSpan< const DilithiumSeedRandomness > seed) const
virtual DilithiumSeedRhoPrime H_maybe_randomized(StrongSpan< const DilithiumSigningSeedK > k, StrongSpan< const DilithiumMessageRepresentative > mu, std::optional< std::reference_wrapper< RandomNumberGenerator > > rng) const =0
Dilithium_Symmetric_Primitives_Base(const DilithiumConstants &mode, std::unique_ptr< DilithiumXOF > xof_adapter)
virtual StrongSpan< const DilithiumCommitmentHash > truncate_commitment_hash(StrongSpan< const DilithiumCommitmentHash > seed) const =0
DilithiumCommitmentHash H(StrongSpan< const DilithiumMessageRepresentative > mu, StrongSpan< const DilithiumSerializedCommitment > w1) const
virtual std::unique_ptr< DilithiumMessageHash > get_message_hash(DilithiumHashedPublicKey tr) const
Dilithium_Symmetric_Primitives_Base & operator=(Dilithium_Symmetric_Primitives_Base &&)=delete
static std::unique_ptr< XOF > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition xof.cpp:54
Helper class to create a RAII-style cleanup callback.
Strong< secure_vector< uint8_t >, struct DilithiumSeedRhoPrime_ > DilithiumSeedRhoPrime
Private seed to sample the polynomial vectors s1 and s2 from.
Strong< std::vector< uint8_t >, struct DilithiumMessageRepresentative_ > DilithiumMessageRepresentative
Representation of the message to be signed.
Strong< secure_vector< uint8_t >, struct DilithiumSeedK_ > DilithiumSigningSeedK
Private seed K used during signing.
Strong< std::vector< uint8_t >, struct DilithiumPublicSeed_ > DilithiumSeedRho
Public seed to sample the polynomial matrix A from.
Strong< std::vector< uint8_t >, struct DilithiumCommitmentHash_ > DilithiumCommitmentHash
Hash of the message representative and the signer's commitment.
BOTAN_FORCE_INLINE constexpr T rho(T x)
Definition rotate.h:53
Strong< std::vector< uint8_t >, struct DilithiumHashedPublicKey_ > DilithiumHashedPublicKey