arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/folding/protogalaxy/traits.rs
folding-schemes/src/folding/protogalaxy/traits.rsRaw
  1use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, Absorb};
  2use ark_ec::CurveGroup;
  3use ark_ff::PrimeField;
  4use ark_r1cs_std::{fields::fp::FpVar, uint8::UInt8, ToConstraintFieldGadget};
  5use ark_relations::r1cs::SynthesisError;
  6use ark_std::{cfg_into_iter, log2, One};
  7use rayon::prelude::*;
  8
  9use super::{constants::RUNNING, utils::pow_i, CommittedInstance, CommittedInstanceVar, Witness};
 10use crate::{
 11    arith::{r1cs::R1CS, Arith},
 12    folding::circuits::CF1,
 13    transcript::AbsorbNonNative,
 14    utils::vec::is_zero_vec,
 15    Error,
 16};
 17
 18// Implements the trait for absorbing ProtoGalaxy's CommittedInstance.
 19impl<C: CurveGroup, const TYPE: bool> Absorb for CommittedInstance<C, TYPE>
 20where
 21    C::ScalarField: Absorb,
 22{
 23    fn to_sponge_bytes(&self, dest: &mut Vec<u8>) {
 24        C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest);
 25    }
 26
 27    fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
 28        self.phi
 29            .to_native_sponge_field_elements_as_vec()
 30            .to_sponge_field_elements(dest);
 31        self.betas.to_sponge_field_elements(dest);
 32        self.e.to_sponge_field_elements(dest);
 33        self.x.to_sponge_field_elements(dest);
 34    }
 35}
 36
 37// Implements the trait for absorbing ProtoGalaxy's CommittedInstanceVar in-circuit.
 38impl<C: CurveGroup, const TYPE: bool> AbsorbGadget<C::ScalarField>
 39    for CommittedInstanceVar<C, TYPE>
 40{
 41    fn to_sponge_bytes(&self) -> Result<Vec<UInt8<C::ScalarField>>, SynthesisError> {
 42        FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?)
 43    }
 44
 45    fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
 46        Ok([
 47            self.phi.to_constraint_field()?,
 48            self.betas.to_sponge_field_elements()?,
 49            self.e.to_sponge_field_elements()?,
 50            self.x.to_sponge_field_elements()?,
 51        ]
 52        .concat())
 53    }
 54}
 55
 56/// Implements `Arith` for R1CS, where the witness is of type [`Witness`], and
 57/// the committed instance is of type [`CommittedInstance`].
 58///
 59/// Due to the error term `CommittedInstance.e`, R1CS here is considered as a
 60/// relaxed R1CS.
 61///
 62/// See `nova/traits.rs` for the rationale behind the design.
 63impl<C: CurveGroup, const TYPE: bool> Arith<Witness<CF1<C>>, CommittedInstance<C, TYPE>>
 64    for R1CS<CF1<C>>
 65{
 66    type Evaluation = Vec<CF1<C>>;
 67
 68    fn eval_relation(
 69        &self,
 70        w: &Witness<CF1<C>>,
 71        u: &CommittedInstance<C, TYPE>,
 72    ) -> Result<Self::Evaluation, Error> {
 73        self.eval_at_z(&[&[C::ScalarField::one()][..], &u.x, &w.w].concat())
 74    }
 75
 76    fn check_evaluation(
 77        _w: &Witness<C::ScalarField>,
 78        u: &CommittedInstance<C, TYPE>,
 79        e: Vec<C::ScalarField>,
 80    ) -> Result<(), Error> {
 81        let ok = if TYPE == RUNNING {
 82            if u.betas.len() != log2(e.len()) as usize {
 83                return Err(Error::NotSameLength(
 84                    "instance.betas.len()".to_string(),
 85                    u.betas.len(),
 86                    "log2(e.len())".to_string(),
 87                    log2(e.len()) as usize,
 88                ));
 89            }
 90
 91            u.e == cfg_into_iter!(e)
 92                .enumerate()
 93                .map(|(i, e_i)| pow_i(i, &u.betas) * e_i)
 94                .sum::<CF1<C>>()
 95        } else {
 96            is_zero_vec(&e)
 97        };
 98        ok.then_some(()).ok_or(Error::NotSatisfied)
 99    }
100}
101
102#[cfg(test)]
103pub mod tests {
104    use super::*;
105    use ark_bn254::{Fr, G1Projective as Projective};
106    use ark_r1cs_std::{alloc::AllocVar, R1CSVar};
107    use ark_relations::r1cs::ConstraintSystem;
108    use ark_std::UniformRand;
109    use rand::Rng;
110
111    /// test that checks the native CommittedInstance.to_sponge_{bytes,field_elements}
112    /// vs the R1CS constraints version
113    #[test]
114    pub fn test_committed_instance_to_sponge_preimage() {
115        let mut rng = ark_std::test_rng();
116
117        let t = rng.gen::<u8>() as usize;
118        let io_len = rng.gen::<u8>() as usize;
119
120        let ci = CommittedInstance::<Projective, true> {
121            phi: Projective::rand(&mut rng),
122            betas: (0..t).map(|_| Fr::rand(&mut rng)).collect(),
123            e: Fr::rand(&mut rng),
124            x: (0..io_len).map(|_| Fr::rand(&mut rng)).collect(),
125        };
126
127        let bytes = ci.to_sponge_bytes_as_vec();
128        let field_elements = ci.to_sponge_field_elements_as_vec();
129
130        let cs = ConstraintSystem::<Fr>::new_ref();
131
132        let ciVar =
133            CommittedInstanceVar::<Projective, true>::new_witness(cs.clone(), || Ok(ci.clone()))
134                .unwrap();
135        let bytes_var = ciVar.to_sponge_bytes().unwrap();
136        let field_elements_var = ciVar.to_sponge_field_elements().unwrap();
137
138        assert!(cs.is_satisfied().unwrap());
139
140        // check that the natively computed and in-circuit computed hashes match
141        assert_eq!(bytes_var.value().unwrap(), bytes);
142        assert_eq!(field_elements_var.value().unwrap(), field_elements);
143    }
144}