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> {
 32  fn r1cs_instance_and_witness(
 33    &self,
 34    shape: &R1CSShape<G>,
 35    ck: &CommitmentKey<G>,
 36  ) -> Result<(R1CSInstance<G>, R1CSWitness<G>), NovaError> {
 37    let W = R1CSWitness::<G>::new(shape, &self.aux_assignment)?;
 38    let X = &self.input_assignment[1..];
 39
 40    let comm_W = W.commit(ck);
 41
 42    let instance = R1CSInstance::<G>::new(shape, &comm_W, X)?;
 43
 44    Ok((instance, W))
 45  }
 46}
 47
 48impl<G: Group> NovaShape<G> for ShapeCS<G> {
 49  fn r1cs_shape(&self) -> (R1CSShape<G>, CommitmentKey<G>) {
 50    let mut A: Vec<(usize, usize, G::Scalar)> = Vec::new();
 51    let mut B: Vec<(usize, usize, G::Scalar)> = Vec::new();
 52    let mut C: Vec<(usize, usize, G::Scalar)> = Vec::new();
 53
 54    let mut num_cons_added = 0;
 55    let mut X = (&mut A, &mut B, &mut C, &mut num_cons_added);
 56
 57    let num_inputs = self.num_inputs();
 58    let num_constraints = self.num_constraints();
 59    let num_vars = self.num_aux();
 60
 61    for constraint in self.constraints.iter() {
 62      add_constraint(
 63        &mut X,
 64        num_vars,
 65        &constraint.0,
 66        &constraint.1,
 67        &constraint.2,
 68      );
 69    }
 70
 71    assert_eq!(num_cons_added, num_constraints);
 72
 73    let S: R1CSShape<G> = {
 74      // Don't count One as an input for shape's purposes.
 75      let res = R1CSShape::new(num_constraints, num_vars, num_inputs - 1, &A, &B, &C);
 76      res.unwrap()
 77    };
 78
 79    let ck = R1CS::<G>::commitment_key(&S);
 80
 81    (S, ck)
 82  }
 83}
 84
 85fn add_constraint<S: PrimeField>(
 86  X: &mut (
 87    &mut Vec<(usize, usize, S)>,
 88    &mut Vec<(usize, usize, S)>,
 89    &mut Vec<(usize, usize, S)>,
 90    &mut usize,
 91  ),
 92  num_vars: usize,
 93  a_lc: &LinearCombination<S>,
 94  b_lc: &LinearCombination<S>,
 95  c_lc: &LinearCombination<S>,
 96) {
 97  let (A, B, C, nn) = X;
 98  let n = **nn;
 99  let one = S::ONE;
100
101  let add_constraint_component = |index: Index, coeff, V: &mut Vec<_>| {
102    match index {
103      Index::Input(idx) => {
104        // Inputs come last, with input 0, reprsenting 'one',
105        // at position num_vars within the witness vector.
106        let i = idx + num_vars;
107        V.push((n, i, one * coeff))
108      }
109      Index::Aux(idx) => V.push((n, idx, one * coeff)),
110    }
111  };
112
113  for (index, coeff) in a_lc.iter() {
114    add_constraint_component(index.0, coeff, A);
115  }
116  for (index, coeff) in b_lc.iter() {
117    add_constraint_component(index.0, coeff, B)
118  }
119  for (index, coeff) in c_lc.iter() {
120    add_constraint_component(index.0, coeff, C)
121  }
122
123  **nn += 1;
124}