Skip to content

Commit

Permalink
Feat/prover: add prover command line utilities (privacy-scaling-explo…
Browse files Browse the repository at this point in the history
…rations#326)

* evm_circuit: move TestCircuit behind a cfg feature

* add initial prover commandline tools

* lint: make clippy happy

* rustfmt

* prover: fix typo and add helpful references from @HAOYUatHZ

* prover: add more error strings

* prover: fix after rebase

* prover:rustfmt
  • Loading branch information
pinkiebell authored Feb 18, 2022
1 parent c221f9b commit 0acc51b
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 19 deletions.
34 changes: 26 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ members = [
"circuit-benchmarks",
"eth-types",
"external-tracer",
"mock"
"mock",
"prover"
]

[patch.crates-io]
Expand Down
11 changes: 8 additions & 3 deletions bus-mapping/src/circuit_input_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ impl Block {
history_hashes: Vec<Word>,
eth_block: &eth_types::Block<TX>,
) -> Result<Self, Error> {
if eth_block.base_fee_per_gas.is_none() {
// FIXME: resolve this once we have proper EIP-1559 support
log::warn!(
"This does not look like a EIP-1559 block - base_fee_per_gas defaults to zero"
);
}

Ok(Self {
chain_id,
history_hashes,
Expand All @@ -216,9 +223,7 @@ impl Block {
.into(),
timestamp: eth_block.timestamp,
difficulty: eth_block.difficulty,
base_fee: eth_block
.base_fee_per_gas
.ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))?,
base_fee: eth_block.base_fee_per_gas.unwrap_or_default(),
container: OperationContainer::new(),
txs: Vec::new(),
code: HashMap::new(),
Expand Down
18 changes: 18 additions & 0 deletions prover/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "prover"
version = "0.1.0"
edition = "2021"

[dependencies]
bus-mapping = { path = "../bus-mapping"}
env_logger = "0.9.0"
ethers-providers = "0.6"
eth-types = { path = "../eth-types" }
halo2 = { git = "https://github.com/appliedzkp/halo2.git", rev = "b78c39cacc1c79d287032f1b5f94beb661b3fb42" }
log = "0.4.14"
pairing = { git = 'https://github.com/appliedzkp/pairing', package = "pairing_bn256" }
rand = "0.8.4"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.78"
tokio = { version = "1.16.1", features = ["macros", "rt-multi-thread"] }
zkevm-circuits = { path = "../zkevm-circuits", features = ["test"] }
28 changes: 28 additions & 0 deletions prover/src/bin/gen_params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use halo2::poly::commitment::Setup;
use pairing::bn256::Bn256;
use std::env;
use std::fs::File;
use std::io::Write;

/// This utility supports parameter generation.
/// Can be invoked with: gen_params <degree> <path to file>
fn main() {
let mut args = env::args();
let params_path: String = args.next_back().expect("path to file");
let degree: u32 = args
.next_back()
.expect("degree")
.parse::<u32>()
.expect("valid number");
let mut file = File::create(&params_path).expect("Failed to create file");

println!("Generating params with degree: {}", degree);

let params = Setup::<Bn256>::new(degree, rand::rngs::OsRng::default());
let mut buf = Vec::new();
params.write(&mut buf).expect("Failed to write params");
file.write_all(&buf[..])
.expect("Failed to write params to file");

println!("Written to {}", params_path);
}
135 changes: 135 additions & 0 deletions prover/src/bin/prover_cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use bus_mapping::circuit_input_builder::BuilderClient;
use bus_mapping::rpc::GethClient;
use env_logger::Env;
use ethers_providers::Http;
use halo2::{
arithmetic::BaseExt,
plonk::*,
poly::commitment::Params,
transcript::{Blake2bWrite, Challenge255},
};
use pairing::bn256::{Fr, G1Affine};
use std::env::var;
use std::fs::File;
use std::io::BufReader;
use std::str::FromStr;
use zkevm_circuits::evm_circuit::{
table::FixedTableTag, test::TestCircuit, witness::block_convert,
};
use zkevm_circuits::state_circuit::StateCircuit;

#[derive(serde::Serialize)]
pub struct Proofs {
state_proof: eth_types::Bytes,
evm_proof: eth_types::Bytes,
}

/// This command generates and prints the proofs to stdout.
/// Required environment variables:
/// - BLOCK_NUM - the block number to generate the proof for
/// - RPC_URL - a geth http rpc that supports the debug namespace
/// - PARAMS_PATH - a path to a file generated with the gen_params tool
// TODO: move the proof generation into a module once we implement a rpc daemon for generating
// proofs.
#[tokio::main]
async fn main() {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();

let block_num: u64 = var("BLOCK_NUM")
.expect("BLOCK_NUM env var")
.parse()
.expect("Cannot parse BLOCK_NUM env var");
let rpc_url: String = var("RPC_URL")
.expect("RPC_URL env var")
.parse()
.expect("Cannot parse RPC_URL env var");
let params_path: String = var("PARAMS_PATH")
.expect("PARAMS_PATH env var")
.parse()
.expect("Cannot parse PARAMS_PATH env var");

// load polynomial commitment parameters
let params_fs = File::open(&params_path).expect("couldn't open params");
let params: Params<G1Affine> =
Params::read::<_>(&mut BufReader::new(params_fs)).expect("Failed to read params");

// request & build the inputs for the circuits
let geth_client = GethClient::new(Http::from_str(&rpc_url).expect("GethClient from RPC_URL"));
let builder = BuilderClient::new(geth_client)
.await
.expect("BuilderClient from GethClient");
let builder = builder
.gen_inputs(block_num)
.await
.expect("gen_inputs for BLOCK_NUM");

// TODO: only {evm,state}_proof are implemented right now
let evm_proof;
let state_proof;
{
// generate evm_circuit proof
let block = block_convert(&builder.block, &builder.code_db);
let circuit = TestCircuit::<Fr>::new(block, FixedTableTag::iterator().collect());

// TODO: can this be pre-generated to a file?
// related
// https://github.com/zcash/halo2/issues/443
// https://github.com/zcash/halo2/issues/449
let vk = keygen_vk(&params, &circuit).expect("keygen_vk for params, evm_circuit");
let pk = keygen_pk(&params, vk, &circuit).expect("keygen_pk for params, vk, evm_circuit");

// create a proof
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
create_proof(&params, &pk, &[circuit], &[], &mut transcript).expect("evm proof");
evm_proof = transcript.finalize();
}

{
// generate state_circuit proof
//
// TODO: this should be configurable
const MEMORY_ADDRESS_MAX: usize = 2000;
const STACK_ADDRESS_MAX: usize = 1300;
const MEMORY_ROWS_MAX: usize = 16384;
const STACK_ROWS_MAX: usize = 16384;
const STORAGE_ROWS_MAX: usize = 16384;
const GLOBAL_COUNTER_MAX: usize = MEMORY_ROWS_MAX + STACK_ROWS_MAX + STORAGE_ROWS_MAX;

let stack_ops = builder.block.container.sorted_stack();
let memory_ops = builder.block.container.sorted_memory();
let storage_ops = builder.block.container.sorted_storage();
let circuit = StateCircuit::<
Fr,
true,
GLOBAL_COUNTER_MAX,
MEMORY_ROWS_MAX,
MEMORY_ADDRESS_MAX,
STACK_ROWS_MAX,
STACK_ADDRESS_MAX,
STORAGE_ROWS_MAX,
> {
randomness: Fr::rand(),
memory_ops,
stack_ops,
storage_ops,
};

// TODO: same quest like in the first scope
let vk = keygen_vk(&params, &circuit).expect("keygen_vk for params, state_circuit");
let pk = keygen_pk(&params, vk, &circuit).expect("keygen_pk for params, vk, state_circuit");

// create a proof
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
create_proof(&params, &pk, &[circuit], &[], &mut transcript).expect("state proof");
state_proof = transcript.finalize();
}

serde_json::to_writer(
std::io::stdout(),
&Proofs {
evm_proof: evm_proof.into(),
state_proof: state_proof.into(),
},
)
.expect("serialize and write");
}
4 changes: 4 additions & 0 deletions zkevm-circuits/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ mock = { path = "../mock" }
[[bench]]
name = "binary_value"
harness = false

[features]
default = []
test = []
14 changes: 7 additions & 7 deletions zkevm-circuits/src/evm_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ impl<F: FieldExt> EvmCircuit<F> {
}
}

#[cfg(test)]
pub(crate) mod test {
#[cfg(feature = "test")]
pub mod test {
use crate::{
evm_circuit::{
param::STEP_HEIGHT,
Expand Down Expand Up @@ -148,7 +148,7 @@ pub(crate) mod test {
}

#[derive(Clone)]
pub(crate) struct TestCircuitConfig<F> {
pub struct TestCircuitConfig<F> {
tx_table: [Column<Advice>; 4],
rw_table: [Column<Advice>; 10],
bytecode_table: [Column<Advice>; 4],
Expand Down Expand Up @@ -310,7 +310,7 @@ pub(crate) mod test {
}

#[derive(Default)]
pub(crate) struct TestCircuit<F> {
pub struct TestCircuit<F> {
block: Block<F>,
fixed_table_tags: Vec<FixedTableTag>,
}
Expand Down Expand Up @@ -386,7 +386,7 @@ pub(crate) mod test {
}
}

pub(crate) fn run_test_circuit<F: FieldExt>(
pub fn run_test_circuit<F: FieldExt>(
block: Block<F>,
fixed_table_tags: Vec<FixedTableTag>,
) -> Result<(), Vec<VerifyFailure>> {
Expand Down Expand Up @@ -420,7 +420,7 @@ pub(crate) mod test {
prover.verify()
}

pub(crate) fn run_test_circuit_incomplete_fixed_table<F: FieldExt>(
pub fn run_test_circuit_incomplete_fixed_table<F: FieldExt>(
block: Block<F>,
) -> Result<(), Vec<VerifyFailure>> {
run_test_circuit(
Expand All @@ -436,7 +436,7 @@ pub(crate) mod test {
)
}

pub(crate) fn run_test_circuit_complete_fixed_table<F: FieldExt>(
pub fn run_test_circuit_complete_fixed_table<F: FieldExt>(
block: Block<F>,
) -> Result<(), Vec<VerifyFailure>> {
run_test_circuit(block, FixedTableTag::iterator().collect())
Expand Down

0 comments on commit 0acc51b

Please sign in to comment.