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