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 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#[cfg(test)]
 63pub mod tests {
 64    use super::*;
 65    use ark_ff::PrimeField;
 66    use ark_pallas::Fr;
 67    use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar};
 68    use ark_relations::r1cs::{
 69        ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
 70    };
 71
 72    // TestCircuit implements the R1CS for: x^3 + x + 5 = y (example from article
 73    // https://www.vitalik.ca/general/2016/12/10/qap.html )
 74    #[derive(Clone, Copy, Debug)]
 75    pub struct TestCircuit<F: PrimeField> {
 76        pub x: F,
 77        pub y: F,
 78    }
 79    impl<F: PrimeField> ConstraintSynthesizer<F> for TestCircuit<F> {
 80        fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
 81            let x = FpVar::<F>::new_input(cs.clone(), || Ok(self.x))?;
 82            let y = FpVar::<F>::new_witness(cs.clone(), || Ok(self.y))?;
 83            let five = FpVar::<F>::new_constant(cs.clone(), F::from(5u32))?;
 84
 85            let comp_y = (&x * &x * &x) + &x + &five;
 86            comp_y.enforce_equal(&y)?;
 87            Ok(())
 88        }
 89    }
 90
 91    #[test]
 92    fn test_cs_to_matrices() {
 93        let cs = ConstraintSystem::<Fr>::new_ref();
 94
 95        let x = Fr::from(5_u32);
 96        let y = x * x * x + x + Fr::from(5_u32);
 97
 98        let test_circuit = TestCircuit::<Fr> { x, y };
 99        test_circuit.generate_constraints(cs.clone()).unwrap();
100        cs.finalize();
101        assert!(cs.is_satisfied().unwrap());
102
103        let cs = cs.into_inner().unwrap();
104
105        // ensure that num_instance_variables is 2: 1 + 1 public input
106        assert_eq!(cs.num_instance_variables, 2);
107
108        let (r1cs, z) = extract_r1cs_and_z::<Fr>(&cs);
109        r1cs.check_relation(&z).unwrap();
110        // ensure that number of public inputs (l) is 1
111        assert_eq!(r1cs.l, 1);
112    }
113}