arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/solidity-verifiers/src/verifiers/g16.rs
solidity-verifiers/src/verifiers/g16.rsRaw
  1use crate::utils::encoding::{g1_to_fq_repr, g2_to_fq_repr};
  2use crate::utils::encoding::{G1Repr, G2Repr};
  3use crate::utils::HeaderInclusion;
  4use crate::{ProtocolVerifierKey, GPL3_SDPX_IDENTIFIER};
  5use ark_bn254::Bn254;
  6use ark_groth16::VerifyingKey;
  7use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
  8use askama::Template;
  9
 10use super::PRAGMA_GROTH16_VERIFIER;
 11
 12#[derive(Template, Default)]
 13#[template(path = "groth16_verifier.askama.sol", ext = "sol")]
 14pub(crate) struct Groth16Verifier {
 15    /// The `alpha * G`, where `G` is the generator of `G1`.
 16    pub(crate) vkey_alpha_g1: G1Repr,
 17    /// The `alpha * H`, where `H` is the generator of `G2`.
 18    pub(crate) vkey_beta_g2: G2Repr,
 19    /// The `gamma * H`, where `H` is the generator of `G2`.
 20    pub(crate) vkey_gamma_g2: G2Repr,
 21    /// The `delta * H`, where `H` is the generator of `G2`.
 22    pub(crate) vkey_delta_g2: G2Repr,
 23    /// Length of the `gamma_abc_g1` vector.
 24    pub(crate) gamma_abc_len: usize,
 25    /// The `gamma^{-1} * (beta * a_i + alpha * b_i + c_i) * H`, where `H` is the generator of `E::G1`.
 26    pub(crate) gamma_abc_g1: Vec<G1Repr>,
 27}
 28
 29impl From<Groth16VerifierKey> for Groth16Verifier {
 30    fn from(g16_vk: Groth16VerifierKey) -> Self {
 31        Self {
 32            vkey_alpha_g1: g1_to_fq_repr(g16_vk.0.alpha_g1),
 33            vkey_beta_g2: g2_to_fq_repr(g16_vk.0.beta_g2),
 34            vkey_gamma_g2: g2_to_fq_repr(g16_vk.0.gamma_g2),
 35            vkey_delta_g2: g2_to_fq_repr(g16_vk.0.delta_g2),
 36            gamma_abc_len: g16_vk.0.gamma_abc_g1.len(),
 37            gamma_abc_g1: g16_vk
 38                .0
 39                .gamma_abc_g1
 40                .iter()
 41                .copied()
 42                .map(g1_to_fq_repr)
 43                .collect(),
 44        }
 45    }
 46}
 47
 48// Ideally this would be linked to the `Decider` trait in FoldingSchemes.
 49// For now, this is the easiest as NovaCycleFold isn't clear target from where we can get all it's needed arguments.
 50#[derive(CanonicalDeserialize, CanonicalSerialize, Clone, PartialEq, Debug)]
 51pub struct Groth16VerifierKey(pub(crate) VerifyingKey<Bn254>);
 52
 53impl From<VerifyingKey<Bn254>> for Groth16VerifierKey {
 54    fn from(value: VerifyingKey<Bn254>) -> Self {
 55        Self(value)
 56    }
 57}
 58
 59impl ProtocolVerifierKey for Groth16VerifierKey {
 60    const PROTOCOL_NAME: &'static str = "Groth16";
 61
 62    fn render_as_template(self, pragma: Option<String>) -> Vec<u8> {
 63        HeaderInclusion::<Groth16Verifier>::builder()
 64            .sdpx(GPL3_SDPX_IDENTIFIER.to_string())
 65            .pragma_version(pragma.unwrap_or(PRAGMA_GROTH16_VERIFIER.to_string()))
 66            .template(self)
 67            .build()
 68            .render()
 69            .unwrap()
 70            .into_bytes()
 71    }
 72}
 73
 74#[cfg(test)]
 75mod tests {
 76    use super::Groth16VerifierKey;
 77    use crate::{
 78        evm::{compile_solidity, save_solidity, Evm},
 79        ProtocolVerifierKey,
 80    };
 81    use ark_bn254::{Bn254, Fr};
 82    use ark_crypto_primitives::snark::SNARK;
 83    use ark_ec::AffineRepr;
 84    use ark_ff::{BigInt, BigInteger, PrimeField};
 85    use ark_groth16::Groth16;
 86    use ark_std::rand::{RngCore, SeedableRng};
 87    use ark_std::test_rng;
 88    use askama::Template;
 89    use itertools::chain;
 90
 91    use super::Groth16Verifier;
 92    use crate::verifiers::tests::{setup, DEFAULT_SETUP_LEN};
 93
 94    pub const FUNCTION_SELECTOR_GROTH16_VERIFY_PROOF: [u8; 4] = [0x43, 0x75, 0x3b, 0x4d];
 95
 96    #[test]
 97    fn groth16_vk_serde_roundtrip() {
 98        let (_, _, _, vk, _) = setup(DEFAULT_SETUP_LEN);
 99
100        let g16_vk = Groth16VerifierKey::from(vk);
101        let mut bytes = vec![];
102        g16_vk.serialize_protocol_verifier_key(&mut bytes).unwrap();
103        let obtained_g16_vk =
104            Groth16VerifierKey::deserialize_protocol_verifier_key(bytes.as_slice()).unwrap();
105
106        assert_eq!(g16_vk, obtained_g16_vk)
107    }
108
109    #[test]
110    fn test_groth16_verifier_accepts_and_rejects_proofs() {
111        let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
112        let (_, _, g16_pk, g16_vk, circuit) = setup(DEFAULT_SETUP_LEN);
113        let g16_vk = Groth16VerifierKey::from(g16_vk);
114
115        let proof = Groth16::<Bn254>::prove(&g16_pk, circuit, &mut rng).unwrap();
116        let res = Groth16Verifier::from(g16_vk).render().unwrap();
117        save_solidity("groth16_verifier.sol", &res);
118        let groth16_verifier_bytecode = compile_solidity(&res, "Verifier");
119        let mut evm = Evm::default();
120        let verifier_address = evm.create(groth16_verifier_bytecode);
121        let (a_x, a_y) = proof.a.xy().unwrap();
122        let (b_x, b_y) = proof.b.xy().unwrap();
123        let (c_x, c_y) = proof.c.xy().unwrap();
124        let mut calldata: Vec<u8> = chain![
125            FUNCTION_SELECTOR_GROTH16_VERIFY_PROOF,
126            a_x.into_bigint().to_bytes_be(),
127            a_y.into_bigint().to_bytes_be(),
128            b_x.c1.into_bigint().to_bytes_be(),
129            b_x.c0.into_bigint().to_bytes_be(),
130            b_y.c1.into_bigint().to_bytes_be(),
131            b_y.c0.into_bigint().to_bytes_be(),
132            c_x.into_bigint().to_bytes_be(),
133            c_y.into_bigint().to_bytes_be(),
134            BigInt::from(Fr::from(circuit.z)).to_bytes_be(),
135        ]
136        .collect();
137        let (_, output) = evm.call(verifier_address, calldata.clone());
138        assert_eq!(*output.last().unwrap(), 1);
139
140        // change calldata to make it invalid
141        let last_calldata_element = calldata.last_mut().unwrap();
142        *last_calldata_element = 0;
143        let (_, output) = evm.call(verifier_address, calldata);
144        assert_eq!(*output.last().unwrap(), 0);
145    }
146}