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