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.0.leading_zeros();
200
201 let divisor_normalized = divisor.0 << shift;
203
204 Self {
205 divisor_normalized,
206 shift,
207 reciprocal: reciprocal(divisor_normalized),
208 }
209 }
210
211 #[must_use]
217 pub const fn default() -> Self {
218 Self {
219 divisor_normalized: Word::MAX,
220 shift: 0,
221 reciprocal: 1,
224 }
225 }
226
227 #[must_use]
229 pub const fn shift(&self) -> u32 {
230 self.shift
231 }
232
233 #[must_use]
237 pub const fn reciprocal_3by2(&self, d0: Word, d1: Word) -> Word {
238 debug_assert!(self.shift == 0 && d1 == self.divisor_normalized);
239
240 let v = self.reciprocal;
241 let p = d1.wrapping_mul(v).wrapping_add(d0);
242
243 let p_lt_d0 = word::choice_from_lt(p, d0);
244 let v = word::select(v, v.wrapping_sub(1), p_lt_d0);
245
246 let p_ge_d1 = word::choice_from_le(d1, p).and(p_lt_d0);
247 let v = word::select(v, v.wrapping_sub(1), p_ge_d1);
248 let p = word::select(p, p.wrapping_sub(d1), p_ge_d1);
249 let p = word::select(p, p.wrapping_sub(d1), p_lt_d0);
250
251 let (t0, t1) = widening_mul(v, d0);
252 let p = p.wrapping_add(t1);
253
254 let p_lt_t1 = word::choice_from_lt(p, t1);
255 let v = word::select(v, v.wrapping_sub(1), p_lt_t1);
256 let d = word::join(d0, d1);
257 let t0p = word::join(t0, p);
258 let t0p_ge_d = word::choice_from_wide_le(d, t0p).and(p_lt_t1);
259 word::select(v, v.wrapping_sub(1), t0p_ge_d)
260 }
261}
262
263impl CtSelect for Reciprocal {
264 fn ct_select(&self, other: &Self, choice: Choice) -> Self {
265 Self {
266 divisor_normalized: Word::ct_select(
267 &self.divisor_normalized,
268 &other.divisor_normalized,
269 choice,
270 ),
271 shift: u32::ct_select(&self.shift, &other.shift, choice),
272 reciprocal: Word::ct_select(&self.reciprocal, &other.reciprocal, choice),
273 }
274 }
275}
276
277impl Default for Reciprocal {
280 fn default() -> Self {
281 Self::default()
282 }
283}
284
285#[inline(always)]
287pub(crate) const fn rem_limb_with_reciprocal<const L: usize>(
288 u: &Uint<L>,
289 reciprocal: &Reciprocal,
290) -> Limb {
291 let (u_shifted, u_hi) = u.shl_limb_with_carry(reciprocal.shift, Limb::ZERO);
292 let mut r = u_hi.0;
293
294 let mut j = L;
295 while j > 0 {
296 j -= 1;
297 let (_, rj) = div2by1(u_shifted.as_limbs()[j].0, r, reciprocal);
298 r = rj;
299 }
300 Limb(r >> reciprocal.shift)
301}
302
303#[inline(always)]
305pub(crate) const fn mul_rem(a: Limb, b: Limb, d: NonZero<Limb>) -> Limb {
306 let rec = Reciprocal::new(d);
307 let (lo, hi) = widening_mul(a.0, b.0);
308 rem_limb_with_reciprocal(&Uint::from_words([lo, hi]), &rec)
309}
310
311#[cfg(test)]
312mod tests {
313 use super::{Reciprocal, div2by1, reciprocal};
314 use crate::{Limb, NonZero, Uint, WideWord, Word, word};
315
316 #[test]
317 fn reciprocal_valid() {
318 #![allow(clippy::integer_division_remainder_used, reason = "test")]
319 fn test(d: Word) {
320 let v = reciprocal(d);
321
322 let expected = WideWord::MAX / WideWord::from(d) - WideWord::from(Word::MAX) - 1;
325 assert_eq!(WideWord::from(v), expected);
326 }
327
328 test(Word::MAX);
329 test(1 << (Word::BITS - 1));
330 test((1 << (Word::BITS - 1)) | 1);
331 }
332
333 #[test]
334 fn reciprocal_3by2_valid() {
335 fn test(d: WideWord) {
336 let (d0, d1) = word::split_wide(d);
337 let v0 = Reciprocal::new(NonZero::<Limb>::new_unwrap(Limb(d1)));
338 let v = v0.reciprocal_3by2(d0, d1);
339
340 let actual = (Uint::<3>::from_word(v)
345 + Uint::<3>::ZERO.set_bit_vartime(Word::BITS, true))
346 .checked_mul(&Uint::<3>::from_wide_word(d))
347 .expect("overflow");
348 let min = Uint::<3>::MAX - Uint::<3>::from_wide_word(d);
349 assert!(actual > min, "{actual} <= {min}");
350 }
351
352 test(WideWord::MAX);
353 test(1 << (WideWord::BITS - 1));
354 test((1 << (WideWord::BITS - 1)) | 1);
355 }
356
357 #[test]
358 fn div2by1_overflow() {
359 let r = Reciprocal::new(NonZero::new(Limb(Word::MAX - 1)).unwrap());
363 assert_eq!(
364 div2by1(Word::MAX - 63, Word::MAX - 2, &r),
365 (Word::MAX, Word::MAX - 65)
366 );
367 }
368}