use crypto_bigint::{Choice, CtOption, CtEq as _, CtLt as _, CtAssign, Zero, One, NonZero, Limb};
#[derive(Clone, Copy, Debug)]
pub enum Error {
UnexpectedEof,
Overflow,
NonCanonical,
Incorrect,
}
pub(super) trait Limbs:
From<u8> + CtAssign + Zero + One + super::composition::Limbs
{
fn wide_div_rem_thin(wide: Self::Wide, thin: &NonZero<Self>) -> (Self::Wide, Self);
fn coprime(a: Self, b_abs: Self, c: Self::Wide) -> Choice;
}
#[expect(clippy::type_complexity)]
pub(super) fn validate_binary_quadratic_form<U: Limbs>(
a: NonZero<U>,
(b_positive, b_abs): (Choice, U),
discriminant_abs: &U::Wide,
) -> CtOption<(NonZero<U>, (Choice, U), U::Wide)> {
let (c, c_is_correct) = {
let mut b_square = b_abs.clone().square();
let mut carry = Limb::ZERO;
for (b_square, discriminant_abs) in <_ as AsMut<[Limb]>>::as_mut(&mut b_square)
.iter_mut()
.zip(discriminant_abs.as_ref().iter().chain(core::iter::repeat(&Limb::ZERO)))
{
let new_limb;
(new_limb, carry) = b_square.carrying_add(*discriminant_abs, carry);
*b_square = new_limb;
}
let mut four_ac = b_square;
{
let four_ac = <_ as AsMut<[Limb]>>::as_mut(&mut four_ac);
for i in (0 .. four_ac.len()).rev() {
let new_limb = (four_ac[i] >> 2) | (carry << (Limb::BITS - 2));
carry = four_ac[i] & Limb::from(0b11u8);
four_ac[i] = new_limb;
}
}
let ac = four_ac;
let (c, rem) = U::wide_div_rem_thin(ac, &a);
(c, carry.is_zero() & rem.is_zero())
};
let reduced_absolute_values;
let reduced_sign;
{
let a = crypto_bigint::UintRef::new(a.as_ref().as_ref());
let b_abs = crypto_bigint::UintRef::new(b_abs.as_ref());
let c = crypto_bigint::UintRef::new(c.as_ref());
reduced_absolute_values = (b_abs.ct_lt(a) | b_abs.ct_eq(a)) & (a.ct_lt(c) | a.ct_eq(c));
reduced_sign = {
let has_equality = b_abs.ct_eq(a) | a.ct_eq(c);
(!has_equality) | b_positive
};
}
let primitive = U::coprime(a.as_ref().clone(), b_abs.clone(), c.clone());
CtOption::new(
(a, (b_positive, b_abs), c),
c_is_correct & reduced_absolute_values & reduced_sign & primitive,
)
}
mod uncompressed;
#[cfg(feature = "alloc")]
mod compressed;
#[cfg(feature = "alloc")]
pub(crate) use compressed::*;