Skip to main content

crypto_bigint/int/
sqrt.rs

1//! [`Int`] square root operations.
2
3use super::Int;
4use crate::{CheckedSquareRoot, CtOption};
5
6impl<const LIMBS: usize> Int<LIMBS> {
7    /// Perform checked sqrt, returning a [`CtOption`] which `is_some`
8    /// only if the integer is non-negative and the square root is exact.
9    #[must_use]
10    pub fn checked_sqrt(&self) -> CtOption<Self> {
11        self.as_uint()
12            .checked_sqrt()
13            .map(|rt| Self::new(rt.limbs))
14            .filter_by(self.is_negative().not())
15    }
16
17    /// Perform checked sqrt, returning a [`CtOption`] which `is_some`
18    /// only if the integer is non-negative and the square root is exact.
19    ///
20    /// Variable time with respect to `self`.
21    #[must_use]
22    pub fn checked_sqrt_vartime(&self) -> Option<Self> {
23        if self.is_negative().not().to_bool_vartime() {
24            self.as_uint()
25                .checked_sqrt_vartime()
26                .map(|rt| Self::new(rt.limbs))
27        } else {
28            None
29        }
30    }
31}
32
33impl<const LIMBS: usize> CheckedSquareRoot for Int<LIMBS> {
34    type Output = Self;
35
36    fn checked_sqrt(&self) -> CtOption<Self::Output> {
37        self.checked_sqrt()
38    }
39
40    fn checked_sqrt_vartime(&self) -> Option<Self::Output> {
41        self.checked_sqrt_vartime()
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use crate::{CheckedSquareRoot, I256};
48
49    #[test]
50    fn square_root_expected() {
51        let tests = [
52            (I256::ZERO, Some(I256::ZERO)),
53            (I256::ONE, Some(I256::ONE)),
54            (I256::MINUS_ONE, None),
55            (I256::from_i8(4), Some(I256::from_i8(2))),
56        ];
57        for (case, expect) in tests {
58            assert_eq!(CheckedSquareRoot::checked_sqrt(&case).into_option(), expect);
59            assert_eq!(CheckedSquareRoot::checked_sqrt_vartime(&case), expect);
60        }
61    }
62}