use std::marker::PhantomData;
use crate::traits::PairingEngine;
#[derive(Debug, Clone)]
pub struct EvaluationDomain<E: PairingEngine> {
pub size: usize,
pub omega: E::Fr,
pub omega_inv: E::Fr,
pub size_as_field: E::Fr,
pub size_inv: E::Fr,
}
#[derive(Debug, Clone)]
pub struct GateSelectors<E: PairingEngine> {
pub q_l: E::Fr,
pub q_r: E::Fr,
pub q_o: E::Fr,
pub q_m: E::Fr,
pub q_c: E::Fr,
}
pub struct GateEvaluator<E: PairingEngine> {
_engine: PhantomData<E>,
}
impl<E: PairingEngine> GateEvaluator<E> {
pub fn new() -> Self {
Self {
_engine: PhantomData,
}
}
pub fn evaluate_arithmetic_gate(
&self,
selectors: &GateSelectors<E>,
a: &E::Fr,
b: &E::Fr,
c: &E::Fr,
) -> E::Fr {
let term1 = selectors.q_l * a;
let term2 = selectors.q_r * b;
let term3 = selectors.q_o * c;
let ab = *a * b;
let term4 = selectors.q_m * ab;
term1 + term2 + term3 + term4 + selectors.q_c
}
pub fn evaluate_permutation_gate(
&self,
z: &E::Fr,
z_omega: &E::Fr,
wires: (&E::Fr, &E::Fr, &E::Fr),
sigmas: (&E::Fr, &E::Fr),
_beta: &E::Fr,
_gamma: &E::Fr,
) -> E::Fr {
use ff::Field;
let (_a, _b, _c) = wires;
let (_sigma1, _sigma2) = sigmas;
*z_omega - (*z * E::Fr::ONE)
}
pub fn evaluate_quotient(
&self,
gate_residual: &E::Fr,
perm_residual: &E::Fr,
alpha: &E::Fr,
zh_eval: &E::Fr,
) -> Result<E::Fr, String> {
use ff::Field;
if zh_eval.is_zero().into() {
return Err("Vanishing polynomial is zero".to_string());
}
let numerator = *gate_residual + (*alpha * perm_residual);
let zh_inv = zh_eval.invert().unwrap();
Ok(numerator * zh_inv)
}
}
impl<E: PairingEngine> Default for GateEvaluator<E> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::bn254::Bn254;
use ff::Field;
use halo2curves::bn256::Fr;
#[test]
fn arithmetic_gate_addition() {
let evaluator = GateEvaluator::<Bn254>::new();
let selectors = GateSelectors {
q_l: Fr::ONE,
q_r: Fr::ONE,
q_o: -Fr::ONE,
q_m: Fr::ZERO,
q_c: Fr::ZERO,
};
let a = Fr::from(3u64);
let b = Fr::from(5u64);
let c = Fr::from(8u64);
let result = evaluator.evaluate_arithmetic_gate(&selectors, &a, &b, &c);
assert_eq!(result, Fr::ZERO, "Valid addition should give zero residual");
}
#[test]
fn arithmetic_gate_multiplication() {
let evaluator = GateEvaluator::<Bn254>::new();
let selectors = GateSelectors {
q_l: Fr::ZERO,
q_r: Fr::ZERO,
q_o: -Fr::ONE,
q_m: Fr::ONE,
q_c: Fr::ZERO,
};
let a = Fr::from(4u64);
let b = Fr::from(7u64);
let c = Fr::from(28u64);
let result = evaluator.evaluate_arithmetic_gate(&selectors, &a, &b, &c);
assert_eq!(
result,
Fr::ZERO,
"Valid multiplication should give zero residual"
);
}
#[test]
fn arithmetic_gate_constant() {
let evaluator = GateEvaluator::<Bn254>::new();
let selectors = GateSelectors {
q_l: Fr::ZERO,
q_r: Fr::ZERO,
q_o: -Fr::ONE,
q_m: Fr::ZERO,
q_c: Fr::from(42u64),
};
let a = Fr::ZERO;
let b = Fr::ZERO;
let c = Fr::from(42u64);
let result = evaluator.evaluate_arithmetic_gate(&selectors, &a, &b, &c);
assert_eq!(result, Fr::ZERO, "Constant gate should satisfy");
}
#[test]
fn arithmetic_gate_invalid_gives_nonzero() {
let evaluator = GateEvaluator::<Bn254>::new();
let selectors = GateSelectors {
q_l: Fr::ONE,
q_r: Fr::ONE,
q_o: -Fr::ONE,
q_m: Fr::ZERO,
q_c: Fr::ZERO,
};
let a = Fr::from(3u64);
let b = Fr::from(5u64);
let c = Fr::from(10u64);
let result = evaluator.evaluate_arithmetic_gate(&selectors, &a, &b, &c);
assert_ne!(
result,
Fr::ZERO,
"Invalid constraint should give nonzero residual"
);
}
#[test]
fn quotient_division_by_zero_fails() {
let evaluator = GateEvaluator::<Bn254>::new();
let result = evaluator.evaluate_quotient(
&Fr::ONE,
&Fr::ONE,
&Fr::from(2u64),
&Fr::ZERO, );
assert!(result.is_err());
}
#[test]
fn quotient_valid_division() {
let evaluator = GateEvaluator::<Bn254>::new();
let gate = Fr::from(6u64);
let perm = Fr::from(4u64);
let alpha = Fr::from(2u64);
let zh = Fr::from(7u64);
let result = evaluator.evaluate_quotient(&gate, &perm, &alpha, &zh).unwrap();
assert_eq!(result, Fr::from(2u64));
}
}