arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes-solidity/src/verifiers/mod.rs
folding-schemes-solidity/src/verifiers/mod.rsRaw
  1pub mod templates;
  2
  3#[cfg(test)]
  4mod tests {
  5    use crate::evm::{compile_solidity, save_solidity, Evm};
  6    use crate::verifiers::templates::{Groth16Verifier, KZG10Verifier};
  7    use ark_bn254::{Bn254, Fr, G1Projective as G1};
  8    use ark_crypto_primitives::snark::{CircuitSpecificSetupSNARK, SNARK};
  9    use ark_ec::{AffineRepr, CurveGroup};
 10    use ark_ff::{BigInt, BigInteger, PrimeField};
 11    use ark_groth16::Groth16;
 12    use ark_poly_commit::kzg10::VerifierKey;
 13    use ark_r1cs_std::alloc::AllocVar;
 14    use ark_r1cs_std::eq::EqGadget;
 15    use ark_r1cs_std::fields::fp::FpVar;
 16    use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
 17    use ark_std::rand::{RngCore, SeedableRng};
 18    use ark_std::Zero;
 19    use ark_std::{test_rng, UniformRand};
 20    use askama::Template;
 21    use folding_schemes::{
 22        commitment::{
 23            kzg::{KZGProver, KZGSetup, ProverKey},
 24            CommitmentProver,
 25        },
 26        transcript::{
 27            poseidon::{poseidon_test_config, PoseidonTranscript},
 28            Transcript,
 29        },
 30    };
 31    use itertools::chain;
 32    use std::marker::PhantomData;
 33
 34    // Function signatures for proof verification on kzg10 and groth16 contracts
 35    pub const FUNCTION_SIGNATURE_KZG10_CHECK: [u8; 4] = [0x9e, 0x78, 0xcc, 0xf7];
 36    pub const FUNCTION_SIGNATURE_GROTH16_VERIFY_PROOF: [u8; 4] = [0x43, 0x75, 0x3b, 0x4d];
 37
 38    // Pragma statements for verifiers
 39    pub const PRAGMA_GROTH16_VERIFIER: &str = "pragma solidity >=0.7.0 <0.9.0;"; // from snarkjs, avoid changing
 40    pub const PRAGMA_KZG10_VERIFIER: &str = "pragma solidity >=0.8.1 <=0.8.4;";
 41
 42    struct TestAddCircuit<F: PrimeField> {
 43        _f: PhantomData<F>,
 44        pub x: u8,
 45        pub y: u8,
 46        pub z: u8,
 47    }
 48
 49    impl<F: PrimeField> ConstraintSynthesizer<F> for TestAddCircuit<F> {
 50        fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
 51            let x = FpVar::<F>::new_witness(cs.clone(), || Ok(F::from(self.x)))?;
 52            let y = FpVar::<F>::new_witness(cs.clone(), || Ok(F::from(self.y)))?;
 53            let z = FpVar::<F>::new_input(cs.clone(), || Ok(F::from(self.z)))?;
 54            let comp_z = x.clone() + y.clone();
 55            comp_z.enforce_equal(&z)?;
 56            Ok(())
 57        }
 58    }
 59
 60    #[test]
 61    fn test_groth16_kzg10_decider_template_renders() {
 62        let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
 63        let (x, y, z) = (21, 21, 42);
 64        let (_, vk) = {
 65            let c = TestAddCircuit::<Fr> {
 66                _f: PhantomData,
 67                x,
 68                y,
 69                z,
 70            };
 71            Groth16::<Bn254>::setup(c, &mut rng).unwrap()
 72        };
 73        let groth16_template = Groth16Verifier::from(vk, None);
 74        let (pk, vk): (ProverKey<G1>, VerifierKey<Bn254>) = KZGSetup::<Bn254>::setup(&mut rng, 5);
 75        let kzg10_template = KZG10Verifier::from(&vk, &pk.powers_of_g[..5], None, None);
 76        let decider_template = super::templates::Groth16KZG10DeciderVerifier {
 77            groth16_verifier: groth16_template,
 78            kzg10_verifier: kzg10_template,
 79        };
 80        save_solidity("decider.sol", &decider_template.render().unwrap());
 81    }
 82
 83    #[test]
 84    fn test_groth16_kzg10_decider_template_compiles() {
 85        let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
 86        let (x, y, z) = (21, 21, 42);
 87        let (_, vk) = {
 88            let c = TestAddCircuit::<Fr> {
 89                _f: PhantomData,
 90                x,
 91                y,
 92                z,
 93            };
 94            Groth16::<Bn254>::setup(c, &mut rng).unwrap()
 95        };
 96        // we dont specify any pragma values for both verifiers, the pragma from the decider takes over
 97        let groth16_template = Groth16Verifier::from(vk, None);
 98        let (pk, vk): (ProverKey<G1>, VerifierKey<Bn254>) = KZGSetup::<Bn254>::setup(&mut rng, 5);
 99        let kzg10_template = KZG10Verifier::from(&vk, &pk.powers_of_g[..5], None, None);
100        let decider_template = super::templates::Groth16KZG10DeciderVerifier {
101            groth16_verifier: groth16_template,
102            kzg10_verifier: kzg10_template,
103        };
104        let decider_verifier_bytecode =
105            compile_solidity(decider_template.render().unwrap(), "NovaDecider");
106        let mut evm = Evm::default();
107        _ = evm.create(decider_verifier_bytecode);
108    }
109
110    #[test]
111    fn test_groth16_verifier_template_renders() {
112        let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
113        let (x, y, z) = (21, 21, 42);
114        let (_, vk) = {
115            let c = TestAddCircuit::<Fr> {
116                _f: PhantomData,
117                x,
118                y,
119                z,
120            };
121            Groth16::<Bn254>::setup(c, &mut rng).unwrap()
122        };
123        let template = Groth16Verifier::from(vk, Some(PRAGMA_GROTH16_VERIFIER.to_string()));
124        save_solidity("groth16_verifier.sol", &template.render().unwrap());
125        _ = template.render().unwrap();
126    }
127
128    #[test]
129    fn test_groth16_verifier_template_compiles() {
130        let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
131        let (x, y, z) = (21, 21, 42);
132        let (_, vk) = {
133            let c = TestAddCircuit::<Fr> {
134                _f: PhantomData,
135                x,
136                y,
137                z,
138            };
139            Groth16::<Bn254>::setup(c, &mut rng).unwrap()
140        };
141        let res = Groth16Verifier::from(vk, Some(PRAGMA_GROTH16_VERIFIER.to_string()))
142            .render()
143            .unwrap();
144        let groth16_verifier_bytecode = compile_solidity(res, "Verifier");
145        let mut evm = Evm::default();
146        _ = evm.create(groth16_verifier_bytecode);
147    }
148
149    #[test]
150    fn test_groth16_verifier_accepts_and_rejects_proofs() {
151        let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
152        let (x, y, z) = (21, 21, 42);
153        let (pk, vk) = {
154            let c = TestAddCircuit::<Fr> {
155                _f: PhantomData,
156                x,
157                y,
158                z,
159            };
160            Groth16::<Bn254>::setup(c, &mut rng).unwrap()
161        };
162        let c = TestAddCircuit::<Fr> {
163            _f: PhantomData,
164            x,
165            y,
166            z,
167        };
168        let proof = Groth16::<Bn254>::prove(&pk, c, &mut rng).unwrap();
169        let res = Groth16Verifier::from(vk, Some(PRAGMA_GROTH16_VERIFIER.to_string()))
170            .render()
171            .unwrap();
172        save_solidity("groth16_verifier.sol", &res);
173        let groth16_verifier_bytecode = compile_solidity(&res, "Verifier");
174        let mut evm = Evm::default();
175        let verifier_address = evm.create(groth16_verifier_bytecode);
176        let (a_x, a_y) = proof.a.xy().unwrap();
177        let (b_x, b_y) = proof.b.xy().unwrap();
178        let (c_x, c_y) = proof.c.xy().unwrap();
179        let mut calldata: Vec<u8> = chain![
180            FUNCTION_SIGNATURE_GROTH16_VERIFY_PROOF,
181            a_x.into_bigint().to_bytes_be(),
182            a_y.into_bigint().to_bytes_be(),
183            b_x.c1.into_bigint().to_bytes_be(),
184            b_x.c0.into_bigint().to_bytes_be(),
185            b_y.c1.into_bigint().to_bytes_be(),
186            b_y.c0.into_bigint().to_bytes_be(),
187            c_x.into_bigint().to_bytes_be(),
188            c_y.into_bigint().to_bytes_be(),
189            BigInt::from(Fr::from(z)).to_bytes_be(),
190        ]
191        .collect();
192        let (_, output) = evm.call(verifier_address, calldata.clone());
193        assert_eq!(*output.last().unwrap(), 1);
194
195        // change calldata to make it invalid
196        let last_calldata_element = calldata.last_mut().unwrap();
197        *last_calldata_element = 0;
198        let (_, output) = evm.call(verifier_address, calldata);
199        assert_eq!(*output.last().unwrap(), 0);
200    }
201
202    #[test]
203    fn test_kzg_verifier_template_renders() {
204        let rng = &mut test_rng();
205        let n = 10;
206        let (pk, vk): (ProverKey<G1>, VerifierKey<Bn254>) = KZGSetup::<Bn254>::setup(rng, n);
207        let template = KZG10Verifier::from(
208            &vk,
209            &pk.powers_of_g[..5],
210            Some(PRAGMA_KZG10_VERIFIER.to_string()),
211            None,
212        );
213        let res = template.render().unwrap();
214        assert!(res.contains(&vk.g.x.to_string()));
215    }
216
217    #[test]
218    fn test_kzg_verifier_compiles() {
219        let rng = &mut test_rng();
220        let n = 10;
221        let (pk, vk): (ProverKey<G1>, VerifierKey<Bn254>) = KZGSetup::<Bn254>::setup(rng, n);
222        let template = KZG10Verifier::from(
223            &vk,
224            &pk.powers_of_g[..5],
225            Some(PRAGMA_KZG10_VERIFIER.to_string()),
226            None,
227        );
228        let res = template.render().unwrap();
229        let kzg_verifier_bytecode = compile_solidity(res, "KZG10");
230        let mut evm = Evm::default();
231        _ = evm.create(kzg_verifier_bytecode);
232    }
233
234    #[test]
235    fn test_kzg_verifier_accepts_and_rejects_proofs() {
236        let rng = &mut test_rng();
237        let poseidon_config = poseidon_test_config::<Fr>();
238        let transcript_p = &mut PoseidonTranscript::<G1>::new(&poseidon_config);
239        let transcript_v = &mut PoseidonTranscript::<G1>::new(&poseidon_config);
240
241        let n = 10;
242        let (pk, vk): (ProverKey<G1>, VerifierKey<Bn254>) = KZGSetup::<Bn254>::setup(rng, n);
243        let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(rng)).take(n).collect();
244        let cm = KZGProver::<G1>::commit(&pk, &v, &Fr::zero()).unwrap();
245        let (eval, proof) =
246            KZGProver::<G1>::prove(&pk, transcript_p, &cm, &v, &Fr::zero()).unwrap();
247        let template = KZG10Verifier::from(
248            &vk,
249            &pk.powers_of_g[..5],
250            Some(PRAGMA_KZG10_VERIFIER.to_string()),
251            None,
252        );
253        let res = template.render().unwrap();
254        let kzg_verifier_bytecode = compile_solidity(res, "KZG10");
255        let mut evm = Evm::default();
256        let verifier_address = evm.create(kzg_verifier_bytecode);
257
258        let (cm_affine, proof_affine) = (cm.into_affine(), proof.into_affine());
259        let (x_comm, y_comm) = cm_affine.xy().unwrap();
260        let (x_proof, y_proof) = proof_affine.xy().unwrap();
261        let y = eval.into_bigint().to_bytes_be();
262
263        transcript_v.absorb_point(&cm).unwrap();
264        let x = transcript_v.get_challenge();
265
266        let x = x.into_bigint().to_bytes_be();
267        let mut calldata: Vec<u8> = chain![
268            FUNCTION_SIGNATURE_KZG10_CHECK,
269            x_comm.into_bigint().to_bytes_be(),
270            y_comm.into_bigint().to_bytes_be(),
271            x_proof.into_bigint().to_bytes_be(),
272            y_proof.into_bigint().to_bytes_be(),
273            x.clone(),
274            y,
275        ]
276        .collect();
277
278        let (_, output) = evm.call(verifier_address, calldata.clone());
279        assert_eq!(*output.last().unwrap(), 1);
280
281        // change calldata to make it invalid
282        let last_calldata_element = calldata.last_mut().unwrap();
283        *last_calldata_element = 0;
284        let (_, output) = evm.call(verifier_address, calldata);
285        assert_eq!(*output.last().unwrap(), 0);
286    }
287}