arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/arith/ccs.rs
folding-schemes/src/arith/ccs.rsRaw
  1use ark_ff::PrimeField;
  2use ark_std::log2;
  3
  4use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, SparseMatrix};
  5use crate::Error;
  6
  7use super::{r1cs::R1CS, Arith};
  8
  9/// CCS represents the Customizable Constraint Systems structure defined in
 10/// the [CCS paper](https://eprint.iacr.org/2023/552)
 11#[derive(Debug, Clone, Eq, PartialEq)]
 12pub struct CCS<F: PrimeField> {
 13    /// m: number of rows in M_i (such that M_i \in F^{m, n})
 14    pub m: usize,
 15    /// n = |z|, number of cols in M_i
 16    pub n: usize,
 17    /// l = |io|, size of public input/output
 18    pub l: usize,
 19    /// t = |M|, number of matrices
 20    pub t: usize,
 21    /// q = |c| = |S|, number of multisets
 22    pub q: usize,
 23    /// d: max degree in each variable
 24    pub d: usize,
 25    /// s = log(m), dimension of x
 26    pub s: usize,
 27    /// s_prime = log(n), dimension of y
 28    pub s_prime: usize,
 29
 30    /// vector of matrices
 31    pub M: Vec<SparseMatrix<F>>,
 32    /// vector of multisets
 33    pub S: Vec<Vec<usize>>,
 34    /// vector of coefficients
 35    pub c: Vec<F>,
 36}
 37
 38impl<F: PrimeField> Arith<F> for CCS<F> {
 39    /// check that a CCS structure is satisfied by a z vector. Only for testing.
 40    fn check_relation(&self, z: &[F]) -> Result<(), Error> {
 41        let mut result = vec![F::zero(); self.m];
 42
 43        for i in 0..self.q {
 44            // extract the needed M_j matrices out of S_i
 45            let vec_M_j: Vec<&SparseMatrix<F>> = self.S[i].iter().map(|j| &self.M[*j]).collect();
 46
 47            // complete the hadamard chain
 48            let mut hadamard_result = vec![F::one(); self.m];
 49            for M_j in vec_M_j.into_iter() {
 50                hadamard_result = hadamard(&hadamard_result, &mat_vec_mul(M_j, z)?)?;
 51            }
 52
 53            // multiply by the coefficient of this step
 54            let c_M_j_z = vec_scalar_mul(&hadamard_result, &self.c[i]);
 55
 56            // add it to the final vector
 57            result = vec_add(&result, &c_M_j_z)?;
 58        }
 59
 60        // make sure the final vector is all zeroes
 61        for e in result {
 62            if !e.is_zero() {
 63                return Err(Error::NotSatisfied);
 64            }
 65        }
 66
 67        Ok(())
 68    }
 69
 70    fn params_to_bytes(&self) -> Vec<u8> {
 71        [
 72            self.l.to_le_bytes(),
 73            self.m.to_le_bytes(),
 74            self.n.to_le_bytes(),
 75            self.t.to_le_bytes(),
 76            self.q.to_le_bytes(),
 77            self.d.to_le_bytes(),
 78        ]
 79        .concat()
 80    }
 81}
 82
 83impl<F: PrimeField> CCS<F> {
 84    pub fn from_r1cs(r1cs: R1CS<F>) -> Self {
 85        let m = r1cs.A.n_rows;
 86        let n = r1cs.A.n_cols;
 87        CCS {
 88            m,
 89            n,
 90            l: r1cs.l,
 91            s: log2(m) as usize,
 92            s_prime: log2(n) as usize,
 93            t: 3,
 94            q: 2,
 95            d: 2,
 96
 97            S: vec![vec![0, 1], vec![2]],
 98            c: vec![F::one(), F::one().neg()],
 99            M: vec![r1cs.A, r1cs.B, r1cs.C],
100        }
101    }
102
103    pub fn to_r1cs(self) -> R1CS<F> {
104        R1CS::<F> {
105            l: self.l,
106            A: self.M[0].clone(),
107            B: self.M[1].clone(),
108            C: self.M[2].clone(),
109        }
110    }
111}
112
113#[cfg(test)]
114pub mod tests {
115    use super::*;
116    use crate::arith::r1cs::tests::{get_test_r1cs, get_test_z as r1cs_get_test_z};
117    use ark_pallas::Fr;
118
119    pub fn get_test_ccs<F: PrimeField>() -> CCS<F> {
120        let r1cs = get_test_r1cs::<F>();
121        CCS::<F>::from_r1cs(r1cs)
122    }
123    pub fn get_test_z<F: PrimeField>(input: usize) -> Vec<F> {
124        r1cs_get_test_z(input)
125    }
126
127    /// Test that a basic CCS relation can be satisfied
128    #[test]
129    fn test_ccs_relation() {
130        let ccs = get_test_ccs::<Fr>();
131        let z = get_test_z(3);
132
133        ccs.check_relation(&z).unwrap();
134    }
135}