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}