sonobe/src/frontend/arkworks/mod.rs
src/frontend/arkworks/mod.rsRaw
1/// arkworks frontend
2use ark_ff::PrimeField;
3use ark_relations::r1cs::ConstraintSystem;
4
5use crate::ccs::r1cs::R1CS;
6use crate::utils::vec::SparseMatrix;
7
8/// extracts arkworks ConstraintSystem matrices into crate::utils::vec::SparseMatrix format, and
9/// extracts public inputs and witness into z vector. Returns a tuple containing (R1CS, z).
10pub fn extract_r1cs_and_z<F: PrimeField>(cs: &ConstraintSystem<F>) -> (R1CS<F>, Vec<F>) {
11 let r1cs = extract_r1cs(cs);
12
13 // z = (1, x, w)
14 let z = extract_z(cs);
15
16 (r1cs, z)
17}
18
19/// extracts arkworks ConstraintSystem matrices into crate::utils::vec::SparseMatrix format as R1CS
20/// struct.
21pub fn extract_r1cs<F: PrimeField>(cs: &ConstraintSystem<F>) -> R1CS<F> {
22 let m = cs.to_matrices().unwrap();
23
24 let n_rows = cs.num_constraints;
25 let n_cols = cs.num_instance_variables + cs.num_witness_variables; // cs.num_instance_variables already counts the 1
26
27 let A = SparseMatrix::<F> {
28 n_rows,
29 n_cols,
30 coeffs: m.a,
31 };
32 let B = SparseMatrix::<F> {
33 n_rows,
34 n_cols,
35 coeffs: m.b,
36 };
37 let C = SparseMatrix::<F> {
38 n_rows,
39 n_cols,
40 coeffs: m.c,
41 };
42
43 R1CS::<F> {
44 l: cs.num_instance_variables - 1, // -1 to substract the first '1'
45 A,
46 B,
47 C,
48 }
49}
50
51/// extracts public inputs and witness into z vector from arkworks ConstraintSystem.
52pub fn extract_z<F: PrimeField>(cs: &ConstraintSystem<F>) -> Vec<F> {
53 // z = (1, x, w)
54 [
55 // 1 is already included in cs.instance_assignment
56 cs.instance_assignment.clone(),
57 cs.witness_assignment.clone(),
58 ]
59 .concat()
60}
61
62/// extracts the witness and the public inputs from arkworks ConstraintSystem.
63pub fn extract_w_x<F: PrimeField>(cs: &ConstraintSystem<F>) -> (Vec<F>, Vec<F>) {
64 (
65 cs.witness_assignment.clone(),
66 // skip the first element which is '1'
67 cs.instance_assignment[1..].to_vec(),
68 )
69}
70
71#[cfg(test)]
72pub mod tests {
73 use super::*;
74 use ark_ff::PrimeField;
75 use ark_pallas::Fr;
76 use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar};
77 use ark_relations::r1cs::{
78 ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
79 };
80
81 // TestCircuit implements the R1CS for: x^3 + x + 5 = y (example from article
82 // https://www.vitalik.ca/general/2016/12/10/qap.html )
83 #[derive(Clone, Copy, Debug)]
84 pub struct TestCircuit<F: PrimeField> {
85 pub x: F,
86 pub y: F,
87 }
88 impl<F: PrimeField> ConstraintSynthesizer<F> for TestCircuit<F> {
89 fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
90 let x = FpVar::<F>::new_input(cs.clone(), || Ok(self.x))?;
91 let y = FpVar::<F>::new_witness(cs.clone(), || Ok(self.y))?;
92 let five = FpVar::<F>::new_constant(cs.clone(), F::from(5u32))?;
93
94 let comp_y = (&x * &x * &x) + &x + &five;
95 comp_y.enforce_equal(&y)?;
96 Ok(())
97 }
98 }
99
100 #[test]
101 fn test_cs_to_matrices() {
102 let cs = ConstraintSystem::<Fr>::new_ref();
103
104 let x = Fr::from(5_u32);
105 let y = x * x * x + x + Fr::from(5_u32);
106
107 let test_circuit = TestCircuit::<Fr> { x, y };
108 test_circuit.generate_constraints(cs.clone()).unwrap();
109 cs.finalize();
110 assert!(cs.is_satisfied().unwrap());
111
112 let cs = cs.into_inner().unwrap();
113
114 // ensure that num_instance_variables is 2: 1 + 1 public input
115 assert_eq!(cs.num_instance_variables, 2);
116
117 let (r1cs, z) = extract_r1cs_and_z::<Fr>(&cs);
118 r1cs.check_relation(&z).unwrap();
119 // ensure that number of public inputs (l) is 1
120 assert_eq!(r1cs.l, 1);
121 }
122}