1use crate::ct;
7
8pub type Limb = u64;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct WideLimb {
14 pub lo: Limb,
16 pub hi: Limb,
18}
19
20impl WideLimb {
21 #[inline(always)]
23 pub const fn new(lo: Limb, hi: Limb) -> Self {
24 Self { lo, hi }
25 }
26}
27
28#[inline(always)]
33pub fn limb_add_carry(a: Limb, b: Limb, carry_in: Limb) -> (Limb, Limb) {
34 let carry_in = carry_in & 1; let sum = a.wrapping_add(b).wrapping_add(carry_in);
36
37 let carry1 = ct::ct_lt(sum, a);
40 let carry2 = (carry_in & ct::ct_eq(sum, a)) & 1;
41 let carry_out = carry1 | carry2;
42
43 (sum, carry_out)
44}
45
46#[inline(always)]
51pub fn limb_sub_borrow(a: Limb, b: Limb, borrow_in: Limb) -> (Limb, Limb) {
52 let borrow_in = borrow_in & 1; let diff = a.wrapping_sub(b).wrapping_sub(borrow_in);
54
55 let borrow1 = ct::ct_lt(a, b);
58 let borrow2 = (borrow_in & ct::ct_eq(a, b)) & 1;
59 let borrow_out = borrow1 | borrow2;
60
61 (diff, borrow_out)
62}
63
64#[inline(always)]
68pub fn limb_mul_wide(a: Limb, b: Limb) -> WideLimb {
69 let result = (a as u128) * (b as u128);
71 WideLimb {
72 lo: result as u64,
73 hi: (result >> 64) as u64,
74 }
75}
76
77#[inline(always)]
81pub fn limb_mac(x: Limb, y: Limb, carry: Limb) -> (Limb, Limb) {
82 limb_add_carry(x, y, carry)
83}
84
85pub fn normalize(limbs: &mut [Limb]) -> usize {
91 let mut len = limbs.len();
92
93 while len > 1 && limbs[len - 1] == 0 {
96 len -= 1;
97 }
98
99 len
100}
101
102pub fn canonicalize(limbs: &mut [Limb]) -> usize {
111 let normalized_len = normalize(limbs);
112
113 if normalized_len == 1 && limbs[0] == 0 {
115 return 1;
116 }
117
118 normalized_len
119}
120
121#[inline(always)]
123pub fn is_zero(limbs: &[Limb]) -> bool {
124 limbs.iter().all(|&x| x == 0)
125}
126
127pub fn ct_compare(a: &[Limb], b: &[Limb]) -> u64 {
136 debug_assert_eq!(a.len(), b.len());
137
138 let mut gt = 0u64;
139 let mut eq = 1u64;
140
141 for i in (0..a.len()).rev() {
143 let a_gt_b = ct::ct_gt(a[i], b[i]);
144 let a_eq_b = ct::ct_eq(a[i], b[i]);
145
146 gt = ct::ct_select(eq, a_gt_b, gt);
149 eq &= a_eq_b;
150 }
151
152 let lt = eq ^ 1; let lt = lt & !gt; (lt << 1) | gt
157}
158
159#[cfg(all(test, feature = "alloc"))]
160mod tests {
161 #[cfg(feature = "alloc")]
162 use alloc::vec;
163 use super::*;
164
165 #[test]
166 fn test_limb_add_carry() {
167 let (sum, carry) = limb_add_carry(10, 20, 0);
168 assert_eq!(sum, 30);
169 assert_eq!(carry, 0);
170
171 let (sum, carry) = limb_add_carry(u64::MAX, 1, 0);
172 assert_eq!(sum, 0);
173 assert_eq!(carry, 1);
174
175 let (sum, carry) = limb_add_carry(u64::MAX, 0, 1);
176 assert_eq!(sum, 0);
177 assert_eq!(carry, 1);
178 }
179
180 #[test]
181 fn test_limb_sub_borrow() {
182 let (diff, borrow) = limb_sub_borrow(20, 10, 0);
183 assert_eq!(diff, 10);
184 assert_eq!(borrow, 0);
185
186 let (_diff, borrow) = limb_sub_borrow(10, 20, 0);
187 assert_eq!(borrow, 1);
188
189 let (_diff, borrow) = limb_sub_borrow(0, 0, 1);
190 assert_eq!(borrow, 1);
191 }
192
193 #[test]
194 fn test_limb_mul_wide() {
195 let result = limb_mul_wide(0xFFFFFFFFFFFFFFFF, 2);
196 assert_eq!(result.lo, 0xFFFFFFFFFFFFFFFE);
197 assert_eq!(result.hi, 1);
198
199 let result = limb_mul_wide(1 << 32, 1 << 32);
200 assert_eq!(result.lo, 0);
201 assert_eq!(result.hi, 1);
202 }
203
204 #[test]
205 fn test_normalize() {
206 let mut limbs = vec![1, 0, 0, 0];
207 assert_eq!(normalize(&mut limbs), 1);
208
209 let mut limbs = vec![1, 2, 0, 0];
210 assert_eq!(normalize(&mut limbs), 2);
211
212 let mut limbs = vec![0, 0, 0, 0];
213 assert_eq!(normalize(&mut limbs), 1);
214 }
215
216 #[test]
217 fn test_is_zero() {
218 assert!(is_zero(&[0, 0, 0]));
219 assert!(!is_zero(&[1, 0, 0]));
220 assert!(!is_zero(&[0, 1, 0]));
221 }
222}