Skip to main content

fixed_bigint/heapless/
midpoint.rs

1//! `const_num_traits::Midpoint` for `HeaplessBigInt`.
2//!
3//! `(a & b) + ((a ^ b) >> 1)` averages without overflow, and is branchless, so
4//! it is personality-generic and constant-time. The `>> 1` is a single-bit
5//! shift (width-preserving), and `&`/`^`/`+` all resolve at `max(len)`, so the
6//! result is at the operand width.
7
8use super::HeaplessBigInt;
9use crate::MachineWord;
10use const_num_traits::{Midpoint, Personality};
11
12impl<T, const CAP: usize, P: Personality> Midpoint for HeaplessBigInt<T, CAP, P>
13where
14    T: MachineWord,
15{
16    type Output = Self;
17    fn midpoint(self, rhs: Self) -> Self {
18        (self & rhs) + ((self ^ rhs) >> 1usize)
19    }
20}
21
22// `&Self` mirror so `(&h).midpoint(&g)` resolves without an explicit copy.
23impl<T, const CAP: usize, P: Personality> Midpoint for &HeaplessBigInt<T, CAP, P>
24where
25    T: MachineWord,
26{
27    type Output = HeaplessBigInt<T, CAP, P>;
28    fn midpoint(self, rhs: Self) -> Self::Output {
29        <HeaplessBigInt<T, CAP, P> as Midpoint>::midpoint(*self, *rhs)
30    }
31}
32
33#[cfg(test)]
34mod tests {
35    use super::HeaplessBigInt;
36    use const_num_traits::Midpoint;
37
38    type H = HeaplessBigInt<u8, 4>;
39
40    #[test]
41    fn byref_matches_value() {
42        let a = H::from(10u8);
43        let b = H::from(21u8);
44        assert_eq!(Midpoint::midpoint(&a, &b), Midpoint::midpoint(a, b));
45    }
46}