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