snark_verifier_sdk/
evm.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
use crate::{GWC, SHPLONK};

use super::{CircuitExt, PlonkVerifier};
#[cfg(feature = "display")]
use ark_std::{end_timer, start_timer};
use halo2_base::halo2_proofs::{
    halo2curves::bn256::{Bn256, Fq, Fr, G1Affine},
    plonk::{create_proof, verify_proof, Circuit, ProvingKey, VerifyingKey},
    poly::{
        commitment::{ParamsProver, Prover, Verifier},
        kzg::{
            commitment::{KZGCommitmentScheme, ParamsKZG},
            msm::DualMSM,
            multiopen::{ProverGWC, ProverSHPLONK, VerifierGWC, VerifierSHPLONK},
            strategy::{AccumulatorStrategy, GuardKZG},
        },
        VerificationStrategy,
    },
    transcript::{TranscriptReadBuffer, TranscriptWriterBuffer},
};
use itertools::Itertools;
use rand::{rngs::StdRng, SeedableRng};
pub use snark_verifier::loader::evm::encode_calldata;
use snark_verifier::{
    loader::evm::{compile_solidity, EvmLoader},
    pcs::{
        kzg::{KzgAccumulator, KzgAsVerifyingKey, KzgDecidingKey, KzgSuccinctVerifyingKey},
        AccumulationDecider, AccumulationScheme, PolynomialCommitmentScheme,
    },
    system::halo2::{compile, transcript::evm::EvmTranscript, Config},
    verifier::SnarkVerifier,
};
use std::{fs, io, path::Path, rc::Rc};

/// Generates a proof for evm verification using either SHPLONK or GWC proving method. Uses Keccak for Fiat-Shamir.
pub fn gen_evm_proof<'params, C, P, V>(
    params: &'params ParamsKZG<Bn256>,
    pk: &'params ProvingKey<G1Affine>,
    circuit: C,
    instances: Vec<Vec<Fr>>,
) -> Vec<u8>
where
    C: Circuit<Fr>,
    P: Prover<'params, KZGCommitmentScheme<Bn256>>,
    V: Verifier<
        'params,
        KZGCommitmentScheme<Bn256>,
        Guard = GuardKZG<'params, Bn256>,
        MSMAccumulator = DualMSM<'params, Bn256>,
    >,
{
    let instances = instances.iter().map(|instances| instances.as_slice()).collect_vec();

    #[cfg(feature = "display")]
    let proof_time = start_timer!(|| "Create EVM proof");
    let rng = StdRng::from_entropy();
    let proof = {
        let mut transcript = TranscriptWriterBuffer::<_, G1Affine, _>::init(Vec::new());
        create_proof::<KZGCommitmentScheme<Bn256>, P, _, _, EvmTranscript<_, _, _, _>, _>(
            params,
            pk,
            &[circuit],
            &[instances.as_slice()],
            rng,
            &mut transcript,
        )
        .unwrap();
        transcript.finalize()
    };
    #[cfg(feature = "display")]
    end_timer!(proof_time);

    let accept = {
        let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.as_slice());
        VerificationStrategy::<_, V>::finalize(
            verify_proof::<_, V, _, EvmTranscript<_, _, _, _>, _>(
                params.verifier_params(),
                pk.get_vk(),
                AccumulatorStrategy::new(params.verifier_params()),
                &[instances.as_slice()],
                &mut transcript,
            )
            .unwrap(),
        )
    };
    assert!(accept);

    proof
}

pub fn gen_evm_proof_gwc<'params, C: Circuit<Fr>>(
    params: &'params ParamsKZG<Bn256>,
    pk: &'params ProvingKey<G1Affine>,
    circuit: C,
    instances: Vec<Vec<Fr>>,
) -> Vec<u8> {
    gen_evm_proof::<C, ProverGWC<_>, VerifierGWC<_>>(params, pk, circuit, instances)
}

pub fn gen_evm_proof_shplonk<'params, C: Circuit<Fr>>(
    params: &'params ParamsKZG<Bn256>,
    pk: &'params ProvingKey<G1Affine>,
    circuit: C,
    instances: Vec<Vec<Fr>>,
) -> Vec<u8> {
    gen_evm_proof::<C, ProverSHPLONK<_>, VerifierSHPLONK<_>>(params, pk, circuit, instances)
}

pub trait EvmKzgAccumulationScheme = PolynomialCommitmentScheme<
        G1Affine,
        Rc<EvmLoader>,
        VerifyingKey = KzgSuccinctVerifyingKey<G1Affine>,
        Output = KzgAccumulator<G1Affine, Rc<EvmLoader>>,
    > + AccumulationScheme<
        G1Affine,
        Rc<EvmLoader>,
        VerifyingKey = KzgAsVerifyingKey,
        Accumulator = KzgAccumulator<G1Affine, Rc<EvmLoader>>,
    > + AccumulationDecider<G1Affine, Rc<EvmLoader>, DecidingKey = KzgDecidingKey<Bn256>>;

pub fn gen_evm_verifier<C, AS>(
    params: &ParamsKZG<Bn256>,
    vk: &VerifyingKey<G1Affine>,
    num_instance: Vec<usize>,
    path: Option<&Path>,
) -> Vec<u8>
where
    C: CircuitExt<Fr>,
    AS: EvmKzgAccumulationScheme,
{
    let protocol = compile(
        params,
        vk,
        Config::kzg()
            .with_num_instance(num_instance.clone())
            .with_accumulator_indices(C::accumulator_indices()),
    );
    // deciding key
    let dk = (params.get_g()[0], params.g2(), params.s_g2()).into();

    let loader = EvmLoader::new::<Fq, Fr>();
    let protocol = protocol.loaded(&loader);
    let mut transcript = EvmTranscript::<_, Rc<EvmLoader>, _, _>::new(&loader);

    let instances = transcript.load_instances(num_instance);
    let proof =
        PlonkVerifier::<AS>::read_proof(&dk, &protocol, &instances, &mut transcript).unwrap();
    PlonkVerifier::<AS>::verify(&dk, &protocol, &instances, &proof).unwrap();

    let sol_code = loader.solidity_code();
    let byte_code = compile_solidity(&sol_code);
    if let Some(path) = path {
        path.parent().and_then(|dir| fs::create_dir_all(dir).ok()).unwrap();
        fs::write(path, sol_code).unwrap();
    }
    byte_code
}

pub fn gen_evm_verifier_gwc<C: CircuitExt<Fr>>(
    params: &ParamsKZG<Bn256>,
    vk: &VerifyingKey<G1Affine>,
    num_instance: Vec<usize>,
    path: Option<&Path>,
) -> Vec<u8> {
    gen_evm_verifier::<C, GWC>(params, vk, num_instance, path)
}

pub fn gen_evm_verifier_shplonk<C: CircuitExt<Fr>>(
    params: &ParamsKZG<Bn256>,
    vk: &VerifyingKey<G1Affine>,
    num_instance: Vec<usize>,
    path: Option<&Path>,
) -> Vec<u8> {
    gen_evm_verifier::<C, SHPLONK>(params, vk, num_instance, path)
}

#[cfg(feature = "revm")]
pub fn evm_verify(deployment_code: Vec<u8>, instances: Vec<Vec<Fr>>, proof: Vec<u8>) {
    let calldata = encode_calldata(&instances, &proof);
    let gas_cost = snark_verifier::loader::evm::deploy_and_call(deployment_code, calldata).unwrap();
    dbg!(gas_cost);
}

pub fn write_calldata(instances: &[Vec<Fr>], proof: &[u8], path: &Path) -> io::Result<String> {
    let calldata = encode_calldata(instances, proof);
    let calldata = hex::encode(calldata);
    fs::write(path, &calldata)?;
    Ok(calldata)
}