Skip to main content

fixed_bigint/heapless/
identities.rs

1//! `Zero`, `One`, `Default` for `HeaplessBigInt`.
2//!
3//! - `Zero`: mathematical zero, `len = 0`.
4//! - `One`: `len = 1`, `limbs[0] = T::ONE`.
5//! - `Default = Zero`. (The CIOS full-CAP zero is a separate constructor,
6//!   `cios_accumulator`, not `Default`.)
7
8use super::{AssertCapFits, HeaplessBigInt, zero};
9use crate::MachineWord;
10use const_num_traits::{ConstOne, ConstZero, One, Personality, PersonalityTag, Zero};
11use core::marker::PhantomData;
12
13// ── const_num_traits::Zero / One ──
14
15impl<T: MachineWord, const CAP: usize, P: Personality> Zero for HeaplessBigInt<T, CAP, P> {
16    #[inline]
17    fn zero() -> Self {
18        Self::const_zero()
19    }
20
21    #[inline]
22    fn is_zero(&self) -> bool {
23        // Any limb non-zero → non-zero. `Nct` short-circuits; `Ct`
24        // OR-folds every limb so timing is value-independent (the returned
25        // `bool` is still branchable — see `CtIsZero::ct_is_zero` for the
26        // `Choice`-returning form). Limbs beyond `len` are zero by the
27        // zero-tail invariant, so scanning `0..len` suffices.
28        let n = self.len as usize;
29        match P::TAG {
30            PersonalityTag::Nct => {
31                let mut i = 0;
32                while i < n {
33                    if !super::is_zero(&self.limbs[i]) {
34                        return false;
35                    }
36                    i += 1;
37                }
38                true
39            }
40            PersonalityTag::Ct => {
41                let mut acc = zero::<T>();
42                let mut i = 0;
43                while i < n {
44                    acc |= self.limbs[i];
45                    i += 1;
46                }
47                super::is_zero(&acc)
48            }
49        }
50    }
51
52    #[inline]
53    fn set_zero(&mut self) {
54        *self = <Self as Zero>::zero();
55    }
56}
57
58impl<T: MachineWord, const CAP: usize, P: Personality> One for HeaplessBigInt<T, CAP, P> {
59    #[inline]
60    fn one() -> Self {
61        let () = <Self as AssertCapFits>::CHECK;
62        Self::const_one()
63    }
64
65    #[inline]
66    fn set_one(&mut self) {
67        *self = <Self as One>::one();
68    }
69
70    #[inline]
71    fn is_one(&self) -> bool {
72        // `len` is a public shape parameter, so branching on it is fine in
73        // both personalities. `Nct` short-circuits the limb scan; `Ct`
74        // folds `(limbs[0] ^ 1) | limbs[1] | …` with no early return.
75        let n = self.len as usize;
76        if n == 0 {
77            return false;
78        }
79        match P::TAG {
80            PersonalityTag::Nct => {
81                if !<T as const_num_traits::One>::is_one(&self.limbs[0]) {
82                    return false;
83                }
84                let mut i = 1;
85                while i < n {
86                    if !super::is_zero(&self.limbs[i]) {
87                        return false;
88                    }
89                    i += 1;
90                }
91                true
92            }
93            PersonalityTag::Ct => {
94                let mut acc = self.limbs[0] ^ <T as ConstOne>::ONE;
95                let mut i = 1;
96                while i < n {
97                    acc |= self.limbs[i];
98                    i += 1;
99                }
100                super::is_zero(&acc)
101            }
102        }
103    }
104}
105
106impl<T: MachineWord, const CAP: usize, P: Personality> Default for HeaplessBigInt<T, CAP, P> {
107    #[inline]
108    fn default() -> Self {
109        <Self as Zero>::zero()
110    }
111}
112
113// ── const_num_traits::ConstZero / ConstOne ──
114//
115// Declared as `const` items so downstream can use them in const
116// expressions. `ConstOne::ONE` needs a mutable-array initialisation
117// step, which requires a helper `const fn` on stable.
118
119impl<T: MachineWord, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P> {
120    #[inline]
121    const fn const_zero() -> Self {
122        Self {
123            limbs: [<T as ConstZero>::ZERO; CAP],
124            len: 0,
125            _p: PhantomData,
126        }
127    }
128
129    #[inline]
130    const fn const_one() -> Self {
131        assert!(CAP >= 1, "HeaplessBigInt::ONE requires CAP >= 1");
132        let mut limbs = [<T as ConstZero>::ZERO; CAP];
133        limbs[0] = <T as ConstOne>::ONE;
134        Self {
135            limbs,
136            len: 1,
137            _p: PhantomData,
138        }
139    }
140}
141
142impl<T: MachineWord, const CAP: usize, P: Personality> ConstZero for HeaplessBigInt<T, CAP, P> {
143    const ZERO: Self = Self::const_zero();
144}
145
146impl<T: MachineWord, const CAP: usize, P: Personality> ConstOne for HeaplessBigInt<T, CAP, P> {
147    const ONE: Self = Self::const_one();
148}