Skip to main content

crypto_bigint/modular/const_monty_form/
sqrt.rs

1use core::marker::PhantomData;
2
3use super::ConstPrimeMontyParams;
4use crate::{
5    CtOption,
6    modular::{ConstMontyForm, sqrt::sqrt_montgomery_form},
7};
8
9impl<const LIMBS: usize, MOD> ConstMontyForm<MOD, LIMBS>
10where
11    MOD: ConstPrimeMontyParams<LIMBS>,
12{
13    /// Compute the modular square root for `self`, if it exists.
14    #[must_use]
15    pub const fn sqrt(&self) -> CtOption<Self> {
16        let res = sqrt_montgomery_form(self.as_montgomery(), &MOD::PARAMS, &MOD::PRIME_PARAMS);
17        let is_some = res.is_some();
18        CtOption::new(
19            Self {
20                montgomery_form: *res.as_inner_unchecked(),
21                phantom: PhantomData,
22            },
23            is_some,
24        )
25    }
26}
27
28#[cfg(test)]
29mod tests {
30    use crate::{
31        U256, const_prime_monty_params,
32        modular::{ConstMontyForm, ConstPrimeMontyParams},
33    };
34
35    #[test]
36    fn check_sqrt() {
37        // P-256 field modulus
38        // p = 3 mod 4, s = 1, uses Shanks algorithm
39        const_prime_monty_params!(
40            P256Field,
41            U256,
42            "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
43            6
44        );
45        assert_eq!(P256Field::PRIME_PARAMS.s().get(), 1);
46        type ConstForm = ConstMontyForm<P256Field, { U256::LIMBS }>;
47
48        // four is square
49        let four_monty = ConstForm::new(&U256::from(4u32));
50        assert_eq!(
51            four_monty.sqrt().expect("ensured square"),
52            ConstForm::new(&U256::from(2u32))
53        );
54
55        // generator must be non-residue
56        let generator = U256::from_u32(P256Field::PRIME_PARAMS.generator().get());
57        let gen_monty = ConstForm::new(&generator);
58        assert!(gen_monty.sqrt().is_none().to_bool_vartime());
59    }
60}