use crate::{
data_structures::LabeledCommitment, BatchLCProof, LCTerm, LinearCombination,
PolynomialCommitment, String, Vec,
};
use ark_ff::PrimeField;
use ark_nonnative_field::NonNativeFieldVar;
use ark_poly::Polynomial;
use ark_r1cs_std::{fields::fp::FpVar, prelude::*};
use ark_relations::r1cs::{ConstraintSystemRef, Namespace, Result as R1CSResult, SynthesisError};
use ark_std::{borrow::Borrow, cmp::Eq, cmp::PartialEq, hash::Hash, marker::Sized};
use hashbrown::{HashMap, HashSet};
pub trait PrepareGadget<Unprepared, ConstraintF: PrimeField>: Sized {
fn prepare(unprepared: &Unprepared) -> R1CSResult<Self>;
}
#[derive(Clone)]
pub enum LinearCombinationCoeffVar<TargetField: PrimeField, BaseField: PrimeField> {
One,
MinusOne,
Var(NonNativeFieldVar<TargetField, BaseField>),
}
#[derive(Clone)]
pub struct LinearCombinationVar<TargetField: PrimeField, BaseField: PrimeField> {
pub label: String,
pub terms: Vec<(LinearCombinationCoeffVar<TargetField, BaseField>, LCTerm)>,
}
impl<TargetField: PrimeField, BaseField: PrimeField>
AllocVar<LinearCombination<TargetField>, BaseField>
for LinearCombinationVar<TargetField, BaseField>
{
fn new_variable<T>(
cs: impl Into<Namespace<BaseField>>,
val: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> R1CSResult<Self>
where
T: Borrow<LinearCombination<TargetField>>,
{
let LinearCombination { label, terms } = val()?.borrow().clone();
let ns = cs.into();
let cs = ns.cs();
let new_terms: Vec<(LinearCombinationCoeffVar<TargetField, BaseField>, LCTerm)> = terms
.iter()
.map(|term| {
let (f, lc_term) = term;
let fg =
NonNativeFieldVar::new_variable(ark_relations::ns!(cs, "term"), || Ok(f), mode)
.unwrap();
(LinearCombinationCoeffVar::Var(fg), lc_term.clone())
})
.collect();
Ok(Self {
label,
terms: new_terms,
})
}
}
#[derive(Clone, Debug)]
pub struct PCCheckRandomDataVar<TargetField: PrimeField, BaseField: PrimeField> {
pub opening_challenges: Vec<NonNativeFieldVar<TargetField, BaseField>>,
pub opening_challenges_bits: Vec<Vec<Boolean<BaseField>>>,
pub batching_rands: Vec<NonNativeFieldVar<TargetField, BaseField>>,
pub batching_rands_bits: Vec<Vec<Boolean<BaseField>>>,
}
pub trait PCCheckVar<
PCF: PrimeField,
P: Polynomial<PCF>,
PC: PolynomialCommitment<PCF, P>,
ConstraintF: PrimeField,
>: Clone
{
type VerifierKeyVar: AllocVar<PC::VerifierKey, ConstraintF> + Clone + ToBytesGadget<ConstraintF>;
type PreparedVerifierKeyVar: AllocVar<PC::PreparedVerifierKey, ConstraintF>
+ Clone
+ PrepareGadget<Self::VerifierKeyVar, ConstraintF>;
type CommitmentVar: AllocVar<PC::Commitment, ConstraintF> + Clone + ToBytesGadget<ConstraintF>;
type PreparedCommitmentVar: AllocVar<PC::PreparedCommitment, ConstraintF>
+ PrepareGadget<Self::CommitmentVar, ConstraintF>
+ Clone;
type LabeledCommitmentVar: AllocVar<LabeledCommitment<PC::Commitment>, ConstraintF> + Clone;
type PreparedLabeledCommitmentVar: Clone;
type ProofVar: AllocVar<PC::Proof, ConstraintF> + Clone;
type BatchLCProofVar: AllocVar<BatchLCProof<PCF, P, PC>, ConstraintF> + Clone;
fn batch_check_evaluations(
cs: ConstraintSystemRef<ConstraintF>,
verification_key: &Self::VerifierKeyVar,
commitments: &[Self::LabeledCommitmentVar],
query_set: &QuerySetVar<PCF, ConstraintF>,
evaluations: &EvaluationsVar<PCF, ConstraintF>,
proofs: &[Self::ProofVar],
rand_data: &PCCheckRandomDataVar<PCF, ConstraintF>,
) -> R1CSResult<Boolean<ConstraintF>>;
fn prepared_check_combinations(
cs: ConstraintSystemRef<ConstraintF>,
prepared_verification_key: &Self::PreparedVerifierKeyVar,
linear_combinations: &[LinearCombinationVar<PCF, ConstraintF>],
prepared_commitments: &[Self::PreparedLabeledCommitmentVar],
query_set: &QuerySetVar<PCF, ConstraintF>,
evaluations: &EvaluationsVar<PCF, ConstraintF>,
proof: &Self::BatchLCProofVar,
rand_data: &PCCheckRandomDataVar<PCF, ConstraintF>,
) -> R1CSResult<Boolean<ConstraintF>>;
fn create_labeled_commitment(
label: String,
commitment: Self::CommitmentVar,
degree_bound: Option<FpVar<ConstraintF>>,
) -> Self::LabeledCommitmentVar;
fn create_prepared_labeled_commitment(
label: String,
commitment: Self::PreparedCommitmentVar,
degree_bound: Option<FpVar<ConstraintF>>,
) -> Self::PreparedLabeledCommitmentVar;
}
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct LabeledPointVar<TargetField: PrimeField, BaseField: PrimeField> {
pub name: String,
pub value: NonNativeFieldVar<TargetField, BaseField>,
}
#[derive(Clone)]
pub struct QuerySetVar<TargetField: PrimeField, BaseField: PrimeField>(
pub HashSet<(String, LabeledPointVar<TargetField, BaseField>)>,
);
#[derive(Clone)]
pub struct EvaluationsVar<TargetField: PrimeField, BaseField: PrimeField>(
pub HashMap<LabeledPointVar<TargetField, BaseField>, NonNativeFieldVar<TargetField, BaseField>>,
);
impl<TargetField: PrimeField, BaseField: PrimeField> EvaluationsVar<TargetField, BaseField> {
pub fn get_lc_eval(
&self,
lc_string: &str,
point: &NonNativeFieldVar<TargetField, BaseField>,
) -> Result<NonNativeFieldVar<TargetField, BaseField>, SynthesisError> {
let key = LabeledPointVar::<TargetField, BaseField> {
name: String::from(lc_string),
value: point.clone(),
};
Ok(self.0.get(&key).map(|v| (*v).clone()).unwrap())
}
}