Botan 3.11.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 348 of file dilithium_algos.cpp.

349 {
350 if(pk.size() != mode.public_key_bytes()) {
351 throw Decoding_Error("Dilithium: Invalid public key length");
352 }
353
354 BufferSlicer slicer(pk);
356
357 DilithiumPolyVec t1(mode.k());
358 for(auto& p : t1) {
359 poly_unpack_t1(p, slicer);
360 }
361 BOTAN_ASSERT_NOMSG(slicer.empty());
362
363 return {std::move(rho), std::move(t1)};
364}
#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 496 of file dilithium_algos.cpp.

497 {
498 BufferSlicer slicer(sig);
499 BOTAN_ASSERT_NOMSG(slicer.remaining() == mode.signature_bytes());
500
501 auto commitment_hash = slicer.copy<DilithiumCommitmentHash>(mode.commitment_hash_full_bytes());
502
503 DilithiumPolyVec response(mode.l());
504 for(auto& p : response) {
505 poly_unpack_gamma1(p, slicer, mode);
506 }
507 BOTAN_ASSERT_NOMSG(slicer.remaining() == size_t(mode.omega()) + mode.k());
508
509 auto hint = hint_unpack(slicer, mode);
510 BOTAN_ASSERT_NOMSG(slicer.empty());
511 if(!hint.has_value()) {
512 return std::nullopt;
513 }
514
515 return std::make_tuple(std::move(commitment_hash), std::move(response), std::move(hint.value()));
516}
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 822 of file dilithium_algos.cpp.

822 {
824 switch(mode.gamma2()) {
825 case Gamma2::Qminus1DividedBy32:
826 return decompose_all_coefficients<Gamma2::Qminus1DividedBy32>(vec);
827 break;
828 case Gamma2::Qminus1DividedBy88:
829 return decompose_all_coefficients<Gamma2::Qminus1DividedBy88>(vec);
830 break;
831 }
832
834}
#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 521 of file dilithium_algos.cpp.

521 {
523 BufferStuffer stuffer(commitment);
524
525 for(const auto& p : w1) {
526 poly_pack_w1(p, stuffer, mode);
527 }
528
529 return commitment;
530}
Helper class to ease in-place marshalling of concatenated fixed-length values.
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 330 of file dilithium_algos.cpp.

332 {
334 BufferStuffer stuffer(pk);
335
336 stuffer.append(rho);
337 for(const auto& p : t1) {
338 poly_pack_t1(p, stuffer);
339 }
340
341 BOTAN_ASSERT_NOMSG(stuffer.full());
342 return pk;
343}
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 477 of file dilithium_algos.cpp.

480 {
482 BufferStuffer stuffer(sig);
483
484 stuffer.append(c);
485 for(const auto& p : response) {
486 poly_pack_gamma1(p, stuffer, mode);
487 }
488 hint_pack(hint, stuffer, mode);
489
490 return sig;
491}
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 698 of file dilithium_algos.cpp.

698 {
699 DilithiumPolyMatNTT A(mode.k(), mode.l());
700 for(uint8_t r = 0; r < mode.k(); ++r) {
701 for(uint8_t s = 0; s < mode.l(); ++s) {
702 sample_ntt_uniform(rho, A[r][s], load_le(std::array{s, r}), mode);
703 }
704 }
705 return A;
706}
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 668 of file dilithium_algos.cpp.

668 {
669 const auto& sympriv = mode.symmetric_primitives();
670 CT::poison(xi);
671
672 auto [rho, rhoprime, K] = sympriv.H(xi);
673 CT::unpoison(rho); // rho is public (seed for the public matrix A)
674
675 const auto A = Dilithium_Algos::expand_A(rho, mode);
676 auto [s1, s2] = Dilithium_Algos::expand_s(rhoprime, mode);
677 auto [t1, t0] = Dilithium_Algos::compute_t1_and_t0(A, s1, s2);
678
679 CT::unpoison(t1); // part of the public key
680
682 std::make_shared<Dilithium_PublicKeyInternal>(mode, std::move(rho), std::move(t1)),
683 std::make_shared<Dilithium_PrivateKeyInternal>(
684 std::move(mode), std::move(xi), std::move(K), std::move(s1), std::move(s2), std::move(t0)),
685 };
686
687 CT::unpoison(*keypair.second);
688
689 return keypair;
690}
Dilithium_Symmetric_Primitives_Base & symmetric_primitives() const
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:67
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:56
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 731 of file dilithium_algos.cpp.

733 {
734 DilithiumPolyVec s(mode.l());
735 for(auto& p : s) {
736 auto xof = mode.symmetric_primitives().H(rhoprime, nonce++);
737 poly_unpack_gamma1(p, *xof, mode);
738 }
739 return s;
740}
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 711 of file dilithium_algos.cpp.

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

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 939 of file dilithium_algos.cpp.

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

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 846 of file dilithium_algos.cpp.

846 {
847 BOTAN_DEBUG_ASSERT(z.size() == r.size());
848
849 auto make_hint = [gamma2 = uint32_t(mode.gamma2()),
850 q_gamma2 = static_cast<uint32_t>(DilithiumConstants::Q) - uint32_t(mode.gamma2())](
851 int32_t c0, int32_t c1) -> CT::Choice {
852 BOTAN_DEBUG_ASSERT(c0 >= 0);
853 BOTAN_DEBUG_ASSERT(c1 >= 0);
854
855 const uint32_t pc0 = static_cast<uint32_t>(c0);
856 const uint32_t pc1 = static_cast<uint32_t>(c1);
857
858 return (CT::Mask<uint32_t>::is_gt(pc0, gamma2) & CT::Mask<uint32_t>::is_lte(pc0, q_gamma2) &
860 .as_choice();
861 };
862
863 DilithiumPolyVec hint(r.size());
864
865 for(size_t i = 0; i < r.size(); ++i) {
866 for(size_t j = 0; j < r[i].size(); ++j) {
867 hint[i][j] = static_cast<int>(make_hint(z[i][j], r[i][j]).as_bool());
868 }
869 }
870
871 BOTAN_DEBUG_ASSERT(hint.ct_validate_value_range(0, 1));
872
873 return hint;
874}
static constexpr Mask< T > is_lte(T x, T y)
Definition ct_utils.h:463
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:442
static constexpr Mask< T > is_gt(T x, T y)
Definition ct_utils.h:458
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:437
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 749 of file dilithium_algos.cpp.

749 {
750 // This procedure is taken verbatim from Dilithium's reference implementation.
751 auto power2round = [d = DilithiumConstants::D](int32_t r) -> std::pair<int32_t, int32_t> {
752 const int32_t r1 = (r + (1 << (d - 1)) - 1) >> d;
753 const int32_t r0 = r - (r1 << d);
754 return {r1, r0};
755 };
756
757 auto result = std::make_pair(DilithiumPolyVec(vec.size()), DilithiumPolyVec(vec.size()));
758
759 for(size_t i = 0; i < vec.size(); ++i) {
760 for(size_t j = 0; j < vec[i].size(); ++j) {
761 std::tie(result.first[i][j], result.second[i][j]) = power2round(vec[i][j]);
762 }
763 }
764
765 return result;
766}
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 535 of file dilithium_algos.cpp.

535 {
536 // This generator resembles the while loop in the spec.
537 auto xof = mode.symmetric_primitives().H(seed);
539
541 uint64_t signs = load_le(bounded_xof.next<8>());
542 for(size_t i = c.size() - mode.tau(); i < c.size(); ++i) {
543 const auto j = bounded_xof.next_byte([i](uint8_t byte) { return byte <= i; });
544 c[i] = c[j];
545 c[j] = 1 - 2 * (signs & 1);
546 signs >>= 1;
547 }
548
551
552 return c;
553}
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 921 of file dilithium_algos.cpp.

921 {
922 BOTAN_DEBUG_ASSERT(hints.size() == vec.size());
925
927 switch(mode.gamma2()) {
928 case Gamma2::Qminus1DividedBy32:
929 use_hint_on_coefficients<Gamma2::Qminus1DividedBy32>(hints, vec);
930 break;
931 case Gamma2::Qminus1DividedBy88:
932 use_hint_on_coefficients<Gamma2::Qminus1DividedBy88>(hints, vec);
933 break;
934 }
935
937}
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().