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