Skip to main content

big_number/
big_number.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6#[cfg(feature = "alloc")]
7use alloc::{string::String, vec::Vec};
8use core::{
9    fmt,
10    ops::{Add, Div, Mul, Neg, Rem, Sub},
11};
12
13pub const MAX_LIMBS: usize = 256;
14
15const fn max_limbs<const BITS: usize, const LIMBS: usize>() -> [u64; LIMBS] {
16    let mut limbs = [u64::MAX; LIMBS];
17    let rem = BITS % 64;
18    if rem != 0 {
19        limbs[LIMBS - 1] = (1u64 << rem) - 1;
20    }
21    limbs
22}
23
24#[derive(Clone, Copy, PartialEq, Eq)]
25pub struct Uint<const BITS: usize, const LIMBS: usize> {
26    pub limbs: [u64; LIMBS],
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub struct Int<const BITS: usize, const LIMBS: usize>(Uint<BITS, LIMBS>);
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum Error {
34    InvalidRadix,
35    InvalidDigit,
36    EmptyString,
37    Overflow,
38}
39
40#[inline]
41pub const fn adc(a: u64, b: u64, carry: u64) -> (u64, u64) {
42    let sum = (a as u128) + (b as u128) + (carry as u128);
43    (sum as u64, (sum >> 64) as u64)
44}
45
46#[inline]
47pub const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) {
48    let diff = (1u128 << 64) + (a as u128) - (b as u128) - (borrow as u128);
49    (diff as u64, 1u64.wrapping_sub((diff >> 64) as u64))
50}
51
52#[inline]
53pub const fn mac(acc: u64, a: u64, b: u64, carry: u64) -> (u64, u64) {
54    let value = (acc as u128) + (a as u128) * (b as u128) + (carry as u128);
55    (value as u64, (value >> 64) as u64)
56}
57
58fn mul_limbs(out: &mut [u64], a: &[u64], a_len: usize, b: &[u64], b_len: usize) {
59    for i in 0..a_len {
60        let mut carry = 0u64;
61        for j in 0..b_len {
62            let (word, next_carry) = mac(out[i + j], a[i], b[j], carry);
63            out[i + j] = word;
64            carry = next_carry;
65        }
66        let mut k = i + b_len;
67        while carry != 0 {
68            let (word, next_carry) = adc(out[k], 0, carry);
69            out[k] = word;
70            carry = next_carry;
71            k += 1;
72        }
73    }
74}
75
76#[inline]
77const fn ct_select_u64(a: u64, b: u64, choice: bool) -> u64 {
78    let mask = 0u64.wrapping_sub(choice as u64);
79    b ^ ((a ^ b) & mask)
80}
81
82#[inline]
83const fn digit_to_char(digit: u64, upper: bool) -> char {
84    match digit {
85        0..=9 => (b'0' + digit as u8) as char,
86        _ if upper => (b'A' + (digit as u8 - 10)) as char,
87        _ => (b'a' + (digit as u8 - 10)) as char,
88    }
89}
90
91#[inline]
92fn char_to_digit(byte: u8) -> Option<u32> {
93    match byte {
94        b'0'..=b'9' => Some((byte - b'0') as u32),
95        b'a'..=b'z' => Some((byte - b'a' + 10) as u32),
96        b'A'..=b'Z' => Some((byte - b'A' + 10) as u32),
97        _ => None,
98    }
99}
100
101const fn uint_from_u128<const BITS: usize, const LIMBS: usize>(value: u128) -> Uint<BITS, LIMBS> {
102    let mut limbs = [0u64; LIMBS];
103    if LIMBS > 0 {
104        limbs[0] = value as u64;
105    }
106    if LIMBS > 1 {
107        limbs[1] = (value >> 64) as u64;
108    }
109    Uint {
110        limbs,
111    }
112}
113
114fn u128_to_word(value: u128) -> u64 {
115    u64::try_from(value).expect("primitive operand exceeds u64")
116}
117
118fn i128_abs_to_word(value: i128) -> (u64, bool) {
119    (u128_to_word(value.unsigned_abs()), value.is_negative())
120}
121
122impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
123    const _LIMBS_CHECK: () = assert!(LIMBS == (BITS + 63) / 64, "LIMBS must equal ceil(BITS/64)");
124
125    pub const ZERO: Self = Self {
126        limbs: [0u64; LIMBS],
127    };
128    pub const ONE: Self = Self::from_u64(1);
129    pub const MAX: Self = Self {
130        limbs: max_limbs::<BITS, LIMBS>(),
131    };
132
133    #[inline]
134    pub const fn from_limbs(limbs: [u64; LIMBS]) -> Self {
135        Self {
136            limbs,
137        }
138    }
139
140    #[inline]
141    pub const fn from_u64(v: u64) -> Self {
142        let mut limbs = [0u64; LIMBS];
143        if LIMBS > 0 {
144            limbs[0] = v;
145        }
146        Self {
147            limbs,
148        }
149    }
150
151    #[inline]
152    pub fn from_be_slice(bytes: &[u8]) -> Self {
153        assert_eq!(bytes.len(), BITS / 8);
154        let mut limbs = [0u64; LIMBS];
155        let mut i = 0;
156        while i < LIMBS {
157            let start = bytes.len() - ((i + 1) * 8);
158            let mut limb = [0u8; 8];
159            limb.copy_from_slice(&bytes[start..start + 8]);
160            limbs[i] = u64::from_be_bytes(limb);
161            i += 1;
162        }
163        Self {
164            limbs,
165        }
166    }
167
168    #[inline]
169    pub fn from_le_slice(bytes: &[u8]) -> Self {
170        assert_eq!(bytes.len(), BITS / 8);
171        let mut limbs = [0u64; LIMBS];
172        let mut i = 0;
173        while i < LIMBS {
174            let start = i * 8;
175            let mut limb = [0u8; 8];
176            limb.copy_from_slice(&bytes[start..start + 8]);
177            limbs[i] = u64::from_le_bytes(limb);
178            i += 1;
179        }
180        Self {
181            limbs,
182        }
183    }
184
185    #[cfg(feature = "alloc")]
186    #[inline]
187    pub fn to_be_bytes(&self) -> Vec<u8> {
188        let mut out = Vec::with_capacity(BITS / 8);
189        let mut i = LIMBS;
190        while i > 0 {
191            i -= 1;
192            out.extend_from_slice(&self.limbs[i].to_be_bytes());
193        }
194        out
195    }
196
197    #[cfg(feature = "alloc")]
198    #[inline]
199    pub fn to_le_bytes(&self) -> Vec<u8> {
200        let mut out = Vec::with_capacity(BITS / 8);
201        let mut i = 0;
202        while i < LIMBS {
203            out.extend_from_slice(&self.limbs[i].to_le_bytes());
204            i += 1;
205        }
206        out
207    }
208
209    #[inline]
210    pub fn to_be_bytes_fixed<const N: usize>(&self) -> [u8; N] {
211        assert_eq!(N, BITS / 8);
212        let mut out = [0u8; N];
213        let mut i = 0;
214        while i < LIMBS {
215            let start = N - ((i + 1) * 8);
216            out[start..start + 8].copy_from_slice(&self.limbs[i].to_be_bytes());
217            i += 1;
218        }
219        out
220    }
221
222    #[inline]
223    pub fn to_le_bytes_fixed<const N: usize>(&self) -> [u8; N] {
224        assert_eq!(N, BITS / 8);
225        let mut out = [0u8; N];
226        let mut i = 0;
227        while i < LIMBS {
228            let start = i * 8;
229            out[start..start + 8].copy_from_slice(&self.limbs[i].to_le_bytes());
230            i += 1;
231        }
232        out
233    }
234
235    #[inline]
236    pub fn bit(&self, index: usize) -> bool {
237        if index >= BITS {
238            return false;
239        }
240        ((self.limbs[index / 64] >> (index % 64)) & 1) == 1
241    }
242
243    #[inline]
244    pub fn is_zero(&self) -> bool {
245        let mut acc = 0u64;
246        let mut i = 0;
247        while i < LIMBS {
248            acc |= self.limbs[i];
249            i += 1;
250        }
251        acc == 0
252    }
253
254    /// Position of the highest set bit, plus one. Returns 0 for zero.
255    pub fn bit_len(&self) -> usize {
256        let mut i = LIMBS;
257        while i > 0 {
258            i -= 1;
259            if self.limbs[i] != 0 {
260                return i * 64 + 64 - self.limbs[i].leading_zeros() as usize;
261            }
262        }
263        0
264    }
265
266    #[inline]
267    pub fn is_odd(&self) -> bool {
268        (self.limbs[0] & 1) == 1
269    }
270
271    #[inline]
272    pub fn ct_ge(&self, rhs: &Self) -> bool {
273        let (_, borrow) = self.sub_raw(rhs);
274        borrow == 0
275    }
276
277    #[inline]
278    pub fn ct_eq(&self, rhs: &Self) -> bool {
279        let mut diff = 0u64;
280        let mut i = 0;
281        while i < LIMBS {
282            diff |= self.limbs[i] ^ rhs.limbs[i];
283            i += 1;
284        }
285        diff == 0
286    }
287
288    #[inline]
289    pub fn ct_select(a: &Self, b: &Self, choice: bool) -> Self {
290        let mut limbs = [0u64; LIMBS];
291        let mut i = 0;
292        while i < LIMBS {
293            limbs[i] = ct_select_u64(a.limbs[i], b.limbs[i], choice);
294            i += 1;
295        }
296        Self {
297            limbs,
298        }
299    }
300
301    #[inline]
302    pub fn add_raw(&self, rhs: &Self) -> (Self, u64) {
303        let mut out = [0u64; LIMBS];
304        let mut carry = 0u64;
305        let mut i = 0;
306        while i < LIMBS {
307            let (word, next_carry) = adc(self.limbs[i], rhs.limbs[i], carry);
308            out[i] = word;
309            carry = next_carry;
310            i += 1;
311        }
312        (
313            Self {
314                limbs: out,
315            },
316            carry,
317        )
318    }
319
320    #[inline]
321    pub fn sub_raw(&self, rhs: &Self) -> (Self, u64) {
322        let mut out = [0u64; LIMBS];
323        let mut borrow = 0u64;
324        let mut i = 0;
325        while i < LIMBS {
326            let (word, next_borrow) = sbb(self.limbs[i], rhs.limbs[i], borrow);
327            out[i] = word;
328            borrow = next_borrow;
329            i += 1;
330        }
331        (
332            Self {
333                limbs: out,
334            },
335            borrow,
336        )
337    }
338
339    #[inline]
340    pub fn add_mod(&self, rhs: &Self, modulus: &Self) -> Self {
341        let (sum, carry) = self.add_raw(rhs);
342        let (reduced, borrow) = sum.sub_raw(modulus);
343        // Use bitwise OR to avoid short-circuit branching on secret carry/borrow bits.
344        // Reduce when carry==1 (overflow) OR borrow==0 (sum >= modulus).
345        Self::ct_select(&reduced, &sum, (carry | (borrow ^ 1)) != 0)
346    }
347
348    #[inline]
349    pub fn sub_mod(&self, rhs: &Self, modulus: &Self) -> Self {
350        let (diff, borrow) = self.sub_raw(rhs);
351        let (corrected, _) = diff.add_raw(modulus);
352        Self::ct_select(&corrected, &diff, borrow == 1)
353    }
354
355    #[inline]
356    pub fn double_mod(&self, modulus: &Self) -> Self {
357        self.add_mod(self, modulus)
358    }
359
360    fn mul_wide_internal(&self, rhs: &Self) -> [u64; MAX_LIMBS] {
361        assert!(LIMBS * 2 <= MAX_LIMBS);
362        let mut out = [0u64; MAX_LIMBS];
363        let mut i = 0;
364        while i < LIMBS {
365            let mut carry = 0u64;
366            let mut j = 0;
367            while j < LIMBS {
368                let (word, next_carry) = mac(out[i + j], self.limbs[i], rhs.limbs[j], carry);
369                out[i + j] = word;
370                carry = next_carry;
371                j += 1;
372            }
373            let mut k = i + LIMBS;
374            while k < MAX_LIMBS {
375                let (word, next_carry) = adc(out[k], 0, carry);
376                out[k] = word;
377                carry = next_carry;
378                k += 1;
379            }
380            i += 1;
381        }
382        out
383    }
384
385    fn reduce_wide_internal(product: &[u64; MAX_LIMBS], modulus: &Self) -> Self {
386        let total_bits = LIMBS * 128;
387        let mut rem = Self::ZERO;
388        let mut bit_index = total_bits;
389        while bit_index > 0 {
390            bit_index -= 1;
391            let limb_idx = bit_index / 64;
392            let bit_pos = bit_index % 64;
393            let bit = ((product[limb_idx] >> bit_pos) & 1) as u64;
394
395            let mut shifted = [0u64; LIMBS];
396            let mut carry = bit;
397            let mut i = 0;
398            while i < LIMBS {
399                let next = rem.limbs[i] >> 63;
400                shifted[i] = (rem.limbs[i] << 1) | carry;
401                carry = next;
402                i += 1;
403            }
404            let shifted_rem = Self {
405                limbs: shifted,
406            };
407            let (reduced, borrow) = shifted_rem.sub_raw(modulus);
408            // Use bitwise OR to avoid short-circuit branching on secret carry/borrow bits.
409            rem = Self::ct_select(&reduced, &shifted_rem, (carry | (borrow ^ 1)) != 0);
410        }
411        rem
412    }
413
414    #[inline]
415    pub fn mul_mod(&self, rhs: &Self, modulus: &Self) -> Self {
416        let product = self.mul_wide_internal(rhs);
417        Self::reduce_wide_internal(&product, modulus)
418    }
419
420    /// Precompute mu for Barrett reduction, auto-detecting effective limb count.
421    pub fn compute_mu_for_barrett(&self) -> [u64; MAX_LIMBS] {
422        let eff_limbs = (self.bit_len() + 63) / 64;
423        self.compute_mu_for_barrett_eff(eff_limbs)
424    }
425
426    fn compute_mu_for_barrett_eff(&self, eff_limbs: usize) -> [u64; MAX_LIMBS] {
427        const {
428            assert!(LIMBS + 1 <= MAX_LIMBS);
429        }
430        assert!(eff_limbs >= 1 && eff_limbs <= LIMBS);
431
432        let total_bits = eff_limbs * 128;
433        let mut mu = [0u64; MAX_LIMBS];
434        let mut rem = Self::ZERO;
435
436        for bit_pos in (0..=total_bits).rev() {
437            let mut shifted_limbs = [0u64; LIMBS];
438            let mut carry = 0u64;
439            for i in 0..LIMBS {
440                let next = rem.limbs[i] >> 63;
441                shifted_limbs[i] = (rem.limbs[i] << 1) | carry;
442                carry = next;
443            }
444
445            let bit = if bit_pos == total_bits { 1u64 } else { 0u64 };
446            let mut with = shifted_limbs;
447            with[0] |= bit;
448
449            let shifted = Self {
450                limbs: with,
451            };
452            let (reduced, borrow) = shifted.sub_raw(self);
453            // Use the same overflow-aware selection as reduce_wide_internal:
454            // carry == 1 → true value >= 2^(LIMBS*64) >= divisor → always subtract.
455            rem = Self::ct_select(&reduced, &shifted, (carry | (borrow ^ 1)) != 0);
456            // When we subtracted, the quotient bit is 1.
457            if carry | (borrow ^ 1) != 0 {
458                let qi = bit_pos / 64;
459                let qbit = bit_pos % 64;
460                if qi < eff_limbs + 1 {
461                    mu[qi] |= 1 << qbit;
462                }
463            }
464        }
465
466        mu
467    }
468
469    /// Modular exponentiation using Barrett reduction.
470    pub fn modpow_barrett(&self, exp: &Self, modulus: &Self, mu: &[u64]) -> Self {
471        let eff_limbs = (modulus.bit_len() + 63) / 64;
472        self.modpow_barrett_eff(exp, modulus, mu, eff_limbs)
473    }
474
475    /// Barrett modular exponentiation with explicit effective limb count.
476    pub fn modpow_barrett_eff(&self, exp: &Self, modulus: &Self, mu: &[u64], eff_limbs: usize) -> Self {
477        let mut base = self.mul_mod_barrett_eff(&Self::ONE, modulus, mu, eff_limbs);
478        let mut result = Self::ONE;
479        let bits = exp.bit_len();
480        let mut i = 0;
481        while i < bits {
482            if exp.bit(i) {
483                result = result.mul_mod_barrett_eff(&base, modulus, mu, eff_limbs);
484            }
485            base = base.mul_mod_barrett_eff(&base, modulus, mu, eff_limbs);
486            i += 1;
487        }
488        result
489    }
490
491    /// Modular multiplication using Barrett reduction.
492    pub fn mul_mod_barrett(&self, rhs: &Self, modulus: &Self, mu: &[u64]) -> Self {
493        let product = self.mul_wide_internal(rhs);
494        Self::reduce_wide_barrett(&product, modulus, mu)
495    }
496
497    /// Modular multiplication using Barrett reduction with explicit effective limb count.
498    pub fn mul_mod_barrett_eff(&self, rhs: &Self, modulus: &Self, mu: &[u64], eff_limbs: usize) -> Self {
499        let product = self.mul_wide_internal(rhs);
500        Self::reduce_wide_barrett_eff(&product, modulus, mu, eff_limbs)
501    }
502
503    /// Barrett reduction with explicit effective limb count.
504    pub fn reduce_wide_barrett_eff(product: &[u64; MAX_LIMBS], modulus: &Self, mu: &[u64], eff_limbs: usize) -> Self {
505        assert!(mu.len() >= eff_limbs + 1);
506
507        let k = eff_limbs;
508        let k1 = k + 1;
509        let k_minus_1 = k.saturating_sub(1);
510
511        let mut q1 = [0u64; MAX_LIMBS];
512        q1[..k1].copy_from_slice(&product[k_minus_1..k_minus_1 + k1]);
513
514        let mut q2 = [0u64; MAX_LIMBS];
515        mul_limbs(&mut q2, &q1, k1, mu, k1);
516
517        let mut q3 = [0u64; MAX_LIMBS];
518        q3[..k1].copy_from_slice(&q2[k1..k1 + k1]);
519
520        let mut r1 = [0u64; MAX_LIMBS];
521        r1[..k1].copy_from_slice(&product[..k1]);
522
523        let mut q3m = [0u64; MAX_LIMBS];
524        mul_limbs(&mut q3m, &q3[..k1], k1, &modulus.limbs, k);
525        let mut r2 = [0u64; MAX_LIMBS];
526        r2[..k1].copy_from_slice(&q3m[..k1]);
527
528        let mut r = [0u64; MAX_LIMBS];
529        let mut borrow = 0u64;
530        let mut i = 0;
531        while i < k1 {
532            let (word, next_borrow) = sbb(r1[i], r2[i], borrow);
533            r[i] = word;
534            borrow = next_borrow;
535            i += 1;
536        }
537
538        // Conditional subtract modulus up to twice, using the full k+1-limb r.
539        // The Barrett remainder r = product - q3 * n can be up to 3n, requiring
540        // k+1 limbs.  Truncating to k limbs before subtracting would lose the
541        // top limb and give incorrect results.
542        for _ in 0..2 {
543            let mut r_try = r;
544            let mut borrow = 0u64;
545            let mut j = 0;
546            while j < k1 {
547                let mod_limb = if j < LIMBS { modulus.limbs[j] } else { 0u64 };
548                let (word, next_borrow) = sbb(r_try[j], mod_limb, borrow);
549                r_try[j] = word;
550                borrow = next_borrow;
551                j += 1;
552            }
553            let choose = borrow == 0;
554            let mut j = 0;
555            while j < k1 {
556                r[j] = ct_select_u64(r_try[j], r[j], choose);
557                j += 1;
558            }
559        }
560
561        let mut limbs = [0u64; LIMBS];
562        limbs[..k].copy_from_slice(&r[..k]);
563        Self {
564            limbs,
565        }
566    }
567
568    /// Modular exponentiation: `self^exp mod modulus` using square-and-multiply,
569    /// scanning only up to the exponent's bit length.
570    pub fn modpow(&self, exp: &Self, modulus: &Self) -> Self {
571        let mut base = self.mul_mod(&Self::ONE, modulus);
572        let mut result = Self::ONE;
573        let bits = exp.bit_len();
574        let mut i = 0;
575        while i < bits {
576            if exp.bit(i) {
577                result = result.mul_mod(&base, modulus);
578            }
579            base = base.mul_mod(&base, modulus);
580            i += 1;
581        }
582        result
583    }
584
585    /// Barrett reduction of a 2*LIMBS-wide product modulo `modulus`.
586    ///
587    /// `mu` must equal `floor(2^(2*LIMBS*64) / modulus)` and have at least `LIMBS+1` entries.
588    /// Prefer `reduce_wide_barrett_eff` which auto-detects the effective limb count.
589    pub fn reduce_wide_barrett(product: &[u64; MAX_LIMBS], modulus: &Self, mu: &[u64]) -> Self {
590        assert!(mu.len() >= LIMBS + 1);
591
592        let k = LIMBS;
593        let k1 = k + 1;
594        let k_minus_1 = k - 1;
595
596        let mut q1 = [0u64; MAX_LIMBS];
597        q1[..k1].copy_from_slice(&product[k_minus_1..k_minus_1 + k1]);
598
599        let mut q2 = [0u64; MAX_LIMBS];
600        mul_limbs(&mut q2, &q1, k1, mu, k1);
601
602        let mut q3 = [0u64; MAX_LIMBS];
603        q3[..k1].copy_from_slice(&q2[k1..k1 + k1]);
604
605        let mut r1 = [0u64; MAX_LIMBS];
606        r1[..k1].copy_from_slice(&product[..k1]);
607
608        let mut q3m = [0u64; MAX_LIMBS];
609        mul_limbs(&mut q3m, &q3[..k1], k1, &modulus.limbs, k);
610        let mut r2 = [0u64; MAX_LIMBS];
611        r2[..k1].copy_from_slice(&q3m[..k1]);
612
613        let mut r = [0u64; MAX_LIMBS];
614        let mut borrow = 0u64;
615        let mut i = 0;
616        while i < k1 {
617            let (word, next_borrow) = sbb(r1[i], r2[i], borrow);
618            r[i] = word;
619            borrow = next_borrow;
620            i += 1;
621        }
622
623        // Conditional subtract modulus up to twice, using the full k+1-limb r.
624        // The Barrett remainder r = product - q3 * n can be up to 3n, requiring
625        // k+1 limbs.  Truncating to k limbs before subtracting would lose the
626        // top limb and give incorrect results.
627        for _ in 0..2 {
628            let mut r_try = r;
629            let mut borrow = 0u64;
630            let mut j = 0;
631            while j < k1 {
632                let mod_limb = if j < LIMBS { modulus.limbs[j] } else { 0u64 };
633                let (word, next_borrow) = sbb(r_try[j], mod_limb, borrow);
634                r_try[j] = word;
635                borrow = next_borrow;
636                j += 1;
637            }
638            let choose = borrow == 0;
639            let mut j = 0;
640            while j < k1 {
641                r[j] = ct_select_u64(r_try[j], r[j], choose);
642                j += 1;
643            }
644        }
645
646        let mut limbs = [0u64; LIMBS];
647        limbs.copy_from_slice(&r[..LIMBS]);
648        Self {
649            limbs,
650        }
651    }
652
653    #[inline]
654    pub fn add_word(&self, word: u64) -> (Self, u64) {
655        let mut out = self.limbs;
656        let (first, mut carry) = adc(out[0], word, 0);
657        out[0] = first;
658        let mut i = 1;
659        while i < LIMBS {
660            let (next, next_carry) = adc(out[i], 0, carry);
661            out[i] = next;
662            carry = next_carry;
663            i += 1;
664        }
665        (
666            Self {
667                limbs: out,
668            },
669            carry,
670        )
671    }
672
673    #[inline]
674    pub fn sub_word(&self, word: u64) -> (Self, u64) {
675        let mut out = self.limbs;
676        let (first, mut borrow) = sbb(out[0], word, 0);
677        out[0] = first;
678        let mut i = 1;
679        while i < LIMBS {
680            let (next, next_borrow) = sbb(out[i], 0, borrow);
681            out[i] = next;
682            borrow = next_borrow;
683            i += 1;
684        }
685        (
686            Self {
687                limbs: out,
688            },
689            borrow,
690        )
691    }
692
693    #[inline]
694    pub fn mul_word(&self, word: u64) -> (Self, u64) {
695        let mut out = [0u64; LIMBS];
696        let mut carry = 0u64;
697        let mut i = 0;
698        while i < LIMBS {
699            let (next, next_carry) = mac(0, self.limbs[i], word, carry);
700            out[i] = next;
701            carry = next_carry;
702            i += 1;
703        }
704        (
705            Self {
706                limbs: out,
707            },
708            carry,
709        )
710    }
711
712    #[inline]
713    pub fn div_rem_word(&self, word: u64) -> (Self, u64) {
714        assert!(word != 0, "division by zero");
715        let mut out = [0u64; LIMBS];
716        let mut rem = 0u64;
717        let mut i = LIMBS;
718        while i > 0 {
719            i -= 1;
720            let dividend = ((rem as u128) << 64) | self.limbs[i] as u128;
721            out[i] = (dividend / word as u128) as u64;
722            rem = (dividend % word as u128) as u64;
723        }
724        (
725            Self {
726                limbs: out,
727            },
728            rem,
729        )
730    }
731
732    pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, Error> {
733        if !(2..=36).contains(&radix) {
734            return Err(Error::InvalidRadix);
735        }
736        if src.is_empty() {
737            return Err(Error::EmptyString);
738        }
739
740        let mut out = Self::ZERO;
741        for byte in src.bytes() {
742            let digit = char_to_digit(byte).ok_or(Error::InvalidDigit)?;
743            if digit >= radix {
744                return Err(Error::InvalidDigit);
745            }
746            let (mul, high) = out.mul_word(radix as u64);
747            if high != 0 {
748                return Err(Error::Overflow);
749            }
750            let (next, carry) = mul.add_word(digit as u64);
751            if carry != 0 {
752                return Err(Error::Overflow);
753            }
754            out = next;
755        }
756        Ok(out)
757    }
758
759    #[cfg(feature = "alloc")]
760    pub fn to_string_radix(&self, radix: u32) -> String {
761        assert!((2..=36).contains(&radix), "invalid radix");
762        if self.is_zero() {
763            return String::from("0");
764        }
765
766        let mut value = *self;
767        let mut digits = Vec::new();
768        while !value.is_zero() {
769            let (quotient, remainder) = value.div_rem_word(radix as u64);
770            digits.push(digit_to_char(remainder, false));
771            value = quotient;
772        }
773        digits.into_iter().rev().collect()
774    }
775}
776
777#[cfg(feature = "alloc")]
778impl<const BITS: usize, const LIMBS: usize> fmt::Display for Uint<BITS, LIMBS> {
779    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
780        write!(f, "{}", self.to_string_radix(10))
781    }
782}
783
784impl<const BITS: usize, const LIMBS: usize> fmt::LowerHex for Uint<BITS, LIMBS> {
785    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
786        if f.alternate() {
787            f.write_str("0x")?;
788        }
789        let mut started = false;
790        let mut i = LIMBS;
791        while i > 0 {
792            i -= 1;
793            let limb = self.limbs[i];
794            if started {
795                write!(f, "{limb:016x}")?;
796            } else if limb != 0 {
797                write!(f, "{limb:x}")?;
798                started = true;
799            }
800        }
801        if !started {
802            f.write_str("0")?;
803        }
804        Ok(())
805    }
806}
807
808impl<const BITS: usize, const LIMBS: usize> fmt::UpperHex for Uint<BITS, LIMBS> {
809    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810        if f.alternate() {
811            f.write_str("0x")?;
812        }
813        let mut started = false;
814        let mut i = LIMBS;
815        while i > 0 {
816            i -= 1;
817            let limb = self.limbs[i];
818            if started {
819                write!(f, "{limb:016X}")?;
820            } else if limb != 0 {
821                write!(f, "{limb:X}")?;
822                started = true;
823            }
824        }
825        if !started {
826            f.write_str("0")?;
827        }
828        Ok(())
829    }
830}
831
832impl<const BITS: usize, const LIMBS: usize> fmt::Debug for Uint<BITS, LIMBS> {
833    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
834        write!(f, "Uint(0x{self:x})")
835    }
836}
837
838impl<const BITS: usize, const LIMBS: usize> Int<BITS, LIMBS> {
839    const _LIMBS_CHECK: () = assert!(LIMBS == (BITS + 63) / 64, "LIMBS must equal ceil(BITS/64)");
840
841    pub const ZERO: Self = Self(Uint::ZERO);
842    pub const ONE: Self = Self(Uint::ONE);
843    pub const MINUS_ONE: Self = Self(Uint::MAX);
844
845    #[inline]
846    const fn from_uint_bits(bits: Uint<BITS, LIMBS>) -> Self {
847        Self(bits)
848    }
849
850    #[inline]
851    fn from_u128(value: u128) -> Self {
852        Self(uint_from_u128(value))
853    }
854
855    #[inline]
856    fn from_i128(value: i128) -> Self {
857        if value.is_negative() {
858            let magnitude = uint_from_u128::<BITS, LIMBS>(value.unsigned_abs());
859            Self(Self::ZERO.0.sub_raw(&magnitude).0)
860        } else {
861            Self(uint_from_u128(value as u128))
862        }
863    }
864
865    #[inline]
866    pub fn is_negative(&self) -> bool {
867        (self.0.limbs[LIMBS - 1] >> 63) == 1
868    }
869
870    #[inline]
871    pub fn abs(&self) -> Uint<BITS, LIMBS> {
872        if self.is_negative() {
873            Self::ZERO.0.sub_raw(&self.0).0
874        } else {
875            self.0
876        }
877    }
878}
879
880impl<const BITS: usize, const LIMBS: usize> Add for Uint<BITS, LIMBS> {
881    type Output = Self;
882
883    fn add(self, rhs: Self) -> Self::Output {
884        self.add_raw(&rhs).0
885    }
886}
887
888impl<const BITS: usize, const LIMBS: usize> Sub for Uint<BITS, LIMBS> {
889    type Output = Self;
890
891    fn sub(self, rhs: Self) -> Self::Output {
892        self.sub_raw(&rhs).0
893    }
894}
895
896impl<const BITS: usize, const LIMBS: usize> Mul for Uint<BITS, LIMBS> {
897    type Output = Self;
898
899    fn mul(self, rhs: Self) -> Self::Output {
900        let product = self.mul_wide_internal(&rhs);
901        let mut limbs = [0u64; LIMBS];
902        let mut i = 0;
903        while i < LIMBS {
904            limbs[i] = product[i];
905            i += 1;
906        }
907        Self {
908            limbs,
909        }
910    }
911}
912
913impl<const BITS: usize, const LIMBS: usize> Add for Int<BITS, LIMBS> {
914    type Output = Self;
915
916    fn add(self, rhs: Self) -> Self::Output {
917        Self::from_uint_bits(self.0.add_raw(&rhs.0).0)
918    }
919}
920
921impl<const BITS: usize, const LIMBS: usize> Sub for Int<BITS, LIMBS> {
922    type Output = Self;
923
924    fn sub(self, rhs: Self) -> Self::Output {
925        Self::from_uint_bits(self.0.sub_raw(&rhs.0).0)
926    }
927}
928
929impl<const BITS: usize, const LIMBS: usize> Neg for Int<BITS, LIMBS> {
930    type Output = Self;
931
932    fn neg(self) -> Self::Output {
933        Self::from_uint_bits(Int::ZERO.0.sub_raw(&self.0).0)
934    }
935}
936
937macro_rules! impl_uint_ops_unsigned {
938    ($($ty:ty),* $(,)?) => {
939        $(
940            impl<const BITS: usize, const LIMBS: usize> Add<$ty> for Uint<BITS, LIMBS> {
941                type Output = Self;
942                fn add(self, rhs: $ty) -> Self::Output {
943                    self.add_word(u128_to_word(rhs as u128)).0
944                }
945            }
946
947            impl<const BITS: usize, const LIMBS: usize> Sub<$ty> for Uint<BITS, LIMBS> {
948                type Output = Self;
949                fn sub(self, rhs: $ty) -> Self::Output {
950                    self.sub_word(u128_to_word(rhs as u128)).0
951                }
952            }
953
954            impl<const BITS: usize, const LIMBS: usize> Mul<$ty> for Uint<BITS, LIMBS> {
955                type Output = Self;
956                fn mul(self, rhs: $ty) -> Self::Output {
957                    self.mul_word(u128_to_word(rhs as u128)).0
958                }
959            }
960
961            impl<const BITS: usize, const LIMBS: usize> Div<$ty> for Uint<BITS, LIMBS> {
962                type Output = Self;
963                fn div(self, rhs: $ty) -> Self::Output {
964                    self.div_rem_word(u128_to_word(rhs as u128)).0
965                }
966            }
967
968            impl<const BITS: usize, const LIMBS: usize> Rem<$ty> for Uint<BITS, LIMBS> {
969                type Output = u64;
970                fn rem(self, rhs: $ty) -> Self::Output {
971                    self.div_rem_word(u128_to_word(rhs as u128)).1
972                }
973            }
974        )*
975    };
976}
977
978macro_rules! impl_uint_ops_signed {
979    ($($ty:ty),* $(,)?) => {
980        $(
981            impl<const BITS: usize, const LIMBS: usize> Add<$ty> for Uint<BITS, LIMBS> {
982                type Output = Self;
983                fn add(self, rhs: $ty) -> Self::Output {
984                    let (word, negative) = i128_abs_to_word(rhs as i128);
985                    if negative {
986                        self.sub_word(word).0
987                    } else {
988                        self.add_word(word).0
989                    }
990                }
991            }
992
993            impl<const BITS: usize, const LIMBS: usize> Sub<$ty> for Uint<BITS, LIMBS> {
994                type Output = Self;
995                fn sub(self, rhs: $ty) -> Self::Output {
996                    let (word, negative) = i128_abs_to_word(rhs as i128);
997                    if negative {
998                        self.add_word(word).0
999                    } else {
1000                        self.sub_word(word).0
1001                    }
1002                }
1003            }
1004
1005            impl<const BITS: usize, const LIMBS: usize> Mul<$ty> for Uint<BITS, LIMBS> {
1006                type Output = Self;
1007                fn mul(self, rhs: $ty) -> Self::Output {
1008                    self.mul_word(i128_abs_to_word(rhs as i128).0).0
1009                }
1010            }
1011
1012            impl<const BITS: usize, const LIMBS: usize> Div<$ty> for Uint<BITS, LIMBS> {
1013                type Output = Self;
1014                fn div(self, rhs: $ty) -> Self::Output {
1015                    self.div_rem_word(i128_abs_to_word(rhs as i128).0).0
1016                }
1017            }
1018
1019            impl<const BITS: usize, const LIMBS: usize> Rem<$ty> for Uint<BITS, LIMBS> {
1020                type Output = u64;
1021                fn rem(self, rhs: $ty) -> Self::Output {
1022                    self.div_rem_word(i128_abs_to_word(rhs as i128).0).1
1023                }
1024            }
1025        )*
1026    };
1027}
1028
1029macro_rules! impl_int_ops_unsigned {
1030    ($($ty:ty),* $(,)?) => {
1031        $(
1032            impl<const BITS: usize, const LIMBS: usize> Add<$ty> for Int<BITS, LIMBS> {
1033                type Output = Self;
1034                fn add(self, rhs: $ty) -> Self::Output {
1035                    self + Self::from_u128(rhs as u128)
1036                }
1037            }
1038
1039            impl<const BITS: usize, const LIMBS: usize> Sub<$ty> for Int<BITS, LIMBS> {
1040                type Output = Self;
1041                fn sub(self, rhs: $ty) -> Self::Output {
1042                    self - Self::from_u128(rhs as u128)
1043                }
1044            }
1045
1046            impl<const BITS: usize, const LIMBS: usize> Mul<$ty> for Int<BITS, LIMBS> {
1047                type Output = Self;
1048                fn mul(self, rhs: $ty) -> Self::Output {
1049                    let (product, _) = self.abs().mul_word(u128_to_word(rhs as u128));
1050                    let bits = if self.is_negative() {
1051                        Uint::ZERO.sub_raw(&product).0
1052                    } else {
1053                        product
1054                    };
1055                    Self::from_uint_bits(bits)
1056                }
1057            }
1058
1059            impl<const BITS: usize, const LIMBS: usize> Div<$ty> for Int<BITS, LIMBS> {
1060                type Output = Self;
1061                fn div(self, rhs: $ty) -> Self::Output {
1062                    let (quotient, _) = self.abs().div_rem_word(u128_to_word(rhs as u128));
1063                    let bits = if self.is_negative() {
1064                        Uint::ZERO.sub_raw(&quotient).0
1065                    } else {
1066                        quotient
1067                    };
1068                    Self::from_uint_bits(bits)
1069                }
1070            }
1071
1072            impl<const BITS: usize, const LIMBS: usize> Rem<$ty> for Int<BITS, LIMBS> {
1073                type Output = Self;
1074                fn rem(self, rhs: $ty) -> Self::Output {
1075                    let (_, remainder) = self.abs().div_rem_word(u128_to_word(rhs as u128));
1076                    let bits = Uint::from_u64(remainder);
1077                    let bits = if self.is_negative() {
1078                        Uint::ZERO.sub_raw(&bits).0
1079                    } else {
1080                        bits
1081                    };
1082                    Self::from_uint_bits(bits)
1083                }
1084            }
1085        )*
1086    };
1087}
1088
1089macro_rules! impl_int_ops_signed {
1090    ($($ty:ty),* $(,)?) => {
1091        $(
1092            impl<const BITS: usize, const LIMBS: usize> Add<$ty> for Int<BITS, LIMBS> {
1093                type Output = Self;
1094                fn add(self, rhs: $ty) -> Self::Output {
1095                    self + Self::from_i128(rhs as i128)
1096                }
1097            }
1098
1099            impl<const BITS: usize, const LIMBS: usize> Sub<$ty> for Int<BITS, LIMBS> {
1100                type Output = Self;
1101                fn sub(self, rhs: $ty) -> Self::Output {
1102                    self - Self::from_i128(rhs as i128)
1103                }
1104            }
1105
1106            impl<const BITS: usize, const LIMBS: usize> Mul<$ty> for Int<BITS, LIMBS> {
1107                type Output = Self;
1108                fn mul(self, rhs: $ty) -> Self::Output {
1109                    let (word, negative) = i128_abs_to_word(rhs as i128);
1110                    let (product, _) = self.abs().mul_word(word);
1111                    let make_negative = self.is_negative() ^ negative;
1112                    let bits = if make_negative {
1113                        Uint::ZERO.sub_raw(&product).0
1114                    } else {
1115                        product
1116                    };
1117                    Self::from_uint_bits(bits)
1118                }
1119            }
1120
1121            impl<const BITS: usize, const LIMBS: usize> Div<$ty> for Int<BITS, LIMBS> {
1122                type Output = Self;
1123                fn div(self, rhs: $ty) -> Self::Output {
1124                    let (word, negative) = i128_abs_to_word(rhs as i128);
1125                    let (quotient, _) = self.abs().div_rem_word(word);
1126                    let make_negative = self.is_negative() ^ negative;
1127                    let bits = if make_negative {
1128                        Uint::ZERO.sub_raw(&quotient).0
1129                    } else {
1130                        quotient
1131                    };
1132                    Self::from_uint_bits(bits)
1133                }
1134            }
1135
1136            impl<const BITS: usize, const LIMBS: usize> Rem<$ty> for Int<BITS, LIMBS> {
1137                type Output = Self;
1138                fn rem(self, rhs: $ty) -> Self::Output {
1139                    let (word, _) = i128_abs_to_word(rhs as i128);
1140                    let (_, remainder) = self.abs().div_rem_word(word);
1141                    let bits = Uint::from_u64(remainder);
1142                    let bits = if self.is_negative() {
1143                        Uint::ZERO.sub_raw(&bits).0
1144                    } else {
1145                        bits
1146                    };
1147                    Self::from_uint_bits(bits)
1148                }
1149            }
1150        )*
1151    };
1152}
1153
1154impl_uint_ops_unsigned!(u8, u16, u32, u64, u128);
1155impl_uint_ops_signed!(i8, i16, i32, i64, i128);
1156impl_int_ops_unsigned!(u8, u16, u32, u64, u128);
1157impl_int_ops_signed!(i8, i16, i32, i64, i128);
1158
1159#[cfg(test)]
1160mod tests {
1161    use super::*;
1162    type U256 = Uint<256, 4>;
1163    type U128 = Uint<128, 2>;
1164    type I128 = Int<128, 2>;
1165
1166    const P256_MODULUS: U256 = U256::from_limbs([
1167        0xffff_ffff_ffff_ffff,
1168        0x0000_0000_ffff_ffff,
1169        0x0000_0000_0000_0000,
1170        0xffff_ffff_0000_0001,
1171    ]);
1172    const P256_ORDER: U256 = U256::from_limbs([
1173        0xf3b9_cac2_fc63_2551,
1174        0xbce6_faad_a717_9e84,
1175        0xffff_ffff_ffff_ffff,
1176        0xffff_ffff_0000_0000,
1177    ]);
1178    const P256_P_MINUS_TWO: U256 = U256::from_limbs([
1179        0xffff_ffff_ffff_fffd,
1180        0x0000_0000_ffff_ffff,
1181        0x0000_0000_0000_0000,
1182        0xffff_ffff_0000_0001,
1183    ]);
1184    const P256_P_PLUS_ONE_OVER_FOUR: U256 = U256::from_limbs([
1185        0x0000_0000_0000_0000,
1186        0x0000_0000_4000_0000,
1187        0x4000_0000_0000_0000,
1188        0x3fff_ffff_c000_0000,
1189    ]);
1190    const ED25519_P: U256 = U256::from_limbs([
1191        0xffff_ffff_ffff_ffed,
1192        0xffff_ffff_ffff_ffff,
1193        0xffff_ffff_ffff_ffff,
1194        0x7fff_ffff_ffff_ffff,
1195    ]);
1196
1197    fn decode_hex<const N: usize>(input: &str) -> [u8; N] {
1198        assert_eq!(input.len(), N * 2);
1199        let mut out = [0u8; N];
1200        let bytes = input.as_bytes();
1201        let mut i = 0;
1202        while i < N {
1203            let hi = char_to_digit(bytes[i * 2]).unwrap() as u8;
1204            let lo = char_to_digit(bytes[i * 2 + 1]).unwrap() as u8;
1205            out[i] = (hi << 4) | lo;
1206            i += 1;
1207        }
1208        out
1209    }
1210
1211    #[test]
1212    fn raw_arithmetic_reports_carry_and_borrow() {
1213        let (sum, carry) = U128::MAX.add_raw(&U128::ONE);
1214        assert_eq!(sum, U128::ZERO);
1215        assert_eq!(carry, 1);
1216
1217        let (diff, borrow) = U128::ZERO.sub_raw(&U128::ONE);
1218        assert_eq!(diff, U128::MAX);
1219        assert_eq!(borrow, 1);
1220
1221        let (low, high) = U128::MAX.mul_word(2);
1222        assert_eq!(low, U128::from_limbs([0xffff_ffff_ffff_fffe, 0xffff_ffff_ffff_ffff]));
1223        assert_eq!(high, 1);
1224    }
1225
1226    #[test]
1227    fn modular_arithmetic_matches_known_values() {
1228        assert_eq!(P256_P_MINUS_TWO.add_mod(&U256::from_u64(2), &P256_MODULUS), U256::ZERO);
1229        assert_eq!(
1230            P256_MODULUS.sub_mod(&U256::from_u64(1), &P256_MODULUS),
1231            P256_MODULUS - U256::ONE
1232        );
1233        assert_eq!(P256_P_MINUS_TWO.double_mod(&P256_MODULUS), P256_MODULUS - U256::from_u64(4));
1234        assert_eq!(P256_P_PLUS_ONE_OVER_FOUR.mul_mod(&U256::from_u64(4), &P256_MODULUS), U256::ONE);
1235        assert_eq!(P256_ORDER.add_mod(&U256::ONE, &P256_ORDER), U256::ONE);
1236    }
1237
1238    #[test]
1239    fn string_round_trips_for_common_radices() {
1240        let values = [
1241            U256::ZERO,
1242            U256::ONE,
1243            U256::MAX,
1244            U256::from_be_slice(&decode_hex::<32>(
1245                "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
1246            )),
1247        ];
1248
1249        for value in values {
1250            for radix in [2, 10, 16] {
1251                let encoded = value.to_string_radix(radix);
1252                let decoded = U256::from_str_radix(&encoded, radix).unwrap();
1253                assert_eq!(decoded, value);
1254            }
1255        }
1256    }
1257
1258    #[test]
1259    fn operator_overloads_work_with_primitives() {
1260        let value = U128::from_u64(10);
1261        assert_eq!(value + 5u64, U128::from_u64(15));
1262        assert_eq!(value - (-5i32), U128::from_u64(15));
1263        assert_eq!(value * -3i32, U128::from_u64(30));
1264        assert_eq!(value / -3i32, U128::from_u64(3));
1265        assert_eq!(value % -3i32, 1);
1266
1267        let signed = I128::from_i128(-10);
1268        assert_eq!(signed + 3u32, I128::from_i128(-7));
1269        assert_eq!(signed - (-5i32), I128::from_i128(-5));
1270        assert_eq!(signed * -2i32, I128::from_i128(20));
1271        assert_eq!(signed / -4i32, I128::from_i128(2));
1272        assert_eq!(signed % 4u32, I128::from_i128(-2));
1273    }
1274
1275    #[test]
1276    fn constant_time_helpers_select_and_compare() {
1277        let a = U256::from_u64(7);
1278        let b = U256::from_u64(11);
1279        assert_eq!(U256::ct_select(&a, &b, true), a);
1280        assert_eq!(U256::ct_select(&a, &b, false), b);
1281        assert!(a.ct_eq(&a));
1282        assert!(!a.ct_eq(&b));
1283        assert!(b.ct_ge(&a));
1284        assert!(!a.ct_ge(&b));
1285    }
1286
1287    #[test]
1288    fn from_str_radix_rejects_invalid_inputs() {
1289        assert_eq!(U128::from_str_radix("", 10), Err(Error::EmptyString));
1290        assert_eq!(U128::from_str_radix("10", 1), Err(Error::InvalidRadix));
1291        assert_eq!(U128::from_str_radix("2", 2), Err(Error::InvalidDigit));
1292        assert_eq!(U128::from_str_radix("zz", 10), Err(Error::InvalidDigit));
1293        assert_eq!(
1294            U128::from_str_radix("340282366920938463463374607431768211456", 10),
1295            Err(Error::Overflow)
1296        );
1297    }
1298
1299    #[test]
1300    fn byte_round_trips_match_p256_constants() {
1301        let modulus_hex = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
1302        let order_hex = "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551";
1303
1304        let modulus_bytes = decode_hex::<32>(modulus_hex);
1305        let order_bytes = decode_hex::<32>(order_hex);
1306
1307        let modulus = U256::from_be_slice(&modulus_bytes);
1308        let order = U256::from_be_slice(&order_bytes);
1309
1310        assert_eq!(modulus, P256_MODULUS);
1311        assert_eq!(order, P256_ORDER);
1312        assert_eq!(modulus.to_be_bytes_fixed::<32>(), modulus_bytes);
1313        assert_eq!(order.to_be_bytes_fixed::<32>(), order_bytes);
1314        assert_eq!(format!("{modulus:x}"), modulus_hex);
1315        assert_eq!(format!("{order:X}"), order_hex.to_uppercase());
1316    }
1317
1318    #[test]
1319    fn little_endian_round_trip_works() {
1320        let value = U256::from_be_slice(&decode_hex::<32>(
1321            "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
1322        ));
1323        let le = value.to_le_bytes_fixed::<32>();
1324        assert_eq!(U256::from_le_slice(&le), value);
1325    }
1326
1327    #[test]
1328    fn modular_addition_vectors() {
1329        struct Test {
1330            a: U256,
1331            b: U256,
1332            m: U256,
1333            expected: U256,
1334        }
1335        let tests = [
1336            Test {
1337                a: U256::ZERO,
1338                b: U256::ZERO,
1339                m: P256_MODULUS,
1340                expected: U256::ZERO,
1341            },
1342            Test {
1343                a: U256::ZERO,
1344                b: U256::ONE,
1345                m: P256_MODULUS,
1346                expected: U256::ONE,
1347            },
1348            Test {
1349                a: U256::ONE,
1350                b: U256::ONE,
1351                m: P256_MODULUS,
1352                expected: U256::from_u64(2),
1353            },
1354            Test {
1355                a: P256_MODULUS - U256::ONE,
1356                b: U256::ONE,
1357                m: P256_MODULUS,
1358                expected: U256::ZERO,
1359            },
1360            Test {
1361                a: P256_MODULUS - U256::ONE,
1362                b: U256::from_u64(2),
1363                m: P256_MODULUS,
1364                expected: U256::ONE,
1365            },
1366            Test {
1367                a: U256::ZERO,
1368                b: U256::ZERO,
1369                m: P256_ORDER,
1370                expected: U256::ZERO,
1371            },
1372            Test {
1373                a: U256::ZERO,
1374                b: U256::ONE,
1375                m: P256_ORDER,
1376                expected: U256::ONE,
1377            },
1378            Test {
1379                a: U256::ONE,
1380                b: U256::ONE,
1381                m: P256_ORDER,
1382                expected: U256::from_u64(2),
1383            },
1384            Test {
1385                a: U256::MAX,
1386                b: U256::ONE,
1387                m: P256_ORDER,
1388                expected: U256::from_limbs([
1389                    0x0c46_353d_039c_daaf,
1390                    0x4319_0552_58e8_617b,
1391                    0x0000_0000_0000_0000,
1392                    0x0000_0000_ffff_ffff,
1393                ]),
1394            },
1395            Test {
1396                a: P256_ORDER - U256::ONE,
1397                b: U256::ONE,
1398                m: P256_ORDER,
1399                expected: U256::ZERO,
1400            },
1401            Test {
1402                a: P256_ORDER - U256::ONE,
1403                b: U256::from_u64(2),
1404                m: P256_ORDER,
1405                expected: U256::ONE,
1406            },
1407            Test {
1408                a: U256::ZERO,
1409                b: U256::ZERO,
1410                m: ED25519_P,
1411                expected: U256::ZERO,
1412            },
1413            Test {
1414                a: U256::ZERO,
1415                b: U256::ONE,
1416                m: ED25519_P,
1417                expected: U256::ONE,
1418            },
1419            Test {
1420                a: U256::ONE,
1421                b: U256::ONE,
1422                m: ED25519_P,
1423                expected: U256::from_u64(2),
1424            },
1425            Test {
1426                a: U256::from_limbs([
1427                    0xffff_ffff_ffff_ffff,
1428                    0x0000_0000_0000_0000,
1429                    0x0000_0000_0000_0000,
1430                    0x0000_0000_0000_0000,
1431                ]),
1432                b: U256::ONE,
1433                m: P256_MODULUS,
1434                expected: U256::from_limbs([
1435                    0x0000_0000_0000_0000,
1436                    0x0000_0000_0000_0001,
1437                    0x0000_0000_0000_0000,
1438                    0x0000_0000_0000_0000,
1439                ]),
1440            },
1441            Test {
1442                a: U256::from_limbs([
1443                    0xffff_ffff_ffff_ffff,
1444                    0x0000_0000_0000_0000,
1445                    0x0000_0000_0000_0000,
1446                    0x0000_0000_0000_0000,
1447                ]),
1448                b: U256::ONE,
1449                m: P256_ORDER,
1450                expected: U256::from_limbs([
1451                    0x0000_0000_0000_0000,
1452                    0x0000_0000_0000_0001,
1453                    0x0000_0000_0000_0000,
1454                    0x0000_0000_0000_0000,
1455                ]),
1456            },
1457            Test {
1458                a: U256::from_limbs([
1459                    0xffff_ffff_ffff_ffff,
1460                    0x0000_0000_0000_0000,
1461                    0x0000_0000_0000_0000,
1462                    0x0000_0000_0000_0000,
1463                ]),
1464                b: U256::ONE,
1465                m: ED25519_P,
1466                expected: U256::from_limbs([
1467                    0x0000_0000_0000_0000,
1468                    0x0000_0000_0000_0001,
1469                    0x0000_0000_0000_0000,
1470                    0x0000_0000_0000_0000,
1471                ]),
1472            },
1473            Test {
1474                a: ED25519_P - U256::ONE,
1475                b: ED25519_P - U256::ONE,
1476                m: ED25519_P,
1477                expected: (ED25519_P - U256::ONE).double_mod(&ED25519_P),
1478            },
1479        ];
1480        for t in &tests {
1481            assert_eq!(t.a.add_mod(&t.b, &t.m), t.expected, "add_mod({:x}, {:x}, {:x})", t.a, t.b, t.m);
1482        }
1483    }
1484
1485    #[test]
1486    fn modular_subtraction_vectors() {
1487        struct Test {
1488            a: U256,
1489            b: U256,
1490            m: U256,
1491            expected: U256,
1492        }
1493        let tests = [
1494            Test {
1495                a: U256::ZERO,
1496                b: U256::ZERO,
1497                m: P256_MODULUS,
1498                expected: U256::ZERO,
1499            },
1500            Test {
1501                a: U256::ONE,
1502                b: U256::ZERO,
1503                m: P256_MODULUS,
1504                expected: U256::ONE,
1505            },
1506            Test {
1507                a: U256::ZERO,
1508                b: U256::ONE,
1509                m: P256_MODULUS,
1510                expected: P256_MODULUS - U256::ONE,
1511            },
1512            Test {
1513                a: P256_MODULUS - U256::ONE,
1514                b: U256::ONE,
1515                m: P256_MODULUS,
1516                expected: P256_MODULUS - U256::from_u64(2),
1517            },
1518            Test {
1519                a: U256::ONE,
1520                b: P256_MODULUS - U256::ONE,
1521                m: P256_MODULUS,
1522                expected: U256::from_u64(2),
1523            },
1524            Test {
1525                a: U256::ZERO,
1526                b: U256::ZERO,
1527                m: P256_ORDER,
1528                expected: U256::ZERO,
1529            },
1530            Test {
1531                a: U256::ONE,
1532                b: U256::ZERO,
1533                m: P256_ORDER,
1534                expected: U256::ONE,
1535            },
1536            Test {
1537                a: U256::ZERO,
1538                b: U256::ONE,
1539                m: P256_ORDER,
1540                expected: P256_ORDER - U256::ONE,
1541            },
1542            Test {
1543                a: P256_ORDER - U256::ONE,
1544                b: U256::ONE,
1545                m: P256_ORDER,
1546                expected: P256_ORDER - U256::from_u64(2),
1547            },
1548            Test {
1549                a: U256::ONE,
1550                b: P256_ORDER - U256::ONE,
1551                m: P256_ORDER,
1552                expected: U256::from_u64(2),
1553            },
1554            Test {
1555                a: U256::ZERO,
1556                b: U256::ZERO,
1557                m: ED25519_P,
1558                expected: U256::ZERO,
1559            },
1560            Test {
1561                a: U256::ONE,
1562                b: U256::ZERO,
1563                m: ED25519_P,
1564                expected: U256::ONE,
1565            },
1566            Test {
1567                a: U256::ZERO,
1568                b: U256::ONE,
1569                m: ED25519_P,
1570                expected: ED25519_P - U256::ONE,
1571            },
1572            Test {
1573                a: ED25519_P - U256::ONE,
1574                b: U256::ONE,
1575                m: ED25519_P,
1576                expected: ED25519_P - U256::from_u64(2),
1577            },
1578            Test {
1579                a: U256::ONE,
1580                b: ED25519_P - U256::ONE,
1581                m: ED25519_P,
1582                expected: U256::from_u64(2),
1583            },
1584        ];
1585        for t in &tests {
1586            assert_eq!(t.a.sub_mod(&t.b, &t.m), t.expected, "sub_mod({:x}, {:x}, {:x})", t.a, t.b, t.m);
1587        }
1588    }
1589
1590    #[test]
1591    fn modular_multiplication_vectors() {
1592        struct Test {
1593            a: U256,
1594            b: U256,
1595            m: U256,
1596            expected: U256,
1597        }
1598        let tests = [
1599            Test {
1600                a: U256::ZERO,
1601                b: U256::ZERO,
1602                m: P256_MODULUS,
1603                expected: U256::ZERO,
1604            },
1605            Test {
1606                a: U256::ZERO,
1607                b: U256::ONE,
1608                m: P256_MODULUS,
1609                expected: U256::ZERO,
1610            },
1611            Test {
1612                a: U256::ONE,
1613                b: U256::ZERO,
1614                m: P256_MODULUS,
1615                expected: U256::ZERO,
1616            },
1617            Test {
1618                a: U256::ONE,
1619                b: U256::ONE,
1620                m: P256_MODULUS,
1621                expected: U256::ONE,
1622            },
1623            Test {
1624                a: U256::from_u64(2),
1625                b: U256::from_u64(3),
1626                m: P256_MODULUS,
1627                expected: U256::from_u64(6),
1628            },
1629            Test {
1630                a: U256::MAX,
1631                b: U256::ONE,
1632                m: P256_MODULUS,
1633                expected: U256::from_limbs([
1634                    0x0000_0000_0000_0000,
1635                    0xffff_ffff_0000_0000,
1636                    0xffff_ffff_ffff_ffff,
1637                    0x0000_0000_ffff_fffe,
1638                ]),
1639            },
1640            Test {
1641                a: P256_MODULUS - U256::ONE,
1642                b: U256::ONE,
1643                m: P256_MODULUS,
1644                expected: P256_MODULUS - U256::ONE,
1645            },
1646            Test {
1647                a: P256_MODULUS - U256::ONE,
1648                b: P256_MODULUS - U256::ONE,
1649                m: P256_MODULUS,
1650                expected: U256::ONE,
1651            },
1652            Test {
1653                a: P256_MODULUS + U256::ONE,
1654                b: P256_MODULUS + U256::ONE,
1655                m: P256_MODULUS,
1656                expected: U256::ONE,
1657            },
1658            Test {
1659                a: U256::ZERO,
1660                b: U256::ZERO,
1661                m: P256_ORDER,
1662                expected: U256::ZERO,
1663            },
1664            Test {
1665                a: U256::ZERO,
1666                b: U256::ONE,
1667                m: P256_ORDER,
1668                expected: U256::ZERO,
1669            },
1670            Test {
1671                a: U256::ONE,
1672                b: U256::ZERO,
1673                m: P256_ORDER,
1674                expected: U256::ZERO,
1675            },
1676            Test {
1677                a: U256::ONE,
1678                b: U256::ONE,
1679                m: P256_ORDER,
1680                expected: U256::ONE,
1681            },
1682            Test {
1683                a: U256::from_u64(2),
1684                b: U256::from_u64(3),
1685                m: P256_ORDER,
1686                expected: U256::from_u64(6),
1687            },
1688            Test {
1689                a: P256_ORDER - U256::ONE,
1690                b: U256::ONE,
1691                m: P256_ORDER,
1692                expected: P256_ORDER - U256::ONE,
1693            },
1694            Test {
1695                a: P256_ORDER - U256::ONE,
1696                b: P256_ORDER - U256::ONE,
1697                m: P256_ORDER,
1698                expected: U256::ONE,
1699            },
1700            Test {
1701                a: P256_ORDER + U256::ONE,
1702                b: P256_ORDER + U256::ONE,
1703                m: P256_ORDER,
1704                expected: U256::ONE,
1705            },
1706            Test {
1707                a: U256::ZERO,
1708                b: U256::ZERO,
1709                m: ED25519_P,
1710                expected: U256::ZERO,
1711            },
1712            Test {
1713                a: U256::ZERO,
1714                b: U256::ONE,
1715                m: ED25519_P,
1716                expected: U256::ZERO,
1717            },
1718            Test {
1719                a: U256::ONE,
1720                b: U256::ZERO,
1721                m: ED25519_P,
1722                expected: U256::ZERO,
1723            },
1724            Test {
1725                a: U256::ONE,
1726                b: U256::ONE,
1727                m: ED25519_P,
1728                expected: U256::ONE,
1729            },
1730            Test {
1731                a: U256::from_u64(2),
1732                b: U256::from_u64(3),
1733                m: ED25519_P,
1734                expected: U256::from_u64(6),
1735            },
1736            Test {
1737                a: ED25519_P - U256::ONE,
1738                b: U256::ONE,
1739                m: ED25519_P,
1740                expected: ED25519_P - U256::ONE,
1741            },
1742            Test {
1743                a: ED25519_P - U256::ONE,
1744                b: ED25519_P - U256::ONE,
1745                m: ED25519_P,
1746                expected: U256::ONE,
1747            },
1748            Test {
1749                a: ED25519_P + U256::ONE,
1750                b: ED25519_P + U256::ONE,
1751                m: ED25519_P,
1752                expected: U256::ONE,
1753            },
1754            Test {
1755                a: U256::from_limbs([
1756                    0xffff_ffff_ffff_ffff,
1757                    0x0000_0000_0000_0000,
1758                    0x0000_0000_0000_0000,
1759                    0x0000_0000_0000_0000,
1760                ]),
1761                b: U256::from_limbs([
1762                    0xffff_ffff_ffff_ffff,
1763                    0x0000_0000_0000_0000,
1764                    0x0000_0000_0000_0000,
1765                    0x0000_0000_0000_0000,
1766                ]),
1767                m: P256_MODULUS,
1768                expected: U256::from_limbs([
1769                    0x0000_0000_0000_0001,
1770                    0xffff_ffff_ffff_fffe,
1771                    0x0000_0000_0000_0000,
1772                    0x0000_0000_0000_0000,
1773                ]),
1774            },
1775        ];
1776        for t in &tests {
1777            assert_eq!(t.a.mul_mod(&t.b, &t.m), t.expected, "mul_mod({:x}, {:x}, {:x})", t.a, t.b, t.m);
1778        }
1779    }
1780
1781    #[test]
1782    fn raw_addition_vectors() {
1783        struct Test {
1784            a: U256,
1785            b: U256,
1786            expected_sum: U256,
1787            expected_carry: u64,
1788        }
1789        let tests = [
1790            Test {
1791                a: U256::ZERO,
1792                b: U256::ZERO,
1793                expected_sum: U256::ZERO,
1794                expected_carry: 0,
1795            },
1796            Test {
1797                a: U256::ZERO,
1798                b: U256::ONE,
1799                expected_sum: U256::ONE,
1800                expected_carry: 0,
1801            },
1802            Test {
1803                a: U256::ONE,
1804                b: U256::ONE,
1805                expected_sum: U256::from_u64(2),
1806                expected_carry: 0,
1807            },
1808            Test {
1809                a: U256::MAX,
1810                b: U256::ZERO,
1811                expected_sum: U256::MAX,
1812                expected_carry: 0,
1813            },
1814            Test {
1815                a: U256::MAX,
1816                b: U256::ONE,
1817                expected_sum: U256::ZERO,
1818                expected_carry: 1,
1819            },
1820            Test {
1821                a: U256::MAX,
1822                b: U256::MAX,
1823                expected_sum: U256::MAX - U256::ONE,
1824                expected_carry: 1,
1825            },
1826            Test {
1827                a: U256::MAX - U256::ONE,
1828                b: U256::ONE,
1829                expected_sum: U256::MAX,
1830                expected_carry: 0,
1831            },
1832            Test {
1833                a: U256::ONE,
1834                b: U256::MAX,
1835                expected_sum: U256::ZERO,
1836                expected_carry: 1,
1837            },
1838            Test {
1839                a: U256::from_limbs([
1840                    0xffff_ffff_ffff_ffff,
1841                    0x0000_0000_0000_0000,
1842                    0x0000_0000_0000_0000,
1843                    0x0000_0000_0000_0000,
1844                ]),
1845                b: U256::ONE,
1846                expected_sum: U256::from_limbs([
1847                    0x0000_0000_0000_0000,
1848                    0x0000_0000_0000_0001,
1849                    0x0000_0000_0000_0000,
1850                    0x0000_0000_0000_0000,
1851                ]),
1852                expected_carry: 0,
1853            },
1854            Test {
1855                a: U256::from_limbs([
1856                    0xffff_ffff_ffff_ffff,
1857                    0xffff_ffff_ffff_ffff,
1858                    0x0000_0000_0000_0000,
1859                    0x0000_0000_0000_0000,
1860                ]),
1861                b: U256::ONE,
1862                expected_sum: U256::from_limbs([
1863                    0x0000_0000_0000_0000,
1864                    0x0000_0000_0000_0000,
1865                    0x0000_0000_0000_0001,
1866                    0x0000_0000_0000_0000,
1867                ]),
1868                expected_carry: 0,
1869            },
1870        ];
1871        for t in &tests {
1872            let (sum, carry) = t.a.add_raw(&t.b);
1873            assert_eq!(sum, t.expected_sum, "add_raw({:x}, {:x}).sum", t.a, t.b);
1874            assert_eq!(carry, t.expected_carry, "add_raw({:x}, {:x}).carry", t.a, t.b);
1875        }
1876    }
1877
1878    #[test]
1879    fn raw_subtraction_vectors() {
1880        struct Test {
1881            a: U256,
1882            b: U256,
1883            expected_diff: U256,
1884            expected_borrow: u64,
1885        }
1886        let tests = [
1887            Test {
1888                a: U256::ZERO,
1889                b: U256::ZERO,
1890                expected_diff: U256::ZERO,
1891                expected_borrow: 0,
1892            },
1893            Test {
1894                a: U256::ONE,
1895                b: U256::ZERO,
1896                expected_diff: U256::ONE,
1897                expected_borrow: 0,
1898            },
1899            Test {
1900                a: U256::ONE,
1901                b: U256::ONE,
1902                expected_diff: U256::ZERO,
1903                expected_borrow: 0,
1904            },
1905            Test {
1906                a: U256::ZERO,
1907                b: U256::ONE,
1908                expected_diff: U256::MAX,
1909                expected_borrow: 1,
1910            },
1911            Test {
1912                a: U256::MAX,
1913                b: U256::MAX,
1914                expected_diff: U256::ZERO,
1915                expected_borrow: 0,
1916            },
1917            Test {
1918                a: U256::MAX,
1919                b: U256::ZERO,
1920                expected_diff: U256::MAX,
1921                expected_borrow: 0,
1922            },
1923            Test {
1924                a: U256::MAX,
1925                b: U256::MAX - U256::ONE,
1926                expected_diff: U256::ONE,
1927                expected_borrow: 0,
1928            },
1929            Test {
1930                a: U256::ONE,
1931                b: U256::MAX,
1932                expected_diff: U256::from_u64(2),
1933                expected_borrow: 1,
1934            },
1935        ];
1936        for t in &tests {
1937            let (diff, borrow) = t.a.sub_raw(&t.b);
1938            assert_eq!(diff, t.expected_diff, "sub_raw({:x}, {:x}).diff", t.a, t.b);
1939            assert_eq!(borrow, t.expected_borrow, "sub_raw({:x}, {:x}).borrow", t.a, t.b);
1940        }
1941    }
1942
1943    #[test]
1944    fn string_roundtrip_vectors() {
1945        struct Test {
1946            value: U256,
1947            radix: u32,
1948            expected: &'static str,
1949        }
1950        let tests = [
1951            Test {
1952                value: U256::ZERO,
1953                radix: 2,
1954                expected: "0",
1955            },
1956            Test {
1957                value: U256::ZERO,
1958                radix: 10,
1959                expected: "0",
1960            },
1961            Test {
1962                value: U256::ZERO,
1963                radix: 16,
1964                expected: "0",
1965            },
1966            Test {
1967                value: U256::ONE,
1968                radix: 2,
1969                expected: "1",
1970            },
1971            Test {
1972                value: U256::ONE,
1973                radix: 10,
1974                expected: "1",
1975            },
1976            Test {
1977                value: U256::ONE,
1978                radix: 16,
1979                expected: "1",
1980            },
1981            Test {
1982                value: U256::MAX,
1983                radix: 10,
1984                expected: "115792089237316195423570985008687907853269984665640564039457584007913129639935",
1985            },
1986            Test {
1987                value: U256::MAX,
1988                radix: 16,
1989                expected: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1990            },
1991            Test {
1992                value: P256_MODULUS,
1993                radix: 10,
1994                expected: "115792089210356248762697446949407573530086143415290314195533631308867097853951",
1995            },
1996            Test {
1997                value: P256_MODULUS,
1998                radix: 16,
1999                expected: "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
2000            },
2001            Test {
2002                value: P256_ORDER,
2003                radix: 10,
2004                expected: "115792089210356248762697446949407573529996955224135760342422259061068512044369",
2005            },
2006            Test {
2007                value: P256_ORDER,
2008                radix: 16,
2009                expected: "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
2010            },
2011            Test {
2012                value: ED25519_P,
2013                radix: 10,
2014                expected: "57896044618658097711785492504343953926634992332820282019728792003956564819949",
2015            },
2016            Test {
2017                value: ED25519_P,
2018                radix: 16,
2019                expected: "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed",
2020            },
2021        ];
2022        for t in &tests {
2023            let encoded = t.value.to_string_radix(t.radix);
2024            assert_eq!(encoded, t.expected, "to_string_radix({:x}, {})", t.value, t.radix);
2025            let decoded = U256::from_str_radix(t.expected, t.radix).unwrap();
2026            assert_eq!(decoded, t.value, "from_str_radix round-trip");
2027        }
2028    }
2029
2030    #[test]
2031    fn mul_mod_edge_cases() {
2032        assert_eq!(P256_P_PLUS_ONE_OVER_FOUR.mul_mod(&U256::from_u64(4), &P256_MODULUS), U256::ONE);
2033
2034        let (a, _) = U256::MAX.mul_word(2);
2035        assert_eq!(a.add_mod(&U256::ZERO, &P256_MODULUS), U256::MAX.double_mod(&P256_MODULUS));
2036    }
2037
2038    // P-256 generator point coordinates (NIST SP 800-186 / RFC 6979).
2039    // Test vectors generated with Python: `hex((Gx * Gy) % p256_p)` etc.
2040    const P256_GX: U256 = U256::from_be_slice_const(
2041        0x6b17d1f2, 0xe12c4247, 0xf8bce6e5, 0x63a440f2, 0x77037d81, 0x2deb33a0, 0xf4a13945, 0xd898c296,
2042    );
2043    const P256_GY: U256 = U256::from_be_slice_const(
2044        0x4fe342e2, 0xfe1a7f9b, 0x8ee7eb4a, 0x7c0f9e16, 0x2bce3357, 0x6b315ece, 0xcbb64068, 0x37bf51f5,
2045    );
2046
2047    impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
2048        // Helper to build a 256-bit constant from eight 32-bit big-endian words.
2049        // Only valid for BITS=256, LIMBS=4; used only in test helpers.
2050        const fn from_be_slice_const(w7: u32, w6: u32, w5: u32, w4: u32, w3: u32, w2: u32, w1: u32, w0: u32) -> Self {
2051            let limb3 = ((w7 as u64) << 32) | (w6 as u64);
2052            let limb2 = ((w5 as u64) << 32) | (w4 as u64);
2053            let limb1 = ((w3 as u64) << 32) | (w2 as u64);
2054            let limb0 = ((w1 as u64) << 32) | (w0 as u64);
2055            let limbs = [0u64; LIMBS];
2056            if LIMBS > 0 {
2057                let mut l = [0u64; LIMBS];
2058                l[0] = limb0;
2059                l[1] = limb1;
2060                l[2] = limb2;
2061                l[3] = limb3;
2062                return Self {
2063                    limbs: l,
2064                };
2065            }
2066            Self {
2067                limbs,
2068            }
2069        }
2070    }
2071
2072    #[test]
2073    fn p256_mul_mod_with_generator_coordinates() {
2074        // Vectors verified with Python's arbitrary-precision arithmetic.
2075        let gx_gy_mod_p = U256::from_be_slice(&decode_hex::<32>(
2076            "823cd15f6dd3c71933565064513a6b2bd183e554c6a08622f713ebbbface98be",
2077        ));
2078        let gx_sq_mod_p = U256::from_be_slice(&decode_hex::<32>(
2079            "98f6b84d29bef2b281819a5e0e3690d833b699495d694dd1002ae56c426b3f8c",
2080        ));
2081        let gy_sq_mod_p = U256::from_be_slice(&decode_hex::<32>(
2082            "55df5d5850f47bad82149139979369fe498a9022a412b5e0bedd2cfc21c3ed91",
2083        ));
2084
2085        assert_eq!(P256_GX.mul_mod(&P256_GY, &P256_MODULUS), gx_gy_mod_p, "Gx*Gy mod p");
2086        // Commutativity
2087        assert_eq!(
2088            P256_GY.mul_mod(&P256_GX, &P256_MODULUS),
2089            gx_gy_mod_p,
2090            "Gy*Gx mod p (commutativity)"
2091        );
2092        assert_eq!(P256_GX.mul_mod(&P256_GX, &P256_MODULUS), gx_sq_mod_p, "Gx^2 mod p");
2093        assert_eq!(P256_GY.mul_mod(&P256_GY, &P256_MODULUS), gy_sq_mod_p, "Gy^2 mod p");
2094    }
2095
2096    #[test]
2097    fn p256_add_sub_mod_with_generator_coordinates() {
2098        // Gx + Gy mod p256_p  (Python: hex((Gx + Gy) % p))
2099        let gx_plus_gy = U256::from_be_slice(&decode_hex::<32>(
2100            "bafb14d5df46c1e387a4d22fdfb3df08a2d1b0d8991c926fc05779ae1058148b",
2101        ));
2102        // Gx - Gy mod p256_p  (Python: hex((Gx - Gy) % p))
2103        let gx_minus_gy = U256::from_be_slice(&decode_hex::<32>(
2104            "1b348f0fe311c2ac69d4fb9ae794a2dc4b354a29c2b9d4d228eaf8dda0d970a1",
2105        ));
2106        // Gy - Gx mod p256_p
2107        let gy_minus_gx = U256::from_be_slice(&decode_hex::<32>(
2108            "e4cb70ef1cee3d54962b0465186b5d23b4cab5d73d462b2dd71507225f268f5e",
2109        ));
2110
2111        assert_eq!(P256_GX.add_mod(&P256_GY, &P256_MODULUS), gx_plus_gy);
2112        assert_eq!(P256_GX.sub_mod(&P256_GY, &P256_MODULUS), gx_minus_gy);
2113        assert_eq!(P256_GY.sub_mod(&P256_GX, &P256_MODULUS), gy_minus_gx);
2114        // (a-b) + (b-a) = 0 mod p
2115        assert_eq!(gx_minus_gy.add_mod(&gy_minus_gx, &P256_MODULUS), U256::ZERO);
2116    }
2117
2118    #[test]
2119    fn bit_access() {
2120        // Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
2121        // Bit 0: the LSB of limb[0] = 0x...96 → bit 0 = 0
2122        assert!(!P256_GX.bit(0), "bit 0 of Gx");
2123        assert!(P256_GX.bit(1), "bit 1 of Gx");
2124        assert!(P256_GX.bit(2), "bit 2 of Gx");
2125        assert!(P256_GX.bit(63), "bit 63 of Gx");
2126        assert!(!P256_GX.bit(64), "bit 64 of Gx");
2127        assert!(!P256_GX.bit(65), "bit 65 of Gx");
2128        assert!(!P256_GX.bit(127), "bit 127 of Gx");
2129        assert!(!P256_GX.bit(128), "bit 128 of Gx");
2130        assert!(P256_GX.bit(192), "bit 192 of Gx");
2131        assert!(!P256_GX.bit(255), "bit 255 of Gx");
2132        // Out-of-range bit is false
2133        assert!(!P256_GX.bit(256), "bit 256 (out of range) of Gx");
2134
2135        // p256_p: all-ones in low 64 bits → bit 0 is 1
2136        assert!(P256_MODULUS.bit(0), "bit 0 of p256_p");
2137        assert!(P256_MODULUS.bit(63), "bit 63 of p256_p");
2138        assert!(P256_MODULUS.bit(64), "bit 64 of p256_p");
2139        assert!(!P256_MODULUS.bit(96), "bit 96 of p256_p");
2140        assert!(P256_MODULUS.bit(255), "bit 255 of p256_p");
2141
2142        assert!(!U256::ZERO.bit(0));
2143        assert!(!U256::ZERO.bit(255));
2144        assert!(U256::ONE.bit(0));
2145        assert!(!U256::ONE.bit(1));
2146        assert!(U256::MAX.bit(0));
2147        assert!(U256::MAX.bit(255));
2148    }
2149
2150    #[test]
2151    fn is_odd_flag() {
2152        assert!(!U256::ZERO.is_odd(), "0 is even");
2153        assert!(U256::ONE.is_odd(), "1 is odd");
2154        assert!(!U256::from_u64(2).is_odd(), "2 is even");
2155        assert!(U256::from_u64(3).is_odd(), "3 is odd");
2156        assert!(P256_MODULUS.is_odd(), "p256_p is odd");
2157        assert!(P256_ORDER.is_odd(), "p256_n is odd");
2158        assert!(!P256_GX.is_odd(), "Gx is even");
2159        assert!(P256_GY.is_odd(), "Gy is odd");
2160        assert!(U256::MAX.is_odd(), "MAX is odd");
2161    }
2162
2163    #[test]
2164    fn ct_ge_comprehensive() {
2165        let zero = U256::ZERO;
2166        let one = U256::ONE;
2167        let max = U256::MAX;
2168
2169        // Equal values
2170        assert!(zero.ct_ge(&zero), "0 >= 0");
2171        assert!(one.ct_ge(&one), "1 >= 1");
2172        assert!(max.ct_ge(&max), "MAX >= MAX");
2173        assert!(P256_MODULUS.ct_ge(&P256_MODULUS), "p >= p");
2174
2175        // Strict greater
2176        assert!(one.ct_ge(&zero), "1 >= 0");
2177        assert!(max.ct_ge(&zero), "MAX >= 0");
2178        assert!(max.ct_ge(&one), "MAX >= 1");
2179        assert!(P256_GX.ct_ge(&zero), "Gx >= 0");
2180
2181        // Strict less
2182        assert!(!zero.ct_ge(&one), "NOT 0 >= 1");
2183        assert!(!zero.ct_ge(&max), "NOT 0 >= MAX");
2184        assert!(!one.ct_ge(&max), "NOT 1 >= MAX");
2185        assert!(!P256_GX.ct_ge(&max), "NOT Gx >= MAX");
2186
2187        // Adjacent values
2188        assert!((P256_MODULUS - U256::ONE).ct_ge(&(P256_MODULUS - U256::from_u64(2))));
2189        assert!(!P256_MODULUS.sub_mod(&U256::ONE, &P256_MODULUS).ct_ge(&P256_MODULUS));
2190    }
2191
2192    #[test]
2193    fn div_rem_word_vectors() {
2194        // Vectors generated with Python: p256_p / divisor
2195        // p256_p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
2196        struct Test {
2197            dividend: U256,
2198            divisor: u64,
2199            expected_quotient: U256,
2200            expected_rem: u64,
2201        }
2202        let tests = [
2203            Test {
2204                dividend: P256_MODULUS,
2205                divisor: 1,
2206                expected_quotient: P256_MODULUS,
2207                expected_rem: 0,
2208            },
2209            Test {
2210                dividend: P256_MODULUS,
2211                divisor: 2,
2212                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2213                    "7fffffff800000008000000000000000000000007fffffffffffffffffffffff",
2214                )),
2215                expected_rem: 1,
2216            },
2217            Test {
2218                dividend: P256_MODULUS,
2219                divisor: 10,
2220                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2221                    "1999999980000000199999999999999999999999b33333333333333333333333",
2222                )),
2223                expected_rem: 1,
2224            },
2225            Test {
2226                dividend: P256_MODULUS,
2227                divisor: 16,
2228                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2229                    "0ffffffff00000001000000000000000000000000fffffffffffffffffffffff",
2230                )),
2231                expected_rem: 0xf,
2232            },
2233            Test {
2234                dividend: P256_MODULUS,
2235                divisor: 0xffff_ffff,
2236                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2237                    "0000000100000000000000010000000100000001000000020000000200000002",
2238                )),
2239                expected_rem: 1,
2240            },
2241            Test {
2242                dividend: P256_MODULUS,
2243                divisor: 0x1_0000_0000,
2244                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2245                    "00000000ffffffff00000001000000000000000000000000ffffffffffffffff",
2246                )),
2247                expected_rem: 0xffff_ffff,
2248            },
2249            Test {
2250                dividend: U256::ZERO,
2251                divisor: 7,
2252                expected_quotient: U256::ZERO,
2253                expected_rem: 0,
2254            },
2255            Test {
2256                dividend: U256::ONE,
2257                divisor: 7,
2258                expected_quotient: U256::ZERO,
2259                expected_rem: 1,
2260            },
2261            Test {
2262                dividend: U256::from_u64(100),
2263                divisor: 7,
2264                expected_quotient: U256::from_u64(14),
2265                expected_rem: 2,
2266            },
2267        ];
2268        for t in &tests {
2269            let (q, r) = t.dividend.div_rem_word(t.divisor);
2270            assert_eq!(q, t.expected_quotient, "div_rem_word({:x}, {}).quotient", t.dividend, t.divisor);
2271            assert_eq!(r, t.expected_rem, "div_rem_word({:x}, {}).rem", t.dividend, t.divisor);
2272        }
2273    }
2274
2275    #[test]
2276    fn add_word_vectors() {
2277        // Vectors: Python hex(Gx + k) for small k
2278        let gx = P256_GX;
2279        let gx_plus_1 = U256::from_be_slice(&decode_hex::<32>(
2280            "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c297",
2281        ));
2282        let gx_minus_1 = U256::from_be_slice(&decode_hex::<32>(
2283            "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c295",
2284        ));
2285
2286        let (sum, carry) = gx.add_word(1);
2287        assert_eq!(sum, gx_plus_1, "Gx + 1");
2288        assert_eq!(carry, 0);
2289
2290        let (diff, borrow) = gx.sub_word(1);
2291        assert_eq!(diff, gx_minus_1, "Gx - 1");
2292        assert_eq!(borrow, 0);
2293
2294        // Adding to MAX wraps
2295        let (sum_max, carry_max) = U256::MAX.add_word(1);
2296        assert_eq!(sum_max, U256::ZERO);
2297        assert_eq!(carry_max, 1);
2298
2299        // Subtracting from ZERO borrows
2300        let (diff_zero, borrow_zero) = U256::ZERO.sub_word(1);
2301        assert_eq!(diff_zero, U256::MAX);
2302        assert_eq!(borrow_zero, 1);
2303
2304        // Word that carries across limb boundary: 2^64 - 1 + 1
2305        let val = U256::from_u64(u64::MAX);
2306        let (sum2, carry2) = val.add_word(1);
2307        assert_eq!(sum2, U256::from_limbs([0, 1, 0, 0]));
2308        assert_eq!(carry2, 0);
2309    }
2310
2311    #[test]
2312    fn mul_word_vectors() {
2313        // Gx * 2 = 2*Gx (no overflow since Gx < 2^255)
2314        // Python: hex(Gx * 2)
2315        let gx_times_2 = U256::from_be_slice(&decode_hex::<32>(
2316            "d62fa3e5c258848ff179cdcac74881e4ee06fb025bd66741e942728bb131852c",
2317        ));
2318        let (prod, carry) = P256_GX.mul_word(2);
2319        assert_eq!(prod, gx_times_2, "Gx * 2");
2320        assert_eq!(carry, 0, "Gx * 2 carry");
2321
2322        // MAX * 2 = 2^256 - 2: low 256 bits = all-ones XOR 1, overflow carry = 1
2323        let (prod_max, carry_max) = U256::MAX.mul_word(2);
2324        assert_eq!(prod_max, U256::from_limbs([u64::MAX - 1, u64::MAX, u64::MAX, u64::MAX]));
2325        assert_eq!(carry_max, 1);
2326
2327        // ONE * 0 = 0
2328        let (zero_prod, zero_carry) = U256::ONE.mul_word(0);
2329        assert_eq!(zero_prod, U256::ZERO);
2330        assert_eq!(zero_carry, 0);
2331
2332        // from_u64(10) * from_u64(10) (single-word)
2333        let (p, c) = U128::from_u64(u64::MAX).mul_word(u64::MAX);
2334        // u64::MAX * u64::MAX = 2^128 - 2^65 + 1 = (2^64-1)^2
2335        // low 64 bits = 1, high 64 bits = u64::MAX - 1
2336        assert_eq!(p, U128::from_limbs([1, u64::MAX - 1]));
2337        assert_eq!(c, 0);
2338    }
2339
2340    #[test]
2341    fn fibonacci_number_round_trip() {
2342        // Fib(100) = 354224848179261915075
2343        // hex: 0x1333db76a7c594bfc3
2344        // Verified with Python: `a, b = 0, 1; [a, b = b, a+b for _ in range(100)]; print(a)`
2345        let fib100_dec = "354224848179261915075";
2346        let fib100_hex = "1333db76a7c594bfc3";
2347
2348        let from_dec = U128::from_str_radix(fib100_dec, 10).unwrap();
2349        let from_hex = U128::from_str_radix(fib100_hex, 16).unwrap();
2350
2351        assert_eq!(from_dec, from_hex, "Fib(100) from decimal == from hex");
2352        assert_eq!(from_dec.to_string_radix(10), fib100_dec);
2353        assert_eq!(from_dec.to_string_radix(16), fib100_hex);
2354
2355        // Fib(100) in binary
2356        let fib100_bin = from_dec.to_string_radix(2);
2357        let from_bin = U128::from_str_radix(&fib100_bin, 2).unwrap();
2358        assert_eq!(from_bin, from_dec);
2359
2360        // Octal round-trip
2361        let fib100_oct = from_dec.to_string_radix(8);
2362        let from_oct = U128::from_str_radix(&fib100_oct, 8).unwrap();
2363        assert_eq!(from_oct, from_dec);
2364    }
2365
2366    #[test]
2367    fn display_and_debug_formatting() {
2368        // Display uses decimal
2369        assert_eq!(format!("{}", U256::ZERO), "0");
2370        assert_eq!(format!("{}", U256::ONE), "1");
2371        assert_eq!(
2372            format!("{}", U256::MAX),
2373            "115792089237316195423570985008687907853269984665640564039457584007913129639935"
2374        );
2375        assert_eq!(
2376            format!("{}", P256_MODULUS),
2377            "115792089210356248762697446949407573530086143415290314195533631308867097853951"
2378        );
2379
2380        // LowerHex
2381        assert_eq!(format!("{:x}", U256::ZERO), "0");
2382        assert_eq!(format!("{:x}", U256::ONE), "1");
2383        assert_eq!(
2384            format!("{:x}", U256::MAX),
2385            "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
2386        );
2387        assert_eq!(format!("{:#x}", U256::from_u64(255)), "0xff");
2388
2389        // UpperHex
2390        assert_eq!(format!("{:X}", U256::ZERO), "0");
2391        assert_eq!(
2392            format!("{:X}", P256_MODULUS),
2393            "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
2394        );
2395        assert_eq!(format!("{:#X}", U256::from_u64(255)), "0xFF");
2396
2397        // Debug
2398        assert_eq!(format!("{:?}", U256::ZERO), "Uint(0x0)");
2399        assert_eq!(format!("{:?}", U256::ONE), "Uint(0x1)");
2400        assert_eq!(
2401            format!("{:?}", P256_MODULUS),
2402            "Uint(0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff)"
2403        );
2404    }
2405
2406    #[test]
2407    fn to_be_le_bytes_vec() {
2408        // Verify Vec<u8> output matches fixed-size output
2409        let values = [U256::ZERO, U256::ONE, U256::MAX, P256_MODULUS, P256_GX, P256_GY];
2410        for v in &values {
2411            let be_vec = v.to_be_bytes();
2412            let be_fixed = v.to_be_bytes_fixed::<32>();
2413            assert_eq!(be_vec.as_slice(), be_fixed.as_slice(), "BE bytes of {:x}", v);
2414
2415            let le_vec = v.to_le_bytes();
2416            let le_fixed = v.to_le_bytes_fixed::<32>();
2417            assert_eq!(le_vec.as_slice(), le_fixed.as_slice(), "LE bytes of {:x}", v);
2418
2419            // Round-trip through be
2420            let rt_be = U256::from_be_slice(&be_vec);
2421            assert_eq!(rt_be, *v, "BE round-trip of {:x}", v);
2422
2423            // Round-trip through le
2424            let rt_le = U256::from_le_slice(&le_vec);
2425            assert_eq!(rt_le, *v, "LE round-trip of {:x}", v);
2426        }
2427    }
2428
2429    #[test]
2430    fn max_for_non_64_multiple_bits() {
2431        // Uint<130, 3>: LIMBS=3, top limb should have only bits 0-1 set.
2432        // MAX = 2^130 - 1:
2433        //   limb[0] = 2^64 - 1
2434        //   limb[1] = 2^64 - 1
2435        //   limb[2] = 0b11 = 3  (only 2 bits, since 130 % 64 = 2)
2436        type U130 = Uint<130, 3>;
2437        let max = U130::MAX;
2438        assert_eq!(max.limbs[0], u64::MAX, "U130::MAX limb[0]");
2439        assert_eq!(max.limbs[1], u64::MAX, "U130::MAX limb[1]");
2440        assert_eq!(max.limbs[2], 0b11, "U130::MAX limb[2] should have only 2 bits set");
2441
2442        // Uint<192, 3>: 192 = 3*64, all limbs should be u64::MAX
2443        type U192 = Uint<192, 3>;
2444        let max192 = U192::MAX;
2445        assert_eq!(max192.limbs[0], u64::MAX, "U192::MAX limb[0]");
2446        assert_eq!(max192.limbs[1], u64::MAX, "U192::MAX limb[1]");
2447        assert_eq!(max192.limbs[2], u64::MAX, "U192::MAX limb[2]");
2448
2449        // Uint<65, 2>: top limb should have only 1 bit set
2450        type U65 = Uint<65, 2>;
2451        let max65 = U65::MAX;
2452        assert_eq!(max65.limbs[0], u64::MAX, "U65::MAX limb[0]");
2453        assert_eq!(max65.limbs[1], 1, "U65::MAX limb[1] should be 1 (bit 64 only)");
2454    }
2455
2456    #[test]
2457    fn mul_mod_associativity_and_identity() {
2458        // (a * b) * c == a * (b * c) mod p
2459        let a = P256_GX;
2460        let b = P256_GY;
2461        let c = P256_MODULUS - U256::ONE;
2462        let m = P256_MODULUS;
2463
2464        let ab = a.mul_mod(&b, &m);
2465        let bc = b.mul_mod(&c, &m);
2466
2467        assert_eq!(ab.mul_mod(&c, &m), a.mul_mod(&bc, &m), "associativity");
2468
2469        // Identity: a * 1 = a
2470        assert_eq!(a.mul_mod(&U256::ONE, &m), a, "a * 1 = a");
2471        assert_eq!(U256::ONE.mul_mod(&a, &m), a, "1 * a = a");
2472
2473        // Zero: a * 0 = 0
2474        assert_eq!(a.mul_mod(&U256::ZERO, &m), U256::ZERO, "a * 0 = 0");
2475        assert_eq!(U256::ZERO.mul_mod(&a, &m), U256::ZERO, "0 * a = 0");
2476
2477        // Distributivity: (a + b) * c == a*c + b*c mod p
2478        let ab_sum = a.add_mod(&b, &m);
2479        let lhs = ab_sum.mul_mod(&c, &m);
2480        let rhs = a.mul_mod(&c, &m).add_mod(&b.mul_mod(&c, &m), &m);
2481        assert_eq!(lhs, rhs, "distributivity");
2482    }
2483
2484    #[test]
2485    fn mul_mod_barrett_agrees_with_mul_mod() {
2486        // Already tested in ed25519; verify single multiplication works
2487        type U256 = Uint<256, 4>;
2488        let a = U256::from_u64(7);
2489        let b = U256::from_u64(11);
2490        let m = U256::from_limbs([
2491            0xffff_ffff_ffff_ffff,
2492            0x0000_0000_ffff_ffff,
2493            0x0000_0000_0000_0000,
2494            0xffff_ffff_0000_0001,
2495        ]);
2496        let mu = m.compute_mu_for_barrett();
2497        let barrett = a.mul_mod_barrett(&b, &m, &mu);
2498        let standard = a.mul_mod(&b, &m);
2499        assert_eq!(barrett, standard);
2500    }
2501
2502    #[test]
2503    fn modpow_barrett_agrees_with_modpow() {
2504        type U256 = Uint<256, 4>;
2505        // Use P-256 prime so eff_limbs == LIMBS (4 == 4) → takes Barrett path
2506        let m = U256::from_limbs([
2507            0xffff_ffff_ffff_ffff,
2508            0x0000_0000_ffff_ffff,
2509            0x0000_0000_0000_0000,
2510            0xffff_ffff_0000_0001,
2511        ]);
2512        let mu = m.compute_mu_for_barrett();
2513
2514        // 3^5 mod m
2515        let base = U256::from_u64(3);
2516        let exp = U256::from_u64(5);
2517        let barrett = base.modpow_barrett(&exp, &m, &mu);
2518        let standard = base.modpow(&exp, &m);
2519        assert_eq!(barrett, standard, "3^5 mod P256");
2520
2521        // 2^10 mod m
2522        let base = U256::from_u64(2);
2523        let exp = U256::from_u64(10);
2524        let barrett = base.modpow_barrett(&exp, &m, &mu);
2525        let standard = base.modpow(&exp, &m);
2526        assert_eq!(barrett, standard, "2^10 mod P256");
2527
2528        // 123 ^ 456 mod m
2529        let base = U256::from_u64(123);
2530        let exp = U256::from_u64(456);
2531        let barrett = base.modpow_barrett(&exp, &m, &mu);
2532        let standard = base.modpow(&exp, &m);
2533        assert_eq!(barrett, standard, "123^456 mod P256");
2534
2535        // base == m (should give 0)
2536        let base = m;
2537        let exp = U256::from_u64(5);
2538        let barrett = base.modpow_barrett(&exp, &m, &mu);
2539        let standard = base.modpow(&exp, &m);
2540        assert_eq!(barrett, U256::ZERO, "m^5 mod m should be 0");
2541        assert_eq!(barrett, standard);
2542
2543        // exp == 0 (should give 1)
2544        let base = U256::from_u64(123);
2545        let exp = U256::from_u64(0);
2546        let barrett = base.modpow_barrett(&exp, &m, &mu);
2547        let standard = base.modpow(&exp, &m);
2548        assert_eq!(barrett, standard, "123^0 mod P256");
2549        assert_eq!(barrett, U256::ONE, "123^0 mod P256 should be 1");
2550    }
2551
2552    #[test]
2553    fn barrett_reduction_comprehensive() {
2554        type U256 = Uint<256, 4>;
2555        let m = U256::from_limbs([
2556            0xffff_ffff_ffff_ffff,
2557            0x0000_0000_ffff_ffff,
2558            0x0000_0000_0000_0000,
2559            0xffff_ffff_0000_0001,
2560        ]);
2561        let mu = m.compute_mu_for_barrett();
2562
2563        // mul_mod_barrett should match mul_mod for various inputs
2564        for i in 0..100 {
2565            let a = U256::from_limbs([
2566                (i * 1234567 + 1) as u64,
2567                (i * 7654321 + 2) as u64,
2568                (i * 1357924 + 3) as u64,
2569                (i * 2468013 + 4) as u64,
2570            ]);
2571            let b = U256::from_limbs([
2572                (i * 9876543 + 5) as u64,
2573                (i * 3456789 + 6) as u64,
2574                (i * 567899 + 7) as u64,
2575                (i * 1122334 + 8) as u64,
2576            ]);
2577            let expected = a.mul_mod(&b, &m);
2578            let barrett = a.mul_mod_barrett(&b, &m, &mu);
2579            assert_eq!(barrett, expected, "mul_mod_barrett vs mul_mod iteration {i}");
2580        }
2581
2582        // Edge case: (m-1)^2 mod m should be 1
2583        let (am1, _) = m.sub_word(1);
2584        let barrett = am1.mul_mod_barrett(&am1, &m, &mu);
2585        let expected = am1.mul_mod(&am1, &m);
2586        assert_eq!(barrett, expected, "(m-1)^2 mod m");
2587    }
2588
2589    #[test]
2590    fn barrett_modpow_step_trace() {
2591        type U256 = Uint<256, 4>;
2592        let m = U256::from_limbs([
2593            0xffff_ffff_ffff_ffff,
2594            0x0000_0000_ffff_ffff,
2595            0x0000_0000_0000_0000,
2596            0xffff_ffff_0000_0001,
2597        ]);
2598        let mu = m.compute_mu_for_barrett();
2599
2600        // Trace through 123^4 step by step
2601        let a = U256::from_u64(123);
2602
2603        // Step 1: base = 123 * 1 mod m = 123
2604        let base1 = a.mul_mod_barrett(&U256::ONE, &m, &mu);
2605        assert_eq!(base1, U256::from_u64(123), "step1: self*1 mod m");
2606
2607        // Step 2: result = 1, base = 123
2608        // Iterate with exp=4 (100b), LSB first:
2609        // i=0: bit=0 → result unchanged, base = 123*123 mod m
2610        let a2 = base1.mul_mod_barrett(&base1, &m, &mu);
2611        let a2_expected = a.mul_mod(&a, &m);
2612        assert_eq!(a2, a2_expected, "123*123 mod m");
2613
2614        // i=1: bit=0 → result unchanged, base = a2*a2 mod m
2615        let a4 = a2.mul_mod_barrett(&a2, &m, &mu);
2616        let a4_expected = a2.mul_mod(&a2, &m);
2617        assert_eq!(a4, a4_expected, "123^2*123^2 mod m");
2618
2619        // i=2: bit=1 → result = 1 * base = a4, base = a4*a4 mod m
2620        let a8 = a4.mul_mod_barrett(&a4, &m, &mu);
2621        let result_bit2 = a4.mul_mod_barrett(&U256::ONE, &m, &mu);
2622        assert_eq!(result_bit2, a4, "result after bit 2");
2623        let a8_expected = a4.mul_mod(&a4, &m);
2624        assert_eq!(a8, a8_expected, "123^4*123^4 mod m");
2625
2626        // final result should be a4 (since 4=100b, only bit 2 set)
2627        let final_barrett = a.modpow_barrett(&U256::from_u64(4), &m, &mu);
2628        let final_expected = a.modpow(&U256::from_u64(4), &m);
2629        assert_eq!(final_barrett, final_expected, "123^4 mod m via modpow_barrett");
2630    }
2631}