diff --git a/docs/cryptodoc/src/05_00_pubkey.rst b/docs/cryptodoc/src/05_00_pubkey.rst index c7343a4a..1ca5b885 100644 --- a/docs/cryptodoc/src/05_00_pubkey.rst +++ b/docs/cryptodoc/src/05_00_pubkey.rst @@ -20,6 +20,6 @@ encapsulation and decapsulation or the key exchange mechanism. 05_05_xmss 05_06_hss_lms 05_07_spx - 05_08_dilithium + 05_08_ml_dsa 05_09_kyber 05_10_frodokem diff --git a/docs/cryptodoc/src/05_08_dilithium.rst b/docs/cryptodoc/src/05_08_dilithium.rst deleted file mode 100644 index 49c9220e..00000000 --- a/docs/cryptodoc/src/05_08_dilithium.rst +++ /dev/null @@ -1,339 +0,0 @@ -.. _pubkey/dilithium: - -Dilithium -========= - -.. _pubkey_key_generation/dilithium: - -Key Generation --------------- - -Botan's implementation of the CRYSTALS-Dilithium signature algorithm is based on the NIST round 3 specification [Dilithium-R3]_ and -can be found in :srcref:`src/lib/pubkey/dilithium`. -The parameter sets shown in Table :ref:`Supported Dilithium signature algorithms ` are supported. - -.. _pubkey_key_generation/dilithium/parameter_table: - -.. table:: Supported Dilithium signature algorithms and their parameters (see Table 2 of [Dilithium-R3]_) - - +---------------------+------------------+------------------+------------------+ - | ``DilithiumMode`` | ``Dilithium4x4`` | ``Dilithium6x5`` | ``Dilithium8x7`` | - +=====================+==================+==================+==================+ - | NIST Security Level | 2 | 3 | 5 | - +---------------------+------------------+------------------+------------------+ - | :math:`q` | 8380417 | 8380417 | 8380417 | - +---------------------+------------------+------------------+------------------+ - | :math:`d` | 13 | 13 | 13 | - +---------------------+------------------+------------------+------------------+ - | :math:`\tau` | 39 | 49 | 60 | - +---------------------+------------------+------------------+------------------+ - | challenge entropy | 192 | 225 | 257 | - +---------------------+------------------+------------------+------------------+ - | :math:`\gamma_1` | :math:`2^{17}` | :math:`2^{19}` | :math:`2^{19}` | - +---------------------+------------------+------------------+------------------+ - | :math:`\gamma_2` |(q - 1)/88 |(q - 1)/32 |(q - 1)/32 | - +---------------------+------------------+------------------+------------------+ - | :math:`(k, \ell)` | (4, 4) | (6, 5) | (8, 7) | - +---------------------+------------------+------------------+------------------+ - | :math:`\eta` | 2 | 4 | 2 | - +---------------------+------------------+------------------+------------------+ - | :math:`\beta` | 78 | 196 | 120 | - +---------------------+------------------+------------------+------------------+ - | :math:`\omega` | 80 | 55 | 75 | - +---------------------+------------------+------------------+------------------+ - | Repetitions | 4.25 | 5.1 | 3.85 | - +---------------------+------------------+------------------+------------------+ - -The Dilithium implementation is composed of several components. -An overview of the components is provided in Table :ref:`Dilithium components and file locations `. - -.. _pubkey_key_generation/dilithium/component_table: - -.. table:: Dilithium components and file locations. - - +-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Component | File | Purpose | - +===================================================================================+========================================================================================+========================================================================================================================================================================================+ - | :ref:`Modes ` | :srcref:`[src/lib/pubkey/dilithium]/dilithium_common/dilithium.h` | Provide parameters and primitives | - +-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`Constants and Symmetric Primitives ` | :srcref:`[src/lib/pubkey/dilithium]/dilithium_common/dilithium_symmetric_primitives.h` | Constants and primitives interface | - +-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`Modern Variant ` | :srcref:`[src/lib/pubkey/dilithium/dilithium_round3]/dilithium` | "Modern" instantiations of primitives | - +-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`AES Variant ` | :srcref:`[src/lib/pubkey/dilithium/dilithium_round3]/dilithium_aes` | "AES" instantiations of primitives | - +-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`Polynomial Operations ` | :srcref:`[src/lib/pubkey/dilithium]/dilithium_common/dilithium_polynomial.h` | Polynomials and operations on them | - +-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Dilithium | :srcref:`[src/lib/pubkey/dilithium]/dilithium_common/dilithium.h` | Dilithium :ref:`Keys `, :ref:`Signature Creation `, :ref:`Signature Validation ` | - +-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -.. _pubkey_key_generation/dilithium/modes: - -**Modes, Constants and Symmetric Primitives** - -Similar to CRYSTALS-Kyber, the different ways to instantiate Dilithium are realized as different modes (class ``DilithiumMode``; see Table :ref:`Supported Dilithium signature algorithms `). -A ``DilithiumMode`` provides the constants of the respective parameter set as ``DilithiumModeConstants``. -Also like Kyber, Dilithium additionally supports different instantiations of symmetric primitives via the class ``Dilithium_Symmetric_Primitives`` (see usage of SHAKE-128 vs. AES in Section 5.3 of [Dilithium-R3]_). -These are also provided by the mode and result in the "modern" and "AES" versions. -An "AES" version is identified via the ``_aes`` suffix in the mode string. - -.. warning:: - - The AES-based variants of Dilithium are deprecated and will be removed in a future release. - NIST decided not to standardize those variants in their final ML-DSA standard. - -.. _pubkey_key_generation/dilithium/polynomials: - -**Polynomial Operations** - -``A*b`` of a polynomial matrix ``A`` and a polynomial vector ``b`` in the NTT domain is given via ``PolynomialVector::generate_polyvec_matrix_pointwise_montgomery`` and ``a*b`` of two polynomial vectors ``a`` and ``b`` is given via ``PolynomialVector::polyvec_pointwise_poly_montgomery``. -Matrices and vectors are transformed to the NTT representation prior to the operation. -To perform the multiplication ``2^d*a`` with the scalar ``2^d`` and the vector ``a``, the method ``PolynomialVector::polyvec_shiftl`` is used. - -In addition to core polynomial operations, Dilithium relies on several supporting algorithms, see Section 2.3, Section 2.4, and the alterations of Section 5 of [Dilithium-R3]_. -Concretely, :math:`\mathsf{SampleInBall}` of [Dilithium-R3]_ is provided via ``Polynomial::poly_challenge``, :math:`\mathsf{ExpandA}` via ``PolynomialMatrix::generate_matrix``, :math:`\mathsf{ExpandS}` via ``PolynomialVector::fill_polyvec_uniform_eta`` (called to fill vectors of different lengths), and :math:`\mathsf{ExpandMask}` via ``PolynomialVector::polyvecl_uniform_gamma1``. -The function :math:`\mathsf{H}` is instantiated directly. - -Furthermore, the algorithm :math:`\mathsf{Power2Round}_q` of [Dilithium-R3]_ corresponds to the functions ``Polynomial::power2round`` and ``Polynomial::fill_polys_power2round``. -:math:`\mathsf{MakeHint}_q` and :math:`\mathsf{UseHint}_q` of [Dilithium-R3]_ are realized by ``Polynomial::make_hint``\/\ ``Polynomial::generate_hint_polynomial`` and ``Polynomial::use_hint``, respectively. -:math:`\mathsf{Decompose}_q` is given via ``Polynomial::decompose`` and ``Polynomial::poly_decompose``. -During the signature operations, the decomposition functions are used directly instead of using the :math:`\mathsf{HighBits}_q` \/ :math:`\mathsf{LowBits}_q` paradigm. -Versions with element-wise applications on polynomial vectors are given as well. - -Finally, Botan supplies packing operations (Section 5.2, [Dilithium-R3]) and the function ``PolynomialVector::polyvec_chknorm``, which realizes a check if the :math:`\lVert \cdot \rVert_\infty` norm of a given polynomial vector surpasses a provided bound. - -.. _pubkey_key_generation/dilithium/keys: - -**Keys** - -In Botan, Dilithium's keys are represented as ``Dilithium_PublicKey`` for public keys ``pk`` and as ``Dilithium_PrivateKey`` for secret keys ``sk``. -Public keys contain the matrix seed ``rho`` and the public value ``t1``. -Also, when creating a ``pk`` object the value ``tr = CRH(rho || t1)`` is precomputed from the public key values ``rho`` and ``t1``, which is used by the verification algorithm. -We therefore write ``pk = (rho, t1)`` during key generation and ``pk = (rho, t1, tr)`` during verification. -The ``sk`` object contains the values ``rho`` and ``tr`` of the ``pk``. -It also contains the seed ``key``, the vectors ``s1`` and ``s2``, and the value ``t0``. We write ``sk = (rho, tr, key, s1, s2, t0)``. - -The keys use a helper function ``calculate_t0_and_t1`` to compute :math:`(\mathbf{t_1},\mathbf{t_0})` based on the public key seed ``rho`` and private vectors ``s1, s2``, i.e., realizing L. 3, L.5, and L. 6, Fig. 4, [Dilithium-R3]_. -Furthermore, encoding and decoding of keys and signatures are provided via the key classes. - -The Dilithium key generation process follows :math:`\mathsf{Gen}` of Figure 4 of [Dilithium-R3]_ and works as follows (see :srcref:`[src/lib/pubkey/dilithium/dilithium_common]/dilithium.cpp:403|Dilithium_PrivateKey`): - -.. admonition:: Dilithium_PrivateKey::Dilithium_PrivateKey() - - **Input:** - - - ``rng``: random number generator - - ``m``: Dilithium mode providing parameters and symmetric functions - - **Output:** - - - ``sk``: secret key - - ``pk``: public key - - **Steps:** - - 1. Generate random seed ``seedbuf`` using ``rng`` (L. 1, Fig. 4, [Dilithium-R3]_) - 2. ``(rho || rhoprime || key) = H(seedbuf)`` (L. 2, Fig. 4, [Dilithium-R3]_) - 3. ``matrix = PolynomialMatrix::generate_matrix(rho, m)`` (L. 3, Fig. 4, [Dilithium-R3]_) - 4. Use ``PolynomialVector::fill_polyvec_uniform_eta`` to fill ``s1`` and ``s2`` (L. 4, Fig. 4, [Dilithium-R3]_) - 5. ``(t0, t1) = calculate_t0_and_t1(m, rho, s1, s2)`` (L. 5-6, Fig. 4, [Dilithium-R3]_) - 6. ``pk = (rho, t1)`` (:math:`pk` in L. 8, Fig. 4, [Dilithium-R3]_) - 7. ``tr = H(rho || t1)`` (L. 7, Fig. 4, [Dilithium-R3]_) - 8. ``sk = (rho, tr, key, s1, s2, t0)`` (:math:`sk` in L. 8, Fig. 4, [Dilithium-R3]_) - - **Notes:** - - - ``matrix`` is already generated in NTT representation. - - The calculation of ``calculate_t0_and_t1`` includes the computation of ``matrix*s1`` in the NTT domain. - - -.. _pubkey_signature/dilithium/sig: - -Signature Creation ------------------- - -CRYSTALS-Dilithium signing follows the :math:`\mathsf{Sign}` algorithm of Figure 4 of [Dilithium-R3]_. It uses some functions already documented in :ref:`Dilithium Key Generation `. -It is implemented in the ``Dilithium_Signature_Operation`` (see :srcref:`[src/lib/pubkey/dilithium/dilithium_common]/dilithium.cpp:153|sign`) class and receives the secret key via the constructor. -Message bytes are given to the object via consecutive calls of ``Dilithium_Signature_Operation::update``. - -The signature generation process works as follows: - -.. admonition:: ``Dilithium_Signature_Operation::sign()`` - - **Input:** - - - ``sk = (rho, tr, key, s1, s2, t0)``: secret key - - ``matrix``: public key matrix :math:`\mathbf{A}` (corresponds to L. 9, Fig. 4, [Dilithium-R3]_) - - ``mu``: hash of ``tr`` and the message ``msg`` (corresponds to L. 10, Fig. 4, [Dilithium-R3]_) - - ``rng``: random number generator - - ``m``: Dilithium mode providing parameters (``gamma1``, ``gamma2``, ``beta``, ``omega``) and symmetric functions - - ``randomized``: whether randomized signing should be used - - **Output:** - - - ``sig``: signature - - **Steps:** - - 1. If ``randomized``, generate ``rhoprime`` using ``rng``, otherwise set ``rhoprime = H(key || mu)`` (L. 12, Fig. 4, [Dilithium-R3]_) - 2. For incremental ``nonce``: (L. 13, Fig. 4, [Dilithium-R3]_) - - 1. ``y = polyvecl_uniform_gamma1(rhoprime, nonce, m)`` (L. 14, Fig. 4, [Dilithium-R3]_) - 2. ``w1 = A*y`` (L. 15, Fig. 4, [Dilithium-R3]_) - 3. ``(w1, w0) = w1.polyvec_decompose()`` (L. 16, Fig. 4, [Dilithium-R3]_) - 4. ``sm = H(mu || w1)`` (L. 17, Fig. 4, [Dilithium-R3]_) - 5. ``cp = Polynomial::poly_challenge(sm, m)`` (L. 18, Fig. 4, [Dilithium-R3]_) - 6. ``z = y + c*s1`` (L. 19, Fig. 4, [Dilithium-R3]_) - 7. If ``z.polyvec_chknorm(gamma1 - beta)``, continue with next iteration (Check on :math:`\mathbf{z}`, L. 21, Fig. 4, [Dilithium-R3]_) - 8. ``w0 = w0 - c*s2`` (L. 20, Fig. 4, [Dilithium-R3]_) - 9. If ``w0.polyvec_chknorm(gamma2 - beta)``, continue with next iteration (Check on :math:`\mathbf{r_0}`, L. 21, Fig. 4, [Dilithium-R3]_) - 10. ``h = c*t0`` - 11. If ``h.polyvec_chknorm(gamma2)``, continue with next iteration (First check on :math:`c\mathbf{t0}`, L. 24, Fig. 4, [Dilithium-R3]_) - 12. ``w0 = w0 + h`` - 13. ``(h, n) = PolynomialVector::generate_hint_polyvec(w0, w1, m)`` (``h`` is the hint vector, ``n`` the amount of 1's in ``h``; L. 23, Fig. 4, [Dilithium-R3]_, see `Hint Generation`_) - 14. If ``n > omega``, continue with the next iteration (Last check, L. 24, Fig. 4, [Dilithium-R3]_) - 15. ``sig = (z, h, c)`` (L. 26, Fig. 4, [Dilithium-R3]_) - 16. Break loop - - **Notes:** - - - ``matrix`` is already generated in NTT representation in the constructor via ``matrix = PolynomialMatrix::generate_matrix(rho, m)``. - - ``mu = H(tr || msg)`` is already computed beforehand (in the constructor and using the ``update(msg)`` function). - - NTTs are performed as indicated by the comments in Fig. 4, [Dilithium-R3]_. - - ``nonce`` here is incremented by 1 but multiplied by ``l`` within the called function ``polyvecl_uniform_gamma1``. - - ``w0`` corresponds to :math:`\mathbf{r_0}` in Fig. 4, [Dilithium-R3]_ and is computed directly via the decomposition of ``A*y`` and subtraction with ``c*s2``. - - Botan's hint generation differs slightly from [Dilithium-R3]_. This is discussed in `Hint Generation`_. - - -.. _pubkey_signature/dilithium/val: - -Signature Validation --------------------- - -The signature validation follows the :math:`\mathsf{Verify}` algorithm of Figure 4 of [Dilithium-R3]_. It is -implemented in the ``Dilithium_Verification_Operation`` class (see :srcref:`[src/lib/pubkey/dilithium/dilithium_common]/dilithium.cpp:269|is_valid_signature`), which receives the public key via the constructor. -Message bytes are given to the object via consecutive calls of ``Dilithium_Verification_Operation::update``. - -.. admonition:: Dilithium_Verification_Operation::is_valid_signature() - - **Input:** - - - ``pk = (rho, t_1, tr)``: public key - - ``matrix``: public key matrix :math:`\mathbf{A}` (corresponds to L. 27, Fig. 4, [Dilithium-R3]_) - - ``mu``: hash of ``tr`` and the message ``msg`` (corresponds to L. 28, Fig. 4, [Dilithium-R3]_) - - ``sig = (z, h, c)``: the signature - - ``m``: Dilithium mode providing parameters (``gamma1``, ``gamma2``, ``beta``, ``omega``) and symmetric functions - - **Output:** - - - ``true``, if the signature for message ``msg`` is valid. ``false`` otherwise. - - **Steps:** - - 1. Check that the signature has the appropriate length and extract its parameters. Return ``false`` if - the signature length is invalid, ``z`` is no valid signature vector (i.e., ``z.polyvec_chknorm(gamma1 - beta)``), or - ``h`` is no valid hint vector (i.e., ``amount of 1's in h > omega``) (first and third check of L. 31, Fig. 4, [Dilithium-R3]_) - 2. ``cp = Polynomial::poly_challenge(c)`` (L. 29, Fig. 4, [Dilithium-R3]_) - 3. ``w1 = A*z - c*t*2^d`` (Second input of L. 30, Fig. 4, [Dilithium-R3]_) - 4. ``w1 = PolynomialVector::polyvec_use_hint(h, w1, m)`` (L. 30, Fig. 4, [Dilithium-R3]_) - 5. Signature is valid if ``c == H(mu || w1)`` (L. 31, Fig. 4, [Dilithium-R3]_) - - **Notes:** - - - ``matrix`` is already generated in NTT representation in the constructor via ``matrix = PolynomialMatrix::generate_matrix(rho, m)``. - - NTTs are performed as indicated by the comments in Fig. 4, [Dilithium-R3]_. - - mu = ``H(tr || msg)`` is already computed beforehand (in the constructor and using the ``update(msg)`` function). - - -.. _pubkey_signature/dilithium/hint: - -Hint Generation ---------------- - -Dilithium uses a simple technique to reduce the size of the public key. -Given the public matrix :math:`\mathbf{A}` and :math:`\mathbf{t} = \mathbf{As_1} + \mathbf{s_2}`, the public key only contains the "high-order" bits :math:`\mathbf{t_1}` of :math:`\mathbf{t}`. -However, Dilithium's verification algorithm requires computation of the high bits of the sum :math:`\mathbf{Az}-c\mathbf{t}` (see Section 1.1 of [Dilithium-R3]_). -This computation cannot be conducted solely with :math:`\mathbf{t_1}` because carries from the subtraction with the product of :math:`c` and the missing "lower-order" bits :math:`\mathbf{t_0}` may influence the high bits of the result. -In order to still use only :math:`\mathbf{t_1}` in the public key, Dilithium computes a "hint" as part of the signature that indicates the carries. -The corresponding simple algorithm is :math:`\mathsf{MakeHint}_q` specified in Figure 3 of [Dilithium-R3]_. - -More concretely, the goal of the hint is as follows: given :math:`\mathbf{A}\mathbf{z} - c\mathbf{t_1}\cdot 2^d = \mathbf{w}-c\mathbf{s_2}+c\mathbf{t_0}` and the hint, one can recover :math:`\mathbf{w_1}`. -The hint generation of [Dilithium-R3]_ uses inputs :math:`(\mathbf{w}-c\mathbf{s_2}+c\mathbf{t_0},-c\mathbf{t_0})`. -However, like the reference implementation of [Dilithium-R3]_, Botan's hint computation operates on inputs ``(w0 - c*s2 + c*t0, w1)`` and slightly differs to Figure 3 of [Dilithium-R3]_. -Despite this, Botan's hint computation is equivalent to the hint generation of the specification. - -To show the equivalence, we expand the definition of the :math:`[[\ ]]`-operator to vectors, i.e., :math:`[[ \mathbf{u} = \mathbf{v} ]]` returns a vector :math:`\mathbf{b} \in \mathbb{F}_2^{n \cdot k}` comparing all polynomial coefficients of both vectors element-wise. -Then, [Dilithium-R3]_ computes the hint vector as follows: - -.. math:: \mathbf{h} = \mathbf{1} - [[ \mathsf{HighBits}_q(\mathbf{w} - c \mathbf{s_2} + c\mathbf{t_0}, 2\gamma_2) = \mathsf{HighBits}_q(\mathbf{w} - c \mathbf{s_2}, 2\gamma_2) ]] - -According to Section 3.3, Equation (3) of [Dilithium-R3]_, :math:`\mathsf{HighBits}_q(\mathbf{w} - c \mathbf{s_2}, 2\gamma_2)=\mathbf{w_1}`. Also, we can -write :math:`\mathbf{w} = \mathbf{w_1} 2\gamma_2 + \mathbf{w_0}`. We get: - -.. math:: \mathbf{h} = \mathbf{1} - [[ \mathsf{HighBits}_q(\mathbf{w_1} 2\gamma_2 + \mathbf{w_0} - c \mathbf{s_2} + c\mathbf{t_0}, 2\gamma_2) = \mathbf{w_1} ]] - -Since :math:`\|\mathbf{w_0} - c \mathbf{s_2}\|_{\infty} < \gamma_2 - \beta` (second check of L. 21, Fig. 4, [Dilithium-R3]_) and :math:`\|c\mathbf{t_0}\|_{\infty} \leq \gamma_2` (first check of L. 24, Fig. 4, [Dilithium-R3]_), we know that: - -.. math:: \|\mathbf{w_0} - c \mathbf{s_2} + c\mathbf{t_0}\|_{\infty} < 2 \gamma_2 - \beta - -In the following, we will look at the 1-bit hint :math:`h` creation of single polynomial coefficients :math:`x \in \mathbb{Z}_q` of vector elements of :math:`(\mathbf{w_0} - c \mathbf{s_2} + c\mathbf{t_0})` and coefficients :math:`w_1 \in \mathbb{Z}_q` of vector elements of :math:`\mathbf{w_1}`. -Two cases are distinguished. - -**Case 1.** :math:`w_1 \neq 0`: - -:math:`w_1 2 \gamma_2 \in [2 \gamma_2, 4 \gamma_2, ..., (q-1) - 2 \gamma_2]` and therefore: - -.. math:: \beta < w_1 2 \gamma_2 + x < (q-1) - \beta - -According to the constructions of :math:`\mathsf{HighBits}_q` and :math:`\mathsf{Decompose}_q`, we get via L. 23, Figure 3 of [Dilithium-R3]_: - -.. math:: - & \mathsf{HighBits}_q(w_1 2 \gamma_2 + x, 2 \gamma_2) - - =& \frac{(w_1 2 \gamma_2 + x) - (w_1 2 \gamma_2 + x\ \textrm{mod}^{\pm}\ 2 \gamma_2)}{2 \gamma_2} - - =& \frac{w_1 2 \gamma_2 + x - (x\ \textrm{mod}^{\pm}\ 2 \gamma_2)}{2 \gamma_2} - -which equals :math:`w_1` if and only if - -.. math:: (x\ \textrm{mod}^{\pm}\ 2 \gamma_2) = x - -Therefore, :math:`\mathsf{HighBits}_q(w_1 2 \gamma_2 + x, 2\gamma_2) = w_1` (and equivalently :math:`h=0`) if and only if: - -.. math:: -\gamma_2 < x \leq \gamma_2 - -**Case 2.** :math:`w_1 = 0`: - -The equation gets: - -.. math:: \mathsf{HighBits}_q(x, 2 \gamma_2) = 0 - -According to the construction, this equation is true for all values of: - -.. math:: -\gamma_2 < x \leq \gamma_2 - -but also for :math:`x = -\gamma_2`. Hence, the hint becomes :math:`0` if and only if - -.. math:: -\gamma_2 \leq x \leq \gamma_2 - -To demonstrate this, we need to show that -:math:`\mathsf{HighBits}_q(-\gamma_2, 2 \gamma_2) = 0`. In particular, we show that :math:`\mathsf{Decompose}_q(-\gamma_2, 2 \gamma_2)` returns :math:`(0, -\gamma_2)` - -It first computes: - -.. math:: - r = - \gamma_2\ \textrm{mod}^{+}\ q = q - \gamma_2 - -Then, given that :math:`\gamma_2` divides :math:`q - 1`: - -.. math:: - - r_0 =& q - \gamma_2\ \textrm{mod}^{\pm}\ 2 \gamma_2 = (q-1)+1 - \gamma_2\ \textrm{mod}^{\pm}\ 2 \gamma_2 = -\gamma_2 + 1 - - r - r_0 =& (q - \gamma_2) - (-\gamma_2 + 1) = q - 1 - -Hence, the special case occurs (L.21-22, Figure 3 of [Dilithium-R3]_) and we get :math:`r_1 = 0` and :math:`r_0 = -\gamma_2`. - -Taking into account these cases where the hint becomes :math:`0`, Botan only checks the :math:`\gamma_2` bounds of coefficients :math:`x` of the input vector :math:`(\mathbf{w_0} - c \mathbf{s_2} + c\mathbf{t_0})`. -To distinguish both cases with slightly different boundaries, :math:`\mathbf{w_1}` must be given as well. - diff --git a/docs/cryptodoc/src/05_08_ml_dsa.rst b/docs/cryptodoc/src/05_08_ml_dsa.rst new file mode 100644 index 00000000..3e2e1b57 --- /dev/null +++ b/docs/cryptodoc/src/05_08_ml_dsa.rst @@ -0,0 +1,443 @@ +.. _pubkey/ml_dsa: + +ML-DSA +====== + +Botan implements the Module-Lattice-based Digital Signature Algorithm (ML-DSA) +in :srcref:`src/lib/pubkey/dilithium`. The implementation is based on +[FIPS-204]_. The list of supported algorithm parametres is listed in the table +:ref:`pubkey/ml_dsa/params`. + +.. _pubkey/ml_dsa/params: + +.. table:: Supported ML-DSA Parameter Sets (see Table 1 of [FIPS-204]_) + + +------------+-----------+-----------+---------------+-----------+--------------+-----------------+------------------+------------------+---------------+--------------+---------------+----------------+ + | Mode | :math:`q` | :math:`n` | :math:`\zeta` | :math:`d` | :math:`\tau` | :math:`\lambda` | :math:`\gamma_1` | :math:`\gamma_2` | :math:`(k,l)` | :math:`\eta` | :math:`\beta` | :math:`\omega` | + +============+===========+===========+===============+===========+==============+=================+==================+==================+===============+==============+===============+================+ + | ML-DSA-4x4 | 8380417 | 256 | 1753 | 13 | 39 | 128 | 2\ :sup:`17` | :math:`(q-1)/88` | (4,4) | 2 | 78 | 80 | + +------------+-----------+-----------+---------------+-----------+--------------+-----------------+------------------+------------------+---------------+--------------+---------------+----------------+ + | ML-DSA-6x5 | 8380417 | 256 | 1753 | 13 | 49 | 192 | 2\ :sup:`19` | :math:`(q-1)/32` | (6,5) | 4 | 196 | 55 | + +------------+-----------+-----------+---------------+-----------+--------------+-----------------+------------------+------------------+---------------+--------------+---------------+----------------+ + | ML-DSA-8x7 | 8380417 | 256 | 1753 | 13 | 60 | 256 | 2\ :sup:`19` | :math:`(q-1)/32` | (8,7) | 2 | 120 | 75 | + +------------+-----------+-----------+---------------+-----------+--------------+-----------------+------------------+------------------+---------------+--------------+---------------+----------------+ + +The parameter sets claim a NIST security level of 2, 3, and 5 respectively. + +.. _pubkey/ml_dsa/internals: + +Algorithm Internals +------------------- + +[FIPS-204]_ describes three primary operations: key generation, signing, and +verification. + +Internally, those operations are further split into two functional layers: +the public-facing ML-DSA (Section 5), and ML-DSA-internal (Section 6). ML-DSA +and ML-DSA-internal decouple the actual high-level logic from the generation of +randomness. The functions in ML-DSA-internal receive pre-determined random bytes +as needed and are, therefore, fully deterministic. + +ML-DSA is a Schnorr-like signature where the typically interactive protocol is +made non-interactive by pseudorandomly deriving the verifier's challenge from +the commitment and the message to be signed. + +.. _pubkey/ml_dsa/components: + +.. table:: ML-DSA Components and File Locations + + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + | Component | Purpose | [FIPS-204]_ | + +=======================================================================================================================================================+================================================================+====================+ + | :ref:`Types ` (:srcref:`src <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_types.h>`) | Strong Types | n/a | + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + | :ref:`Constants ` (:srcref:`src <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_constants.h>`) | Parameter set instantiation | 4 | + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + | :ref:`Polynomials ` (:srcref:`src <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_polynomial.h>`) | Polynomials, Structures on Polynomials and Operations | 7.5, 7.6 | + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + | :ref:`Algorithms ` (:srcref:`src <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.h>`) | Encoding, Sampling, Key Expansion, Hint Generation, Rounding | 7.1, 7.2, 7.3, 7.4 | + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + | :ref:`Symmetric Primitives ` (:srcref:`src <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_symmetric_primitives.h>`) | ML-DSA abstractions for PRFs, XOFs, Hashes, and KDFs | 3.7 | + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + | :ref:`Internal Keys ` (:srcref:`src <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_keys.h>`) | Internal key representation and serialization | n/a | + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + | :ref:`ML-DSA Implementation ` (:srcref:`src <[src/lib/pubkey/dilithium/ml_dsa]/ml_dsa_impl.h>`) | Functional disambiguation to (also provided) Dilithium | 3.7, 6.2, 6.3, 7.2 | + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + | :ref:`ML-DSA ` (:srcref:`src <[src/lib/pubkey/dilithium/dilithium_common]/dilithium.h>`) | Public ML-DSA API | 5 | + +-------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------+--------------------+ + +.. _pubkey/ml_dsa/types: + +Strong Types +^^^^^^^^^^^^ + +ML-DSA uses strong types and type aliases to represent the various value +types involved in the algorithm. This approach binds the semantic meaning of +values to their types, resulting in a more robust interface and self-documenting +code. Type aliases are defined for ML-DSA polynomials, polynomial vectors, and +polynomial matrices, as well as their NTT representations. All bitstrings, +including various hash values, random seeds, and others, are encapsulated as +strong types. + +.. _pubkey/ml_dsa/constants: + +Paramter Instantiations +^^^^^^^^^^^^^^^^^^^^^^^ + +Botan's ``DilithiumConstants`` class contains all parameters and constants +outlined in Section 4 of [FIPS-204]_ (see :ref:`pubkey/ml_dsa/params`). +Additionally, the class contains parameters implicitly derived from these +constants, such as key and ciphertext sizes, along with various intermediate +value sizes required within internal algorithms. + +Also, this class contains the theoretical XOF-bounds outlined in Appendix C of +[FIPS-204]_ used as a guard rail for the various rejection sampling operations +within the ML-DSA implementation. + +.. _pubkey/ml_dsa/polynomials: + +Polynomial Operations +^^^^^^^^^^^^^^^^^^^^^ + +ML-DSA relies extensively on polynomials within the polynomial ring :math:`R_q`, +utilizing vectors and matrices of polynomials, both inside and outside the NTT +domain. Botan uses :ref:`strong types ` to distinguish +polynomials and polynomial vectors as ``DilithiumPoly`` and +``DilithiumPolyVec``, as well as their NTT counterparts ``DilithiumPolyNTT`` and +``DilithiumPolyVecNTT``. Matrices only appear in the NTT domain and are +represented by the class ``DilithiumPolyMatNTT``. + +ML-KEM, as defined in [FIPS-202]_, also employs polynomials, leading to shared +polynomial logic between the two algorithms. This shared logic is located in +:srcref:`[src/lib/pubkey]/pqcrystals/pqcrystals.h`, encompassing common +operations on vectors and matrices, as well as algorithm-independent operations +like polynomial addition and subtraction. The ML-DSA specific logic implemented +in :srcref:`[src/lib/pubkey/dilithium/dilithium_common]/dilithium_polynomial.h` +supplements this construction by including the NTT (Algorithm 41 of [FIPS-204]_) +and inverse NTT (Algorithm 42 of [FIPS-204]_) operations, along with NTT +polynomial multiplication (Algorithms 45 [FIPS-204]_). + +Due to this type-based construction, the C++ compiler can detect specific +implementation issues statically. For instance, the polynomial +multiplication operation is only defined for the ``PolyVecNTT`` type. Misuse +would result in a compile-time error. + +Botan utilizes Montgomery as well as Barrett reduction and conditional addition +of :math:`q`, for modular reduction and handling of negative values, depending +on the expected result range of certain operations. Those operations are +explicitly applied in the implementation as needed. + +.. _pubkey/ml_dsa/algorithms: + +Internal Algorithms +^^^^^^^^^^^^^^^^^^^ + +The ``Dilithium_Algos`` namespace includes a variety of internal functions to +support the primary algorithm. Table :ref:`pubkey/ml_dsa/algos` offers a summary +of those functions that are exposed to the rest of the implementation. The +:srcref:`[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp` +contains additional functions that are used within this module only, such as the +encoding functionality from [FIPS-204]_ Section 7.1. + +.. _pubkey/ml_dsa/algos: + +.. table:: ML-DSA Algorithms Overview + + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | Function | Description | [FIPS-204]_ | + +=======================================================================================================================================+============================================================================================+=============+ + | :srcref:`encode_public_key <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:327|encode_public_key>` | Byte encoding of a public key | 7.2 A. 22 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`decode_public_key <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:345|decode_public_key>` | Decoding a public key from bytes | 7.2 A. 23 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`encode_keypair <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:368|encode_keypair>` [#dilithium_comp]_ | Byte encoding of a private key | 7.2 A. 24 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`decode_keypair <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:409|decode_keypair>` [#dilithium_comp]_ | Decoding a private key from bytes | 7.2 A. 25 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`encode_signature <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:474|encode_signature>` | Byte encoding of a signature | 7.2 A. 26 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`decode_signature <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:493|decode_signature>` | Decoding a signature from bytes | 7.2 A. 27 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`encode_commitment <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:518|encode_commitment>` | Byte encoding of a commitment | 7.2 A. 28 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`sample_in_ball <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:532|sample_in_ball>` | Sample a challenge from the commitment hash | 7.3 A. 29 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`expand_keypair <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:665|expand_keypair>` | Expand a private key from a seed :math:`\xi` | 6.1 A. 6 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`expand_A <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:695|expand_A>` | Expand matrix :math:`A` from a seed :math:`\rho` | 7.3 A. 32 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`expand_s <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:708|expand_s>` | Expand vectors :math:`s1` and :math:`s2` from a seed :math:`\rho` | 7.3 A. 33 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`expand_mask <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:728|expand_mask>` | Samples a vector :math:`y` from a seed :math:`\rho'` and a nonce :math:`\kappa` | 7.3 A. 34 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`decompose <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:819|decompose>` | Decompose coefficients in a vector :math:`w` into high and low bits | 7.4 A. 36 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`make_hint <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:843|make_hint>` | Allows the signer to compress the signature | 7.4 A. 39 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`use_hint <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:918|use_hint>` | Lets the verifier decompress the signature | 7.4 A. 40 | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + | :srcref:`infinity_norm_within_bound <[src/lib/pubkey/dilithium/dilithium_common]/dilithium_algos.cpp:936|infinity_norm_within_bound>` | Given vector :math:`v` and :math:`bound`, validates that :math:`\|v\|_{\infty} \geq bound` | n/a | + +---------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+-------------+ + +.. [#dilithium_comp] The private key encoding and decoding functions are used + for the legacy support of Dilithium (round 3) only. Botan's ML-DSA + implementation exclusively store its private keys as the secret seed + :math:`\xi`. + +.. _pubkey/ml_dsa/primitives: + +Symmetric Primitives +^^^^^^^^^^^^^^^^^^^^ + +This module provides an interface to the symmetric primitives required to +implement ML-DSA: namely XOFs, hash functions and KDFs. + +To allow sharing significant portions of the ML-DSA implementation with the +pre-standard Dilithium and Dilithium-AES algorithms that Botan currently keeps +supporting, these primitives are accessible via the polymorphic base classes +:srcref:`Dilithium_Symmetric_Primitives_Base +`, +:srcref:`DilithiumXOF +`, +and :srcref:`DilithiumMessageHash +`. + +The concrete implementations relevant for ML-DSA may +be found in :srcref:`[src/lib/pubkey/dilithium]/ml_dsa/ml_dsa_impl.h` and +:srcref:`[src/lib/pubkey/dilithium/dilithium_common/dilithium_shake]/dilithium_shake_xof.h`. + +.. _pubkey/ml_dsa/keys: + +Internal Key Representation +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :srcref:`Dilithium_PublicKeyInternal +` +and :srcref:`Dilithium_PrivateKeyInternal +` +classes are the internal representation of the ML-DSA key pair in expandedd form. + +Additionally, the :srcref:`Dilithium_Keypair_Codec +` +serves as a customization point for the key encoding and decoding functions that +differ between ML-DSA (:math:`\xi` only) and Dilithium (round 3) (partially +expanded key format as specified in [FIPS-204]_). By *always* expanding the +private key from the secret seed :math:`\xi`, sanity checks during decoding of +the key pair can be omitted. + +.. _pubkey/ml_dsa/ml_dsa_impl: + +ML-DSA Specifics +^^^^^^^^^^^^^^^^ + +This module provides concrete ML-DSA specific implementations for the +customization points outlined in :ref:`pubkey/ml_dsa/primitives` and +:ref:`pubkey/ml_dsa/keys`. Namely: + + * :srcref:`ML_DSA_Expanding_Keypair_Codec ` + Implements encoding and decoding of ML-DSA private keys by serializing the + private seed :math:`\xi` and/or expanding the deserialized seed into the + private key representation outlined in :ref:`pubkey/ml_dsa/keys`. + * :srcref:`ML_DSA_MessageHash ` + Implements the transformation of the user-provided message :math:`M` into + the message representation :math:`\mu`. This includes the incorporation of + the domain separations outlined in [FIPS-204]_ Sectoin 5.2 Algorithm 2. + * :srcref:`ML_DSA_Symmetric_Primitives + ` + Implements the ML-DSA specific symmetric primitives based on the specified + SHAKE-based XOFs, the optional hedged randomization of :math:`H(K \| rnd \| \mu)`, + and the domain separator for expanding :math:`\rho`, :math:`\rho'`, and + :math:`K` from the private seed :math:`\xi`. + +.. _pubkey/ml_dsa/ml_dsa_api: + +Public API +^^^^^^^^^^ + +The :srcref:`Dilithium_PublicKey +` +and :srcref:`Dilithium_PrivateKey +` +classes serve as Botan's public API for public and private ML-DSA keys, +respectively. The :srcref:`DilithiumMode +` class +is used to select the desired parameter set. + +New applications that do not rely on the pre-standard Dilithium round 3 +implementations are strongly advised to use the type aliases for ML-DSA defined +in :srcref:`[src/lib/pubkey/dilithium/ml_dsa]/ml_dsa.h`. + + +.. _pubkey/ml_dsa/kyber_compat: + +Dilithium Compatibility +----------------------- + +The final ML-DSA standard is not compatible with the round 3 submission of +Dilithium. Botan did provide support for Dilithium and Dilithium-AES as +specified in [Dilithium-R3]_ since April 2023. This support is still available +and can be activated by enabling the ``dilithium`` or ``dilithium_aes`` modules. + +Note that Dilithium-AES is already deprecated, and both Dilithium and +Dilithium-AES may be removed as early as the next major release of the library. +It is not advisable to use any other variant than the ones specified in +[FIPS-204]_. + +.. _pubkey/ml_dsa/keygen: + +Key Generation +-------------- + +Generating a fresh ML-DSA key pair as specified in [FIPS-204]_ Section 5.1 +Algorithm 1, is available in the constructor of :srcref:`Dilithium_PrivateKey +`. +This mostly delegates the actual key generation to the internal function +:srcref:`expand_keypair +` +that follows [FIPS-204]_ Section 6.1 Algorithm 6. + +.. admonition:: Dilithium_PrivateKey::Dilithium_PrivateKey / Dilithium_Algos::expand_keypair + + **Input:** + + - ``rng``: random number generator + - ``mode``: ML-DSA parameter set descriptor + + **Output:** + + - ``sk``: private signing key + - ``pk``: public verification key + + **Steps:** + + 1. Generate a random 32-byte seed :math:`\xi` using ``rng`` + 2. :math:`(\rho, \rho', K) = H(\xi)` (32, 64, and 32 bytes respectively) + 3. Sample matrix :math:`\hat{A}` from :math:`\rho` using ``expand_A`` + 4. Sample vectors :math:`s_1` and :math:`s_2` from :math:`\rho'` using ``expand_s`` + 5. Calculate :math:`(t_1, t_0)` from :math:`\hat{A}`, :math:`s_1`, and :math:`s_2` using ``compute_t1_and_t0`` (see :srcref:`here `) + + 1. :math:`t = NTT^{-1}(\hat{A} \cdot NTT(s_1)) + s_2` + 2. :math:`(t_1, t_0) = power2round(t)` (see :srcref:`here `) + + 6. :math:`pk = (\rho, t_1)` and :math:`sk = (\xi, K, s_1, s_2, t_0)` + + **Notes:** + + - Step 1 corresponds to [FIPS-204]_ Algorithm 1 + - Steps 2-5 correspond to [FIPS-204]_ Algorithm 6 + - Step 6 returns the key pair in Botan's internal representation. The + encoding and hashing of the encoded public key are done later and on + demand. + + +.. _pubkey/ml_dsa/signing: + +Signing +------- + +Signature generation as specified in [FIPS-204]_ Algorithms 2 and 7 are +implemented in :srcref:`Dilithium_Signature_Operation::sign +` with the +preparation of the message representative :math:`\mu` being done in +:srcref:`DilithiumMessageHash +`. + +.. admonition:: Dilithium_Signature_Operation::sign + + **Input:** + + - ``sk``: private signing key, with :math:`\hat{A}` and :math:`\hat{s_1}`, :math:`\hat{s_2}`, and :math:`\hat{t_0}` in NTT domain + - ``M``: message to be signed + + **Output:** + + - ``signature``: the valid signature + + **Steps:** + + 1. Calculate the message representative :math:`\mu = H(sk.tr \| 0x00 \| 0x00 \| M)` (see :srcref:`here `) + 2. :math:`\rho' = H(sk.K \| rnd \| \mu)` (see :srcref:`here `) + 3. Run the rejection sampling loop (incrementing the nonce :math:`\kappa` by :math:`l` in each iteration) + + 1. Expand :math:`y` from :math:`\rho'` and :math:`\kappa` using ``expand_mask`` + 2. :math:`\hat{w} = \hat{A} \cdot NTT(y)` + 3. :math:`w = NTT^{-1}(\hat{w})` + 4. :math:`(w_1, w_0) = decompose(w)` + 5. :math:`\tilde{c} = H(\mu \| w_1)` (:math:`w_1` is encoded using ``encode_commitment``) + 6. :math:`\hat{c} = NTT(sample\_in\_ball(\tilde{c}))` + 7. :math:`cs_1 = NTT^{-1}(\hat{c} \cdot sk.\hat{s_1})` + 8. :math:`z = y + cs_1` + 9. *Retry* iff :math:`\|z\|_{\infty} \geq \gamma_1 - \beta` (see ``infinity_norm_within_bound``) + 10. :math:`cs_2 = NTT^{-1}(\hat{c} \cdot sk.\hat{s_2})` + 11. :math:`r_0 = w_0 - cs_2` + 12. *Retry* iff :math:`\|r_0\|_{\infty} \geq \gamma_2 - \beta` (see ``infinity_norm_within_bound``)) + 13. :math:`ct_0 = NTT^{-1}(\hat{c} \cdot sk.\hat{t_0})` + 14. *Retry* iff :math:`\|c\|_{\infty} \geq \gamma_2` (see ``infinity_norm_within_bound``) + 15. :math:`h = make\_hint(r_0 + ct_0, w_1)` + 16. *Retry* if the Hamming weight of :math:`h > \omega` + + 4. :math:`\sigma = (\tilde{c}, z, h)` encoded using ``encode_signature`` + + **Notes:** + + - This algorithm description assumes that the private signing key is expanded + into the internal representation already. Additionally, the expansion of + :math:`\hat{A}`, as well as the NTT for :math:`s_1`, :math:`s_2`, and + :math:`t_0` are done :srcref:`prior to the actual signing operation + ` + to armortize the complexity of these operations across multiple consecutive + signature generations. + - Step 1: Botan 3.6.0 does not yet support the application-defined context + string as specified in [FIPS-204]_ Algorithm 2. See `GitHub #4376 + `_. + - Step 3.12: We calculate :math:`r_0 = w_0 - cs_2`, this is equivalent to + :math:`r_0 = LowBits(w - cs_2)` as specified in [FIPS-204]_ Algorithm 7. + - Step 3.15: We generate the hint from :math:`w_0 - cs_2 + ct_0` this is equivalent + to the specification's :math:`w - cs_2 + ct_0`. + +.. _pubkey/ml_dsa/verification: + +Signature Verification +---------------------- + +Signature verification as specified in [FIPS-204]_ Algorithms 3 and 8 are +implemented in :srcref:`Dilithium_Verification_Operation::is_valid_signature +` +with the preparation of the message representative :math:`\mu` being done in +:srcref:`DilithiumMessageHash +`. + +.. admonition:: Dilithium_Verification_Operation::is_valid_signature + + **Input:** + + - ``pk``: public verification key, with :math:`\hat{A}` and :math:`\hat{t_1'} = NTT(t_1 \cdot 2^{d})` in NTT domain + - ``M``: message to be verified + - ``signature``: the signature to be verified + + **Output:** + + - ``ok``: boolean value whether or not the signature is valid + + **Steps:** + + 1. Calculate the message representative :math:`\mu = H(H(pk) \| 0x00 \| 0x00 \| M)` (see :srcref:`here `) + 2. Decode the signature into :math:`(\tilde{c}, z, h)` using ``decode_signature`` + 3. *Abort with "not valid"* if the Hamming weight of :math:`h > \omega` + 4. *Abort with "not valid"* if :math:`\|z\|_{\infty} \geq \gamma_1 - \beta` (see ``infinity_norm_within_bound``) + 5. :math:`\hat{c} = NTT(sample\_in\_ball(\tilde{c}))` + 6. :math:`w'_{approx} = \hat{A} \cdot NTT(z) - \hat{c} \cdot \hat{t_1'}` + 7. :math:`w_1' = use\_hint(w'_{approx}, h)` + 8. :math:`\tilde{c'} = H(\mu, w_1')` (:math:`w_1'` is encoded using ``encode_commitment``) + 9. Iff :math:`\tilde{c} = \tilde{c'}` *return "valid"*, else *"not valid"* + + **Notes:** + + - This algorithm description assumes that the public verification key is + deserialized into the internal representation already. Additionally, the + expansion of :math:`\hat{A}`, as well as the prepartion of + :math:`\hat{t_1'} = NTT(t_1 \cdot 2^{d})` are done :srcref:`prior to the actual + verification operation + ` + to armortize the complexity of these operations across multiple consecutive + signature verification. diff --git a/docs/cryptodoc/src/90_bibliographie.rst b/docs/cryptodoc/src/90_bibliographie.rst index c072e2f7..47fc1675 100644 --- a/docs/cryptodoc/src/90_bibliographie.rst +++ b/docs/cryptodoc/src/90_bibliographie.rst @@ -51,6 +51,10 @@ SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions. http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf +.. [FIPS-204] Federal Information Processing Standards Publication 204. + Module-Lattice-Based Digital Signature Standard. + http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf + .. [FrodoKEM-ISO] Erdem Alkim, Joppe W. Bos, Léo Ducas, Patrick Longa, Ilya Mironov, Michael Naehrig, Valeria Nikolaenko, Chris Peikert, Ananth Raghunathan, Douglas Stebila "FrodoKEM: Learning With Errors Key Encapsulation Preliminary Standardization Proposal (2023-03-14)", Preliminary Standardization Proposal submitted to ISO, 2023,