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}
 56
 57impl<F: PrimeField> RelaxedR1CS<F> {
 58    /// check that a RelaxedR1CS structure is satisfied by a z vector. Only for testing.
 59    pub fn check_relation(&self, z: &[F]) -> Result<(), Error> {
 60        let Az = mat_vec_mul_sparse(&self.A, z);
 61        let Bz = mat_vec_mul_sparse(&self.B, z);
 62        let Cz = mat_vec_mul_sparse(&self.C, z);
 63        let uCz = vec_scalar_mul(&Cz, &self.u);
 64        let uCzE = vec_add(&uCz, &self.E);
 65        let AzBz = hadamard(&Az, &Bz);
 66        if AzBz != uCzE {
 67            return Err(Error::NotSatisfied);
 68        }
 69
 70        Ok(())
 71    }
 72}
 73
 74#[cfg(test)]
 75pub mod tests {
 76    use super::*;
 77    use crate::utils::vec::tests::{to_F_matrix, to_F_vec};
 78    use ark_pallas::Fr;
 79
 80    pub fn get_test_r1cs<F: PrimeField>() -> R1CS<F> {
 81        // R1CS for: x^3 + x + 5 = y (example from article
 82        // https://www.vitalik.ca/general/2016/12/10/qap.html )
 83        let A = to_F_matrix::<F>(vec![
 84            vec![0, 1, 0, 0, 0, 0],
 85            vec![0, 0, 0, 1, 0, 0],
 86            vec![0, 1, 0, 0, 1, 0],
 87            vec![5, 0, 0, 0, 0, 1],
 88        ]);
 89        let B = to_F_matrix::<F>(vec![
 90            vec![0, 1, 0, 0, 0, 0],
 91            vec![0, 1, 0, 0, 0, 0],
 92            vec![1, 0, 0, 0, 0, 0],
 93            vec![1, 0, 0, 0, 0, 0],
 94        ]);
 95        let C = to_F_matrix::<F>(vec![
 96            vec![0, 0, 0, 1, 0, 0],
 97            vec![0, 0, 0, 0, 1, 0],
 98            vec![0, 0, 0, 0, 0, 1],
 99            vec![0, 0, 1, 0, 0, 0],
100        ]);
101
102        R1CS::<F> { l: 1, A, B, C }
103    }
104
105    pub fn get_test_z<F: PrimeField>(input: usize) -> Vec<F> {
106        // z = (1, io, w)
107        to_F_vec(vec![
108            1,
109            input,                             // io
110            input * input * input + input + 5, // x^3 + x + 5
111            input * input,                     // x^2
112            input * input * input,             // x^2 * x
113            input * input * input + input,     // x^3 + x
114        ])
115    }
116
117    #[test]
118    fn test_check_relation() {
119        let r1cs = get_test_r1cs::<Fr>();
120        let z = get_test_z(5);
121        r1cs.check_relation(&z).unwrap();
122        r1cs.relax().check_relation(&z).unwrap();
123    }
124}