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