arnaucube
arnaucube/fold-babyjubjubsPublic Self-hosted repository
fold-babyjubjubs/src/fcircuit.rs
src/fcircuit.rsRaw
  1use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
  2use ark_ec::CurveGroup;
  3use ark_ff::{BigInteger, Field, PrimeField};
  4use ark_r1cs_std::alloc::{AllocVar, AllocationMode};
  5use ark_r1cs_std::prelude::CurveVar;
  6use ark_r1cs_std::{
  7    boolean::Boolean,
  8    eq::EqGadget,
  9    fields::{fp::FpVar, FieldVar},
 10};
 11use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};
 12use ark_std::{marker::PhantomData, Zero};
 13use core::borrow::Borrow;
 14use std::fmt::Debug;
 15
 16use arkeddsa::{constraints::verify, signature::Signature, PublicKey};
 17use folding_schemes::{frontend::FCircuit, Error};
 18
 19pub type CF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
 20
 21/// Test circuit to be folded
 22#[derive(Clone, Debug)]
 23pub struct FoldSigsStepCircuit<
 24    F: PrimeField,
 25    C: CurveGroup,
 26    GC: CurveVar<C, F>,
 27    const SIGS_PER_STEP: usize,
 28> {
 29    _c: PhantomData<C>,
 30    _gc: PhantomData<GC>,
 31    config: PoseidonConfig<F>,
 32}
 33impl<F: PrimeField, C: CurveGroup, GC: CurveVar<C, F>, const SIGS_PER_STEP: usize> FCircuit<F>
 34    for FoldSigsStepCircuit<F, C, GC, SIGS_PER_STEP>
 35where
 36    F: Absorb,
 37    C: CurveGroup<BaseField = F>,
 38{
 39    type Params = PoseidonConfig<F>;
 40    type ExternalInputs = VecExtInp<C, SIGS_PER_STEP>;
 41    type ExternalInputsVar = VecExtInpVar<C, GC, SIGS_PER_STEP>;
 42
 43    fn new(config: Self::Params) -> Result<Self, Error> {
 44        Ok(Self {
 45            _c: PhantomData,
 46            _gc: PhantomData,
 47            config,
 48        })
 49    }
 50    fn state_len(&self) -> usize {
 51        1
 52    }
 53    fn generate_step_constraints(
 54        &self,
 55        cs: ConstraintSystemRef<F>,
 56        _i: usize,
 57        z_i: Vec<FpVar<F>>,
 58        external_inputs: Self::ExternalInputsVar,
 59    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 60        let mut count = z_i[0].clone();
 61        for i in 0..SIGS_PER_STEP {
 62            let e = external_inputs.0[i].clone();
 63            let res = verify::<C, GC>(
 64                cs.clone(),
 65                self.config.clone(),
 66                e.pk,
 67                (e.sig_r, e.sig_s),
 68                e.msg,
 69            )?;
 70            res.enforce_equal(&Boolean::<F>::TRUE)?;
 71            count = count.clone() + FpVar::<F>::one();
 72        }
 73
 74        Ok(vec![count])
 75    }
 76}
 77
 78// recall, here C = ed_on_bn254, so C::BaseField = BN254::ScalarField
 79#[derive(Clone, Copy, Debug, PartialEq)]
 80pub struct ExtInp<C: CurveGroup> {
 81    msg: CF<C>,
 82    pk: PublicKey<C>,
 83    sig: Signature<C>,
 84}
 85impl<C: CurveGroup> Default for ExtInp<C> {
 86    fn default() -> Self {
 87        Self {
 88            msg: CF::<C>::zero(),
 89            pk: PublicKey(C::zero().into_affine()),
 90            sig: Signature::new(C::zero().into_affine(), C::ScalarField::zero()),
 91        }
 92    }
 93}
 94
 95#[derive(Clone, Debug)]
 96pub struct VecExtInp<C: CurveGroup, const SIGS_PER_STEP: usize>(Vec<ExtInp<C>>);
 97impl<C: CurveGroup, const SIGS_PER_STEP: usize> Default for VecExtInp<C, SIGS_PER_STEP> {
 98    fn default() -> Self {
 99        VecExtInp(vec![ExtInp::default(); SIGS_PER_STEP])
100    }
101}
102
103#[derive(Clone, Debug)]
104pub struct ExtInpVar<C: CurveGroup, GC: CurveVar<C, CF<C>>> {
105    msg: FpVar<CF<C>>,
106    pk: GC,
107    sig_r: GC,
108    sig_s: Vec<Boolean<CF<C>>>,
109}
110impl<C: CurveGroup, GC: CurveVar<C, CF<C>>> Default for ExtInpVar<C, GC> {
111    fn default() -> Self {
112        Self {
113            msg: FpVar::<CF<C>>::zero(),
114            pk: GC::zero(),
115            sig_r: GC::zero(),
116            sig_s: vec![Boolean::<CF<C>>::FALSE; 253], // TODO 253-> fieldbitsize
117        }
118    }
119}
120
121#[derive(Clone, Debug)]
122pub struct VecExtInpVar<C: CurveGroup, GC: CurveVar<C, CF<C>>, const SIGS_PER_STEP: usize>(
123    Vec<ExtInpVar<C, GC>>,
124);
125impl<C: CurveGroup, GC: CurveVar<C, CF<C>>, const SIGS_PER_STEP: usize> Default
126    for VecExtInpVar<C, GC, SIGS_PER_STEP>
127{
128    fn default() -> Self {
129        VecExtInpVar(vec![ExtInpVar::default(); SIGS_PER_STEP])
130    }
131}
132
133impl<C, GC, const SIGS_PER_STEP: usize> AllocVar<VecExtInp<C, SIGS_PER_STEP>, CF<C>>
134    for VecExtInpVar<C, GC, SIGS_PER_STEP>
135where
136    C: CurveGroup,
137    GC: CurveVar<C, CF<C>>,
138{
139    fn new_variable<T: Borrow<VecExtInp<C, SIGS_PER_STEP>>>(
140        cs: impl Into<Namespace<CF<C>>>,
141        f: impl FnOnce() -> Result<T, SynthesisError>,
142        mode: AllocationMode,
143    ) -> Result<Self, SynthesisError> {
144        f().and_then(|val| {
145            let cs = cs.into();
146
147            let mut v = vec![];
148            for e in val.borrow().0.iter() {
149                let msg = FpVar::<CF<C>>::new_variable(cs.clone(), || Ok(e.msg), mode)?;
150                let pk = GC::new_variable(cs.clone(), || Ok(e.pk.0), mode)?;
151                let sig_r = GC::new_variable(cs.clone(), || Ok(e.sig.r), mode)?;
152                let sig_s = Vec::<Boolean<CF<C>>>::new_variable(
153                    cs.clone(),
154                    || Ok(e.sig.s.into_bigint().to_bits_le()),
155                    mode,
156                )?;
157                v.push(ExtInpVar {
158                    msg,
159                    pk,
160                    sig_r,
161                    sig_s,
162                });
163            }
164
165            Ok(Self(v))
166        })
167    }
168}
169
170#[cfg(test)]
171pub mod tests {
172    use super::*;
173    use ark_bn254::Fr;
174    use ark_ec::AdditiveGroup;
175    use ark_r1cs_std::{alloc::AllocVar, R1CSVar};
176    use ark_relations::r1cs::ConstraintSystem;
177    use ark_std::rand::Rng;
178    use rand_core::CryptoRngCore;
179    use std::str::FromStr;
180
181    use folding_schemes::transcript::poseidon::poseidon_canonical_config;
182
183    use arkeddsa::{
184        ed_on_bn254_twist::{constraints::EdwardsVar, EdwardsProjective},
185        SigningKey,
186    };
187
188    pub fn gen_signatures<R: Rng + CryptoRngCore, const SIGS_PER_STEP: usize>(
189        rng: &mut R,
190        poseidon_config: &PoseidonConfig<Fr>,
191        steps: usize,
192    ) -> Vec<VecExtInp<EdwardsProjective, SIGS_PER_STEP>> {
193        let mut r = vec![];
194        for _ in 0..steps {
195            let mut res: Vec<ExtInp<EdwardsProjective>> = Vec::new();
196            for _ in 0..SIGS_PER_STEP {
197                let sk =
198                    SigningKey::<EdwardsProjective>::generate::<blake2::Blake2b512>(rng).unwrap();
199                let msg = Fr::from_str("12345").unwrap();
200                let sig = sk
201                    .sign::<blake2::Blake2b512>(&poseidon_config, &msg)
202                    .unwrap();
203                let pk = sk.public_key();
204                pk.verify(&poseidon_config, &msg, &sig).unwrap();
205                res.push(ExtInp {
206                    msg,
207                    pk: pk.clone(),
208                    sig,
209                });
210            }
211            r.push(VecExtInp(res));
212        }
213        r
214    }
215
216    #[test]
217    fn test_sig() {
218        const SIGS_PER_STEP: usize = 10;
219        let mut rng = rand::rngs::OsRng;
220        let poseidon_config = poseidon_canonical_config::<Fr>();
221
222        const N: usize = 1;
223        let ext_inps =
224            gen_signatures::<rand::rngs::OsRng, SIGS_PER_STEP>(&mut rng, &poseidon_config, 1);
225        let e = ext_inps[0].0[0].clone();
226        e.pk.verify(&poseidon_config, &e.msg, &e.sig).unwrap();
227    }
228
229    fn ensure_fcircuit_trait<FC: FCircuit<Fr>>(params: FC::Params) {
230        let _ = FC::new(params);
231    }
232
233    // test to check that the Sha256FCircuit computes the same values inside and outside the circuit
234    #[test]
235    fn test_fcircuit() {
236        const SIGS_PER_STEP: usize = 10;
237        let mut rng = rand::rngs::OsRng;
238        let poseidon_config = poseidon_canonical_config::<Fr>();
239
240        let ext_inps =
241            gen_signatures::<rand::rngs::OsRng, SIGS_PER_STEP>(&mut rng, &poseidon_config, 1);
242        let ext_inps = ext_inps[0].clone();
243
244        // here `Fr` is the BN254::G1::Fr = ed_on_bn254_twist::EdwardsProjective::Fq
245        let cs = ConstraintSystem::<Fr>::new_ref();
246
247        type FC = FoldSigsStepCircuit<Fr, EdwardsProjective, EdwardsVar, SIGS_PER_STEP>;
248        ensure_fcircuit_trait::<FC>(poseidon_config.clone());
249
250        let circuit = FC::new(poseidon_config).unwrap();
251        let z_i = vec![Fr::ZERO];
252
253        let external_inputs_var =
254            VecExtInpVar::<EdwardsProjective, EdwardsVar, SIGS_PER_STEP>::new_witness(
255                cs.clone(),
256                || Ok(ext_inps),
257            )
258            .unwrap();
259
260        let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i)).unwrap();
261        let computed_z_i1Var = circuit
262            .generate_step_constraints(cs.clone(), 0, z_iVar.clone(), external_inputs_var)
263            .unwrap();
264        assert_eq!(
265            computed_z_i1Var.value().unwrap(),
266            vec![Fr::from(SIGS_PER_STEP as u32)]
267        );
268        assert!(cs.is_satisfied().unwrap());
269        dbg!(cs.num_constraints());
270        dbg!(&computed_z_i1Var.value().unwrap());
271    }
272}