decaf377/ark_curve/r1cs/
fqvar_ext.rsuse ark_r1cs_std::eq::EqGadget;
use ark_r1cs_std::prelude::{AllocVar, Boolean, FieldVar};
use ark_r1cs_std::select::CondSelectGadget;
use ark_r1cs_std::{R1CSVar, ToBitsGadget};
use ark_relations::r1cs::SynthesisError;
use crate::ark_curve::{constants::ZETA, r1cs::FqVar};
use crate::Fq;
pub trait FqVarExtension: Sized {
fn isqrt(&self) -> Result<(Boolean<Fq>, FqVar), SynthesisError>;
fn is_negative(&self) -> Result<Boolean<Fq>, SynthesisError>;
fn is_nonnegative(&self) -> Result<Boolean<Fq>, SynthesisError>;
fn abs(self) -> Result<Self, SynthesisError>;
}
impl FqVarExtension for FqVar {
fn isqrt(&self) -> Result<(Boolean<Fq>, FqVar), SynthesisError> {
let den = self.value().unwrap_or(Fq::ONE);
let (was_square, y) = Fq::sqrt_ratio_zeta(&Fq::ONE, &den);
let cs = self.cs();
let was_square_var = Boolean::new_witness(cs.clone(), || Ok(was_square))?;
let y_var = FqVar::new_witness(cs.clone(), || Ok(y))?;
let y_squared_var = y_var.square()?;
let den_var_is_zero = self.is_eq(&FqVar::zero())?;
let den_var = FqVar::conditionally_select(&den_var_is_zero, &FqVar::one(), self)?;
let den_var_inv = den_var.inverse()?;
let in_case_1 = was_square_var.clone();
y_squared_var.conditional_enforce_equal(&den_var_inv, &in_case_1)?;
let was_not_square_var = was_square_var.not();
let in_case_3 = was_not_square_var.and(&den_var_is_zero)?;
y_squared_var.conditional_enforce_equal(&FqVar::zero(), &in_case_3)?;
let zeta_var = FqVar::new_constant(cs, ZETA)?;
let zeta_times_one_over_den_var = zeta_var * den_var_inv;
let in_case_4 = was_not_square_var.and(&den_var_is_zero.not())?;
y_squared_var.conditional_enforce_equal(&zeta_times_one_over_den_var, &in_case_4)?;
let in_case = in_case_1.or(&in_case_3)?.or(&in_case_4)?;
in_case.enforce_equal(&Boolean::TRUE)?;
Ok((was_square_var, y_var))
}
fn is_negative(&self) -> Result<Boolean<Fq>, SynthesisError> {
Ok(self.is_nonnegative()?.not())
}
fn is_nonnegative(&self) -> Result<Boolean<Fq>, SynthesisError> {
let bitvars = self.to_bits_le()?;
let true_var = Boolean::<Fq>::TRUE;
let false_var = Boolean::<Fq>::FALSE;
let lhs = bitvars[0].and(&true_var)?;
let is_nonnegative_var = lhs.is_eq(&false_var)?;
Ok(is_nonnegative_var)
}
fn abs(self) -> Result<Self, SynthesisError> {
let absolute_value =
FqVar::conditionally_select(&self.is_nonnegative()?, &self, &self.negate()?)?;
Ok(absolute_value)
}
}