From 8300ed76c85736c6bf04188019e158bcaeb87ff4 Mon Sep 17 00:00:00 2001
From: Weikeng Chen <w.k@berkeley.edu>
Date: Wed, 9 Dec 2020 12:58:06 -0800
Subject: [PATCH] Add traits for constraints (#59)

* add the trait part of the constraints

* fix

* Update src/constraints.rs

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>

* Update src/constraints.rs

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>

* Update src/constraints.rs

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>

* Update src/constraints.rs

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>

* Update src/constraints.rs

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>

* fix

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>
---
 Cargo.toml         |   5 ++
 src/constraints.rs | 198 +++++++++++++++++++++++++++++++++++++++++++++
 src/lib.rs         |   6 ++
 3 files changed, 209 insertions(+)
 create mode 100644 src/constraints.rs

diff --git a/Cargo.toml b/Cargo.toml
index 988c86b..5c5e522 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,6 +27,10 @@ ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = fa
 ark-poly = { git = "https://github.com/arkworks-rs/algebra", default-features = false }
 
 ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false }
+ark-relations = { git = "https://github.com/arkworks-rs/snark", default-features = false, optional = true }
+ark-r1cs-std = { git = "https://github.com/arkworks-rs/r1cs-std", default-features = false, optional = true }
+ark-nonnative-field = { git = "https://github.com/arkworks-rs/nonnative", default-features = false, optional = true }
+hashbrown = { version = "0.9", optional = true }
 
 bench-utils = { git = "https://github.com/arkworks-rs/utils", default-features = false  }
 
@@ -57,5 +61,6 @@ debug = true
 [features]
 default = [ "std", "parallel" ]
 std = [ "ark-ff/std", "ark-ec/std", "ark-poly/std", "ark-std/std", "ark-serialize/std" ]
+r1cs = [ "ark-relations", "ark-r1cs-std", "ark-nonnative-field", "hashbrown" ]
 print-trace = [ "bench-utils/print-trace" ]
 parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-poly/parallel", "ark-std/parallel", "rayon" ]
diff --git a/src/constraints.rs b/src/constraints.rs
new file mode 100644
index 0000000..c3e9f40
--- /dev/null
+++ b/src/constraints.rs
@@ -0,0 +1,198 @@
+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};
+
+/// Define the minimal interface of prepared allocated structures.
+pub trait PrepareGadget<Unprepared, ConstraintF: PrimeField>: Sized {
+    /// Prepare from an unprepared element.
+    fn prepare(unprepared: &Unprepared) -> R1CSResult<Self>;
+}
+
+/// A coefficient of `LinearCombination`.
+#[allow(non_camel_case_types)]
+#[derive(Clone)]
+pub enum LinearCombinationCoeffVar<TargetField: PrimeField, BaseField: PrimeField> {
+    /// Coefficient 1.
+    One,
+    /// Coefficient -1.
+    MinusOne,
+    /// Other coefficient, represented as a nonnative field element.
+    Var(NonNativeFieldVar<TargetField, BaseField>),
+}
+
+/// An allocated version of `LinearCombination`.
+#[derive(Clone)]
+pub struct LinearCombinationVar<TargetField: PrimeField, BaseField: PrimeField> {
+    /// The label.
+    pub label: String,
+    /// The linear combination of `(coeff, poly_label)` pairs.
+    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)]
+/// A collection of random data used in the polynomial commitment checking.
+pub struct PCCheckRandomDataVar<TargetField: PrimeField, BaseField: PrimeField> {
+    /// Opening challenges.
+    /// The prover and the verifier MUST use the same opening challenges.
+    pub opening_challenges: Vec<NonNativeFieldVar<TargetField, BaseField>>,
+    /// Bit representations of the opening challenges.
+    pub opening_challenges_bits: Vec<Vec<Boolean<BaseField>>>,
+    /// Batching random numbers.
+    /// The verifier can choose these numbers freely, as long as they are random.
+    pub batching_rands: Vec<NonNativeFieldVar<TargetField, BaseField>>,
+    /// Bit representations of the batching random numbers.
+    pub batching_rands_bits: Vec<Vec<Boolean<BaseField>>>,
+}
+
+/// Describes the interface for a gadget for a `PolynomialCommitment`
+/// verifier.
+pub trait PCCheckVar<
+    PCF: PrimeField,
+    P: Polynomial<PCF>,
+    PC: PolynomialCommitment<PCF, P>,
+    ConstraintF: PrimeField,
+>: Clone
+{
+    /// An allocated version of `PC::VerifierKey`.
+    type VerifierKeyVar: AllocVar<PC::VerifierKey, ConstraintF> + Clone + ToBytesGadget<ConstraintF>;
+    /// An allocated version of `PC::PreparedVerifierKey`.
+    type PreparedVerifierKeyVar: AllocVar<PC::PreparedVerifierKey, ConstraintF>
+        + Clone
+        + PrepareGadget<Self::VerifierKeyVar, ConstraintF>;
+    /// An allocated version of `PC::Commitment`.
+    type CommitmentVar: AllocVar<PC::Commitment, ConstraintF> + Clone + ToBytesGadget<ConstraintF>;
+    /// An allocated version of `PC::PreparedCommitment`.
+    type PreparedCommitmentVar: AllocVar<PC::PreparedCommitment, ConstraintF>
+        + PrepareGadget<Self::CommitmentVar, ConstraintF>
+        + Clone;
+    /// An allocated version of `LabeledCommitment<PC::Commitment>`.
+    type LabeledCommitmentVar: AllocVar<LabeledCommitment<PC::Commitment>, ConstraintF> + Clone;
+    /// A prepared, allocated version of `LabeledCommitment<PC::Commitment>`.
+    type PreparedLabeledCommitmentVar: Clone;
+    /// An allocated version of `PC::Proof`.
+    type ProofVar: AllocVar<PC::Proof, ConstraintF> + Clone;
+
+    /// An allocated version of `PC::BatchLCProof`.
+    type BatchLCProofVar: AllocVar<BatchLCProof<PCF, P, PC>, ConstraintF> + Clone;
+
+    /// Add to `ConstraintSystemRef<ConstraintF>` new constraints that check that `proof_i` is a valid evaluation
+    /// proof at `point_i` for the polynomial in `commitment_i`.
+    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>>;
+
+    /// Add to `ConstraintSystemRef<ConstraintF>` new constraints that conditionally check that `proof` is a valid evaluation
+    /// proof at the points in `query_set` for the combinations `linear_combinations`.
+    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>>;
+
+    /// Create the labeled commitment gadget from the commitment gadget
+    fn create_labeled_commitment(
+        label: String,
+        commitment: Self::CommitmentVar,
+        degree_bound: Option<FpVar<ConstraintF>>,
+    ) -> Self::LabeledCommitmentVar;
+
+    /// Create the prepared labeled commitment gadget from the commitment gadget
+    fn create_prepared_labeled_commitment(
+        label: String,
+        commitment: Self::PreparedCommitmentVar,
+        degree_bound: Option<FpVar<ConstraintF>>,
+    ) -> Self::PreparedLabeledCommitmentVar;
+}
+
+#[derive(Clone, Hash, PartialEq, Eq)]
+/// A labeled point variable, for queries to a polynomial commitment.
+pub struct LabeledPointVar<TargetField: PrimeField, BaseField: PrimeField> {
+    /// The label of the point.
+    /// MUST be a unique identifier in a query set.
+    pub name: String,
+    /// The point value.
+    pub value: NonNativeFieldVar<TargetField, BaseField>,
+}
+
+/// An allocated version of `QuerySet`.
+#[derive(Clone)]
+pub struct QuerySetVar<TargetField: PrimeField, BaseField: PrimeField>(
+    pub HashSet<(String, LabeledPointVar<TargetField, BaseField>)>,
+);
+
+/// An allocated version of `Evaluations`.
+#[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> {
+    /// find the evaluation result
+    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())
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 49c989c..8daeec3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -33,6 +33,12 @@ use ark_std::{
 pub mod data_structures;
 pub use data_structures::*;
 
+/// R1CS constraints for polynomial constraints.
+#[cfg(feature = "r1cs")]
+mod constraints;
+#[cfg(feature = "r1cs")]
+pub use constraints::*;
+
 /// Errors pertaining to query sets.
 pub mod error;
 pub use error::*;
-- 
GitLab