arnaucube
arnaucube/sonobePublic Self-hosted repository
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 m = cs.to_matrices().unwrap();
 12
 13    let n_rows = cs.num_constraints;
 14    let n_cols = cs.num_instance_variables + cs.num_witness_variables; // cs.num_instance_variables already counts the 1
 15
 16    let A = SparseMatrix::<F> {
 17        n_rows,
 18        n_cols,
 19        coeffs: m.a,
 20    };
 21    let B = SparseMatrix::<F> {
 22        n_rows,
 23        n_cols,
 24        coeffs: m.b,
 25    };
 26    let C = SparseMatrix::<F> {
 27        n_rows,
 28        n_cols,
 29        coeffs: m.c,
 30    };
 31
 32    // z = (1, x, w)
 33    let z: Vec<F> = [
 34        // 1 is already included in cs.instance_assignment
 35        cs.instance_assignment.clone(),
 36        cs.witness_assignment.clone(),
 37    ]
 38    .concat();
 39
 40    (
 41        R1CS::<F> {
 42            l: cs.num_instance_variables,
 43            A,
 44            B,
 45            C,
 46        },
 47        z,
 48    )
 49}
 50
 51#[cfg(test)]
 52pub mod tests {
 53    use super::*;
 54    use ark_ff::PrimeField;
 55    use ark_pallas::Fr;
 56    use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar};
 57    use ark_relations::r1cs::{
 58        ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
 59    };
 60
 61    // TestCircuit implements the R1CS for: x^3 + x + 5 = y (example from article
 62    // https://www.vitalik.ca/general/2016/12/10/qap.html )
 63    #[derive(Clone, Copy, Debug)]
 64    pub struct TestCircuit<F: PrimeField> {
 65        pub x: F,
 66        pub y: F,
 67    }
 68    impl<F: PrimeField> ConstraintSynthesizer<F> for TestCircuit<F> {
 69        fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
 70            let x = FpVar::<F>::new_input(cs.clone(), || Ok(self.x))?;
 71            let y = FpVar::<F>::new_witness(cs.clone(), || Ok(self.y))?;
 72            let five = FpVar::<F>::new_constant(cs.clone(), F::from(5u32))?;
 73
 74            let comp_y = (&x * &x * &x) + &x + &five;
 75            comp_y.enforce_equal(&y)?;
 76            Ok(())
 77        }
 78    }
 79
 80    #[test]
 81    fn test_cs_to_matrices() {
 82        let cs = ConstraintSystem::<Fr>::new_ref();
 83
 84        let x = Fr::from(5_u32);
 85        let y = x * x * x + x + Fr::from(5_u32);
 86
 87        let test_circuit = TestCircuit::<Fr> { x, y };
 88        test_circuit.generate_constraints(cs.clone()).unwrap();
 89        cs.finalize();
 90        assert!(cs.is_satisfied().unwrap());
 91
 92        let cs = cs.into_inner().unwrap();
 93
 94        // ensure that num_instance_variables is 2: 1 + 1 public input
 95        assert_eq!(cs.num_instance_variables, 2);
 96
 97        let (r1cs, z) = extract_r1cs_and_z::<Fr>(&cs);
 98        r1cs.check_relation(&z).unwrap();
 99    }
100}