use super::gcd::bingcd_step;
use crate::modular::bingcd::matrix::{DividedIntMatrix, DividedPatternMatrix, PatternMatrix, Unit};
use crate::primitives::u32_max;
use crate::{Choice, Int, Limb, NonZeroUint, Odd, OddUint, U64, U128, Uint, Word};
#[inline(always)]
const fn binxgcd_step<const LIMBS: usize, const MATRIX_LIMBS: usize>(
a: &mut Uint<LIMBS>,
b: &mut Uint<LIMBS>,
matrix: &mut DividedPatternMatrix<MATRIX_LIMBS>,
halt_at_zero: Choice,
) -> Word {
let (a_odd, swap, j) = bingcd_step(a, b);
matrix.conditional_swap_rows(swap);
matrix.conditional_subtract_bottom_row_from_top(a_odd);
matrix.conditional_double_bottom_row(a.is_nonzero().or(halt_at_zero.not()));
j
}
pub(crate) struct RawXgcdOutput<const LIMBS: usize, MATRIX> {
gcd: OddUint<LIMBS>,
matrix: MATRIX,
}
pub(crate) type DividedPatternXgcdOutput<const LIMBS: usize> =
RawXgcdOutput<LIMBS, DividedPatternMatrix<LIMBS>>;
impl<const LIMBS: usize> DividedPatternXgcdOutput<LIMBS> {
pub(crate) const fn divide(self) -> PatternXgcdOutput<LIMBS> {
let DividedPatternMatrix {
inner: mut matrix,
k,
k_upper_bound,
..
} = self.matrix;
let PatternMatrix {
m00: x,
m01: y,
m10: rhs_div_gcd,
m11: lhs_div_gcd,
..
} = &mut matrix;
if k_upper_bound > 0 {
*x = x.bounded_div2k_mod_q(
k,
k_upper_bound,
&rhs_div_gcd.to_odd().expect_copied("odd by construction"),
);
*y = y.bounded_div2k_mod_q(
k,
k_upper_bound,
&lhs_div_gcd.to_odd().expect_copied("odd by construction"),
);
}
PatternXgcdOutput {
gcd: self.gcd,
matrix,
}
}
}
pub(crate) type PatternXgcdOutput<const LIMBS: usize> = RawXgcdOutput<LIMBS, PatternMatrix<LIMBS>>;
impl<const LIMBS: usize> PatternXgcdOutput<LIMBS> {
pub(crate) const fn gcd(&self) -> OddUint<LIMBS> {
self.gcd
}
pub(crate) const fn bezout_coefficients(&self) -> (Int<LIMBS>, Int<LIMBS>) {
let PatternMatrix {
m00,
m01,
m10,
m11,
pattern,
..
} = self.matrix;
let m10_sub_m00 = m10.wrapping_sub(&m00);
let m11_sub_m01 = m11.wrapping_sub(&m01);
let apply = Uint::lte(&m10_sub_m00, &m00).and(Uint::lte(&m11_sub_m01, &m01));
let m00 = *Uint::select(&m00, &m10_sub_m00, apply)
.wrapping_neg_if(apply.xor(pattern.not()))
.as_int();
let m01 = *Uint::select(&m01, &m11_sub_m01, apply)
.wrapping_neg_if(apply.xor(pattern))
.as_int();
(m00, m01)
}
pub(crate) const fn quotients(&self) -> (Uint<LIMBS>, Uint<LIMBS>) {
let PatternMatrix {
m10: rhs_div_gcd,
m11: lhs_div_gcd,
..
} = self.matrix;
(lhs_div_gcd, rhs_div_gcd)
}
}
const SUMMARY_BITS: u32 = U64::BITS - 1;
const SUMMARY_LIMBS: usize = U64::LIMBS;
const DOUBLE_SUMMARY_LIMBS: usize = U128::LIMBS;
impl<const LIMBS: usize> OddUint<LIMBS> {
const MIN_BINXGCD_ITERATIONS: u32 = 2 * Self::BITS - 1;
pub(crate) const fn binxgcd_nz(&self, rhs: &NonZeroUint<LIMBS>) -> PatternXgcdOutput<LIMBS> {
let (lhs_, rhs_) = (self.as_ref(), rhs.as_ref());
let rhs_is_even = rhs_.is_odd().not();
let (abs_diff, rhs_gt_lhs) = lhs_.abs_diff(rhs_);
let odd_rhs = Odd(Uint::select(rhs_, &abs_diff, rhs_is_even));
let mut output = self.binxgcd_odd(&odd_rhs);
let matrix = &mut output.matrix;
let case_one = rhs_is_even.and(rhs_gt_lhs);
matrix.conditional_subtract_right_column_from_left(case_one);
let case_two = rhs_is_even.and(rhs_gt_lhs.not());
matrix.conditional_add_right_column_to_left(case_two);
matrix.conditional_negate(case_two);
output
}
#[inline]
pub(crate) const fn binxgcd_odd(&self, rhs: &Self) -> PatternXgcdOutput<LIMBS> {
if LIMBS < 4 {
self.classic_binxgcd(rhs).divide()
} else {
self.optimized_binxgcd(rhs).divide()
}
}
pub(crate) const fn classic_binxgcd(&self, rhs: &Self) -> DividedPatternXgcdOutput<LIMBS> {
let (gcd, _, matrix, _) =
self.partial_binxgcd::<LIMBS>(rhs.as_ref(), Self::MIN_BINXGCD_ITERATIONS, Choice::TRUE);
DividedPatternXgcdOutput { gcd, matrix }
}
pub(crate) const fn optimized_binxgcd(&self, rhs: &Self) -> DividedPatternXgcdOutput<LIMBS> {
assert!(Self::BITS >= U128::BITS);
self.optimized_binxgcd_::<SUMMARY_BITS, SUMMARY_LIMBS, DOUBLE_SUMMARY_LIMBS>(rhs)
}
pub(crate) const fn optimized_binxgcd_<
const K: u32,
const LIMBS_K: usize,
const LIMBS_2K: usize,
>(
&self,
rhs: &Self,
) -> DividedPatternXgcdOutput<LIMBS> {
let (mut a, mut b) = (*self.as_ref(), *rhs.as_ref());
let mut state = DividedIntMatrix::UNIT;
let (mut a_is_negative, mut b_is_negative);
let mut i = 0;
while i < Self::MIN_BINXGCD_ITERATIONS.div_ceil(K - 1) {
i += 1;
let b_bits = b.bits();
let n = u32_max(2 * K, u32_max(a.bits(), b_bits));
let compact_a = a.compact::<K, LIMBS_2K>(n);
let compact_b = b.compact::<K, LIMBS_2K>(n);
let b_eq_compact_b =
Choice::from_u32_le(b_bits, K - 1).or(Choice::from_u32_eq(n, 2 * K));
let (.., update_matrix, _) = compact_a
.to_odd()
.expect_copied("a is always odd")
.partial_binxgcd::<LIMBS_K>(&compact_b, K - 1, b_eq_compact_b);
let (updated_a, updated_b) = update_matrix.extended_apply_to::<LIMBS, K>((a, b));
(a, a_is_negative) = updated_a.dropped_abs_sign();
(b, b_is_negative) = updated_b.dropped_abs_sign();
state = update_matrix.mul_int_matrix(&state);
state.conditional_negate_top_row(a_is_negative);
state.conditional_negate_bottom_row(b_is_negative);
}
let gcd = a
.to_odd()
.expect_copied("gcd of an odd value with something else is always odd");
let matrix = state.to_divided_pattern_matrix();
DividedPatternXgcdOutput { gcd, matrix }
}
#[inline(always)]
pub(super) const fn partial_binxgcd<const UPDATE_LIMBS: usize>(
&self,
rhs: &Uint<LIMBS>,
iterations: u32,
halt_at_zero: Choice,
) -> (Self, Uint<LIMBS>, DividedPatternMatrix<UPDATE_LIMBS>, Word) {
let (mut a, mut b) = (*self.as_ref(), *rhs);
let mut matrix = DividedPatternMatrix::UNIT;
Uint::swap(&mut a, &mut b);
matrix.swap_rows();
let mut jacobi_neg = 0;
let mut i = 0;
while i < iterations {
jacobi_neg ^=
binxgcd_step::<LIMBS, UPDATE_LIMBS>(&mut a, &mut b, &mut matrix, halt_at_zero);
i += 1;
}
Uint::swap(&mut a, &mut b);
matrix.swap_rows();
let a = a.to_odd().expect_copied("a is always odd");
(a, b, matrix, jacobi_neg)
}
}
impl<const LIMBS: usize> Uint<LIMBS> {
const fn abs_diff(&self, rhs: &Self) -> (Self, Choice) {
let (diff, borrow) = self.borrowing_sub(rhs, Limb::ZERO);
let rhs_gt_self = borrow.is_nonzero();
let abs_diff = diff.wrapping_neg_if(rhs_gt_self);
(abs_diff, rhs_gt_self)
}
}
#[cfg(all(test, not(miri)))]
mod tests {
use crate::modular::bingcd::xgcd::PatternXgcdOutput;
use crate::{Concat, Uint};
use core::ops::Div;
mod test_extract_quotients {
use crate::modular::bingcd::matrix::DividedPatternMatrix;
use crate::modular::bingcd::xgcd::{DividedPatternXgcdOutput, RawXgcdOutput};
use crate::{Choice, U64, Uint};
fn raw_binxgcdoutput_setup<const LIMBS: usize>(
matrix: DividedPatternMatrix<LIMBS>,
) -> DividedPatternXgcdOutput<LIMBS> {
RawXgcdOutput {
gcd: Uint::<LIMBS>::ONE.to_odd().unwrap(),
matrix,
}
}
#[test]
fn test_extract_quotients_unit() {
let output =
raw_binxgcdoutput_setup(DividedPatternMatrix::<{ U64::LIMBS }>::UNIT).divide();
let (lhs_on_gcd, rhs_on_gcd) = output.quotients();
assert_eq!(lhs_on_gcd, Uint::ONE);
assert_eq!(rhs_on_gcd, Uint::ZERO);
}
#[test]
fn test_extract_quotients_basic() {
let output = raw_binxgcdoutput_setup(DividedPatternMatrix::<{ U64::LIMBS }>::new_u64(
(0, 0, 5, 7),
Choice::FALSE,
0,
0,
))
.divide();
let (lhs_on_gcd, rhs_on_gcd) = output.quotients();
assert_eq!(lhs_on_gcd, Uint::from(7u32));
assert_eq!(rhs_on_gcd, Uint::from(5u32));
let output = raw_binxgcdoutput_setup(DividedPatternMatrix::<{ U64::LIMBS }>::new_u64(
(0, 0, 7u64, 5u64),
Choice::TRUE,
0,
0,
))
.divide();
let (lhs_on_gcd, rhs_on_gcd) = output.quotients();
assert_eq!(lhs_on_gcd, Uint::from(5u32));
assert_eq!(rhs_on_gcd, Uint::from(7u32));
}
}
mod test_derive_bezout_coefficients {
use crate::modular::bingcd::matrix::DividedPatternMatrix;
use crate::modular::bingcd::xgcd::RawXgcdOutput;
use crate::{Choice, Int, U64, Uint};
#[test]
fn test_derive_bezout_coefficients_unit() {
let output = RawXgcdOutput {
gcd: Uint::ONE.to_odd().unwrap(),
matrix: DividedPatternMatrix::<{ U64::LIMBS }>::UNIT,
}
.divide();
let (x, y) = output.bezout_coefficients();
assert_eq!(x, Int::ONE);
assert_eq!(y, Int::ZERO);
}
#[test]
fn test_derive_bezout_coefficients_basic() {
let output = RawXgcdOutput {
gcd: U64::ONE.to_odd().unwrap(),
matrix: DividedPatternMatrix::new_u64((2u64, 3u64, 5u64, 5u64), Choice::TRUE, 0, 0),
}
.divide();
let (x, y) = output.bezout_coefficients();
assert_eq!(x, Int::from(2i32));
assert_eq!(y, Int::from(-3i32));
let output = RawXgcdOutput {
gcd: U64::ONE.to_odd().unwrap(),
matrix: DividedPatternMatrix::new_u64(
(2u64, 3u64, 3u64, 5u64),
Choice::FALSE,
0,
1,
),
}
.divide();
let (x, y) = output.bezout_coefficients();
assert_eq!(x, Int::from(1i32));
assert_eq!(y, Int::from(-2i32));
}
#[test]
fn test_derive_bezout_coefficients_removes_doublings_easy() {
let output = RawXgcdOutput {
gcd: U64::ONE.to_odd().unwrap(),
matrix: DividedPatternMatrix::new_u64((2u64, 6u64, 3u64, 5u64), Choice::TRUE, 1, 1),
}
.divide();
let (x, y) = output.bezout_coefficients();
assert_eq!(x, Int::ONE);
assert_eq!(y, Int::from(-3i32));
let output = RawXgcdOutput {
gcd: U64::ONE.to_odd().unwrap(),
matrix: DividedPatternMatrix::new_u64(
(120u64, 64u64, 7u64, 5u64),
Choice::FALSE,
5,
6,
),
}
.divide();
let (x, y) = output.bezout_coefficients();
assert_eq!(x, Int::from(-9i32));
assert_eq!(y, Int::from(2i32));
}
#[test]
fn test_derive_bezout_coefficients_removes_doublings_for_odd_numbers() {
let output = RawXgcdOutput {
gcd: U64::ONE.to_odd().unwrap(),
matrix: DividedPatternMatrix::new_u64(
(2u64, 6u64, 7u64, 5u64),
Choice::FALSE,
3,
7,
),
}
.divide();
let (x, y) = output.bezout_coefficients();
assert_eq!(x, Int::from(-2i32));
assert_eq!(y, Int::from(2i32));
}
}
mod test_partial_binxgcd {
use crate::modular::bingcd::matrix::DividedPatternMatrix;
use crate::{Choice, Gcd, Odd, U64};
const A: Odd<U64> = Odd::from_be_hex("CA048AFA63CD6A1F");
const B: U64 = U64::from_be_hex("AE693BF7BE8E5566");
#[test]
fn test_partial_binxgcd() {
let (.., matrix, _) = A.partial_binxgcd::<{ U64::LIMBS }>(&B, 5, Choice::TRUE);
assert_eq!(matrix.k, 5);
assert_eq!(
matrix,
DividedPatternMatrix::new_u64((8u64, 4u64, 2u64, 5u64), Choice::TRUE, 5, 5)
);
}
#[test]
fn test_partial_binxgcd_constructs_correct_matrix() {
let target_a = U64::from_be_hex("1CB3FB3FA1218FDB").to_odd().unwrap();
let target_b = U64::from_be_hex("0EA028AF0F8966B6");
let (new_a, new_b, matrix, _) =
A.partial_binxgcd::<{ U64::LIMBS }>(&B, 5, Choice::TRUE);
assert_eq!(new_a, target_a);
assert_eq!(new_b, target_b);
let (computed_a, computed_b) =
matrix.extended_apply_to::<{ U64::LIMBS }, 6>((A.get(), B));
let computed_a = computed_a.dropped_abs_sign().0;
let computed_b = computed_b.dropped_abs_sign().0;
assert_eq!(computed_a, target_a);
assert_eq!(computed_b, target_b);
}
const SMALL_A: Odd<U64> = Odd::from_be_hex("0000000003CD6A1F");
const SMALL_B: U64 = U64::from_be_hex("000000000E8E5566");
#[test]
fn test_partial_binxgcd_halts() {
let (gcd, _, matrix, _) =
SMALL_A.partial_binxgcd::<{ U64::LIMBS }>(&SMALL_B, 60, Choice::TRUE);
assert_eq!(matrix.k, 35);
assert_eq!(matrix.k_upper_bound, 60);
assert_eq!(gcd.get(), SMALL_A.gcd(&SMALL_B));
}
#[test]
fn test_partial_binxgcd_does_not_halt() {
let (gcd, .., matrix, _) =
SMALL_A.partial_binxgcd::<{ U64::LIMBS }>(&SMALL_B, 60, Choice::FALSE);
assert_eq!(matrix.k, 60);
assert_eq!(matrix.k_upper_bound, 60);
assert_eq!(gcd.get(), SMALL_A.gcd(&SMALL_B));
}
}
fn test_xgcd<const LIMBS: usize, const DOUBLE: usize>(
lhs: Uint<LIMBS>,
rhs: Uint<LIMBS>,
output: PatternXgcdOutput<LIMBS>,
) where
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
{
assert_eq!(lhs.gcd(&rhs), output.gcd, "{lhs} {rhs}");
let (lhs_on_gcd, rhs_on_gcd) = output.quotients();
assert_eq!(lhs_on_gcd, lhs.div(output.gcd.as_nz_ref()));
assert_eq!(rhs_on_gcd, rhs.div(output.gcd.as_nz_ref()));
let (x, y) = output.bezout_coefficients();
assert_eq!(
x.concatenating_mul_unsigned(&lhs) + y.concatenating_mul_unsigned(&rhs),
*output.gcd.resize().as_int(),
);
assert!(x.abs() <= rhs.div(output.gcd.as_nz_ref()));
assert!(y.abs() <= lhs.div(output.gcd.as_nz_ref()));
if lhs != rhs {
assert!(x.abs() <= rhs_on_gcd.shr(1) || rhs_on_gcd.is_zero().to_bool());
assert!(y.abs() <= lhs_on_gcd.shr(1) || lhs_on_gcd.is_zero().to_bool());
}
}
mod test_binxgcd_nz {
use crate::modular::bingcd::xgcd::tests::test_xgcd;
use crate::{
Concat, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192, Uint,
};
fn binxgcd_nz_test<const LIMBS: usize, const DOUBLE: usize>(
lhs: Uint<LIMBS>,
rhs: Uint<LIMBS>,
) where
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
{
let output = lhs.to_odd().unwrap().binxgcd_nz(&rhs.to_nz().unwrap());
test_xgcd(lhs, rhs, output);
}
fn binxgcd_nz_tests<const LIMBS: usize, const DOUBLE: usize>()
where
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
{
let max_int = *Int::MAX.as_uint();
let int_abs_min = Int::MIN.abs();
binxgcd_nz_test(Uint::ONE, Uint::ONE);
binxgcd_nz_test(Uint::ONE, max_int);
binxgcd_nz_test(Uint::ONE, int_abs_min);
binxgcd_nz_test(Uint::ONE, Uint::MAX);
binxgcd_nz_test(max_int, Uint::ONE);
binxgcd_nz_test(max_int, max_int);
binxgcd_nz_test(max_int, int_abs_min);
binxgcd_nz_test(max_int, Uint::MAX);
binxgcd_nz_test(Uint::MAX, Uint::ONE);
binxgcd_nz_test(Uint::MAX, max_int);
binxgcd_nz_test(Uint::MAX, int_abs_min);
binxgcd_nz_test(Uint::MAX, Uint::MAX);
}
#[test]
fn test_binxgcd_nz() {
binxgcd_nz_tests::<{ U64::LIMBS }, { U128::LIMBS }>();
binxgcd_nz_tests::<{ U128::LIMBS }, { U256::LIMBS }>();
binxgcd_nz_tests::<{ U192::LIMBS }, { U384::LIMBS }>();
binxgcd_nz_tests::<{ U256::LIMBS }, { U512::LIMBS }>();
binxgcd_nz_tests::<{ U384::LIMBS }, { U768::LIMBS }>();
binxgcd_nz_tests::<{ U512::LIMBS }, { U1024::LIMBS }>();
binxgcd_nz_tests::<{ U1024::LIMBS }, { U2048::LIMBS }>();
binxgcd_nz_tests::<{ U2048::LIMBS }, { U4096::LIMBS }>();
binxgcd_nz_tests::<{ U4096::LIMBS }, { U8192::LIMBS }>();
}
}
mod test_classic_binxgcd {
use crate::modular::bingcd::xgcd::tests::test_xgcd;
use crate::{
Concat, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192, Uint,
};
fn classic_binxgcd_test<const LIMBS: usize, const DOUBLE: usize>(
lhs: Uint<LIMBS>,
rhs: Uint<LIMBS>,
) where
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
{
let output = lhs
.to_odd()
.unwrap()
.classic_binxgcd(&rhs.to_odd().unwrap())
.divide();
test_xgcd(lhs, rhs, output);
}
fn classic_binxgcd_tests<const LIMBS: usize, const DOUBLE: usize>()
where
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
{
let max_int = *Int::MAX.as_uint();
classic_binxgcd_test(Uint::ONE, Uint::ONE);
classic_binxgcd_test(Uint::ONE, max_int);
classic_binxgcd_test(Uint::ONE, Uint::MAX);
classic_binxgcd_test(max_int, Uint::ONE);
classic_binxgcd_test(max_int, max_int);
classic_binxgcd_test(max_int, Uint::MAX);
classic_binxgcd_test(Uint::MAX, Uint::ONE);
classic_binxgcd_test(Uint::MAX, max_int);
classic_binxgcd_test(Uint::MAX, Uint::MAX);
}
#[test]
fn test_classic_binxgcd() {
classic_binxgcd_tests::<{ U64::LIMBS }, { U128::LIMBS }>();
classic_binxgcd_tests::<{ U128::LIMBS }, { U256::LIMBS }>();
classic_binxgcd_tests::<{ U192::LIMBS }, { U384::LIMBS }>();
classic_binxgcd_tests::<{ U256::LIMBS }, { U512::LIMBS }>();
classic_binxgcd_tests::<{ U384::LIMBS }, { U768::LIMBS }>();
classic_binxgcd_tests::<{ U512::LIMBS }, { U1024::LIMBS }>();
classic_binxgcd_tests::<{ U1024::LIMBS }, { U2048::LIMBS }>();
classic_binxgcd_tests::<{ U2048::LIMBS }, { U4096::LIMBS }>();
classic_binxgcd_tests::<{ U4096::LIMBS }, { U8192::LIMBS }>();
}
}
mod test_optimized_binxgcd {
use crate::modular::bingcd::xgcd::tests::test_xgcd;
use crate::modular::bingcd::xgcd::{DOUBLE_SUMMARY_LIMBS, SUMMARY_BITS, SUMMARY_LIMBS};
use crate::{
Concat, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192, Uint,
};
fn test<const LIMBS: usize, const DOUBLE: usize>(lhs: Uint<LIMBS>, rhs: Uint<LIMBS>)
where
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
{
let output = lhs
.to_odd()
.unwrap()
.optimized_binxgcd(&rhs.to_odd().unwrap())
.divide();
test_xgcd(lhs, rhs, output);
}
fn run_tests<const LIMBS: usize, const DOUBLE: usize>()
where
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
{
let upper_bound = *Int::MAX.as_uint();
test(Uint::ONE, Uint::ONE);
test(Uint::ONE, upper_bound);
test(Uint::ONE, Uint::MAX);
test(upper_bound, Uint::ONE);
test(upper_bound, upper_bound);
test(upper_bound, Uint::MAX);
test(Uint::MAX, Uint::ONE);
test(Uint::MAX, upper_bound);
test(Uint::MAX, Uint::MAX);
}
#[test]
fn test_optimized_binxgcd_edge_cases() {
assert_eq!(SUMMARY_BITS, 63);
assert_eq!(SUMMARY_LIMBS, U64::LIMBS);
assert_eq!(DOUBLE_SUMMARY_LIMBS, U128::LIMBS);
let a = U256::from_be_hex(
"1234567890ABCDEF80000000000000000000000000000000BEDCBA0987654321",
);
let b = U256::from_be_hex(
"1234567890ABCDEF800000000000000000000000000000007EDCBA0987654321",
);
assert!(a > b);
assert!(
a.compact::<SUMMARY_BITS, DOUBLE_SUMMARY_LIMBS>(U256::BITS)
< b.compact::<SUMMARY_BITS, DOUBLE_SUMMARY_LIMBS>(U256::BITS)
);
test(a, b);
test(b, a);
let a = U256::from_be_hex(
"1234567890ABCDEF80000000000000000000000000000000FEDCBA0987654321",
);
let b = U256::from_be_hex(
"1234567890ABCDEF800000000000000000000000000000007EDCBA0987654321",
);
assert!(a > b);
assert_eq!(
a.compact::<SUMMARY_BITS, DOUBLE_SUMMARY_LIMBS>(U256::BITS),
b.compact::<SUMMARY_BITS, DOUBLE_SUMMARY_LIMBS>(U256::BITS)
);
test(a, b);
test(b, a);
}
#[test]
fn optimized_binxgcd() {
run_tests::<{ U128::LIMBS }, { U256::LIMBS }>();
run_tests::<{ U192::LIMBS }, { U384::LIMBS }>();
run_tests::<{ U256::LIMBS }, { U512::LIMBS }>();
run_tests::<{ U384::LIMBS }, { U768::LIMBS }>();
run_tests::<{ U512::LIMBS }, { U1024::LIMBS }>();
run_tests::<{ U1024::LIMBS }, { U2048::LIMBS }>();
run_tests::<{ U2048::LIMBS }, { U4096::LIMBS }>();
run_tests::<{ U4096::LIMBS }, { U8192::LIMBS }>();
}
}
}