crypto_bigint/modular/const_monty_form/
macros.rs

1//! Macro support.
2
3/// Implements a modulus with the given name, type, and value, in that specific order. Please
4/// `use crypto_bigint::traits::Encoding` to make this work.
5///
6/// For example,
7/// `impl_modulus!(MyModulus, U256, "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");`
8/// implements a 256-bit modulus named `MyModulus`.
9///
10/// The modulus _must_ be odd, or this will panic.
11// TODO: Use `adt_const_params` once stabilized to make a `ConstMontyForm` generic around a modulus rather
12// than having to implement a ZST + trait
13#[macro_export]
14macro_rules! impl_modulus {
15    ($name:ident, $uint_type:ty, $value:expr) => {
16        impl_modulus!(
17            $name,
18            $uint_type,
19            $value,
20            "Modulus which impls `ConstMontyParams`"
21        );
22    };
23    ($name:ident, $uint_type:ty, $value:expr, $doc:expr) => {
24        #[doc = $doc]
25        #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
26        pub struct $name;
27        impl<const DLIMBS: usize> $crate::modular::ConstMontyParams<{ <$uint_type>::LIMBS }>
28            for $name
29        where
30            $uint_type: $crate::ConcatMixed<MixedOutput = $crate::Uint<DLIMBS>>,
31        {
32            const LIMBS: usize = <$uint_type>::LIMBS;
33            const MODULUS: $crate::Odd<$uint_type> = $crate::Odd::<$uint_type>::from_be_hex($value);
34
35            // `R mod MODULUS` where `R = 2^BITS`.
36            // Represents 1 in Montgomery form.
37            const ONE: $uint_type = $crate::Uint::MAX
38                .rem_vartime(Self::MODULUS.as_nz_ref())
39                .wrapping_add(&$crate::Uint::ONE);
40
41            // `R^2 mod MODULUS`, used to convert integers to Montgomery form.
42            const R2: $uint_type =
43                $crate::Uint::rem_wide_vartime(Self::ONE.square_wide(), Self::MODULUS.as_nz_ref());
44
45            const MOD_NEG_INV: $crate::Limb = $crate::Limb(
46                $crate::Word::MIN.wrapping_sub(
47                    Self::MODULUS
48                        .as_ref()
49                        .inv_mod2k_vartime($crate::Word::BITS)
50                        .expect("modulus ensured odd")
51                        .as_limbs()[0]
52                        .0,
53                ),
54            );
55
56            // Leading zeros in the modulus, used to choose optimized algorithms.
57            const MOD_LEADING_ZEROS: u32 = {
58                let z = Self::MODULUS.as_ref().leading_zeros();
59                if z >= $crate::Word::BITS {
60                    $crate::Word::BITS - 1
61                } else {
62                    z
63                }
64            };
65
66            const R3: $uint_type = $crate::modular::montgomery_reduction(
67                &Self::R2.square_wide(),
68                &Self::MODULUS,
69                Self::MOD_NEG_INV,
70            );
71        }
72    };
73}
74
75/// Creates a `ConstMontyForm` with the given value for a specific modulus.
76///
77/// For example, `const_monty_form!(U256::from(105u64), MyModulus);`
78/// creates a `ConstMontyForm` for 105 mod `MyModulus`.
79///
80/// The modulus _must_ be odd, or this will panic.
81#[macro_export]
82macro_rules! const_monty_form {
83    ($variable:ident, $modulus:ident) => {
84        $crate::modular::ConstMontyForm::<$modulus, { $modulus::LIMBS }>::new(&$variable)
85    };
86}
87
88#[cfg(test)]
89mod tests {
90    use crate::modular::ConstMontyParams;
91    use crate::{Limb, U64};
92
93    #[test]
94    fn new_params_with_valid_modulus() {
95        impl_modulus!(Mod, U64, "0000000000000003");
96
97        assert_eq!(Mod::MOD_LEADING_ZEROS, core::cmp::min(Limb::BITS - 1, 62));
98    }
99}