arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/utils/gadgets.rs
folding-schemes/src/utils/gadgets.rsRaw
  1use ark_ff::PrimeField;
  2use ark_r1cs_std::{
  3    alloc::{AllocVar, AllocationMode},
  4    fields::{fp::FpVar, FieldVar},
  5    R1CSVar,
  6};
  7use ark_relations::r1cs::{Namespace, SynthesisError};
  8use core::{borrow::Borrow, marker::PhantomData};
  9
 10use crate::utils::vec::SparseMatrix;
 11
 12pub trait MatrixGadget<FV> {
 13    fn mul_vector(&self, v: &[FV]) -> Result<Vec<FV>, SynthesisError>;
 14}
 15
 16pub trait VectorGadget<FV> {
 17    fn add(&self, other: &Self) -> Result<Vec<FV>, SynthesisError>;
 18
 19    fn mul_scalar(&self, other: &FV) -> Result<Vec<FV>, SynthesisError>;
 20
 21    fn hadamard(&self, other: &Self) -> Result<Vec<FV>, SynthesisError>;
 22}
 23
 24impl<F: PrimeField> VectorGadget<FpVar<F>> for [FpVar<F>] {
 25    fn add(&self, other: &Self) -> Result<Vec<FpVar<F>>, SynthesisError> {
 26        if self.len() != other.len() {
 27            return Err(SynthesisError::Unsatisfiable);
 28        }
 29        Ok(self.iter().zip(other.iter()).map(|(a, b)| a + b).collect())
 30    }
 31
 32    fn mul_scalar(&self, c: &FpVar<F>) -> Result<Vec<FpVar<F>>, SynthesisError> {
 33        Ok(self.iter().map(|a| a * c).collect())
 34    }
 35
 36    fn hadamard(&self, other: &Self) -> Result<Vec<FpVar<F>>, SynthesisError> {
 37        if self.len() != other.len() {
 38            return Err(SynthesisError::Unsatisfiable);
 39        }
 40        Ok(self.iter().zip(other.iter()).map(|(a, b)| a * b).collect())
 41    }
 42}
 43
 44#[derive(Debug, Clone)]
 45pub struct SparseMatrixVar<F: PrimeField, CF: PrimeField, FV: AllocVar<F, CF>> {
 46    _f: PhantomData<F>,
 47    _cf: PhantomData<CF>,
 48    _fv: PhantomData<FV>,
 49    pub n_rows: usize,
 50    pub n_cols: usize,
 51    // same format as the native SparseMatrix (which follows ark_relations::r1cs::Matrix format
 52    pub coeffs: Vec<Vec<(FV, usize)>>,
 53}
 54
 55impl<F, CF, FV> AllocVar<SparseMatrix<F>, CF> for SparseMatrixVar<F, CF, FV>
 56where
 57    F: PrimeField,
 58    CF: PrimeField,
 59    FV: AllocVar<F, CF>,
 60{
 61    fn new_variable<T: Borrow<SparseMatrix<F>>>(
 62        cs: impl Into<Namespace<CF>>,
 63        f: impl FnOnce() -> Result<T, SynthesisError>,
 64        mode: AllocationMode,
 65    ) -> Result<Self, SynthesisError> {
 66        f().and_then(|val| {
 67            let cs = cs.into();
 68
 69            let mut coeffs: Vec<Vec<(FV, usize)>> = Vec::new();
 70            for row in val.borrow().coeffs.iter() {
 71                let mut rowVar: Vec<(FV, usize)> = Vec::new();
 72                for &(value, col_i) in row.iter() {
 73                    let coeffVar = FV::new_variable(cs.clone(), || Ok(value), mode)?;
 74                    rowVar.push((coeffVar, col_i));
 75                }
 76                coeffs.push(rowVar);
 77            }
 78
 79            Ok(Self {
 80                _f: PhantomData,
 81                _cf: PhantomData,
 82                _fv: PhantomData,
 83                n_rows: val.borrow().n_rows,
 84                n_cols: val.borrow().n_cols,
 85                coeffs,
 86            })
 87        })
 88    }
 89}
 90
 91impl<F: PrimeField> MatrixGadget<FpVar<F>> for SparseMatrixVar<F, F, FpVar<F>> {
 92    fn mul_vector(&self, v: &[FpVar<F>]) -> Result<Vec<FpVar<F>>, SynthesisError> {
 93        Ok(self
 94            .coeffs
 95            .iter()
 96            .map(|row| {
 97                let products = row
 98                    .iter()
 99                    .map(|(value, col_i)| value * &v[*col_i])
100                    .collect::<Vec<_>>();
101                if products.is_constant() {
102                    FpVar::constant(products.value().unwrap_or_default().into_iter().sum())
103                } else {
104                    products.iter().sum()
105                }
106            })
107            .collect())
108    }
109}