/root/kaspa/kaspa-fuzz/rusty-kaspa/math/src/lehmer.rs
Line
Count
Source
1
//! Variable-time modular inversion via Lehmer's extended-GCD algorithm, fully
2
//! stack-allocated and generic over the operand width (little-endian base-2^64
3
//! limbs). [`LehmerInvert::lehmer_invert`] is the entry point, available on
4
//! every `construct_uint!` type and on primitive `u64`/`u128` (whose native
5
//! division doubles as a reference oracle in tests and fuzzing); the production
6
//! user is the 3072-bit MuHash element.
7
//!
8
//! This is a *Euclidean* extended GCD (true quotients), not the binary
9
//! Bernstein-Yang "safegcd" divstep. The distinction matters: safegcd divides by
10
//! 2 each step, so its cofactors carry a `2^-62k` factor that must be paid down
11
//! with a full-width modular reduction every round, whereas a Euclidean GCD keeps
12
//! a single cofactor pair of clean integers that grow gradually (~`n/2` limbs on
13
//! average) and need only one sign fixup at the end.
14
//!
15
//! Outer loop ([`invert`]): each iteration extracts a 2x2 reduction matrix from
16
//! the aligned top *two* words of the two remainders (the half-GCD guess
17
//! [`hgcd2`]) and applies it to the full remainders ([`apply_matrix_xy`]) and to
18
//! the cofactor pair ([`apply_matrix_t`]), peeling ~62 bits per matrix (~50
19
//! matrices for a 3072-bit inverse). When the guess cannot confirm even one
20
//! quotient it falls back to a single exact Euclidean division step.
21
//!
22
//! The guess ([`hgcd2`]) works on the top two `u64` words: a quotient of 1 is
23
//! resolved by one two-word subtraction and a top-word compare, so a hardware
24
//! divide is needed only for `q >= 2`. A trailing half-limb refinement keeps
25
//! every matrix entry below `2^63`, so the matrix-apply accumulators never
26
//! overflow and carry no per-step guard.
27
//!
28
//! Sign convention: track only `(t0, t1)`, the cofactor of `value`, kept
29
//! non-negative and growing; flip a `swapped` flag on each Euclidean swap and
30
//! recover the answer's sign from it at exit.
31
//!
32
//! Algorithm: Knuth, TAOCP Vol. 2, sec. 4.5.2, Algorithm L. Adapted from the
33
//! MIT-licensed 256-bit implementation by Dean Little (Copyright (c) 2026 Dean
34
//! Little, <https://github.com/blueshift-gg/solana-secp256k1>, `src/lehmer.rs`),
35
//! generalized to arbitrary limb counts with a two-word half-GCD guess. Uses
36
//! native `u128`/`i128` accumulators plus the uint type's own division
37
//! ([`LehmerOps::div_rem`]) for the rare multi-limb-divisor fallback; no
38
//! external dependency.
39
//!
40
//! The limb loops are generic over the concrete `[u64; N]` buffer types
41
//! ([`LimbArray`]) rather than slices, so each width monomorphizes with
42
//! compile-time trip counts and elided bounds checks, keeping the 3072-bit
43
//! codegen equivalent to the pre-generalization fixed-width version (kept
44
//! frozen in `benches/support/lehmer_fixed48.rs` for A/B comparison).
45
46
use core::cmp::Ordering;
47
48
/// Diagnostics-only per-inverse operation counters (enabled with the
49
/// `lehmer-instrument` feature). Used by `examples/lehmer_stats.rs` to measure
50
/// the work distribution. No effect on the production path.
51
#[cfg(feature = "lehmer-instrument")]
52
pub mod instrument {
53
    use core::sync::atomic::AtomicU64;
54
    pub static MATRICES: AtomicU64 = AtomicU64::new(0);
55
    pub static FALLBACK_STEPS: AtomicU64 = AtomicU64::new(0);
56
    pub static DIVIDES: AtomicU64 = AtomicU64::new(0);
57
    pub static APPLY_XY_LIMBS: AtomicU64 = AtomicU64::new(0);
58
    pub static APPLY_T_LIMBS: AtomicU64 = AtomicU64::new(0);
59
    pub static SWAPS: AtomicU64 = AtomicU64::new(0);
60
    pub static INVERSES: AtomicU64 = AtomicU64::new(0);
61
    pub static GCD_DIV_NORM: AtomicU64 = AtomicU64::new(0);
62
}
63
64
macro_rules! count {
65
    ($name:ident += $v:expr) => {{
66
        #[cfg(feature = "lehmer-instrument")]
67
        instrument::$name.fetch_add($v, core::sync::atomic::Ordering::Relaxed);
68
    }};
69
}
70
71
// Invariant checks: `debug_assert!` by default (free in release), promoted to
72
// always-on `assert!` under the `strict-asserts` feature so optimized fuzz and
73
// test builds verify every invariant regardless of `debug-assertions`.
74
#[cfg(not(feature = "strict-asserts"))]
75
macro_rules! strict_assert {
76
    ($($arg:tt)*) => { debug_assert!($($arg)*) };
77
}
78
#[cfg(feature = "strict-asserts")]
79
macro_rules! strict_assert {
80
    ($($arg:tt)*) => { assert!($($arg)*) };
81
}
82
#[cfg(not(feature = "strict-asserts"))]
83
macro_rules! strict_assert_eq {
84
    ($($arg:tt)*) => { debug_assert_eq!($($arg)*) };
85
}
86
#[cfg(feature = "strict-asserts")]
87
macro_rules! strict_assert_eq {
88
    ($($arg:tt)*) => { assert_eq!($($arg)*) };
89
}
90
91
/// Fixed-size little-endian limb buffer, blanket-implemented for every
92
/// `[u64; N]`. The inversion's working storage; keeping the concrete array
93
/// type generic (rather than passing slices around) monomorphizes the limb
94
/// loops per width, so trip counts and bounds stay compile-time constants.
95
pub trait LimbArray: Copy {
96
    const LEN: usize;
97
    const ZERO: Self;
98
    fn as_slice(&self) -> &[u64];
99
    fn as_mut_slice(&mut self) -> &mut [u64];
100
}
101
102
impl<const N: usize> LimbArray for [u64; N] {
103
    const LEN: usize = N;
104
    const ZERO: Self = [0; N];
105
    #[inline(always)]
106
235k
    fn as_slice(&self) -> &[u64] {
107
235k
        self
108
235k
    }
_RNvXNtCs8KLYHAG7u19_10kaspa_math6lehmerAyj2_NtB2_9LimbArray8as_sliceCs1uXV1nWfJt5_4u128
Line
Count
Source
106
203k
    fn as_slice(&self) -> &[u64] {
107
203k
        self
108
203k
    }
_RNvXNtCs8KLYHAG7u19_10kaspa_math6lehmerAyja_NtB2_9LimbArray8as_sliceCs1uXV1nWfJt5_4u128
Line
Count
Source
106
32.7k
    fn as_slice(&self) -> &[u64] {
107
32.7k
        self
108
32.7k
    }
Unexecuted instantiation: _RNvXININtCs8KLYHAG7u19_10kaspa_math6lehmer0KpEAypNtB5_9LimbArray8as_sliceB7_
109
    #[inline(always)]
110
96.1k
    fn as_mut_slice(&mut self) -> &mut [u64] {
111
96.1k
        self
112
96.1k
    }
_RNvXNtCs8KLYHAG7u19_10kaspa_math6lehmerAyj2_NtB2_9LimbArray12as_mut_sliceCs1uXV1nWfJt5_4u128
Line
Count
Source
110
45.5k
    fn as_mut_slice(&mut self) -> &mut [u64] {
111
45.5k
        self
112
45.5k
    }
_RNvXNtCs8KLYHAG7u19_10kaspa_math6lehmerAyja_NtB2_9LimbArray12as_mut_sliceCs1uXV1nWfJt5_4u128
Line
Count
Source
110
50.5k
    fn as_mut_slice(&mut self) -> &mut [u64] {
111
50.5k
        self
112
50.5k
    }
Unexecuted instantiation: _RNvXININtCs8KLYHAG7u19_10kaspa_math6lehmer0KpEAypNtB5_9LimbArray12as_mut_sliceB7_
113
}
114
115
/// Extra limbs every cofactor buffer ([`LehmerOps::Cofactor`]) carries beyond
116
/// the operand width, absorbing carry-out during a matrix application and the
117
/// multi-limb fallback. Compile-time checked per width in [`invert`].
118
pub const COFACTOR_HEADROOM: usize = 8;
119
120
/// What Lehmer inversion needs from a uint type beyond plain limb arithmetic:
121
/// its limb representation and an exact multi-limb division (the rare fallback
122
/// when the two-word guess cannot confirm a quotient, and the defensive branch
123
/// of the final reduction).
124
///
125
/// Implemented by `construct_uint!` for every generated type, and manually for
126
/// primitive `u64`/`u128`.
127
pub trait LehmerOps: Copy {
128
    /// The operand representation, `[u64; N]`.
129
    type Limbs: LimbArray;
130
    /// The cofactor working buffer, `[u64; N + COFACTOR_HEADROOM]`. The
131
    /// cofactor of `value` is bounded in magnitude by the modulus (<= `N`
132
    /// limbs); the extra headroom absorbs carry-out during a matrix
133
    /// application and the multi-limb fallback. Supplied per-impl because
134
    /// stable Rust cannot spell the sum generically.
135
    type Cofactor: LimbArray;
136
    fn from_limbs(limbs: Self::Limbs) -> Self;
137
    fn into_limbs(self) -> Self::Limbs;
138
    /// `(self / other, self % other)`.
139
    fn div_rem(self, other: Self) -> (Self, Self);
140
}
141
142
impl LehmerOps for u64 {
143
    type Limbs = [u64; 1];
144
    type Cofactor = [u64; 1 + COFACTOR_HEADROOM];
145
    #[inline]
146
0
    fn from_limbs(limbs: Self::Limbs) -> Self {
147
0
        limbs[0]
148
0
    }
149
    #[inline]
150
0
    fn into_limbs(self) -> Self::Limbs {
151
0
        [self]
152
0
    }
153
    #[inline]
154
0
    fn div_rem(self, other: Self) -> (Self, Self) {
155
0
        (self / other, self % other)
156
0
    }
157
}
158
159
impl LehmerOps for u128 {
160
    type Limbs = [u64; 2];
161
    type Cofactor = [u64; 2 + COFACTOR_HEADROOM];
162
    #[inline]
163
4.32k
    fn from_limbs(limbs: Self::Limbs) -> Self {
164
4.32k
        ((limbs[1] as u128) << 64) | (limbs[0] as u128)
165
4.32k
    }
166
    #[inline]
167
13.0k
    fn into_limbs(self) -> Self::Limbs {
168
13.0k
        [self as u64, (self >> 64) as u64]
169
13.0k
    }
170
    #[inline]
171
2.78k
    fn div_rem(self, other: Self) -> (Self, Self) {
172
2.78k
        (self / other, self % other)
173
2.78k
    }
174
}
175
176
/// Modular inversion as a method on any [`LehmerOps`] type.
177
pub trait LehmerInvert: Sized {
178
    /// The multiplicative inverse of `self` modulo `modulus`, in `[0, modulus)`.
179
    ///
180
    /// Total over all inputs: `self` is reduced first when `self >= modulus`,
181
    /// and `None` is returned when no inverse exists (`gcd != 1`, which covers
182
    /// a zero residue, or `modulus < 2`).
183
    fn lehmer_invert(self, modulus: Self) -> Option<Self>;
184
}
185
186
impl<U: LehmerOps> LehmerInvert for U {
187
9.24k
    fn lehmer_invert(self, modulus: Self) -> Option<Self> {
188
9.24k
        let m = modulus.into_limbs();
189
9.24k
        let ms = m.as_slice();
190
9.24k
        if ms[0] < 2 && ms[1..].iter().all(|&w| w == 0) {
_RNCNvXs1_NtCs8KLYHAG7u19_10kaspa_math6lehmerNtCs1uXV1nWfJt5_4u1287Uint128NtB7_12LehmerInvert13lehmer_invert0BI_
Line
Count
Source
190
586
        if ms[0] < 2 && ms[1..].iter().all(|&w| w == 0) {
_RNCNvXs1_NtCs8KLYHAG7u19_10kaspa_math6lehmeroNtB7_12LehmerInvert13lehmer_invert0Cs1uXV1nWfJt5_4u128
Line
Count
Source
190
586
        if ms[0] < 2 && ms[1..].iter().all(|&w| w == 0) {
Unexecuted instantiation: _RNCNvXININtCs8KLYHAG7u19_10kaspa_math6lehmers1_0pEpNtB7_12LehmerInvert13lehmer_invert0B9_
191
0
            return None;
192
9.24k
        }
193
9.24k
        let mut value = self.into_limbs();
194
9.24k
        if cmp_n(value.as_slice(), ms) != Ordering::Less {
195
3.52k
            value = self.div_rem(modulus).1.into_limbs();
196
5.72k
        }
197
9.24k
        let mut out = U::Limbs::ZERO;
198
9.24k
        invert::<U>(value, m, &mut out).then(|| U::from_limbs(out))
_RNCNvXs1_NtCs8KLYHAG7u19_10kaspa_math6lehmerNtCs1uXV1nWfJt5_4u1287Uint128NtB7_12LehmerInvert13lehmer_inverts_0BI_
Line
Count
Source
198
2.27k
        invert::<U>(value, m, &mut out).then(|| U::from_limbs(out))
_RNCNvXs1_NtCs8KLYHAG7u19_10kaspa_math6lehmeroNtB7_12LehmerInvert13lehmer_inverts_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
198
2.27k
        invert::<U>(value, m, &mut out).then(|| U::from_limbs(out))
Unexecuted instantiation: _RNCNvXININtCs8KLYHAG7u19_10kaspa_math6lehmers1_0pEpNtB7_12LehmerInvert13lehmer_inverts_0B9_
199
9.24k
    }
_RNvXs1_NtCs8KLYHAG7u19_10kaspa_math6lehmerNtCs1uXV1nWfJt5_4u1287Uint128NtB5_12LehmerInvert13lehmer_invertBG_
Line
Count
Source
187
4.62k
    fn lehmer_invert(self, modulus: Self) -> Option<Self> {
188
4.62k
        let m = modulus.into_limbs();
189
4.62k
        let ms = m.as_slice();
190
4.62k
        if ms[0] < 2 && ms[1..].iter().all(|&w| w == 0) {
191
0
            return None;
192
4.62k
        }
193
4.62k
        let mut value = self.into_limbs();
194
4.62k
        if cmp_n(value.as_slice(), ms) != Ordering::Less {
195
1.76k
            value = self.div_rem(modulus).1.into_limbs();
196
2.86k
        }
197
4.62k
        let mut out = U::Limbs::ZERO;
198
4.62k
        invert::<U>(value, m, &mut out).then(|| U::from_limbs(out))
199
4.62k
    }
_RNvXs1_NtCs8KLYHAG7u19_10kaspa_math6lehmeroNtB5_12LehmerInvert13lehmer_invertCs1uXV1nWfJt5_4u128
Line
Count
Source
187
4.62k
    fn lehmer_invert(self, modulus: Self) -> Option<Self> {
188
4.62k
        let m = modulus.into_limbs();
189
4.62k
        let ms = m.as_slice();
190
4.62k
        if ms[0] < 2 && ms[1..].iter().all(|&w| w == 0) {
191
0
            return None;
192
4.62k
        }
193
4.62k
        let mut value = self.into_limbs();
194
4.62k
        if cmp_n(value.as_slice(), ms) != Ordering::Less {
195
1.76k
            value = self.div_rem(modulus).1.into_limbs();
196
2.86k
        }
197
4.62k
        let mut out = U::Limbs::ZERO;
198
4.62k
        invert::<U>(value, m, &mut out).then(|| U::from_limbs(out))
199
4.62k
    }
Unexecuted instantiation: _RNvXININtCs8KLYHAG7u19_10kaspa_math6lehmers1_0pEpNtB5_12LehmerInvert13lehmer_invertB7_
200
}
201
202
// Matrix entries from `hgcd2` are below `2^63` by construction (the half-limb
203
// refinement discards the least significant half limb), so the `i128`/`u128`
204
// accumulators in the matrix applications cannot overflow
205
// (`a*x + b*y + carry < 2^128` with `a, b < 2^63` and `x, y < 2^64`).
206
207
/// Compute the multiplicative inverse of `value` modulo `modulus` (an odd
208
/// modulus, e.g. the MuHash prime), via Lehmer's extended GCD. `value`,
209
/// `modulus` and `out` are little-endian base-2^64 limb arrays, and `value`
210
/// must already be reduced (`value < modulus`).
211
/// [`LehmerInvert::lehmer_invert`] is the totalized wrapper without the
212
/// reduction precondition.
213
///
214
/// Returns `true` and writes the inverse into `out` when
215
/// `gcd(value, modulus) == 1`; returns `false` (leaving `out` unspecified)
216
/// otherwise. A zero `value` yields `false`.
217
9.24k
pub fn invert<U: LehmerOps>(value: U::Limbs, modulus: U::Limbs, out: &mut U::Limbs) -> bool {
218
    const {
219
        assert!(U::Cofactor::LEN >= U::Limbs::LEN + COFACTOR_HEADROOM, "cofactor buffer lacks the required headroom");
220
    }
221
9.24k
    count!(INVERSES += 1);
222
9.24k
    if is_zero(value.as_slice()) {
223
334
        core::hint::cold_path();
224
334
        return false;
225
8.91k
    }
226
8.91k
    strict_assert!(cmp_n(value.as_slice(), modulus.as_slice()).is_lt(), "invert requires value < modulus");
227
228
    // Euclidean state on (x, y) with x >= y, plus the cofactor of `value`.
229
    // Invariant: x ≡ -t0·value (mod m) and y ≡ t1·value (mod m) when
230
    // `swapped == false`, and the roles flip with each swap. `x`, `y` are owned
231
    // working buffers (they are reduced in place).
232
8.91k
    let mut x: U::Limbs = modulus;
233
8.91k
    let mut y: U::Limbs = value;
234
8.91k
    let mut x_len = top_len(x.as_slice());
235
8.91k
    let mut y_len = top_len(y.as_slice());
236
8.91k
    let mut t0 = U::Cofactor::ZERO;
237
8.91k
    let mut t1 = from_word::<U::Cofactor>(1);
238
8.91k
    let mut t0_len = 1usize; // 0 has conventional length 1
239
8.91k
    let mut t1_len = 1usize;
240
8.91k
    let mut swapped = false;
241
242
    // Multi-limb phase: run until y collapses to a single limb, then finish
243
    // with a u64 extended-Euclidean tail.
244
19.9k
    while y_len > 1 {
245
11.0k
        let (x_hi, y_hi) = highest_two_words_normalized(x.as_slice(), y.as_slice(), x_len);
246
11.0k
        let guess = hgcd2((x_hi >> 64) as u64, x_hi as u64, (y_hi >> 64) as u64, y_hi as u64);
247
248
11.0k
        if let Some((a, b, c, d)) = guess {
249
9.00k
            count!(MATRICES += 1);
250
9.00k
            (x_len, y_len) = apply_matrix_xy(&mut x, &mut y, x_len, a, b, c, d);
251
9.00k
            apply_matrix_t(&mut t0, &mut t1, &mut t0_len, &mut t1_len, a, b, c, d);
252
253
            // A partial guess can leave x < y; restore x >= y, toggling the sign.
254
9.00k
            if x_len < y_len || (x_len == y_len && cmp_prefix(x.as_slice(), y.as_slice(), x_len).is_lt()) {
255
4.16k
                core::mem::swap(&mut x, &mut y);
256
4.16k
                core::mem::swap(&mut x_len, &mut y_len);
257
4.16k
                core::mem::swap(&mut t0, &mut t1);
258
4.16k
                core::mem::swap(&mut t0_len, &mut t1_len);
259
4.16k
                swapped = !swapped;
260
4.84k
            }
261
2.05k
        } else {
262
2.05k
            // The guess almost always confirms a quotient, so this exact-division
263
2.05k
            // path is cold; keep it out of the hot loop body.
264
2.05k
            core::hint::cold_path();
265
2.05k
            count!(FALLBACK_STEPS += 1);
266
2.05k
            // Guess could not confirm a quotient: one exact Euclidean step.
267
2.05k
            let (q, r) = div_rem_step::<U>(&x, &y);
268
2.05k
            t_add_qmul(&mut t0, &mut t0_len, q.as_slice(), &t1, t1_len);
269
2.05k
            x = y;
270
2.05k
            x_len = y_len;
271
2.05k
            y = r;
272
2.05k
            y_len = top_len(y.as_slice());
273
2.05k
            core::mem::swap(&mut t0, &mut t1);
274
2.05k
            core::mem::swap(&mut t0_len, &mut t1_len);
275
2.05k
            swapped = !swapped;
276
2.05k
        }
277
    }
278
279
    // Single-limb tail. `y` is now <= 1 limb; one u64 extended Euclidean step
280
    // replaces the remaining ~tens of `t_add_qmul` iterations.
281
8.91k
    if y_len == 1 && y.as_slice()[0] != 0 {
282
8.82k
        if x.as_slice()[1..].iter().any(|&w| w != 0) {
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer6invertNtCs1uXV1nWfJt5_4u1287Uint128E0BM_
Line
Count
Source
282
4.41k
        if x.as_slice()[1..].iter().any(|&w| w != 0) {
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer6invertoE0Cs1uXV1nWfJt5_4u128
Line
Count
Source
282
4.41k
        if x.as_slice()[1..].iter().any(|&w| w != 0) {
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer6invertpE0B6_
283
3.93k
            let (q, r) = div_rem_step::<U>(&x, &y);
284
3.93k
            t_add_qmul(&mut t0, &mut t0_len, q.as_slice(), &t1, t1_len);
285
3.93k
            x = from_word(y.as_slice()[0]);
286
3.93k
            y = r;
287
3.93k
            core::mem::swap(&mut t0, &mut t1);
288
3.93k
            core::mem::swap(&mut t0_len, &mut t1_len);
289
3.93k
            swapped = !swapped;
290
4.88k
        }
291
292
8.82k
        let (g, cx, cy) = gcd_ext_u64(x.as_slice()[0], y.as_slice()[0]);
293
294
        // Fold the sign of the chosen cofactor into `swapped`, then combine
295
        // magnitudes: new_t0 = |cx|·t0 + |cy|·t1.
296
8.82k
        if cx < 0 || (cx == 0 && cy > 0) {
297
4.08k
            swapped = !swapped;
298
4.73k
        }
299
8.82k
        let mut new_t0 = U::Cofactor::ZERO;
300
8.82k
        let mut new_t0_len = 1usize;
301
8.82k
        add_mul_word(&mut new_t0, &mut new_t0_len, cx.unsigned_abs(), &t0, t0_len);
302
8.82k
        add_mul_word(&mut new_t0, &mut new_t0_len, cy.unsigned_abs(), &t1, t1_len);
303
8.82k
        t0 = new_t0;
304
305
8.82k
        x = from_word(g);
306
8.82k
        x_len = if g == 0 { 0 } else { 1 };
307
88
    }
308
309
    // For an odd prime modulus and `value` in [1, m), the gcd is 1.
310
8.91k
    if !(x_len == 1 && x.as_slice()[0] == 1) {
311
4.37k
        return false;
312
4.54k
    }
313
314
    // x = 1 = ±t0·value (mod m). With `swapped`, the inverse is +t0; otherwise
315
    // it is -t0 ≡ m - t0. Reduce t0 into [0, m) first.
316
4.54k
    let mut inv = reduce_mod::<U>(&t0, &modulus);
317
4.54k
    if !swapped && !is_zero(inv.as_slice()) {
318
2.40k
        inv = sub_n(&modulus, &inv);
319
2.40k
    }
320
4.54k
    strict_assert!(
321
4.54k
        !is_zero(inv.as_slice()) && cmp_n(inv.as_slice(), modulus.as_slice()).is_lt(),
322
        "invert: result outside (0, modulus)"
323
    );
324
4.54k
    *out = inv;
325
4.54k
    true
326
9.24k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer6invertNtCs1uXV1nWfJt5_4u1287Uint128EBK_
Line
Count
Source
217
4.62k
pub fn invert<U: LehmerOps>(value: U::Limbs, modulus: U::Limbs, out: &mut U::Limbs) -> bool {
218
    const {
219
        assert!(U::Cofactor::LEN >= U::Limbs::LEN + COFACTOR_HEADROOM, "cofactor buffer lacks the required headroom");
220
    }
221
4.62k
    count!(INVERSES += 1);
222
4.62k
    if is_zero(value.as_slice()) {
223
167
        core::hint::cold_path();
224
167
        return false;
225
4.45k
    }
226
4.45k
    strict_assert!(cmp_n(value.as_slice(), modulus.as_slice()).is_lt(), "invert requires value < modulus");
227
228
    // Euclidean state on (x, y) with x >= y, plus the cofactor of `value`.
229
    // Invariant: x ≡ -t0·value (mod m) and y ≡ t1·value (mod m) when
230
    // `swapped == false`, and the roles flip with each swap. `x`, `y` are owned
231
    // working buffers (they are reduced in place).
232
4.45k
    let mut x: U::Limbs = modulus;
233
4.45k
    let mut y: U::Limbs = value;
234
4.45k
    let mut x_len = top_len(x.as_slice());
235
4.45k
    let mut y_len = top_len(y.as_slice());
236
4.45k
    let mut t0 = U::Cofactor::ZERO;
237
4.45k
    let mut t1 = from_word::<U::Cofactor>(1);
238
4.45k
    let mut t0_len = 1usize; // 0 has conventional length 1
239
4.45k
    let mut t1_len = 1usize;
240
4.45k
    let mut swapped = false;
241
242
    // Multi-limb phase: run until y collapses to a single limb, then finish
243
    // with a u64 extended-Euclidean tail.
244
9.98k
    while y_len > 1 {
245
5.53k
        let (x_hi, y_hi) = highest_two_words_normalized(x.as_slice(), y.as_slice(), x_len);
246
5.53k
        let guess = hgcd2((x_hi >> 64) as u64, x_hi as u64, (y_hi >> 64) as u64, y_hi as u64);
247
248
5.53k
        if let Some((a, b, c, d)) = guess {
249
4.50k
            count!(MATRICES += 1);
250
4.50k
            (x_len, y_len) = apply_matrix_xy(&mut x, &mut y, x_len, a, b, c, d);
251
4.50k
            apply_matrix_t(&mut t0, &mut t1, &mut t0_len, &mut t1_len, a, b, c, d);
252
253
            // A partial guess can leave x < y; restore x >= y, toggling the sign.
254
4.50k
            if x_len < y_len || (x_len == y_len && cmp_prefix(x.as_slice(), y.as_slice(), x_len).is_lt()) {
255
2.08k
                core::mem::swap(&mut x, &mut y);
256
2.08k
                core::mem::swap(&mut x_len, &mut y_len);
257
2.08k
                core::mem::swap(&mut t0, &mut t1);
258
2.08k
                core::mem::swap(&mut t0_len, &mut t1_len);
259
2.08k
                swapped = !swapped;
260
2.42k
            }
261
1.02k
        } else {
262
1.02k
            // The guess almost always confirms a quotient, so this exact-division
263
1.02k
            // path is cold; keep it out of the hot loop body.
264
1.02k
            core::hint::cold_path();
265
1.02k
            count!(FALLBACK_STEPS += 1);
266
1.02k
            // Guess could not confirm a quotient: one exact Euclidean step.
267
1.02k
            let (q, r) = div_rem_step::<U>(&x, &y);
268
1.02k
            t_add_qmul(&mut t0, &mut t0_len, q.as_slice(), &t1, t1_len);
269
1.02k
            x = y;
270
1.02k
            x_len = y_len;
271
1.02k
            y = r;
272
1.02k
            y_len = top_len(y.as_slice());
273
1.02k
            core::mem::swap(&mut t0, &mut t1);
274
1.02k
            core::mem::swap(&mut t0_len, &mut t1_len);
275
1.02k
            swapped = !swapped;
276
1.02k
        }
277
    }
278
279
    // Single-limb tail. `y` is now <= 1 limb; one u64 extended Euclidean step
280
    // replaces the remaining ~tens of `t_add_qmul` iterations.
281
4.45k
    if y_len == 1 && y.as_slice()[0] != 0 {
282
4.41k
        if x.as_slice()[1..].iter().any(|&w| w != 0) {
283
1.96k
            let (q, r) = div_rem_step::<U>(&x, &y);
284
1.96k
            t_add_qmul(&mut t0, &mut t0_len, q.as_slice(), &t1, t1_len);
285
1.96k
            x = from_word(y.as_slice()[0]);
286
1.96k
            y = r;
287
1.96k
            core::mem::swap(&mut t0, &mut t1);
288
1.96k
            core::mem::swap(&mut t0_len, &mut t1_len);
289
1.96k
            swapped = !swapped;
290
2.44k
        }
291
292
4.41k
        let (g, cx, cy) = gcd_ext_u64(x.as_slice()[0], y.as_slice()[0]);
293
294
        // Fold the sign of the chosen cofactor into `swapped`, then combine
295
        // magnitudes: new_t0 = |cx|·t0 + |cy|·t1.
296
4.41k
        if cx < 0 || (cx == 0 && cy > 0) {
297
2.04k
            swapped = !swapped;
298
2.36k
        }
299
4.41k
        let mut new_t0 = U::Cofactor::ZERO;
300
4.41k
        let mut new_t0_len = 1usize;
301
4.41k
        add_mul_word(&mut new_t0, &mut new_t0_len, cx.unsigned_abs(), &t0, t0_len);
302
4.41k
        add_mul_word(&mut new_t0, &mut new_t0_len, cy.unsigned_abs(), &t1, t1_len);
303
4.41k
        t0 = new_t0;
304
305
4.41k
        x = from_word(g);
306
4.41k
        x_len = if g == 0 { 0 } else { 1 };
307
44
    }
308
309
    // For an odd prime modulus and `value` in [1, m), the gcd is 1.
310
4.45k
    if !(x_len == 1 && x.as_slice()[0] == 1) {
311
2.18k
        return false;
312
2.27k
    }
313
314
    // x = 1 = ±t0·value (mod m). With `swapped`, the inverse is +t0; otherwise
315
    // it is -t0 ≡ m - t0. Reduce t0 into [0, m) first.
316
2.27k
    let mut inv = reduce_mod::<U>(&t0, &modulus);
317
2.27k
    if !swapped && !is_zero(inv.as_slice()) {
318
1.20k
        inv = sub_n(&modulus, &inv);
319
1.20k
    }
320
2.27k
    strict_assert!(
321
2.27k
        !is_zero(inv.as_slice()) && cmp_n(inv.as_slice(), modulus.as_slice()).is_lt(),
322
        "invert: result outside (0, modulus)"
323
    );
324
2.27k
    *out = inv;
325
2.27k
    true
326
4.62k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer6invertoECs1uXV1nWfJt5_4u128
Line
Count
Source
217
4.62k
pub fn invert<U: LehmerOps>(value: U::Limbs, modulus: U::Limbs, out: &mut U::Limbs) -> bool {
218
    const {
219
        assert!(U::Cofactor::LEN >= U::Limbs::LEN + COFACTOR_HEADROOM, "cofactor buffer lacks the required headroom");
220
    }
221
4.62k
    count!(INVERSES += 1);
222
4.62k
    if is_zero(value.as_slice()) {
223
167
        core::hint::cold_path();
224
167
        return false;
225
4.45k
    }
226
4.45k
    strict_assert!(cmp_n(value.as_slice(), modulus.as_slice()).is_lt(), "invert requires value < modulus");
227
228
    // Euclidean state on (x, y) with x >= y, plus the cofactor of `value`.
229
    // Invariant: x ≡ -t0·value (mod m) and y ≡ t1·value (mod m) when
230
    // `swapped == false`, and the roles flip with each swap. `x`, `y` are owned
231
    // working buffers (they are reduced in place).
232
4.45k
    let mut x: U::Limbs = modulus;
233
4.45k
    let mut y: U::Limbs = value;
234
4.45k
    let mut x_len = top_len(x.as_slice());
235
4.45k
    let mut y_len = top_len(y.as_slice());
236
4.45k
    let mut t0 = U::Cofactor::ZERO;
237
4.45k
    let mut t1 = from_word::<U::Cofactor>(1);
238
4.45k
    let mut t0_len = 1usize; // 0 has conventional length 1
239
4.45k
    let mut t1_len = 1usize;
240
4.45k
    let mut swapped = false;
241
242
    // Multi-limb phase: run until y collapses to a single limb, then finish
243
    // with a u64 extended-Euclidean tail.
244
9.98k
    while y_len > 1 {
245
5.53k
        let (x_hi, y_hi) = highest_two_words_normalized(x.as_slice(), y.as_slice(), x_len);
246
5.53k
        let guess = hgcd2((x_hi >> 64) as u64, x_hi as u64, (y_hi >> 64) as u64, y_hi as u64);
247
248
5.53k
        if let Some((a, b, c, d)) = guess {
249
4.50k
            count!(MATRICES += 1);
250
4.50k
            (x_len, y_len) = apply_matrix_xy(&mut x, &mut y, x_len, a, b, c, d);
251
4.50k
            apply_matrix_t(&mut t0, &mut t1, &mut t0_len, &mut t1_len, a, b, c, d);
252
253
            // A partial guess can leave x < y; restore x >= y, toggling the sign.
254
4.50k
            if x_len < y_len || (x_len == y_len && cmp_prefix(x.as_slice(), y.as_slice(), x_len).is_lt()) {
255
2.08k
                core::mem::swap(&mut x, &mut y);
256
2.08k
                core::mem::swap(&mut x_len, &mut y_len);
257
2.08k
                core::mem::swap(&mut t0, &mut t1);
258
2.08k
                core::mem::swap(&mut t0_len, &mut t1_len);
259
2.08k
                swapped = !swapped;
260
2.42k
            }
261
1.02k
        } else {
262
1.02k
            // The guess almost always confirms a quotient, so this exact-division
263
1.02k
            // path is cold; keep it out of the hot loop body.
264
1.02k
            core::hint::cold_path();
265
1.02k
            count!(FALLBACK_STEPS += 1);
266
1.02k
            // Guess could not confirm a quotient: one exact Euclidean step.
267
1.02k
            let (q, r) = div_rem_step::<U>(&x, &y);
268
1.02k
            t_add_qmul(&mut t0, &mut t0_len, q.as_slice(), &t1, t1_len);
269
1.02k
            x = y;
270
1.02k
            x_len = y_len;
271
1.02k
            y = r;
272
1.02k
            y_len = top_len(y.as_slice());
273
1.02k
            core::mem::swap(&mut t0, &mut t1);
274
1.02k
            core::mem::swap(&mut t0_len, &mut t1_len);
275
1.02k
            swapped = !swapped;
276
1.02k
        }
277
    }
278
279
    // Single-limb tail. `y` is now <= 1 limb; one u64 extended Euclidean step
280
    // replaces the remaining ~tens of `t_add_qmul` iterations.
281
4.45k
    if y_len == 1 && y.as_slice()[0] != 0 {
282
4.41k
        if x.as_slice()[1..].iter().any(|&w| w != 0) {
283
1.96k
            let (q, r) = div_rem_step::<U>(&x, &y);
284
1.96k
            t_add_qmul(&mut t0, &mut t0_len, q.as_slice(), &t1, t1_len);
285
1.96k
            x = from_word(y.as_slice()[0]);
286
1.96k
            y = r;
287
1.96k
            core::mem::swap(&mut t0, &mut t1);
288
1.96k
            core::mem::swap(&mut t0_len, &mut t1_len);
289
1.96k
            swapped = !swapped;
290
2.44k
        }
291
292
4.41k
        let (g, cx, cy) = gcd_ext_u64(x.as_slice()[0], y.as_slice()[0]);
293
294
        // Fold the sign of the chosen cofactor into `swapped`, then combine
295
        // magnitudes: new_t0 = |cx|·t0 + |cy|·t1.
296
4.41k
        if cx < 0 || (cx == 0 && cy > 0) {
297
2.04k
            swapped = !swapped;
298
2.36k
        }
299
4.41k
        let mut new_t0 = U::Cofactor::ZERO;
300
4.41k
        let mut new_t0_len = 1usize;
301
4.41k
        add_mul_word(&mut new_t0, &mut new_t0_len, cx.unsigned_abs(), &t0, t0_len);
302
4.41k
        add_mul_word(&mut new_t0, &mut new_t0_len, cy.unsigned_abs(), &t1, t1_len);
303
4.41k
        t0 = new_t0;
304
305
4.41k
        x = from_word(g);
306
4.41k
        x_len = if g == 0 { 0 } else { 1 };
307
44
    }
308
309
    // For an odd prime modulus and `value` in [1, m), the gcd is 1.
310
4.45k
    if !(x_len == 1 && x.as_slice()[0] == 1) {
311
2.18k
        return false;
312
2.27k
    }
313
314
    // x = 1 = ±t0·value (mod m). With `swapped`, the inverse is +t0; otherwise
315
    // it is -t0 ≡ m - t0. Reduce t0 into [0, m) first.
316
2.27k
    let mut inv = reduce_mod::<U>(&t0, &modulus);
317
2.27k
    if !swapped && !is_zero(inv.as_slice()) {
318
1.20k
        inv = sub_n(&modulus, &inv);
319
1.20k
    }
320
2.27k
    strict_assert!(
321
2.27k
        !is_zero(inv.as_slice()) && cmp_n(inv.as_slice(), modulus.as_slice()).is_lt(),
322
        "invert: result outside (0, modulus)"
323
    );
324
2.27k
    *out = inv;
325
2.27k
    true
326
4.62k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer6invertpEB4_
327
328
/// Two-word subtract `(h1·2^64 + l1) - (h2·2^64 + l2)`, returning `(hi, lo)`.
329
/// Callers guarantee the minuend is the larger, so no underflow off the top.
330
#[inline(always)]
331
76.5k
fn sub2(h1: u64, l1: u64, h2: u64, l2: u64) -> (u64, u64) {
332
76.5k
    let (lo, borrow) = l1.overflowing_sub(l2);
333
76.5k
    (h1.wrapping_sub(h2).wrapping_sub(borrow as u64), lo)
334
76.5k
}
335
336
/// Fold the next half limb up into a fresh full word, `(hi << 32) | (lo >> 32)`,
337
/// for the handoff from the main hgcd2 loop (working on top *words*) to the
338
/// half-limb refinement loop. `hi < 2^32` here, so the result fits a `u64`.
339
#[inline(always)]
340
13.2k
fn fold_half(hi: u64, lo: u64) -> u64 {
341
13.2k
    (hi << 32).wrapping_add(lo >> 32)
342
13.2k
}
343
344
/// The half-GCD guess: from the aligned top *two* words of the remainders
345
/// (`(ah, al) >=~ (bh, bl)`), run Euclidean steps on the 128-bit approximation
346
/// and return the 2x2 reduction matrix in this module's `(a, b, c, d)`
347
/// convention, `(x', y') = (a·x - b·y, d·y - c·x)`. Returns `None` when no
348
/// quotient can be confirmed (the caller then takes one exact division step).
349
///
350
/// A quotient of 1 is resolved by one two-word subtraction and a top-word
351
/// compare, so [`gcd_div`] (the hardware divide) is reached only for `q >= 2`.
352
/// The trailing half-limb refinement (the `HALF_LIMIT_2` loop) keeps every
353
/// matrix entry below `2^63`, which is why the `apply_matrix_*` accumulators
354
/// need no per-step overflow guard. All matrix arithmetic is `wrapping_*`
355
/// (entries are `< 2^63`, so it never actually wraps) to avoid the workspace
356
/// `overflow-checks = true` panic pads.
357
#[inline]
358
11.0k
fn hgcd2(mut ah: u64, mut al: u64, mut bh: u64, mut bl: u64) -> Option<(u64, u64, u64, u64)> {
359
    // Need at least two leading bits of headroom in both top words. The guess
360
    // almost always confirms a quotient, so every `return None` here is cold.
361
11.0k
    if ah < 2 || bh < 2 {
362
48
        core::hint::cold_path();
363
48
        return None;
364
11.0k
    }
365
366
    // Reduction matrix M = (m00 m01; m10 m11), accumulated by the same column
367
    // updates as the full-width apply; returned remapped to (a,b,c,d).
368
    let (mut m00, mut m01, mut m10, mut m11): (u64, u64, u64, u64);
369
11.0k
    if ah > bh || (ah == bh && al > bl) {
370
10.9k
        (ah, al) = sub2(ah, al, bh, bl); // a -= b
371
10.9k
        if ah < 2 {
372
1.92k
            return None;
373
9.00k
        }
374
9.00k
        (m01, m10) = (1, 0);
375
    } else {
376
88
        (bh, bl) = sub2(bh, bl, ah, al); // b -= a
377
88
        if bh < 2 {
378
88
            return None;
379
0
        }
380
0
        (m01, m10) = (0, 1);
381
    }
382
9.00k
    (m00, m11) = (1, 1);
383
384
    const HALF: u32 = 32;
385
    const HALF_LIMIT_1: u64 = 1 << HALF;
386
387
9.00k
    let mut subtract_a = ah < bh;
388
9.00k
    let mut subtract_a1 = false;
389
9.00k
    let mut done = false;
390
    loop {
391
41.6k
        if subtract_a {
392
5.56k
            subtract_a = false;
393
5.56k
        } else {
394
36.0k
            if ah == bh {
395
376
                done = true;
396
376
                break;
397
35.7k
            }
398
35.7k
            if ah < HALF_LIMIT_1 {
399
                // Top words collapsed to a half limb: fold in the next half from
400
                // the low words and finish in the refinement loop below.
401
3.65k
                ah = fold_half(ah, al);
402
3.65k
                bh = fold_half(bh, bl);
403
3.65k
                break;
404
32.0k
            }
405
            // Subtract a -= q·b (affects the second column of M).
406
32.0k
            (ah, al) = sub2(ah, al, bh, bl);
407
32.0k
            if ah < 2 {
408
182
                done = true;
409
182
                break;
410
31.8k
            }
411
31.8k
            if ah <= bh {
412
11.8k
                m01 = m01.wrapping_add(m00); // q = 1: no divide
413
11.8k
                m11 = m11.wrapping_add(m10);
414
11.8k
            } else {
415
20.0k
                let n = ((ah as u128) << 64) | al as u128;
416
20.0k
                let d = ((bh as u128) << 64) | bl as u128;
417
20.0k
                let (mut q, r) = gcd_div(n, d);
418
20.0k
                ah = (r >> 64) as u64;
419
20.0k
                al = r as u64;
420
20.0k
                if ah < 2 {
421
668
                    m01 = m01.wrapping_add(q.wrapping_mul(m00)); // q correct, a too small
422
668
                    m11 = m11.wrapping_add(q.wrapping_mul(m10));
423
668
                    done = true;
424
668
                    break;
425
19.3k
                }
426
19.3k
                q = q.wrapping_add(1); // one subtraction already taken above
427
19.3k
                m01 = m01.wrapping_add(q.wrapping_mul(m00));
428
19.3k
                m11 = m11.wrapping_add(q.wrapping_mul(m10));
429
            }
430
        }
431
36.7k
        if ah == bh {
432
348
            done = true;
433
348
            break;
434
36.4k
        }
435
36.4k
        if bh < HALF_LIMIT_1 {
436
2.95k
            ah = fold_half(ah, al);
437
2.95k
            bh = fold_half(bh, bl);
438
2.95k
            subtract_a1 = true;
439
2.95k
            break;
440
33.4k
        }
441
        // Subtract b -= q·a (affects the first column of M).
442
33.4k
        (bh, bl) = sub2(bh, bl, ah, al);
443
33.4k
        if bh < 2 {
444
184
            done = true;
445
184
            break;
446
33.2k
        }
447
33.2k
        if bh <= ah {
448
11.6k
            m00 = m00.wrapping_add(m01); // q = 1: no divide
449
11.6k
            m10 = m10.wrapping_add(m11);
450
11.6k
        } else {
451
21.6k
            let n = ((bh as u128) << 64) | bl as u128;
452
21.6k
            let d = ((ah as u128) << 64) | al as u128;
453
21.6k
            let (mut q, r) = gcd_div(n, d);
454
21.6k
            bh = (r >> 64) as u64;
455
21.6k
            bl = r as u64;
456
21.6k
            if bh < 2 {
457
642
                m00 = m00.wrapping_add(q.wrapping_mul(m01));
458
642
                m10 = m10.wrapping_add(q.wrapping_mul(m11));
459
642
                done = true;
460
642
                break;
461
21.0k
            }
462
21.0k
            q = q.wrapping_add(1);
463
21.0k
            m00 = m00.wrapping_add(q.wrapping_mul(m01));
464
21.0k
            m10 = m10.wrapping_add(q.wrapping_mul(m11));
465
        }
466
    }
467
468
    // Half-limb refinement: peel a bit more (single-word divides on the folded
469
    // top words) until |a - b| fits in one limb + 1 bit. This is what keeps the
470
    // matrix entries below 2^63, discarding the least significant half limb.
471
9.00k
    if !done {
472
        const HALF_LIMIT_2: u64 = 1 << (HALF + 1);
473
        loop {
474
39.6k
            if subtract_a1 {
475
2.95k
                subtract_a1 = false;
476
2.95k
            } else {
477
36.7k
                ah = ah.wrapping_sub(bh);
478
36.7k
                if ah < HALF_LIMIT_2 {
479
1.48k
                    break;
480
35.2k
                }
481
35.2k
                if ah <= bh {
482
14.5k
                    m01 = m01.wrapping_add(m00);
483
14.5k
                    m11 = m11.wrapping_add(m10);
484
14.5k
                } else {
485
20.6k
                    let q = ah / bh;
486
20.6k
                    ah %= bh;
487
20.6k
                    if ah < HALF_LIMIT_2 {
488
1.83k
                        m01 = m01.wrapping_add(q.wrapping_mul(m00));
489
1.83k
                        m11 = m11.wrapping_add(q.wrapping_mul(m10));
490
1.83k
                        break;
491
18.8k
                    }
492
18.8k
                    let q = q.wrapping_add(1);
493
18.8k
                    m01 = m01.wrapping_add(q.wrapping_mul(m00));
494
18.8k
                    m11 = m11.wrapping_add(q.wrapping_mul(m10));
495
                }
496
            }
497
36.3k
            bh = bh.wrapping_sub(ah);
498
36.3k
            if bh < HALF_LIMIT_2 {
499
1.47k
                break;
500
34.8k
            }
501
34.8k
            if ah >= bh {
502
14.6k
                m00 = m00.wrapping_add(m01);
503
14.6k
                m10 = m10.wrapping_add(m11);
504
14.6k
            } else {
505
20.2k
                let q = bh / ah;
506
20.2k
                bh %= ah;
507
20.2k
                if bh < HALF_LIMIT_2 {
508
1.81k
                    m00 = m00.wrapping_add(q.wrapping_mul(m01));
509
1.81k
                    m10 = m10.wrapping_add(q.wrapping_mul(m11));
510
1.81k
                    break;
511
18.4k
                }
512
18.4k
                let q = q.wrapping_add(1);
513
18.4k
                m00 = m00.wrapping_add(q.wrapping_mul(m01));
514
18.4k
                m10 = m10.wrapping_add(q.wrapping_mul(m11));
515
            }
516
        }
517
2.40k
    }
518
519
    // Every entry stays below 2^63 (the half-limb refinement's exit bound, which
520
    // the `apply_matrix_*` overflow analyses rely on), and the column updates
521
    // preserve the unit determinant of the elementary step matrices.
522
9.00k
    strict_assert!(m00 < 1 << 63 && m01 < 1 << 63 && m10 < 1 << 63 && m11 < 1 << 63, "hgcd2: matrix entry reached 2^63");
523
9.00k
    strict_assert_eq!((m00 as i128) * (m11 as i128) - (m01 as i128) * (m10 as i128), 1, "hgcd2: determinant is not 1");
524
525
    // Remap M to this module's apply convention:
526
    // x' = m11·x - m01·y, y' = m00·y - m10·x.
527
9.00k
    Some((m11, m01, m10, m00))
528
11.0k
}
529
530
/// `(q, r) = (n / d, n % d)` for 128-bit `n, d` with `d >= 2^64`, computed from
531
/// hardware `u64` divisions (via [`div_2by1`]) instead of the `u128 / u128`
532
/// software routine. The quotient is `< 2^64` since `n < 2^128 <= d * 2^64`.
533
#[inline(always)]
534
41.6k
fn gcd_div(n: u128, d: u128) -> (u64, u128) {
535
41.6k
    count!(DIVIDES += 1);
536
41.6k
    let (n1, n0) = ((n >> 64) as u64, n as u64);
537
41.6k
    let (mut d1, mut d0) = ((d >> 64) as u64, d as u64);
538
41.6k
    strict_assert!(d1 != 0);
539
41.6k
    let (q, r) = (n1 / d1, n1 % d1);
540
41.6k
    let (q, rem) = if q > d1 {
541
        // Non-normalized divisor: when `d1`'s top word is small, the single-word
542
        // estimate `q = n1/d1` can exceed `d1`. Rare but genuinely reachable (a
543
        // b-step can drop the divisor below 2^32 before an a-step divides by it),
544
        // so this is required for correctness, not merely defensive; marked cold
545
        // because it is rare. Normalize `d1` to have its top bit set, then do one
546
        // 128/64 division.
547
3.58k
        core::hint::cold_path();
548
3.58k
        count!(GCD_DIV_NORM += 1);
549
3.58k
        let c = d1.leading_zeros();
550
3.58k
        let wc = 64 - c;
551
3.58k
        let n2 = n1 >> wc;
552
3.58k
        let n1n = (n1 << c) | (n0 >> wc);
553
3.58k
        let n0n = n0 << c;
554
3.58k
        d1 = (d1 << c) | (d0 >> wc);
555
3.58k
        d0 <<= c;
556
3.58k
        let (mut q, rem1) = div_2by1(n2, n1n, d1);
557
3.58k
        let prod = (q as u128) * (d0 as u128);
558
3.58k
        let (mut t1, mut t0) = ((prod >> 64) as u64, prod as u64);
559
3.58k
        if t1 > rem1 || (t1 == rem1 && t0 > n0n) {
560
236
            q -= 1;
561
236
            let (nt0, br) = t0.overflowing_sub(d0);
562
236
            t0 = nt0;
563
236
            t1 = t1.wrapping_sub(d1).wrapping_sub(br as u64);
564
3.34k
        }
565
3.58k
        let (rr0, br) = n0n.overflowing_sub(t0);
566
3.58k
        let rr1 = rem1.wrapping_sub(t1).wrapping_sub(br as u64);
567
3.58k
        let rr = ((rr1 as u128) << 64) | rr0 as u128;
568
3.58k
        (q, rr >> c) // undo normalization
569
    } else {
570
38.0k
        let mut q = q;
571
38.0k
        let prod = (q as u128).wrapping_mul(d0 as u128);
572
38.0k
        let (mut t1, mut t0) = ((prod >> 64) as u64, prod as u64);
573
38.0k
        if t1 > r || (t1 == r && t0 > n0) {
574
694
            q -= 1;
575
694
            let (nt0, br) = t0.overflowing_sub(d0);
576
694
            t0 = nt0;
577
694
            t1 = t1.wrapping_sub(d1).wrapping_sub(br as u64);
578
37.4k
        }
579
38.0k
        let (rr0, br) = n0.overflowing_sub(t0);
580
38.0k
        let rr1 = r.wrapping_sub(t1).wrapping_sub(br as u64);
581
38.0k
        (q, ((rr1 as u128) << 64) | rr0 as u128)
582
    };
583
    // Exact reconstruction: cannot wrap for a correct result since q·d + r = n < 2^128.
584
41.6k
    strict_assert!(rem < d && (q as u128).wrapping_mul(d).wrapping_add(rem) == n, "gcd_div: bad quotient or remainder");
585
41.6k
    (q, rem)
586
41.6k
}
587
588
/// Multiply-accumulate: `acc + m·w + carry`, returning `(low 64 bits, high 64
589
/// bits)`. The high word is the carry into the next limb. A single widening
590
/// `64x64->128` multiply plus an add-with-carry; the carry is one word.
591
#[inline(always)]
592
36.0k
fn mac(acc: u64, m: u64, w: u64, carry: u64) -> (u64, u64) {
593
36.0k
    let t = (m as u128).wrapping_mul(w as u128).wrapping_add(acc as u128).wrapping_add(carry as u128);
594
36.0k
    (t as u64, (t >> 64) as u64)
595
36.0k
}
596
597
/// Multiply-subtract-borrow: `acc - m·w - borrow`, returning `(low 64 bits,
598
/// borrow)`. The borrow is the magnitude subtracted off the next limb. It fits
599
/// in one word because callers pass `m < 2^63` (the [`hgcd2`] entry bound), so
600
/// `m·w + borrow < 2^127 + 2^64` and its high word stays below `2^63`.
601
#[inline(always)]
602
36.0k
fn msb(acc: u64, m: u64, w: u64, borrow: u64) -> (u64, u64) {
603
36.0k
    let sub = (m as u128).wrapping_mul(w as u128).wrapping_add(borrow as u128);
604
36.0k
    let (lo, b) = acc.overflowing_sub(sub as u64);
605
36.0k
    (lo, ((sub >> 64) as u64).wrapping_add(b as u64))
606
36.0k
}
607
608
/// `(x, y) <- (a·x - b·y, d·y - c·x)`, over the `len` live limbs only (the
609
/// current larger length), returning the new `(x_len, y_len)`. Both results are
610
/// non-negative and fit in `len` limbs for matrices from [`hgcd2`], so
611
/// the limbs above `len` (already zero) stay zero. Tracking lengths here lets
612
/// passes shrink with the remainders instead of always touching all limbs.
613
///
614
/// Each output uses a multiply-accumulate / multiply-subtract structure: a `mac`
615
/// carry chain for the additive term and an independent `msb` borrow chain for
616
/// the subtractive one, both single-word. Keeping the two chains independent
617
/// shortens the loop-carried dependency versus a fused signed-`i128` accumulator,
618
/// which would serialize a two-register carry plus a per-limb sign-extension
619
/// every step.
620
#[inline]
621
9.00k
fn apply_matrix_xy<A: LimbArray>(x: &mut A, y: &mut A, len: usize, a: u64, b: u64, c: u64, d: u64) -> (usize, usize) {
622
9.00k
    let (x, y) = (x.as_mut_slice(), y.as_mut_slice());
623
    // A single up-front bound: once the compiler knows `len` is within both
624
    // buffers, every `[i]` with `i < len` below is provably in-bounds, so the
625
    // per-limb bounds checks collapse into this one branch and no `unsafe` is
626
    // needed. `len` never exceeds the limb count here, so this never actually
627
    // panics.
628
9.00k
    assert!(len <= x.len() && x.len() == y.len(), "apply_matrix_xy: len exceeds the limb count");
629
9.00k
    count!(APPLY_XY_LIMBS += len as u64);
630
    // x' = a·x - b·y: `carry_ax` accumulates a·x, `borrow_x` peels off b·y.
631
9.00k
    let mut carry_ax: u64 = 0;
632
9.00k
    let mut borrow_x: u64 = 0;
633
    // y' = d·y - c·x.
634
9.00k
    let mut carry_dy: u64 = 0;
635
9.00k
    let mut borrow_y: u64 = 0;
636
637
18.0k
    for i in 0..len {
638
18.0k
        let xi = x[i];
639
18.0k
        let yi = y[i];
640
18.0k
641
18.0k
        let (px, ncx) = mac(0, a, xi, carry_ax);
642
18.0k
        let (nx, nbx) = msb(px, b, yi, borrow_x);
643
18.0k
        carry_ax = ncx;
644
18.0k
        borrow_x = nbx;
645
18.0k
646
18.0k
        let (py, ncy) = mac(0, d, yi, carry_dy);
647
18.0k
        let (ny, nby) = msb(py, c, xi, borrow_y);
648
18.0k
        carry_dy = ncy;
649
18.0k
        borrow_y = nby;
650
18.0k
651
18.0k
        x[i] = nx;
652
18.0k
        y[i] = ny;
653
18.0k
    }
654
    // Non-negative result fitting in `len` limbs: the positive carry-out exactly
655
    // cancels the negative borrow-out (both name the same high limb, which is 0).
656
9.00k
    strict_assert_eq!(carry_ax, borrow_x, "apply_matrix_xy: x went negative or overflowed len limbs");
657
9.00k
    strict_assert_eq!(carry_dy, borrow_y, "apply_matrix_xy: y went negative or overflowed len limbs");
658
659
13.1k
    let nlx = x[..len].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xyAyj2_E0Cs1uXV1nWfJt5_4u128
Line
Count
Source
659
13.1k
    let nlx = x[..len].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xypE0B6_
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xyAyj2_Es_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
659
9.00k
    let nlx = x[..len].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xypEs_0B6_
660
13.1k
    let nly = y[..len].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xyAyj2_Es0_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
660
13.1k
    let nly = y[..len].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xypEs0_0B6_
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xyAyj2_Es1_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
660
9.00k
    let nly = y[..len].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xypEs1_0B6_
661
9.00k
    (nlx, nly)
662
9.00k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xyAyj2_ECs1uXV1nWfJt5_4u128
Line
Count
Source
621
9.00k
fn apply_matrix_xy<A: LimbArray>(x: &mut A, y: &mut A, len: usize, a: u64, b: u64, c: u64, d: u64) -> (usize, usize) {
622
9.00k
    let (x, y) = (x.as_mut_slice(), y.as_mut_slice());
623
    // A single up-front bound: once the compiler knows `len` is within both
624
    // buffers, every `[i]` with `i < len` below is provably in-bounds, so the
625
    // per-limb bounds checks collapse into this one branch and no `unsafe` is
626
    // needed. `len` never exceeds the limb count here, so this never actually
627
    // panics.
628
9.00k
    assert!(len <= x.len() && x.len() == y.len(), "apply_matrix_xy: len exceeds the limb count");
629
9.00k
    count!(APPLY_XY_LIMBS += len as u64);
630
    // x' = a·x - b·y: `carry_ax` accumulates a·x, `borrow_x` peels off b·y.
631
9.00k
    let mut carry_ax: u64 = 0;
632
9.00k
    let mut borrow_x: u64 = 0;
633
    // y' = d·y - c·x.
634
9.00k
    let mut carry_dy: u64 = 0;
635
9.00k
    let mut borrow_y: u64 = 0;
636
637
18.0k
    for i in 0..len {
638
18.0k
        let xi = x[i];
639
18.0k
        let yi = y[i];
640
18.0k
641
18.0k
        let (px, ncx) = mac(0, a, xi, carry_ax);
642
18.0k
        let (nx, nbx) = msb(px, b, yi, borrow_x);
643
18.0k
        carry_ax = ncx;
644
18.0k
        borrow_x = nbx;
645
18.0k
646
18.0k
        let (py, ncy) = mac(0, d, yi, carry_dy);
647
18.0k
        let (ny, nby) = msb(py, c, xi, borrow_y);
648
18.0k
        carry_dy = ncy;
649
18.0k
        borrow_y = nby;
650
18.0k
651
18.0k
        x[i] = nx;
652
18.0k
        y[i] = ny;
653
18.0k
    }
654
    // Non-negative result fitting in `len` limbs: the positive carry-out exactly
655
    // cancels the negative borrow-out (both name the same high limb, which is 0).
656
9.00k
    strict_assert_eq!(carry_ax, borrow_x, "apply_matrix_xy: x went negative or overflowed len limbs");
657
9.00k
    strict_assert_eq!(carry_dy, borrow_y, "apply_matrix_xy: y went negative or overflowed len limbs");
658
659
9.00k
    let nlx = x[..len].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
660
9.00k
    let nly = y[..len].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
661
9.00k
    (nlx, nly)
662
9.00k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer15apply_matrix_xypEB4_
663
664
/// `(t0, t1) <- (a·t0 + b·t1, c·t0 + d·t1)`, growing by at most one limb.
665
/// All-positive (the cofactor matrix uses `+` signs), so `u128` accumulators
666
/// suffice. Lengths are tracked inline; the cell at `max_len` is always written
667
/// (carry or zero) to keep `t[len..] == 0` without a separate clearing pass.
668
#[allow(clippy::too_many_arguments)]
669
#[inline]
670
9.00k
fn apply_matrix_t<C: LimbArray>(t0: &mut C, t1: &mut C, t0_len: &mut usize, t1_len: &mut usize, a: u64, b: u64, c: u64, d: u64) {
671
9.00k
    let (t0, t1) = (t0.as_mut_slice(), t1.as_mut_slice());
672
9.00k
    let max_len = (*t0_len).max(*t1_len);
673
9.00k
    count!(APPLY_T_LIMBS += max_len as u64);
674
    // Single up-front bound; see `apply_matrix_xy`. With `max_len` known to be
675
    // within both buffers, the body `[i]` (i < max_len), the carry write
676
    // `[max_len]`, and the length scan (`max_len + 1` limbs) are all provably
677
    // in-bounds, collapsing the per-limb checks into this one branch. The
678
    // cofactor magnitude is bounded by the modulus with 8 limbs of headroom,
679
    // so the bound always holds.
680
9.00k
    assert!(max_len < t0.len() && t0.len() == t1.len(), "cofactor exceeded the cofactor buffer");
681
9.00k
    let (a, b, c, d) = (a as u128, b as u128, c as u128, d as u128);
682
683
9.00k
    let mut c0: u128 = 0;
684
9.00k
    let mut c1: u128 = 0;
685
686
9.00k
    for i in 0..max_len {
687
9.00k
        let ti0 = t0[i] as u128;
688
9.00k
        let ti1 = t1[i] as u128;
689
9.00k
690
9.00k
        let p_at0 = a.wrapping_mul(ti0);
691
9.00k
        let p_bt1 = b.wrapping_mul(ti1);
692
9.00k
        let p_ct0 = c.wrapping_mul(ti0);
693
9.00k
        let p_dt1 = d.wrapping_mul(ti1);
694
9.00k
695
9.00k
        let n0 = c0.wrapping_add(p_at0).wrapping_add(p_bt1);
696
9.00k
        let n1 = c1.wrapping_add(p_ct0).wrapping_add(p_dt1);
697
9.00k
698
9.00k
        t0[i] = n0 as u64;
699
9.00k
        t1[i] = n1 as u64;
700
9.00k
        c0 = n0 >> 64;
701
9.00k
        c1 = n1 >> 64;
702
9.00k
    }
703
    // Carry-out (provably < 2^64); also clears any stale cell at `max_len`.
704
9.00k
    strict_assert!(c0 >> 64 == 0 && c1 >> 64 == 0, "apply_matrix_t: carry-out exceeded one limb");
705
9.00k
    t0[max_len] = c0 as u64;
706
9.00k
    t1[max_len] = c1 as u64;
707
708
14.8k
    let nl0 = t0[..max_len + 1].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tAyja_E0Cs1uXV1nWfJt5_4u128
Line
Count
Source
708
14.8k
    let nl0 = t0[..max_len + 1].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tpE0B6_
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tAyja_Es_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
708
9.00k
    let nl0 = t0[..max_len + 1].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tpEs_0B6_
709
14.7k
    let nl1 = t1[..max_len + 1].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tAyja_Es0_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
709
14.7k
    let nl1 = t1[..max_len + 1].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tpEs0_0B6_
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tAyja_Es1_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
709
9.00k
    let nl1 = t1[..max_len + 1].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tpEs1_0B6_
710
9.00k
    *t0_len = nl0.max(1);
711
9.00k
    *t1_len = nl1.max(1);
712
9.00k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tAyja_ECs1uXV1nWfJt5_4u128
Line
Count
Source
670
9.00k
fn apply_matrix_t<C: LimbArray>(t0: &mut C, t1: &mut C, t0_len: &mut usize, t1_len: &mut usize, a: u64, b: u64, c: u64, d: u64) {
671
9.00k
    let (t0, t1) = (t0.as_mut_slice(), t1.as_mut_slice());
672
9.00k
    let max_len = (*t0_len).max(*t1_len);
673
9.00k
    count!(APPLY_T_LIMBS += max_len as u64);
674
    // Single up-front bound; see `apply_matrix_xy`. With `max_len` known to be
675
    // within both buffers, the body `[i]` (i < max_len), the carry write
676
    // `[max_len]`, and the length scan (`max_len + 1` limbs) are all provably
677
    // in-bounds, collapsing the per-limb checks into this one branch. The
678
    // cofactor magnitude is bounded by the modulus with 8 limbs of headroom,
679
    // so the bound always holds.
680
9.00k
    assert!(max_len < t0.len() && t0.len() == t1.len(), "cofactor exceeded the cofactor buffer");
681
9.00k
    let (a, b, c, d) = (a as u128, b as u128, c as u128, d as u128);
682
683
9.00k
    let mut c0: u128 = 0;
684
9.00k
    let mut c1: u128 = 0;
685
686
9.00k
    for i in 0..max_len {
687
9.00k
        let ti0 = t0[i] as u128;
688
9.00k
        let ti1 = t1[i] as u128;
689
9.00k
690
9.00k
        let p_at0 = a.wrapping_mul(ti0);
691
9.00k
        let p_bt1 = b.wrapping_mul(ti1);
692
9.00k
        let p_ct0 = c.wrapping_mul(ti0);
693
9.00k
        let p_dt1 = d.wrapping_mul(ti1);
694
9.00k
695
9.00k
        let n0 = c0.wrapping_add(p_at0).wrapping_add(p_bt1);
696
9.00k
        let n1 = c1.wrapping_add(p_ct0).wrapping_add(p_dt1);
697
9.00k
698
9.00k
        t0[i] = n0 as u64;
699
9.00k
        t1[i] = n1 as u64;
700
9.00k
        c0 = n0 >> 64;
701
9.00k
        c1 = n1 >> 64;
702
9.00k
    }
703
    // Carry-out (provably < 2^64); also clears any stale cell at `max_len`.
704
9.00k
    strict_assert!(c0 >> 64 == 0 && c1 >> 64 == 0, "apply_matrix_t: carry-out exceeded one limb");
705
9.00k
    t0[max_len] = c0 as u64;
706
9.00k
    t1[max_len] = c1 as u64;
707
708
9.00k
    let nl0 = t0[..max_len + 1].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
709
9.00k
    let nl1 = t1[..max_len + 1].iter().rposition(|&w| w != 0).map_or(0, |i| i + 1);
710
9.00k
    *t0_len = nl0.max(1);
711
9.00k
    *t1_len = nl1.max(1);
712
9.00k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer14apply_matrix_tpEB4_
713
714
/// `t0 += q · t1`, where `q` is up to `N` limbs (the exact Euclidean quotient).
715
5.99k
fn t_add_qmul<C: LimbArray>(t0: &mut C, t0_len: &mut usize, q: &[u64], t1: &C, t1_len: usize) {
716
5.99k
    let (t0, t1) = (t0.as_mut_slice(), t1.as_slice());
717
5.99k
    let cap = t0.len();
718
11.9k
    for (i, &qi) in q.iter().enumerate() {
719
11.9k
        if qi == 0 {
720
3.34k
            continue;
721
8.63k
        }
722
8.63k
        let qi = qi as u128;
723
8.63k
        let mut carry: u64 = 0;
724
8.63k
        for (j, &t1j) in t1.iter().enumerate().take(t1_len) {
725
8.63k
            let k = i + j;
726
8.63k
            if k >= cap {
727
0
                strict_assert_eq!(carry, 0, "t_add_qmul: truncated nonzero limb");
728
0
                break;
729
8.63k
            }
730
8.63k
            let prod = qi.wrapping_mul(t1j as u128).wrapping_add(t0[k] as u128).wrapping_add(carry as u128);
731
8.63k
            t0[k] = prod as u64;
732
8.63k
            carry = (prod >> 64) as u64;
733
        }
734
8.63k
        let mut k = i + t1_len;
735
9.86k
        while carry > 0 && k < cap {
736
1.22k
            let (s, c) = t0[k].overflowing_add(carry);
737
1.22k
            t0[k] = s;
738
1.22k
            carry = c as u64;
739
1.22k
            k += 1;
740
1.22k
        }
741
8.63k
        strict_assert!(carry == 0, "t_add_qmul: carry lost off the top");
742
    }
743
5.99k
    *t0_len = top_len_t(t0);
744
5.99k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10t_add_qmulAyja_ECs1uXV1nWfJt5_4u128
Line
Count
Source
715
5.99k
fn t_add_qmul<C: LimbArray>(t0: &mut C, t0_len: &mut usize, q: &[u64], t1: &C, t1_len: usize) {
716
5.99k
    let (t0, t1) = (t0.as_mut_slice(), t1.as_slice());
717
5.99k
    let cap = t0.len();
718
11.9k
    for (i, &qi) in q.iter().enumerate() {
719
11.9k
        if qi == 0 {
720
3.34k
            continue;
721
8.63k
        }
722
8.63k
        let qi = qi as u128;
723
8.63k
        let mut carry: u64 = 0;
724
8.63k
        for (j, &t1j) in t1.iter().enumerate().take(t1_len) {
725
8.63k
            let k = i + j;
726
8.63k
            if k >= cap {
727
0
                strict_assert_eq!(carry, 0, "t_add_qmul: truncated nonzero limb");
728
0
                break;
729
8.63k
            }
730
8.63k
            let prod = qi.wrapping_mul(t1j as u128).wrapping_add(t0[k] as u128).wrapping_add(carry as u128);
731
8.63k
            t0[k] = prod as u64;
732
8.63k
            carry = (prod >> 64) as u64;
733
        }
734
8.63k
        let mut k = i + t1_len;
735
9.86k
        while carry > 0 && k < cap {
736
1.22k
            let (s, c) = t0[k].overflowing_add(carry);
737
1.22k
            t0[k] = s;
738
1.22k
            carry = c as u64;
739
1.22k
            k += 1;
740
1.22k
        }
741
8.63k
        strict_assert!(carry == 0, "t_add_qmul: carry lost off the top");
742
    }
743
5.99k
    *t0_len = top_len_t(t0);
744
5.99k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10t_add_qmulpEB4_
745
746
/// `out += w · t` (multi-limb unsigned), used by the single-limb tail.
747
17.6k
fn add_mul_word<C: LimbArray>(out: &mut C, out_len: &mut usize, w: u64, t: &C, t_len: usize) {
748
17.6k
    let (out, t) = (out.as_mut_slice(), t.as_slice());
749
17.6k
    let cap = out.len();
750
17.6k
    if w != 0 {
751
16.2k
        let w = w as u128;
752
16.2k
        let mut carry: u64 = 0;
753
24.7k
        for j in 0..t_len {
754
            // `j < t_len <= cap` always, but the bound also lets the compiler
755
            // clamp the trip count and skip the per-limb bounds check.
756
24.7k
            if j >= cap {
757
0
                break;
758
24.7k
            }
759
24.7k
            let prod = w.wrapping_mul(t[j] as u128).wrapping_add(out[j] as u128).wrapping_add(carry as u128);
760
24.7k
            out[j] = prod as u64;
761
24.7k
            carry = (prod >> 64) as u64;
762
        }
763
16.2k
        let mut k = t_len;
764
18.3k
        while carry > 0 && k < cap {
765
2.14k
            let (s, c) = out[k].overflowing_add(carry);
766
2.14k
            out[k] = s;
767
2.14k
            carry = c as u64;
768
2.14k
            k += 1;
769
2.14k
        }
770
16.2k
        strict_assert!(carry == 0, "add_mul_word: carry lost off the top");
771
1.43k
    }
772
17.6k
    *out_len = top_len_t(out);
773
17.6k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer12add_mul_wordAyja_ECs1uXV1nWfJt5_4u128
Line
Count
Source
747
17.6k
fn add_mul_word<C: LimbArray>(out: &mut C, out_len: &mut usize, w: u64, t: &C, t_len: usize) {
748
17.6k
    let (out, t) = (out.as_mut_slice(), t.as_slice());
749
17.6k
    let cap = out.len();
750
17.6k
    if w != 0 {
751
16.2k
        let w = w as u128;
752
16.2k
        let mut carry: u64 = 0;
753
24.7k
        for j in 0..t_len {
754
            // `j < t_len <= cap` always, but the bound also lets the compiler
755
            // clamp the trip count and skip the per-limb bounds check.
756
24.7k
            if j >= cap {
757
0
                break;
758
24.7k
            }
759
24.7k
            let prod = w.wrapping_mul(t[j] as u128).wrapping_add(out[j] as u128).wrapping_add(carry as u128);
760
24.7k
            out[j] = prod as u64;
761
24.7k
            carry = (prod >> 64) as u64;
762
        }
763
16.2k
        let mut k = t_len;
764
18.3k
        while carry > 0 && k < cap {
765
2.14k
            let (s, c) = out[k].overflowing_add(carry);
766
2.14k
            out[k] = s;
767
2.14k
            carry = c as u64;
768
2.14k
            k += 1;
769
2.14k
        }
770
16.2k
        strict_assert!(carry == 0, "add_mul_word: carry lost off the top");
771
1.43k
    }
772
17.6k
    *out_len = top_len_t(out);
773
17.6k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer12add_mul_wordpEB4_
774
775
/// `(q, r) = (x / y, x % y)`. Fast path for a single-limb divisor (the common
776
/// case once Lehmer has shrunk `y`); otherwise the uint type's own
777
/// [`LehmerOps::div_rem`].
778
5.99k
fn div_rem_step<U: LehmerOps>(x: &U::Limbs, y: &U::Limbs) -> (U::Limbs, U::Limbs) {
779
5.99k
    if y.as_slice()[1..].iter().all(|&w| w == 0) {
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer12div_rem_stepNtCs1uXV1nWfJt5_4u1287Uint128E0BT_
Line
Count
Source
779
2.99k
    if y.as_slice()[1..].iter().all(|&w| w == 0) {
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer12div_rem_stepoE0Cs1uXV1nWfJt5_4u128
Line
Count
Source
779
2.99k
    if y.as_slice()[1..].iter().all(|&w| w == 0) {
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer12div_rem_steppE0B6_
780
3.93k
        let (q, r0) = div_n_by_1(x, y.as_slice()[0]);
781
3.93k
        return (q, from_word(r0));
782
2.05k
    }
783
2.05k
    let (q, r) = U::from_limbs(*x).div_rem(U::from_limbs(*y));
784
2.05k
    (q.into_limbs(), r.into_limbs())
785
5.99k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer12div_rem_stepNtCs1uXV1nWfJt5_4u1287Uint128EBR_
Line
Count
Source
778
2.99k
fn div_rem_step<U: LehmerOps>(x: &U::Limbs, y: &U::Limbs) -> (U::Limbs, U::Limbs) {
779
2.99k
    if y.as_slice()[1..].iter().all(|&w| w == 0) {
780
1.96k
        let (q, r0) = div_n_by_1(x, y.as_slice()[0]);
781
1.96k
        return (q, from_word(r0));
782
1.02k
    }
783
1.02k
    let (q, r) = U::from_limbs(*x).div_rem(U::from_limbs(*y));
784
1.02k
    (q.into_limbs(), r.into_limbs())
785
2.99k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer12div_rem_stepoECs1uXV1nWfJt5_4u128
Line
Count
Source
778
2.99k
fn div_rem_step<U: LehmerOps>(x: &U::Limbs, y: &U::Limbs) -> (U::Limbs, U::Limbs) {
779
2.99k
    if y.as_slice()[1..].iter().all(|&w| w == 0) {
780
1.96k
        let (q, r0) = div_n_by_1(x, y.as_slice()[0]);
781
1.96k
        return (q, from_word(r0));
782
1.02k
    }
783
1.02k
    let (q, r) = U::from_limbs(*x).div_rem(U::from_limbs(*y));
784
1.02k
    (q.into_limbs(), r.into_limbs())
785
2.99k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer12div_rem_steppEB4_
786
787
/// `(q, r) = (x / d, x % d)` for a nonzero single-limb divisor `d` (the common
788
/// case once Lehmer has collapsed `y`). The divisor is constant across all
789
/// limbs, so a reciprocal is computed once and each limb costs two multiplies
790
/// instead of a hardware divide. Precomputed-reciprocal division
791
/// (Moller-Granlund, 2011).
792
3.93k
fn div_n_by_1<A: LimbArray>(x: &A, d: u64) -> (A, u64) {
793
3.93k
    strict_assert!(d != 0);
794
3.93k
    let x = x.as_slice();
795
3.93k
    let n = x.len();
796
3.93k
    let mut q = A::ZERO;
797
3.93k
    let qs = q.as_mut_slice();
798
3.93k
    let s = d.leading_zeros();
799
3.93k
    let r = if s == 0 {
800
        // `d` already has its top bit set: no normalization shift needed.
801
966
        let v = invert_limb(d);
802
966
        let mut r: u64 = 0;
803
1.93k
        for i in (0..n).rev() {
804
1.93k
            (qs[i], r) = div_2by1_preinv(r, x[i], d, v);
805
1.93k
        }
806
966
        r
807
    } else {
808
        // Normalize: divide `x << s` by `d << s` (same quotient); the bits shifted
809
        // off the top of `x` seed the running remainder, and `x % d = r >> s`.
810
2.97k
        let d_norm = d << s;
811
2.97k
        let v = invert_limb(d_norm);
812
2.97k
        let mut r = x[n - 1] >> (64 - s);
813
5.94k
        for i in (0..n).rev() {
814
5.94k
            let lo = if i == 0 { 0 } else { x[i - 1] };
815
5.94k
            let cur = (x[i] << s) | (lo >> (64 - s));
816
5.94k
            (qs[i], r) = div_2by1_preinv(r, cur, d_norm, v);
817
        }
818
2.97k
        r >> s
819
    };
820
3.93k
    strict_assert!(r < d, "div_n_by_1: remainder not below the divisor");
821
3.93k
    (q, r)
822
3.93k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10div_n_by_1Ayj2_ECs1uXV1nWfJt5_4u128
Line
Count
Source
792
3.93k
fn div_n_by_1<A: LimbArray>(x: &A, d: u64) -> (A, u64) {
793
3.93k
    strict_assert!(d != 0);
794
3.93k
    let x = x.as_slice();
795
3.93k
    let n = x.len();
796
3.93k
    let mut q = A::ZERO;
797
3.93k
    let qs = q.as_mut_slice();
798
3.93k
    let s = d.leading_zeros();
799
3.93k
    let r = if s == 0 {
800
        // `d` already has its top bit set: no normalization shift needed.
801
966
        let v = invert_limb(d);
802
966
        let mut r: u64 = 0;
803
1.93k
        for i in (0..n).rev() {
804
1.93k
            (qs[i], r) = div_2by1_preinv(r, x[i], d, v);
805
1.93k
        }
806
966
        r
807
    } else {
808
        // Normalize: divide `x << s` by `d << s` (same quotient); the bits shifted
809
        // off the top of `x` seed the running remainder, and `x % d = r >> s`.
810
2.97k
        let d_norm = d << s;
811
2.97k
        let v = invert_limb(d_norm);
812
2.97k
        let mut r = x[n - 1] >> (64 - s);
813
5.94k
        for i in (0..n).rev() {
814
5.94k
            let lo = if i == 0 { 0 } else { x[i - 1] };
815
5.94k
            let cur = (x[i] << s) | (lo >> (64 - s));
816
5.94k
            (qs[i], r) = div_2by1_preinv(r, cur, d_norm, v);
817
        }
818
2.97k
        r >> s
819
    };
820
3.93k
    strict_assert!(r < d, "div_n_by_1: remainder not below the divisor");
821
3.93k
    (q, r)
822
3.93k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10div_n_by_1pEB4_
823
824
/// Reciprocal of a normalized 64-bit divisor `d` (top bit set):
825
/// `v = floor((2^128 - 1) / d) - 2^64`, the "3/2" reciprocal consumed by
826
/// [`div_2by1_preinv`] (Moller-Granlund, "Improved division by invariant
827
/// integers", 2011). The lone wide divide here runs once per [`div_n_by_1`]
828
/// call (amortized over all `N` limbs), so it is off the per-limb hot path.
829
#[inline]
830
3.93k
const fn invert_limb(d: u64) -> u64 {
831
3.93k
    strict_assert!(d >> 63 == 1, "invert_limb requires a normalized divisor");
832
    // v = floor((2^128 - 1) / d) - 2^64 = floor(((!d)·2^64 + !0) / d): subtracting
833
    // 2^64·d from the numerator drops the quotient by exactly 2^64, and that
834
    // numerator's high word `!d` is `< d` for a normalized `d`, so the quotient
835
    // fits a u64 and the software 128/64 [`div_2by1`] computes it -- avoiding the
836
    // slow `u128 / u128` (`__udivti3`).
837
3.93k
    div_2by1(!d, u64::MAX, d).0
838
3.93k
}
839
840
/// `(nh·2^64 + nl) / d -> (q, r)` via the precomputed reciprocal `di` from
841
/// [`invert_limb`]. Requires `d` normalized (top bit set) and `nh < d` (so the
842
/// quotient fits a `u64`); the returned `r` satisfies `r < d`, sustaining that
843
/// precondition limb to limb. One widening multiply, a branchless first
844
/// correction, and a rarely-taken second. All `wrapping_*` (the workspace builds
845
/// with `overflow-checks = true`).
846
#[inline(always)]
847
7.87k
fn div_2by1_preinv(nh: u64, nl: u64, d: u64, di: u64) -> (u64, u64) {
848
7.87k
    strict_assert!(d >> 63 == 1 && nh < d);
849
    // (qh:ql) = nh·di + (nh + 1)·2^64 + nl
850
7.87k
    let prod = (nh as u128).wrapping_mul(di as u128);
851
7.87k
    let (mut qh, ql) = ((prod >> 64) as u64, prod as u64);
852
7.87k
    let (ql, carry) = ql.overflowing_add(nl);
853
7.87k
    qh = qh.wrapping_add(nh.wrapping_add(1)).wrapping_add(carry as u64);
854
855
7.87k
    let mut r = nl.wrapping_sub(qh.wrapping_mul(d));
856
    // First correction: if the estimate `qh` is one too high, `r` wraps above
857
    // `ql`; `mask` is all-ones then, folding the `-1`/`+d` fixup in branch-free.
858
7.87k
    let mask = 0u64.wrapping_sub((r > ql) as u64);
859
7.87k
    qh = qh.wrapping_add(mask);
860
7.87k
    r = r.wrapping_add(mask & d);
861
    // Second correction (rare): a still-too-small quotient leaves `r >= d`.
862
7.87k
    if r >= d {
863
14
        r = r.wrapping_sub(d);
864
14
        qh = qh.wrapping_add(1);
865
7.85k
    }
866
7.87k
    strict_assert!(r < d, "div_2by1_preinv: remainder not below the divisor");
867
7.87k
    (qh, r)
868
7.87k
}
869
870
/// `(hi·2^64 + lo) / d -> (q, r)`. Knuth Algorithm D specialized to 128/64.
871
/// Precondition: `d != 0` and `hi < d` (so the quotient fits in a `u64`).
872
///
873
/// Not on the per-limb hot path (that goes through [`div_n_by_1`]'s reciprocal
874
/// step, [`div_2by1_preinv`]): this generic divide is reached only once per
875
/// [`div_n_by_1`] (to seed the reciprocal, via [`invert_limb`]) and from
876
/// [`gcd_div`]'s rare normalization branch, so a plain software long division is
877
/// fine.
878
#[inline]
879
7.51k
const fn div_2by1(hi: u64, lo: u64, d: u64) -> (u64, u64) {
880
7.51k
    strict_assert!(d != 0);
881
7.51k
    strict_assert!(hi < d, "div_2by1 quotient would overflow u64");
882
883
7.51k
    let s = d.leading_zeros();
884
7.51k
    let dn = if s == 0 { d } else { d << s };
885
7.51k
    let un32 = if s == 0 { hi } else { (hi << s) | (lo >> (64 - s)) };
886
7.51k
    let un10 = if s == 0 { lo } else { lo << s };
887
888
7.51k
    let vn1 = dn >> 32;
889
7.51k
    let vn0 = dn & 0xFFFF_FFFF;
890
7.51k
    let un1 = un10 >> 32;
891
7.51k
    let un0 = un10 & 0xFFFF_FFFF;
892
893
7.51k
    let mut q1 = un32 / vn1;
894
7.51k
    let mut rhat = un32 - q1 * vn1;
895
7.97k
    while q1 >= (1u64 << 32) || q1 * vn0 > (rhat << 32) | un1 {
896
706
        q1 -= 1;
897
706
        rhat += vn1;
898
706
        if rhat >= (1u64 << 32) {
899
250
            break;
900
456
        }
901
    }
902
903
7.51k
    let un21 = (un32 << 32).wrapping_add(un1).wrapping_sub(q1.wrapping_mul(dn));
904
7.51k
    let mut q0 = un21 / vn1;
905
7.51k
    let mut rhat = un21 - q0 * vn1;
906
8.11k
    while q0 >= (1u64 << 32) || q0 * vn0 > (rhat << 32) | un0 {
907
1.28k
        q0 -= 1;
908
1.28k
        rhat += vn1;
909
1.28k
        if rhat >= (1u64 << 32) {
910
688
            break;
911
594
        }
912
    }
913
914
7.51k
    let r = (un21 << 32).wrapping_add(un0).wrapping_sub(q0.wrapping_mul(dn)) >> s;
915
7.51k
    let q = (q1 << 32) | q0;
916
7.51k
    strict_assert!(
917
7.51k
        r < d && (q as u128).wrapping_mul(d as u128).wrapping_add(r as u128) == ((hi as u128) << 64) | lo as u128,
918
        "div_2by1: bad quotient or remainder"
919
    );
920
7.51k
    (q, r)
921
7.51k
}
922
923
/// Extended Euclidean GCD of two `u64`s: `(gcd, cx, cy)` with `cx·x + cy·y = g`.
924
/// Called once per inversion, so `i128` intermediates are fine.
925
8.82k
fn gcd_ext_u64(mut x: u64, mut y: u64) -> (u64, i64, i64) {
926
8.82k
    let (x0, y0) = (x as i128, y as i128);
927
8.82k
    let (mut a, mut b, mut c, mut d) = (1i128, 0i128, 0i128, 1i128);
928
108k
    while y != 0 {
929
99.2k
        let q = (x / y) as i128;
930
99.2k
        let r = x.wrapping_sub((q as u64).wrapping_mul(y));
931
99.2k
        let (nc, nd) = (a.wrapping_sub(q.wrapping_mul(c)), b.wrapping_sub(q.wrapping_mul(d)));
932
99.2k
        a = c;
933
99.2k
        b = d;
934
99.2k
        c = nc;
935
99.2k
        d = nd;
936
99.2k
        x = y;
937
99.2k
        y = r;
938
99.2k
    }
939
    // Cofactors are bounded by the inputs (so the i64 narrowing is lossless) and
940
    // satisfy the Bezout identity for the returned gcd.
941
8.82k
    strict_assert!(i64::try_from(a).is_ok() && i64::try_from(b).is_ok(), "gcd_ext_u64: cofactor overflowed i64");
942
8.82k
    strict_assert_eq!(a.wrapping_mul(x0).wrapping_add(b.wrapping_mul(y0)), x as i128, "gcd_ext_u64: Bezout identity failed");
943
8.82k
    (x, a as i64, b as i64)
944
8.82k
}
945
946
/// Reduce a cofactor (with at most the modulus' significant limbs) into
947
/// `[0, m)`. The cofactor is bounded by `m` at loop exit, so a few
948
/// subtractions suffice; the `div_rem` branch is a defensive fallback.
949
4.54k
fn reduce_mod<U: LehmerOps>(value: &U::Cofactor, m: &U::Limbs) -> U::Limbs {
950
4.54k
    let n = U::Limbs::LEN;
951
36.3k
    strict_assert!(value.as_slice()[n..].iter().all(|&w| w == 0), "cofactor exceeded the modulus width");
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10reduce_modNtCs1uXV1nWfJt5_4u1287Uint128E0BR_
Line
Count
Source
951
18.1k
    strict_assert!(value.as_slice()[n..].iter().all(|&w| w == 0), "cofactor exceeded the modulus width");
_RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10reduce_modoE0Cs1uXV1nWfJt5_4u128
Line
Count
Source
951
18.1k
    strict_assert!(value.as_slice()[n..].iter().all(|&w| w == 0), "cofactor exceeded the modulus width");
Unexecuted instantiation: _RNCINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10reduce_modpE0B6_
952
4.54k
    let mut out = U::Limbs::ZERO;
953
4.54k
    out.as_mut_slice().copy_from_slice(&value.as_slice()[..n]);
954
4.54k
    for _ in 0..8 {
955
4.54k
        if cmp_n(out.as_slice(), m.as_slice()).is_lt() {
956
4.54k
            return out;
957
0
        }
958
0
        out = sub_n(&out, m);
959
    }
960
0
    U::from_limbs(out).div_rem(U::from_limbs(*m)).1.into_limbs()
961
4.54k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10reduce_modNtCs1uXV1nWfJt5_4u1287Uint128EBP_
Line
Count
Source
949
2.27k
fn reduce_mod<U: LehmerOps>(value: &U::Cofactor, m: &U::Limbs) -> U::Limbs {
950
2.27k
    let n = U::Limbs::LEN;
951
2.27k
    strict_assert!(value.as_slice()[n..].iter().all(|&w| w == 0), "cofactor exceeded the modulus width");
952
2.27k
    let mut out = U::Limbs::ZERO;
953
2.27k
    out.as_mut_slice().copy_from_slice(&value.as_slice()[..n]);
954
2.27k
    for _ in 0..8 {
955
2.27k
        if cmp_n(out.as_slice(), m.as_slice()).is_lt() {
956
2.27k
            return out;
957
0
        }
958
0
        out = sub_n(&out, m);
959
    }
960
0
    U::from_limbs(out).div_rem(U::from_limbs(*m)).1.into_limbs()
961
2.27k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10reduce_modoECs1uXV1nWfJt5_4u128
Line
Count
Source
949
2.27k
fn reduce_mod<U: LehmerOps>(value: &U::Cofactor, m: &U::Limbs) -> U::Limbs {
950
2.27k
    let n = U::Limbs::LEN;
951
2.27k
    strict_assert!(value.as_slice()[n..].iter().all(|&w| w == 0), "cofactor exceeded the modulus width");
952
2.27k
    let mut out = U::Limbs::ZERO;
953
2.27k
    out.as_mut_slice().copy_from_slice(&value.as_slice()[..n]);
954
2.27k
    for _ in 0..8 {
955
2.27k
        if cmp_n(out.as_slice(), m.as_slice()).is_lt() {
956
2.27k
            return out;
957
0
        }
958
0
        out = sub_n(&out, m);
959
    }
960
0
    U::from_limbs(out).div_rem(U::from_limbs(*m)).1.into_limbs()
961
2.27k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer10reduce_modpEB4_
962
963
/// Top 128-bit prefix of `x` and of `y`, both shifted left by the same amount so
964
/// the prefix of the larger operand `x` has its top bit set (the normalization
965
/// [`hgcd2`] expects). `y` is read at the same limb positions as `x`, so its
966
/// prefix is naturally the smaller. Requires `x` the larger operand and
967
/// `x_len >= 2`.
968
#[inline]
969
11.0k
fn highest_two_words_normalized(x: &[u64], y: &[u64], x_len: usize) -> (u128, u128) {
970
11.0k
    strict_assert!(x_len >= 2);
971
11.0k
    let i = x_len - 1;
972
11.0k
    let lz = x[i].leading_zeros();
973
11.0k
    let lo_idx_ok = i >= 2;
974
    // Combine the limbs at positions (i, i-1, i-2) into the top 128 bits after a
975
    // left shift by `lz`. `arr[i]`'s `lz` leading zeros guarantee no overflow.
976
22.1k
    let combine = |hi: u64, mid: u64, lo: u64| -> u128 {
977
22.1k
        let base = ((hi as u128) << 64) | (mid as u128);
978
22.1k
        if lz == 0 { base } else { (base << lz) | ((lo >> (64 - lz)) as u128) }
979
22.1k
    };
_RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer28highest_two_words_normalized0Cs1uXV1nWfJt5_4u128
Line
Count
Source
976
22.1k
    let combine = |hi: u64, mid: u64, lo: u64| -> u128 {
977
22.1k
        let base = ((hi as u128) << 64) | (mid as u128);
978
22.1k
        if lz == 0 { base } else { (base << lz) | ((lo >> (64 - lz)) as u128) }
979
22.1k
    };
Unexecuted instantiation: _RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer28highest_two_words_normalized0B5_
980
11.0k
    let x_lo = if lo_idx_ok { x[i - 2] } else { 0 };
981
11.0k
    let y_lo = if lo_idx_ok { y[i - 2] } else { 0 };
982
11.0k
    let (x_hi, y_hi) = (combine(x[i], x[i - 1], x_lo), combine(y[i], y[i - 1], y_lo));
983
11.0k
    strict_assert!(x_hi >> 127 == 1 && y_hi <= x_hi, "highest_two_words_normalized: prefixes unnormalized or misordered");
984
11.0k
    (x_hi, y_hi)
985
11.0k
}
986
987
/// A limb buffer holding the single word `w`.
988
#[inline]
989
25.6k
fn from_word<A: LimbArray>(w: u64) -> A {
990
25.6k
    let mut a = A::ZERO;
991
25.6k
    a.as_mut_slice()[0] = w;
992
25.6k
    a
993
25.6k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer9from_wordAyj2_ECs1uXV1nWfJt5_4u128
Line
Count
Source
989
16.6k
fn from_word<A: LimbArray>(w: u64) -> A {
990
16.6k
    let mut a = A::ZERO;
991
16.6k
    a.as_mut_slice()[0] = w;
992
16.6k
    a
993
16.6k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer9from_wordAyja_ECs1uXV1nWfJt5_4u128
Line
Count
Source
989
8.91k
fn from_word<A: LimbArray>(w: u64) -> A {
990
8.91k
    let mut a = A::ZERO;
991
8.91k
    a.as_mut_slice()[0] = w;
992
8.91k
    a
993
8.91k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer9from_wordpEB4_
994
995
#[inline]
996
16.1k
fn is_zero(x: &[u64]) -> bool {
997
18.0k
    x.iter().all(|&w| w == 0)
_RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer7is_zero0Cs1uXV1nWfJt5_4u128
Line
Count
Source
997
18.0k
    x.iter().all(|&w| w == 0)
Unexecuted instantiation: _RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer7is_zero0B5_
998
16.1k
}
999
1000
#[inline]
1001
19.8k
fn top_len(x: &[u64]) -> usize {
1002
25.3k
    x.iter().rposition(|&w| w != 0).map_or(0, |i| i + 1)
_RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer7top_len0Cs1uXV1nWfJt5_4u128
Line
Count
Source
1002
25.3k
    x.iter().rposition(|&w| w != 0).map_or(0, |i| i + 1)
Unexecuted instantiation: _RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer7top_len0B5_
_RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer7top_lens_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
1002
19.7k
    x.iter().rposition(|&w| w != 0).map_or(0, |i| i + 1)
Unexecuted instantiation: _RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer7top_lens_0B5_
1003
19.8k
}
1004
1005
/// Significant length of a cofactor buffer; 0 maps to 1 by convention.
1006
#[inline]
1007
23.6k
fn top_len_t(x: &[u64]) -> usize {
1008
222k
    x.iter().rposition(|&w| w != 0).map_or(1, |i| i + 1)
_RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer9top_len_t0Cs1uXV1nWfJt5_4u128
Line
Count
Source
1008
222k
    x.iter().rposition(|&w| w != 0).map_or(1, |i| i + 1)
Unexecuted instantiation: _RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer9top_len_t0B5_
_RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer9top_len_ts_0Cs1uXV1nWfJt5_4u128
Line
Count
Source
1008
22.0k
    x.iter().rposition(|&w| w != 0).map_or(1, |i| i + 1)
Unexecuted instantiation: _RNCNvNtCs8KLYHAG7u19_10kaspa_math6lehmer9top_len_ts_0B5_
1009
23.6k
}
1010
1011
#[inline]
1012
2.40k
fn sub_n<A: LimbArray>(a: &A, b: &A) -> A {
1013
2.40k
    let mut out = A::ZERO;
1014
2.40k
    let (a, b, o) = (a.as_slice(), b.as_slice(), out.as_mut_slice());
1015
2.40k
    let mut borrow = 0u64;
1016
4.80k
    for i in 0..o.len() {
1017
4.80k
        let (d1, b1) = a[i].overflowing_sub(b[i]);
1018
4.80k
        let (d2, b2) = d1.overflowing_sub(borrow);
1019
4.80k
        o[i] = d2;
1020
4.80k
        borrow = (b1 | b2) as u64;
1021
4.80k
    }
1022
2.40k
    out
1023
2.40k
}
_RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer5sub_nAyj2_ECs1uXV1nWfJt5_4u128
Line
Count
Source
1012
2.40k
fn sub_n<A: LimbArray>(a: &A, b: &A) -> A {
1013
2.40k
    let mut out = A::ZERO;
1014
2.40k
    let (a, b, o) = (a.as_slice(), b.as_slice(), out.as_mut_slice());
1015
2.40k
    let mut borrow = 0u64;
1016
4.80k
    for i in 0..o.len() {
1017
4.80k
        let (d1, b1) = a[i].overflowing_sub(b[i]);
1018
4.80k
        let (d2, b2) = d1.overflowing_sub(borrow);
1019
4.80k
        o[i] = d2;
1020
4.80k
        borrow = (b1 | b2) as u64;
1021
4.80k
    }
1022
2.40k
    out
1023
2.40k
}
Unexecuted instantiation: _RINvNtCs8KLYHAG7u19_10kaspa_math6lehmer5sub_npEB4_
1024
1025
/// Full-width limb compare of two equal-length buffers.
1026
#[inline]
1027
27.2k
fn cmp_n(a: &[u64], b: &[u64]) -> Ordering {
1028
27.2k
    strict_assert_eq!(a.len(), b.len());
1029
27.2k
    cmp_prefix(a, b, a.len())
1030
27.2k
}
1031
1032
#[inline]
1033
36.0k
fn cmp_prefix(a: &[u64], b: &[u64], n: usize) -> Ordering {
1034
42.3k
    for i in (0..n).rev() {
1035
42.3k
        match a[i].cmp(&b[i]) {
1036
6.91k
            Ordering::Equal => continue,
1037
35.4k
            other => return other,
1038
        }
1039
    }
1040
612
    Ordering::Equal
1041
36.0k
}
1042
1043
#[cfg(test)]
1044
mod tests {
1045
    use super::*;
1046
    use crate::Uint3072;
1047
    use rand_chacha::{
1048
        ChaCha8Rng,
1049
        rand_core::{RngCore, SeedableRng},
1050
    };
1051
1052
    const N: usize = 48;
1053
1054
    // MuHash prime: 2^3072 - 1103717.
1055
    const MUHASH_PRIME: Uint3072 = {
1056
        let mut max = Uint3072::MAX;
1057
        max.0[0] -= 1103717 - 1;
1058
        max
1059
    };
1060
1061
    fn lehmer_inv(value: [u64; N], modulus: [u64; N]) -> Option<[u64; N]> {
1062
        let mut out = [0u64; N];
1063
        invert::<Uint3072>(value, modulus, &mut out).then_some(out)
1064
    }
1065
1066
    // Malachite reference oracle over any LehmerOps type. The generic `Uint::mod_inverse` was
1067
    // removed, so this calls malachite's `Natural::mod_inverse` directly (malachite is a
1068
    // dev-dependency, available here). Requires `value < modulus`, like `invert`.
1069
    fn malachite_inv<U: LehmerOps>(value: U, modulus: U) -> Option<U> {
1070
        use malachite_base::num::arithmetic::traits::ModInverse;
1071
        use malachite_nz::natural::Natural;
1072
        let x = Natural::from_limbs_asc(value.into_limbs().as_slice());
1073
        let m = Natural::from_limbs_asc(modulus.into_limbs().as_slice());
1074
        x.mod_inverse(m).map(|inv| {
1075
            let mut out = U::Limbs::ZERO;
1076
            let limbs = inv.into_limbs_asc();
1077
            out.as_mut_slice()[..limbs.len()].copy_from_slice(&limbs);
1078
            U::from_limbs(out)
1079
        })
1080
    }
1081
1082
    fn addmod(a: Uint3072, b: Uint3072, m: Uint3072) -> Uint3072 {
1083
        let (res, overflow) = a.overflowing_add(b);
1084
        if overflow || res >= m { res.overflowing_sub(m).0 } else { res }
1085
    }
1086
1087
    /// `(a * b) mod m` via binary double-and-add (overflow-safe oracle).
1088
    fn mulmod(a: Uint3072, b: Uint3072, m: Uint3072) -> Uint3072 {
1089
        let mut result = Uint3072::ZERO;
1090
        let mut base = a % m;
1091
        let mut exp = b;
1092
        while !exp.is_zero() {
1093
            if exp.0[0] & 1 == 1 {
1094
                result = addmod(result, base, m);
1095
            }
1096
            base = addmod(base, base, m);
1097
            exp = exp >> 1;
1098
        }
1099
        result
1100
    }
1101
1102
    #[test]
1103
    fn matches_malachite_muhash_prime() {
1104
        // Lehmer must agree bit-for-bit with malachite (the reference) on the MuHash prime.
1105
        let mut rng = ChaCha8Rng::seed_from_u64(42);
1106
        let mut buf = [0u8; Uint3072::BYTES];
1107
        for _ in 0..2000 {
1108
            rng.fill_bytes(&mut buf);
1109
            let v = Uint3072::from_le_bytes(buf) % MUHASH_PRIME;
1110
            if v.is_zero() {
1111
                continue;
1112
            }
1113
            let expected = malachite_inv(v, MUHASH_PRIME).unwrap();
1114
            let got = lehmer_inv(v.0, MUHASH_PRIME.0).unwrap();
1115
            assert_eq!(got.as_slice(), expected.0.as_slice(), "v={v}");
1116
        }
1117
    }
1118
1119
    #[test]
1120
    fn product_is_one_muhash_prime() {
1121
        // v * inv(v) == 1 (mod prime), independent of any oracle.
1122
        let mut rng = ChaCha8Rng::seed_from_u64(99);
1123
        let mut buf = [0u8; Uint3072::BYTES];
1124
        for _ in 0..500 {
1125
            rng.fill_bytes(&mut buf);
1126
            let v = Uint3072::from_le_bytes(buf) % MUHASH_PRIME;
1127
            if v.is_zero() {
1128
                continue;
1129
            }
1130
            let inv = lehmer_inv(v.0, MUHASH_PRIME.0).unwrap();
1131
            assert_eq!(mulmod(v, Uint3072(inv), MUHASH_PRIME), Uint3072::from_u64(1), "v={v}");
1132
        }
1133
    }
1134
1135
    #[test]
1136
    fn small_values_force_multilimb_quotient() {
1137
        // Tiny `value` makes the first quotient ~48 limbs, exercising the
1138
        // multi-limb `div_rem` fallback and the wide `t_add_qmul` path.
1139
        for v_small in [1u64, 2, 3, 5, 7, 1103717, u64::MAX] {
1140
            let v = Uint3072::from_u64(v_small);
1141
            let inv = lehmer_inv(v.0, MUHASH_PRIME.0).unwrap();
1142
            assert_eq!(mulmod(v, Uint3072(inv), MUHASH_PRIME), Uint3072::from_u64(1), "v={v_small}");
1143
        }
1144
    }
1145
1146
    #[test]
1147
    fn edge_cases_muhash_prime() {
1148
        let one = Uint3072::from_u64(1);
1149
        let p_minus_1 = MUHASH_PRIME.overflowing_sub(one).0;
1150
        assert_eq!(lehmer_inv(one.0, MUHASH_PRIME.0).unwrap().as_slice(), one.0.as_slice());
1151
        assert_eq!(lehmer_inv(p_minus_1.0, MUHASH_PRIME.0).unwrap().as_slice(), p_minus_1.0.as_slice());
1152
        assert!(lehmer_inv(Uint3072::ZERO.0, MUHASH_PRIME.0).is_none());
1153
    }
1154
1155
    #[test]
1156
    fn div_n_by_1_matches_uint_div() {
1157
        // The reciprocal n-by-1 division must agree with Uint3072::div_rem across
1158
        // tiny, normalized (top bit set), and arbitrary unnormalized divisors.
1159
        let mut rng = ChaCha8Rng::seed_from_u64(7);
1160
        let mut buf = [0u8; Uint3072::BYTES];
1161
        for _ in 0..20000 {
1162
            rng.fill_bytes(&mut buf);
1163
            let x = Uint3072::from_le_bytes(buf);
1164
            let d = match rng.next_u64() % 4 {
1165
                0 => 1 + (rng.next_u64() % 1000),  // tiny (large shift)
1166
                1 => rng.next_u64() | (1 << 63),   // already normalized
1167
                2 => (rng.next_u64() >> 7).max(1), // unnormalized
1168
                _ => rng.next_u64().max(1),        // arbitrary
1169
            };
1170
            let (q, r) = div_n_by_1(&x.0, d);
1171
            let mut dl = [0u64; N];
1172
            dl[0] = d;
1173
            let (eq, er) = Uint3072(x.0).div_rem(Uint3072(dl));
1174
            assert_eq!(q.as_slice(), eq.0.as_slice(), "quotient mismatch x={x} d={d}");
1175
            assert_eq!(r, er.0[0], "remainder mismatch x={x} d={d}");
1176
        }
1177
        // Boundary divisors: 1, 2, MAX, 2^63 (min normalized), 2^63-1 (max
1178
        // unnormalized), and the MuHash prime difference constant.
1179
        for &d in &[1u64, 2, 3, u64::MAX, 1 << 63, (1 << 63) - 1, 1103717] {
1180
            rng.fill_bytes(&mut buf);
1181
            let x = Uint3072::from_le_bytes(buf);
1182
            let (q, r) = div_n_by_1(&x.0, d);
1183
            let mut dl = [0u64; N];
1184
            dl[0] = d;
1185
            let (eq, er) = Uint3072(x.0).div_rem(Uint3072(dl));
1186
            assert_eq!(q.as_slice(), eq.0.as_slice(), "quotient mismatch x={x} d={d}");
1187
            assert_eq!(r, er.0[0], "remainder mismatch x={x} d={d}");
1188
        }
1189
    }
1190
1191
    #[test]
1192
    fn gcd_div_matches_u128_both_branches() {
1193
        // `gcd_div` computes `(n/d, n%d)` for 128-bit `n, d` with `d >= 2^64`.
1194
        // Cover both arms against the native `u128` oracle: the normal arm
1195
        // (`q = n1/d1 <= d1`) and the rare normalization arm (`q > d1`), which
1196
        // fires when the divisor's top word is small. The normalization arm is
1197
        // hit only occasionally through `invert`, so pin it directly here.
1198
        let oracle = |n: u128, d: u128| ((n / d) as u64, n % d);
1199
1200
        // Explicit cases that force `q > d1` (small divisor top word).
1201
        let forcing: &[(u128, u128)] = &[
1202
            (u128::MAX, (1u128 << 64) | 1), // d1 = 1
1203
            (u128::MAX, 1u128 << 64),       // d = 2^64
1204
            ((0xDEAD_BEEFu128 << 96) | 0x1234, (1u128 << 64) | u64::MAX as u128),
1205
            (u128::MAX, (2u128 << 64) | 7),                     // d1 = 2
1206
            (u128::MAX - 12345, (0x1_0000u128 << 64) | 0xABCD), // d1 = 2^16
1207
        ];
1208
        for &(n, d) in forcing {
1209
            assert!((n >> 64) as u64 / (d >> 64) as u64 > (d >> 64) as u64, "case does not force q>d1");
1210
            assert_eq!(gcd_div(n, d), oracle(n, d), "q>d1 arm mismatch n={n} d={d}");
1211
        }
1212
        // Normal arm (`q <= d1`): divisor with a large top word.
1213
        for &(n, d) in &[(u128::MAX, (u64::MAX as u128) << 64 | 3), (1u128 << 127, (1u128 << 127) | 1)] {
1214
            assert!((n >> 64) as u64 / (d >> 64) as u64 <= (d >> 64) as u64, "case is not the normal arm");
1215
            assert_eq!(gcd_div(n, d), oracle(n, d), "normal arm mismatch n={n} d={d}");
1216
        }
1217
1218
        // Randomized, biased to small divisor top words so most iterations take
1219
        // the `q > d1` arm; every result checked bit-for-bit against `u128`.
1220
        let mut rng = ChaCha8Rng::seed_from_u64(2024);
1221
        let mut branch_hits = 0u64;
1222
        for _ in 0..200_000 {
1223
            let n = ((rng.next_u64() as u128) << 64) | rng.next_u64() as u128;
1224
            let d1 = (rng.next_u64() % (1 << 20)) + 1; // 1 ..= 2^20
1225
            let d = ((d1 as u128) << 64) | rng.next_u64() as u128;
1226
            assert_eq!(gcd_div(n, d), oracle(n, d), "random gcd_div mismatch n={n} d={d}");
1227
            if (n >> 64) as u64 / d1 > d1 {
1228
                branch_hits += 1;
1229
            }
1230
        }
1231
        assert!(branch_hits > 1000, "q>d1 arm under-exercised: only {branch_hits} hits");
1232
    }
1233
1234
    #[test]
1235
    fn q_gt_d1_vector_matches_malachite() {
1236
        // A full-inverse input that drives `gcd_div` through its `q > d1`
1237
        // normalization arm, pinned as an explicit regression case (that arm is
1238
        // otherwise only hit occasionally by the random-vector tests).
1239
        let v: [u64; N] = [
1240
            0xbaac78a3d8d04a44,
1241
            0x454126b8efd12383,
1242
            0xa93bb055d701be60,
1243
            0xe940f5627944ba89,
1244
            0x68842c54edf3df88,
1245
            0xf7c6332a4e2be869,
1246
            0x396e8533e978070a,
1247
            0x2703f08794977aad,
1248
            0x373dc910525ad335,
1249
            0x52520bee468a9073,
1250
            0xf4580a27f3ca91ee,
1251
            0x5de1060b3d65f732,
1252
            0x4b1072d2e2cc0da1,
1253
            0x4e2a032ba51f609a,
1254
            0xeae5995402410005,
1255
            0x885f9eb04a59ab3c,
1256
            0x165446e913daa18e,
1257
            0xf2b1311c3eb843c0,
1258
            0x630b8232162a2fca,
1259
            0xe4224b2c61bafd4e,
1260
            0x25397d500e52b519,
1261
            0x7cd55e35a4ac6022,
1262
            0x8629892065e194c0,
1263
            0x713ea3ded7bcd68c,
1264
            0xf1f138b0052d1fdc,
1265
            0x7974414d82958c31,
1266
            0xc29243783567cf96,
1267
            0xf9214af62a72ec1e,
1268
            0xa1e4feb97fdbfe07,
1269
            0x5c92a43f23a3989e,
1270
            0x1ad829d92571a26a,
1271
            0xd09dd31bf57bf618,
1272
            0x00772f32162d2fd3,
1273
            0x1c0dcedad1142715,
1274
            0x677b857b2c9c2713,
1275
            0xe64b41b0e187f9e7,
1276
            0x4062f89c0309cd59,
1277
            0x3edc673c30e10664,
1278
            0x330b6c680b777302,
1279
            0x423676df7dfd8ccf,
1280
            0x347fe8b7dee8ca42,
1281
            0x0fb4eb8629ef71c1,
1282
            0x5e898abada4103ac,
1283
            0x39820234bad59fb2,
1284
            0xd780c6aeaaa89812,
1285
            0x61bdb22ece416ba0,
1286
            0x79f1821384ef3f44,
1287
            0x803912aebf95eede,
1288
        ];
1289
        let got = lehmer_inv(v, MUHASH_PRIME.0).unwrap();
1290
        assert_eq!(got.as_slice(), malachite_inv(Uint3072(v), MUHASH_PRIME).unwrap().0.as_slice());
1291
        assert_eq!(mulmod(Uint3072(v), Uint3072(got), MUHASH_PRIME), Uint3072::from_u64(1));
1292
    }
1293
1294
    #[test]
1295
    fn hgcd2_none_when_top_word_below_two() {
1296
        // The guess returns `None` (caller falls back to one exact division step)
1297
        // exactly when a top word is `< 2`; otherwise it confirms a matrix.
1298
        assert!(hgcd2(1, 0, 5, 0).is_none()); // ah < 2
1299
        assert!(hgcd2(5, 0, 0, 9).is_none()); // bh < 2
1300
        assert!(hgcd2(u64::MAX, 0, u64::MAX >> 1, 0).is_some()); // well-separated -> confirms a quotient
1301
    }
1302
1303
    /// Extended-Euclid reference for u64 moduli, in i128 (all magnitudes fit).
1304
    fn egcd_inv_u64(v: u64, m: u64) -> Option<u64> {
1305
        let (mut old_r, mut r) = (m as i128, v as i128);
1306
        let (mut old_t, mut t) = (0i128, 1i128);
1307
        while r != 0 {
1308
            let q = old_r / r;
1309
            (old_r, r) = (r, old_r - q * r);
1310
            (old_t, t) = (t, old_t - q * t);
1311
        }
1312
        (old_r == 1).then(|| old_t.rem_euclid(m as i128) as u64)
1313
    }
1314
1315
    #[test]
1316
    fn u64_exhaustive_small_range() {
1317
        // Every (value, modulus) with modulus in [2, 512) and value in [0, 4m):
1318
        // agreement with the extended-Euclid oracle, covering gcd != 1 -> None
1319
        // and the value-reduction path.
1320
        for m in 2u64..512 {
1321
            for v in 0..m * 4 {
1322
                let got = v.lehmer_invert(m);
1323
                assert_eq!(got, egcd_inv_u64(v % m, m), "v={v} m={m}");
1324
                if let Some(inv) = got {
1325
                    assert_eq!((inv as u128 * (v % m) as u128 % m as u128) as u64, 1, "v={v} m={m}");
1326
                }
1327
            }
1328
        }
1329
    }
1330
1331
    #[test]
1332
    fn u64_random_matches_oracle() {
1333
        let mut rng = ChaCha8Rng::seed_from_u64(17);
1334
        for _ in 0..200_000 {
1335
            let m = rng.next_u64().max(2);
1336
            let v = rng.next_u64();
1337
            assert_eq!(v.lehmer_invert(m), egcd_inv_u64(v % m, m), "v={v} m={m}");
1338
        }
1339
    }
1340
1341
    #[test]
1342
    fn u128_random_matches_malachite() {
1343
        // Primitive u128 impl vs malachite, mixing full-width and single-limb
1344
        // operands to cross the multi-limb/single-limb phase boundary.
1345
        let mut rng = ChaCha8Rng::seed_from_u64(23);
1346
        let mut sample = |wide: bool| {
1347
            if wide { ((rng.next_u64() as u128) << 64) | rng.next_u64() as u128 } else { rng.next_u64() as u128 }
1348
        };
1349
        for i in 0..50_000u32 {
1350
            let m = sample(i % 4 != 0).max(2);
1351
            let v = sample(i % 3 != 0);
1352
            let got = v.lehmer_invert(m);
1353
            assert_eq!(got, malachite_inv(v % m, m), "v={v} m={m}");
1354
        }
1355
    }
1356
1357
    #[test]
1358
    fn uint_sizes_match_malachite() {
1359
        // The construct_uint! impls at the other production widths, vs malachite.
1360
        use crate::{Uint192, Uint256, Uint320};
1361
        let mut rng = ChaCha8Rng::seed_from_u64(29);
1362
        macro_rules! check {
1363
            ($ty:ty, $iters:expr) => {{
1364
                let mut buf = [0u8; <$ty>::BYTES];
1365
                for _ in 0..$iters {
1366
                    rng.fill_bytes(&mut buf);
1367
                    let m = <$ty>::from_le_bytes(buf);
1368
                    if m < 2u64 {
1369
                        continue;
1370
                    }
1371
                    rng.fill_bytes(&mut buf);
1372
                    let v = <$ty>::from_le_bytes(buf);
1373
                    assert_eq!(v.lehmer_invert(m), malachite_inv(v % m, m), "v={v} m={m}");
1374
                }
1375
            }};
1376
        }
1377
        check!(Uint192, 3000);
1378
        check!(Uint256, 3000);
1379
        check!(Uint320, 3000);
1380
    }
1381
1382
    #[test]
1383
    fn lehmer_invert_edge_semantics() {
1384
        // Totality of the trait method: degenerate moduli, unreduced values,
1385
        // non-coprime pairs.
1386
        assert_eq!(0u64.lehmer_invert(0), None);
1387
        assert_eq!(5u64.lehmer_invert(0), None);
1388
        assert_eq!(5u64.lehmer_invert(1), None);
1389
        assert_eq!(1u64.lehmer_invert(2), Some(1));
1390
        assert_eq!(7u64.lehmer_invert(7), None); // value == modulus reduces to 0
1391
        assert_eq!(9u64.lehmer_invert(7), 2u64.lehmer_invert(7)); // reduction path
1392
        assert_eq!(4u64.lehmer_invert(6), None); // gcd = 2
1393
        assert_eq!(3u64.lehmer_invert(8), Some(3)); // even modulus, coprime value
1394
        assert_eq!(3u128.lehmer_invert(8), Some(3));
1395
        assert_eq!(Uint3072::from_u64(5).lehmer_invert(Uint3072::from_u64(1)), None);
1396
        assert_eq!(Uint3072::from_u64(3).lehmer_invert(Uint3072::from_u64(8)), Some(Uint3072::from_u64(3)));
1397
    }
1398
}
/root/kaspa/kaspa-fuzz/rusty-kaspa/math/src/uint.rs
Line
Count
Source
1
#[doc(hidden)]
2
pub use {faster_hex, js_sys, kaspa_utils, serde, wasm_bindgen};
3
4
// TODO: Add u32 support for optimization on 32 bit machines.
5
6
#[macro_export]
7
macro_rules! construct_uint {
8
    ($name:ident, $n_words:literal $(, $derive_trait:ty)*) => {
9
        /// Little-endian large integer type
10
        #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug$(, $derive_trait )*)]
11
        pub struct $name(pub [u64; $n_words]);
12
        #[allow(unused)]
13
        impl $name {
14
            pub const ZERO: Self = $name([0; $n_words]);
15
            pub const MIN: Self = Self::ZERO;
16
            pub const MAX: Self = $name([u64::MAX; $n_words]);
17
            pub const BITS: u32 = $n_words * u64::BITS;
18
            pub const BYTES: usize = $n_words * size_of::<u64>();
19
            pub const LIMBS: usize = $n_words;
20
21
            #[inline]
22
0
            pub fn from_u64(n: u64) -> Self {
23
0
                let mut ret = Self::ZERO;
24
0
                ret.0[0] = n;
25
0
                ret
26
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1288from_u64
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3208from_u64
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30728from_u64
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1928from_u64
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2568from_u64
27
            #[inline]
28
0
            pub fn from_u128(n: u128) -> Self {
29
0
                let mut ret = Self::ZERO;
30
0
                ret.0[0] = n as u64;
31
0
                ret.0[1] = (n >> 64) as u64;
32
0
                ret
33
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1289from_u128
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3209from_u128
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30729from_u128
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1929from_u128
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2569from_u128
34
35
            #[inline]
36
7.26k
            pub fn as_u128(self) -> u128 {
37
7.26k
                self.0[0] as u128 | ((self.0[1] as u128) << 64)
38
7.26k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1287as_u128
Line
Count
Source
36
7.26k
            pub fn as_u128(self) -> u128 {
37
7.26k
                self.0[0] as u128 | ((self.0[1] as u128) << 64)
38
7.26k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3207as_u128
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30727as_u128
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1927as_u128
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2567as_u128
39
40
            #[inline]
41
5.02k
            pub fn as_u64(self) -> u64 {
42
5.02k
                self.0[0] as u64
43
5.02k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1286as_u64
Line
Count
Source
41
5.02k
            pub fn as_u64(self) -> u64 {
42
5.02k
                self.0[0] as u64
43
5.02k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3206as_u64
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30726as_u64
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1926as_u64
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2566as_u64
44
45
            #[inline(always)]
46
4.97k
            pub fn is_zero(self) -> bool {
47
5.86k
                self.0.iter().all(|&a| a == 0)
_RNCNvMCs1uXV1nWfJt5_4u128NtB4_7Uint1287is_zero0B4_
Line
Count
Source
47
5.86k
                self.0.iter().all(|&a| a == 0)
Unexecuted instantiation: _RNCNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint3207is_zero0B8_
Unexecuted instantiation: _RNCNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint30727is_zero0B8_
Unexecuted instantiation: _RNCNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint1927is_zero0B7_
Unexecuted instantiation: _RNCNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint2567is_zero0B7_
48
4.97k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1287is_zero
Line
Count
Source
46
4.97k
            pub fn is_zero(self) -> bool {
47
4.97k
                self.0.iter().all(|&a| a == 0)
48
4.97k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3207is_zero
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30727is_zero
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1927is_zero
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2567is_zero
49
50
            /// Return the least number of bits needed to represent the number
51
            #[inline(always)]
52
36.8k
            pub fn bits(&self) -> u32 {
53
41.5k
                for (i, &word) in self.0.iter().enumerate().rev() {
54
41.5k
                    if word != 0 {
55
35.1k
                        return u64::BITS * (i as u32 + 1) - word.leading_zeros();
56
6.46k
                    }
57
                }
58
1.72k
                0
59
36.8k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1284bits
Line
Count
Source
52
36.8k
            pub fn bits(&self) -> u32 {
53
41.5k
                for (i, &word) in self.0.iter().enumerate().rev() {
54
41.5k
                    if word != 0 {
55
35.1k
                        return u64::BITS * (i as u32 + 1) - word.leading_zeros();
56
6.46k
                    }
57
                }
58
1.72k
                0
59
36.8k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3204bits
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30724bits
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1924bits
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2564bits
60
61
            #[inline(always)]
62
4.97k
            pub fn leading_zeros(&self) -> u32 {
63
4.97k
                return Self::BITS - self.bits();
64
4.97k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12813leading_zeros
Line
Count
Source
62
4.97k
            pub fn leading_zeros(&self) -> u32 {
63
4.97k
                return Self::BITS - self.bits();
64
4.97k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32013leading_zeros
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307213leading_zeros
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19213leading_zeros
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25613leading_zeros
65
66
            #[inline]
67
19.6k
            pub fn overflowing_shl(self, mut s: u32) -> (Self, bool) {
68
19.6k
                let overflows = s >= Self::BITS;
69
19.6k
                s %= Self::BITS;
70
19.6k
                let mut ret = [0u64; $n_words];
71
19.6k
                let left_words = (s / 64) as usize;
72
19.6k
                let left_shifts = s % 64;
73
74
35.8k
                for i in left_words..$n_words {
75
35.8k
                    ret[i] = self.0[i - left_words] << left_shifts;
76
35.8k
                }
77
19.6k
                if left_shifts > 0 {
78
9.46k
                    let left_over = 64 - left_shifts;
79
9.46k
                    for i in left_words + 1..$n_words {
80
6.24k
                        ret[i] |= self.0[i - 1 - left_words] >> left_over;
81
6.24k
                    }
82
10.2k
                }
83
19.6k
                (Self(ret), overflows)
84
19.6k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12815overflowing_shl
Line
Count
Source
67
19.6k
            pub fn overflowing_shl(self, mut s: u32) -> (Self, bool) {
68
19.6k
                let overflows = s >= Self::BITS;
69
19.6k
                s %= Self::BITS;
70
19.6k
                let mut ret = [0u64; $n_words];
71
19.6k
                let left_words = (s / 64) as usize;
72
19.6k
                let left_shifts = s % 64;
73
74
35.8k
                for i in left_words..$n_words {
75
35.8k
                    ret[i] = self.0[i - left_words] << left_shifts;
76
35.8k
                }
77
19.6k
                if left_shifts > 0 {
78
9.46k
                    let left_over = 64 - left_shifts;
79
9.46k
                    for i in left_words + 1..$n_words {
80
6.24k
                        ret[i] |= self.0[i - 1 - left_words] >> left_over;
81
6.24k
                    }
82
10.2k
                }
83
19.6k
                (Self(ret), overflows)
84
19.6k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32015overflowing_shl
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307215overflowing_shl
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19215overflowing_shl
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25615overflowing_shl
85
86
            #[inline]
87
4.97k
            pub fn wrapping_shl(self, s: u32) -> Self {
88
4.97k
                self.overflowing_shl(s).0
89
4.97k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12812wrapping_shl
Line
Count
Source
87
4.97k
            pub fn wrapping_shl(self, s: u32) -> Self {
88
4.97k
                self.overflowing_shl(s).0
89
4.97k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32012wrapping_shl
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307212wrapping_shl
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19212wrapping_shl
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25612wrapping_shl
90
91
            #[inline]
92
123k
            pub fn overflowing_shr(self, mut s: u32) -> (Self, bool) {
93
123k
                let overflows = s >= Self::BITS;
94
123k
                s %= Self::BITS;
95
123k
                let mut ret = [0u64; Self::LIMBS];
96
123k
                let left_words = (s / 64) as usize;
97
123k
                let left_shifts = s % 64;
98
99
244k
                for i in left_words..Self::LIMBS {
100
244k
                    ret[i - left_words] = self.0[i] >> left_shifts;
101
244k
                }
102
123k
                if left_shifts > 0 {
103
121k
                    let left_over = 64 - left_shifts;
104
121k
                    for i in left_words + 1..Self::LIMBS {
105
119k
                        ret[i - left_words - 1] |= self.0[i] << left_over;
106
119k
                    }
107
1.76k
                }
108
123k
                (Self(ret), overflows)
109
123k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12815overflowing_shr
Line
Count
Source
92
123k
            pub fn overflowing_shr(self, mut s: u32) -> (Self, bool) {
93
123k
                let overflows = s >= Self::BITS;
94
123k
                s %= Self::BITS;
95
123k
                let mut ret = [0u64; Self::LIMBS];
96
123k
                let left_words = (s / 64) as usize;
97
123k
                let left_shifts = s % 64;
98
99
244k
                for i in left_words..Self::LIMBS {
100
244k
                    ret[i - left_words] = self.0[i] >> left_shifts;
101
244k
                }
102
123k
                if left_shifts > 0 {
103
121k
                    let left_over = 64 - left_shifts;
104
121k
                    for i in left_words + 1..Self::LIMBS {
105
119k
                        ret[i - left_words - 1] |= self.0[i] << left_over;
106
119k
                    }
107
1.76k
                }
108
123k
                (Self(ret), overflows)
109
123k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32015overflowing_shr
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307215overflowing_shr
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19215overflowing_shr
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25615overflowing_shr
110
111
            #[inline]
112
5.42k
            pub fn overflowing_add(mut self, other: Self) -> (Self, bool) {
113
                // Replace with std once stabilized:https://github.com/rust-lang/rust/issues/85532
114
                #[inline(always)]
115
10.8k
                pub const fn carrying_add_u64(lhs: u64, rhs: u64, carry: bool) -> (u64, bool) {
116
10.8k
                    let (a, b) = lhs.overflowing_add(rhs);
117
10.8k
                    let (c, d) = a.overflowing_add(carry as u64);
118
10.8k
                    (c, b != d)
119
10.8k
                }
_RNvNvMCs1uXV1nWfJt5_4u128NtB4_7Uint12815overflowing_add16carrying_add_u64
Line
Count
Source
115
10.8k
                pub const fn carrying_add_u64(lhs: u64, rhs: u64, carry: bool) -> (u64, bool) {
116
10.8k
                    let (a, b) = lhs.overflowing_add(rhs);
117
10.8k
                    let (c, d) = a.overflowing_add(carry as u64);
118
10.8k
                    (c, b != d)
119
10.8k
                }
Unexecuted instantiation: _RNvNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint32015overflowing_add16carrying_add_u64
Unexecuted instantiation: _RNvNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint307215overflowing_add16carrying_add_u64
Unexecuted instantiation: _RNvNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint19215overflowing_add16carrying_add_u64
Unexecuted instantiation: _RNvNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint25615overflowing_add16carrying_add_u64
120
5.42k
                let mut carry = false;
121
                let mut carry_out;
122
10.8k
                for i in 0..Self::LIMBS {
123
10.8k
                    (self.0[i], carry_out) = carrying_add_u64(self.0[i], other.0[i], carry);
124
10.8k
                    carry = carry_out;
125
10.8k
                }
126
5.42k
                (self, carry)
127
5.42k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12815overflowing_add
Line
Count
Source
112
5.42k
            pub fn overflowing_add(mut self, other: Self) -> (Self, bool) {
113
                // Replace with std once stabilized:https://github.com/rust-lang/rust/issues/85532
114
                #[inline(always)]
115
                pub const fn carrying_add_u64(lhs: u64, rhs: u64, carry: bool) -> (u64, bool) {
116
                    let (a, b) = lhs.overflowing_add(rhs);
117
                    let (c, d) = a.overflowing_add(carry as u64);
118
                    (c, b != d)
119
                }
120
5.42k
                let mut carry = false;
121
                let mut carry_out;
122
10.8k
                for i in 0..Self::LIMBS {
123
10.8k
                    (self.0[i], carry_out) = carrying_add_u64(self.0[i], other.0[i], carry);
124
10.8k
                    carry = carry_out;
125
10.8k
                }
126
5.42k
                (self, carry)
127
5.42k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32015overflowing_add
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307215overflowing_add
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19215overflowing_add
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25615overflowing_add
128
129
            #[inline]
130
5.11k
            pub fn overflowing_add_u64(mut self, other: u64) -> (Self, bool) {
131
                let mut carry: bool;
132
5.11k
                (self.0[0], carry) = self.0[0].overflowing_add(other);
133
5.11k
                for i in 1..Self::LIMBS {
134
5.11k
                    if !carry {
135
2.86k
                        break;
136
2.24k
                    }
137
2.24k
                    (self.0[i], carry) = self.0[i].overflowing_add(1);
138
                }
139
5.11k
                (self, carry)
140
5.11k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12819overflowing_add_u64
Line
Count
Source
130
5.11k
            pub fn overflowing_add_u64(mut self, other: u64) -> (Self, bool) {
131
                let mut carry: bool;
132
5.11k
                (self.0[0], carry) = self.0[0].overflowing_add(other);
133
5.11k
                for i in 1..Self::LIMBS {
134
5.11k
                    if !carry {
135
2.86k
                        break;
136
2.24k
                    }
137
2.24k
                    (self.0[i], carry) = self.0[i].overflowing_add(1);
138
                }
139
5.11k
                (self, carry)
140
5.11k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32019overflowing_add_u64
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307219overflowing_add_u64
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19219overflowing_add_u64
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25619overflowing_add_u64
141
142
            #[inline]
143
53.0k
            pub fn overflowing_sub(mut self, other: Self) -> (Self, bool) {
144
                // Replace with std once stabilized:https://github.com/rust-lang/rust/issues/85532
145
                #[inline(always)]
146
106k
                pub const fn borrowing_sub_u64(lhs: u64, rhs: u64, borrow: bool) -> (u64, bool) {
147
106k
                    let (a, b) = lhs.overflowing_sub(rhs);
148
106k
                    let (c, d) = a.overflowing_sub(borrow as u64);
149
106k
                    (c, b != d)
150
106k
                }
_RNvNvMCs1uXV1nWfJt5_4u128NtB4_7Uint12815overflowing_sub17borrowing_sub_u64
Line
Count
Source
146
106k
                pub const fn borrowing_sub_u64(lhs: u64, rhs: u64, borrow: bool) -> (u64, bool) {
147
106k
                    let (a, b) = lhs.overflowing_sub(rhs);
148
106k
                    let (c, d) = a.overflowing_sub(borrow as u64);
149
106k
                    (c, b != d)
150
106k
                }
Unexecuted instantiation: _RNvNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint32015overflowing_sub17borrowing_sub_u64
Unexecuted instantiation: _RNvNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint307215overflowing_sub17borrowing_sub_u64
Unexecuted instantiation: _RNvNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint19215overflowing_sub17borrowing_sub_u64
Unexecuted instantiation: _RNvNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint25615overflowing_sub17borrowing_sub_u64
151
152
53.0k
                let mut carry = false;
153
                let mut carry_out;
154
106k
                for i in 0..Self::LIMBS {
155
106k
                    (self.0[i], carry_out) = borrowing_sub_u64(self.0[i], other.0[i], carry);
156
106k
                    carry = carry_out;
157
106k
                }
158
53.0k
                (self, carry)
159
53.0k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12815overflowing_sub
Line
Count
Source
143
53.0k
            pub fn overflowing_sub(mut self, other: Self) -> (Self, bool) {
144
                // Replace with std once stabilized:https://github.com/rust-lang/rust/issues/85532
145
                #[inline(always)]
146
                pub const fn borrowing_sub_u64(lhs: u64, rhs: u64, borrow: bool) -> (u64, bool) {
147
                    let (a, b) = lhs.overflowing_sub(rhs);
148
                    let (c, d) = a.overflowing_sub(borrow as u64);
149
                    (c, b != d)
150
                }
151
152
53.0k
                let mut carry = false;
153
                let mut carry_out;
154
106k
                for i in 0..Self::LIMBS {
155
106k
                    (self.0[i], carry_out) = borrowing_sub_u64(self.0[i], other.0[i], carry);
156
106k
                    carry = carry_out;
157
106k
                }
158
53.0k
                (self, carry)
159
53.0k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32015overflowing_sub
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307215overflowing_sub
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19215overflowing_sub
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25615overflowing_sub
160
161
            #[inline]
162
0
            pub fn saturating_sub(self, other: Self) -> Self {
163
0
                let (sum, carry) = self.overflowing_sub(other);
164
0
                if carry { Self::ZERO } else { sum }
165
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12814saturating_sub
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32014saturating_sub
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307214saturating_sub
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19214saturating_sub
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25614saturating_sub
166
167
            #[inline]
168
0
            pub fn saturating_add(self, other: Self) -> Self {
169
0
                let (sum, carry) = self.overflowing_add(other);
170
0
                if carry { Self::MAX } else { sum }
171
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12814saturating_add
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32014saturating_add
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307214saturating_add
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19214saturating_add
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25614saturating_add
172
173
            /// Multiplication by u64
174
            #[inline]
175
5.09k
            pub fn overflowing_mul_u64(self, other: u64) -> (Self, bool) {
176
5.09k
                let (this, carry) = self.carrying_mul_u64(other);
177
5.09k
                (this, carry != 0)
178
5.09k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12819overflowing_mul_u64
Line
Count
Source
175
5.09k
            pub fn overflowing_mul_u64(self, other: u64) -> (Self, bool) {
176
5.09k
                let (this, carry) = self.carrying_mul_u64(other);
177
5.09k
                (this, carry != 0)
178
5.09k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32019overflowing_mul_u64
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307219overflowing_mul_u64
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19219overflowing_mul_u64
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25619overflowing_mul_u64
179
180
            #[inline]
181
5.09k
            pub fn carrying_mul_u64(mut self, other: u64) -> (Self, u64) {
182
5.09k
                let mut carry: u128 = 0;
183
10.1k
                for i in 0..Self::LIMBS {
184
10.1k
                    // TODO: Use `carrying_mul` when stabilized: https://github.com/rust-lang/rust/issues/85532
185
10.1k
                    let n = carry + (other as u128) * (self.0[i] as u128);
186
10.1k
                    self.0[i] = n as u64;
187
10.1k
                    carry = (n >> 64) & u64::MAX as u128;
188
10.1k
                }
189
5.09k
                (self, carry as u64)
190
5.09k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12816carrying_mul_u64
Line
Count
Source
181
5.09k
            pub fn carrying_mul_u64(mut self, other: u64) -> (Self, u64) {
182
5.09k
                let mut carry: u128 = 0;
183
10.1k
                for i in 0..Self::LIMBS {
184
10.1k
                    // TODO: Use `carrying_mul` when stabilized: https://github.com/rust-lang/rust/issues/85532
185
10.1k
                    let n = carry + (other as u128) * (self.0[i] as u128);
186
10.1k
                    self.0[i] = n as u64;
187
10.1k
                    carry = (n >> 64) & u64::MAX as u128;
188
10.1k
                }
189
5.09k
                (self, carry as u64)
190
5.09k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32016carrying_mul_u64
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307216carrying_mul_u64
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19216carrying_mul_u64
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25616carrying_mul_u64
191
192
            #[inline]
193
5.38k
            pub fn overflowing_mul(self, other: Self) -> (Self, bool) {
194
                // We should probably replace this with a Montgomery multiplication algorithm
195
5.38k
                let mut result = Self::ZERO;
196
5.38k
                let mut carry_out = false;
197
10.7k
                for j in 0..Self::LIMBS {
198
10.7k
                    let mut carry = 0;
199
10.7k
                    let mut i = 0;
200
26.9k
                    while i + j < Self::LIMBS {
201
16.1k
                        let n = (self.0[i] as u128) * (other.0[j] as u128) + (result.0[i + j] as u128) + (carry as u128);
202
16.1k
                        result.0[i + j] = n as u64;
203
16.1k
                        carry = (n >> 64) as u64;
204
16.1k
                        i += 1;
205
16.1k
                    }
206
10.7k
                    carry_out |= carry != 0;
207
                }
208
5.38k
                (result, carry_out)
209
5.38k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12815overflowing_mul
Line
Count
Source
193
5.38k
            pub fn overflowing_mul(self, other: Self) -> (Self, bool) {
194
                // We should probably replace this with a Montgomery multiplication algorithm
195
5.38k
                let mut result = Self::ZERO;
196
5.38k
                let mut carry_out = false;
197
10.7k
                for j in 0..Self::LIMBS {
198
10.7k
                    let mut carry = 0;
199
10.7k
                    let mut i = 0;
200
26.9k
                    while i + j < Self::LIMBS {
201
16.1k
                        let n = (self.0[i] as u128) * (other.0[j] as u128) + (result.0[i + j] as u128) + (carry as u128);
202
16.1k
                        result.0[i + j] = n as u64;
203
16.1k
                        carry = (n >> 64) as u64;
204
16.1k
                        i += 1;
205
16.1k
                    }
206
10.7k
                    carry_out |= carry != 0;
207
                }
208
5.38k
                (result, carry_out)
209
5.38k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32015overflowing_mul
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307215overflowing_mul
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19215overflowing_mul
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25615overflowing_mul
210
            /// Creates big integer value from a byte slice using
211
            /// little-endian encoding
212
            #[inline(always)]
213
153k
            pub fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self {
214
153k
                let mut out = [0u64; Self::LIMBS];
215
                // This should optimize to basically a transmute.
216
153k
                out.iter_mut()
217
153k
                    .zip(bytes.chunks_exact(8))
218
307k
                    .for_each(|(word, bytes)| *word = u64::from_le_bytes(bytes.try_into().unwrap()));
_RNCNvMCs1uXV1nWfJt5_4u128NtB4_7Uint12813from_le_bytes0B4_
Line
Count
Source
218
307k
                    .for_each(|(word, bytes)| *word = u64::from_le_bytes(bytes.try_into().unwrap()));
Unexecuted instantiation: _RNCNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint32013from_le_bytes0B8_
Unexecuted instantiation: _RNCNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint307213from_le_bytes0B8_
Unexecuted instantiation: _RNCNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint19213from_le_bytes0B7_
Unexecuted instantiation: _RNCNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint25613from_le_bytes0B7_
219
153k
                Self(out)
220
153k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12813from_le_bytes
Line
Count
Source
213
153k
            pub fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self {
214
153k
                let mut out = [0u64; Self::LIMBS];
215
                // This should optimize to basically a transmute.
216
153k
                out.iter_mut()
217
153k
                    .zip(bytes.chunks_exact(8))
218
153k
                    .for_each(|(word, bytes)| *word = u64::from_le_bytes(bytes.try_into().unwrap()));
219
153k
                Self(out)
220
153k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32013from_le_bytes
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307213from_le_bytes
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19213from_le_bytes
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25613from_le_bytes
221
222
            /// Creates big integer value from a byte slice using
223
            /// big-endian encoding
224
            #[inline(always)]
225
0
            pub fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self {
226
0
                let mut out = [0u64; Self::LIMBS];
227
0
                out.iter_mut()
228
0
                    .rev()
229
0
                    .zip(bytes.chunks_exact(8))
230
0
                    .for_each(|(word, bytes)| *word = u64::from_be_bytes(bytes.try_into().unwrap()));
Unexecuted instantiation: _RNCNvMCs1uXV1nWfJt5_4u128NtB4_7Uint12813from_be_bytes0B4_
Unexecuted instantiation: _RNCNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint32013from_be_bytes0B8_
Unexecuted instantiation: _RNCNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint307213from_be_bytes0B8_
Unexecuted instantiation: _RNCNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint19213from_be_bytes0B7_
Unexecuted instantiation: _RNCNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint25613from_be_bytes0B7_
231
0
                Self(out)
232
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12813from_be_bytes
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32013from_be_bytes
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307213from_be_bytes
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19213from_be_bytes
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25613from_be_bytes
233
234
            /// Convert's the Uint into little endian byte array
235
            #[inline(always)]
236
4.92k
            pub fn to_le_bytes(self) -> [u8; Self::BYTES] {
237
4.92k
                let mut out = [0u8; Self::BYTES];
238
                // This should optimize to basically a transmute.
239
9.85k
                out.chunks_exact_mut(8).zip(self.0).for_each(|(bytes, word)| bytes.copy_from_slice(&word.to_le_bytes()));
_RNCNvMCs1uXV1nWfJt5_4u128NtB4_7Uint12811to_le_bytes0B4_
Line
Count
Source
239
9.85k
                out.chunks_exact_mut(8).zip(self.0).for_each(|(bytes, word)| bytes.copy_from_slice(&word.to_le_bytes()));
Unexecuted instantiation: _RNCNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint32011to_le_bytes0B8_
Unexecuted instantiation: _RNCNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint307211to_le_bytes0B8_
Unexecuted instantiation: _RNCNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint19211to_le_bytes0B7_
Unexecuted instantiation: _RNCNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint25611to_le_bytes0B7_
240
4.92k
                out
241
4.92k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12811to_le_bytes
Line
Count
Source
236
4.92k
            pub fn to_le_bytes(self) -> [u8; Self::BYTES] {
237
4.92k
                let mut out = [0u8; Self::BYTES];
238
                // This should optimize to basically a transmute.
239
4.92k
                out.chunks_exact_mut(8).zip(self.0).for_each(|(bytes, word)| bytes.copy_from_slice(&word.to_le_bytes()));
240
4.92k
                out
241
4.92k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32011to_le_bytes
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307211to_le_bytes
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19211to_le_bytes
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25611to_le_bytes
242
243
            /// Convert's the Uint into big endian byte array
244
            #[inline(always)]
245
4.88k
            pub fn to_be_bytes(self) -> [u8; Self::BYTES] {
246
4.88k
                let mut out = [0u8; Self::BYTES];
247
                // This should optimize to basically a transmute.
248
4.88k
                out.chunks_exact_mut(8)
249
4.88k
                    .zip(self.0.into_iter().rev())
250
9.76k
                    .for_each(|(bytes, word)| bytes.copy_from_slice(&word.to_be_bytes()));
_RNCNvMCs1uXV1nWfJt5_4u128NtB4_7Uint12811to_be_bytes0B4_
Line
Count
Source
250
9.76k
                    .for_each(|(bytes, word)| bytes.copy_from_slice(&word.to_be_bytes()));
Unexecuted instantiation: _RNCNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint32011to_be_bytes0B8_
Unexecuted instantiation: _RNCNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint307211to_be_bytes0B8_
Unexecuted instantiation: _RNCNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint19211to_be_bytes0B7_
Unexecuted instantiation: _RNCNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint25611to_be_bytes0B7_
251
4.88k
                out
252
4.88k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12811to_be_bytes
Line
Count
Source
245
4.88k
            pub fn to_be_bytes(self) -> [u8; Self::BYTES] {
246
4.88k
                let mut out = [0u8; Self::BYTES];
247
                // This should optimize to basically a transmute.
248
4.88k
                out.chunks_exact_mut(8)
249
4.88k
                    .zip(self.0.into_iter().rev())
250
4.88k
                    .for_each(|(bytes, word)| bytes.copy_from_slice(&word.to_be_bytes()));
251
4.88k
                out
252
4.88k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32011to_be_bytes
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307211to_be_bytes
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19211to_be_bytes
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25611to_be_bytes
253
254
            #[inline(always)]
255
0
            pub fn to_be_bytes_var(self) -> Vec<u8> {
256
0
                let bytes = self.to_be_bytes();
257
0
                let start = bytes.iter().copied().position(|b| b != 0).unwrap_or(bytes.len());
Unexecuted instantiation: _RNCNvMCs1uXV1nWfJt5_4u128NtB4_7Uint12815to_be_bytes_var0B4_
Unexecuted instantiation: _RNCNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint32015to_be_bytes_var0B8_
Unexecuted instantiation: _RNCNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint307215to_be_bytes_var0B8_
Unexecuted instantiation: _RNCNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint19215to_be_bytes_var0B7_
Unexecuted instantiation: _RNCNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint25615to_be_bytes_var0B7_
258
0
                Vec::from(&bytes[start..])
259
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12815to_be_bytes_var
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32015to_be_bytes_var
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307215to_be_bytes_var
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19215to_be_bytes_var
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25615to_be_bytes_var
260
261
            #[inline]
262
0
            pub fn div_rem_u64(mut self, other: u64) -> (Self, u64) {
263
0
                let mut rem = 0u64;
264
0
                self.0.iter_mut().rev().for_each(|d| {
265
0
                    let n = (rem as u128) << 64 | (*d as u128);
266
0
                    *d = (n / other as u128) as u64;
267
0
                    rem = (n % other as u128) as u64;
268
0
                });
Unexecuted instantiation: _RNCNvMCs1uXV1nWfJt5_4u128NtB4_7Uint12811div_rem_u640B4_
Unexecuted instantiation: _RNCNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint32011div_rem_u640B8_
Unexecuted instantiation: _RNCNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint307211div_rem_u640B8_
Unexecuted instantiation: _RNCNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint19211div_rem_u640B7_
Unexecuted instantiation: _RNCNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint25611div_rem_u640B7_
269
0
                (self, rem)
270
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12811div_rem_u64
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32011div_rem_u64
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307211div_rem_u64
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19211div_rem_u64
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25611div_rem_u64
271
272
            #[inline]
273
4.97k
            pub fn as_f64(&self) -> f64 {
274
                // Reference: https://blog.m-ou.se/floats/
275
                // Step 1: Get leading zeroes
276
4.97k
                let leading_zeroes =  self.leading_zeros();
277
                // Step 2: Align the bits to the left, so the highest bit will be 1.
278
4.97k
                let left_aligned = self.wrapping_shl(leading_zeroes);
279
                // Step 3: Take the highest 53 bits as the mantissa (equivalent to shifting by (Self::BITS - 53))
280
4.97k
                let mut mantissa = left_aligned.0[Self::LIMBS - 1] >> 11;
281
                // Step 4: Get the dropped bits, which are the bits that are not part of the mantissa
282
                // The dropped bits are left_aligned << 53 (everything except the highest 53 bits).
283
                // Unlike the blog here we split the highest bit and the rest of the bits into 2 variables.
284
                // We first take the highest 11 bits that were dropped.
285
4.97k
                let highest_dropped_bits = left_aligned.0[Self::LIMBS - 1] << 53;
286
4.97k
                let highest_dropped_bit = highest_dropped_bits >> 63 != 0;
287
                // Now we OR together the rest of the bits.
288
4.97k
                let mut rest_dropped_bits = highest_dropped_bits << 1; // Remove the highest.
289
4.97k
                for &word in &left_aligned.0[..Self::LIMBS - 1] {
290
4.97k
                    rest_dropped_bits |= word;
291
4.97k
                }
292
                // This is true if the dropped bits are higher than half the int.
293
4.97k
                let higher_than_half = highest_dropped_bit & (rest_dropped_bits != 0);
294
4.97k
                let exactly_half_but_mantissa_odd = highest_dropped_bit & (rest_dropped_bits == 0) & (mantissa & 1 == 1);
295
                // Step 5: if the dropped bits are higher than half the int, we add 1 to the mantissa.
296
                // If the dropped bits are exactly half the int, we add 1 to the mantissa only if the mantissa is odd. (IEEE-754)
297
4.97k
                mantissa += (higher_than_half | exactly_half_but_mantissa_odd) as u64;
298
                // Step 6: Calculate the exponent
299
                // If self is 0, exponent should be 0 (special meaning) and mantissa will end up 0 too
300
                // Otherwise, (Self::BITS - 1 - leading_zeros) + 1022 so it simplifies to Self::BITS + 1021 - leading_zeroes
301
                // 1023 and 1022 are the cutoffs for the exponent having the msb next to the decimal point
302
4.97k
                let exponent = if self.is_zero() { 0 } else { u64::from(Self::BITS) + 1021 - u64::from(leading_zeroes) };
303
                // Step 7: sign bit is always 0, exponent is shifted into place
304
                // Use addition instead of bitwise OR to saturate the exponent if mantissa overflows
305
4.97k
                f64::from_bits((exponent << 52) + mantissa)
306
4.97k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1286as_f64
Line
Count
Source
273
4.97k
            pub fn as_f64(&self) -> f64 {
274
                // Reference: https://blog.m-ou.se/floats/
275
                // Step 1: Get leading zeroes
276
4.97k
                let leading_zeroes =  self.leading_zeros();
277
                // Step 2: Align the bits to the left, so the highest bit will be 1.
278
4.97k
                let left_aligned = self.wrapping_shl(leading_zeroes);
279
                // Step 3: Take the highest 53 bits as the mantissa (equivalent to shifting by (Self::BITS - 53))
280
4.97k
                let mut mantissa = left_aligned.0[Self::LIMBS - 1] >> 11;
281
                // Step 4: Get the dropped bits, which are the bits that are not part of the mantissa
282
                // The dropped bits are left_aligned << 53 (everything except the highest 53 bits).
283
                // Unlike the blog here we split the highest bit and the rest of the bits into 2 variables.
284
                // We first take the highest 11 bits that were dropped.
285
4.97k
                let highest_dropped_bits = left_aligned.0[Self::LIMBS - 1] << 53;
286
4.97k
                let highest_dropped_bit = highest_dropped_bits >> 63 != 0;
287
                // Now we OR together the rest of the bits.
288
4.97k
                let mut rest_dropped_bits = highest_dropped_bits << 1; // Remove the highest.
289
4.97k
                for &word in &left_aligned.0[..Self::LIMBS - 1] {
290
4.97k
                    rest_dropped_bits |= word;
291
4.97k
                }
292
                // This is true if the dropped bits are higher than half the int.
293
4.97k
                let higher_than_half = highest_dropped_bit & (rest_dropped_bits != 0);
294
4.97k
                let exactly_half_but_mantissa_odd = highest_dropped_bit & (rest_dropped_bits == 0) & (mantissa & 1 == 1);
295
                // Step 5: if the dropped bits are higher than half the int, we add 1 to the mantissa.
296
                // If the dropped bits are exactly half the int, we add 1 to the mantissa only if the mantissa is odd. (IEEE-754)
297
4.97k
                mantissa += (higher_than_half | exactly_half_but_mantissa_odd) as u64;
298
                // Step 6: Calculate the exponent
299
                // If self is 0, exponent should be 0 (special meaning) and mantissa will end up 0 too
300
                // Otherwise, (Self::BITS - 1 - leading_zeros) + 1022 so it simplifies to Self::BITS + 1021 - leading_zeroes
301
                // 1023 and 1022 are the cutoffs for the exponent having the msb next to the decimal point
302
4.97k
                let exponent = if self.is_zero() { 0 } else { u64::from(Self::BITS) + 1021 - u64::from(leading_zeroes) };
303
                // Step 7: sign bit is always 0, exponent is shifted into place
304
                // Use addition instead of bitwise OR to saturate the exponent if mantissa overflows
305
4.97k
                f64::from_bits((exponent << 52) + mantissa)
306
4.97k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3206as_f64
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30726as_f64
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1926as_f64
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2566as_f64
307
308
            // divmod like operation, returns (quotient, remainder)
309
            #[inline]
310
13.4k
            pub fn div_rem(self, other: Self) -> (Self, Self) {
311
13.4k
                let mut sub_copy = self;
312
13.4k
                let mut shift_copy = other;
313
13.4k
                let mut ret = [0u64; Self::LIMBS];
314
315
13.4k
                let my_bits = self.bits();
316
13.4k
                let your_bits = other.bits();
317
318
                // Check for division by 0
319
13.4k
                assert_ne!(your_bits, 0, "attempted to divide {} by zero", self);
320
321
                // Early return in case we are dividing by a larger number than us
322
13.4k
                if my_bits < your_bits {
323
3.77k
                    return (Self(ret), sub_copy);
324
9.63k
                }
325
326
                // Bitwise long division
327
9.63k
                let mut shift = my_bits - your_bits;
328
9.63k
                shift_copy = shift_copy << shift;
329
                loop {
330
118k
                    if sub_copy >= shift_copy {
331
53.0k
                        let (shift_index, shift_val) = ((shift / 64) as usize, shift % 64);
332
53.0k
                        ret[shift_index] |= 1 << shift_val;
333
53.0k
                        sub_copy = sub_copy - shift_copy;
334
65.5k
                    }
335
118k
                    shift_copy = shift_copy >> 1;
336
118k
                    if shift == 0 {
337
9.63k
                        break;
338
108k
                    }
339
108k
                    shift -= 1;
340
                }
341
342
9.63k
                (Self(ret), sub_copy)
343
13.4k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1287div_rem
Line
Count
Source
310
13.4k
            pub fn div_rem(self, other: Self) -> (Self, Self) {
311
13.4k
                let mut sub_copy = self;
312
13.4k
                let mut shift_copy = other;
313
13.4k
                let mut ret = [0u64; Self::LIMBS];
314
315
13.4k
                let my_bits = self.bits();
316
13.4k
                let your_bits = other.bits();
317
318
                // Check for division by 0
319
13.4k
                assert_ne!(your_bits, 0, "attempted to divide {} by zero", self);
320
321
                // Early return in case we are dividing by a larger number than us
322
13.4k
                if my_bits < your_bits {
323
3.77k
                    return (Self(ret), sub_copy);
324
9.63k
                }
325
326
                // Bitwise long division
327
9.63k
                let mut shift = my_bits - your_bits;
328
9.63k
                shift_copy = shift_copy << shift;
329
                loop {
330
118k
                    if sub_copy >= shift_copy {
331
53.0k
                        let (shift_index, shift_val) = ((shift / 64) as usize, shift % 64);
332
53.0k
                        ret[shift_index] |= 1 << shift_val;
333
53.0k
                        sub_copy = sub_copy - shift_copy;
334
65.5k
                    }
335
118k
                    shift_copy = shift_copy >> 1;
336
118k
                    if shift == 0 {
337
9.63k
                        break;
338
108k
                    }
339
108k
                    shift -= 1;
340
                }
341
342
9.63k
                (Self(ret), sub_copy)
343
13.4k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3207div_rem
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30727div_rem
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1927div_rem
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2567div_rem
344
345
            // The general malachite-backed `mod_inverse` was removed; modular inversion is
346
            // provided for every Uint by the in-repo `lehmer` module (`math/src/lehmer.rs`, MIT,
347
            // faster than malachite) through the `LehmerInvert` extension trait, backed by the
348
            // `LehmerOps` impl below.
349
350
            #[inline]
351
4.83k
            pub fn iter_be_bits(self) -> impl ExactSizeIterator<Item = bool> + core::iter::FusedIterator {
352
                struct BinaryIterator {
353
                    array: [u64; $n_words],
354
                    bit: usize,
355
                }
356
357
                impl Iterator for BinaryIterator {
358
                    type Item = bool;
359
360
                    #[inline]
361
623k
                    fn next(&mut self) -> Option<Self::Item> {
362
623k
                        if self.bit >= 64 * $n_words {
363
4.83k
                            return None;
364
619k
                        }
365
619k
                        let (word, subbit) = (self.bit / 64, self.bit % 64);
366
619k
                        let current_bit = self.array[$n_words - word - 1] & (1 << 64 - subbit - 1);
367
619k
                        self.bit += 1;
368
619k
                        Some(current_bit != 0)
369
623k
                    }
_RNvXNvMCs1uXV1nWfJt5_4u128NtB5_7Uint12812iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator4next
Line
Count
Source
361
623k
                    fn next(&mut self) -> Option<Self::Item> {
362
623k
                        if self.bit >= 64 * $n_words {
363
4.83k
                            return None;
364
619k
                        }
365
619k
                        let (word, subbit) = (self.bit / 64, self.bit % 64);
366
619k
                        let current_bit = self.array[$n_words - word - 1] & (1 << 64 - subbit - 1);
367
619k
                        self.bit += 1;
368
619k
                        Some(current_bit != 0)
369
623k
                    }
Unexecuted instantiation: _RNvXNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint32012iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator4next
Unexecuted instantiation: _RNvXNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint307212iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator4next
Unexecuted instantiation: _RNvXNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint19212iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator4next
Unexecuted instantiation: _RNvXNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint25612iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator4next
370
371
                    #[inline]
372
0
                    fn nth(&mut self, n: usize) -> Option<Self::Item> {
373
0
                        match self.bit.checked_add(n) {
374
0
                            Some(bit) => {
375
0
                                self.bit = bit;
376
0
                                self.next()
377
                            }
378
                            None => {
379
0
                                self.bit = usize::MAX;
380
0
                                None
381
                            }
382
                        }
383
0
                    }
Unexecuted instantiation: _RNvXNvMCs1uXV1nWfJt5_4u128NtB5_7Uint12812iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator3nth
Unexecuted instantiation: _RNvXNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint32012iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator3nth
Unexecuted instantiation: _RNvXNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint307212iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator3nth
Unexecuted instantiation: _RNvXNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint19212iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator3nth
Unexecuted instantiation: _RNvXNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint25612iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator3nth
384
                    #[inline]
385
0
                    fn size_hint(&self) -> (usize, Option<usize>) {
386
0
                        let remaining_bits = $n_words * (u64::BITS as usize) - self.bit;
387
0
                        (remaining_bits, Some(remaining_bits))
388
0
                    }
Unexecuted instantiation: _RNvXNvMCs1uXV1nWfJt5_4u128NtB5_7Uint12812iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator9size_hint
Unexecuted instantiation: _RNvXNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint32012iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator9size_hint
Unexecuted instantiation: _RNvXNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint307212iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator9size_hint
Unexecuted instantiation: _RNvXNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint19212iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator9size_hint
Unexecuted instantiation: _RNvXNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint25612iter_be_bitsNtB2_14BinaryIteratorNtNtNtNtCsloNou9alJSK_4core4iter6traits8iterator8Iterator9size_hint
389
                }
390
                impl ExactSizeIterator for BinaryIterator {}
391
                impl core::iter::FusedIterator for BinaryIterator {}
392
393
4.83k
                BinaryIterator { array: self.0, bit: 0 }
394
4.83k
            }
_RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12812iter_be_bits
Line
Count
Source
351
4.83k
            pub fn iter_be_bits(self) -> impl ExactSizeIterator<Item = bool> + core::iter::FusedIterator {
352
                struct BinaryIterator {
353
                    array: [u64; $n_words],
354
                    bit: usize,
355
                }
356
357
                impl Iterator for BinaryIterator {
358
                    type Item = bool;
359
360
                    #[inline]
361
                    fn next(&mut self) -> Option<Self::Item> {
362
                        if self.bit >= 64 * $n_words {
363
                            return None;
364
                        }
365
                        let (word, subbit) = (self.bit / 64, self.bit % 64);
366
                        let current_bit = self.array[$n_words - word - 1] & (1 << 64 - subbit - 1);
367
                        self.bit += 1;
368
                        Some(current_bit != 0)
369
                    }
370
371
                    #[inline]
372
                    fn nth(&mut self, n: usize) -> Option<Self::Item> {
373
                        match self.bit.checked_add(n) {
374
                            Some(bit) => {
375
                                self.bit = bit;
376
                                self.next()
377
                            }
378
                            None => {
379
                                self.bit = usize::MAX;
380
                                None
381
                            }
382
                        }
383
                    }
384
                    #[inline]
385
                    fn size_hint(&self) -> (usize, Option<usize>) {
386
                        let remaining_bits = $n_words * (u64::BITS as usize) - self.bit;
387
                        (remaining_bits, Some(remaining_bits))
388
                    }
389
                }
390
                impl ExactSizeIterator for BinaryIterator {}
391
                impl core::iter::FusedIterator for BinaryIterator {}
392
393
4.83k
                BinaryIterator { array: self.0, bit: 0 }
394
4.83k
            }
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32012iter_be_bits
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307212iter_be_bits
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19212iter_be_bits
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25612iter_be_bits
395
396
            /// Converts a Self::BYTES*2 hex string interpreted as big endian, into a Uint
397
            #[inline]
398
0
            pub fn from_hex(hex: &str) -> Result<Self, $crate::uint::faster_hex::Error> {
399
0
                if hex.len() > Self::BYTES * 2 {
400
0
                    return Err($crate::uint::faster_hex::Error::InvalidLength(hex.len()));
401
0
                }
402
0
                let mut out = [0u8; Self::BYTES];
403
0
                let mut input = [b'0'; Self::BYTES * 2];
404
0
                let start = input.len() - hex.len();
405
0
                input[start..].copy_from_slice(hex.as_bytes());
406
0
                $crate::uint::faster_hex::hex_decode(&input, &mut out)?;
407
0
                Ok(Self::from_be_bytes(out))
408
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1288from_hex
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3208from_hex
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30728from_hex
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1928from_hex
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2568from_hex
409
410
            #[inline]
411
0
            pub fn from_be_bytes_var(bytes: &[u8]) -> Result<Self, $crate::uint::TryFromSliceError> {
412
0
                if bytes.len() > Self::BYTES {
413
0
                    return Err($crate::uint::TryFromSliceError);
414
0
                }
415
0
                let mut out = [0u8; Self::BYTES];
416
0
                let start = Self::BYTES - bytes.len();
417
0
                out[start..].copy_from_slice(bytes);
418
0
                Ok(Self::from_be_bytes(out))
419
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint12817from_be_bytes_var
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint32017from_be_bytes_var
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint307217from_be_bytes_var
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint19217from_be_bytes_var
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint25617from_be_bytes_var
420
421
            #[inline]
422
0
            pub fn as_bigint(&self) -> Result<$crate::uint::js_sys::BigInt, $crate::Error> {
423
0
                self.try_into()
424
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1289as_bigint
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3209as_bigint
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30729as_bigint
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1929as_bigint
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2569as_bigint
425
426
            #[inline]
427
0
            pub fn to_bigint(self) -> Result<$crate::uint::js_sys::BigInt, $crate::Error> {
428
0
                self.try_into()
429
0
            }
Unexecuted instantiation: _RNvMCs1uXV1nWfJt5_4u128NtB2_7Uint1289to_bigint
Unexecuted instantiation: _RNvMs1J_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint3209to_bigint
Unexecuted instantiation: _RNvMs2x_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint30729to_bigint
Unexecuted instantiation: _RNvMs5_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint1929to_bigint
Unexecuted instantiation: _RNvMsV_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint2569to_bigint
430
431
        }
432
433
        impl $crate::lehmer::LehmerOps for $name {
434
            type Limbs = [u64; $n_words];
435
            type Cofactor = [u64; $n_words + $crate::lehmer::COFACTOR_HEADROOM];
436
            #[inline]
437
4.32k
            fn from_limbs(limbs: Self::Limbs) -> Self {
438
4.32k
                Self(limbs)
439
4.32k
            }
_RNvXs_Cs1uXV1nWfJt5_4u128NtB4_7Uint128NtNtCs8KLYHAG7u19_10kaspa_math6lehmer9LehmerOps10from_limbs
Line
Count
Source
437
4.32k
            fn from_limbs(limbs: Self::Limbs) -> Self {
438
4.32k
                Self(limbs)
439
4.32k
            }
Unexecuted instantiation: _RNvXs1K_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtB6_6lehmer9LehmerOps10from_limbs
Unexecuted instantiation: _RNvXs2y_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtB6_6lehmer9LehmerOps10from_limbs
Unexecuted instantiation: _RNvXs6_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtB5_6lehmer9LehmerOps10from_limbs
Unexecuted instantiation: _RNvXsW_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint256NtNtB5_6lehmer9LehmerOps10from_limbs
440
            #[inline]
441
13.0k
            fn into_limbs(self) -> Self::Limbs {
442
13.0k
                self.0
443
13.0k
            }
_RNvXs_Cs1uXV1nWfJt5_4u128NtB4_7Uint128NtNtCs8KLYHAG7u19_10kaspa_math6lehmer9LehmerOps10into_limbs
Line
Count
Source
441
13.0k
            fn into_limbs(self) -> Self::Limbs {
442
13.0k
                self.0
443
13.0k
            }
Unexecuted instantiation: _RNvXs1K_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtB6_6lehmer9LehmerOps10into_limbs
Unexecuted instantiation: _RNvXs2y_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtB6_6lehmer9LehmerOps10into_limbs
Unexecuted instantiation: _RNvXs6_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtB5_6lehmer9LehmerOps10into_limbs
Unexecuted instantiation: _RNvXsW_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint256NtNtB5_6lehmer9LehmerOps10into_limbs
444
            #[inline]
445
2.78k
            fn div_rem(self, other: Self) -> (Self, Self) {
446
2.78k
                $name::div_rem(self, other)
447
2.78k
            }
_RNvXs_Cs1uXV1nWfJt5_4u128NtB4_7Uint128NtNtCs8KLYHAG7u19_10kaspa_math6lehmer9LehmerOps7div_rem
Line
Count
Source
445
2.78k
            fn div_rem(self, other: Self) -> (Self, Self) {
446
2.78k
                $name::div_rem(self, other)
447
2.78k
            }
Unexecuted instantiation: _RNvXs1K_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtB6_6lehmer9LehmerOps7div_rem
Unexecuted instantiation: _RNvXs2y_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtB6_6lehmer9LehmerOps7div_rem
Unexecuted instantiation: _RNvXs6_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtB5_6lehmer9LehmerOps7div_rem
Unexecuted instantiation: _RNvXsW_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint256NtNtB5_6lehmer9LehmerOps7div_rem
448
        }
449
450
        impl $crate::uint::kaspa_utils::mem_size::MemSizeEstimator for $name {
451
0
            fn estimate_mem_units(&self) -> usize {
452
0
                1
453
454
0
            }
Unexecuted instantiation: _RNvXs0_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsk5EKZBqjsTv_11kaspa_utils8mem_size16MemSizeEstimator18estimate_mem_units
Unexecuted instantiation: _RNvXs1L_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsk5EKZBqjsTv_11kaspa_utils8mem_size16MemSizeEstimator18estimate_mem_units
Unexecuted instantiation: _RNvXs2z_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsk5EKZBqjsTv_11kaspa_utils8mem_size16MemSizeEstimator18estimate_mem_units
Unexecuted instantiation: _RNvXs7_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsk5EKZBqjsTv_11kaspa_utils8mem_size16MemSizeEstimator18estimate_mem_units
Unexecuted instantiation: _RNvXsX_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint256NtNtCsk5EKZBqjsTv_11kaspa_utils8mem_size16MemSizeEstimator18estimate_mem_units
455
        }
456
457
        impl $crate::uint::kaspa_utils::hex::ToHex for $name {
458
0
            fn to_hex(&self) -> String {
459
0
                self.to_be_bytes().as_slice().to_hex()
460
0
            }
Unexecuted instantiation: _RNvXs1_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
Unexecuted instantiation: _RNvXs1M_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
Unexecuted instantiation: _RNvXs2A_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
Unexecuted instantiation: _RNvXs8_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
Unexecuted instantiation: _RNvXsY_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint256NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
461
        }
462
463
        impl $crate::uint::kaspa_utils::hex::ToHex for &$name {
464
0
            fn to_hex(&self) -> String {
465
0
                self.to_be_bytes().as_slice().to_hex()
466
0
            }
Unexecuted instantiation: _RNvXs2_Cs1uXV1nWfJt5_4u128RNtB5_7Uint128NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
Unexecuted instantiation: _RNvXs1N_Cs8KLYHAG7u19_10kaspa_mathRNtB6_7Uint320NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
Unexecuted instantiation: _RNvXs2B_Cs8KLYHAG7u19_10kaspa_mathRNtB6_8Uint3072NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
Unexecuted instantiation: _RNvXs9_Cs8KLYHAG7u19_10kaspa_mathRNtB5_7Uint192NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
Unexecuted instantiation: _RNvXsZ_Cs8KLYHAG7u19_10kaspa_mathRNtB5_7Uint256NtNtCsk5EKZBqjsTv_11kaspa_utils3hex5ToHex6to_hex
467
        }
468
469
        impl $crate::uint::kaspa_utils::hex::FromHex for $name {
470
            type Error = $crate::Error;
471
0
            fn from_hex(hex: &str) -> Result<$name, Self::Error> {
472
0
                Ok($name::from_hex(hex)?)
473
0
            }
Unexecuted instantiation: _RNvXs3_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsk5EKZBqjsTv_11kaspa_utils3hex7FromHex8from_hex
Unexecuted instantiation: _RNvXs10_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtCsk5EKZBqjsTv_11kaspa_utils3hex7FromHex8from_hex
Unexecuted instantiation: _RNvXs1O_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsk5EKZBqjsTv_11kaspa_utils3hex7FromHex8from_hex
Unexecuted instantiation: _RNvXs2C_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsk5EKZBqjsTv_11kaspa_utils3hex7FromHex8from_hex
Unexecuted instantiation: _RNvXsa_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsk5EKZBqjsTv_11kaspa_utils3hex7FromHex8from_hex
474
        }
475
476
        impl PartialEq<u64> for $name {
477
            #[inline]
478
0
            fn eq(&self, other: &u64) -> bool {
479
0
                let bigger = self.0[1..].iter().any(|&x| x != 0);
Unexecuted instantiation: _RNCNvXs4_Cs1uXV1nWfJt5_4u128NtB7_7Uint128INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq0B7_
Unexecuted instantiation: _RNCNvXs11_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq0B8_
Unexecuted instantiation: _RNCNvXs1P_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq0B8_
Unexecuted instantiation: _RNCNvXs2D_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq0B8_
Unexecuted instantiation: _RNCNvXsb_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq0B7_
480
0
                !bigger && self.0[0] == *other
481
0
            }
Unexecuted instantiation: _RNvXs4_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq
Unexecuted instantiation: _RNvXs11_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq
Unexecuted instantiation: _RNvXs1P_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq
Unexecuted instantiation: _RNvXs2D_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq
Unexecuted instantiation: _RNvXsb_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtCsloNou9alJSK_4core3cmp9PartialEqyE2eq
482
        }
483
        impl PartialOrd<u64> for $name {
484
            #[inline]
485
0
            fn partial_cmp(&self, other: &u64) -> Option<core::cmp::Ordering> {
486
0
                let bigger = self.0[1..].iter().any(|&x| x != 0);
Unexecuted instantiation: _RNCNvXs5_Cs1uXV1nWfJt5_4u128NtB7_7Uint128INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp0B7_
Unexecuted instantiation: _RNCNvXs12_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp0B8_
Unexecuted instantiation: _RNCNvXs1Q_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp0B8_
Unexecuted instantiation: _RNCNvXs2E_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp0B8_
Unexecuted instantiation: _RNCNvXsc_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp0B7_
487
0
                if bigger {
488
0
                    Some(core::cmp::Ordering::Greater)
489
                } else {
490
0
                    self.0[0].partial_cmp(other)
491
                }
492
0
            }
Unexecuted instantiation: _RNvXs5_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp
Unexecuted instantiation: _RNvXs12_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp
Unexecuted instantiation: _RNvXs1Q_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp
Unexecuted instantiation: _RNvXs2E_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp
Unexecuted instantiation: _RNvXsc_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtCsloNou9alJSK_4core3cmp10PartialOrdyE11partial_cmp
493
        }
494
495
        impl PartialEq<u128> for $name {
496
            #[inline]
497
67.8k
            fn eq(&self, other: &u128) -> bool {
498
67.8k
                let bigger = self.0[2..].iter().any(|&x| x != 0);
Unexecuted instantiation: _RNCNvXs6_Cs1uXV1nWfJt5_4u128NtB7_7Uint128INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq0B7_
Unexecuted instantiation: _RNCNvXs13_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq0B8_
Unexecuted instantiation: _RNCNvXs1R_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq0B8_
Unexecuted instantiation: _RNCNvXs2F_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq0B8_
Unexecuted instantiation: _RNCNvXsd_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq0B7_
499
67.8k
                !bigger && self.0[0] == (*other as u64) && self.0[1] == ((*other >> 64) as u64)
500
67.8k
            }
_RNvXs6_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq
Line
Count
Source
497
67.8k
            fn eq(&self, other: &u128) -> bool {
498
67.8k
                let bigger = self.0[2..].iter().any(|&x| x != 0);
499
67.8k
                !bigger && self.0[0] == (*other as u64) && self.0[1] == ((*other >> 64) as u64)
500
67.8k
            }
Unexecuted instantiation: _RNvXs13_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq
Unexecuted instantiation: _RNvXs1R_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq
Unexecuted instantiation: _RNvXs2F_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq
Unexecuted instantiation: _RNvXsd_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtCsloNou9alJSK_4core3cmp9PartialEqoE2eq
501
        }
502
        impl PartialOrd<u128> for $name {
503
            #[inline]
504
0
            fn partial_cmp(&self, other: &u128) -> Option<core::cmp::Ordering> {
505
0
                let bigger = self.0[2..].iter().any(|&x| x != 0);
Unexecuted instantiation: _RNCNvXs7_Cs1uXV1nWfJt5_4u128NtB7_7Uint128INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp0B7_
Unexecuted instantiation: _RNCNvXs14_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp0B8_
Unexecuted instantiation: _RNCNvXs1S_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp0B8_
Unexecuted instantiation: _RNCNvXs2G_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp0B8_
Unexecuted instantiation: _RNCNvXse_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp0B7_
506
0
                if bigger {
507
0
                    Some(core::cmp::Ordering::Greater)
508
                } else {
509
0
                    self.as_u128().partial_cmp(other)
510
                }
511
0
            }
Unexecuted instantiation: _RNvXs7_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp
Unexecuted instantiation: _RNvXs14_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp
Unexecuted instantiation: _RNvXs1S_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp
Unexecuted instantiation: _RNvXs2G_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp
Unexecuted instantiation: _RNvXse_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtCsloNou9alJSK_4core3cmp10PartialOrdoE11partial_cmp
512
        }
513
514
        impl PartialOrd for $name {
515
            #[inline]
516
118k
            fn partial_cmp(&self, other: &$name) -> Option<core::cmp::Ordering> {
517
118k
                Some(self.cmp(&other))
518
118k
            }
_RNvXs8_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsloNou9alJSK_4core3cmp10PartialOrd11partial_cmp
Line
Count
Source
516
118k
            fn partial_cmp(&self, other: &$name) -> Option<core::cmp::Ordering> {
517
118k
                Some(self.cmp(&other))
518
118k
            }
Unexecuted instantiation: _RNvXs15_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtCsloNou9alJSK_4core3cmp10PartialOrd11partial_cmp
Unexecuted instantiation: _RNvXs1T_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsloNou9alJSK_4core3cmp10PartialOrd11partial_cmp
Unexecuted instantiation: _RNvXs2H_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsloNou9alJSK_4core3cmp10PartialOrd11partial_cmp
Unexecuted instantiation: _RNvXsf_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsloNou9alJSK_4core3cmp10PartialOrd11partial_cmp
519
        }
520
521
        impl Ord for $name {
522
            #[inline]
523
118k
            fn cmp(&self, other: &$name) -> core::cmp::Ordering {
524
                // We need to manually implement ordering because we use little-endian
525
                // and the auto derive is a lexicographic ordering(i.e. memcmp)
526
                // which with numbers is equivalent to big-endian
527
118k
                Iterator::cmp(self.0.iter().rev(), other.0.iter().rev())
528
118k
            }
_RNvXs9_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsloNou9alJSK_4core3cmp3Ord3cmp
Line
Count
Source
523
118k
            fn cmp(&self, other: &$name) -> core::cmp::Ordering {
524
                // We need to manually implement ordering because we use little-endian
525
                // and the auto derive is a lexicographic ordering(i.e. memcmp)
526
                // which with numbers is equivalent to big-endian
527
118k
                Iterator::cmp(self.0.iter().rev(), other.0.iter().rev())
528
118k
            }
Unexecuted instantiation: _RNvXs16_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtCsloNou9alJSK_4core3cmp3Ord3cmp
Unexecuted instantiation: _RNvXs1U_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsloNou9alJSK_4core3cmp3Ord3cmp
Unexecuted instantiation: _RNvXs2I_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsloNou9alJSK_4core3cmp3Ord3cmp
Unexecuted instantiation: _RNvXsg_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsloNou9alJSK_4core3cmp3Ord3cmp
529
        }
530
531
        impl core::ops::Add<$name> for $name {
532
            type Output = $name;
533
534
            #[inline]
535
            #[track_caller]
536
5.42k
            fn add(self, other: $name) -> $name {
537
5.42k
                let (sum, carry) = self.overflowing_add(other);
538
5.42k
                debug_assert!(!carry, "attempt to add with overflow"); // Check in debug that it didn't overflow
539
5.42k
                sum
540
5.42k
            }
_RNvXsa_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops5arith3Add3add
Line
Count
Source
536
5.42k
            fn add(self, other: $name) -> $name {
537
5.42k
                let (sum, carry) = self.overflowing_add(other);
538
5.42k
                debug_assert!(!carry, "attempt to add with overflow"); // Check in debug that it didn't overflow
539
5.42k
                sum
540
5.42k
            }
Unexecuted instantiation: _RNvXs17_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops5arith3Add3add
Unexecuted instantiation: _RNvXs1V_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops5arith3Add3add
Unexecuted instantiation: _RNvXs2J_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops5arith3Add3add
Unexecuted instantiation: _RNvXsh_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops5arith3Add3add
541
        }
542
543
        impl core::ops::Add<u64> for $name {
544
            type Output = $name;
545
546
            #[inline]
547
            #[track_caller]
548
5.11k
            fn add(self, other: u64) -> $name {
549
5.11k
                let (sum, carry) = self.overflowing_add_u64(other);
550
5.11k
                debug_assert!(!carry, "attempt to add with overflow"); // Check in debug that it didn't overflow
551
5.11k
                sum
552
5.11k
            }
_RNvXsb_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtNtCsloNou9alJSK_4core3ops5arith3AddyE3add
Line
Count
Source
548
5.11k
            fn add(self, other: u64) -> $name {
549
5.11k
                let (sum, carry) = self.overflowing_add_u64(other);
550
5.11k
                debug_assert!(!carry, "attempt to add with overflow"); // Check in debug that it didn't overflow
551
5.11k
                sum
552
5.11k
            }
Unexecuted instantiation: _RNvXs18_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtNtCsloNou9alJSK_4core3ops5arith3AddyE3add
Unexecuted instantiation: _RNvXs1W_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtNtCsloNou9alJSK_4core3ops5arith3AddyE3add
Unexecuted instantiation: _RNvXs2K_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtNtCsloNou9alJSK_4core3ops5arith3AddyE3add
Unexecuted instantiation: _RNvXsi_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtNtCsloNou9alJSK_4core3ops5arith3AddyE3add
553
        }
554
555
        impl core::ops::Sub<$name> for $name {
556
            type Output = $name;
557
558
            #[inline]
559
            #[track_caller]
560
53.0k
            fn sub(self, other: $name) -> $name {
561
53.0k
                let (sum, carry) = self.overflowing_sub(other);
562
53.0k
                debug_assert!(!carry, "attempt to subtract with overflow"); // Check in debug that it didn't overflow
563
53.0k
                sum
564
53.0k
            }
_RNvXsc_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops5arith3Sub3sub
Line
Count
Source
560
53.0k
            fn sub(self, other: $name) -> $name {
561
53.0k
                let (sum, carry) = self.overflowing_sub(other);
562
53.0k
                debug_assert!(!carry, "attempt to subtract with overflow"); // Check in debug that it didn't overflow
563
53.0k
                sum
564
53.0k
            }
Unexecuted instantiation: _RNvXs19_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops5arith3Sub3sub
Unexecuted instantiation: _RNvXs1X_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops5arith3Sub3sub
Unexecuted instantiation: _RNvXs2L_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops5arith3Sub3sub
Unexecuted instantiation: _RNvXsj_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops5arith3Sub3sub
565
        }
566
567
        impl core::ops::Mul<$name> for $name {
568
            type Output = $name;
569
570
            #[inline]
571
            #[track_caller]
572
5.38k
            fn mul(self, other: $name) -> $name {
573
5.38k
                let (product, carry) = self.overflowing_mul(other);
574
5.38k
                debug_assert!(!carry, "attempt to multiply with overflow"); // Check in debug that it didn't overflow
575
5.38k
                product
576
5.38k
            }
_RNvXsd_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops5arith3Mul3mul
Line
Count
Source
572
5.38k
            fn mul(self, other: $name) -> $name {
573
5.38k
                let (product, carry) = self.overflowing_mul(other);
574
5.38k
                debug_assert!(!carry, "attempt to multiply with overflow"); // Check in debug that it didn't overflow
575
5.38k
                product
576
5.38k
            }
Unexecuted instantiation: _RNvXs1Y_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops5arith3Mul3mul
Unexecuted instantiation: _RNvXs1a_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops5arith3Mul3mul
Unexecuted instantiation: _RNvXs2M_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops5arith3Mul3mul
Unexecuted instantiation: _RNvXsk_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops5arith3Mul3mul
577
        }
578
579
        impl core::ops::Mul<u64> for $name {
580
            type Output = $name;
581
582
            #[inline]
583
            #[track_caller]
584
5.09k
            fn mul(self, other: u64) -> $name {
585
5.09k
                let (product, carry) = self.overflowing_mul_u64(other);
586
5.09k
                debug_assert!(!carry, "attempt to multiply with overflow"); // Check in debug that it didn't overflow
587
5.09k
                product
588
5.09k
            }
_RNvXse_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtNtCsloNou9alJSK_4core3ops5arith3MulyE3mul
Line
Count
Source
584
5.09k
            fn mul(self, other: u64) -> $name {
585
5.09k
                let (product, carry) = self.overflowing_mul_u64(other);
586
5.09k
                debug_assert!(!carry, "attempt to multiply with overflow"); // Check in debug that it didn't overflow
587
5.09k
                product
588
5.09k
            }
Unexecuted instantiation: _RNvXs1Z_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtNtCsloNou9alJSK_4core3ops5arith3MulyE3mul
Unexecuted instantiation: _RNvXs1b_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtNtCsloNou9alJSK_4core3ops5arith3MulyE3mul
Unexecuted instantiation: _RNvXs2N_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtNtCsloNou9alJSK_4core3ops5arith3MulyE3mul
Unexecuted instantiation: _RNvXsl_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtNtCsloNou9alJSK_4core3ops5arith3MulyE3mul
589
        }
590
591
        impl core::ops::Div<$name> for $name {
592
            type Output = $name;
593
594
            #[inline]
595
5.35k
            fn div(self, other: $name) -> $name {
596
5.35k
                self.div_rem(other).0
597
5.35k
            }
_RNvXsf_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops5arith3Div3div
Line
Count
Source
595
5.35k
            fn div(self, other: $name) -> $name {
596
5.35k
                self.div_rem(other).0
597
5.35k
            }
Unexecuted instantiation: _RNvXs1c_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops5arith3Div3div
Unexecuted instantiation: _RNvXs20_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops5arith3Div3div
Unexecuted instantiation: _RNvXs2O_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops5arith3Div3div
Unexecuted instantiation: _RNvXsm_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops5arith3Div3div
598
        }
599
600
        impl core::ops::Rem<$name> for $name {
601
            type Output = $name;
602
603
            #[inline]
604
5.26k
            fn rem(self, other: $name) -> $name {
605
5.26k
                self.div_rem(other).1
606
5.26k
            }
_RNvXsg_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops5arith3Rem3rem
Line
Count
Source
604
5.26k
            fn rem(self, other: $name) -> $name {
605
5.26k
                self.div_rem(other).1
606
5.26k
            }
Unexecuted instantiation: _RNvXs1d_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops5arith3Rem3rem
Unexecuted instantiation: _RNvXs21_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops5arith3Rem3rem
Unexecuted instantiation: _RNvXs2P_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops5arith3Rem3rem
Unexecuted instantiation: _RNvXsn_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops5arith3Rem3rem
607
        }
608
609
        impl core::ops::Div<u64> for $name {
610
            type Output = $name;
611
612
            #[inline]
613
0
            fn div(self, other: u64) -> $name {
614
0
                self.div_rem_u64(other).0
615
0
            }
Unexecuted instantiation: _RNvXsh_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtNtCsloNou9alJSK_4core3ops5arith3DivyE3div
Unexecuted instantiation: _RNvXs1e_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtNtCsloNou9alJSK_4core3ops5arith3DivyE3div
Unexecuted instantiation: _RNvXs22_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtNtCsloNou9alJSK_4core3ops5arith3DivyE3div
Unexecuted instantiation: _RNvXs2Q_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtNtCsloNou9alJSK_4core3ops5arith3DivyE3div
Unexecuted instantiation: _RNvXso_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtNtCsloNou9alJSK_4core3ops5arith3DivyE3div
616
        }
617
618
        impl core::ops::Rem<u64> for $name {
619
            type Output = u64;
620
621
0
            fn rem(self, other: u64) -> u64 {
622
0
                self.div_rem_u64(other).1
623
0
            }
Unexecuted instantiation: _RNvXsi_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtNtCsloNou9alJSK_4core3ops5arith3RemyE3rem
Unexecuted instantiation: _RNvXs1f_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtNtCsloNou9alJSK_4core3ops5arith3RemyE3rem
Unexecuted instantiation: _RNvXs23_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtNtCsloNou9alJSK_4core3ops5arith3RemyE3rem
Unexecuted instantiation: _RNvXs2R_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtNtCsloNou9alJSK_4core3ops5arith3RemyE3rem
Unexecuted instantiation: _RNvXsp_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtNtCsloNou9alJSK_4core3ops5arith3RemyE3rem
624
        }
625
626
        impl core::ops::BitAnd<$name> for $name {
627
            type Output = $name;
628
629
            #[inline]
630
5.19k
            fn bitand(mut self, other: $name) -> $name {
631
10.3k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a &= *b);
_RNCNvXsj_Cs1uXV1nWfJt5_4u128NtB7_7Uint128NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand0B7_
Line
Count
Source
631
10.3k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a &= *b);
Unexecuted instantiation: _RNCNvXs1g_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand0B8_
Unexecuted instantiation: _RNCNvXs24_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand0B8_
Unexecuted instantiation: _RNCNvXs2S_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand0B8_
Unexecuted instantiation: _RNCNvXsq_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand0B7_
632
5.19k
                self
633
5.19k
            }
_RNvXsj_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand
Line
Count
Source
630
5.19k
            fn bitand(mut self, other: $name) -> $name {
631
5.19k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a &= *b);
632
5.19k
                self
633
5.19k
            }
Unexecuted instantiation: _RNvXs1g_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand
Unexecuted instantiation: _RNvXs24_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand
Unexecuted instantiation: _RNvXs2S_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand
Unexecuted instantiation: _RNvXsq_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops3bit6BitAnd6bitand
634
        }
635
636
        impl core::ops::BitXor<$name> for $name {
637
            type Output = $name;
638
639
            #[inline]
640
5.13k
            fn bitxor(mut self, other: $name) -> $name {
641
10.2k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a ^= *b);
_RNCNvXsk_Cs1uXV1nWfJt5_4u128NtB7_7Uint128NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor0B7_
Line
Count
Source
641
10.2k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a ^= *b);
Unexecuted instantiation: _RNCNvXs1h_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor0B8_
Unexecuted instantiation: _RNCNvXs25_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor0B8_
Unexecuted instantiation: _RNCNvXs2T_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor0B8_
Unexecuted instantiation: _RNCNvXsr_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor0B7_
642
5.13k
                self
643
5.13k
            }
_RNvXsk_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor
Line
Count
Source
640
5.13k
            fn bitxor(mut self, other: $name) -> $name {
641
5.13k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a ^= *b);
642
5.13k
                self
643
5.13k
            }
Unexecuted instantiation: _RNvXs1h_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor
Unexecuted instantiation: _RNvXs25_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor
Unexecuted instantiation: _RNvXs2T_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor
Unexecuted instantiation: _RNvXsr_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops3bit6BitXor6bitxor
644
        }
645
646
        impl core::ops::BitOr<$name> for $name {
647
            type Output = $name;
648
649
            #[inline]
650
5.16k
            fn bitor(mut self, other: $name) -> $name {
651
10.3k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a |= *b);
_RNCNvXsl_Cs1uXV1nWfJt5_4u128NtB7_7Uint128NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor0B7_
Line
Count
Source
651
10.3k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a |= *b);
Unexecuted instantiation: _RNCNvXs1i_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor0B8_
Unexecuted instantiation: _RNCNvXs26_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor0B8_
Unexecuted instantiation: _RNCNvXs2U_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor0B8_
Unexecuted instantiation: _RNCNvXss_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor0B7_
652
5.16k
                self
653
5.16k
            }
_RNvXsl_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor
Line
Count
Source
650
5.16k
            fn bitor(mut self, other: $name) -> $name {
651
5.16k
                self.0.iter_mut().zip(other.0.iter()).for_each(|(a, b)| *a |= *b);
652
5.16k
                self
653
5.16k
            }
Unexecuted instantiation: _RNvXs1i_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor
Unexecuted instantiation: _RNvXs26_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor
Unexecuted instantiation: _RNvXs2U_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor
Unexecuted instantiation: _RNvXss_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops3bit5BitOr5bitor
654
        }
655
656
        impl core::ops::Not for $name {
657
            type Output = $name;
658
659
            #[inline]
660
5.12k
            fn not(mut self) -> $name {
661
10.2k
                self.0.iter_mut().for_each(|a| *a = !*a);
_RNCNvXsm_Cs1uXV1nWfJt5_4u128NtB7_7Uint128NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not0B7_
Line
Count
Source
661
10.2k
                self.0.iter_mut().for_each(|a| *a = !*a);
Unexecuted instantiation: _RNCNvXs1j_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not0B8_
Unexecuted instantiation: _RNCNvXs27_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not0B8_
Unexecuted instantiation: _RNCNvXs2V_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not0B8_
Unexecuted instantiation: _RNCNvXst_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not0B7_
662
5.12k
                self
663
5.12k
            }
_RNvXsm_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not
Line
Count
Source
660
5.12k
            fn not(mut self) -> $name {
661
5.12k
                self.0.iter_mut().for_each(|a| *a = !*a);
662
5.12k
                self
663
5.12k
            }
Unexecuted instantiation: _RNvXs1j_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not
Unexecuted instantiation: _RNvXs27_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not
Unexecuted instantiation: _RNvXs2V_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not
Unexecuted instantiation: _RNvXst_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtNtCsloNou9alJSK_4core3ops3bit3Not3not
664
        }
665
666
        impl core::ops::Shl<u32> for $name {
667
            type Output = $name;
668
669
            #[inline]
670
            #[track_caller]
671
14.7k
            fn shl(self, shift: u32) -> $name {
672
14.7k
                let (res, carry) = self.overflowing_shl(shift);
673
14.7k
                debug_assert!(!carry, "attempt to shift left with overflow"); // Check in debug that it didn't overflow
674
14.7k
                res
675
14.7k
            }
_RNvXsn_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtNtCsloNou9alJSK_4core3ops3bit3ShlmE3shl
Line
Count
Source
671
14.7k
            fn shl(self, shift: u32) -> $name {
672
14.7k
                let (res, carry) = self.overflowing_shl(shift);
673
14.7k
                debug_assert!(!carry, "attempt to shift left with overflow"); // Check in debug that it didn't overflow
674
14.7k
                res
675
14.7k
            }
Unexecuted instantiation: _RNvXs1k_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtNtCsloNou9alJSK_4core3ops3bit3ShlmE3shl
Unexecuted instantiation: _RNvXs28_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtNtCsloNou9alJSK_4core3ops3bit3ShlmE3shl
Unexecuted instantiation: _RNvXs2W_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtNtCsloNou9alJSK_4core3ops3bit3ShlmE3shl
Unexecuted instantiation: _RNvXsu_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtNtCsloNou9alJSK_4core3ops3bit3ShlmE3shl
676
        }
677
678
        impl core::ops::Shr<u32> for $name {
679
            type Output = $name;
680
681
            #[inline]
682
            #[track_caller]
683
123k
            fn shr(self, shift: u32) -> $name {
684
123k
                let (res, carry) = self.overflowing_shr(shift);
685
123k
                debug_assert!(!carry, "attempt to shift left with overflow"); // Check in debug that it didn't overflow
686
123k
                res
687
123k
            }
_RNvXso_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtNtCsloNou9alJSK_4core3ops3bit3ShrmE3shr
Line
Count
Source
683
123k
            fn shr(self, shift: u32) -> $name {
684
123k
                let (res, carry) = self.overflowing_shr(shift);
685
123k
                debug_assert!(!carry, "attempt to shift left with overflow"); // Check in debug that it didn't overflow
686
123k
                res
687
123k
            }
Unexecuted instantiation: _RNvXs1l_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtNtCsloNou9alJSK_4core3ops3bit3ShrmE3shr
Unexecuted instantiation: _RNvXs29_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtNtCsloNou9alJSK_4core3ops3bit3ShrmE3shr
Unexecuted instantiation: _RNvXs2X_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtNtCsloNou9alJSK_4core3ops3bit3ShrmE3shr
Unexecuted instantiation: _RNvXsv_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtNtCsloNou9alJSK_4core3ops3bit3ShrmE3shr
688
        }
689
690
        impl core::iter::Sum for $name {
691
            #[inline]
692
            #[track_caller]
693
0
            fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
694
0
                let first = iter.next().unwrap_or_else(|| Self::ZERO);
695
0
                iter.fold(first, |a, b| a + b)
Unexecuted instantiation: _RNCINvXsp_Cs1uXV1nWfJt5_4u128NtB8_7Uint128NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEs_0B8_
Unexecuted instantiation: _RNCINvXs1m_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint256NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEs_0B9_
Unexecuted instantiation: _RNCINvXs2Y_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint3072NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEs_0B9_
Unexecuted instantiation: _RNCINvXs2a_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint320NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEs_0B9_
Unexecuted instantiation: _RNCINvXsw_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint192NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEs_0B8_
696
0
            }
Unexecuted instantiation: _RINvXsp_Cs1uXV1nWfJt5_4u128NtB6_7Uint128NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEB6_
Unexecuted instantiation: _RINvXs1m_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint256NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEB7_
Unexecuted instantiation: _RINvXs2Y_Cs8KLYHAG7u19_10kaspa_mathNtB7_8Uint3072NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEB7_
Unexecuted instantiation: _RINvXs2a_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint320NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEB7_
Unexecuted instantiation: _RINvXsw_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint192NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3Sum3sumpEB6_
697
        }
698
699
        impl core::iter::Product for $name {
700
            #[inline]
701
            #[track_caller]
702
0
            fn product<I: Iterator<Item = Self>>(mut iter: I) -> Self {
703
0
                let first = iter.next().unwrap_or_else(|| Self::from_u64(1));
Unexecuted instantiation: _RNCINvXsq_Cs1uXV1nWfJt5_4u128NtB8_7Uint128NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpE0B8_
Unexecuted instantiation: _RNCINvXs1n_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint256NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpE0B9_
Unexecuted instantiation: _RNCINvXs2Z_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint3072NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpE0B9_
Unexecuted instantiation: _RNCINvXs2b_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint320NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpE0B9_
Unexecuted instantiation: _RNCINvXsx_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint192NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpE0B8_
704
0
                iter.fold(first, |a, b| a * b)
Unexecuted instantiation: _RNCINvXsq_Cs1uXV1nWfJt5_4u128NtB8_7Uint128NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEs_0B8_
Unexecuted instantiation: _RNCINvXs1n_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint256NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEs_0B9_
Unexecuted instantiation: _RNCINvXs2Z_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint3072NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEs_0B9_
Unexecuted instantiation: _RNCINvXs2b_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint320NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEs_0B9_
Unexecuted instantiation: _RNCINvXsx_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint192NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEs_0B8_
705
0
            }
Unexecuted instantiation: _RINvXsq_Cs1uXV1nWfJt5_4u128NtB6_7Uint128NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEB6_
Unexecuted instantiation: _RINvXs1n_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint256NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEB7_
Unexecuted instantiation: _RINvXs2Z_Cs8KLYHAG7u19_10kaspa_mathNtB7_8Uint3072NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEB7_
Unexecuted instantiation: _RINvXs2b_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint320NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEB7_
Unexecuted instantiation: _RINvXsx_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint192NtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7Product7productpEB6_
706
        }
707
708
        impl<'a> core::iter::Sum<&'a $name> for $name {
709
            #[inline]
710
            #[track_caller]
711
0
            fn sum<I: Iterator<Item = &'a Self>>(mut iter: I) -> Self {
712
0
                let first = iter.next().copied().unwrap_or_else(|| Self::ZERO);
713
0
                iter.fold(first, |a, &b| a + b)
Unexecuted instantiation: _RNCINvXsr_Cs1uXV1nWfJt5_4u128NtB8_7Uint128INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBr_E3sumpEs_0B8_
Unexecuted instantiation: _RNCINvXs1o_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint256INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBz_E3sumpEs_0B9_
Unexecuted instantiation: _RNCINvXs2c_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint320INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBz_E3sumpEs_0B9_
Unexecuted instantiation: _RNCINvXs30_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint3072INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBz_E3sumpEs_0B9_
Unexecuted instantiation: _RNCINvXsy_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint192INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBy_E3sumpEs_0B8_
714
0
            }
Unexecuted instantiation: _RINvXsr_Cs1uXV1nWfJt5_4u128NtB6_7Uint128INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBp_E3sumpEB6_
Unexecuted instantiation: _RINvXs1o_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint256INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBx_E3sumpEB7_
Unexecuted instantiation: _RINvXs2c_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint320INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBx_E3sumpEB7_
Unexecuted instantiation: _RINvXs30_Cs8KLYHAG7u19_10kaspa_mathNtB7_8Uint3072INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBx_E3sumpEB7_
Unexecuted instantiation: _RINvXsy_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint192INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum3SumRBw_E3sumpEB6_
715
        }
716
717
        impl<'a> core::iter::Product<&'a $name> for $name {
718
            #[inline]
719
            #[track_caller]
720
0
            fn product<I: Iterator<Item = &'a Self>>(mut iter: I) -> Self {
721
0
                let first = iter.next().copied().unwrap_or_else(|| Self::from_u64(1));
Unexecuted instantiation: _RNCINvXss_Cs1uXV1nWfJt5_4u128NtB8_7Uint128INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBr_E7productpE0B8_
Unexecuted instantiation: _RNCINvXs1p_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint256INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBz_E7productpE0B9_
Unexecuted instantiation: _RNCINvXs2d_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint320INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBz_E7productpE0B9_
Unexecuted instantiation: _RNCINvXs31_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint3072INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBz_E7productpE0B9_
Unexecuted instantiation: _RNCINvXsz_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint192INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBy_E7productpE0B8_
722
0
                iter.fold(first, |a, &b| a * b)
Unexecuted instantiation: _RNCINvXss_Cs1uXV1nWfJt5_4u128NtB8_7Uint128INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBr_E7productpEs_0B8_
Unexecuted instantiation: _RNCINvXs1p_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint256INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBz_E7productpEs_0B9_
Unexecuted instantiation: _RNCINvXs2d_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint320INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBz_E7productpEs_0B9_
Unexecuted instantiation: _RNCINvXs31_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint3072INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBz_E7productpEs_0B9_
Unexecuted instantiation: _RNCINvXsz_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint192INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBy_E7productpEs_0B8_
723
0
            }
Unexecuted instantiation: _RINvXss_Cs1uXV1nWfJt5_4u128NtB6_7Uint128INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBp_E7productpEB6_
Unexecuted instantiation: _RINvXs1p_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint256INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBx_E7productpEB7_
Unexecuted instantiation: _RINvXs2d_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint320INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBx_E7productpEB7_
Unexecuted instantiation: _RINvXs31_Cs8KLYHAG7u19_10kaspa_mathNtB7_8Uint3072INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBx_E7productpEB7_
Unexecuted instantiation: _RINvXsz_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint192INtNtNtNtCsloNou9alJSK_4core4iter6traits5accum7ProductRBw_E7productpEB6_
724
        }
725
726
        impl Default for $name {
727
            #[inline]
728
0
            fn default() -> Self {
729
0
                Self::ZERO
730
0
            }
Unexecuted instantiation: _RNvXst_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsloNou9alJSK_4core7default7Default7default
Unexecuted instantiation: _RNvXs1q_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtCsloNou9alJSK_4core7default7Default7default
Unexecuted instantiation: _RNvXs2e_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsloNou9alJSK_4core7default7Default7default
Unexecuted instantiation: _RNvXs32_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsloNou9alJSK_4core7default7Default7default
Unexecuted instantiation: _RNvXsA_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsloNou9alJSK_4core7default7Default7default
731
        }
732
733
        impl From<u64> for $name {
734
            #[inline]
735
0
            fn from(x: u64) -> Self {
736
0
                Self::from_u64(x)
737
0
            }
Unexecuted instantiation: _RNvXsu_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtCsloNou9alJSK_4core7convert4FromyE4from
Unexecuted instantiation: _RNvXs1r_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtCsloNou9alJSK_4core7convert4FromyE4from
Unexecuted instantiation: _RNvXs2f_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtCsloNou9alJSK_4core7convert4FromyE4from
Unexecuted instantiation: _RNvXs33_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtCsloNou9alJSK_4core7convert4FromyE4from
Unexecuted instantiation: _RNvXsB_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtCsloNou9alJSK_4core7convert4FromyE4from
738
        }
739
740
        impl core::convert::TryFrom<$name> for u128 {
741
            type Error = $crate::uint::TryFromIntError;
742
743
            #[inline]
744
0
            fn try_from(value: $name) -> Result<Self, Self::Error> {
745
0
                if value.0[2..].iter().any(|&x| x != 0) {
Unexecuted instantiation: _RNCNvXsv_Cs1uXV1nWfJt5_4u128oINtNtCsloNou9alJSK_4core7convert7TryFromNtB7_7Uint128E8try_from0B7_
Unexecuted instantiation: _RNCNvXs1s_Cs8KLYHAG7u19_10kaspa_mathoINtNtCsloNou9alJSK_4core7convert7TryFromNtB8_7Uint256E8try_from0B8_
Unexecuted instantiation: _RNCNvXs2g_Cs8KLYHAG7u19_10kaspa_mathoINtNtCsloNou9alJSK_4core7convert7TryFromNtB8_7Uint320E8try_from0B8_
Unexecuted instantiation: _RNCNvXs34_Cs8KLYHAG7u19_10kaspa_mathoINtNtCsloNou9alJSK_4core7convert7TryFromNtB8_8Uint3072E8try_from0B8_
Unexecuted instantiation: _RNCNvXsC_Cs8KLYHAG7u19_10kaspa_mathoINtNtCsloNou9alJSK_4core7convert7TryFromNtB7_7Uint192E8try_from0B7_
746
0
                    Err($crate::uint::TryFromIntError)
747
                } else {
748
0
                    Ok(value.as_u128())
749
                }
750
0
            }
Unexecuted instantiation: _RNvXsv_Cs1uXV1nWfJt5_4u128oINtNtCsloNou9alJSK_4core7convert7TryFromNtB5_7Uint128E8try_from
Unexecuted instantiation: _RNvXs1s_Cs8KLYHAG7u19_10kaspa_mathoINtNtCsloNou9alJSK_4core7convert7TryFromNtB6_7Uint256E8try_from
Unexecuted instantiation: _RNvXs2g_Cs8KLYHAG7u19_10kaspa_mathoINtNtCsloNou9alJSK_4core7convert7TryFromNtB6_7Uint320E8try_from
Unexecuted instantiation: _RNvXs34_Cs8KLYHAG7u19_10kaspa_mathoINtNtCsloNou9alJSK_4core7convert7TryFromNtB6_8Uint3072E8try_from
Unexecuted instantiation: _RNvXsC_Cs8KLYHAG7u19_10kaspa_mathoINtNtCsloNou9alJSK_4core7convert7TryFromNtB5_7Uint192E8try_from
751
        }
752
753
        impl core::fmt::LowerHex for $name {
754
            #[inline]
755
0
            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
756
0
                let mut hex = [0u8; Self::BYTES * 2];
757
0
                let bytes = self.to_be_bytes();
758
0
                $crate::uint::faster_hex::hex_encode(&bytes, &mut hex).expect("The output is exactly twice the size of the input");
759
0
                let first_non_zero = hex.iter().position(|&x| x != b'0').unwrap_or(hex.len() - 1);
Unexecuted instantiation: _RNCNvXsw_Cs1uXV1nWfJt5_4u128NtB7_7Uint128NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt0B7_
Unexecuted instantiation: _RNCNvXs1t_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint256NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt0B8_
Unexecuted instantiation: _RNCNvXs2h_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint320NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt0B8_
Unexecuted instantiation: _RNCNvXs35_Cs8KLYHAG7u19_10kaspa_mathNtB8_8Uint3072NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt0B8_
Unexecuted instantiation: _RNCNvXsD_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint192NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt0B7_
760
                // The string is hex encoded so must be valid UTF8.
761
0
                let str = unsafe { core::str::from_utf8_unchecked(&hex[first_non_zero..]) };
762
0
                f.pad_integral(true, "0x", str)
763
0
            }
Unexecuted instantiation: _RNvXsw_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt
Unexecuted instantiation: _RNvXs1t_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt
Unexecuted instantiation: _RNvXs2h_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt
Unexecuted instantiation: _RNvXs35_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt
Unexecuted instantiation: _RNvXsD_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsloNou9alJSK_4core3fmt8LowerHex3fmt
764
        }
765
766
        // Based on https://github.com/rust-lang/rust/blob/2e44c17c12cec45b6a682b1e53a04ac5b5fcc9d2/library/core/src/fmt/num.rs#L209
767
        impl core::fmt::Display for $name {
768
            #[inline]
769
0
            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
770
                // 2 digit decimal look up table
771
                static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
772
            2021222324252627282930313233343536373839\
773
            4041424344454647484950515253545556575859\
774
            6061626364656667686970717273747576777879\
775
            8081828384858687888990919293949596979899";
776
777
0
                let mut buf = [0u8; $name::LIMBS * 20]; // 2**64-1 takes 20 digits to represent.
778
0
                let mut n = *self;
779
0
                let mut curr = buf.len();
780
781
                // eagerly decode 4 characters at a time
782
                const STEP: u64 = 10_000;
783
0
                while n >= STEP {
784
0
                    let rem: u64;
785
0
                    (n, rem) = n.div_rem_u64(STEP);
786
0
                    let rem = rem as usize;
787
0
                    let d1 = (rem / 100) << 1;
788
0
                    let d2 = (rem % 100) << 1;
789
0
                    curr -= 4;
790
0
791
0
                    buf[curr] = DEC_DIGITS_LUT[d1];
792
0
                    buf[curr + 1] = DEC_DIGITS_LUT[d1 + 1];
793
0
                    buf[curr + 2] = DEC_DIGITS_LUT[d2];
794
0
                    buf[curr + 3] = DEC_DIGITS_LUT[d2 + 1];
795
0
                }
796
                // if we reach here numbers are <= 9999, so at most 4 chars long
797
0
                let mut n = n.as_u64() as usize; // possibly reduce 64bit math
798
799
                // decode 2 more chars, if > 2 chars
800
0
                if n >= 100 {
801
0
                    let d1 = (n % 100) << 1;
802
0
                    n /= 100;
803
0
                    curr -= 2;
804
0
                    buf[curr] = DEC_DIGITS_LUT[d1 as usize];
805
0
                    buf[curr + 1] = DEC_DIGITS_LUT[d1 + 1 as usize];
806
0
                }
807
808
                // decode last 1 or 2 chars
809
0
                if n < 10 {
810
0
                    curr -= 1;
811
0
                    buf[curr] = (n as u8) + b'0'
812
0
                } else {
813
0
                    let d1 = n << 1;
814
0
                    curr -= 2;
815
0
                    buf[curr] = DEC_DIGITS_LUT[d1];
816
0
                    buf[curr + 1] = DEC_DIGITS_LUT[d1 + 1];
817
0
                }
818
819
                // SAFETY: everything up to `curr` is valid UTF8 because `DEC_DIGITS_LUT` is.
820
0
                let buf_str = unsafe { std::str::from_utf8_unchecked(&buf[curr..]) };
821
0
                f.pad_integral(true, "", buf_str)
822
0
            }
Unexecuted instantiation: _RNvXsx_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsloNou9alJSK_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs1u_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtCsloNou9alJSK_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs2i_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsloNou9alJSK_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs36_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsloNou9alJSK_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsE_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsloNou9alJSK_4core3fmt7Display3fmt
823
        }
824
825
        impl core::fmt::Binary for $name {
826
            #[inline]
827
0
            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
828
                const BIN_LEN: usize = $name::BITS as usize;
829
0
                let mut buf = [0u8; BIN_LEN];
830
0
                let mut first_one = BIN_LEN - 1;
831
0
                for (index, (bit, char)) in self.iter_be_bits().zip(buf.iter_mut()).enumerate() {
832
0
                    *char = bit as u8 + b'0';
833
0
                    if first_one == BIN_LEN - 1 && bit {
834
0
                        first_one = index;
835
0
                    }
836
                }
837
                // We only wrote '0' and '1' so this is always valid UTF-8
838
0
                let buf_str = unsafe { std::str::from_utf8_unchecked(&buf[first_one..]) };
839
0
                f.pad_integral(true, "0b", buf_str)
840
0
            }
Unexecuted instantiation: _RNvXsy_Cs1uXV1nWfJt5_4u128NtB5_7Uint128NtNtCsloNou9alJSK_4core3fmt6Binary3fmt
Unexecuted instantiation: _RNvXs1v_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256NtNtCsloNou9alJSK_4core3fmt6Binary3fmt
Unexecuted instantiation: _RNvXs2j_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320NtNtCsloNou9alJSK_4core3fmt6Binary3fmt
Unexecuted instantiation: _RNvXs37_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072NtNtCsloNou9alJSK_4core3fmt6Binary3fmt
Unexecuted instantiation: _RNvXsF_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192NtNtCsloNou9alJSK_4core3fmt6Binary3fmt
841
        }
842
843
        // We can't derive because the array might be bigger than 32,
844
        // so we just implement it the same as arrays.
845
        impl $crate::uint::serde::Serialize for $name {
846
            #[inline]
847
0
            fn serialize<S: $crate::uint::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
848
0
                if serializer.is_human_readable() {
849
0
                    let mut hex = [0u8; Self::BYTES * 2];
850
0
                    let bytes = self.to_be_bytes();
851
0
                    $crate::uint::faster_hex::hex_encode(&bytes, &mut hex).expect("The output is exactly twice the size of the input");
852
0
                    let hex_str = unsafe { std::str::from_utf8_unchecked(&hex) };
853
0
                    serializer.serialize_str(hex_str)
854
                } else {
855
                    use $crate::uint::serde::ser::SerializeTuple;
856
0
                    let mut seq = serializer.serialize_tuple(Self::LIMBS)?;
857
0
                    for limb in &self.0 {
858
0
                        seq.serialize_element(limb)?;
859
                    }
860
0
                    seq.end()
861
                }
862
0
            }
Unexecuted instantiation: _RINvXsz_Cs1uXV1nWfJt5_4u128NtB6_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core3ser9Serialize9serializepEB6_
Unexecuted instantiation: _RINvXs1w_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core3ser9Serialize9serializepEB7_
Unexecuted instantiation: _RINvXs2k_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core3ser9Serialize9serializepEB7_
Unexecuted instantiation: _RINvXs38_Cs8KLYHAG7u19_10kaspa_mathNtB7_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core3ser9Serialize9serializepEB7_
Unexecuted instantiation: _RINvXsG_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core3ser9Serialize9serializepEB6_
863
        }
864
865
        impl<'de> $crate::uint::serde::Deserialize<'de> for $name {
866
            #[inline]
867
0
            fn deserialize<D: $crate::uint::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
868
0
                if deserializer.is_human_readable() {
869
0
                    let hex = <std::string::String as $crate::uint::serde::Deserialize>::deserialize(deserializer)?;
870
0
                    Ok(Self::from_hex(&hex).map_err($crate::uint::serde::de::Error::custom)?)
871
                } else {
872
                    use core::{fmt, marker::PhantomData};
873
                    use $crate::uint::serde::de::{Error, SeqAccess, Visitor};
874
                    struct EmptyVisitor(PhantomData<$name>);
875
                    impl<'de> Visitor<'de> for EmptyVisitor {
876
                        type Value = $name;
877
                        #[inline]
878
879
0
                        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
880
0
                            formatter.write_str(concat!("an integer with ", $n_words, " limbs"))
881
0
                        }
Unexecuted instantiation: _RNvXNvXsA_Cs1uXV1nWfJt5_4u128NtB8_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB2_12EmptyVisitorNtBG_7Visitor9expecting
Unexecuted instantiation: _RNvXNvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB2_12EmptyVisitorNtBO_7Visitor9expecting
Unexecuted instantiation: _RNvXNvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB2_12EmptyVisitorNtBO_7Visitor9expecting
Unexecuted instantiation: _RNvXNvXs39_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB2_12EmptyVisitorNtBP_7Visitor9expecting
Unexecuted instantiation: _RNvXNvXsH_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB2_12EmptyVisitorNtBN_7Visitor9expecting
882
883
                        #[inline]
884
0
                        fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
885
0
                            let mut ret = $name::ZERO;
886
0
                            for (i, limb) in ret.0.iter_mut().enumerate() {
887
0
                                *limb = seq.next_element()?.ok_or_else(|| Error::invalid_length(i, &self))?;
Unexecuted instantiation: _RNCINvXNvXsA_Cs1uXV1nWfJt5_4u128NtBb_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB5_12EmptyVisitorNtBJ_7Visitor9visit_seqpE0Bb_
Unexecuted instantiation: _RNCINvXNvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtBc_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB5_12EmptyVisitorNtBR_7Visitor9visit_seqpE0Bc_
Unexecuted instantiation: _RNCINvXNvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtBc_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB5_12EmptyVisitorNtBR_7Visitor9visit_seqpE0Bc_
Unexecuted instantiation: _RNCINvXNvXs39_Cs8KLYHAG7u19_10kaspa_mathNtBc_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB5_12EmptyVisitorNtBS_7Visitor9visit_seqpE0Bc_
Unexecuted instantiation: _RNCINvXNvXsH_Cs8KLYHAG7u19_10kaspa_mathNtBb_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB5_12EmptyVisitorNtBQ_7Visitor9visit_seqpE0Bb_
888
                            }
889
0
                            Ok(ret)
890
0
                        }
Unexecuted instantiation: _RINvXNvXsA_Cs1uXV1nWfJt5_4u128NtB9_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB3_12EmptyVisitorNtBH_7Visitor9visit_seqpEB9_
Unexecuted instantiation: _RINvXNvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtBa_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB3_12EmptyVisitorNtBP_7Visitor9visit_seqpEBa_
Unexecuted instantiation: _RINvXNvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtBa_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB3_12EmptyVisitorNtBP_7Visitor9visit_seqpEBa_
Unexecuted instantiation: _RINvXNvXs39_Cs8KLYHAG7u19_10kaspa_mathNtBa_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB3_12EmptyVisitorNtBQ_7Visitor9visit_seqpEBa_
Unexecuted instantiation: _RINvXNvXsH_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializeNtB3_12EmptyVisitorNtBO_7Visitor9visit_seqpEB9_
891
                    }
892
0
                    deserializer.deserialize_tuple(Self::LIMBS, EmptyVisitor(PhantomData))
893
                }
894
0
            }
Unexecuted instantiation: _RINvXsA_Cs1uXV1nWfJt5_4u128NtB6_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializepEB6_
Unexecuted instantiation: _RINvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializepEB7_
Unexecuted instantiation: _RINvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializepEB7_
Unexecuted instantiation: _RINvXs39_Cs8KLYHAG7u19_10kaspa_mathNtB7_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializepEB7_
Unexecuted instantiation: _RINvXsH_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize11deserializepEB6_
895
896
            #[inline]
897
0
            fn deserialize_in_place<D: $crate::uint::serde::Deserializer<'de>>(
898
0
                deserializer: D,
899
0
                place: &mut Self,
900
0
            ) -> Result<(), D::Error> {
901
0
                if deserializer.is_human_readable() {
902
903
                    use core::fmt;
904
                    use $crate::uint::serde::de::{Error, Visitor};
905
                    struct InPlaceVisitor<'a>(&'a mut $name);
906
907
                    impl<'de, 'a> Visitor<'de> for InPlaceVisitor<'a> {
908
                        type Value = ();
909
                        #[inline]
910
0
                        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
911
0
                            formatter.write_str("a hex string")
912
0
                        }
Unexecuted instantiation: _RNvXNvXsA_Cs1uXV1nWfJt5_4u128NtB8_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB2_14InPlaceVisitorNtBG_7Visitor9expecting
Unexecuted instantiation: _RNvXNvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB2_14InPlaceVisitorNtBO_7Visitor9expecting
Unexecuted instantiation: _RNvXNvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB2_14InPlaceVisitorNtBO_7Visitor9expecting
Unexecuted instantiation: _RNvXNvXs39_Cs8KLYHAG7u19_10kaspa_mathNtB9_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB2_14InPlaceVisitorNtBP_7Visitor9expecting
Unexecuted instantiation: _RNvXNvXsH_Cs8KLYHAG7u19_10kaspa_mathNtB8_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB2_14InPlaceVisitorNtBN_7Visitor9expecting
913
                        #[inline]
914
0
                        fn visit_str<E>(self, hex: &str) -> Result<Self::Value, E>
915
0
                        where
916
0
                            E: Error,
917
                        {
918
0
                            if hex.len() > $name::BYTES * 2 {
919
0
                                return Err($crate::uint::serde::de::Error::custom("invalid hex string length"));
920
0
                            }
921
0
                            let mut bytes = [0u8; $name::BYTES];
922
0
                            let mut input = [b'0'; $name::BYTES * 2];
923
0
                            let start = input.len() - hex.len();
924
0
                            input[start..].copy_from_slice(hex.as_bytes());
925
0
                            $crate::uint::faster_hex::hex_decode(&input, &mut bytes).map_err(Error::custom)?;
926
927
0
                            self.0.0.iter_mut()
928
0
                                .rev()
929
0
                                .zip(bytes.chunks_exact(8))
930
0
                                .for_each(|(word, bytes)| *word = u64::from_be_bytes(bytes.try_into().unwrap()));
Unexecuted instantiation: _RNCINvXNvXsA_Cs1uXV1nWfJt5_4u128NtBb_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_14InPlaceVisitorNtBJ_7Visitor9visit_strpE0Bb_
Unexecuted instantiation: _RNCINvXNvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtBc_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_14InPlaceVisitorNtBR_7Visitor9visit_strpE0Bc_
Unexecuted instantiation: _RNCINvXNvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtBc_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_14InPlaceVisitorNtBR_7Visitor9visit_strpE0Bc_
Unexecuted instantiation: _RNCINvXNvXs39_Cs8KLYHAG7u19_10kaspa_mathNtBc_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_14InPlaceVisitorNtBS_7Visitor9visit_strpE0Bc_
Unexecuted instantiation: _RNCINvXNvXsH_Cs8KLYHAG7u19_10kaspa_mathNtBb_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_14InPlaceVisitorNtBQ_7Visitor9visit_strpE0Bb_
931
932
0
                            Ok(())
933
0
                        }
Unexecuted instantiation: _RINvXNvXsA_Cs1uXV1nWfJt5_4u128NtB9_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB3_14InPlaceVisitorNtBH_7Visitor9visit_strpEB9_
Unexecuted instantiation: _RINvXNvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtBa_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB3_14InPlaceVisitorNtBP_7Visitor9visit_strpEBa_
Unexecuted instantiation: _RINvXNvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtBa_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB3_14InPlaceVisitorNtBP_7Visitor9visit_strpEBa_
Unexecuted instantiation: _RINvXNvXs39_Cs8KLYHAG7u19_10kaspa_mathNtBa_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB3_14InPlaceVisitorNtBQ_7Visitor9visit_strpEBa_
Unexecuted instantiation: _RINvXNvXsH_Cs8KLYHAG7u19_10kaspa_mathNtB9_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB3_14InPlaceVisitorNtBO_7Visitor9visit_strpEB9_
934
                    }
935
0
                    deserializer.deserialize_str(InPlaceVisitor(place))
936
937
                } else {
938
                    use core::fmt;
939
                    use $crate::uint::serde::de::{Error, SeqAccess, Visitor};
940
                    struct InPlaceVisitor<'a>(&'a mut $name);
941
942
                    impl<'de, 'a> Visitor<'de> for InPlaceVisitor<'a> {
943
                        type Value = ();
944
                        #[inline]
945
0
                        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
946
0
                            formatter.write_str(concat!("an integer with ", $n_words, " limbs"))
947
0
                        }
Unexecuted instantiation: _RNvXs_NvXsA_Cs1uXV1nWfJt5_4u128NtBa_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB4_s_14InPlaceVisitorNtBI_7Visitor9expecting
Unexecuted instantiation: _RNvXs_NvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtBb_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB4_s_14InPlaceVisitorNtBQ_7Visitor9expecting
Unexecuted instantiation: _RNvXs_NvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtBb_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB4_s_14InPlaceVisitorNtBQ_7Visitor9expecting
Unexecuted instantiation: _RNvXs_NvXs39_Cs8KLYHAG7u19_10kaspa_mathNtBb_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB4_s_14InPlaceVisitorNtBR_7Visitor9expecting
Unexecuted instantiation: _RNvXs_NvXsH_Cs8KLYHAG7u19_10kaspa_mathNtBa_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB4_s_14InPlaceVisitorNtBP_7Visitor9expecting
948
                        #[inline]
949
0
                        fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
950
0
                            for (idx, dest) in self.0 .0[..].iter_mut().enumerate() {
951
0
                                match seq.next_element()? {
952
0
                                    Some(elem) => *dest = elem,
953
                                    None => {
954
0
                                        return Err(Error::invalid_length(idx, &self));
955
                                    }
956
                                }
957
                            }
958
0
                            Ok(())
959
0
                        }
Unexecuted instantiation: _RINvXs_NvXsA_Cs1uXV1nWfJt5_4u128NtBb_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_s_14InPlaceVisitorNtBJ_7Visitor9visit_seqpEBb_
Unexecuted instantiation: _RINvXs_NvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtBc_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_s_14InPlaceVisitorNtBR_7Visitor9visit_seqpEBc_
Unexecuted instantiation: _RINvXs_NvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtBc_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_s_14InPlaceVisitorNtBR_7Visitor9visit_seqpEBc_
Unexecuted instantiation: _RINvXs_NvXs39_Cs8KLYHAG7u19_10kaspa_mathNtBc_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_s_14InPlaceVisitorNtBS_7Visitor9visit_seqpEBc_
Unexecuted instantiation: _RINvXs_NvXsH_Cs8KLYHAG7u19_10kaspa_mathNtBb_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placeNtB5_s_14InPlaceVisitorNtBQ_7Visitor9visit_seqpEBb_
960
                    }
961
0
                    deserializer.deserialize_tuple(Self::LIMBS, InPlaceVisitor(place))
962
                }
963
0
            }
Unexecuted instantiation: _RINvXsA_Cs1uXV1nWfJt5_4u128NtB6_7Uint128NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placepEB6_
Unexecuted instantiation: _RINvXs1x_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint256NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placepEB7_
Unexecuted instantiation: _RINvXs2l_Cs8KLYHAG7u19_10kaspa_mathNtB7_7Uint320NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placepEB7_
Unexecuted instantiation: _RINvXs39_Cs8KLYHAG7u19_10kaspa_mathNtB7_8Uint3072NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placepEB7_
Unexecuted instantiation: _RINvXsH_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint192NtNtCs3hf9a0Cf7S3_10serde_core2de11Deserialize20deserialize_in_placepEB6_
964
965
        }
966
967
        impl TryFrom<&$name> for $crate::uint::js_sys::BigInt {
968
            type Error = $crate::Error;
969
            #[inline]
970
0
            fn try_from(value: &$name) -> Result<$crate::uint::js_sys::BigInt, Self::Error> {
971
                use $crate::wasm::*;
972
0
                BigInt::new(&JsValue::from_str(&format!("0x{value:x}"))).map_err(|err|$crate::Error::JsSys(Sendable(err)))
Unexecuted instantiation: _RNCNvXsB_Cs1uXV1nWfJt5_4u128NtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB7_7Uint128E8try_from0B7_
Unexecuted instantiation: _RNCNvXs1y_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB8_7Uint256E8try_from0B8_
Unexecuted instantiation: _RNCNvXs2m_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB8_7Uint320E8try_from0B8_
Unexecuted instantiation: _RNCNvXs3a_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB8_8Uint3072E8try_from0B8_
Unexecuted instantiation: _RNCNvXsI_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB7_7Uint192E8try_from0B7_
973
0
            }
Unexecuted instantiation: _RNvXsB_Cs1uXV1nWfJt5_4u128NtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB5_7Uint128E8try_from
Unexecuted instantiation: _RNvXs1y_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB6_7Uint256E8try_from
Unexecuted instantiation: _RNvXs2m_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB6_7Uint320E8try_from
Unexecuted instantiation: _RNvXs3a_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB6_8Uint3072E8try_from
Unexecuted instantiation: _RNvXsI_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromRNtB5_7Uint192E8try_from
974
        }
975
976
        impl TryFrom<$name> for $crate::uint::js_sys::BigInt {
977
            type Error = $crate::Error;
978
            #[inline]
979
0
            fn try_from(value: $name) -> Result<$crate::uint::js_sys::BigInt, Self::Error> {
980
                use $crate::wasm::*;
981
0
                BigInt::try_from(&value)
982
0
            }
Unexecuted instantiation: _RNvXsC_Cs1uXV1nWfJt5_4u128NtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromNtB5_7Uint128E8try_from
Unexecuted instantiation: _RNvXs1z_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromNtB6_7Uint256E8try_from
Unexecuted instantiation: _RNvXs2n_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromNtB6_7Uint320E8try_from
Unexecuted instantiation: _RNvXs3b_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromNtB6_8Uint3072E8try_from
Unexecuted instantiation: _RNvXsJ_Cs8KLYHAG7u19_10kaspa_mathNtCs2VzSvXtaRFf_6js_sys6BigIntINtNtCsloNou9alJSK_4core7convert7TryFromNtB5_7Uint192E8try_from
983
        }
984
985
        impl TryFrom<$crate::uint::wasm_bindgen::JsValue> for $name {
986
            type Error = $crate::Error;
987
0
            fn try_from(js_value: $crate::uint::wasm_bindgen::JsValue) -> Result<Self, Self::Error> {
988
                use $crate::wasm::*;
989
990
0
                if js_value.is_string() || js_value.is_array() {
991
0
                    let bytes = js_value.try_as_vec_u8()?;
992
0
                    Ok(Self::from_be_bytes_var(&bytes)?)
993
0
                } else if js_value.is_bigint() {
994
0
                    let v: &BigInt = js_value.dyn_ref().unwrap();
995
0
                    let hex = String::from(v.to_string(16)?);
996
0
                    Ok(Self::from_hex(hex.as_str())?)
997
                } else {
998
0
                    return Err(Self::Error::NotCompatible);
999
                }
1000
0
            }
Unexecuted instantiation: _RNvXsD_Cs1uXV1nWfJt5_4u128NtB5_7Uint128INtNtCsloNou9alJSK_4core7convert7TryFromNtCseeN0L2AkAf8_12wasm_bindgen7JsValueE8try_from
Unexecuted instantiation: _RNvXs1A_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint256INtNtCsloNou9alJSK_4core7convert7TryFromNtCseeN0L2AkAf8_12wasm_bindgen7JsValueE8try_from
Unexecuted instantiation: _RNvXs2o_Cs8KLYHAG7u19_10kaspa_mathNtB6_7Uint320INtNtCsloNou9alJSK_4core7convert7TryFromNtCseeN0L2AkAf8_12wasm_bindgen7JsValueE8try_from
Unexecuted instantiation: _RNvXs3c_Cs8KLYHAG7u19_10kaspa_mathNtB6_8Uint3072INtNtCsloNou9alJSK_4core7convert7TryFromNtCseeN0L2AkAf8_12wasm_bindgen7JsValueE8try_from
Unexecuted instantiation: _RNvXsK_Cs8KLYHAG7u19_10kaspa_mathNtB5_7Uint192INtNtCsloNou9alJSK_4core7convert7TryFromNtCseeN0L2AkAf8_12wasm_bindgen7JsValueE8try_from
1001
        }
1002
1003
    };
1004
}
1005
1006
/// The error type returned when a checked integral type conversion fails.
1007
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1008
pub struct TryFromIntError;
1009
1010
impl std::error::Error for TryFromIntError {}
1011
1012
impl core::fmt::Display for TryFromIntError {
1013
0
    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1014
0
        "out of range integral type conversion attempted".fmt(fmt)
1015
0
    }
1016
}
1017
1018
impl From<core::convert::Infallible> for TryFromIntError {
1019
    fn from(x: core::convert::Infallible) -> TryFromIntError {
1020
        match x {}
1021
    }
1022
}
1023
1024
/// The error type returned when a slice conversion fails.
1025
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1026
pub struct TryFromSliceError;
1027
1028
impl std::error::Error for TryFromSliceError {}
1029
1030
impl core::fmt::Display for TryFromSliceError {
1031
0
    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1032
0
        "conversion attempted from a slice too large".fmt(fmt)
1033
0
    }
1034
}
1035
1036
impl From<core::convert::Infallible> for TryFromSliceError {
1037
    fn from(x: core::convert::Infallible) -> TryFromSliceError {
1038
        match x {}
1039
    }
1040
}
1041
1042
#[cfg(test)]
1043
mod tests {
1044
    use rand_chacha::{
1045
        ChaCha8Rng,
1046
        rand_core::{RngCore, SeedableRng},
1047
    };
1048
    use std::fmt::Write;
1049
    construct_uint!(Uint128, 2);
1050
1051
    #[test]
1052
    fn test_u128() {
1053
        use core::fmt::Arguments;
1054
        let mut fmt_buf = String::with_capacity(256);
1055
        let mut fmt_buf2 = String::with_capacity(256);
1056
        let mut assert_equal_args = |arg1: Arguments, arg2: Arguments| {
1057
            fmt_buf.clear();
1058
            fmt_buf2.clear();
1059
            fmt_buf.write_fmt(arg1).unwrap();
1060
            fmt_buf2.write_fmt(arg2).unwrap();
1061
            assert_eq!(fmt_buf, fmt_buf2);
1062
        };
1063
        let mut assert_equal = |a: Uint128, b: u128, check_fmt: bool| {
1064
            assert_eq!(a, b);
1065
            assert_eq!(a.to_le_bytes(), b.to_le_bytes());
1066
            if !check_fmt {
1067
                return;
1068
            }
1069
1070
            assert_equal_args(format_args!("{a:}"), format_args!("{b:}"));
1071
            assert_equal_args(format_args!("{a:b}"), format_args!("{b:b}")); // Test Binary
1072
            assert_equal_args(format_args!("{a:#b}"), format_args!("{b:#b}")); // Test Binary with prefix
1073
            assert_equal_args(format_args!("{a:0128b}"), format_args!("{b:0128b}")); // Test binary with length
1074
            assert_equal_args(format_args!("{a:x}"), format_args!("{b:x}")); // Test LowerHex
1075
            assert_equal_args(format_args!("{a:#x}"), format_args!("{b:#x}")); // Test LowerHex with prefix
1076
            // Test LowerHex with padding
1077
            assert_equal_args(format_args!("{a:032x}"), format_args!("{b:032x}"));
1078
        };
1079
        let mut rng = ChaCha8Rng::from_seed([0; 32]);
1080
        let mut buf = [0u8; 16];
1081
        let mut str_buf = String::with_capacity(32);
1082
        for i in 0..80_000 {
1083
            // Checking all the fmt's is quite expensive.
1084
            let check_fmt = i % 8 == 1;
1085
            rng.fill_bytes(&mut buf);
1086
            let mine = Uint128::from_le_bytes(buf);
1087
            let default = u128::from_le_bytes(buf);
1088
            rng.fill_bytes(&mut buf);
1089
            let mine2 = Uint128::from_le_bytes(buf);
1090
            let default2 = u128::from_le_bytes(buf);
1091
            assert_equal(mine, default, check_fmt);
1092
            assert_equal(mine2, default2, check_fmt);
1093
1094
            let mine = mine.overflowing_add(mine2).0.overflowing_mul(mine2).0;
1095
            let default = default.overflowing_add(default2).0.overflowing_mul(default2).0;
1096
            assert_equal(mine, default, check_fmt);
1097
            let shift = rng.next_u32() % 4096;
1098
            {
1099
                let mine_overflow_shl = mine.overflowing_shl(shift);
1100
                let default_overflow_shl = default.overflowing_shl(shift);
1101
                assert_equal(mine_overflow_shl.0, default_overflow_shl.0, check_fmt);
1102
                assert_eq!(mine_overflow_shl.1, default_overflow_shl.1);
1103
            }
1104
            {
1105
                let mine_overflow_shr = mine.overflowing_shl(shift);
1106
                let default_overflow_shr = default.overflowing_shl(shift);
1107
                assert_equal(mine_overflow_shr.0, default_overflow_shr.0, check_fmt);
1108
                assert_eq!(mine_overflow_shr.1, default_overflow_shr.1);
1109
            }
1110
            {
1111
                let mine_divrem = mine.div_rem(mine2);
1112
                let default_divrem = (default / default2, default % default2);
1113
                assert_equal(mine_divrem.0, default_divrem.0, check_fmt);
1114
                assert_equal(mine_divrem.1, default_divrem.1, check_fmt);
1115
            }
1116
            // Test conversion to f64
1117
            {
1118
                let mine_f64 = mine.as_f64();
1119
                let default_f64 = default as f64;
1120
                assert_eq!(mine_f64, default_f64);
1121
            }
1122
            // Test fast u64 division.
1123
            {
1124
                let rand_u64 = rng.next_u64();
1125
                let mine_divrem = mine.div_rem_u64(rand_u64);
1126
                let default_divrem = (default / u128::from(rand_u64), default % u128::from(rand_u64));
1127
                assert_equal(mine_divrem.0, default_divrem.0, check_fmt);
1128
                assert_eq!(mine_divrem.1, u64::try_from(default_divrem.1).unwrap());
1129
            }
1130
            // Test fast u64 multiplication
1131
            {
1132
                let rand_u64 = rng.next_u64();
1133
                let mine_mult = mine.overflowing_mul_u64(rand_u64);
1134
                let default_mult = default.overflowing_mul(rand_u64 as u128);
1135
                assert_equal(mine_mult.0, default_mult.0, check_fmt);
1136
                assert_eq!(mine_mult.1, default_mult.1);
1137
            }
1138
            // Test fast u64 addition
1139
            {
1140
                let rand_u64 = rng.next_u64();
1141
                let mine_add = mine.overflowing_add_u64(rand_u64);
1142
                let default_add = default.overflowing_add(rand_u64 as u128);
1143
                assert_equal(mine_add.0, default_add.0, check_fmt);
1144
                assert_eq!(mine_add.1, default_add.1);
1145
            }
1146
            // Roundtrip Little-Endian bytes conversion
1147
            {
1148
                let mine_le = mine.to_le_bytes();
1149
                let default_le = default.to_le_bytes();
1150
                assert_eq!(mine_le, default_le);
1151
                assert_eq!(mine, Uint128::from_le_bytes(mine_le));
1152
            }
1153
            // Roundtrip Big-Endian bytes conversion
1154
            {
1155
                let mine_le = mine.to_be_bytes();
1156
                let default_le = default.to_be_bytes();
1157
                assert_eq!(mine_le, default_le);
1158
                assert_eq!(mine, Uint128::from_be_bytes(mine_le));
1159
            }
1160
            // Roundtrip hex
1161
            if check_fmt {
1162
                str_buf.clear();
1163
                str_buf.write_fmt(format_args!("{mine:032x}")).unwrap();
1164
                assert_eq!(mine, Uint128::from_hex(&str_buf).unwrap());
1165
            }
1166
        }
1167
    }
1168
1169
    #[test]
1170
    fn test_saturating_ops() {
1171
        let u1 = Uint128::from_u128(u128::MAX);
1172
        let u2 = Uint128::from_u64(u64::MAX);
1173
        // Sub
1174
        assert_eq!(u1.saturating_sub(u2), Uint128::from_u128(u128::MAX - u64::MAX as u128));
1175
        assert_eq!(u1.saturating_sub(u2).as_u128(), u128::MAX - u64::MAX as u128);
1176
        assert_eq!(u2.saturating_sub(u1), Uint128::ZERO);
1177
        // Add
1178
        assert_eq!(u1.saturating_add(Uint128::from_u64(1)), Uint128::MAX);
1179
        assert_eq!(u2.saturating_add(Uint128::from_u64(1)), Uint128::from_u128(u64::MAX as u128 + 1));
1180
    }
1181
1182
    // `test_mod_inv` is commented out: it exercised the generic `mod_inverse` (Uint128), which was
1183
    // removed along with the malachite-backed implementation. The only production inverse is the
1184
    // 3072-bit MuHash case, now covered by the `lehmer.rs` unit tests (bit-for-bit vs malachite +
1185
    // `v * inv == 1` self-check) and the `math/fuzz` `u3072` target. Kept here for history.
1186
    /*
1187
    #[test]
1188
    fn test_mod_inv() {
1189
        use core::cmp::Ordering;
1190
        let mut rng = ChaCha8Rng::from_seed([0; 32]);
1191
        let mut buf = [0u8; 16];
1192
        for _ in 0..50_000 {
1193
            rng.fill_bytes(&mut buf);
1194
            let uint1 = Uint128::from_le_bytes(buf);
1195
            rng.fill_bytes(&mut buf);
1196
            let uint2 = Uint128::from_le_bytes(buf);
1197
            let (bigger, smaller) = match uint1.cmp(&uint2) {
1198
                Ordering::Greater => (uint1, uint2),
1199
                Ordering::Less => (uint2, uint1),
1200
                Ordering::Equal => continue,
1201
            };
1202
            let inv = smaller.mod_inverse(bigger);
1203
            if let Some(inv) = inv {
1204
                assert_eq!(prod_bin(inv, smaller, bigger), 1u64);
1205
            }
1206
        }
1207
1208
        fn sum(x: Uint128, y: Uint128, m: Uint128) -> Uint128 {
1209
            let res = x.overflowing_add(y).0;
1210
            if res < x || res >= m { res.overflowing_sub(m).0 } else { res }
1211
        }
1212
        fn prod_bin(x: Uint128, y: Uint128, m: Uint128) -> Uint128 {
1213
            if y == 1u64 {
1214
                return x;
1215
            } else if y == 0u64 {
1216
                return Uint128::ZERO;
1217
            }
1218
            let mut res = prod_bin(x, y >> 1, m);
1219
            res = sum(res, res, m);
1220
            if (y.as_u64() & 1) == 1 {
1221
                res = sum(res, x, m);
1222
            }
1223
            res
1224
        }
1225
    }
1226
    */
1227
}
/root/kaspa/kaspa-fuzz/rusty-kaspa/math/src/int.rs
Line
Count
Source
1
use core::fmt::{self, Display};
2
use core::ops::{Add, Div, Mul, Sub};
3
4
#[derive(Copy, Clone, Debug)]
5
pub struct SignedInteger<T> {
6
    abs: T,
7
    negative: bool,
8
}
9
10
impl<T> From<T> for SignedInteger<T> {
11
    #[inline]
12
0
    fn from(u: T) -> Self {
13
0
        Self { abs: u, negative: false }
14
0
    }
15
}
16
impl<T: From<u64>> SignedInteger<T> {
17
    #[inline]
18
0
    pub fn positive_u64(u: u64) -> Self {
19
0
        Self { abs: T::from(u), negative: false }
20
0
    }
21
}
22
23
impl<T: Display> Display for SignedInteger<T> {
24
    #[inline]
25
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26
0
        if self.negative {
27
0
            write!(f, "-")?;
28
0
        }
29
0
        write!(f, "{}", self.abs)
30
0
    }
31
}
32
33
impl<T: Copy> SignedInteger<T> {
34
    #[inline]
35
0
    pub const fn abs(&self) -> T {
36
0
        self.abs
37
0
    }
38
39
    #[inline]
40
0
    pub const fn negative(&self) -> bool {
41
0
        self.negative
42
0
    }
43
}
44
45
impl<T: Sub<Output = T> + Add<Output = T> + Ord> Sub for SignedInteger<T> {
46
    type Output = Self;
47
    #[inline]
48
    #[track_caller]
49
0
    fn sub(self, other: Self) -> Self::Output {
50
0
        match (self.negative, other.negative) {
51
            (false, false) | (true, true) => {
52
0
                if self.abs < other.abs {
53
0
                    Self { negative: !self.negative, abs: other.abs - self.abs }
54
                } else {
55
0
                    Self { negative: self.negative, abs: self.abs - other.abs }
56
                }
57
            }
58
0
            (false, true) | (true, false) => Self { negative: self.negative, abs: self.abs + other.abs },
59
        }
60
0
    }
61
}
62
63
impl<T: Mul<Output = T>> Mul for SignedInteger<T> {
64
    type Output = Self;
65
    #[inline]
66
    #[track_caller]
67
0
    fn mul(self, rhs: Self) -> Self::Output {
68
0
        Self { negative: self.negative ^ rhs.negative, abs: self.abs * rhs.abs }
69
0
    }
70
}
71
72
impl<T: Div<Output = T>> Div for SignedInteger<T> {
73
    type Output = Self;
74
    #[inline]
75
    #[track_caller]
76
0
    fn div(self, rhs: Self) -> Self::Output {
77
0
        Self { negative: self.negative ^ rhs.negative, abs: self.abs / rhs.abs }
78
0
    }
79
}
80
81
impl<T: PartialEq + PartialEq<u64>> PartialEq for SignedInteger<T> {
82
0
    fn eq(&self, other: &Self) -> bool {
83
0
        if self.abs == 0 && other.abs == 0 {
84
            // neg/pos zeros are considered equal
85
0
            return true;
86
0
        }
87
0
        self.negative == other.negative && self.abs == other.abs
88
0
    }
89
}
90
91
impl<T: PartialEq + PartialEq<u64>> Eq for SignedInteger<T> {}
92
93
impl<T: PartialOrd + PartialEq<u64>> PartialOrd for SignedInteger<T> {
94
0
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
95
0
        if self.abs == 0 && other.abs == 0 {
96
            // neg/pos zeros are considered equal
97
0
            return Some(std::cmp::Ordering::Equal);
98
0
        }
99
0
        match (self.negative, other.negative) {
100
0
            (false, false) => self.abs.partial_cmp(&other.abs),
101
0
            (true, true) => other.abs.partial_cmp(&self.abs),
102
0
            (true, false) => Some(std::cmp::Ordering::Less),
103
0
            (false, true) => Some(std::cmp::Ordering::Greater),
104
        }
105
0
    }
106
}
107
108
#[cfg(test)]
109
mod tests {
110
    use crate::{Uint192, int::SignedInteger};
111
112
    fn from_u64(val: u64) -> SignedInteger<Uint192> {
113
        SignedInteger::from(Uint192::from_u64(val))
114
    }
115
116
    #[test]
117
    fn test_partial_eq() {
118
        assert_eq!(from_u64(0), SignedInteger::from(Uint192::ZERO));
119
        assert_eq!(from_u64(0), from_u64(10) - from_u64(10));
120
        assert_eq!(from_u64(0), from_u64(10) - from_u64(20) - from_u64(10) * (from_u64(0) - from_u64(1))); // 0 == 10 - 20 -(-10)
121
        assert_eq!(from_u64(0) - from_u64(1000), from_u64(0) - from_u64(1000)); // -1000 = -1000
122
        assert_eq!(from_u64(1000), from_u64(1000));
123
    }
124
125
    #[test]
126
    fn test_partial_cmp() {
127
        // Test cases related to 0 and equality
128
        assert!(from_u64(0) >= from_u64(10) - from_u64(20) - from_u64(10) * (from_u64(0) - from_u64(1))); // pos 0 >= neg 0
129
        assert!(from_u64(0) <= from_u64(10) - from_u64(20) - from_u64(10) * (from_u64(0) - from_u64(1))); // pos 0 <= neg 0
130
131
        // Test all possible neg/pos combinations
132
        assert!(from_u64(100) > from_u64(0) - from_u64(1000)); // pos > neg
133
        assert!(from_u64(0) - from_u64(100) < from_u64(10)); // neg < pos
134
        assert!(from_u64(0) - from_u64(1000) < from_u64(0) - from_u64(100)); // -1000 < -100
135
        assert!(from_u64(0) - from_u64(1000) <= from_u64(0) - from_u64(1000)); // -1000 <= -1000
136
        assert!(from_u64(0) - from_u64(1000) >= from_u64(0) - from_u64(1000)); // -1000 >= -1000
137
        assert!(from_u64(1000) > from_u64(100));
138
        assert!(from_u64(100) < from_u64(1000));
139
        assert!(from_u64(1000) >= from_u64(1000));
140
        assert!(from_u64(100) <= from_u64(100));
141
    }
142
}
/root/kaspa/kaspa-fuzz/rusty-kaspa/math/src/lib.rs
Line
Count
Source
1
use borsh::{BorshDeserialize, BorshSerialize};
2
use wasm_bindgen::JsValue;
3
use workflow_core::sendable::Sendable;
4
5
pub mod int;
6
pub mod lehmer;
7
pub mod uint;
8
pub mod wasm;
9
10
construct_uint!(Uint192, 3, BorshSerialize, BorshDeserialize);
11
construct_uint!(Uint256, 4);
12
construct_uint!(Uint320, 5);
13
construct_uint!(Uint3072, 48);
14
15
/// Returns the ceiling of the base-2 logarithm of `x`, i.e. the smallest `k` such that `2^k >= x`.
16
/// If `x` is 0, returns 0.
17
#[inline]
18
0
pub const fn ceil_log_2(x: u64) -> u64 {
19
0
    (u64::BITS - x.saturating_sub(1).leading_zeros()) as u64
20
0
}
21
22
#[derive(thiserror::Error, Debug)]
23
pub enum Error {
24
    #[error("{0:?}")]
25
    JsValue(Sendable<JsValue>),
26
27
    #[error("Invalid hex string: {0}")]
28
    Hex(#[from] faster_hex::Error),
29
30
    #[error(transparent)]
31
    TryFromSliceError(#[from] uint::TryFromSliceError),
32
    // TryFromSliceError(#[from] std::array::TryFromSliceError),
33
    #[error("Utf8 error: {0}")]
34
    Utf8(#[from] std::str::Utf8Error),
35
36
    #[error(transparent)]
37
    WorkflowWasm(#[from] workflow_wasm::error::Error),
38
39
    #[error(transparent)]
40
    SerdeWasmBindgen(#[from] serde_wasm_bindgen::Error),
41
42
    #[error("{0:?}")]
43
    JsSys(Sendable<js_sys::Error>),
44
45
    #[error("Supplied value is not compatible with this type")]
46
    NotCompatible,
47
48
    #[error("range error: {0:?}")]
49
    Range(Sendable<js_sys::RangeError>),
50
}
51
52
impl From<js_sys::Error> for Error {
53
0
    fn from(err: js_sys::Error) -> Self {
54
0
        Error::JsSys(Sendable(err))
55
0
    }
56
}
57
58
impl From<js_sys::RangeError> for Error {
59
0
    fn from(err: js_sys::RangeError) -> Self {
60
0
        Error::Range(Sendable(err))
61
0
    }
62
}
63
64
impl From<JsValue> for Error {
65
0
    fn from(err: JsValue) -> Self {
66
0
        Error::JsValue(Sendable(err))
67
0
    }
68
}
69
70
impl Uint256 {
71
    #[inline]
72
0
    pub fn from_compact_target_bits(bits: u32) -> Self {
73
        // This is a floating-point "compact" encoding originally used by
74
        // OpenSSL, which satoshi put into consensus code, so we're stuck
75
        // with it. The exponent needs to have 3 subtracted from it, hence
76
        // this goofy decoding code:
77
0
        let (mant, expt) = {
78
0
            let unshifted_expt = bits >> 24;
79
0
            if unshifted_expt <= 3 {
80
0
                ((bits & 0xFFFFFF) >> (8 * (3 - unshifted_expt)), 0)
81
            } else {
82
0
                (bits & 0xFFFFFF, 8 * ((bits >> 24) - 3))
83
            }
84
        };
85
        // The mantissa is signed but may not be negative
86
0
        if mant > 0x7FFFFF { Uint256::ZERO } else { Uint256::from_u64(u64::from(mant)) << expt }
87
0
    }
88
89
    #[inline]
90
    /// Computes the target value in float format from BigInt format.
91
0
    pub fn compact_target_bits(self) -> u32 {
92
0
        let mut size = self.bits().div_ceil(8);
93
0
        let mut compact = if size <= 3 {
94
0
            (self.as_u64() << (8 * (3 - size))) as u32
95
        } else {
96
0
            let bn = self >> (8 * (size - 3));
97
0
            bn.as_u64() as u32
98
        };
99
100
0
        if (compact & 0x00800000) != 0 {
101
0
            compact >>= 8;
102
0
            size += 1;
103
0
        }
104
0
        compact | (size << 24)
105
0
    }
106
}
107
108
impl From<Uint256> for Uint320 {
109
    #[inline]
110
0
    fn from(u: Uint256) -> Self {
111
0
        let mut result = Uint320::ZERO;
112
0
        result.0[..4].copy_from_slice(&u.0);
113
0
        result
114
0
    }
115
}
116
117
impl TryFrom<Uint320> for Uint256 {
118
    type Error = crate::uint::TryFromIntError;
119
120
    #[inline]
121
0
    fn try_from(value: Uint320) -> Result<Self, Self::Error> {
122
0
        if value.0[4] != 0 {
123
0
            Err(crate::uint::TryFromIntError)
124
        } else {
125
0
            let mut result = Uint256::ZERO;
126
0
            result.0.copy_from_slice(&value.0[..4]);
127
0
            Ok(result)
128
        }
129
0
    }
130
}
131
132
impl TryFrom<Uint256> for Uint192 {
133
    type Error = crate::uint::TryFromIntError;
134
135
    #[inline]
136
0
    fn try_from(value: Uint256) -> Result<Self, Self::Error> {
137
0
        if value.0[3] != 0 {
138
0
            Err(crate::uint::TryFromIntError)
139
        } else {
140
0
            let mut result = Uint192::ZERO;
141
0
            result.0.copy_from_slice(&value.0[..3]);
142
0
            Ok(result)
143
        }
144
0
    }
145
}
146
147
#[cfg(test)]
148
mod tests {
149
    use crate::{Uint256, Uint3072};
150
151
    #[test]
152
    fn test_overflow_bug() {
153
        let a = Uint256::from_le_bytes([
154
            255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
155
            255, 255,
156
        ]);
157
        let b = Uint256::from_le_bytes([
158
            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 71, 33, 0, 0, 0, 0, 0, 0,
159
            0, 32, 0, 0, 0,
160
        ]);
161
        let c = a.overflowing_add(b).0;
162
        let expected = [254, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 71, 33, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0];
163
        assert_eq!(c.to_le_bytes(), expected);
164
    }
165
    #[rustfmt::skip]
166
    #[test]
167
    fn div_rem_u3072_bug() {
168
        let r = Uint3072([
169
            18446744073708447899, 18446744069733351423, 18446744073709551615, 18446744073709551615,
170
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
171
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
172
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
173
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
174
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
175
            18446744073709551615, 18446744073642442751, 18446744073709551615, 18446744073709551615,
176
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
177
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
178
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
179
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
180
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
181
        ]);
182
        let newr = Uint3072([
183
            0, 3976200192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
184
            0, 67108864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
185
        ]);
186
        let expected = Uint3072([
187
            18446744073709551614, 18446744073709551615, 18446744073709551615, 18446744073709551615,
188
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
189
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
190
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
191
            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
192
            18446744073709551615, 18446744073709551615, 274877906943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
193
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194
        ]);
195
        assert_eq!(r / newr, expected);
196
    }
197
}
198
199
#[cfg(test)]
200
mod ceil_log_2_tests {
201
    use crate::ceil_log_2;
202
203
    /// Independent reference: the smallest `k` such that `2^k >= x`. Computed in `u128` so it
204
    /// stays correct for `x` near `u64::MAX` (where the answer is 64). Returns 0 if `x` is 0.
205
    fn oracle(x: u64) -> u64 {
206
        if x == 0 {
207
            return 0;
208
        }
209
        let mut k = 0u64;
210
        while (1u128 << k) < x as u128 {
211
            k += 1;
212
        }
213
        k
214
    }
215
216
    /// A spread of inputs exercising the dense low range, every power-of-2 boundary, and the top.
217
    fn sample_inputs() -> impl Iterator<Item = u64> {
218
        let dense = 0..=8192u64;
219
        let boundaries = (0..64u32).flat_map(|k| {
220
            let p = 1u64 << k;
221
            // p-1 (clamped away from negative), p, p+1
222
            [p.saturating_sub(1), p, p + 1]
223
        });
224
        dense.chain(boundaries).chain([u64::MAX])
225
    }
226
227
    #[test]
228
    fn known_values() {
229
        for (x, expected) in [
230
            (0u64, 0u64),
231
            (1, 0),
232
            (2, 1),
233
            (3, 2),
234
            (4, 2),
235
            (5, 3),
236
            (7, 3),
237
            (8, 3),
238
            (9, 4),
239
            (1023, 10),
240
            (1024, 10),
241
            (1025, 11),
242
            (1u64 << 63, 63),
243
            ((1u64 << 63) + 1, 64),
244
            (u64::MAX, 64),
245
        ] {
246
            assert_eq!(ceil_log_2(x), expected, "ceil_log_2({x})");
247
        }
248
    }
249
250
    #[test]
251
    fn correctness_matches_oracle() {
252
        for x in sample_inputs() {
253
            assert_eq!(ceil_log_2(x), oracle(x), "x={x}");
254
        }
255
    }
256
257
    #[test]
258
    fn compatibility_matches_malachite() {
259
        // Direct equivalence with the malachite `CeilingLogBase2` this replaced. malachite is a
260
        // dev-dependency only (the oracle); permanent coverage is `correctness_matches_oracle`.
261
        // Skip x=0 since malachite panics on it; our implementation intentionally returns 0.
262
        use malachite_base::num::arithmetic::traits::CeilingLogBase2;
263
        for x in sample_inputs() {
264
            if x != 0 {
265
                assert_eq!(ceil_log_2(x), x.ceiling_log_base_2(), "x={x}");
266
            }
267
        }
268
    }
269
}