arnaucube
arnaucube/NovaPublic Self-hosted repository
Nova/src/bellperson/r1cs.rs
src/bellperson/r1cs.rsRaw
  1//! Support for generating R1CS using bellperson.
  2
  3#![allow(non_snake_case)]
  4
  5use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment};
  6use crate::{
  7  errors::NovaError,
  8  r1cs::{R1CSInstance, R1CSShape, R1CSWitness, R1CS},
  9  traits::Group,
 10  CommitmentKey,
 11};
 12use bellperson::{Index, LinearCombination};
 13use ff::PrimeField;
 14
 15/// `NovaWitness` provide a method for acquiring an `R1CSInstance` and `R1CSWitness` from implementers.
 16pub trait NovaWitness<G: Group> {
 17  /// Return an instance and witness, given a shape and ck.
 18  fn r1cs_instance_and_witness(
 19    &self,
 20    shape: &R1CSShape<G>,
 21    ck: &CommitmentKey<G>,
 22  ) -> Result<(R1CSInstance<G>, R1CSWitness<G>), NovaError>;
 23}
 24
 25/// `NovaShape` provides methods for acquiring `R1CSShape` and `CommitmentKey` from implementers.
 26pub trait NovaShape<G: Group> {
 27  /// Return an appropriate `R1CSShape` and `CommitmentKey` structs.
 28  fn r1cs_shape(&self) -> (R1CSShape<G>, CommitmentKey<G>);
 29}
 30
 31impl<G: Group> NovaWitness<G> for SatisfyingAssignment<G>
 32where
 33  G::Scalar: PrimeField,
 34{
 35  fn r1cs_instance_and_witness(
 36    &self,
 37    shape: &R1CSShape<G>,
 38    ck: &CommitmentKey<G>,
 39  ) -> Result<(R1CSInstance<G>, R1CSWitness<G>), NovaError> {
 40    let W = R1CSWitness::<G>::new(shape, &self.aux_assignment)?;
 41    let X = &self.input_assignment[1..];
 42
 43    let comm_W = W.commit(ck);
 44
 45    let instance = R1CSInstance::<G>::new(shape, &comm_W, X)?;
 46
 47    Ok((instance, W))
 48  }
 49}
 50
 51impl<G: Group> NovaShape<G> for ShapeCS<G>
 52where
 53  G::Scalar: PrimeField,
 54{
 55  fn r1cs_shape(&self) -> (R1CSShape<G>, CommitmentKey<G>) {
 56    let mut A: Vec<(usize, usize, G::Scalar)> = Vec::new();
 57    let mut B: Vec<(usize, usize, G::Scalar)> = Vec::new();
 58    let mut C: Vec<(usize, usize, G::Scalar)> = Vec::new();
 59
 60    let mut num_cons_added = 0;
 61    let mut X = (&mut A, &mut B, &mut C, &mut num_cons_added);
 62
 63    let num_inputs = self.num_inputs();
 64    let num_constraints = self.num_constraints();
 65    let num_vars = self.num_aux();
 66
 67    for constraint in self.constraints.iter() {
 68      add_constraint(
 69        &mut X,
 70        num_vars,
 71        &constraint.0,
 72        &constraint.1,
 73        &constraint.2,
 74      );
 75    }
 76
 77    assert_eq!(num_cons_added, num_constraints);
 78
 79    let S: R1CSShape<G> = {
 80      // Don't count One as an input for shape's purposes.
 81      let res = R1CSShape::new(num_constraints, num_vars, num_inputs - 1, &A, &B, &C);
 82      res.unwrap()
 83    };
 84
 85    let ck = R1CS::<G>::commitment_key(&S);
 86
 87    (S, ck)
 88  }
 89}
 90
 91fn add_constraint<S: PrimeField>(
 92  X: &mut (
 93    &mut Vec<(usize, usize, S)>,
 94    &mut Vec<(usize, usize, S)>,
 95    &mut Vec<(usize, usize, S)>,
 96    &mut usize,
 97  ),
 98  num_vars: usize,
 99  a_lc: &LinearCombination<S>,
100  b_lc: &LinearCombination<S>,
101  c_lc: &LinearCombination<S>,
102) {
103  let (A, B, C, nn) = X;
104  let n = **nn;
105  let one = S::one();
106
107  let add_constraint_component = |index: Index, coeff, V: &mut Vec<_>| {
108    match index {
109      Index::Input(idx) => {
110        // Inputs come last, with input 0, reprsenting 'one',
111        // at position num_vars within the witness vector.
112        let i = idx + num_vars;
113        V.push((n, i, one * coeff))
114      }
115      Index::Aux(idx) => V.push((n, idx, one * coeff)),
116    }
117  };
118
119  for (index, coeff) in a_lc.iter() {
120    add_constraint_component(index.0, coeff, A);
121  }
122  for (index, coeff) in b_lc.iter() {
123    add_constraint_component(index.0, coeff, B)
124  }
125  for (index, coeff) in c_lc.iter() {
126    add_constraint_component(index.0, coeff, C)
127  }
128
129  **nn += 1;
130}