1use crate::{
6 Choice, CtSelect, Limb, NonZero, Uint, WideWord, Word, primitives::widening_mul, word,
7};
8
9cpubits::cpubits! {
10 32 => {
11 pub const fn reciprocal(d: Word) -> Word {
15 debug_assert!(d >= (1 << (Word::BITS - 1)));
16
17 let d0 = d & 1;
18 let d10 = d >> 22;
19 let d21 = (d >> 11) + 1;
20 let d31 = (d >> 1) + d0;
21 let v0 = short_div((1 << 24) - (1 << 14) + (1 << 9), 24, d10, 10);
22 let (_lo, hi) = widening_mul(v0 * v0, d21);
23 let v1 = (v0 << 4) - hi - 1;
24
25 debug_assert!(widening_mul(v1, d31).1 == (1 << 16) - 1);
27 let e = v1.wrapping_mul(d31).wrapping_neg() + (v1 >> 1) * d0;
28
29 let (_lo, hi) = widening_mul(v1, e);
30 let v2 = (v1 << 15).wrapping_add(hi >> 1);
34
35 let x = v2.wrapping_add(1);
39 let (_lo, hi) = widening_mul(x, d);
40 let hi = word::select(d, hi, Choice::from_u32_nz(x));
41
42 v2.wrapping_sub(hi).wrapping_sub(d)
43 }
44 }
45 64 => {
46 pub const fn reciprocal(d: Word) -> Word {
50 debug_assert!(d >= (1 << (Word::BITS - 1)));
51
52 let d0 = d & 1;
53 let d9 = d >> 55;
54 let d40 = (d >> 24) + 1;
55 let d63 = (d >> 1) + d0;
56 let v0 = short_div((1 << 19) - 3 * (1 << 8), 19, d9 as u32, 9) as u64;
57 let v1 = (v0 << 11) - ((v0 * v0 * d40) >> 40) - 1;
58 let v2 = (v1 << 13) + ((v1 * ((1 << 60) - v1 * d40)) >> 47);
59
60 debug_assert!(widening_mul(v2, d63).1 == (1 << 32) - 1);
62 let e = v2.wrapping_mul(d63).wrapping_neg() + (v2 >> 1) * d0;
63
64 let (_lo, hi) = widening_mul(v2, e);
65 let v3 = (v2 << 31).wrapping_add(hi >> 1);
66
67 let x = v3.wrapping_add(1);
71 let (_lo, hi) = widening_mul(x, d);
72 let hi = word::select(d, hi, word::choice_from_nz(x));
73
74 v3.wrapping_sub(hi).wrapping_sub(d)
75 }
76 }
77}
78
79#[inline(always)]
82const fn short_div(mut dividend: u32, dividend_bits: u32, divisor: u32, divisor_bits: u32) -> u32 {
83 let mut divisor = divisor << (dividend_bits - divisor_bits);
93 let mut quotient: u32 = 0;
94 let mut i = dividend_bits - divisor_bits + 1;
95
96 while i > 0 {
97 i -= 1;
98 let bit = Choice::from_u32_lt(dividend, divisor);
99 dividend = bit.select_u32(dividend.wrapping_sub(divisor), dividend);
100 divisor >>= 1;
101 quotient |= bit.not().select_u32(0, 1 << i);
102 }
103
104 quotient
105}
106
107#[inline(always)]
112pub(crate) const fn div2by1(u0: Word, u1: Word, reciprocal: &Reciprocal) -> (Word, Word) {
113 let d = reciprocal.divisor_normalized;
114 let v = reciprocal.reciprocal;
115
116 debug_assert!(d >= (1 << (Word::BITS - 1)), "divisor top bit unset");
117 debug_assert!(u1 < d, "dividend >= divisor");
118
119 let q = (v as WideWord * u1 as WideWord) + word::join(u0, u1);
120 let (q0, q1) = word::split_wide(q);
121 let q1 = q1.wrapping_add(1);
122 let r = u0.wrapping_sub(q1.wrapping_mul(d));
123
124 let r_gt_q0 = word::choice_to_mask(word::choice_from_lt(q0, r));
125 let q1 = q1.wrapping_sub(r_gt_q0 & 1);
126 let r = r.wrapping_add(r_gt_q0 & d);
127
128 debug_assert!(r < d || q1 < Word::MAX);
132 let r_ge_d = word::choice_to_mask(word::choice_from_le(d, r));
133 let q1 = q1.wrapping_add(r_ge_d & 1);
134 let r = r.wrapping_sub(r_ge_d & d);
135
136 (q1, r)
137}
138
139#[inline(always)]
147#[allow(clippy::cast_possible_truncation)]
148pub(crate) const fn div3by2(
149 (u0, u1, u2): (Word, Word, Word),
150 (d0, d1): (Word, Word),
151 v: Word,
152) -> (Word, WideWord) {
153 let d = word::join(d0, d1);
154 let u_hi = word::join(u1, u2);
155
156 debug_assert!(d >= (1 << (WideWord::BITS - 1)), "divisor top bit unset");
157 debug_assert!(u_hi <= d, "dividend > divisor");
158
159 let q = (v as WideWord * u2 as WideWord) + u_hi;
160 let (q0, q1) = word::split_wide(q);
161 let r1 = u1.wrapping_sub(q1.wrapping_mul(d1));
162 let t = d0 as WideWord * q1 as WideWord;
163 let r = word::join(u0, r1).wrapping_sub(t).wrapping_sub(d);
164
165 let r1_ge_q0 = word::choice_to_wide_mask(word::choice_from_le(q0, (r >> Word::BITS) as Word));
166 let q1 = q1.wrapping_add(!(r1_ge_q0 as Word) & 1);
167 let r = r.wrapping_add(r1_ge_q0 & d);
168
169 let r_ge_d = word::choice_to_wide_mask(word::choice_from_wide_le(d, r));
170 let q1 = q1.wrapping_add(r_ge_d as Word & 1);
171 let r = r.wrapping_sub(r_ge_d & d);
172
173 let maxed = word::choice_from_wide_eq(u_hi, d);
177 let q1 = q1 | word::choice_to_mask(maxed);
178 let r = word::select_wide(r, d.saturating_add(u0 as WideWord), maxed);
179
180 (q1, r)
181}
182
183#[derive(Copy, Clone, Debug, PartialEq, Eq)]
185pub struct Reciprocal {
186 divisor_normalized: Word,
187 shift: u32,
188 reciprocal: Word,
189}
190
191impl Reciprocal {
192 #[must_use]
195 pub const fn new(divisor: NonZero<Limb>) -> Self {
196 let divisor = divisor.get_copy();
197
198 let shift = divisor.leading_zeros();
199
200 let divisor_normalized = divisor.0 << shift;
202
203 Self {
204 divisor_normalized,
205 shift,
206 reciprocal: reciprocal(divisor_normalized),
207 }
208 }
209
210 #[must_use]
216 pub const fn default() -> Self {
217 Self {
218 divisor_normalized: Word::MAX,
219 shift: 0,
220 reciprocal: 1,
223 }
224 }
225
226 #[must_use]
228 pub const fn shift(&self) -> u32 {
229 self.shift
230 }
231
232 #[must_use]
236 pub const fn reciprocal_3by2(&self, d0: Word, d1: Word) -> Word {
237 debug_assert!(self.shift == 0 && d1 == self.divisor_normalized);
238
239 let v = self.reciprocal;
240 let p = d1.wrapping_mul(v).wrapping_add(d0);
241
242 let p_lt_d0 = word::choice_from_lt(p, d0);
243 let v = word::select(v, v.wrapping_sub(1), p_lt_d0);
244
245 let p_ge_d1 = word::choice_from_le(d1, p).and(p_lt_d0);
246 let v = word::select(v, v.wrapping_sub(1), p_ge_d1);
247 let p = word::select(p, p.wrapping_sub(d1), p_ge_d1);
248 let p = word::select(p, p.wrapping_sub(d1), p_lt_d0);
249
250 let (t0, t1) = widening_mul(v, d0);
251 let p = p.wrapping_add(t1);
252
253 let p_lt_t1 = word::choice_from_lt(p, t1);
254 let v = word::select(v, v.wrapping_sub(1), p_lt_t1);
255 let d = word::join(d0, d1);
256 let t0p = word::join(t0, p);
257 let t0p_ge_d = word::choice_from_wide_le(d, t0p).and(p_lt_t1);
258 word::select(v, v.wrapping_sub(1), t0p_ge_d)
259 }
260}
261
262impl CtSelect for Reciprocal {
263 fn ct_select(&self, other: &Self, choice: Choice) -> Self {
264 Self {
265 divisor_normalized: Word::ct_select(
266 &self.divisor_normalized,
267 &other.divisor_normalized,
268 choice,
269 ),
270 shift: u32::ct_select(&self.shift, &other.shift, choice),
271 reciprocal: Word::ct_select(&self.reciprocal, &other.reciprocal, choice),
272 }
273 }
274}
275
276impl Default for Reciprocal {
279 fn default() -> Self {
280 Self::default()
281 }
282}
283
284#[inline(always)]
286pub(crate) const fn rem_limb_with_reciprocal<const L: usize>(
287 u: &Uint<L>,
288 reciprocal: &Reciprocal,
289) -> Limb {
290 let (u_shifted, u_hi) = u.shl_limb_with_carry(reciprocal.shift, Limb::ZERO);
291 let mut r = u_hi.0;
292
293 let mut j = L;
294 while j > 0 {
295 j -= 1;
296 let (_, rj) = div2by1(u_shifted.as_limbs()[j].0, r, reciprocal);
297 r = rj;
298 }
299 Limb(r >> reciprocal.shift)
300}
301
302#[inline(always)]
304pub(crate) const fn mul_rem(a: Limb, b: Limb, d: NonZero<Limb>) -> Limb {
305 let rec = Reciprocal::new(d);
306 let (lo, hi) = widening_mul(a.0, b.0);
307 rem_limb_with_reciprocal(&Uint::from_words([lo, hi]), &rec)
308}
309
310#[cfg(test)]
311mod tests {
312 use super::{Reciprocal, div2by1, reciprocal};
313 use crate::{Limb, NonZero, Uint, WideWord, Word, word};
314
315 #[test]
316 fn reciprocal_valid() {
317 #![allow(clippy::integer_division_remainder_used, reason = "test")]
318 fn test(d: Word) {
319 let v = reciprocal(d);
320
321 let expected = WideWord::MAX / WideWord::from(d) - WideWord::from(Word::MAX) - 1;
324 assert_eq!(WideWord::from(v), expected);
325 }
326
327 test(Word::MAX);
328 test(1 << (Word::BITS - 1));
329 test((1 << (Word::BITS - 1)) | 1);
330 }
331
332 #[test]
333 fn reciprocal_3by2_valid() {
334 fn test(d: WideWord) {
335 let (d0, d1) = word::split_wide(d);
336 let v0 = Reciprocal::new(NonZero::<Limb>::new_unwrap(Limb(d1)));
337 let v = v0.reciprocal_3by2(d0, d1);
338
339 let actual = (Uint::<3>::from_word(v)
344 + Uint::<3>::ZERO.set_bit_vartime(Word::BITS, true))
345 .checked_mul(&Uint::<3>::from_wide_word(d))
346 .expect("overflow");
347 let min = Uint::<3>::MAX - Uint::<3>::from_wide_word(d);
348 assert!(actual > min, "{actual} <= {min}");
349 }
350
351 test(WideWord::MAX);
352 test(1 << (WideWord::BITS - 1));
353 test((1 << (WideWord::BITS - 1)) | 1);
354 }
355
356 #[test]
357 fn div2by1_overflow() {
358 let r = Reciprocal::new(NonZero::new(Limb(Word::MAX - 1)).unwrap());
362 assert_eq!(
363 div2by1(Word::MAX - 63, Word::MAX - 2, &r),
364 (Word::MAX, Word::MAX - 65)
365 );
366 }
367}