/src/botan/build/include/internal/botan/internal/ml_dsa_impl.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Asymmetric primitives for ML-DSA |
3 | | * (C) 2024 Jack Lloyd |
4 | | * (C) 2024 Fabian Albert, René Meusel - Rohde & Schwarz Cybersecurity |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #ifndef BOTAN_ML_DSA_SYM_PRIMITIVES_H_ |
10 | | #define BOTAN_ML_DSA_SYM_PRIMITIVES_H_ |
11 | | |
12 | | #include <botan/internal/dilithium_symmetric_primitives.h> |
13 | | |
14 | | #include <botan/rng.h> |
15 | | #include <botan/internal/dilithium_keys.h> |
16 | | #include <botan/internal/dilithium_shake_xof.h> |
17 | | #include <botan/internal/int_utils.h> |
18 | | |
19 | | namespace Botan { |
20 | | |
21 | | class ML_DSA_Expanding_Keypair_Codec final : public Dilithium_Keypair_Codec { |
22 | | public: |
23 | | secure_vector<uint8_t> encode_keypair(DilithiumInternalKeypair keypair) const override; |
24 | | DilithiumInternalKeypair decode_keypair(std::span<const uint8_t> private_key, |
25 | | DilithiumConstants mode) const override; |
26 | | }; |
27 | | |
28 | | class ML_DSA_MessageHash final : public DilithiumMessageHash { |
29 | | public: |
30 | | using DilithiumMessageHash::DilithiumMessageHash; |
31 | | |
32 | 0 | bool is_valid_user_context(std::span<const uint8_t> user_context) const final { |
33 | 0 | return user_context.size() <= 255; |
34 | 0 | } |
35 | | |
36 | 0 | void start(std::span<const uint8_t> user_context) final { |
37 | | // ML-DSA introduced an application-specific context string that is |
38 | | // empty by default and can be set by the application. |
39 | | // |
40 | | // In HashML-DSA, there's an additional domain information, namely |
41 | | // the serialized OID of the hash function used to hash the message. |
42 | | // |
43 | | // See FIPS 204, Algorithm 2, line 10 and Algorithm 7, line 6, and |
44 | | // FIPS 204, Section 5.4 |
45 | |
|
46 | 0 | DilithiumMessageHash::start(user_context); |
47 | 0 | constexpr uint8_t domain_separator = 0x00; // HashML-DSA would use 0x01 |
48 | 0 | const uint8_t context_length = checked_cast_to<uint8_t>(user_context.size()); |
49 | 0 | update(std::array{domain_separator, context_length}); |
50 | 0 | update(user_context); |
51 | 0 | } |
52 | | }; |
53 | | |
54 | | class ML_DSA_Symmetric_Primitives final : public Dilithium_Symmetric_Primitives_Base { |
55 | | private: |
56 | | /// Rho prime computation for ML-DSA |
57 | | DilithiumSeedRhoPrime H(StrongSpan<const DilithiumSigningSeedK> k, |
58 | | StrongSpan<const DilithiumOptionalRandomness> rnd, |
59 | 0 | StrongSpan<const DilithiumMessageRepresentative> mu) const { |
60 | 0 | return H_256<DilithiumSeedRhoPrime>(DilithiumConstants::SEED_RHOPRIME_BYTES, k, rnd, mu); |
61 | 0 | } |
62 | | |
63 | | public: |
64 | | ML_DSA_Symmetric_Primitives(const DilithiumConstants& mode) : |
65 | 17 | Dilithium_Symmetric_Primitives_Base(mode, std::make_unique<DilithiumShakeXOF>()), |
66 | 17 | m_seed_expansion_domain_separator({mode.k(), mode.l()}) {} |
67 | | |
68 | | DilithiumSeedRhoPrime H_maybe_randomized( |
69 | | StrongSpan<const DilithiumSigningSeedK> k, |
70 | | StrongSpan<const DilithiumMessageRepresentative> mu, |
71 | 0 | std::optional<std::reference_wrapper<RandomNumberGenerator>> rng) const override { |
72 | | // NIST FIPS 204, Algorithm 2 (ML-DSA.Sign), line 5-8: |
73 | 0 | const auto rnd = [&] { |
74 | 0 | DilithiumOptionalRandomness optional_randomness(DilithiumConstants::OPTIONAL_RANDOMNESS_BYTES); |
75 | 0 | if(rng.has_value()) { |
76 | 0 | rng->get().randomize(optional_randomness); |
77 | 0 | } |
78 | 0 | return optional_randomness; |
79 | 0 | }(); |
80 | 0 | return H(k, rnd, mu); |
81 | 0 | } |
82 | | |
83 | | StrongSpan<const DilithiumCommitmentHash> truncate_commitment_hash( |
84 | 0 | StrongSpan<const DilithiumCommitmentHash> seed) const override { |
85 | 0 | return seed; |
86 | 0 | } |
87 | | |
88 | 0 | std::unique_ptr<DilithiumMessageHash> get_message_hash(DilithiumHashedPublicKey tr) const override { |
89 | 0 | return std::make_unique<ML_DSA_MessageHash>(std::move(tr)); |
90 | 0 | } |
91 | | |
92 | 0 | std::optional<std::array<uint8_t, 2>> seed_expansion_domain_separator() const override { |
93 | 0 | return m_seed_expansion_domain_separator; |
94 | 0 | } |
95 | | |
96 | | private: |
97 | | std::array<uint8_t, 2> m_seed_expansion_domain_separator; |
98 | | }; |
99 | | |
100 | | } // namespace Botan |
101 | | |
102 | | #endif |