Skip to main content

big_number/
big_number.rs

1//! Fixed-size unsigned and signed big integers with `u64` limbs.
2//!
3//! The central type is [`Uint<BITS, LIMBS>`], a `LIMBS * 64`-bit stack value
4//! used by the [`crypto`](https://github.com/rust-stdx/stdx) crate as the
5//! backing type for RSA, the NIST prime curves and Curve25519 arithmetic. The
6//! crate is `no_std`-compatible; heap-allocating helpers (`to_be_bytes`,
7//! `to_string_radix`, `Display`) require the `alloc` feature.
8//!
9//! # Representation
10//!
11//! `LIMBS` must equal `ceil(BITS / 64)` (enforced by a compile-time check).
12//! Values are stored little-endian, base `2^64`. When `BITS` is not a multiple
13//! of 64 the top limb may hold up to `BITS % 64` significant bits; the byte
14//! conversion helpers ([`Uint::from_be_slice`] and friends) and
15//! [`Uint::from_str_radix`] reject or mask anything above `BITS`.
16//!
17//! Arithmetic operators (`+`, `-`, `*`) are **wrapping**: carry/borrow past
18//! `LIMBS` limbs is silently discarded, matching primitive integer semantics.
19//! Use the explicit `*_raw`, `mul_word` and `div_rem_word` methods when the
20//! carry/borrow matters.
21//!
22//! # Constant time
23//!
24//! `add_mod`, `sub_mod`, `double_mod`, `mul_mod`, `mul_mod_barrett`,
25//! `ct_select`, `ct_eq` and `ct_ge` branch only on public bounds, not on limb
26//! values. In contrast [`Uint::modpow`] and [`Uint::modpow_barrett`] iterate
27//! over the exponent bits with a data-dependent branch and are therefore only
28//! suitable for a *public* exponent (e.g. the RSA public exponent `e`).
29//!
30//! # Errors, panics and limits
31//!
32//! - [`Uint::from_str_radix`] returns [`Error`] for invalid input; it never
33//!   panics and does not allocate.
34//! - The byte conversion helpers and the modular methods assert their
35//!   documented length/limb preconditions (see each method).
36//! - No method allocates unless it returns a `Vec`/`String`.
37
38#![cfg_attr(not(feature = "std"), no_std)]
39
40#[cfg(feature = "alloc")]
41extern crate alloc;
42
43#[cfg(feature = "alloc")]
44use alloc::{string::String, vec::Vec};
45use core::{
46    fmt,
47    ops::{Add, Div, Mul, Neg, Rem, Sub},
48};
49
50// Largest number of limbs a `Uint` may use is `MAX_LIMBS / 2` (the wide
51// product of two values must fit). Barrett reduction additionally needs one
52// limb of headroom on the `q1 * mu` intermediate, so `MAX_LIMBS` must be at
53// least `2 * (eff_limbs + 1)`. 260 limbs supports a 130-limb (8320-bit) wide
54// product and up to a 129-limb (8256-bit) modulus with Barrett reduction.
55pub const MAX_LIMBS: usize = 260;
56
57/// Largest effective limb count accepted by Barrett reduction, i.e. the
58/// largest `eff_limbs` for which `2 * (eff_limbs + 1) <= MAX_LIMBS`.
59pub const MAX_BARRETT_LIMBS: usize = MAX_LIMBS / 2 - 1;
60
61const fn max_limbs<const BITS: usize, const LIMBS: usize>() -> [u64; LIMBS] {
62    let mut limbs = [u64::MAX; LIMBS];
63    let rem = BITS % 64;
64    if rem != 0 {
65        limbs[LIMBS - 1] = (1u64 << rem) - 1;
66    }
67    limbs
68}
69
70/// A fixed-size unsigned integer of `BITS` bits stored in `LIMBS` 64-bit limbs.
71///
72/// `LIMBS` must be `ceil(BITS / 64)` (checked at compile time). Values are
73/// little-endian. When `BITS` is not a multiple of 64 the caller must keep the
74/// unused high bits of the top limb zero; the decoding helpers do this
75/// automatically but [`Uint::from_limbs`] does not.
76#[derive(Clone, Copy, PartialEq, Eq)]
77#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
78pub struct Uint<const BITS: usize, const LIMBS: usize> {
79    pub limbs: [u64; LIMBS],
80}
81
82/// A fixed-size two's-complement signed integer of `BITS` bits.
83///
84/// The sign bit is bit `BITS - 1`. Arithmetic wraps around the `BITS`-bit
85/// range. Note that when `BITS` is not a multiple of 64 the unused high bits
86/// of the top limb are significant to the representation; keep them
87/// sign-extended for well-formed values.
88#[derive(Clone, Copy, Debug, PartialEq, Eq)]
89pub struct Int<const BITS: usize, const LIMBS: usize>(Uint<BITS, LIMBS>);
90
91/// Errors returned by [`Uint::from_str_radix`].
92#[derive(Clone, Copy, Debug, PartialEq, Eq)]
93pub enum Error {
94    /// The radix was outside `2..=36`.
95    InvalidRadix,
96    /// A character was not an ASCII digit valid for the radix.
97    InvalidDigit,
98    /// The input string was empty.
99    EmptyString,
100    /// The value does not fit in `BITS` bits.
101    Overflow,
102}
103
104#[inline]
105pub const fn adc(a: u64, b: u64, carry: u64) -> (u64, u64) {
106    let sum = (a as u128) + (b as u128) + (carry as u128);
107    (sum as u64, (sum >> 64) as u64)
108}
109
110#[inline]
111pub const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) {
112    let diff = (1u128 << 64) + (a as u128) - (b as u128) - (borrow as u128);
113    (diff as u64, 1u64.wrapping_sub((diff >> 64) as u64))
114}
115
116#[inline]
117pub const fn mac(acc: u64, a: u64, b: u64, carry: u64) -> (u64, u64) {
118    let value = (acc as u128) + (a as u128) * (b as u128) + (carry as u128);
119    (value as u64, (value >> 64) as u64)
120}
121
122/// Schoolbook multiply-accumulate of `a[..a_len]` and `b[..b_len]` into `out`.
123///
124/// `out` must be at least `a_len + b_len` limbs and zero-initialised for the
125/// range `0..a_len + b_len` unless it deliberately carries an accumulator. The
126/// carry propagated past `i + b_len` cannot exceed `out.len()` for a product
127/// that fits; the loop is bounded defensively.
128fn mul_limbs(out: &mut [u64], a: &[u64], a_len: usize, b: &[u64], b_len: usize) {
129    for i in 0..a_len {
130        let mut carry = 0u64;
131        for j in 0..b_len {
132            let (word, next_carry) = mac(out[i + j], a[i], b[j], carry);
133            out[i + j] = word;
134            carry = next_carry;
135        }
136        let mut k = i + b_len;
137        while carry != 0 && k < out.len() {
138            let (word, next_carry) = adc(out[k], 0, carry);
139            out[k] = word;
140            carry = next_carry;
141            k += 1;
142        }
143    }
144}
145
146#[inline]
147const fn ct_select_u64(a: u64, b: u64, choice: bool) -> u64 {
148    let mask = 0u64.wrapping_sub(choice as u64);
149    b ^ ((a ^ b) & mask)
150}
151
152#[cfg(feature = "alloc")]
153#[inline]
154const fn digit_to_char(digit: u64, upper: bool) -> char {
155    match digit {
156        0..=9 => (b'0' + digit as u8) as char,
157        _ if upper => (b'A' + (digit as u8 - 10)) as char,
158        _ => (b'a' + (digit as u8 - 10)) as char,
159    }
160}
161
162#[inline]
163fn char_to_digit(byte: u8) -> Option<u32> {
164    match byte {
165        b'0'..=b'9' => Some((byte - b'0') as u32),
166        b'a'..=b'z' => Some((byte - b'a' + 10) as u32),
167        b'A'..=b'Z' => Some((byte - b'A' + 10) as u32),
168        _ => None,
169    }
170}
171
172const fn uint_from_u128<const BITS: usize, const LIMBS: usize>(value: u128) -> Uint<BITS, LIMBS> {
173    let mut limbs = [0u64; LIMBS];
174    if LIMBS > 0 {
175        limbs[0] = value as u64;
176    }
177    if LIMBS > 1 {
178        limbs[1] = (value >> 64) as u64;
179    }
180    Uint {
181        limbs,
182    }
183}
184
185fn u128_to_word(value: u128) -> u64 {
186    u64::try_from(value).expect("primitive operand exceeds u64")
187}
188
189fn i128_abs_to_word(value: i128) -> (u64, bool) {
190    (u128_to_word(value.unsigned_abs()), value.is_negative())
191}
192
193/// Clears a limb buffer. With the `zeroize` feature this uses volatile writes
194/// that cannot be optimised away; otherwise it is a no-op.
195#[inline]
196fn zeroize_limbs(limbs: &mut [u64]) {
197    #[cfg(feature = "zeroize")]
198    zeroize::Zeroize::zeroize(limbs);
199    #[cfg(not(feature = "zeroize"))]
200    let _ = limbs;
201}
202
203impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
204    const _LIMBS_CHECK: () = assert!(LIMBS == BITS.div_ceil(64), "LIMBS must equal ceil(BITS/64)");
205
206    pub const ZERO: Self = Self {
207        limbs: [0u64; LIMBS],
208    };
209    pub const ONE: Self = Self::from_u64(1);
210    pub const MAX: Self = Self {
211        limbs: max_limbs::<BITS, LIMBS>(),
212    };
213
214    /// Builds a value directly from its little-endian limbs.
215    ///
216    /// This is a low-level escape hatch: when `BITS` is not a multiple of 64
217    /// the caller is responsible for ensuring the unused high bits of the top
218    /// limb are zero. The decoding helpers ([`Self::from_be_slice`],
219    /// [`Self::from_le_slice`], [`Self::from_str_radix`]) enforce this for you.
220    #[inline]
221    pub const fn from_limbs(limbs: [u64; LIMBS]) -> Self {
222        Self {
223            limbs,
224        }
225    }
226
227    /// Builds a value from a `u64`.
228    #[inline]
229    pub const fn from_u64(v: u64) -> Self {
230        let mut limbs = [0u64; LIMBS];
231        if LIMBS > 0 {
232            limbs[0] = v;
233        }
234        Self {
235            limbs,
236        }
237    }
238
239    /// Clears any bits at or above `BITS` in the top limb.
240    #[inline]
241    const fn truncate_to_bits(mut self) -> Self {
242        let rem = BITS % 64;
243        if rem != 0 {
244            self.limbs[LIMBS - 1] &= (1u64 << rem) - 1;
245        }
246        self
247    }
248
249    /// Decodes `LIMBS * 8` big-endian bytes.
250    ///
251    /// The expected byte length is the limb-aligned width `ceil(BITS / 64) * 8`
252    /// bytes, which equals `BITS / 8` whenever `BITS` is a multiple of 64. Any
253    /// bits at or above `BITS` are cleared.
254    ///
255    /// # Panics
256    ///
257    /// Panics if `bytes.len() != LIMBS * 8`.
258    #[inline]
259    pub fn from_be_slice(bytes: &[u8]) -> Self {
260        assert_eq!(bytes.len(), LIMBS * 8, "expected LIMBS * 8 big-endian bytes");
261        let mut limbs = [0u64; LIMBS];
262        let mut i = 0;
263        while i < LIMBS {
264            let start = (LIMBS - 1 - i) * 8;
265            let mut limb = [0u8; 8];
266            limb.copy_from_slice(&bytes[start..start + 8]);
267            limbs[i] = u64::from_be_bytes(limb);
268            i += 1;
269        }
270        Self {
271            limbs,
272        }
273        .truncate_to_bits()
274    }
275
276    /// Decodes `LIMBS * 8` little-endian bytes.
277    ///
278    /// The expected byte length is the limb-aligned width `ceil(BITS / 64) * 8`
279    /// bytes, which equals `BITS / 8` whenever `BITS` is a multiple of 64. Any
280    /// bits at or above `BITS` are cleared.
281    ///
282    /// # Panics
283    ///
284    /// Panics if `bytes.len() != LIMBS * 8`.
285    #[inline]
286    pub fn from_le_slice(bytes: &[u8]) -> Self {
287        assert_eq!(bytes.len(), LIMBS * 8, "expected LIMBS * 8 little-endian bytes");
288        let mut limbs = [0u64; LIMBS];
289        let mut i = 0;
290        while i < LIMBS {
291            let start = i * 8;
292            let mut limb = [0u8; 8];
293            limb.copy_from_slice(&bytes[start..start + 8]);
294            limbs[i] = u64::from_le_bytes(limb);
295            i += 1;
296        }
297        Self {
298            limbs,
299        }
300        .truncate_to_bits()
301    }
302
303    /// Encodes the value as `LIMBS * 8` big-endian bytes.
304    ///
305    /// Allocates a `Vec`. Prefer [`Self::to_be_bytes_fixed`] in allocation-free
306    /// contexts.
307    #[cfg(feature = "alloc")]
308    #[inline]
309    pub fn to_be_bytes(&self) -> Vec<u8> {
310        let mut out = Vec::with_capacity(LIMBS * 8);
311        let mut i = LIMBS;
312        while i > 0 {
313            i -= 1;
314            out.extend_from_slice(&self.limbs[i].to_be_bytes());
315        }
316        out
317    }
318
319    /// Encodes the value as `LIMBS * 8` little-endian bytes.
320    ///
321    /// Allocates a `Vec`. Prefer [`Self::to_le_bytes_fixed`] in allocation-free
322    /// contexts.
323    #[cfg(feature = "alloc")]
324    #[inline]
325    pub fn to_le_bytes(&self) -> Vec<u8> {
326        let mut out = Vec::with_capacity(LIMBS * 8);
327        let mut i = 0;
328        while i < LIMBS {
329            out.extend_from_slice(&self.limbs[i].to_le_bytes());
330            i += 1;
331        }
332        out
333    }
334
335    /// Encodes the value as `N` big-endian bytes.
336    ///
337    /// # Panics
338    ///
339    /// Panics if `N != LIMBS * 8`.
340    #[inline]
341    pub fn to_be_bytes_fixed<const N: usize>(&self) -> [u8; N] {
342        assert_eq!(N, LIMBS * 8, "expected an array of LIMBS * 8 big-endian bytes");
343        let mut out = [0u8; N];
344        let mut i = 0;
345        while i < LIMBS {
346            let start = N - ((i + 1) * 8);
347            out[start..start + 8].copy_from_slice(&self.limbs[i].to_be_bytes());
348            i += 1;
349        }
350        out
351    }
352
353    /// Encodes the value as `N` little-endian bytes.
354    ///
355    /// # Panics
356    ///
357    /// Panics if `N != LIMBS * 8`.
358    #[inline]
359    pub fn to_le_bytes_fixed<const N: usize>(&self) -> [u8; N] {
360        assert_eq!(N, LIMBS * 8, "expected an array of LIMBS * 8 little-endian bytes");
361        let mut out = [0u8; N];
362        let mut i = 0;
363        while i < LIMBS {
364            let start = i * 8;
365            out[start..start + 8].copy_from_slice(&self.limbs[i].to_le_bytes());
366            i += 1;
367        }
368        out
369    }
370
371    /// Returns bit `index` (0 is the least significant).
372    ///
373    /// Returns `false` for any `index >= BITS`.
374    #[inline]
375    pub fn bit(&self, index: usize) -> bool {
376        if index >= BITS {
377            return false;
378        }
379        ((self.limbs[index / 64] >> (index % 64)) & 1) == 1
380    }
381
382    /// Returns `true` when the value is zero.
383    #[inline]
384    pub fn is_zero(&self) -> bool {
385        let mut acc = 0u64;
386        let mut i = 0;
387        while i < LIMBS {
388            acc |= self.limbs[i];
389            i += 1;
390        }
391        acc == 0
392    }
393
394    /// Position of the highest set bit, plus one. Returns 0 for zero.
395    pub fn bit_len(&self) -> usize {
396        let mut i = LIMBS;
397        while i > 0 {
398            i -= 1;
399            if self.limbs[i] != 0 {
400                return i * 64 + 64 - self.limbs[i].leading_zeros() as usize;
401            }
402        }
403        0
404    }
405
406    /// Returns `true` when the value is odd.
407    #[inline]
408    pub fn is_odd(&self) -> bool {
409        (self.limbs[0] & 1) == 1
410    }
411
412    /// Constant-time `self >= rhs`.
413    ///
414    /// The execution path does not depend on the operand values.
415    #[inline]
416    pub fn ct_ge(&self, rhs: &Self) -> bool {
417        let (_, borrow) = self.sub_raw(rhs);
418        borrow == 0
419    }
420
421    /// Constant-time `self == rhs`.
422    #[inline]
423    pub fn ct_eq(&self, rhs: &Self) -> bool {
424        let mut diff = 0u64;
425        let mut i = 0;
426        while i < LIMBS {
427            diff |= self.limbs[i] ^ rhs.limbs[i];
428            i += 1;
429        }
430        diff == 0
431    }
432
433    /// Constant-time select: returns `*a` if `choice` is `true`, else `*b`.
434    #[inline]
435    pub fn ct_select(a: &Self, b: &Self, choice: bool) -> Self {
436        let mut limbs = [0u64; LIMBS];
437        let mut i = 0;
438        while i < LIMBS {
439            limbs[i] = ct_select_u64(a.limbs[i], b.limbs[i], choice);
440            i += 1;
441        }
442        Self {
443            limbs,
444        }
445    }
446
447    /// Adds with carry, returning the wrapped sum and the carry out (`0` or `1`).
448    #[inline]
449    pub fn add_raw(&self, rhs: &Self) -> (Self, u64) {
450        let mut out = [0u64; LIMBS];
451        let mut carry = 0u64;
452        let mut i = 0;
453        while i < LIMBS {
454            let (word, next_carry) = adc(self.limbs[i], rhs.limbs[i], carry);
455            out[i] = word;
456            carry = next_carry;
457            i += 1;
458        }
459        (
460            Self {
461                limbs: out,
462            },
463            carry,
464        )
465    }
466
467    /// Subtracts with borrow, returning the wrapped difference and the borrow
468    /// out (`0` or `1`).
469    #[inline]
470    pub fn sub_raw(&self, rhs: &Self) -> (Self, u64) {
471        let mut out = [0u64; LIMBS];
472        let mut borrow = 0u64;
473        let mut i = 0;
474        while i < LIMBS {
475            let (word, next_borrow) = sbb(self.limbs[i], rhs.limbs[i], borrow);
476            out[i] = word;
477            borrow = next_borrow;
478            i += 1;
479        }
480        (
481            Self {
482                limbs: out,
483            },
484            borrow,
485        )
486    }
487
488    /// `(self + rhs) mod modulus`, constant time.
489    ///
490    /// Requires `self < modulus` and `rhs < modulus`, and `modulus > 0`.
491    #[inline]
492    pub fn add_mod(&self, rhs: &Self, modulus: &Self) -> Self {
493        let (sum, carry) = self.add_raw(rhs);
494        let (reduced, borrow) = sum.sub_raw(modulus);
495        // Use bitwise OR to avoid short-circuit branching on secret carry/borrow bits.
496        // Reduce when carry==1 (overflow) OR borrow==0 (sum >= modulus).
497        Self::ct_select(&reduced, &sum, (carry | (borrow ^ 1)) != 0)
498    }
499
500    /// `(self - rhs) mod modulus`, constant time.
501    ///
502    /// Requires `self < modulus`, `rhs < modulus`, and `modulus > 0`. For
503    /// `self < rhs` the result wraps to `modulus - (rhs - self)`.
504    #[inline]
505    pub fn sub_mod(&self, rhs: &Self, modulus: &Self) -> Self {
506        let (diff, borrow) = self.sub_raw(rhs);
507        let (corrected, _) = diff.add_raw(modulus);
508        Self::ct_select(&corrected, &diff, borrow == 1)
509    }
510
511    /// `(self + self) mod modulus`, constant time.
512    ///
513    /// Requires `self < modulus` and `modulus > 0`.
514    #[inline]
515    pub fn double_mod(&self, modulus: &Self) -> Self {
516        self.add_mod(self, modulus)
517    }
518
519    fn mul_wide_internal(&self, rhs: &Self) -> [u64; MAX_LIMBS] {
520        assert!(LIMBS * 2 <= MAX_LIMBS);
521        let mut out = [0u64; MAX_LIMBS];
522        let mut i = 0;
523        while i < LIMBS {
524            let mut carry = 0u64;
525            let mut j = 0;
526            while j < LIMBS {
527                let (word, next_carry) = mac(out[i + j], self.limbs[i], rhs.limbs[j], carry);
528                out[i + j] = word;
529                carry = next_carry;
530                j += 1;
531            }
532            let mut k = i + LIMBS;
533            while carry != 0 && k < MAX_LIMBS {
534                let (word, next_carry) = adc(out[k], 0, carry);
535                out[k] = word;
536                carry = next_carry;
537                k += 1;
538            }
539            i += 1;
540        }
541        out
542    }
543
544    fn reduce_wide_internal(product: &[u64; MAX_LIMBS], modulus: &Self) -> Self {
545        let total_bits = LIMBS * 128;
546        let mut rem = Self::ZERO;
547        let mut bit_index = total_bits;
548        while bit_index > 0 {
549            bit_index -= 1;
550            let limb_idx = bit_index / 64;
551            let bit_pos = bit_index % 64;
552            let bit = ((product[limb_idx] >> bit_pos) & 1) as u64;
553
554            let mut shifted = [0u64; LIMBS];
555            let mut carry = bit;
556            let mut i = 0;
557            while i < LIMBS {
558                let next = rem.limbs[i] >> 63;
559                shifted[i] = (rem.limbs[i] << 1) | carry;
560                carry = next;
561                i += 1;
562            }
563            let shifted_rem = Self {
564                limbs: shifted,
565            };
566            let (reduced, borrow) = shifted_rem.sub_raw(modulus);
567            // Use bitwise OR to avoid short-circuit branching on secret carry/borrow bits.
568            rem = Self::ct_select(&reduced, &shifted_rem, (carry | (borrow ^ 1)) != 0);
569        }
570        rem
571    }
572
573    /// `(self * rhs) mod modulus` using a bit-serial (shift-and-subtract)
574    /// reduction.
575    ///
576    /// Constant time in the operands. Requires `modulus > 0` and that the wide
577    /// product fits in `2 * LIMBS` limbs (always true). This is the reference
578    /// implementation; prefer [`Self::mul_mod_barrett`] in hot loops.
579    #[inline]
580    pub fn mul_mod(&self, rhs: &Self, modulus: &Self) -> Self {
581        let mut product = self.mul_wide_internal(rhs);
582        let result = Self::reduce_wide_internal(&product, modulus);
583        zeroize_limbs(&mut product[..]);
584        result
585    }
586
587    /// Schoolbook product of the low `eff_limbs` limbs of each operand into a
588    /// `W`-limb buffer.
589    ///
590    /// Exact when both operands are below `2^(eff_limbs * 64)`; `W` must be at
591    /// least `2 * eff_limbs`. Using the effective width instead of the full
592    /// `LIMBS` is what makes modular operations on small values in a wide type
593    /// (for example RSA moduli in `Uint<8192, 128>`) fast.
594    fn mul_wide_eff<const W: usize>(&self, rhs: &Self, eff_limbs: usize) -> [u64; W] {
595        assert!(2 * eff_limbs <= W, "working width W is too small");
596        let mut out = [0u64; W];
597        mul_limbs(&mut out, &self.limbs, eff_limbs, &rhs.limbs, eff_limbs);
598        out
599    }
600
601    /// Computes `mu = floor(2^(2 * eff_limbs * 64) / self)` for Barrett
602    /// reduction, where `eff_limbs` is `ceil(self.bit_len() / 64)`.
603    ///
604    /// Pass the result to [`Self::modpow_barrett`] or
605    /// [`Self::mul_mod_barrett_eff`]. The value is produced for the modulus's
606    /// own effective limb count, which is what those functions use.
607    ///
608    /// # Panics
609    ///
610    /// Panics when `self` is zero (the reciprocal is undefined).
611    pub fn compute_mu_for_barrett(&self) -> [u64; MAX_LIMBS] {
612        let eff_limbs = self.bit_len().div_ceil(64);
613        self.compute_mu_for_barrett_eff(eff_limbs)
614    }
615
616    fn compute_mu_for_barrett_eff(&self, eff_limbs: usize) -> [u64; MAX_LIMBS] {
617        const {
618            assert!(LIMBS + 1 <= MAX_LIMBS);
619        }
620        assert!(eff_limbs >= 1 && eff_limbs <= LIMBS, "modulus must be nonzero");
621
622        let total_bits = eff_limbs * 128;
623        let mut mu = [0u64; MAX_LIMBS];
624        let mut rem = Self::ZERO;
625
626        for bit_pos in (0..=total_bits).rev() {
627            let mut shifted_limbs = [0u64; LIMBS];
628            let mut carry = 0u64;
629            for i in 0..LIMBS {
630                let next = rem.limbs[i] >> 63;
631                shifted_limbs[i] = (rem.limbs[i] << 1) | carry;
632                carry = next;
633            }
634
635            let bit = if bit_pos == total_bits { 1u64 } else { 0u64 };
636            let mut with = shifted_limbs;
637            with[0] |= bit;
638
639            let shifted = Self {
640                limbs: with,
641            };
642            let (reduced, borrow) = shifted.sub_raw(self);
643            // Use the same overflow-aware selection as reduce_wide_internal:
644            // carry == 1 → true value >= 2^(LIMBS*64) >= divisor → always subtract.
645            rem = Self::ct_select(&reduced, &shifted, (carry | (borrow ^ 1)) != 0);
646            // When we subtracted, the quotient bit is 1.
647            if carry | (borrow ^ 1) != 0 {
648                let qi = bit_pos / 64;
649                let qbit = bit_pos % 64;
650                if qi < eff_limbs + 1 {
651                    mu[qi] |= 1 << qbit;
652                }
653            }
654        }
655
656        mu
657    }
658
659    /// `self^exp mod modulus` using Barrett reduction.
660    ///
661    /// `mu` must be produced by [`Self::compute_mu_for_barrett`] for the same
662    /// `modulus`; the effective limb count is derived from `modulus.bit_len()`.
663    /// The base is reduced internally, so any input is accepted.
664    ///
665    /// Not constant time in `exp` (it branches on each exponent bit); only use
666    /// it with a public exponent.
667    ///
668    /// # Panics
669    ///
670    /// Panics when `modulus` is zero or its effective limb count exceeds
671    /// [`MAX_BARRETT_LIMBS`].
672    pub fn modpow_barrett(&self, exp: &Self, modulus: &Self, mu: &[u64]) -> Self {
673        self.modpow_barrett_w::<MAX_LIMBS>(exp, modulus, mu)
674    }
675
676    /// Barrett modular exponentiation with an explicit effective limb count.
677    ///
678    /// `eff_limbs` must equal `ceil(modulus.bit_len() / 64)` and `mu` must be
679    /// the matching reciprocal. See [`Self::modpow_barrett`] for the other
680    /// requirements.
681    pub fn modpow_barrett_eff(&self, exp: &Self, modulus: &Self, mu: &[u64], eff_limbs: usize) -> Self {
682        self.modpow_barrett_impl::<MAX_LIMBS>(exp, modulus, mu, eff_limbs)
683    }
684
685    /// Barrett modular exponentiation with a caller-chosen working width `W`.
686    ///
687    /// `W` must be at least `2 * (eff_limbs + 1)`, where `eff_limbs` is the
688    /// modulus's effective limb count. A `W` near that lower bound keeps the
689    /// scratch buffers small and is significantly faster than the default
690    /// [`Self::modpow_barrett`] (which uses `W = MAX_LIMBS`). Callers should
691    /// pick `W` from the modulus size; see the RSA public-key code.
692    pub fn modpow_barrett_w<const W: usize>(&self, exp: &Self, modulus: &Self, mu: &[u64]) -> Self {
693        let eff_limbs = modulus.bit_len().div_ceil(64);
694        self.modpow_barrett_impl::<W>(exp, modulus, mu, eff_limbs)
695    }
696
697    fn modpow_barrett_impl<const W: usize>(&self, exp: &Self, modulus: &Self, mu: &[u64], eff_limbs: usize) -> Self {
698        assert!(eff_limbs >= 1 && eff_limbs <= MAX_BARRETT_LIMBS, "eff_limbs out of range");
699        assert!(2 * (eff_limbs + 1) <= W, "working width W is too small for the modulus");
700        let mut base = self.mul_mod_barrett_impl::<W>(&Self::ONE, modulus, mu, eff_limbs);
701        let mut result = Self::ONE;
702        let bits = exp.bit_len();
703        let mut i = 0;
704        while i < bits {
705            if exp.bit(i) {
706                result = result.mul_mod_barrett_impl::<W>(&base, modulus, mu, eff_limbs);
707            }
708            i += 1;
709            // The square after the most significant bit is never consumed.
710            if i < bits {
711                base = base.mul_mod_barrett_impl::<W>(&base, modulus, mu, eff_limbs);
712            }
713        }
714        zeroize_limbs(&mut base.limbs);
715        result
716    }
717
718    /// `(self * rhs) mod modulus` using Barrett reduction.
719    ///
720    /// `mu` must be produced by [`Self::compute_mu_for_barrett`] for the same
721    /// `modulus`. Both operands must already be reduced (`< 2^(eff*64)`, in
722    /// practice `< modulus`); passing unreduced operands yields silently wrong
723    /// results. The effective limb count is derived from `modulus.bit_len()`.
724    ///
725    /// # Panics
726    ///
727    /// Panics under the same conditions as [`Self::reduce_wide_barrett_eff`].
728    pub fn mul_mod_barrett(&self, rhs: &Self, modulus: &Self, mu: &[u64]) -> Self {
729        self.mul_mod_barrett_w::<MAX_LIMBS>(rhs, modulus, mu)
730    }
731
732    /// Barrett multiplication with an explicit effective limb count.
733    ///
734    /// `eff_limbs` must equal `ceil(modulus.bit_len() / 64)` and both operands
735    /// must already be reduced. See [`Self::mul_mod_barrett`].
736    pub fn mul_mod_barrett_eff(&self, rhs: &Self, modulus: &Self, mu: &[u64], eff_limbs: usize) -> Self {
737        self.mul_mod_barrett_impl::<MAX_LIMBS>(rhs, modulus, mu, eff_limbs)
738    }
739
740    /// Barrett multiplication with a caller-chosen working width `W`.
741    ///
742    /// `W` must be at least `2 * (eff_limbs + 1)` where `eff_limbs` is the
743    /// modulus's effective limb count. Picking `W` near that bound (instead of
744    /// the default `MAX_LIMBS`) makes this much faster; see
745    /// [`Self::modpow_barrett_w`].
746    ///
747    /// The operands must already be reduced below the modulus.
748    pub fn mul_mod_barrett_w<const W: usize>(&self, rhs: &Self, modulus: &Self, mu: &[u64]) -> Self {
749        let eff_limbs = modulus.bit_len().div_ceil(64);
750        self.mul_mod_barrett_impl::<W>(rhs, modulus, mu, eff_limbs)
751    }
752
753    fn mul_mod_barrett_impl<const W: usize>(&self, rhs: &Self, modulus: &Self, mu: &[u64], eff_limbs: usize) -> Self {
754        assert!(eff_limbs >= 1 && eff_limbs <= MAX_BARRETT_LIMBS, "eff_limbs out of range");
755        assert!(2 * (eff_limbs + 1) <= W, "working width W is too small for the modulus");
756        debug_assert!(
757            self.bit_len() <= eff_limbs * 64 && rhs.bit_len() <= eff_limbs * 64,
758            "Barrett operands must be reduced below 2^(eff_limbs * 64)"
759        );
760        let mut product = self.mul_wide_eff::<W>(rhs, eff_limbs);
761        let result = Self::reduce_wide_barrett_eff_impl::<W>(&product, modulus, mu, eff_limbs);
762        zeroize_limbs(&mut product[..]);
763        result
764    }
765
766    /// Barrett reduction of a `2 * LIMBS`-wide product with an explicit
767    /// effective limb count `k = eff_limbs`.
768    ///
769    /// `mu` must equal `floor(2^(2 * k * 64) / modulus)` — that is, the value
770    /// returned by [`Self::compute_mu_for_barrett`] for this modulus — and have
771    /// at least `k + 1` entries. The product must be less than
772    /// `2^(2 * k * 64)`; when `k < LIMBS` this means the factors of the product
773    /// must already be reduced (see [`Self::mul_mod_barrett_eff`]).
774    ///
775    /// # Panics
776    ///
777    /// Panics when `eff_limbs` is out of range, when the effective width does
778    /// not fit in `MAX_LIMBS`, or when `mu` is too short.
779    pub fn reduce_wide_barrett_eff(product: &[u64; MAX_LIMBS], modulus: &Self, mu: &[u64], eff_limbs: usize) -> Self {
780        Self::reduce_wide_barrett_eff_impl::<MAX_LIMBS>(&product[..], modulus, mu, eff_limbs)
781    }
782
783    fn reduce_wide_barrett_eff_impl<const W: usize>(
784        product: &[u64],
785        modulus: &Self,
786        mu: &[u64],
787        eff_limbs: usize,
788    ) -> Self {
789        assert!(eff_limbs >= 1 && eff_limbs <= LIMBS, "eff_limbs out of range");
790        assert!(
791            eff_limbs <= MAX_BARRETT_LIMBS,
792            "Barrett reduction supports at most MAX_BARRETT_LIMBS effective limbs"
793        );
794        assert!(2 * (eff_limbs + 1) <= W, "working width W is too small for the modulus");
795        assert!(product.len() >= 2 * eff_limbs, "product slice is too short");
796        assert!(mu.len() >= eff_limbs + 1, "mu is too short for the effective limb count");
797
798        let k = eff_limbs;
799        let k1 = k + 1;
800        let k_minus_1 = k.saturating_sub(1);
801
802        let mut q1 = [0u64; W];
803        q1[..k1].copy_from_slice(&product[k_minus_1..k_minus_1 + k1]);
804
805        let mut q2 = [0u64; W];
806        mul_limbs(&mut q2, &q1, k1, mu, k1);
807
808        let mut q3 = [0u64; W];
809        q3[..k1].copy_from_slice(&q2[k1..k1 + k1]);
810
811        let mut r1 = [0u64; W];
812        r1[..k1].copy_from_slice(&product[..k1]);
813
814        let mut q3m = [0u64; W];
815        mul_limbs(&mut q3m, &q3[..k1], k1, &modulus.limbs, k);
816        let mut r2 = [0u64; W];
817        r2[..k1].copy_from_slice(&q3m[..k1]);
818
819        let mut r = [0u64; W];
820        let mut borrow = 0u64;
821        let mut i = 0;
822        while i < k1 {
823            let (word, next_borrow) = sbb(r1[i], r2[i], borrow);
824            r[i] = word;
825            borrow = next_borrow;
826            i += 1;
827        }
828
829        // Conditional subtract modulus up to twice, using the full k+1-limb r.
830        // The Barrett remainder r = product - q3 * n can be up to 3n, requiring
831        // k+1 limbs.  Truncating to k limbs before subtracting would lose the
832        // top limb and give incorrect results.
833        for _ in 0..2 {
834            let mut r_try = r;
835            let mut borrow = 0u64;
836            let mut j = 0;
837            while j < k1 {
838                let mod_limb = if j < LIMBS { modulus.limbs[j] } else { 0u64 };
839                let (word, next_borrow) = sbb(r_try[j], mod_limb, borrow);
840                r_try[j] = word;
841                borrow = next_borrow;
842                j += 1;
843            }
844            let choose = borrow == 0;
845            let mut j = 0;
846            while j < k1 {
847                r[j] = ct_select_u64(r_try[j], r[j], choose);
848                j += 1;
849            }
850        }
851
852        let mut limbs = [0u64; LIMBS];
853        limbs[..k].copy_from_slice(&r[..k]);
854        let result = Self {
855            limbs,
856        };
857        zeroize_limbs(&mut q1);
858        zeroize_limbs(&mut q2);
859        zeroize_limbs(&mut q3);
860        zeroize_limbs(&mut r1);
861        zeroize_limbs(&mut q3m);
862        zeroize_limbs(&mut r2);
863        zeroize_limbs(&mut r);
864        result
865    }
866
867    /// `self^exp mod modulus` using square-and-multiply, scanning only up to
868    /// the exponent's bit length.
869    ///
870    /// Uses the bit-serial [`Self::mul_mod`] reduction and is therefore slow;
871    /// prefer [`Self::modpow_barrett`] in hot loops.
872    ///
873    /// Not constant time in `exp` (it branches on each exponent bit); only use
874    /// it with a public exponent.
875    ///
876    /// # Panics
877    ///
878    /// In debug builds `modulus` must be nonzero; in release a zero modulus
879    /// yields an unreduced result.
880    pub fn modpow(&self, exp: &Self, modulus: &Self) -> Self {
881        let mut base = self.mul_mod(&Self::ONE, modulus);
882        let mut result = Self::ONE;
883        let bits = exp.bit_len();
884        let mut i = 0;
885        while i < bits {
886            if exp.bit(i) {
887                result = result.mul_mod(&base, modulus);
888            }
889            i += 1;
890            // The square after the most significant bit is never consumed.
891            if i < bits {
892                base = base.mul_mod(&base, modulus);
893            }
894        }
895        zeroize_limbs(&mut base.limbs);
896        result
897    }
898
899    /// Barrett reduction of a `2 * LIMBS`-wide product modulo `modulus`.
900    ///
901    /// The effective limb count is derived from `modulus.bit_len()`, so `mu`
902    /// must be the matching value from [`Self::compute_mu_for_barrett`]. The
903    /// product must be less than `2^(2 * k * 64)`, where `k` is that effective
904    /// limb count; when the modulus does not fill all `LIMBS` limbs this means
905    /// the product's factors must already be reduced (see
906    /// [`Self::mul_mod_barrett`]).
907    ///
908    /// Equivalent to [`Self::reduce_wide_barrett_eff`] with
909    /// `k = ceil(modulus.bit_len() / 64)`.
910    pub fn reduce_wide_barrett(product: &[u64; MAX_LIMBS], modulus: &Self, mu: &[u64]) -> Self {
911        let eff_limbs = modulus.bit_len().div_ceil(64);
912        Self::reduce_wide_barrett_eff(product, modulus, mu, eff_limbs)
913    }
914
915    /// Adds a single `u64`, returning the wrapped result and carry out.
916    #[inline]
917    pub fn add_word(&self, word: u64) -> (Self, u64) {
918        let mut out = self.limbs;
919        let (first, mut carry) = adc(out[0], word, 0);
920        out[0] = first;
921        let mut i = 1;
922        while i < LIMBS {
923            let (next, next_carry) = adc(out[i], 0, carry);
924            out[i] = next;
925            carry = next_carry;
926            i += 1;
927        }
928        (
929            Self {
930                limbs: out,
931            },
932            carry,
933        )
934    }
935
936    /// Subtracts a single `u64`, returning the wrapped result and borrow out.
937    #[inline]
938    pub fn sub_word(&self, word: u64) -> (Self, u64) {
939        let mut out = self.limbs;
940        let (first, mut borrow) = sbb(out[0], word, 0);
941        out[0] = first;
942        let mut i = 1;
943        while i < LIMBS {
944            let (next, next_borrow) = sbb(out[i], 0, borrow);
945            out[i] = next;
946            borrow = next_borrow;
947            i += 1;
948        }
949        (
950            Self {
951                limbs: out,
952            },
953            borrow,
954        )
955    }
956
957    /// Multiplies by a single `u64`, returning the low `LIMBS` limbs and the
958    /// carry (high word) out.
959    #[inline]
960    pub fn mul_word(&self, word: u64) -> (Self, u64) {
961        let mut out = [0u64; LIMBS];
962        let mut carry = 0u64;
963        let mut i = 0;
964        while i < LIMBS {
965            let (next, next_carry) = mac(0, self.limbs[i], word, carry);
966            out[i] = next;
967            carry = next_carry;
968            i += 1;
969        }
970        (
971            Self {
972                limbs: out,
973            },
974            carry,
975        )
976    }
977
978    /// Divides by a single `u64`, returning the quotient and remainder.
979    ///
980    /// # Panics
981    ///
982    /// Panics if `word` is zero.
983    #[inline]
984    pub fn div_rem_word(&self, word: u64) -> (Self, u64) {
985        assert!(word != 0, "division by zero");
986        let mut out = [0u64; LIMBS];
987        let mut rem = 0u64;
988        let mut i = LIMBS;
989        while i > 0 {
990            i -= 1;
991            let dividend = ((rem as u128) << 64) | self.limbs[i] as u128;
992            out[i] = (dividend / word as u128) as u64;
993            rem = (dividend % word as u128) as u64;
994        }
995        (
996            Self {
997                limbs: out,
998            },
999            rem,
1000        )
1001    }
1002
1003    /// Adds `value` at limb `index`, propagating the carry into higher limbs.
1004    ///
1005    /// Returns the carry out (zero when it fits). Used for the two-word
1006    /// `u128` operators.
1007    #[inline]
1008    fn add_word_at(&self, index: usize, word: u64) -> (Self, u64) {
1009        let mut out = self.limbs;
1010        let mut carry = word;
1011        let mut i = index;
1012        while i < LIMBS && carry != 0 {
1013            let (next, next_carry) = adc(out[i], carry, 0);
1014            out[i] = next;
1015            carry = next_carry;
1016            i += 1;
1017        }
1018        (
1019            Self {
1020                limbs: out,
1021            },
1022            carry,
1023        )
1024    }
1025
1026    /// Subtracts `value` at limb `index`, propagating the borrow into higher
1027    /// limbs. Returns the borrow out.
1028    #[inline]
1029    fn sub_word_at(&self, index: usize, word: u64) -> (Self, u64) {
1030        let mut out = self.limbs;
1031        let mut borrow = word;
1032        let mut i = index;
1033        while i < LIMBS && borrow != 0 {
1034            let (next, next_borrow) = sbb(out[i], borrow, 0);
1035            out[i] = next;
1036            borrow = next_borrow;
1037            i += 1;
1038        }
1039        (
1040            Self {
1041                limbs: out,
1042            },
1043            borrow,
1044        )
1045    }
1046
1047    /// Adds a `u128`, wrapping on overflow.
1048    #[inline]
1049    pub fn add_u128(&self, value: u128) -> Self {
1050        let (lo, hi) = (value as u64, (value >> 64) as u64);
1051        self.add_word(lo).0.add_word_at(1, hi).0
1052    }
1053
1054    /// Subtracts a `u128`, wrapping on underflow.
1055    #[inline]
1056    pub fn sub_u128(&self, value: u128) -> Self {
1057        let (lo, hi) = (value as u64, (value >> 64) as u64);
1058        self.sub_word(lo).0.sub_word_at(1, hi).0
1059    }
1060
1061    /// Multiplies by a `u128`, returning the low `BITS` bits (wrapping).
1062    #[inline]
1063    pub fn mul_u128(&self, value: u128) -> Self {
1064        let (lo, hi) = (value as u64, (value >> 64) as u64);
1065        if hi == 0 {
1066            return self.mul_word(lo).0;
1067        }
1068        let (low, _) = self.mul_word(lo);
1069        let (high, _) = self.mul_word(hi);
1070        // result = low + (high << 64); the top limb of `high` shifts out.
1071        let mut out = low.limbs;
1072        let mut carry = 0u64;
1073        let mut j = 1;
1074        while j < LIMBS {
1075            let (sum, next_carry) = adc(out[j], high.limbs[j - 1], carry);
1076            out[j] = sum;
1077            carry = next_carry;
1078            j += 1;
1079        }
1080        Self {
1081            limbs: out,
1082        }
1083    }
1084
1085    /// Divides by a `u128`, returning the quotient and remainder.
1086    ///
1087    /// # Panics
1088    ///
1089    /// Panics if `divisor` is zero.
1090    pub fn div_rem_u128(&self, divisor: u128) -> (Self, u128) {
1091        assert!(divisor != 0, "division by zero");
1092        if divisor <= u64::MAX as u128 {
1093            let (q, r) = self.div_rem_word(divisor as u64);
1094            return (q, r as u128);
1095        }
1096        // The divisor needs two limbs. When the type is a single limb, it is
1097        // larger than any representable value, so the quotient is zero.
1098        if LIMBS < 2 {
1099            return (Self::ZERO, self.limbs[0] as u128);
1100        }
1101        let d = {
1102            let mut limbs = [0u64; LIMBS];
1103            limbs[0] = divisor as u64;
1104            limbs[1] = (divisor >> 64) as u64;
1105            Self {
1106                limbs,
1107            }
1108        };
1109
1110        let mut quotient = Self::ZERO;
1111        let mut rem = Self::ZERO;
1112        let mut i = self.bit_len();
1113        while i > 0 {
1114            i -= 1;
1115            // rem = rem * 2 + bit(i)
1116            let mut carry = self.bit(i) as u64;
1117            let mut j = 0;
1118            while j < LIMBS {
1119                let next = rem.limbs[j] >> 63;
1120                rem.limbs[j] = (rem.limbs[j] << 1) | carry;
1121                carry = next;
1122                j += 1;
1123            }
1124            // The shifted remainder is < 2 * divisor; when it carries out of
1125            // the limbs it is certainly >= divisor.
1126            let (sub, borrow) = rem.sub_raw(&d);
1127            if carry != 0 || borrow == 0 {
1128                rem = sub;
1129                quotient.limbs[i / 64] |= 1u64 << (i % 64);
1130            }
1131        }
1132        let remainder = rem.limbs[0] as u128 | ((rem.limbs[1] as u128) << 64);
1133        (quotient, remainder)
1134    }
1135
1136    /// Parses `src` as an unsigned integer in `radix` (2..=36), accepting the
1137    /// ASCII digits `0-9`, `a-z` and `A-Z`.
1138    ///
1139    /// Leading zero digits are accepted. The value must fit in `BITS` bits,
1140    /// otherwise [`Error::Overflow`] is returned. Signs (`+`/`-`), whitespace,
1141    /// `_` separators and prefixes such as `0x` are not accepted. The input
1142    /// length is bounded before any per-digit work, so a hostile multi-megabyte
1143    /// string cannot force unbounded computation. This method never allocates.
1144    ///
1145    /// # Errors
1146    ///
1147    /// Returns [`Error::InvalidRadix`] for `radix` outside `2..=36`,
1148    /// [`Error::EmptyString`] for an empty input, [`Error::InvalidDigit`] for a
1149    /// non-digit or out-of-range character, and [`Error::Overflow`] when the
1150    /// value does not fit in `BITS` bits.
1151    ///
1152    /// # Examples
1153    ///
1154    /// ```
1155    /// use big_number::Uint;
1156    /// let max = Uint::<64, 1>::from_str_radix("ffffffffffffffff", 16).unwrap();
1157    /// assert_eq!(max, Uint::<64, 1>::MAX);
1158    /// assert!(Uint::<64, 1>::from_str_radix("10000000000000000", 16).is_err()); // 2^64
1159    /// ```
1160    pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, Error> {
1161        if !(2..=36).contains(&radix) {
1162            return Err(Error::InvalidRadix);
1163        }
1164        if src.is_empty() {
1165            return Err(Error::EmptyString);
1166        }
1167
1168        // Skip leading zeros: they do not change the value and skipping them
1169        // keeps the loop below proportional to the significant digits rather
1170        // than to the input length.
1171        let bytes = src.as_bytes();
1172        let start = bytes.iter().position(|&b| b != b'0').unwrap_or(bytes.len());
1173        if start == bytes.len() {
1174            return Ok(Self::ZERO);
1175        }
1176        let significant = &bytes[start..];
1177
1178        // A value below 2^BITS has at most `BITS / floor(log2(radix)) + 1`
1179        // digits, so a longer significant run necessarily overflows. This is a
1180        // fast rejection that also bounds the work below.
1181        let bits_per_digit = (63 - (radix as u64).leading_zeros()) as usize;
1182        if significant.len() > BITS / bits_per_digit + 1 {
1183            return Err(Error::Overflow);
1184        }
1185
1186        let mut out = Self::ZERO;
1187        for &byte in significant {
1188            let digit = char_to_digit(byte).ok_or(Error::InvalidDigit)?;
1189            if digit >= radix {
1190                return Err(Error::InvalidDigit);
1191            }
1192            let (mul, high) = out.mul_word(radix as u64);
1193            if high != 0 {
1194                return Err(Error::Overflow);
1195            }
1196            let (next, carry) = mul.add_word(digit as u64);
1197            if carry != 0 {
1198                return Err(Error::Overflow);
1199            }
1200            out = next;
1201        }
1202        // `mul_word`/`add_word` only detect overflow past `LIMBS * 64` bits, so
1203        // reject values that fit the limbs but exceed `BITS`.
1204        if out.bit_len() > BITS {
1205            return Err(Error::Overflow);
1206        }
1207        Ok(out)
1208    }
1209
1210    /// Formats the value in `radix` (2..=36) using lowercase digits.
1211    ///
1212    /// Allocates a single [`String`].
1213    ///
1214    /// # Panics
1215    ///
1216    /// Panics if `radix` is outside `2..=36`.
1217    #[cfg(feature = "alloc")]
1218    pub fn to_string_radix(&self, radix: u32) -> String {
1219        assert!((2..=36).contains(&radix), "invalid radix");
1220        if self.is_zero() {
1221            return String::from("0");
1222        }
1223
1224        // Upper bound on the number of digits, so the buffer is allocated once.
1225        let bits_per_digit = (63 - (radix as u64).leading_zeros()) as usize;
1226        let capacity = self.bit_len() / bits_per_digit + 1;
1227        let mut digits: Vec<u8> = Vec::with_capacity(capacity);
1228        let mut value = *self;
1229        while !value.is_zero() {
1230            let (quotient, remainder) = value.div_rem_word(radix as u64);
1231            digits.push(digit_to_char(remainder, false) as u8);
1232            value = quotient;
1233        }
1234        digits.reverse();
1235        // Every byte is an ASCII digit, so validation succeeds without copying.
1236        String::from_utf8(digits).expect("digits are ASCII")
1237    }
1238}
1239
1240#[cfg(feature = "alloc")]
1241impl<const BITS: usize, const LIMBS: usize> fmt::Display for Uint<BITS, LIMBS> {
1242    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1243        f.write_str(&self.to_string_radix(10))
1244    }
1245}
1246
1247impl<const BITS: usize, const LIMBS: usize> fmt::LowerHex for Uint<BITS, LIMBS> {
1248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1249        if f.alternate() {
1250            f.write_str("0x")?;
1251        }
1252        let mut started = false;
1253        let mut i = LIMBS;
1254        while i > 0 {
1255            i -= 1;
1256            let limb = self.limbs[i];
1257            if started {
1258                write!(f, "{limb:016x}")?;
1259            } else if limb != 0 {
1260                write!(f, "{limb:x}")?;
1261                started = true;
1262            }
1263        }
1264        if !started {
1265            f.write_str("0")?;
1266        }
1267        Ok(())
1268    }
1269}
1270
1271impl<const BITS: usize, const LIMBS: usize> fmt::UpperHex for Uint<BITS, LIMBS> {
1272    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1273        if f.alternate() {
1274            f.write_str("0x")?;
1275        }
1276        let mut started = false;
1277        let mut i = LIMBS;
1278        while i > 0 {
1279            i -= 1;
1280            let limb = self.limbs[i];
1281            if started {
1282                write!(f, "{limb:016X}")?;
1283            } else if limb != 0 {
1284                write!(f, "{limb:X}")?;
1285                started = true;
1286            }
1287        }
1288        if !started {
1289            f.write_str("0")?;
1290        }
1291        Ok(())
1292    }
1293}
1294
1295impl<const BITS: usize, const LIMBS: usize> fmt::Debug for Uint<BITS, LIMBS> {
1296    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1297        write!(f, "Uint(0x{self:x})")
1298    }
1299}
1300
1301impl<const BITS: usize, const LIMBS: usize> Int<BITS, LIMBS> {
1302    const _LIMBS_CHECK: () = assert!(LIMBS == BITS.div_ceil(64), "LIMBS must equal ceil(BITS/64)");
1303
1304    pub const ZERO: Self = Self(Uint::ZERO);
1305    pub const ONE: Self = Self(Uint::ONE);
1306    pub const MINUS_ONE: Self = Self(Uint::MAX);
1307
1308    #[inline]
1309    const fn from_uint_bits(bits: Uint<BITS, LIMBS>) -> Self {
1310        Self(bits)
1311    }
1312
1313    #[inline]
1314    fn from_u128(value: u128) -> Self {
1315        Self(uint_from_u128(value))
1316    }
1317
1318    #[inline]
1319    fn from_i128(value: i128) -> Self {
1320        if value.is_negative() {
1321            let magnitude = uint_from_u128::<BITS, LIMBS>(value.unsigned_abs());
1322            Self(Self::ZERO.0.sub_raw(&magnitude).0)
1323        } else {
1324            Self(uint_from_u128(value as u128))
1325        }
1326    }
1327
1328    /// Returns `true` when the sign bit (bit `BITS - 1`) is set.
1329    #[inline]
1330    pub fn is_negative(&self) -> bool {
1331        self.0.bit(BITS - 1)
1332    }
1333
1334    /// Returns the absolute value as an unsigned [`Uint`].
1335    #[inline]
1336    pub fn abs(&self) -> Uint<BITS, LIMBS> {
1337        if self.is_negative() {
1338            Self::ZERO.0.sub_raw(&self.0).0
1339        } else {
1340            self.0
1341        }
1342    }
1343}
1344
1345impl<const BITS: usize, const LIMBS: usize> Add for Uint<BITS, LIMBS> {
1346    type Output = Self;
1347
1348    fn add(self, rhs: Self) -> Self::Output {
1349        self.add_raw(&rhs).0
1350    }
1351}
1352
1353impl<const BITS: usize, const LIMBS: usize> Sub for Uint<BITS, LIMBS> {
1354    type Output = Self;
1355
1356    fn sub(self, rhs: Self) -> Self::Output {
1357        self.sub_raw(&rhs).0
1358    }
1359}
1360
1361impl<const BITS: usize, const LIMBS: usize> Mul for Uint<BITS, LIMBS> {
1362    type Output = Self;
1363
1364    fn mul(self, rhs: Self) -> Self::Output {
1365        let mut product = self.mul_wide_internal(&rhs);
1366        let mut limbs = [0u64; LIMBS];
1367        let mut i = 0;
1368        while i < LIMBS {
1369            limbs[i] = product[i];
1370            i += 1;
1371        }
1372        zeroize_limbs(&mut product[..]);
1373        Self {
1374            limbs,
1375        }
1376    }
1377}
1378
1379impl<const BITS: usize, const LIMBS: usize> Add for Int<BITS, LIMBS> {
1380    type Output = Self;
1381
1382    fn add(self, rhs: Self) -> Self::Output {
1383        Self::from_uint_bits(self.0.add_raw(&rhs.0).0)
1384    }
1385}
1386
1387impl<const BITS: usize, const LIMBS: usize> Sub for Int<BITS, LIMBS> {
1388    type Output = Self;
1389
1390    fn sub(self, rhs: Self) -> Self::Output {
1391        Self::from_uint_bits(self.0.sub_raw(&rhs.0).0)
1392    }
1393}
1394
1395impl<const BITS: usize, const LIMBS: usize> Neg for Int<BITS, LIMBS> {
1396    type Output = Self;
1397
1398    fn neg(self) -> Self::Output {
1399        Self::from_uint_bits(Int::ZERO.0.sub_raw(&self.0).0)
1400    }
1401}
1402
1403macro_rules! impl_uint_ops_unsigned {
1404    ($($ty:ty),* $(,)?) => {
1405        $(
1406            impl<const BITS: usize, const LIMBS: usize> Add<$ty> for Uint<BITS, LIMBS> {
1407                type Output = Self;
1408                fn add(self, rhs: $ty) -> Self::Output {
1409                    self.add_word(u128_to_word(rhs as u128)).0
1410                }
1411            }
1412
1413            impl<const BITS: usize, const LIMBS: usize> Sub<$ty> for Uint<BITS, LIMBS> {
1414                type Output = Self;
1415                fn sub(self, rhs: $ty) -> Self::Output {
1416                    self.sub_word(u128_to_word(rhs as u128)).0
1417                }
1418            }
1419
1420            impl<const BITS: usize, const LIMBS: usize> Mul<$ty> for Uint<BITS, LIMBS> {
1421                type Output = Self;
1422                fn mul(self, rhs: $ty) -> Self::Output {
1423                    self.mul_word(u128_to_word(rhs as u128)).0
1424                }
1425            }
1426
1427            impl<const BITS: usize, const LIMBS: usize> Div<$ty> for Uint<BITS, LIMBS> {
1428                type Output = Self;
1429                fn div(self, rhs: $ty) -> Self::Output {
1430                    self.div_rem_word(u128_to_word(rhs as u128)).0
1431                }
1432            }
1433
1434            impl<const BITS: usize, const LIMBS: usize> Rem<$ty> for Uint<BITS, LIMBS> {
1435                type Output = u64;
1436                fn rem(self, rhs: $ty) -> Self::Output {
1437                    self.div_rem_word(u128_to_word(rhs as u128)).1
1438                }
1439            }
1440        )*
1441    };
1442}
1443
1444macro_rules! impl_uint_ops_signed {
1445    ($($ty:ty),* $(,)?) => {
1446        $(
1447            impl<const BITS: usize, const LIMBS: usize> Add<$ty> for Uint<BITS, LIMBS> {
1448                type Output = Self;
1449                fn add(self, rhs: $ty) -> Self::Output {
1450                    let (word, negative) = i128_abs_to_word(rhs as i128);
1451                    if negative {
1452                        self.sub_word(word).0
1453                    } else {
1454                        self.add_word(word).0
1455                    }
1456                }
1457            }
1458
1459            impl<const BITS: usize, const LIMBS: usize> Sub<$ty> for Uint<BITS, LIMBS> {
1460                type Output = Self;
1461                fn sub(self, rhs: $ty) -> Self::Output {
1462                    let (word, negative) = i128_abs_to_word(rhs as i128);
1463                    if negative {
1464                        self.add_word(word).0
1465                    } else {
1466                        self.sub_word(word).0
1467                    }
1468                }
1469            }
1470
1471            impl<const BITS: usize, const LIMBS: usize> Mul<$ty> for Uint<BITS, LIMBS> {
1472                type Output = Self;
1473                fn mul(self, rhs: $ty) -> Self::Output {
1474                    self.mul_word(i128_abs_to_word(rhs as i128).0).0
1475                }
1476            }
1477
1478            impl<const BITS: usize, const LIMBS: usize> Div<$ty> for Uint<BITS, LIMBS> {
1479                type Output = Self;
1480                fn div(self, rhs: $ty) -> Self::Output {
1481                    self.div_rem_word(i128_abs_to_word(rhs as i128).0).0
1482                }
1483            }
1484
1485            impl<const BITS: usize, const LIMBS: usize> Rem<$ty> for Uint<BITS, LIMBS> {
1486                type Output = u64;
1487                fn rem(self, rhs: $ty) -> Self::Output {
1488                    self.div_rem_word(i128_abs_to_word(rhs as i128).0).1
1489                }
1490            }
1491        )*
1492    };
1493}
1494
1495macro_rules! impl_int_ops_unsigned {
1496    ($($ty:ty),* $(,)?) => {
1497        $(
1498            impl<const BITS: usize, const LIMBS: usize> Add<$ty> for Int<BITS, LIMBS> {
1499                type Output = Self;
1500                fn add(self, rhs: $ty) -> Self::Output {
1501                    self + Self::from_u128(rhs as u128)
1502                }
1503            }
1504
1505            impl<const BITS: usize, const LIMBS: usize> Sub<$ty> for Int<BITS, LIMBS> {
1506                type Output = Self;
1507                fn sub(self, rhs: $ty) -> Self::Output {
1508                    self - Self::from_u128(rhs as u128)
1509                }
1510            }
1511
1512            impl<const BITS: usize, const LIMBS: usize> Mul<$ty> for Int<BITS, LIMBS> {
1513                type Output = Self;
1514                fn mul(self, rhs: $ty) -> Self::Output {
1515                    let (product, _) = self.abs().mul_word(u128_to_word(rhs as u128));
1516                    let bits = if self.is_negative() {
1517                        Uint::ZERO.sub_raw(&product).0
1518                    } else {
1519                        product
1520                    };
1521                    Self::from_uint_bits(bits)
1522                }
1523            }
1524
1525            impl<const BITS: usize, const LIMBS: usize> Div<$ty> for Int<BITS, LIMBS> {
1526                type Output = Self;
1527                fn div(self, rhs: $ty) -> Self::Output {
1528                    let (quotient, _) = self.abs().div_rem_word(u128_to_word(rhs as u128));
1529                    let bits = if self.is_negative() {
1530                        Uint::ZERO.sub_raw(&quotient).0
1531                    } else {
1532                        quotient
1533                    };
1534                    Self::from_uint_bits(bits)
1535                }
1536            }
1537
1538            impl<const BITS: usize, const LIMBS: usize> Rem<$ty> for Int<BITS, LIMBS> {
1539                type Output = Self;
1540                fn rem(self, rhs: $ty) -> Self::Output {
1541                    let (_, remainder) = self.abs().div_rem_word(u128_to_word(rhs as u128));
1542                    let bits = Uint::from_u64(remainder);
1543                    let bits = if self.is_negative() {
1544                        Uint::ZERO.sub_raw(&bits).0
1545                    } else {
1546                        bits
1547                    };
1548                    Self::from_uint_bits(bits)
1549                }
1550            }
1551        )*
1552    };
1553}
1554
1555macro_rules! impl_int_ops_signed {
1556    ($($ty:ty),* $(,)?) => {
1557        $(
1558            impl<const BITS: usize, const LIMBS: usize> Add<$ty> for Int<BITS, LIMBS> {
1559                type Output = Self;
1560                fn add(self, rhs: $ty) -> Self::Output {
1561                    self + Self::from_i128(rhs as i128)
1562                }
1563            }
1564
1565            impl<const BITS: usize, const LIMBS: usize> Sub<$ty> for Int<BITS, LIMBS> {
1566                type Output = Self;
1567                fn sub(self, rhs: $ty) -> Self::Output {
1568                    self - Self::from_i128(rhs as i128)
1569                }
1570            }
1571
1572            impl<const BITS: usize, const LIMBS: usize> Mul<$ty> for Int<BITS, LIMBS> {
1573                type Output = Self;
1574                fn mul(self, rhs: $ty) -> Self::Output {
1575                    let (word, negative) = i128_abs_to_word(rhs as i128);
1576                    let (product, _) = self.abs().mul_word(word);
1577                    let make_negative = self.is_negative() != negative;
1578                    let bits = if make_negative {
1579                        Uint::ZERO.sub_raw(&product).0
1580                    } else {
1581                        product
1582                    };
1583                    Self::from_uint_bits(bits)
1584                }
1585            }
1586
1587            impl<const BITS: usize, const LIMBS: usize> Div<$ty> for Int<BITS, LIMBS> {
1588                type Output = Self;
1589                fn div(self, rhs: $ty) -> Self::Output {
1590                    let (word, negative) = i128_abs_to_word(rhs as i128);
1591                    let (quotient, _) = self.abs().div_rem_word(word);
1592                    let make_negative = self.is_negative() != negative;
1593                    let bits = if make_negative {
1594                        Uint::ZERO.sub_raw(&quotient).0
1595                    } else {
1596                        quotient
1597                    };
1598                    Self::from_uint_bits(bits)
1599                }
1600            }
1601
1602            impl<const BITS: usize, const LIMBS: usize> Rem<$ty> for Int<BITS, LIMBS> {
1603                type Output = Self;
1604                fn rem(self, rhs: $ty) -> Self::Output {
1605                    let (word, _) = i128_abs_to_word(rhs as i128);
1606                    let (_, remainder) = self.abs().div_rem_word(word);
1607                    let bits = Uint::from_u64(remainder);
1608                    let bits = if self.is_negative() {
1609                        Uint::ZERO.sub_raw(&bits).0
1610                    } else {
1611                        bits
1612                    };
1613                    Self::from_uint_bits(bits)
1614                }
1615            }
1616        )*
1617    };
1618}
1619
1620impl_uint_ops_unsigned!(u8, u16, u32, u64);
1621impl_uint_ops_signed!(i8, i16, i32, i64);
1622impl_int_ops_unsigned!(u8, u16, u32, u64);
1623impl_int_ops_signed!(i8, i16, i32, i64);
1624
1625// `u128`/`i128` operands are handled explicitly through the two-word helpers
1626// (`add_u128`, `sub_u128`, `mul_u128`, `div_rem_u128`) so that no operand
1627// value can trigger a panic.
1628impl<const BITS: usize, const LIMBS: usize> Add<u128> for Uint<BITS, LIMBS> {
1629    type Output = Self;
1630    fn add(self, rhs: u128) -> Self::Output {
1631        self.add_u128(rhs)
1632    }
1633}
1634
1635impl<const BITS: usize, const LIMBS: usize> Sub<u128> for Uint<BITS, LIMBS> {
1636    type Output = Self;
1637    fn sub(self, rhs: u128) -> Self::Output {
1638        self.sub_u128(rhs)
1639    }
1640}
1641
1642impl<const BITS: usize, const LIMBS: usize> Mul<u128> for Uint<BITS, LIMBS> {
1643    type Output = Self;
1644    fn mul(self, rhs: u128) -> Self::Output {
1645        self.mul_u128(rhs)
1646    }
1647}
1648
1649impl<const BITS: usize, const LIMBS: usize> Div<u128> for Uint<BITS, LIMBS> {
1650    type Output = Self;
1651    fn div(self, rhs: u128) -> Self::Output {
1652        self.div_rem_u128(rhs).0
1653    }
1654}
1655
1656impl<const BITS: usize, const LIMBS: usize> Rem<u128> for Uint<BITS, LIMBS> {
1657    type Output = u128;
1658    fn rem(self, rhs: u128) -> Self::Output {
1659        self.div_rem_u128(rhs).1
1660    }
1661}
1662
1663impl<const BITS: usize, const LIMBS: usize> Add<i128> for Uint<BITS, LIMBS> {
1664    type Output = Self;
1665    fn add(self, rhs: i128) -> Self::Output {
1666        if rhs < 0 {
1667            self.sub_u128(rhs.unsigned_abs())
1668        } else {
1669            self.add_u128(rhs as u128)
1670        }
1671    }
1672}
1673
1674impl<const BITS: usize, const LIMBS: usize> Sub<i128> for Uint<BITS, LIMBS> {
1675    type Output = Self;
1676    fn sub(self, rhs: i128) -> Self::Output {
1677        if rhs < 0 {
1678            self.add_u128(rhs.unsigned_abs())
1679        } else {
1680            self.sub_u128(rhs as u128)
1681        }
1682    }
1683}
1684
1685impl<const BITS: usize, const LIMBS: usize> Mul<i128> for Uint<BITS, LIMBS> {
1686    type Output = Self;
1687    fn mul(self, rhs: i128) -> Self::Output {
1688        self.mul_u128(rhs.unsigned_abs())
1689    }
1690}
1691
1692impl<const BITS: usize, const LIMBS: usize> Div<i128> for Uint<BITS, LIMBS> {
1693    type Output = Self;
1694    fn div(self, rhs: i128) -> Self::Output {
1695        self.div_rem_u128(rhs.unsigned_abs()).0
1696    }
1697}
1698
1699impl<const BITS: usize, const LIMBS: usize> Rem<i128> for Uint<BITS, LIMBS> {
1700    type Output = u128;
1701    fn rem(self, rhs: i128) -> Self::Output {
1702        self.div_rem_u128(rhs.unsigned_abs()).1
1703    }
1704}
1705
1706impl<const BITS: usize, const LIMBS: usize> Add<u128> for Int<BITS, LIMBS> {
1707    type Output = Self;
1708    fn add(self, rhs: u128) -> Self::Output {
1709        self + Self::from_u128(rhs)
1710    }
1711}
1712
1713impl<const BITS: usize, const LIMBS: usize> Sub<u128> for Int<BITS, LIMBS> {
1714    type Output = Self;
1715    fn sub(self, rhs: u128) -> Self::Output {
1716        self - Self::from_u128(rhs)
1717    }
1718}
1719
1720impl<const BITS: usize, const LIMBS: usize> Mul<u128> for Int<BITS, LIMBS> {
1721    type Output = Self;
1722    fn mul(self, rhs: u128) -> Self::Output {
1723        let product = self.abs().mul_u128(rhs);
1724        let bits = if self.is_negative() {
1725            Uint::ZERO.sub_raw(&product).0
1726        } else {
1727            product
1728        };
1729        Self::from_uint_bits(bits)
1730    }
1731}
1732
1733impl<const BITS: usize, const LIMBS: usize> Div<u128> for Int<BITS, LIMBS> {
1734    type Output = Self;
1735    fn div(self, rhs: u128) -> Self::Output {
1736        let (quotient, _) = self.abs().div_rem_u128(rhs);
1737        let bits = if self.is_negative() {
1738            Uint::ZERO.sub_raw(&quotient).0
1739        } else {
1740            quotient
1741        };
1742        Self::from_uint_bits(bits)
1743    }
1744}
1745
1746impl<const BITS: usize, const LIMBS: usize> Rem<u128> for Int<BITS, LIMBS> {
1747    type Output = Self;
1748    fn rem(self, rhs: u128) -> Self::Output {
1749        let (_, remainder) = self.abs().div_rem_u128(rhs);
1750        let bits = uint_from_u128::<BITS, LIMBS>(remainder);
1751        let bits = if self.is_negative() {
1752            Uint::ZERO.sub_raw(&bits).0
1753        } else {
1754            bits
1755        };
1756        Self::from_uint_bits(bits)
1757    }
1758}
1759
1760impl<const BITS: usize, const LIMBS: usize> Add<i128> for Int<BITS, LIMBS> {
1761    type Output = Self;
1762    fn add(self, rhs: i128) -> Self::Output {
1763        self + Self::from_i128(rhs)
1764    }
1765}
1766
1767impl<const BITS: usize, const LIMBS: usize> Sub<i128> for Int<BITS, LIMBS> {
1768    type Output = Self;
1769    fn sub(self, rhs: i128) -> Self::Output {
1770        self - Self::from_i128(rhs)
1771    }
1772}
1773
1774impl<const BITS: usize, const LIMBS: usize> Mul<i128> for Int<BITS, LIMBS> {
1775    type Output = Self;
1776    fn mul(self, rhs: i128) -> Self::Output {
1777        let product = self.abs().mul_u128(rhs.unsigned_abs());
1778        let make_negative = self.is_negative() != rhs.is_negative();
1779        let bits = if make_negative {
1780            Uint::ZERO.sub_raw(&product).0
1781        } else {
1782            product
1783        };
1784        Self::from_uint_bits(bits)
1785    }
1786}
1787
1788impl<const BITS: usize, const LIMBS: usize> Div<i128> for Int<BITS, LIMBS> {
1789    type Output = Self;
1790    fn div(self, rhs: i128) -> Self::Output {
1791        let (quotient, _) = self.abs().div_rem_u128(rhs.unsigned_abs());
1792        let make_negative = self.is_negative() != rhs.is_negative();
1793        let bits = if make_negative {
1794            Uint::ZERO.sub_raw(&quotient).0
1795        } else {
1796            quotient
1797        };
1798        Self::from_uint_bits(bits)
1799    }
1800}
1801
1802impl<const BITS: usize, const LIMBS: usize> Rem<i128> for Int<BITS, LIMBS> {
1803    type Output = Self;
1804    fn rem(self, rhs: i128) -> Self::Output {
1805        let (_, remainder) = self.abs().div_rem_u128(rhs.unsigned_abs());
1806        let bits = uint_from_u128::<BITS, LIMBS>(remainder);
1807        let bits = if self.is_negative() {
1808            Uint::ZERO.sub_raw(&bits).0
1809        } else {
1810            bits
1811        };
1812        Self::from_uint_bits(bits)
1813    }
1814}
1815
1816#[cfg(test)]
1817mod tests {
1818    use super::*;
1819    type U256 = Uint<256, 4>;
1820    type U128 = Uint<128, 2>;
1821    type I128 = Int<128, 2>;
1822
1823    const P256_MODULUS: U256 = U256::from_limbs([
1824        0xffff_ffff_ffff_ffff,
1825        0x0000_0000_ffff_ffff,
1826        0x0000_0000_0000_0000,
1827        0xffff_ffff_0000_0001,
1828    ]);
1829    const P256_ORDER: U256 = U256::from_limbs([
1830        0xf3b9_cac2_fc63_2551,
1831        0xbce6_faad_a717_9e84,
1832        0xffff_ffff_ffff_ffff,
1833        0xffff_ffff_0000_0000,
1834    ]);
1835    const P256_P_MINUS_TWO: U256 = U256::from_limbs([
1836        0xffff_ffff_ffff_fffd,
1837        0x0000_0000_ffff_ffff,
1838        0x0000_0000_0000_0000,
1839        0xffff_ffff_0000_0001,
1840    ]);
1841    const P256_P_PLUS_ONE_OVER_FOUR: U256 = U256::from_limbs([
1842        0x0000_0000_0000_0000,
1843        0x0000_0000_4000_0000,
1844        0x4000_0000_0000_0000,
1845        0x3fff_ffff_c000_0000,
1846    ]);
1847    const ED25519_P: U256 = U256::from_limbs([
1848        0xffff_ffff_ffff_ffed,
1849        0xffff_ffff_ffff_ffff,
1850        0xffff_ffff_ffff_ffff,
1851        0x7fff_ffff_ffff_ffff,
1852    ]);
1853
1854    fn decode_hex<const N: usize>(input: &str) -> [u8; N] {
1855        assert_eq!(input.len(), N * 2);
1856        let mut out = [0u8; N];
1857        let bytes = input.as_bytes();
1858        let mut i = 0;
1859        while i < N {
1860            let hi = char_to_digit(bytes[i * 2]).unwrap() as u8;
1861            let lo = char_to_digit(bytes[i * 2 + 1]).unwrap() as u8;
1862            out[i] = (hi << 4) | lo;
1863            i += 1;
1864        }
1865        out
1866    }
1867
1868    #[test]
1869    fn raw_arithmetic_reports_carry_and_borrow() {
1870        let (sum, carry) = U128::MAX.add_raw(&U128::ONE);
1871        assert_eq!(sum, U128::ZERO);
1872        assert_eq!(carry, 1);
1873
1874        let (diff, borrow) = U128::ZERO.sub_raw(&U128::ONE);
1875        assert_eq!(diff, U128::MAX);
1876        assert_eq!(borrow, 1);
1877
1878        let (low, high) = U128::MAX.mul_word(2);
1879        assert_eq!(low, U128::from_limbs([0xffff_ffff_ffff_fffe, 0xffff_ffff_ffff_ffff]));
1880        assert_eq!(high, 1);
1881    }
1882
1883    #[test]
1884    fn modular_arithmetic_matches_known_values() {
1885        assert_eq!(P256_P_MINUS_TWO.add_mod(&U256::from_u64(2), &P256_MODULUS), U256::ZERO);
1886        assert_eq!(
1887            P256_MODULUS.sub_mod(&U256::from_u64(1), &P256_MODULUS),
1888            P256_MODULUS - U256::ONE
1889        );
1890        assert_eq!(P256_P_MINUS_TWO.double_mod(&P256_MODULUS), P256_MODULUS - U256::from_u64(4));
1891        assert_eq!(P256_P_PLUS_ONE_OVER_FOUR.mul_mod(&U256::from_u64(4), &P256_MODULUS), U256::ONE);
1892        assert_eq!(P256_ORDER.add_mod(&U256::ONE, &P256_ORDER), U256::ONE);
1893    }
1894
1895    #[test]
1896    fn string_round_trips_for_common_radices() {
1897        let values = [
1898            U256::ZERO,
1899            U256::ONE,
1900            U256::MAX,
1901            U256::from_be_slice(&decode_hex::<32>(
1902                "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
1903            )),
1904        ];
1905
1906        for value in values {
1907            for radix in [2, 10, 16] {
1908                let encoded = value.to_string_radix(radix);
1909                let decoded = U256::from_str_radix(&encoded, radix).unwrap();
1910                assert_eq!(decoded, value);
1911            }
1912        }
1913    }
1914
1915    #[test]
1916    fn operator_overloads_work_with_primitives() {
1917        let value = U128::from_u64(10);
1918        assert_eq!(value + 5u64, U128::from_u64(15));
1919        assert_eq!(value - (-5i32), U128::from_u64(15));
1920        assert_eq!(value * -3i32, U128::from_u64(30));
1921        assert_eq!(value / -3i32, U128::from_u64(3));
1922        assert_eq!(value % -3i32, 1);
1923
1924        let signed = I128::from_i128(-10);
1925        assert_eq!(signed + 3u32, I128::from_i128(-7));
1926        assert_eq!(signed - (-5i32), I128::from_i128(-5));
1927        assert_eq!(signed * -2i32, I128::from_i128(20));
1928        assert_eq!(signed / -4i32, I128::from_i128(2));
1929        assert_eq!(signed % 4u32, I128::from_i128(-2));
1930    }
1931
1932    #[cfg(feature = "zeroize")]
1933    #[test]
1934    fn zeroize_clears_limb_buffers() {
1935        let mut buffer = [0xA5u64; 8];
1936        zeroize_limbs(&mut buffer);
1937        assert_eq!(buffer, [0u64; 8]);
1938
1939        let mut value = U256::MAX;
1940        zeroize::Zeroize::zeroize(&mut value);
1941        assert!(value.is_zero());
1942    }
1943
1944    #[test]
1945    fn constant_time_helpers_select_and_compare() {
1946        let a = U256::from_u64(7);
1947        let b = U256::from_u64(11);
1948        assert_eq!(U256::ct_select(&a, &b, true), a);
1949        assert_eq!(U256::ct_select(&a, &b, false), b);
1950        assert!(a.ct_eq(&a));
1951        assert!(!a.ct_eq(&b));
1952        assert!(b.ct_ge(&a));
1953        assert!(!a.ct_ge(&b));
1954    }
1955
1956    #[test]
1957    fn from_str_radix_rejects_invalid_inputs() {
1958        assert_eq!(U128::from_str_radix("", 10), Err(Error::EmptyString));
1959        assert_eq!(U128::from_str_radix("10", 1), Err(Error::InvalidRadix));
1960        assert_eq!(U128::from_str_radix("2", 2), Err(Error::InvalidDigit));
1961        assert_eq!(U128::from_str_radix("zz", 10), Err(Error::InvalidDigit));
1962        assert_eq!(
1963            U128::from_str_radix("340282366920938463463374607431768211456", 10),
1964            Err(Error::Overflow)
1965        );
1966    }
1967
1968    #[test]
1969    fn byte_round_trips_match_p256_constants() {
1970        let modulus_hex = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
1971        let order_hex = "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551";
1972
1973        let modulus_bytes = decode_hex::<32>(modulus_hex);
1974        let order_bytes = decode_hex::<32>(order_hex);
1975
1976        let modulus = U256::from_be_slice(&modulus_bytes);
1977        let order = U256::from_be_slice(&order_bytes);
1978
1979        assert_eq!(modulus, P256_MODULUS);
1980        assert_eq!(order, P256_ORDER);
1981        assert_eq!(modulus.to_be_bytes_fixed::<32>(), modulus_bytes);
1982        assert_eq!(order.to_be_bytes_fixed::<32>(), order_bytes);
1983        assert_eq!(format!("{modulus:x}"), modulus_hex);
1984        assert_eq!(format!("{order:X}"), order_hex.to_uppercase());
1985    }
1986
1987    #[test]
1988    fn little_endian_round_trip_works() {
1989        let value = U256::from_be_slice(&decode_hex::<32>(
1990            "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
1991        ));
1992        let le = value.to_le_bytes_fixed::<32>();
1993        assert_eq!(U256::from_le_slice(&le), value);
1994    }
1995
1996    #[test]
1997    fn modular_addition_vectors() {
1998        struct Test {
1999            a: U256,
2000            b: U256,
2001            m: U256,
2002            expected: U256,
2003        }
2004        let tests = [
2005            Test {
2006                a: U256::ZERO,
2007                b: U256::ZERO,
2008                m: P256_MODULUS,
2009                expected: U256::ZERO,
2010            },
2011            Test {
2012                a: U256::ZERO,
2013                b: U256::ONE,
2014                m: P256_MODULUS,
2015                expected: U256::ONE,
2016            },
2017            Test {
2018                a: U256::ONE,
2019                b: U256::ONE,
2020                m: P256_MODULUS,
2021                expected: U256::from_u64(2),
2022            },
2023            Test {
2024                a: P256_MODULUS - U256::ONE,
2025                b: U256::ONE,
2026                m: P256_MODULUS,
2027                expected: U256::ZERO,
2028            },
2029            Test {
2030                a: P256_MODULUS - U256::ONE,
2031                b: U256::from_u64(2),
2032                m: P256_MODULUS,
2033                expected: U256::ONE,
2034            },
2035            Test {
2036                a: U256::ZERO,
2037                b: U256::ZERO,
2038                m: P256_ORDER,
2039                expected: U256::ZERO,
2040            },
2041            Test {
2042                a: U256::ZERO,
2043                b: U256::ONE,
2044                m: P256_ORDER,
2045                expected: U256::ONE,
2046            },
2047            Test {
2048                a: U256::ONE,
2049                b: U256::ONE,
2050                m: P256_ORDER,
2051                expected: U256::from_u64(2),
2052            },
2053            Test {
2054                a: U256::MAX,
2055                b: U256::ONE,
2056                m: P256_ORDER,
2057                expected: U256::from_limbs([
2058                    0x0c46_353d_039c_daaf,
2059                    0x4319_0552_58e8_617b,
2060                    0x0000_0000_0000_0000,
2061                    0x0000_0000_ffff_ffff,
2062                ]),
2063            },
2064            Test {
2065                a: P256_ORDER - U256::ONE,
2066                b: U256::ONE,
2067                m: P256_ORDER,
2068                expected: U256::ZERO,
2069            },
2070            Test {
2071                a: P256_ORDER - U256::ONE,
2072                b: U256::from_u64(2),
2073                m: P256_ORDER,
2074                expected: U256::ONE,
2075            },
2076            Test {
2077                a: U256::ZERO,
2078                b: U256::ZERO,
2079                m: ED25519_P,
2080                expected: U256::ZERO,
2081            },
2082            Test {
2083                a: U256::ZERO,
2084                b: U256::ONE,
2085                m: ED25519_P,
2086                expected: U256::ONE,
2087            },
2088            Test {
2089                a: U256::ONE,
2090                b: U256::ONE,
2091                m: ED25519_P,
2092                expected: U256::from_u64(2),
2093            },
2094            Test {
2095                a: U256::from_limbs([
2096                    0xffff_ffff_ffff_ffff,
2097                    0x0000_0000_0000_0000,
2098                    0x0000_0000_0000_0000,
2099                    0x0000_0000_0000_0000,
2100                ]),
2101                b: U256::ONE,
2102                m: P256_MODULUS,
2103                expected: U256::from_limbs([
2104                    0x0000_0000_0000_0000,
2105                    0x0000_0000_0000_0001,
2106                    0x0000_0000_0000_0000,
2107                    0x0000_0000_0000_0000,
2108                ]),
2109            },
2110            Test {
2111                a: U256::from_limbs([
2112                    0xffff_ffff_ffff_ffff,
2113                    0x0000_0000_0000_0000,
2114                    0x0000_0000_0000_0000,
2115                    0x0000_0000_0000_0000,
2116                ]),
2117                b: U256::ONE,
2118                m: P256_ORDER,
2119                expected: U256::from_limbs([
2120                    0x0000_0000_0000_0000,
2121                    0x0000_0000_0000_0001,
2122                    0x0000_0000_0000_0000,
2123                    0x0000_0000_0000_0000,
2124                ]),
2125            },
2126            Test {
2127                a: U256::from_limbs([
2128                    0xffff_ffff_ffff_ffff,
2129                    0x0000_0000_0000_0000,
2130                    0x0000_0000_0000_0000,
2131                    0x0000_0000_0000_0000,
2132                ]),
2133                b: U256::ONE,
2134                m: ED25519_P,
2135                expected: U256::from_limbs([
2136                    0x0000_0000_0000_0000,
2137                    0x0000_0000_0000_0001,
2138                    0x0000_0000_0000_0000,
2139                    0x0000_0000_0000_0000,
2140                ]),
2141            },
2142            Test {
2143                a: ED25519_P - U256::ONE,
2144                b: ED25519_P - U256::ONE,
2145                m: ED25519_P,
2146                expected: (ED25519_P - U256::ONE).double_mod(&ED25519_P),
2147            },
2148        ];
2149        for t in &tests {
2150            assert_eq!(t.a.add_mod(&t.b, &t.m), t.expected, "add_mod({:x}, {:x}, {:x})", t.a, t.b, t.m);
2151        }
2152    }
2153
2154    #[test]
2155    fn modular_subtraction_vectors() {
2156        struct Test {
2157            a: U256,
2158            b: U256,
2159            m: U256,
2160            expected: U256,
2161        }
2162        let tests = [
2163            Test {
2164                a: U256::ZERO,
2165                b: U256::ZERO,
2166                m: P256_MODULUS,
2167                expected: U256::ZERO,
2168            },
2169            Test {
2170                a: U256::ONE,
2171                b: U256::ZERO,
2172                m: P256_MODULUS,
2173                expected: U256::ONE,
2174            },
2175            Test {
2176                a: U256::ZERO,
2177                b: U256::ONE,
2178                m: P256_MODULUS,
2179                expected: P256_MODULUS - U256::ONE,
2180            },
2181            Test {
2182                a: P256_MODULUS - U256::ONE,
2183                b: U256::ONE,
2184                m: P256_MODULUS,
2185                expected: P256_MODULUS - U256::from_u64(2),
2186            },
2187            Test {
2188                a: U256::ONE,
2189                b: P256_MODULUS - U256::ONE,
2190                m: P256_MODULUS,
2191                expected: U256::from_u64(2),
2192            },
2193            Test {
2194                a: U256::ZERO,
2195                b: U256::ZERO,
2196                m: P256_ORDER,
2197                expected: U256::ZERO,
2198            },
2199            Test {
2200                a: U256::ONE,
2201                b: U256::ZERO,
2202                m: P256_ORDER,
2203                expected: U256::ONE,
2204            },
2205            Test {
2206                a: U256::ZERO,
2207                b: U256::ONE,
2208                m: P256_ORDER,
2209                expected: P256_ORDER - U256::ONE,
2210            },
2211            Test {
2212                a: P256_ORDER - U256::ONE,
2213                b: U256::ONE,
2214                m: P256_ORDER,
2215                expected: P256_ORDER - U256::from_u64(2),
2216            },
2217            Test {
2218                a: U256::ONE,
2219                b: P256_ORDER - U256::ONE,
2220                m: P256_ORDER,
2221                expected: U256::from_u64(2),
2222            },
2223            Test {
2224                a: U256::ZERO,
2225                b: U256::ZERO,
2226                m: ED25519_P,
2227                expected: U256::ZERO,
2228            },
2229            Test {
2230                a: U256::ONE,
2231                b: U256::ZERO,
2232                m: ED25519_P,
2233                expected: U256::ONE,
2234            },
2235            Test {
2236                a: U256::ZERO,
2237                b: U256::ONE,
2238                m: ED25519_P,
2239                expected: ED25519_P - U256::ONE,
2240            },
2241            Test {
2242                a: ED25519_P - U256::ONE,
2243                b: U256::ONE,
2244                m: ED25519_P,
2245                expected: ED25519_P - U256::from_u64(2),
2246            },
2247            Test {
2248                a: U256::ONE,
2249                b: ED25519_P - U256::ONE,
2250                m: ED25519_P,
2251                expected: U256::from_u64(2),
2252            },
2253        ];
2254        for t in &tests {
2255            assert_eq!(t.a.sub_mod(&t.b, &t.m), t.expected, "sub_mod({:x}, {:x}, {:x})", t.a, t.b, t.m);
2256        }
2257    }
2258
2259    #[test]
2260    fn modular_multiplication_vectors() {
2261        struct Test {
2262            a: U256,
2263            b: U256,
2264            m: U256,
2265            expected: U256,
2266        }
2267        let tests = [
2268            Test {
2269                a: U256::ZERO,
2270                b: U256::ZERO,
2271                m: P256_MODULUS,
2272                expected: U256::ZERO,
2273            },
2274            Test {
2275                a: U256::ZERO,
2276                b: U256::ONE,
2277                m: P256_MODULUS,
2278                expected: U256::ZERO,
2279            },
2280            Test {
2281                a: U256::ONE,
2282                b: U256::ZERO,
2283                m: P256_MODULUS,
2284                expected: U256::ZERO,
2285            },
2286            Test {
2287                a: U256::ONE,
2288                b: U256::ONE,
2289                m: P256_MODULUS,
2290                expected: U256::ONE,
2291            },
2292            Test {
2293                a: U256::from_u64(2),
2294                b: U256::from_u64(3),
2295                m: P256_MODULUS,
2296                expected: U256::from_u64(6),
2297            },
2298            Test {
2299                a: U256::MAX,
2300                b: U256::ONE,
2301                m: P256_MODULUS,
2302                expected: U256::from_limbs([
2303                    0x0000_0000_0000_0000,
2304                    0xffff_ffff_0000_0000,
2305                    0xffff_ffff_ffff_ffff,
2306                    0x0000_0000_ffff_fffe,
2307                ]),
2308            },
2309            Test {
2310                a: P256_MODULUS - U256::ONE,
2311                b: U256::ONE,
2312                m: P256_MODULUS,
2313                expected: P256_MODULUS - U256::ONE,
2314            },
2315            Test {
2316                a: P256_MODULUS - U256::ONE,
2317                b: P256_MODULUS - U256::ONE,
2318                m: P256_MODULUS,
2319                expected: U256::ONE,
2320            },
2321            Test {
2322                a: P256_MODULUS + U256::ONE,
2323                b: P256_MODULUS + U256::ONE,
2324                m: P256_MODULUS,
2325                expected: U256::ONE,
2326            },
2327            Test {
2328                a: U256::ZERO,
2329                b: U256::ZERO,
2330                m: P256_ORDER,
2331                expected: U256::ZERO,
2332            },
2333            Test {
2334                a: U256::ZERO,
2335                b: U256::ONE,
2336                m: P256_ORDER,
2337                expected: U256::ZERO,
2338            },
2339            Test {
2340                a: U256::ONE,
2341                b: U256::ZERO,
2342                m: P256_ORDER,
2343                expected: U256::ZERO,
2344            },
2345            Test {
2346                a: U256::ONE,
2347                b: U256::ONE,
2348                m: P256_ORDER,
2349                expected: U256::ONE,
2350            },
2351            Test {
2352                a: U256::from_u64(2),
2353                b: U256::from_u64(3),
2354                m: P256_ORDER,
2355                expected: U256::from_u64(6),
2356            },
2357            Test {
2358                a: P256_ORDER - U256::ONE,
2359                b: U256::ONE,
2360                m: P256_ORDER,
2361                expected: P256_ORDER - U256::ONE,
2362            },
2363            Test {
2364                a: P256_ORDER - U256::ONE,
2365                b: P256_ORDER - U256::ONE,
2366                m: P256_ORDER,
2367                expected: U256::ONE,
2368            },
2369            Test {
2370                a: P256_ORDER + U256::ONE,
2371                b: P256_ORDER + U256::ONE,
2372                m: P256_ORDER,
2373                expected: U256::ONE,
2374            },
2375            Test {
2376                a: U256::ZERO,
2377                b: U256::ZERO,
2378                m: ED25519_P,
2379                expected: U256::ZERO,
2380            },
2381            Test {
2382                a: U256::ZERO,
2383                b: U256::ONE,
2384                m: ED25519_P,
2385                expected: U256::ZERO,
2386            },
2387            Test {
2388                a: U256::ONE,
2389                b: U256::ZERO,
2390                m: ED25519_P,
2391                expected: U256::ZERO,
2392            },
2393            Test {
2394                a: U256::ONE,
2395                b: U256::ONE,
2396                m: ED25519_P,
2397                expected: U256::ONE,
2398            },
2399            Test {
2400                a: U256::from_u64(2),
2401                b: U256::from_u64(3),
2402                m: ED25519_P,
2403                expected: U256::from_u64(6),
2404            },
2405            Test {
2406                a: ED25519_P - U256::ONE,
2407                b: U256::ONE,
2408                m: ED25519_P,
2409                expected: ED25519_P - U256::ONE,
2410            },
2411            Test {
2412                a: ED25519_P - U256::ONE,
2413                b: ED25519_P - U256::ONE,
2414                m: ED25519_P,
2415                expected: U256::ONE,
2416            },
2417            Test {
2418                a: ED25519_P + U256::ONE,
2419                b: ED25519_P + U256::ONE,
2420                m: ED25519_P,
2421                expected: U256::ONE,
2422            },
2423            Test {
2424                a: U256::from_limbs([
2425                    0xffff_ffff_ffff_ffff,
2426                    0x0000_0000_0000_0000,
2427                    0x0000_0000_0000_0000,
2428                    0x0000_0000_0000_0000,
2429                ]),
2430                b: U256::from_limbs([
2431                    0xffff_ffff_ffff_ffff,
2432                    0x0000_0000_0000_0000,
2433                    0x0000_0000_0000_0000,
2434                    0x0000_0000_0000_0000,
2435                ]),
2436                m: P256_MODULUS,
2437                expected: U256::from_limbs([
2438                    0x0000_0000_0000_0001,
2439                    0xffff_ffff_ffff_fffe,
2440                    0x0000_0000_0000_0000,
2441                    0x0000_0000_0000_0000,
2442                ]),
2443            },
2444        ];
2445        for t in &tests {
2446            assert_eq!(t.a.mul_mod(&t.b, &t.m), t.expected, "mul_mod({:x}, {:x}, {:x})", t.a, t.b, t.m);
2447        }
2448    }
2449
2450    #[test]
2451    fn raw_addition_vectors() {
2452        struct Test {
2453            a: U256,
2454            b: U256,
2455            expected_sum: U256,
2456            expected_carry: u64,
2457        }
2458        let tests = [
2459            Test {
2460                a: U256::ZERO,
2461                b: U256::ZERO,
2462                expected_sum: U256::ZERO,
2463                expected_carry: 0,
2464            },
2465            Test {
2466                a: U256::ZERO,
2467                b: U256::ONE,
2468                expected_sum: U256::ONE,
2469                expected_carry: 0,
2470            },
2471            Test {
2472                a: U256::ONE,
2473                b: U256::ONE,
2474                expected_sum: U256::from_u64(2),
2475                expected_carry: 0,
2476            },
2477            Test {
2478                a: U256::MAX,
2479                b: U256::ZERO,
2480                expected_sum: U256::MAX,
2481                expected_carry: 0,
2482            },
2483            Test {
2484                a: U256::MAX,
2485                b: U256::ONE,
2486                expected_sum: U256::ZERO,
2487                expected_carry: 1,
2488            },
2489            Test {
2490                a: U256::MAX,
2491                b: U256::MAX,
2492                expected_sum: U256::MAX - U256::ONE,
2493                expected_carry: 1,
2494            },
2495            Test {
2496                a: U256::MAX - U256::ONE,
2497                b: U256::ONE,
2498                expected_sum: U256::MAX,
2499                expected_carry: 0,
2500            },
2501            Test {
2502                a: U256::ONE,
2503                b: U256::MAX,
2504                expected_sum: U256::ZERO,
2505                expected_carry: 1,
2506            },
2507            Test {
2508                a: U256::from_limbs([
2509                    0xffff_ffff_ffff_ffff,
2510                    0x0000_0000_0000_0000,
2511                    0x0000_0000_0000_0000,
2512                    0x0000_0000_0000_0000,
2513                ]),
2514                b: U256::ONE,
2515                expected_sum: U256::from_limbs([
2516                    0x0000_0000_0000_0000,
2517                    0x0000_0000_0000_0001,
2518                    0x0000_0000_0000_0000,
2519                    0x0000_0000_0000_0000,
2520                ]),
2521                expected_carry: 0,
2522            },
2523            Test {
2524                a: U256::from_limbs([
2525                    0xffff_ffff_ffff_ffff,
2526                    0xffff_ffff_ffff_ffff,
2527                    0x0000_0000_0000_0000,
2528                    0x0000_0000_0000_0000,
2529                ]),
2530                b: U256::ONE,
2531                expected_sum: U256::from_limbs([
2532                    0x0000_0000_0000_0000,
2533                    0x0000_0000_0000_0000,
2534                    0x0000_0000_0000_0001,
2535                    0x0000_0000_0000_0000,
2536                ]),
2537                expected_carry: 0,
2538            },
2539        ];
2540        for t in &tests {
2541            let (sum, carry) = t.a.add_raw(&t.b);
2542            assert_eq!(sum, t.expected_sum, "add_raw({:x}, {:x}).sum", t.a, t.b);
2543            assert_eq!(carry, t.expected_carry, "add_raw({:x}, {:x}).carry", t.a, t.b);
2544        }
2545    }
2546
2547    #[test]
2548    fn raw_subtraction_vectors() {
2549        struct Test {
2550            a: U256,
2551            b: U256,
2552            expected_diff: U256,
2553            expected_borrow: u64,
2554        }
2555        let tests = [
2556            Test {
2557                a: U256::ZERO,
2558                b: U256::ZERO,
2559                expected_diff: U256::ZERO,
2560                expected_borrow: 0,
2561            },
2562            Test {
2563                a: U256::ONE,
2564                b: U256::ZERO,
2565                expected_diff: U256::ONE,
2566                expected_borrow: 0,
2567            },
2568            Test {
2569                a: U256::ONE,
2570                b: U256::ONE,
2571                expected_diff: U256::ZERO,
2572                expected_borrow: 0,
2573            },
2574            Test {
2575                a: U256::ZERO,
2576                b: U256::ONE,
2577                expected_diff: U256::MAX,
2578                expected_borrow: 1,
2579            },
2580            Test {
2581                a: U256::MAX,
2582                b: U256::MAX,
2583                expected_diff: U256::ZERO,
2584                expected_borrow: 0,
2585            },
2586            Test {
2587                a: U256::MAX,
2588                b: U256::ZERO,
2589                expected_diff: U256::MAX,
2590                expected_borrow: 0,
2591            },
2592            Test {
2593                a: U256::MAX,
2594                b: U256::MAX - U256::ONE,
2595                expected_diff: U256::ONE,
2596                expected_borrow: 0,
2597            },
2598            Test {
2599                a: U256::ONE,
2600                b: U256::MAX,
2601                expected_diff: U256::from_u64(2),
2602                expected_borrow: 1,
2603            },
2604        ];
2605        for t in &tests {
2606            let (diff, borrow) = t.a.sub_raw(&t.b);
2607            assert_eq!(diff, t.expected_diff, "sub_raw({:x}, {:x}).diff", t.a, t.b);
2608            assert_eq!(borrow, t.expected_borrow, "sub_raw({:x}, {:x}).borrow", t.a, t.b);
2609        }
2610    }
2611
2612    #[test]
2613    fn string_roundtrip_vectors() {
2614        struct Test {
2615            value: U256,
2616            radix: u32,
2617            expected: &'static str,
2618        }
2619        let tests = [
2620            Test {
2621                value: U256::ZERO,
2622                radix: 2,
2623                expected: "0",
2624            },
2625            Test {
2626                value: U256::ZERO,
2627                radix: 10,
2628                expected: "0",
2629            },
2630            Test {
2631                value: U256::ZERO,
2632                radix: 16,
2633                expected: "0",
2634            },
2635            Test {
2636                value: U256::ONE,
2637                radix: 2,
2638                expected: "1",
2639            },
2640            Test {
2641                value: U256::ONE,
2642                radix: 10,
2643                expected: "1",
2644            },
2645            Test {
2646                value: U256::ONE,
2647                radix: 16,
2648                expected: "1",
2649            },
2650            Test {
2651                value: U256::MAX,
2652                radix: 10,
2653                expected: "115792089237316195423570985008687907853269984665640564039457584007913129639935",
2654            },
2655            Test {
2656                value: U256::MAX,
2657                radix: 16,
2658                expected: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
2659            },
2660            Test {
2661                value: P256_MODULUS,
2662                radix: 10,
2663                expected: "115792089210356248762697446949407573530086143415290314195533631308867097853951",
2664            },
2665            Test {
2666                value: P256_MODULUS,
2667                radix: 16,
2668                expected: "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
2669            },
2670            Test {
2671                value: P256_ORDER,
2672                radix: 10,
2673                expected: "115792089210356248762697446949407573529996955224135760342422259061068512044369",
2674            },
2675            Test {
2676                value: P256_ORDER,
2677                radix: 16,
2678                expected: "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
2679            },
2680            Test {
2681                value: ED25519_P,
2682                radix: 10,
2683                expected: "57896044618658097711785492504343953926634992332820282019728792003956564819949",
2684            },
2685            Test {
2686                value: ED25519_P,
2687                radix: 16,
2688                expected: "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed",
2689            },
2690        ];
2691        for t in &tests {
2692            let encoded = t.value.to_string_radix(t.radix);
2693            assert_eq!(encoded, t.expected, "to_string_radix({:x}, {})", t.value, t.radix);
2694            let decoded = U256::from_str_radix(t.expected, t.radix).unwrap();
2695            assert_eq!(decoded, t.value, "from_str_radix round-trip");
2696        }
2697    }
2698
2699    #[test]
2700    fn mul_mod_edge_cases() {
2701        assert_eq!(P256_P_PLUS_ONE_OVER_FOUR.mul_mod(&U256::from_u64(4), &P256_MODULUS), U256::ONE);
2702
2703        let (a, _) = U256::MAX.mul_word(2);
2704        assert_eq!(a.add_mod(&U256::ZERO, &P256_MODULUS), U256::MAX.double_mod(&P256_MODULUS));
2705    }
2706
2707    // P-256 generator point coordinates (NIST SP 800-186 / RFC 6979).
2708    // Test vectors generated with Python: `hex((Gx * Gy) % p256_p)` etc.
2709    const P256_GX: U256 = U256::from_be_slice_const(
2710        0x6b17d1f2, 0xe12c4247, 0xf8bce6e5, 0x63a440f2, 0x77037d81, 0x2deb33a0, 0xf4a13945, 0xd898c296,
2711    );
2712    const P256_GY: U256 = U256::from_be_slice_const(
2713        0x4fe342e2, 0xfe1a7f9b, 0x8ee7eb4a, 0x7c0f9e16, 0x2bce3357, 0x6b315ece, 0xcbb64068, 0x37bf51f5,
2714    );
2715
2716    impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
2717        // Helper to build a 256-bit constant from eight 32-bit big-endian words.
2718        // Only valid for BITS=256, LIMBS=4; used only in test helpers.
2719        const fn from_be_slice_const(w7: u32, w6: u32, w5: u32, w4: u32, w3: u32, w2: u32, w1: u32, w0: u32) -> Self {
2720            let limb3 = ((w7 as u64) << 32) | (w6 as u64);
2721            let limb2 = ((w5 as u64) << 32) | (w4 as u64);
2722            let limb1 = ((w3 as u64) << 32) | (w2 as u64);
2723            let limb0 = ((w1 as u64) << 32) | (w0 as u64);
2724            let limbs = [0u64; LIMBS];
2725            if LIMBS > 0 {
2726                let mut l = [0u64; LIMBS];
2727                l[0] = limb0;
2728                l[1] = limb1;
2729                l[2] = limb2;
2730                l[3] = limb3;
2731                return Self {
2732                    limbs: l,
2733                };
2734            }
2735            Self {
2736                limbs,
2737            }
2738        }
2739    }
2740
2741    #[test]
2742    fn p256_mul_mod_with_generator_coordinates() {
2743        // Vectors verified with Python's arbitrary-precision arithmetic.
2744        let gx_gy_mod_p = U256::from_be_slice(&decode_hex::<32>(
2745            "823cd15f6dd3c71933565064513a6b2bd183e554c6a08622f713ebbbface98be",
2746        ));
2747        let gx_sq_mod_p = U256::from_be_slice(&decode_hex::<32>(
2748            "98f6b84d29bef2b281819a5e0e3690d833b699495d694dd1002ae56c426b3f8c",
2749        ));
2750        let gy_sq_mod_p = U256::from_be_slice(&decode_hex::<32>(
2751            "55df5d5850f47bad82149139979369fe498a9022a412b5e0bedd2cfc21c3ed91",
2752        ));
2753
2754        assert_eq!(P256_GX.mul_mod(&P256_GY, &P256_MODULUS), gx_gy_mod_p, "Gx*Gy mod p");
2755        // Commutativity
2756        assert_eq!(
2757            P256_GY.mul_mod(&P256_GX, &P256_MODULUS),
2758            gx_gy_mod_p,
2759            "Gy*Gx mod p (commutativity)"
2760        );
2761        assert_eq!(P256_GX.mul_mod(&P256_GX, &P256_MODULUS), gx_sq_mod_p, "Gx^2 mod p");
2762        assert_eq!(P256_GY.mul_mod(&P256_GY, &P256_MODULUS), gy_sq_mod_p, "Gy^2 mod p");
2763    }
2764
2765    #[test]
2766    fn p256_add_sub_mod_with_generator_coordinates() {
2767        // Gx + Gy mod p256_p  (Python: hex((Gx + Gy) % p))
2768        let gx_plus_gy = U256::from_be_slice(&decode_hex::<32>(
2769            "bafb14d5df46c1e387a4d22fdfb3df08a2d1b0d8991c926fc05779ae1058148b",
2770        ));
2771        // Gx - Gy mod p256_p  (Python: hex((Gx - Gy) % p))
2772        let gx_minus_gy = U256::from_be_slice(&decode_hex::<32>(
2773            "1b348f0fe311c2ac69d4fb9ae794a2dc4b354a29c2b9d4d228eaf8dda0d970a1",
2774        ));
2775        // Gy - Gx mod p256_p
2776        let gy_minus_gx = U256::from_be_slice(&decode_hex::<32>(
2777            "e4cb70ef1cee3d54962b0465186b5d23b4cab5d73d462b2dd71507225f268f5e",
2778        ));
2779
2780        assert_eq!(P256_GX.add_mod(&P256_GY, &P256_MODULUS), gx_plus_gy);
2781        assert_eq!(P256_GX.sub_mod(&P256_GY, &P256_MODULUS), gx_minus_gy);
2782        assert_eq!(P256_GY.sub_mod(&P256_GX, &P256_MODULUS), gy_minus_gx);
2783        // (a-b) + (b-a) = 0 mod p
2784        assert_eq!(gx_minus_gy.add_mod(&gy_minus_gx, &P256_MODULUS), U256::ZERO);
2785    }
2786
2787    #[test]
2788    fn bit_access() {
2789        // Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
2790        // Bit 0: the LSB of limb[0] = 0x...96 → bit 0 = 0
2791        assert!(!P256_GX.bit(0), "bit 0 of Gx");
2792        assert!(P256_GX.bit(1), "bit 1 of Gx");
2793        assert!(P256_GX.bit(2), "bit 2 of Gx");
2794        assert!(P256_GX.bit(63), "bit 63 of Gx");
2795        assert!(!P256_GX.bit(64), "bit 64 of Gx");
2796        assert!(!P256_GX.bit(65), "bit 65 of Gx");
2797        assert!(!P256_GX.bit(127), "bit 127 of Gx");
2798        assert!(!P256_GX.bit(128), "bit 128 of Gx");
2799        assert!(P256_GX.bit(192), "bit 192 of Gx");
2800        assert!(!P256_GX.bit(255), "bit 255 of Gx");
2801        // Out-of-range bit is false
2802        assert!(!P256_GX.bit(256), "bit 256 (out of range) of Gx");
2803
2804        // p256_p: all-ones in low 64 bits → bit 0 is 1
2805        assert!(P256_MODULUS.bit(0), "bit 0 of p256_p");
2806        assert!(P256_MODULUS.bit(63), "bit 63 of p256_p");
2807        assert!(P256_MODULUS.bit(64), "bit 64 of p256_p");
2808        assert!(!P256_MODULUS.bit(96), "bit 96 of p256_p");
2809        assert!(P256_MODULUS.bit(255), "bit 255 of p256_p");
2810
2811        assert!(!U256::ZERO.bit(0));
2812        assert!(!U256::ZERO.bit(255));
2813        assert!(U256::ONE.bit(0));
2814        assert!(!U256::ONE.bit(1));
2815        assert!(U256::MAX.bit(0));
2816        assert!(U256::MAX.bit(255));
2817    }
2818
2819    #[test]
2820    fn is_odd_flag() {
2821        assert!(!U256::ZERO.is_odd(), "0 is even");
2822        assert!(U256::ONE.is_odd(), "1 is odd");
2823        assert!(!U256::from_u64(2).is_odd(), "2 is even");
2824        assert!(U256::from_u64(3).is_odd(), "3 is odd");
2825        assert!(P256_MODULUS.is_odd(), "p256_p is odd");
2826        assert!(P256_ORDER.is_odd(), "p256_n is odd");
2827        assert!(!P256_GX.is_odd(), "Gx is even");
2828        assert!(P256_GY.is_odd(), "Gy is odd");
2829        assert!(U256::MAX.is_odd(), "MAX is odd");
2830    }
2831
2832    #[test]
2833    fn ct_ge_comprehensive() {
2834        let zero = U256::ZERO;
2835        let one = U256::ONE;
2836        let max = U256::MAX;
2837
2838        // Equal values
2839        assert!(zero.ct_ge(&zero), "0 >= 0");
2840        assert!(one.ct_ge(&one), "1 >= 1");
2841        assert!(max.ct_ge(&max), "MAX >= MAX");
2842        assert!(P256_MODULUS.ct_ge(&P256_MODULUS), "p >= p");
2843
2844        // Strict greater
2845        assert!(one.ct_ge(&zero), "1 >= 0");
2846        assert!(max.ct_ge(&zero), "MAX >= 0");
2847        assert!(max.ct_ge(&one), "MAX >= 1");
2848        assert!(P256_GX.ct_ge(&zero), "Gx >= 0");
2849
2850        // Strict less
2851        assert!(!zero.ct_ge(&one), "NOT 0 >= 1");
2852        assert!(!zero.ct_ge(&max), "NOT 0 >= MAX");
2853        assert!(!one.ct_ge(&max), "NOT 1 >= MAX");
2854        assert!(!P256_GX.ct_ge(&max), "NOT Gx >= MAX");
2855
2856        // Adjacent values
2857        assert!((P256_MODULUS - U256::ONE).ct_ge(&(P256_MODULUS - U256::from_u64(2))));
2858        assert!(!P256_MODULUS.sub_mod(&U256::ONE, &P256_MODULUS).ct_ge(&P256_MODULUS));
2859    }
2860
2861    #[test]
2862    fn div_rem_word_vectors() {
2863        // Vectors generated with Python: p256_p / divisor
2864        // p256_p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
2865        struct Test {
2866            dividend: U256,
2867            divisor: u64,
2868            expected_quotient: U256,
2869            expected_rem: u64,
2870        }
2871        let tests = [
2872            Test {
2873                dividend: P256_MODULUS,
2874                divisor: 1,
2875                expected_quotient: P256_MODULUS,
2876                expected_rem: 0,
2877            },
2878            Test {
2879                dividend: P256_MODULUS,
2880                divisor: 2,
2881                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2882                    "7fffffff800000008000000000000000000000007fffffffffffffffffffffff",
2883                )),
2884                expected_rem: 1,
2885            },
2886            Test {
2887                dividend: P256_MODULUS,
2888                divisor: 10,
2889                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2890                    "1999999980000000199999999999999999999999b33333333333333333333333",
2891                )),
2892                expected_rem: 1,
2893            },
2894            Test {
2895                dividend: P256_MODULUS,
2896                divisor: 16,
2897                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2898                    "0ffffffff00000001000000000000000000000000fffffffffffffffffffffff",
2899                )),
2900                expected_rem: 0xf,
2901            },
2902            Test {
2903                dividend: P256_MODULUS,
2904                divisor: 0xffff_ffff,
2905                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2906                    "0000000100000000000000010000000100000001000000020000000200000002",
2907                )),
2908                expected_rem: 1,
2909            },
2910            Test {
2911                dividend: P256_MODULUS,
2912                divisor: 0x1_0000_0000,
2913                expected_quotient: U256::from_be_slice(&decode_hex::<32>(
2914                    "00000000ffffffff00000001000000000000000000000000ffffffffffffffff",
2915                )),
2916                expected_rem: 0xffff_ffff,
2917            },
2918            Test {
2919                dividend: U256::ZERO,
2920                divisor: 7,
2921                expected_quotient: U256::ZERO,
2922                expected_rem: 0,
2923            },
2924            Test {
2925                dividend: U256::ONE,
2926                divisor: 7,
2927                expected_quotient: U256::ZERO,
2928                expected_rem: 1,
2929            },
2930            Test {
2931                dividend: U256::from_u64(100),
2932                divisor: 7,
2933                expected_quotient: U256::from_u64(14),
2934                expected_rem: 2,
2935            },
2936        ];
2937        for t in &tests {
2938            let (q, r) = t.dividend.div_rem_word(t.divisor);
2939            assert_eq!(q, t.expected_quotient, "div_rem_word({:x}, {}).quotient", t.dividend, t.divisor);
2940            assert_eq!(r, t.expected_rem, "div_rem_word({:x}, {}).rem", t.dividend, t.divisor);
2941        }
2942    }
2943
2944    #[test]
2945    fn add_word_vectors() {
2946        // Vectors: Python hex(Gx + k) for small k
2947        let gx = P256_GX;
2948        let gx_plus_1 = U256::from_be_slice(&decode_hex::<32>(
2949            "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c297",
2950        ));
2951        let gx_minus_1 = U256::from_be_slice(&decode_hex::<32>(
2952            "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c295",
2953        ));
2954
2955        let (sum, carry) = gx.add_word(1);
2956        assert_eq!(sum, gx_plus_1, "Gx + 1");
2957        assert_eq!(carry, 0);
2958
2959        let (diff, borrow) = gx.sub_word(1);
2960        assert_eq!(diff, gx_minus_1, "Gx - 1");
2961        assert_eq!(borrow, 0);
2962
2963        // Adding to MAX wraps
2964        let (sum_max, carry_max) = U256::MAX.add_word(1);
2965        assert_eq!(sum_max, U256::ZERO);
2966        assert_eq!(carry_max, 1);
2967
2968        // Subtracting from ZERO borrows
2969        let (diff_zero, borrow_zero) = U256::ZERO.sub_word(1);
2970        assert_eq!(diff_zero, U256::MAX);
2971        assert_eq!(borrow_zero, 1);
2972
2973        // Word that carries across limb boundary: 2^64 - 1 + 1
2974        let val = U256::from_u64(u64::MAX);
2975        let (sum2, carry2) = val.add_word(1);
2976        assert_eq!(sum2, U256::from_limbs([0, 1, 0, 0]));
2977        assert_eq!(carry2, 0);
2978    }
2979
2980    #[test]
2981    fn mul_word_vectors() {
2982        // Gx * 2 = 2*Gx (no overflow since Gx < 2^255)
2983        // Python: hex(Gx * 2)
2984        let gx_times_2 = U256::from_be_slice(&decode_hex::<32>(
2985            "d62fa3e5c258848ff179cdcac74881e4ee06fb025bd66741e942728bb131852c",
2986        ));
2987        let (prod, carry) = P256_GX.mul_word(2);
2988        assert_eq!(prod, gx_times_2, "Gx * 2");
2989        assert_eq!(carry, 0, "Gx * 2 carry");
2990
2991        // MAX * 2 = 2^256 - 2: low 256 bits = all-ones XOR 1, overflow carry = 1
2992        let (prod_max, carry_max) = U256::MAX.mul_word(2);
2993        assert_eq!(prod_max, U256::from_limbs([u64::MAX - 1, u64::MAX, u64::MAX, u64::MAX]));
2994        assert_eq!(carry_max, 1);
2995
2996        // ONE * 0 = 0
2997        let (zero_prod, zero_carry) = U256::ONE.mul_word(0);
2998        assert_eq!(zero_prod, U256::ZERO);
2999        assert_eq!(zero_carry, 0);
3000
3001        // from_u64(10) * from_u64(10) (single-word)
3002        let (p, c) = U128::from_u64(u64::MAX).mul_word(u64::MAX);
3003        // u64::MAX * u64::MAX = 2^128 - 2^65 + 1 = (2^64-1)^2
3004        // low 64 bits = 1, high 64 bits = u64::MAX - 1
3005        assert_eq!(p, U128::from_limbs([1, u64::MAX - 1]));
3006        assert_eq!(c, 0);
3007    }
3008
3009    #[test]
3010    fn fibonacci_number_round_trip() {
3011        // Fib(100) = 354224848179261915075
3012        // hex: 0x1333db76a7c594bfc3
3013        // Verified with Python: `a, b = 0, 1; [a, b = b, a+b for _ in range(100)]; print(a)`
3014        let fib100_dec = "354224848179261915075";
3015        let fib100_hex = "1333db76a7c594bfc3";
3016
3017        let from_dec = U128::from_str_radix(fib100_dec, 10).unwrap();
3018        let from_hex = U128::from_str_radix(fib100_hex, 16).unwrap();
3019
3020        assert_eq!(from_dec, from_hex, "Fib(100) from decimal == from hex");
3021        assert_eq!(from_dec.to_string_radix(10), fib100_dec);
3022        assert_eq!(from_dec.to_string_radix(16), fib100_hex);
3023
3024        // Fib(100) in binary
3025        let fib100_bin = from_dec.to_string_radix(2);
3026        let from_bin = U128::from_str_radix(&fib100_bin, 2).unwrap();
3027        assert_eq!(from_bin, from_dec);
3028
3029        // Octal round-trip
3030        let fib100_oct = from_dec.to_string_radix(8);
3031        let from_oct = U128::from_str_radix(&fib100_oct, 8).unwrap();
3032        assert_eq!(from_oct, from_dec);
3033    }
3034
3035    #[test]
3036    fn display_and_debug_formatting() {
3037        // Display uses decimal
3038        assert_eq!(format!("{}", U256::ZERO), "0");
3039        assert_eq!(format!("{}", U256::ONE), "1");
3040        assert_eq!(
3041            format!("{}", U256::MAX),
3042            "115792089237316195423570985008687907853269984665640564039457584007913129639935"
3043        );
3044        assert_eq!(
3045            format!("{}", P256_MODULUS),
3046            "115792089210356248762697446949407573530086143415290314195533631308867097853951"
3047        );
3048
3049        // LowerHex
3050        assert_eq!(format!("{:x}", U256::ZERO), "0");
3051        assert_eq!(format!("{:x}", U256::ONE), "1");
3052        assert_eq!(
3053            format!("{:x}", U256::MAX),
3054            "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
3055        );
3056        assert_eq!(format!("{:#x}", U256::from_u64(255)), "0xff");
3057
3058        // UpperHex
3059        assert_eq!(format!("{:X}", U256::ZERO), "0");
3060        assert_eq!(
3061            format!("{:X}", P256_MODULUS),
3062            "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
3063        );
3064        assert_eq!(format!("{:#X}", U256::from_u64(255)), "0xFF");
3065
3066        // Debug
3067        assert_eq!(format!("{:?}", U256::ZERO), "Uint(0x0)");
3068        assert_eq!(format!("{:?}", U256::ONE), "Uint(0x1)");
3069        assert_eq!(
3070            format!("{:?}", P256_MODULUS),
3071            "Uint(0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff)"
3072        );
3073    }
3074
3075    #[test]
3076    fn to_be_le_bytes_vec() {
3077        // Verify Vec<u8> output matches fixed-size output
3078        let values = [U256::ZERO, U256::ONE, U256::MAX, P256_MODULUS, P256_GX, P256_GY];
3079        for v in &values {
3080            let be_vec = v.to_be_bytes();
3081            let be_fixed = v.to_be_bytes_fixed::<32>();
3082            assert_eq!(be_vec.as_slice(), be_fixed.as_slice(), "BE bytes of {:x}", v);
3083
3084            let le_vec = v.to_le_bytes();
3085            let le_fixed = v.to_le_bytes_fixed::<32>();
3086            assert_eq!(le_vec.as_slice(), le_fixed.as_slice(), "LE bytes of {:x}", v);
3087
3088            // Round-trip through be
3089            let rt_be = U256::from_be_slice(&be_vec);
3090            assert_eq!(rt_be, *v, "BE round-trip of {:x}", v);
3091
3092            // Round-trip through le
3093            let rt_le = U256::from_le_slice(&le_vec);
3094            assert_eq!(rt_le, *v, "LE round-trip of {:x}", v);
3095        }
3096    }
3097
3098    #[test]
3099    fn max_for_non_64_multiple_bits() {
3100        // Uint<130, 3>: LIMBS=3, top limb should have only bits 0-1 set.
3101        // MAX = 2^130 - 1:
3102        //   limb[0] = 2^64 - 1
3103        //   limb[1] = 2^64 - 1
3104        //   limb[2] = 0b11 = 3  (only 2 bits, since 130 % 64 = 2)
3105        type U130 = Uint<130, 3>;
3106        let max = U130::MAX;
3107        assert_eq!(max.limbs[0], u64::MAX, "U130::MAX limb[0]");
3108        assert_eq!(max.limbs[1], u64::MAX, "U130::MAX limb[1]");
3109        assert_eq!(max.limbs[2], 0b11, "U130::MAX limb[2] should have only 2 bits set");
3110
3111        // Uint<192, 3>: 192 = 3*64, all limbs should be u64::MAX
3112        type U192 = Uint<192, 3>;
3113        let max192 = U192::MAX;
3114        assert_eq!(max192.limbs[0], u64::MAX, "U192::MAX limb[0]");
3115        assert_eq!(max192.limbs[1], u64::MAX, "U192::MAX limb[1]");
3116        assert_eq!(max192.limbs[2], u64::MAX, "U192::MAX limb[2]");
3117
3118        // Uint<65, 2>: top limb should have only 1 bit set
3119        type U65 = Uint<65, 2>;
3120        let max65 = U65::MAX;
3121        assert_eq!(max65.limbs[0], u64::MAX, "U65::MAX limb[0]");
3122        assert_eq!(max65.limbs[1], 1, "U65::MAX limb[1] should be 1 (bit 64 only)");
3123    }
3124
3125    #[test]
3126    fn mul_mod_associativity_and_identity() {
3127        // (a * b) * c == a * (b * c) mod p
3128        let a = P256_GX;
3129        let b = P256_GY;
3130        let c = P256_MODULUS - U256::ONE;
3131        let m = P256_MODULUS;
3132
3133        let ab = a.mul_mod(&b, &m);
3134        let bc = b.mul_mod(&c, &m);
3135
3136        assert_eq!(ab.mul_mod(&c, &m), a.mul_mod(&bc, &m), "associativity");
3137
3138        // Identity: a * 1 = a
3139        assert_eq!(a.mul_mod(&U256::ONE, &m), a, "a * 1 = a");
3140        assert_eq!(U256::ONE.mul_mod(&a, &m), a, "1 * a = a");
3141
3142        // Zero: a * 0 = 0
3143        assert_eq!(a.mul_mod(&U256::ZERO, &m), U256::ZERO, "a * 0 = 0");
3144        assert_eq!(U256::ZERO.mul_mod(&a, &m), U256::ZERO, "0 * a = 0");
3145
3146        // Distributivity: (a + b) * c == a*c + b*c mod p
3147        let ab_sum = a.add_mod(&b, &m);
3148        let lhs = ab_sum.mul_mod(&c, &m);
3149        let rhs = a.mul_mod(&c, &m).add_mod(&b.mul_mod(&c, &m), &m);
3150        assert_eq!(lhs, rhs, "distributivity");
3151    }
3152
3153    #[test]
3154    fn mul_mod_barrett_agrees_with_mul_mod() {
3155        // Already tested in ed25519; verify single multiplication works
3156        type U256 = Uint<256, 4>;
3157        let a = U256::from_u64(7);
3158        let b = U256::from_u64(11);
3159        let m = U256::from_limbs([
3160            0xffff_ffff_ffff_ffff,
3161            0x0000_0000_ffff_ffff,
3162            0x0000_0000_0000_0000,
3163            0xffff_ffff_0000_0001,
3164        ]);
3165        let mu = m.compute_mu_for_barrett();
3166        let barrett = a.mul_mod_barrett(&b, &m, &mu);
3167        let standard = a.mul_mod(&b, &m);
3168        assert_eq!(barrett, standard);
3169    }
3170
3171    #[test]
3172    fn modpow_barrett_agrees_with_modpow() {
3173        type U256 = Uint<256, 4>;
3174        // Use P-256 prime so eff_limbs == LIMBS (4 == 4) → takes Barrett path
3175        let m = U256::from_limbs([
3176            0xffff_ffff_ffff_ffff,
3177            0x0000_0000_ffff_ffff,
3178            0x0000_0000_0000_0000,
3179            0xffff_ffff_0000_0001,
3180        ]);
3181        let mu = m.compute_mu_for_barrett();
3182
3183        // 3^5 mod m
3184        let base = U256::from_u64(3);
3185        let exp = U256::from_u64(5);
3186        let barrett = base.modpow_barrett(&exp, &m, &mu);
3187        let standard = base.modpow(&exp, &m);
3188        assert_eq!(barrett, standard, "3^5 mod P256");
3189
3190        // 2^10 mod m
3191        let base = U256::from_u64(2);
3192        let exp = U256::from_u64(10);
3193        let barrett = base.modpow_barrett(&exp, &m, &mu);
3194        let standard = base.modpow(&exp, &m);
3195        assert_eq!(barrett, standard, "2^10 mod P256");
3196
3197        // 123 ^ 456 mod m
3198        let base = U256::from_u64(123);
3199        let exp = U256::from_u64(456);
3200        let barrett = base.modpow_barrett(&exp, &m, &mu);
3201        let standard = base.modpow(&exp, &m);
3202        assert_eq!(barrett, standard, "123^456 mod P256");
3203
3204        // base == m (should give 0)
3205        let base = m;
3206        let exp = U256::from_u64(5);
3207        let barrett = base.modpow_barrett(&exp, &m, &mu);
3208        let standard = base.modpow(&exp, &m);
3209        assert_eq!(barrett, U256::ZERO, "m^5 mod m should be 0");
3210        assert_eq!(barrett, standard);
3211
3212        // exp == 0 (should give 1)
3213        let base = U256::from_u64(123);
3214        let exp = U256::from_u64(0);
3215        let barrett = base.modpow_barrett(&exp, &m, &mu);
3216        let standard = base.modpow(&exp, &m);
3217        assert_eq!(barrett, standard, "123^0 mod P256");
3218        assert_eq!(barrett, U256::ONE, "123^0 mod P256 should be 1");
3219    }
3220
3221    #[test]
3222    fn barrett_reduction_comprehensive() {
3223        type U256 = Uint<256, 4>;
3224        let m = U256::from_limbs([
3225            0xffff_ffff_ffff_ffff,
3226            0x0000_0000_ffff_ffff,
3227            0x0000_0000_0000_0000,
3228            0xffff_ffff_0000_0001,
3229        ]);
3230        let mu = m.compute_mu_for_barrett();
3231
3232        // mul_mod_barrett should match mul_mod for various inputs
3233        for i in 0..100 {
3234            let a = U256::from_limbs([
3235                (i * 1234567 + 1) as u64,
3236                (i * 7654321 + 2) as u64,
3237                (i * 1357924 + 3) as u64,
3238                (i * 2468013 + 4) as u64,
3239            ]);
3240            let b = U256::from_limbs([
3241                (i * 9876543 + 5) as u64,
3242                (i * 3456789 + 6) as u64,
3243                (i * 567899 + 7) as u64,
3244                (i * 1122334 + 8) as u64,
3245            ]);
3246            let expected = a.mul_mod(&b, &m);
3247            let barrett = a.mul_mod_barrett(&b, &m, &mu);
3248            assert_eq!(barrett, expected, "mul_mod_barrett vs mul_mod iteration {i}");
3249        }
3250
3251        // Edge case: (m-1)^2 mod m should be 1
3252        let (am1, _) = m.sub_word(1);
3253        let barrett = am1.mul_mod_barrett(&am1, &m, &mu);
3254        let expected = am1.mul_mod(&am1, &m);
3255        assert_eq!(barrett, expected, "(m-1)^2 mod m");
3256    }
3257
3258    #[test]
3259    fn barrett_modpow_step_trace() {
3260        type U256 = Uint<256, 4>;
3261        let m = U256::from_limbs([
3262            0xffff_ffff_ffff_ffff,
3263            0x0000_0000_ffff_ffff,
3264            0x0000_0000_0000_0000,
3265            0xffff_ffff_0000_0001,
3266        ]);
3267        let mu = m.compute_mu_for_barrett();
3268
3269        // Trace through 123^4 step by step
3270        let a = U256::from_u64(123);
3271
3272        // Step 1: base = 123 * 1 mod m = 123
3273        let base1 = a.mul_mod_barrett(&U256::ONE, &m, &mu);
3274        assert_eq!(base1, U256::from_u64(123), "step1: self*1 mod m");
3275
3276        // Step 2: result = 1, base = 123
3277        // Iterate with exp=4 (100b), LSB first:
3278        // i=0: bit=0 → result unchanged, base = 123*123 mod m
3279        let a2 = base1.mul_mod_barrett(&base1, &m, &mu);
3280        let a2_expected = a.mul_mod(&a, &m);
3281        assert_eq!(a2, a2_expected, "123*123 mod m");
3282
3283        // i=1: bit=0 → result unchanged, base = a2*a2 mod m
3284        let a4 = a2.mul_mod_barrett(&a2, &m, &mu);
3285        let a4_expected = a2.mul_mod(&a2, &m);
3286        assert_eq!(a4, a4_expected, "123^2*123^2 mod m");
3287
3288        // i=2: bit=1 → result = 1 * base = a4, base = a4*a4 mod m
3289        let a8 = a4.mul_mod_barrett(&a4, &m, &mu);
3290        let result_bit2 = a4.mul_mod_barrett(&U256::ONE, &m, &mu);
3291        assert_eq!(result_bit2, a4, "result after bit 2");
3292        let a8_expected = a4.mul_mod(&a4, &m);
3293        assert_eq!(a8, a8_expected, "123^4*123^4 mod m");
3294
3295        // final result should be a4 (since 4=100b, only bit 2 set)
3296        let final_barrett = a.modpow_barrett(&U256::from_u64(4), &m, &mu);
3297        let final_expected = a.modpow(&U256::from_u64(4), &m);
3298        assert_eq!(final_barrett, final_expected, "123^4 mod m via modpow_barrett");
3299    }
3300}