arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/src/ccs/r1cs.rs
src/ccs/r1cs.rsRaw
  1use ark_ff::PrimeField;
  2
  3use crate::utils::vec::*;
  4use crate::Error;
  5
  6#[derive(Debug, Clone, Eq, PartialEq)]
  7pub struct R1CS<F: PrimeField> {
  8    pub l: usize, // io len
  9    pub A: SparseMatrix<F>,
 10    pub B: SparseMatrix<F>,
 11    pub C: SparseMatrix<F>,
 12}
 13
 14impl<F: PrimeField> R1CS<F> {
 15    /// returns a tuple containing (w, x) (witness and public inputs respectively)
 16    pub fn split_z(&self, z: &[F]) -> (Vec<F>, Vec<F>) {
 17        (z[self.l + 1..].to_vec(), z[1..self.l + 1].to_vec())
 18    }
 19
 20    /// check that a R1CS structure is satisfied by a z vector. Only for testing.
 21    pub fn check_relation(&self, z: &[F]) -> Result<(), Error> {
 22        let Az = mat_vec_mul_sparse(&self.A, z);
 23        let Bz = mat_vec_mul_sparse(&self.B, z);
 24        let Cz = mat_vec_mul_sparse(&self.C, z);
 25        let AzBz = hadamard(&Az, &Bz);
 26        assert_eq!(AzBz, Cz);
 27
 28        Ok(())
 29    }
 30
 31    /// converts the R1CS instance into a RelaxedR1CS as described in
 32    /// [Nova](https://eprint.iacr.org/2021/370.pdf) section 4.1.
 33    pub fn relax(self) -> RelaxedR1CS<F> {
 34        RelaxedR1CS::<F> {
 35            l: self.l,
 36            E: vec![F::zero(); self.A.n_rows],
 37            A: self.A,
 38            B: self.B,
 39            C: self.C,
 40            u: F::one(),
 41        }
 42    }
 43}
 44
 45#[derive(Debug, Clone, Eq, PartialEq)]
 46pub struct RelaxedR1CS<F: PrimeField> {
 47    pub l: usize, // io len
 48    pub A: SparseMatrix<F>,
 49    pub B: SparseMatrix<F>,
 50    pub C: SparseMatrix<F>,
 51    pub u: F,
 52    pub E: Vec<F>,
 53}
 54impl<F: PrimeField> RelaxedR1CS<F> {
 55    /// check that a RelaxedR1CS structure is satisfied by a z vector. Only for testing.
 56    pub fn check_relation(&self, z: &[F]) -> Result<(), Error> {
 57        let Az = mat_vec_mul_sparse(&self.A, z);
 58        let Bz = mat_vec_mul_sparse(&self.B, z);
 59        let Cz = mat_vec_mul_sparse(&self.C, z);
 60        let uCz = vec_scalar_mul(&Cz, &self.u);
 61        let uCzE = vec_add(&uCz, &self.E);
 62        let AzBz = hadamard(&Az, &Bz);
 63        assert_eq!(AzBz, uCzE);
 64
 65        Ok(())
 66    }
 67}
 68
 69#[cfg(test)]
 70pub mod tests {
 71    use super::*;
 72    use crate::utils::vec::tests::{to_F_matrix, to_F_vec};
 73    use ark_pallas::Fr;
 74
 75    pub fn get_test_r1cs<F: PrimeField>() -> R1CS<F> {
 76        // R1CS for: x^3 + x + 5 = y (example from article
 77        // https://www.vitalik.ca/general/2016/12/10/qap.html )
 78        let A = to_F_matrix::<F>(vec![
 79            vec![0, 1, 0, 0, 0, 0],
 80            vec![0, 0, 0, 1, 0, 0],
 81            vec![0, 1, 0, 0, 1, 0],
 82            vec![5, 0, 0, 0, 0, 1],
 83        ]);
 84        let B = to_F_matrix::<F>(vec![
 85            vec![0, 1, 0, 0, 0, 0],
 86            vec![0, 1, 0, 0, 0, 0],
 87            vec![1, 0, 0, 0, 0, 0],
 88            vec![1, 0, 0, 0, 0, 0],
 89        ]);
 90        let C = to_F_matrix::<F>(vec![
 91            vec![0, 0, 0, 1, 0, 0],
 92            vec![0, 0, 0, 0, 1, 0],
 93            vec![0, 0, 0, 0, 0, 1],
 94            vec![0, 0, 1, 0, 0, 0],
 95        ]);
 96
 97        R1CS::<F> { l: 1, A, B, C }
 98    }
 99
100    pub fn get_test_z<F: PrimeField>(input: usize) -> Vec<F> {
101        // z = (1, io, w)
102        to_F_vec(vec![
103            1,
104            input,                             // io
105            input * input * input + input + 5, // x^3 + x + 5
106            input * input,                     // x^2
107            input * input * input,             // x^2 * x
108            input * input * input + input,     // x^3 + x
109        ])
110    }
111
112    #[test]
113    fn test_check_relation() {
114        let r1cs = get_test_r1cs::<Fr>();
115        let z = get_test_z(5);
116        r1cs.check_relation(&z).unwrap();
117        r1cs.relax().check_relation(&z).unwrap();
118    }
119}