use crate::{
data_structures::LabeledCommitment, BatchLCProof, LCTerm, LinearCombination,
PCPreparedCommitment, PCPreparedVerifierKey, PolynomialCommitment,
};
use ark_ff::PrimeField;
use ark_poly::Polynomial;
use ark_r1cs_std::{
fields::{emulated_fp::EmulatedFpVar, fp::FpVar},
prelude::*,
};
use ark_relations::r1cs::{ConstraintSystemRef, Namespace, Result as R1CSResult, SynthesisError};
use ark_std::{
borrow::Borrow,
cmp::{Eq, PartialEq},
hash::{BuildHasherDefault, Hash},
};
#[cfg(not(feature = "std"))]
use ark_std::{string::String, vec::Vec};
use hashbrown::{HashMap, HashSet};
#[cfg(all(
target_has_atomic = "8",
target_has_atomic = "16",
target_has_atomic = "32",
target_has_atomic = "64",
target_has_atomic = "ptr"
))]
type DefaultHasher = ahash::AHasher;
#[cfg(not(all(
target_has_atomic = "8",
target_has_atomic = "16",
target_has_atomic = "32",
target_has_atomic = "64",
target_has_atomic = "ptr"
)))]
type DefaultHasher = fnv::FnvHasher;
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(EmulatedFpVar<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 =
EmulatedFpVar::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<EmulatedFpVar<TargetField, BaseField>>,
pub opening_challenges_bits: Vec<Vec<Boolean<BaseField>>>,
pub batching_rands: Vec<EmulatedFpVar<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 PreparedVerifierKey: PCPreparedVerifierKey<PC::VerifierKey> + Clone;
type PreparedCommitment: PCPreparedCommitment<PC::Commitment>;
type VerifierKeyVar: AllocVar<PC::VerifierKey, ConstraintF> + Clone;
type PreparedVerifierKeyVar: AllocVar<Self::PreparedVerifierKey, ConstraintF>
+ Clone
+ PrepareGadget<Self::VerifierKeyVar, ConstraintF>;
type CommitmentVar: AllocVar<PC::Commitment, ConstraintF> + Clone;
type PreparedCommitmentVar: AllocVar<Self::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, PC::BatchProof>, 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: EmulatedFpVar<TargetField, BaseField>,
}
#[derive(Clone)]
pub struct QuerySetVar<TargetField: PrimeField, BaseField: PrimeField>(
pub HashSet<
(String, LabeledPointVar<TargetField, BaseField>),
BuildHasherDefault<DefaultHasher>,
>,
);
#[derive(Clone)]
pub struct EvaluationsVar<TargetField: PrimeField, BaseField: PrimeField>(
pub HashMap<
LabeledPointVar<TargetField, BaseField>,
EmulatedFpVar<TargetField, BaseField>,
BuildHasherDefault<DefaultHasher>,
>,
);
impl<TargetField: PrimeField, BaseField: PrimeField> EvaluationsVar<TargetField, BaseField> {
pub fn get_lc_eval(
&self,
lc_string: &str,
point: &EmulatedFpVar<TargetField, BaseField>,
) -> Result<EmulatedFpVar<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())
}
}