crypto_bigint/uint/boxed/
neg_mod.rs

1//! [`BoxedUint`] modular negation operations.
2
3use crate::{BoxedUint, Limb, NegMod};
4use subtle::ConditionallySelectable;
5
6impl BoxedUint {
7    /// Computes `-a mod p`.
8    /// Assumes `self` is in `[0, p)`.
9    pub fn neg_mod(&self, p: &Self) -> Self {
10        debug_assert_eq!(self.bits_precision(), p.bits_precision());
11        let is_zero = self.is_zero();
12        let mut ret = p.sbb(self, Limb::ZERO).0;
13
14        for i in 0..self.nlimbs() {
15            // Set ret to 0 if the original value was 0, in which
16            // case ret would be p.
17            ret.limbs[i].conditional_assign(&Limb::ZERO, is_zero);
18        }
19
20        ret
21    }
22
23    /// Computes `-a mod p` for the special modulus
24    /// `p = MAX+1-c` where `c` is small enough to fit in a single [`Limb`].
25    pub fn neg_mod_special(&self, c: Limb) -> Self {
26        Self::zero_with_precision(self.bits_precision()).sub_mod_special(self, c)
27    }
28}
29
30impl NegMod for BoxedUint {
31    type Output = Self;
32
33    fn neg_mod(&self, p: &Self) -> Self {
34        debug_assert!(self < p);
35        self.neg_mod(p)
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use crate::BoxedUint;
42    use hex_literal::hex;
43
44    #[test]
45    fn neg_mod_random() {
46        let x = BoxedUint::from_be_slice(
47            &hex!("8d16e171674b4e6d8529edba4593802bf30b8cb161dd30aa8e550d41380007c2"),
48            256,
49        )
50        .unwrap();
51        let p = BoxedUint::from_be_slice(
52            &hex!("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"),
53            256,
54        )
55        .unwrap();
56
57        let actual = x.neg_mod(&p);
58        let expected = BoxedUint::from_be_slice(
59            &hex!("056c53337d72b9d666f86c9256ce5f08cabc1b63b207864ce0d6ecf010e2d9f3"),
60            256,
61        )
62        .unwrap();
63
64        assert_eq!(expected, actual);
65    }
66
67    #[test]
68    fn neg_mod_zero() {
69        let x = BoxedUint::from_be_slice(
70            &hex!("0000000000000000000000000000000000000000000000000000000000000000"),
71            256,
72        )
73        .unwrap();
74        let p = BoxedUint::from_be_slice(
75            &hex!("928334a4e4be0843ec225a4c9c61df34bdc7a81513e4b6f76f2bfa3148e2e1b5"),
76            256,
77        )
78        .unwrap();
79
80        let actual = x.neg_mod(&p);
81        let expected = BoxedUint::from_be_slice(
82            &hex!("0000000000000000000000000000000000000000000000000000000000000000"),
83            256,
84        )
85        .unwrap();
86
87        assert_eq!(expected, actual);
88    }
89}