sonobe_primitives/arithmetizations/r1cs/
circuits.rs1use ark_ff::{PrimeField, Zero};
4use ark_r1cs_std::alloc::{AllocVar, AllocationMode};
5use ark_relations::gr1cs::{Namespace, SynthesisError};
6use ark_std::{One, borrow::Borrow, ops::Mul};
7
8use super::R1CS;
9use crate::{
10 algebra::ops::{
11 eq::EquivalenceGadget,
12 matrix::{MatrixGadget, SparseMatrixVar},
13 vector::VectorGadget,
14 },
15 arithmetizations::ArithRelationGadget,
16 circuits::Assignments,
17};
18
19#[allow(non_snake_case)]
26#[derive(Debug, Clone)]
27pub struct R1CSMatricesVar<FVar> {
28 A: SparseMatrixVar<FVar>,
29 B: SparseMatrixVar<FVar>,
30 C: SparseMatrixVar<FVar>,
31}
32
33impl<F: PrimeField, ConstraintF: PrimeField, FVar: AllocVar<F, ConstraintF>>
34 AllocVar<R1CS<F>, ConstraintF> for R1CSMatricesVar<FVar>
35{
36 fn new_variable<T: Borrow<R1CS<F>>>(
37 cs: impl Into<Namespace<ConstraintF>>,
38 f: impl FnOnce() -> Result<T, SynthesisError>,
39 mode: AllocationMode,
40 ) -> Result<Self, SynthesisError> {
41 f().and_then(|val| {
42 let cs = cs.into();
43
44 let val = val.borrow();
45
46 Ok(Self {
47 A: SparseMatrixVar::<FVar>::new_variable(
48 cs.clone(),
49 || Ok(&val.matrices[0]),
50 mode,
51 )?,
52 B: SparseMatrixVar::<FVar>::new_variable(
53 cs.clone(),
54 || Ok(&val.matrices[1]),
55 mode,
56 )?,
57 C: SparseMatrixVar::<FVar>::new_variable(
58 cs.clone(),
59 || Ok(&val.matrices[2]),
60 mode,
61 )?,
62 })
63 })
64 }
65}
66
67impl<FVar> R1CSMatricesVar<FVar>
68where
69 SparseMatrixVar<FVar>: MatrixGadget<FVar>,
70 [FVar]: VectorGadget<FVar>,
71 for<'a> &'a FVar: Mul<&'a FVar, Output = FVar>,
72{
73 #[allow(non_snake_case)]
77 pub fn evaluate_r1cs(
78 &self,
79 z: Assignments<FVar, impl AsRef<[FVar]>>,
80 ) -> Result<Vec<FVar>, SynthesisError> {
81 let Az = self.A.mul_vector(&z)?;
84 let Bz = self.B.mul_vector(&z)?;
85 let Cz = self.C.mul_vector(&z)?;
86 let uCz = Cz.scale(&z[0])?;
87 let AzBz = Az.hadamard(&Bz)?;
88 AzBz.sub(&uCz)
89 }
90}
91
92impl<FVar, WVar: AsRef<[FVar]>, UVar: AsRef<[FVar]>> ArithRelationGadget<WVar, UVar>
93 for R1CSMatricesVar<FVar>
94where
95 SparseMatrixVar<FVar>: MatrixGadget<FVar>,
96 [FVar]: VectorGadget<FVar> + EquivalenceGadget<[FVar]>,
97 FVar: Clone + Zero + One,
99 for<'a> &'a FVar: Mul<&'a FVar, Output = FVar>,
100{
101 type Evaluation = Vec<FVar>;
102
103 fn eval_relation(&self, w: &WVar, u: &UVar) -> Result<Self::Evaluation, SynthesisError> {
104 self.evaluate_r1cs((FVar::one(), u.as_ref(), w.as_ref()).into())
105 }
106
107 fn check_evaluation(_w: &WVar, _u: &UVar, e: Self::Evaluation) -> Result<(), SynthesisError> {
108 e.enforce_equivalent(&vec![FVar::zero(); e.len()])
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use ark_bn254::Fr;
115 use ark_ff::{One, UniformRand, Zero};
116 use ark_std::{error::Error, rand::thread_rng};
117
118 use super::*;
119 use crate::{
120 circuits::utils::{constraints_for_test, satisfying_assignments_for_test},
121 relations::Relation,
122 };
123
124 #[test]
125 fn test_eval() -> Result<(), Box<dyn Error>> {
126 let mut rng = thread_rng();
127 let r1cs = constraints_for_test::<Fr>();
128
129 assert!(
130 r1cs.evaluate_r1cs(satisfying_assignments_for_test(Fr::rand(&mut rng)))?
131 .into_iter()
132 .all(|e| e.is_zero())
133 );
134 assert!(
135 !r1cs
136 .evaluate_r1cs(Assignments::from((
137 Fr::one(),
138 vec![Fr::rand(&mut rng)],
139 vec![
140 Fr::rand(&mut rng),
141 Fr::rand(&mut rng),
142 Fr::rand(&mut rng),
143 Fr::rand(&mut rng),
144 ],
145 )))?
146 .into_iter()
147 .all(|e| e.is_zero())
148 );
149
150 Ok(())
151 }
152
153 #[test]
154 fn test_check() -> Result<(), Box<dyn Error>> {
155 let mut rng = thread_rng();
156 let r1cs = constraints_for_test::<Fr>();
157
158 let assignments = satisfying_assignments_for_test(Fr::rand(&mut rng));
159
160 assert!(
161 r1cs.check_relation(&assignments.private, &assignments.public)
162 .is_ok()
163 );
164 assert!(
165 r1cs.check_relation(
166 &[
167 Fr::rand(&mut rng),
168 Fr::rand(&mut rng),
169 Fr::rand(&mut rng),
170 Fr::rand(&mut rng),
171 ],
172 &[Fr::rand(&mut rng)]
173 )
174 .is_err()
175 );
176
177 Ok(())
178 }
179}