arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/arith/ccs/mod.rs
folding-schemes/src/arith/ccs/mod.rsRaw
  1use ark_ff::PrimeField;
  2use ark_std::log2;
  3
  4use crate::utils::vec::{
  5    hadamard, is_zero_vec, mat_vec_mul, vec_add, vec_scalar_mul, SparseMatrix,
  6};
  7use crate::Error;
  8
  9use super::ArithSerializer;
 10use super::{r1cs::R1CS, Arith};
 11
 12pub mod circuits;
 13
 14/// CCS represents the Customizable Constraint Systems structure defined in
 15/// the [CCS paper](https://eprint.iacr.org/2023/552)
 16#[derive(Debug, Clone, Eq, PartialEq)]
 17pub struct CCS<F: PrimeField> {
 18    /// m: number of rows in M_i (such that M_i \in F^{m, n})
 19    pub m: usize,
 20    /// n = |z|, number of cols in M_i
 21    pub n: usize,
 22    /// l = |io|, size of public input/output
 23    pub l: usize,
 24    /// t = |M|, number of matrices
 25    pub t: usize,
 26    /// q = |c| = |S|, number of multisets
 27    pub q: usize,
 28    /// d: max degree in each variable
 29    pub d: usize,
 30    /// s = log(m), dimension of x
 31    pub s: usize,
 32    /// s_prime = log(n), dimension of y
 33    pub s_prime: usize,
 34
 35    /// vector of matrices
 36    pub M: Vec<SparseMatrix<F>>,
 37    /// vector of multisets
 38    pub S: Vec<Vec<usize>>,
 39    /// vector of coefficients
 40    pub c: Vec<F>,
 41}
 42
 43impl<F: PrimeField> CCS<F> {
 44    /// Evaluates the CCS relation at a given vector of assignments `z`
 45    pub fn eval_at_z(&self, z: &[F]) -> Result<Vec<F>, Error> {
 46        let mut result = vec![F::zero(); self.m];
 47
 48        for i in 0..self.q {
 49            // extract the needed M_j matrices out of S_i
 50            let vec_M_j: Vec<&SparseMatrix<F>> = self.S[i].iter().map(|j| &self.M[*j]).collect();
 51
 52            // complete the hadamard chain
 53            let mut hadamard_result = vec![F::one(); self.m];
 54            for M_j in vec_M_j.into_iter() {
 55                hadamard_result = hadamard(&hadamard_result, &mat_vec_mul(M_j, z)?)?;
 56            }
 57
 58            // multiply by the coefficient of this step
 59            let c_M_j_z = vec_scalar_mul(&hadamard_result, &self.c[i]);
 60
 61            // add it to the final vector
 62            result = vec_add(&result, &c_M_j_z)?;
 63        }
 64
 65        Ok(result)
 66    }
 67
 68    /// returns a tuple containing (w, x) (witness and public inputs respectively)
 69    pub fn split_z(&self, z: &[F]) -> (Vec<F>, Vec<F>) {
 70        (z[self.l + 1..].to_vec(), z[1..self.l + 1].to_vec())
 71    }
 72}
 73
 74impl<F: PrimeField, W: AsRef<[F]>, U: AsRef<[F]>> Arith<W, U> for CCS<F> {
 75    type Evaluation = Vec<F>;
 76
 77    fn eval_relation(&self, w: &W, u: &U) -> Result<Self::Evaluation, Error> {
 78        self.eval_at_z(&[&[F::one()], u.as_ref(), w.as_ref()].concat())
 79    }
 80
 81    fn check_evaluation(_w: &W, _u: &U, e: Self::Evaluation) -> Result<(), Error> {
 82        is_zero_vec(&e).then_some(()).ok_or(Error::NotSatisfied)
 83    }
 84}
 85
 86impl<F: PrimeField> ArithSerializer for CCS<F> {
 87    fn params_to_le_bytes(&self) -> Vec<u8> {
 88        [
 89            self.l.to_le_bytes(),
 90            self.m.to_le_bytes(),
 91            self.n.to_le_bytes(),
 92            self.t.to_le_bytes(),
 93            self.q.to_le_bytes(),
 94            self.d.to_le_bytes(),
 95        ]
 96        .concat()
 97    }
 98}
 99
100impl<F: PrimeField> From<R1CS<F>> for CCS<F> {
101    fn from(r1cs: R1CS<F>) -> Self {
102        let m = r1cs.num_constraints();
103        let n = r1cs.num_variables();
104        CCS {
105            m,
106            n,
107            l: r1cs.num_public_inputs(),
108            s: log2(m) as usize,
109            s_prime: log2(n) as usize,
110            t: 3,
111            q: 2,
112            d: 2,
113
114            S: vec![vec![0, 1], vec![2]],
115            c: vec![F::one(), F::one().neg()],
116            M: vec![r1cs.A, r1cs.B, r1cs.C],
117        }
118    }
119}
120
121#[cfg(test)]
122pub mod tests {
123    use super::*;
124    use crate::{
125        arith::r1cs::tests::{get_test_r1cs, get_test_z as r1cs_get_test_z, get_test_z_split},
126        utils::vec::is_zero_vec,
127    };
128    use ark_pallas::Fr;
129
130    pub fn get_test_ccs<F: PrimeField>() -> CCS<F> {
131        get_test_r1cs::<F>().into()
132    }
133    pub fn get_test_z<F: PrimeField>(input: usize) -> Vec<F> {
134        r1cs_get_test_z(input)
135    }
136
137    #[test]
138    fn test_eval_ccs_relation() {
139        let ccs = get_test_ccs::<Fr>();
140        let (_, x, mut w) = get_test_z_split(3);
141
142        let f_w = ccs.eval_relation(&w, &x).unwrap();
143        assert!(is_zero_vec(&f_w));
144
145        w[1] = Fr::from(111);
146        let f_w = ccs.eval_relation(&w, &x).unwrap();
147        assert!(!is_zero_vec(&f_w));
148    }
149
150    /// Test that a basic CCS relation can be satisfied
151    #[test]
152    fn test_check_ccs_relation() {
153        let ccs = get_test_ccs::<Fr>();
154        let (_, x, w) = get_test_z_split(3);
155
156        ccs.check_relation(&w, &x).unwrap();
157    }
158}