use crate::{BatchLCProof, LCTerm, LabeledCommitment, LinearCombination, PolynomialCommitment, String, Vec};
use snarkvm_fields::PrimeField;
use snarkvm_gadgets::{
fields::FpGadget,
utilities::{alloc::AllocGadget, boolean::Boolean, ToBytesGadget},
};
use snarkvm_nonnative::NonNativeFieldVar;
use snarkvm_r1cs::{ConstraintSystem, SynthesisError};
use core::borrow::Borrow;
use hashbrown::{HashMap, HashSet};
pub trait PrepareGadget<Unprepared, F: PrimeField>: Sized {
fn prepare<CS: ConstraintSystem<F>>(cs: CS, unprepared: &Unprepared) -> Result<Self, SynthesisError>;
}
#[derive(Clone, Debug)]
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> AllocGadget<LinearCombination<TargetField>, BaseField>
for LinearCombinationVar<TargetField, BaseField>
{
#[inline]
fn alloc_constant<FN, T, CS: ConstraintSystem<BaseField>>(mut cs: CS, value_gen: FN) -> Result<Self, SynthesisError>
where
FN: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<LinearCombination<TargetField>>,
{
let LinearCombination { label, terms } = value_gen()?.borrow().clone();
let new_terms: Vec<(LinearCombinationCoeffVar<TargetField, BaseField>, LCTerm)> = terms
.iter()
.enumerate()
.map(|(i, term)| {
let (coefficient, lc_term) = term;
let fg =
NonNativeFieldVar::alloc_constant(cs.ns(|| format!("term_{}", i)), || Ok(coefficient)).unwrap();
(LinearCombinationCoeffVar::Var(fg), lc_term.clone())
})
.collect();
Ok(Self {
label,
terms: new_terms,
})
}
#[inline]
fn alloc<FN, T, CS: ConstraintSystem<BaseField>>(mut cs: CS, value_gen: FN) -> Result<Self, SynthesisError>
where
FN: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<LinearCombination<TargetField>>,
{
let LinearCombination { label, terms } = value_gen()?.borrow().clone();
let new_terms: Vec<(LinearCombinationCoeffVar<TargetField, BaseField>, LCTerm)> = terms
.iter()
.enumerate()
.map(|(i, term)| {
let (coefficient, lc_term) = term;
let fg = NonNativeFieldVar::alloc(cs.ns(|| format!("term_{}", i)), || Ok(coefficient)).unwrap();
(LinearCombinationCoeffVar::Var(fg), lc_term.clone())
})
.collect();
Ok(Self {
label,
terms: new_terms,
})
}
#[inline]
fn alloc_input<FN, T, CS: ConstraintSystem<BaseField>>(mut cs: CS, value_gen: FN) -> Result<Self, SynthesisError>
where
FN: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<LinearCombination<TargetField>>,
{
let LinearCombination { label, terms } = value_gen()?.borrow().clone();
let new_terms: Vec<(LinearCombinationCoeffVar<TargetField, BaseField>, LCTerm)> = terms
.iter()
.enumerate()
.map(|(i, term)| {
let (coefficient, lc_term) = term;
let fg = NonNativeFieldVar::alloc_input(cs.ns(|| format!("term_{}", i)), || Ok(coefficient)).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>>,
pub batching_rands: Vec<NonNativeFieldVar<TargetField, BaseField>>,
pub batching_rands_bits: Vec<Vec<Boolean>>,
}
pub trait PCCheckVar<PCF: PrimeField, PC: PolynomialCommitment<PCF>, ConstraintF: PrimeField>: Clone {
type VerifierKeyVar: AllocGadget<PC::VerifierKey, ConstraintF> + Clone + ToBytesGadget<ConstraintF>;
type PreparedVerifierKeyVar: AllocGadget<PC::PreparedVerifierKey, ConstraintF>
+ Clone
+ PrepareGadget<Self::VerifierKeyVar, ConstraintF>;
type CommitmentVar: AllocGadget<PC::Commitment, ConstraintF> + Clone + ToBytesGadget<ConstraintF>;
type PreparedCommitmentVar: AllocGadget<PC::PreparedCommitment, ConstraintF>
+ PrepareGadget<Self::CommitmentVar, ConstraintF>
+ Clone;
type LabeledCommitmentVar: AllocGadget<LabeledCommitment<PC::Commitment>, ConstraintF> + Clone;
type PreparedLabeledCommitmentVar: Clone;
type ProofVar: AllocGadget<PC::Proof, ConstraintF> + Clone;
type BatchLCProofVar: AllocGadget<BatchLCProof<PCF, PC>, ConstraintF> + Clone;
fn batch_check_evaluations<CS: ConstraintSystem<ConstraintF>>(
cs: CS,
verification_key: &Self::VerifierKeyVar,
commitments: &[Self::LabeledCommitmentVar],
query_set: &QuerySetVar<PCF, ConstraintF>,
evaluations: &EvaluationsVar<PCF, ConstraintF>,
proofs: &[Self::ProofVar],
rand_data: &PCCheckRandomDataVar<PCF, ConstraintF>,
) -> Result<Boolean, SynthesisError>;
fn prepared_check_combinations<CS: ConstraintSystem<ConstraintF>>(
cs: CS,
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>,
) -> Result<Boolean, SynthesisError>;
fn create_labeled_commitment(
label: String,
commitment: Self::CommitmentVar,
degree_bound: Option<FpGadget<ConstraintF>>,
) -> Self::LabeledCommitmentVar;
fn create_prepared_labeled_commitment(
label: String,
commitment: Self::PreparedCommitmentVar,
degree_bound: Option<FpGadget<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())
}
}