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