Skip to main content

fixed_bigint/heapless/
parity.rs

1//! `const_num_traits::Parity` (and its masked-return `CtParity`) for
2//! `HeaplessBigInt`.
3//!
4//! Parity is a single-bit inspection of the lowest limb — no full-value
5//! scan. For `len == 0` (mathematical zero shape) the answer is
6//! deterministically even.
7
8use super::HeaplessBigInt;
9use crate::MachineWord;
10use const_num_traits::{Parity, Personality};
11
12impl<T, const CAP: usize, P: Personality> Parity for HeaplessBigInt<T, CAP, P>
13where
14    T: MachineWord + Parity,
15{
16    fn is_odd(self) -> bool {
17        if self.len == 0 {
18            false
19        } else {
20            self.limbs[0].is_odd()
21        }
22    }
23
24    fn is_even(self) -> bool {
25        !self.is_odd()
26    }
27}
28
29// `CtParity` — masked-return parity, same subtle-predicate style as
30// `CtIsZero` (cmp.rs). Uniform across personalities; `subtle`'s
31// constructors aren't `const fn`, so this is a plain impl. A `len == 0`
32// value is deterministically even.
33impl<T, const CAP: usize, P: Personality> const_num_traits::ops::ct::CtParity
34    for HeaplessBigInt<T, CAP, P>
35where
36    T: MachineWord + subtle::ConstantTimeEq,
37{
38    fn ct_is_odd(&self) -> subtle::Choice {
39        if self.len == 0 {
40            return subtle::Choice::from(0);
41        }
42        let lsb = self.limbs[0] & <T as const_num_traits::ConstOne>::ONE;
43        !lsb.ct_eq(&<T as const_num_traits::ConstZero>::ZERO)
44    }
45
46    fn ct_is_even(&self) -> subtle::Choice {
47        !<Self as const_num_traits::ops::ct::CtParity>::ct_is_odd(self)
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::HeaplessBigInt;
54    use const_num_traits::ops::ct::CtParity;
55
56    type H = HeaplessBigInt<u8, 4>;
57
58    #[test]
59    fn ct_parity_matches_value_parity() {
60        for v in [0u32, 1, 2, 3, 0xFFFF_FFFE, 0xFFFF_FFFF] {
61            let h = H::from(v);
62            assert_eq!(bool::from(h.ct_is_odd()), v & 1 == 1, "odd({v})");
63            assert_eq!(bool::from(h.ct_is_even()), v & 1 == 0, "even({v})");
64        }
65    }
66}