nova_snark/frontend/
r1cs.rs1use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment, test_shape_cs::TestShapeCS};
3use crate::{
4 errors::NovaError,
5 frontend::{Index, LinearCombination},
6 r1cs::{R1CSInstance, R1CSShape, R1CSWitness, SparseMatrix},
7 traits::Engine,
8 CommitmentKey,
9};
10use ff::PrimeField;
11
12pub trait NovaWitness<E: Engine> {
14 fn r1cs_instance_and_witness(
16 &self,
17 shape: &R1CSShape<E>,
18 ck: &CommitmentKey<E>,
19 ) -> Result<(R1CSInstance<E>, R1CSWitness<E>), NovaError>;
20}
21
22pub trait NovaShape<E: Engine> {
24 fn r1cs_shape(&self) -> Result<R1CSShape<E>, NovaError>;
26}
27
28impl<E: Engine> NovaWitness<E> for SatisfyingAssignment<E> {
29 fn r1cs_instance_and_witness(
30 &self,
31 shape: &R1CSShape<E>,
32 ck: &CommitmentKey<E>,
33 ) -> Result<(R1CSInstance<E>, R1CSWitness<E>), NovaError> {
34 let W = R1CSWitness::<E>::new(shape, self.aux_assignment())?;
35 let X = &self.input_assignment()[1..];
36
37 let comm_W = W.commit(ck);
38
39 let instance = R1CSInstance::<E>::new(shape, &comm_W, X)?;
40
41 Ok((instance, W))
42 }
43}
44
45macro_rules! impl_nova_shape {
46 ( $name:ident) => {
47 impl<E: Engine> NovaShape<E> for $name<E>
48 where
49 E::Scalar: PrimeField,
50 {
51 fn r1cs_shape(&self) -> Result<R1CSShape<E>, NovaError> {
52 let mut A = SparseMatrix::<E::Scalar>::empty();
53 let mut B = SparseMatrix::<E::Scalar>::empty();
54 let mut C = SparseMatrix::<E::Scalar>::empty();
55
56 let mut num_cons_added = 0;
57 let mut X = (&mut A, &mut B, &mut C, &mut num_cons_added);
58 let num_inputs = self.num_inputs();
59 let num_constraints = self.num_constraints();
60 let num_vars = self.num_aux();
61
62 for constraint in self.constraints.iter() {
63 add_constraint(
64 &mut X,
65 num_vars,
66 &constraint.0,
67 &constraint.1,
68 &constraint.2,
69 );
70 }
71 assert_eq!(num_cons_added, num_constraints);
72
73 A.cols = num_vars + num_inputs;
74 B.cols = num_vars + num_inputs;
75 C.cols = num_vars + num_inputs;
76
77 R1CSShape::new(num_constraints, num_vars, num_inputs - 1, A, B, C)
79 }
80 }
81 };
82}
83
84impl_nova_shape!(ShapeCS);
85impl_nova_shape!(TestShapeCS);
86
87fn add_constraint<S: PrimeField>(
88 X: &mut (
89 &mut SparseMatrix<S>,
90 &mut SparseMatrix<S>,
91 &mut SparseMatrix<S>,
92 &mut usize,
93 ),
94 num_vars: usize,
95 a_lc: &LinearCombination<S>,
96 b_lc: &LinearCombination<S>,
97 c_lc: &LinearCombination<S>,
98) {
99 let (A, B, C, nn) = X;
100 let n = **nn;
101 assert_eq!(n + 1, A.indptr.len(), "A: invalid shape");
102 assert_eq!(n + 1, B.indptr.len(), "B: invalid shape");
103 assert_eq!(n + 1, C.indptr.len(), "C: invalid shape");
104
105 let add_constraint_component = |index: Index, coeff: &S, M: &mut SparseMatrix<S>| {
106 if *coeff != S::ZERO {
108 match index {
109 Index::Input(idx) => {
110 let idx = idx + num_vars;
113 M.data.push(*coeff);
114 M.indices.push(idx);
115 }
116 Index::Aux(idx) => {
117 M.data.push(*coeff);
118 M.indices.push(idx);
119 }
120 }
121 }
122 };
123
124 for (index, coeff) in a_lc.iter() {
125 add_constraint_component(index.0, coeff, A);
126 }
127 A.indptr.push(A.indices.len());
128
129 for (index, coeff) in b_lc.iter() {
130 add_constraint_component(index.0, coeff, B)
131 }
132 B.indptr.push(B.indices.len());
133
134 for (index, coeff) in c_lc.iter() {
135 add_constraint_component(index.0, coeff, C)
136 }
137 C.indptr.push(C.indices.len());
138
139 **nn += 1;
140}