Botan 3.10.0
Crypto and TLS for C&
Botan::Dilithium_Algos Namespace Reference

Functions

std::pair< DilithiumSeedRho, DilithiumPolyVecdecode_public_key (StrongSpan< const DilithiumSerializedPublicKey > pk, const DilithiumConstants &mode)
std::optional< std::tuple< DilithiumCommitmentHash, DilithiumPolyVec, DilithiumPolyVec > > decode_signature (StrongSpan< const DilithiumSerializedSignature > sig, const DilithiumConstants &mode)
std::pair< DilithiumPolyVec, DilithiumPolyVecdecompose (const DilithiumPolyVec &vec, const DilithiumConstants &mode)
DilithiumSerializedCommitment encode_commitment (const DilithiumPolyVec &w1, const DilithiumConstants &mode)
DilithiumSerializedPublicKey encode_public_key (StrongSpan< const DilithiumSeedRho > rho, const DilithiumPolyVec &t1, const DilithiumConstants &mode)
DilithiumSerializedSignature encode_signature (StrongSpan< const DilithiumCommitmentHash > c, const DilithiumPolyVec &response, const DilithiumPolyVec &hint, const DilithiumConstants &mode)
DilithiumPolyMatNTT expand_A (StrongSpan< const DilithiumSeedRho > rho, const DilithiumConstants &mode)
DilithiumInternalKeypair expand_keypair (DilithiumSeedRandomness xi, DilithiumConstants mode)
DilithiumPolyVec expand_mask (StrongSpan< const DilithiumSeedRhoPrime > rhoprime, uint16_t nonce, const DilithiumConstants &mode)
std::pair< DilithiumPolyVec, DilithiumPolyVecexpand_s (StrongSpan< const DilithiumSeedRhoPrime > rhoprime, const DilithiumConstants &mode)
bool infinity_norm_within_bound (const DilithiumPolyVec &vec, size_t bound)
DilithiumPolyVec make_hint (const DilithiumPolyVec &z, const DilithiumPolyVec &r, const DilithiumConstants &mode)
std::pair< DilithiumPolyVec, DilithiumPolyVecpower2round (const DilithiumPolyVec &vec)
DilithiumPoly sample_in_ball (StrongSpan< const DilithiumCommitmentHash > seed, const DilithiumConstants &mode)
void use_hint (DilithiumPolyVec &vec, const DilithiumPolyVec &hints, const DilithiumConstants &mode)

Function Documentation

◆ decode_public_key()

std::pair< DilithiumSeedRho, DilithiumPolyVec > Botan::Dilithium_Algos::decode_public_key ( StrongSpan< const DilithiumSerializedPublicKey > pk,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 23 (pkDecode)

Definition at line 344 of file dilithium_algos.cpp.

345 {
346 if(pk.size() != mode.public_key_bytes()) {
347 throw Decoding_Error("Dilithium: Invalid public key length");
348 }
349
350 BufferSlicer slicer(pk);
352
353 DilithiumPolyVec t1(mode.k());
354 for(auto& p : t1) {
355 poly_unpack_t1(p, slicer);
356 }
357 BOTAN_ASSERT_NOMSG(slicer.empty());
358
359 return {std::move(rho), std::move(t1)};
360}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
size_t public_key_bytes() const
byte length of the encoded public key
uint8_t k() const
dimensions of the expanded matrix A
static constexpr size_t SEED_RHO_BYTES
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
Botan::CRYSTALS::PolynomialVector< DilithiumPolyTraits, Botan::CRYSTALS::Domain::Normal > DilithiumPolyVec
Strong< std::vector< uint8_t >, struct DilithiumPublicSeed_ > DilithiumSeedRho
Public seed to sample the polynomial matrix A from.
BOTAN_FORCE_INLINE constexpr T rho(T x)
Definition rotate.h:53

References BOTAN_ASSERT_NOMSG, Botan::BufferSlicer::copy(), Botan::BufferSlicer::empty(), Botan::DilithiumConstants::k(), Botan::DilithiumConstants::public_key_bytes(), Botan::rho(), Botan::DilithiumConstants::SEED_RHO_BYTES, and Botan::StrongSpan< T >::size().

Referenced by Botan::Dilithium_PublicKeyInternal::decode().

◆ decode_signature()

std::optional< std::tuple< DilithiumCommitmentHash, DilithiumPolyVec, DilithiumPolyVec > > Botan::Dilithium_Algos::decode_signature ( StrongSpan< const DilithiumSerializedSignature > sig,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 27 (sigDecode)

Definition at line 492 of file dilithium_algos.cpp.

493 {
494 BufferSlicer slicer(sig);
495 BOTAN_ASSERT_NOMSG(slicer.remaining() == mode.signature_bytes());
496
497 auto commitment_hash = slicer.copy<DilithiumCommitmentHash>(mode.commitment_hash_full_bytes());
498
499 DilithiumPolyVec response(mode.l());
500 for(auto& p : response) {
501 poly_unpack_gamma1(p, slicer, mode);
502 }
503 BOTAN_ASSERT_NOMSG(slicer.remaining() == size_t(mode.omega()) + mode.k());
504
505 auto hint = hint_unpack(slicer, mode);
506 BOTAN_ASSERT_NOMSG(slicer.empty());
507 if(!hint.has_value()) {
508 return std::nullopt;
509 }
510
511 return std::make_tuple(std::move(commitment_hash), std::move(response), std::move(hint.value()));
512}
size_t commitment_hash_full_bytes() const
length of the entire commitment hash 'c~' in bytes (differs between R3 and ML-DSA)
size_t signature_bytes() const
byte length of the encoded signature
uint8_t l() const
dimensions of the expanded matrix A
DilithiumOmega omega() const
maximal hamming weight of the hint polynomial vector 'h'
Strong< std::vector< uint8_t >, struct DilithiumCommitmentHash_ > DilithiumCommitmentHash
Hash of the message representative and the signer's commitment.

References BOTAN_ASSERT_NOMSG, Botan::DilithiumConstants::commitment_hash_full_bytes(), Botan::BufferSlicer::copy(), Botan::BufferSlicer::empty(), Botan::DilithiumConstants::k(), Botan::DilithiumConstants::l(), Botan::DilithiumConstants::omega(), Botan::BufferSlicer::remaining(), and Botan::DilithiumConstants::signature_bytes().

◆ decompose()

std::pair< DilithiumPolyVec, DilithiumPolyVec > Botan::Dilithium_Algos::decompose ( const DilithiumPolyVec & vec,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 36 (Decompose) on a polynomial vector

Algorithms 37 (HighBits) and 38 (LowBits) are not implemented explicitly, simply use the first (HighBits) and second (LowBits) element of the result.

Definition at line 818 of file dilithium_algos.cpp.

818 {
820 switch(mode.gamma2()) {
821 case Gamma2::Qminus1DividedBy32:
822 return decompose_all_coefficients<Gamma2::Qminus1DividedBy32>(vec);
823 break;
824 case Gamma2::Qminus1DividedBy88:
825 return decompose_all_coefficients<Gamma2::Qminus1DividedBy88>(vec);
826 break;
827 }
828
830}
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:163
DilithiumGamma2 gamma2() const
low-order rounding range for decomposing the commitment from polynomial vector 'w'

References BOTAN_ASSERT_UNREACHABLE, and Botan::DilithiumConstants::gamma2().

◆ encode_commitment()

DilithiumSerializedCommitment Botan::Dilithium_Algos::encode_commitment ( const DilithiumPolyVec & w1,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 28 (w1Encode)

Definition at line 517 of file dilithium_algos.cpp.

517 {
519 BufferStuffer stuffer(commitment);
520
521 for(const auto& p : w1) {
522 poly_pack_w1(p, stuffer, mode);
523 }
524
525 return commitment;
526}
Helper class to ease in-place marshalling of concatenated fixed-length values.
Definition stl_util.h:133
size_t serialized_commitment_bytes() const
byte length of the packed commitment polynomial vector 'w1'
Strong< std::vector< uint8_t >, struct DilithiumSerializedCommitment_ > DilithiumSerializedCommitment
Serialized representation of a commitment w1.

References Botan::DilithiumConstants::serialized_commitment_bytes().

◆ encode_public_key()

DilithiumSerializedPublicKey Botan::Dilithium_Algos::encode_public_key ( StrongSpan< const DilithiumSeedRho > rho,
const DilithiumPolyVec & t1,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 22 (pkEncode)

Definition at line 326 of file dilithium_algos.cpp.

328 {
330 BufferStuffer stuffer(pk);
331
332 stuffer.append(rho);
333 for(const auto& p : t1) {
334 poly_pack_t1(p, stuffer);
335 }
336
337 BOTAN_ASSERT_NOMSG(stuffer.full());
338 return pk;
339}
Strong< std::vector< uint8_t >, struct DilithiumSerializedPublicKey_ > DilithiumSerializedPublicKey
Serialized public key data (result of pkEncode(pk)).

References Botan::BufferStuffer::append(), BOTAN_ASSERT_NOMSG, Botan::BufferStuffer::full(), Botan::DilithiumConstants::public_key_bytes(), and Botan::rho().

Referenced by Botan::Dilithium_PublicKeyInternal::raw_pk().

◆ encode_signature()

DilithiumSerializedSignature Botan::Dilithium_Algos::encode_signature ( StrongSpan< const DilithiumCommitmentHash > c,
const DilithiumPolyVec & response,
const DilithiumPolyVec & hint,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 26 (sigEncode)

Definition at line 473 of file dilithium_algos.cpp.

476 {
478 BufferStuffer stuffer(sig);
479
480 stuffer.append(c);
481 for(const auto& p : response) {
482 poly_pack_gamma1(p, stuffer, mode);
483 }
484 hint_pack(hint, stuffer, mode);
485
486 return sig;
487}
Strong< std::vector< uint8_t >, struct DilithiumSerializedSignature_ > DilithiumSerializedSignature
Serialized signature data.

References Botan::BufferStuffer::append(), and Botan::DilithiumConstants::signature_bytes().

◆ expand_A()

DilithiumPolyMatNTT Botan::Dilithium_Algos::expand_A ( StrongSpan< const DilithiumSeedRho > rho,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 32 (ExpandA)

Note that the actual concatenation of rho, s and r is done downstream in the sampling function.

Definition at line 694 of file dilithium_algos.cpp.

694 {
695 DilithiumPolyMatNTT A(mode.k(), mode.l());
696 for(uint8_t r = 0; r < mode.k(); ++r) {
697 for(uint8_t s = 0; s < mode.l(); ++s) {
698 sample_ntt_uniform(rho, A[r][s], load_le(std::array{s, r}), mode);
699 }
700 }
701 return A;
702}
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495
Botan::CRYSTALS::PolynomialMatrix< DilithiumPolyTraits > DilithiumPolyMatNTT

References Botan::DilithiumConstants::k(), Botan::DilithiumConstants::l(), Botan::load_le(), and Botan::rho().

Referenced by expand_keypair().

◆ expand_keypair()

DilithiumInternalKeypair Botan::Dilithium_Algos::expand_keypair ( DilithiumSeedRandomness xi,
DilithiumConstants mode )

NIST FIPS 204, Algorithm 6 (ML-DSA.KeyGen_internal)

Lines 5-7 are extracted into a separate function, see above. The key encoding is deferred until the user explicitly invokes the encoding.

Definition at line 664 of file dilithium_algos.cpp.

664 {
665 const auto& sympriv = mode.symmetric_primitives();
666 CT::poison(xi);
667
668 auto [rho, rhoprime, K] = sympriv.H(xi);
669 CT::unpoison(rho); // rho is public (seed for the public matrix A)
670
671 const auto A = Dilithium_Algos::expand_A(rho, mode);
672 auto [s1, s2] = Dilithium_Algos::expand_s(rhoprime, mode);
673 auto [t1, t0] = Dilithium_Algos::compute_t1_and_t0(A, s1, s2);
674
675 CT::unpoison(t1); // part of the public key
676
678 std::make_shared<Dilithium_PublicKeyInternal>(mode, std::move(rho), std::move(t1)),
679 std::make_shared<Dilithium_PrivateKeyInternal>(
680 std::move(mode), std::move(xi), std::move(K), std::move(s1), std::move(s2), std::move(t0)),
681 };
682
683 CT::unpoison(*keypair.second);
684
685 return keypair;
686}
Dilithium_Symmetric_Primitives_Base & symmetric_primitives() const
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:65
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:54
DilithiumPolyMatNTT expand_A(StrongSpan< const DilithiumSeedRho > rho, const DilithiumConstants &mode)
std::pair< DilithiumPolyVec, DilithiumPolyVec > expand_s(StrongSpan< const DilithiumSeedRhoPrime > rhoprime, const DilithiumConstants &mode)
std::pair< std::shared_ptr< Dilithium_PublicKeyInternal >, std::shared_ptr< Dilithium_PrivateKeyInternal > > DilithiumInternalKeypair
Internal representation of a Dilithium key pair.

References expand_A(), expand_s(), Botan::CT::poison(), Botan::rho(), Botan::DilithiumConstants::symmetric_primitives(), and Botan::CT::unpoison().

Referenced by Botan::ML_DSA_Expanding_Keypair_Codec::decode_keypair(), and Botan::Dilithium_PrivateKey::Dilithium_PrivateKey().

◆ expand_mask()

DilithiumPolyVec Botan::Dilithium_Algos::expand_mask ( StrongSpan< const DilithiumSeedRhoPrime > rhoprime,
uint16_t nonce,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 34 (ExpandMask)

Definition at line 727 of file dilithium_algos.cpp.

729 {
730 DilithiumPolyVec s(mode.l());
731 for(auto& p : s) {
732 auto& xof = mode.symmetric_primitives().H(rhoprime, nonce++);
733 poly_unpack_gamma1(p, xof, mode);
734 }
735 return s;
736}
DilithiumHashedPublicKey H(StrongSpan< const DilithiumSerializedPublicKey > pk) const

References Botan::Dilithium_Symmetric_Primitives_Base::H(), Botan::DilithiumConstants::l(), and Botan::DilithiumConstants::symmetric_primitives().

◆ expand_s()

std::pair< DilithiumPolyVec, DilithiumPolyVec > Botan::Dilithium_Algos::expand_s ( StrongSpan< const DilithiumSeedRhoPrime > rhoprime,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 33 (ExpandS)

Definition at line 707 of file dilithium_algos.cpp.

708 {
709 auto result = std::make_pair(DilithiumPolyVec(mode.l()), DilithiumPolyVec(mode.k()));
710 auto& [s1, s2] = result;
711
712 uint16_t nonce = 0;
713 for(auto& p : s1) {
714 sample_uniform_eta(rhoprime, p, nonce++, mode);
715 }
716
717 for(auto& p : s2) {
718 sample_uniform_eta(rhoprime, p, nonce++, mode);
719 }
720
721 return result;
722}

References Botan::DilithiumConstants::k(), and Botan::DilithiumConstants::l().

Referenced by expand_keypair().

◆ infinity_norm_within_bound()

bool Botan::Dilithium_Algos::infinity_norm_within_bound ( const DilithiumPolyVec & vec,
size_t bound )

Definition at line 935 of file dilithium_algos.cpp.

935 {
936 BOTAN_DEBUG_ASSERT(bound <= (DilithiumConstants::Q - 1) / 8);
937
938 // It is ok to leak which coefficient violates the bound as the probability
939 // for each coefficient is independent of secret data but we must not leak
940 // the sign of the centralized representative.
941 for(const auto& p : vec) {
942 for(auto c : p) {
943 const auto abs_c = c - is_negative_mask(c).if_set_return(2 * c);
944 if(CT::driveby_unpoison(abs_c >= bound)) {
945 return false;
946 }
947 }
948 }
949
950 return true;
951}
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:129
static constexpr T Q
modulus
decltype(auto) driveby_unpoison(T &&v)
Definition ct_utils.h:241

References BOTAN_DEBUG_ASSERT, Botan::CT::driveby_unpoison(), and Botan::DilithiumConstants::Q.

◆ make_hint()

DilithiumPolyVec Botan::Dilithium_Algos::make_hint ( const DilithiumPolyVec & z,
const DilithiumPolyVec & r,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 39 (MakeHint)

MakeHint is specified per value in FIPS 204. This implements the algorithm for the entire polynomial vector. The specified algorithm is equivalent to the inner lambda.

TODO: This is taken from the reference implementation. We should implement it as specified in the spec, and see if that has any performance impact.

Definition at line 842 of file dilithium_algos.cpp.

842 {
843 BOTAN_DEBUG_ASSERT(z.size() == r.size());
844
845 auto make_hint = [gamma2 = uint32_t(mode.gamma2()),
846 q_gamma2 = static_cast<uint32_t>(DilithiumConstants::Q) - uint32_t(mode.gamma2())](
847 int32_t c0, int32_t c1) -> CT::Choice {
848 BOTAN_DEBUG_ASSERT(c0 >= 0);
849 BOTAN_DEBUG_ASSERT(c1 >= 0);
850
851 const uint32_t pc0 = static_cast<uint32_t>(c0);
852 const uint32_t pc1 = static_cast<uint32_t>(c1);
853
854 return (CT::Mask<uint32_t>::is_gt(pc0, gamma2) & CT::Mask<uint32_t>::is_lte(pc0, q_gamma2) &
856 .as_choice();
857 };
858
859 DilithiumPolyVec hint(r.size());
860
861 for(size_t i = 0; i < r.size(); ++i) {
862 for(size_t j = 0; j < r[i].size(); ++j) {
863 hint[i][j] = static_cast<int>(make_hint(z[i][j], r[i][j]).as_bool());
864 }
865 }
866
867 BOTAN_DEBUG_ASSERT(hint.ct_validate_value_range(0, 1));
868
869 return hint;
870}
static constexpr Mask< T > is_lte(T x, T y)
Definition ct_utils.h:491
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:470
static constexpr Mask< T > is_gt(T x, T y)
Definition ct_utils.h:486
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:465
DilithiumPolyVec make_hint(const DilithiumPolyVec &z, const DilithiumPolyVec &r, const DilithiumConstants &mode)

References BOTAN_DEBUG_ASSERT, Botan::CRYSTALS::PolynomialVector< Trait, D >::ct_validate_value_range(), Botan::DilithiumConstants::gamma2(), Botan::CT::Mask< T >::is_equal(), Botan::CT::Mask< T >::is_gt(), Botan::CT::Mask< T >::is_lte(), Botan::CT::Mask< T >::is_zero(), make_hint(), Botan::DilithiumConstants::Q, and Botan::CRYSTALS::PolynomialVector< Trait, D >::size().

Referenced by make_hint().

◆ power2round()

std::pair< DilithiumPolyVec, DilithiumPolyVec > Botan::Dilithium_Algos::power2round ( const DilithiumPolyVec & vec)

NIST FIPS 204, Algorithm 35 (Power2Round)

In contrast to the spec, this function takes a polynomial vector and performs the power2round operation on each coefficient in the vector. The actual Algorithm 35 as specified is actually just the inner lambda.

Definition at line 745 of file dilithium_algos.cpp.

745 {
746 // This procedure is taken verbatim from Dilithium's reference implementation.
747 auto power2round = [d = DilithiumConstants::D](int32_t r) -> std::pair<int32_t, int32_t> {
748 const int32_t r1 = (r + (1 << (d - 1)) - 1) >> d;
749 const int32_t r0 = r - (r1 << d);
750 return {r1, r0};
751 };
752
753 auto result = std::make_pair(DilithiumPolyVec(vec.size()), DilithiumPolyVec(vec.size()));
754
755 for(size_t i = 0; i < vec.size(); ++i) {
756 for(size_t j = 0; j < vec[i].size(); ++j) {
757 std::tie(result.first[i][j], result.second[i][j]) = power2round(vec[i][j]);
758 }
759 }
760
761 return result;
762}
static constexpr T D
number of dropped bits from t (see FIPS 204 Section 5)
std::pair< DilithiumPolyVec, DilithiumPolyVec > power2round(const DilithiumPolyVec &vec)

References Botan::DilithiumConstants::D, power2round(), and Botan::CRYSTALS::PolynomialVector< Trait, D >::size().

Referenced by power2round().

◆ sample_in_ball()

DilithiumPoly Botan::Dilithium_Algos::sample_in_ball ( StrongSpan< const DilithiumCommitmentHash > seed,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 29 (SampleInBall)

Definition at line 531 of file dilithium_algos.cpp.

531 {
532 // This generator resembles the while loop in the spec.
533 auto& xof = mode.symmetric_primitives().H(seed);
535
537 uint64_t signs = load_le(bounded_xof.next<8>());
538 for(size_t i = c.size() - mode.tau(); i < c.size(); ++i) {
539 const auto j = bounded_xof.next_byte([i](uint8_t byte) { return byte <= i; });
540 c[i] = c[j];
541 c[j] = 1 - 2 * (signs & 1);
542 signs >>= 1;
543 }
544
547
548 return c;
549}
constexpr size_t hamming_weight() const noexcept
Definition pqcrystals.h:294
constexpr size_t size() const
Definition pqcrystals.h:276
constexpr bool ct_validate_value_range(T min, T max) const noexcept
Definition pqcrystals.h:289
DilithiumTau tau() const
hamming weight of the polynomial 'c' sampled from the commitment's hash
detail::Bounded_XOF< XOF &, bound > Bounded_XOF
Botan::CRYSTALS::Polynomial< DilithiumPolyTraits, Botan::CRYSTALS::Domain::Normal > DilithiumPoly

References BOTAN_DEBUG_ASSERT, Botan::CRYSTALS::Polynomial< Trait, D >::ct_validate_value_range(), Botan::Dilithium_Symmetric_Primitives_Base::H(), Botan::CRYSTALS::Polynomial< Trait, D >::hamming_weight(), Botan::load_le(), Botan::CRYSTALS::Polynomial< Trait, D >::size(), Botan::DilithiumConstants::symmetric_primitives(), and Botan::DilithiumConstants::tau().

◆ use_hint()

void Botan::Dilithium_Algos::use_hint ( DilithiumPolyVec & vec,
const DilithiumPolyVec & hints,
const DilithiumConstants & mode )

NIST FIPS 204, Algorithm 40 (UseHint)

UseHint is specified per value in FIPS 204. This implements the algorithm for the entire polynomial vector. The specified algorithm is equivalent to the inner lambdas of 'use_hint_with_coefficients'.

Definition at line 917 of file dilithium_algos.cpp.

917 {
918 BOTAN_DEBUG_ASSERT(hints.size() == vec.size());
921
923 switch(mode.gamma2()) {
924 case Gamma2::Qminus1DividedBy32:
925 use_hint_on_coefficients<Gamma2::Qminus1DividedBy32>(hints, vec);
926 break;
927 case Gamma2::Qminus1DividedBy88:
928 use_hint_on_coefficients<Gamma2::Qminus1DividedBy88>(hints, vec);
929 break;
930 }
931
933}
constexpr bool ct_validate_value_range(T min, T max) const noexcept
Definition pqcrystals.h:439

References BOTAN_DEBUG_ASSERT, Botan::CRYSTALS::PolynomialVector< Trait, D >::ct_validate_value_range(), Botan::DilithiumConstants::gamma2(), Botan::DilithiumConstants::Q, and Botan::CRYSTALS::PolynomialVector< Trait, D >::size().