use ff::Field;
use midnight_proofs::{
circuit::Layouter,
plonk::{Error, Expression},
};
use crate::{
field::AssignedNative,
instructions::ArithInstructions,
verifier::{expressions::compress_expressions, lookup::LookupEvaluated, SelfEmulation},
};
#[allow(clippy::too_many_arguments)]
pub(crate) fn lookup_expressions<S: SelfEmulation>(
layouter: &mut impl Layouter<S::F>,
scalar_chip: &S::ScalarChip,
lookup_evals: &LookupEvaluated<S>,
input_expressions: &[Expression<S::F>],
table_expressions: &[Expression<S::F>],
advice_evals: &[AssignedNative<S::F>],
fixed_evals: &[AssignedNative<S::F>],
instance_evals: &[AssignedNative<S::F>],
l_0: &AssignedNative<S::F>,
l_last: &AssignedNative<S::F>,
l_blind: &AssignedNative<S::F>,
theta: &AssignedNative<S::F>,
beta: &AssignedNative<S::F>,
gamma: &AssignedNative<S::F>,
) -> Result<Vec<AssignedNative<S::F>>, Error> {
let active_rows = {
scalar_chip.linear_combination(
layouter,
&[(-S::F::ONE, l_last.clone()), (-S::F::ONE, l_blind.clone())],
S::F::ONE,
)?
};
let id_1 = {
let z = &lookup_evals.product_eval;
scalar_chip.add_and_mul(
layouter,
(S::F::ONE, l_0),
(S::F::ZERO, z),
(S::F::ZERO, l_0),
S::F::ZERO,
-S::F::ONE,
)?
};
let id_2 = {
let z = &lookup_evals.product_eval;
let aux = scalar_chip.add_and_mul(
layouter,
(-S::F::ONE, z),
(S::F::ZERO, z),
(S::F::ZERO, z),
S::F::ZERO,
S::F::ONE,
)?;
scalar_chip.mul(layouter, l_last, &aux, None)?
};
let id_3 = {
let left = {
let aux1 = scalar_chip.add(layouter, &lookup_evals.permuted_input_eval, beta)?;
let aux2 = scalar_chip.add(layouter, &lookup_evals.permuted_table_eval, gamma)?;
let aux = scalar_chip.mul(layouter, &aux1, &aux2, None)?;
scalar_chip.mul(layouter, &lookup_evals.product_next_eval, &aux, None)?
};
let right = {
let compressed1 = compress_expressions::<S>(
layouter,
scalar_chip,
advice_evals,
fixed_evals,
instance_evals,
theta,
input_expressions,
)?;
let compressed2 = compress_expressions::<S>(
layouter,
scalar_chip,
advice_evals,
fixed_evals,
instance_evals,
theta,
table_expressions,
)?;
let aux1 = scalar_chip.add(layouter, &compressed1, beta)?;
let aux2 = scalar_chip.add(layouter, &compressed2, gamma)?;
let aux = scalar_chip.mul(layouter, &aux1, &aux2, None)?;
scalar_chip.mul(layouter, &lookup_evals.product_eval, &aux, None)?
};
let left_minus_right = scalar_chip.sub(layouter, &left, &right)?;
scalar_chip.mul(layouter, &left_minus_right, &active_rows, None)?
};
let input_minus_table = scalar_chip.sub(
layouter,
&lookup_evals.permuted_input_eval,
&lookup_evals.permuted_table_eval,
)?;
let id_4 = scalar_chip.mul(layouter, l_0, &input_minus_table, None)?;
let id_5 = {
let input_minus_prev = scalar_chip.sub(
layouter,
&lookup_evals.permuted_input_eval,
&lookup_evals.permuted_input_inv_eval,
)?;
let aux = scalar_chip.mul(layouter, &input_minus_table, &input_minus_prev, None)?;
scalar_chip.mul(layouter, &aux, &active_rows, None)?
};
Ok(vec![id_1, id_2, id_3, id_4, id_5])
}