use ff::Field;
use midnight_proofs::{circuit::Layouter, plonk::Error};
use num_bigint::BigUint;
use super::PublicInputInstructions;
use crate::{
instructions::{
ArithInstructions, AssertionInstructions, AssignmentInstructions, ControlFlowInstructions,
EqualityInstructions, ZeroInstructions,
},
types::{AssignedBit, InnerConstants, Instantiable},
utils::util::qnr,
CircuitField,
};
pub trait FieldInstructions<F, Assigned>:
AssignmentInstructions<F, Assigned>
+ PublicInputInstructions<F, Assigned>
+ AssertionInstructions<F, Assigned>
+ ArithInstructions<F, Assigned>
+ EqualityInstructions<F, Assigned>
+ ZeroInstructions<F, Assigned>
+ ControlFlowInstructions<F, Assigned>
+ AssignmentInstructions<F, AssignedBit<F>>
where
F: CircuitField,
Assigned::Element: CircuitField,
Assigned: Instantiable<F> + InnerConstants + Clone,
{
fn order(&self) -> BigUint;
fn assert_qr(&self, layouter: &mut impl Layouter<F>, x: &Assigned) -> Result<(), Error> {
let sqrt_x_value =
x.value().map(|x| Assigned::Element::sqrt(&x).expect("a quadratic residue"));
let sqrt_x = self.assign(layouter, sqrt_x_value)?;
let sqr = self.mul(layouter, &sqrt_x, &sqrt_x, None)?;
self.assert_equal(layouter, &sqr, x)
}
fn is_square(
&self,
layouter: &mut impl Layouter<F>,
x: &Assigned,
) -> Result<AssignedBit<F>, Error> {
let is_square_value = x.value().map(|x| bool::from(x.sqrt().is_some()));
let is_square = self.assign(layouter, is_square_value)?;
let x_times_qnr = self.mul_by_constant(layouter, x, qnr::<Assigned::Element>())?;
let y = self.select(layouter, &is_square, x, &x_times_qnr)?;
self.assert_qr(layouter, &y)?;
Ok(is_square)
}
}