Skip to content

Commit

Permalink
Merge pull request #8 from 0xPolygonZero/proof_gen_merge
Browse files Browse the repository at this point in the history
Proof gen merge
  • Loading branch information
BGluth authored Dec 12, 2023
2 parents 982c215 + fe44ef7 commit 044bd5e
Show file tree
Hide file tree
Showing 25 changed files with 2,278 additions and 33 deletions.
28 changes: 5 additions & 23 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,27 +1,9 @@
[package]
name = "proof_protocol_decoder"
authors = ["Polygon Zero <bgluth@polygon.technology>"]
version = "0.1.0"
edition = "2021"
[workspace]
members = ["plonky_block_proof_gen", "protocol_decoder"]
resolver = "2"

[dependencies]
bytes = "1.5.0"
ciborium = "0.2.1"
ciborium-io = "0.2.1"
enum-as-inner = "0.6.0"
enumn = "0.1.12"
eth_trie_utils = { git = "https://github.com/0xPolygonZero/eth_trie_utils.git", rev = "e9ec4ec2aa2ae976b7c699ef40c1ffc716d87ed5" }
[workspace.dependencies]
ethereum-types = "0.14.1"
hex-literal = "0.4.1"
hex = "0.4.3"
keccak-hash = "0.10.0"
log = "0.4.20"
plonky2_evm = { git = "https://github.com/0xPolygonZero/plonky2.git", rev = "32d009671a1af86312807ba2dc90e9bb4f4a94da" }
thiserror = "1.0.49"
rlp = "0.5.2"
rlp-derive = "0.1.0"
plonky2_evm = { git = "https://github.com/0xPolygonZero/plonky2.git", rev = "7efd147e0888c5c6754a4d7ee2691a2ff5c82072" }
serde = "1.0.166"
serde_with = "3.4.0"

[dev-dependencies]
pretty_env_logger = "0.5.0"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A flexible protocol that clients (eg. full nodes) can use to easily generate blo

## Specification

Temporary [high-level overview and comparison](docs/usage_seq_diagrams.md) to what the old Edge setup used to look like. The specification itself is in the repo [here](src/trace_protocol.rs).
Temporary [high-level overview and comparison](docs/usage_seq_diagrams.md) to what the old Edge setup used to look like. The specification itself is in the repo [here](protocol_decoder/src/trace_protocol.rs).

Because processing the incoming proof protocol payload is not a resource bottleneck, the design is not worrying too much about performance. Instead, the core focus is flexibility in clients creating their own implementation, where the protocol supports multiple ways to provide different pieces of data. For example, there are multiple different formats available to provide the trie pre-images in, and the implementor can choose whichever is closest to its own internal data structures.

Expand Down
16 changes: 16 additions & 0 deletions plonky_block_proof_gen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "plonky_block_proof_gen"
description = "Generates block proofs from zero proof IR."
version = "0.1.0"
authors = ["Polygon Zero <bgluth@polygon.technology>"]
edition = "2021"
license = "MIT OR Apache-2.0"

[dependencies]
ethereum-types = { workspace = true }
log = { workspace = true }
paste = "1.0.14"
plonky2 = { git = "https://github.com/0xPolygonZero/plonky2.git", rev = "7efd147e0888c5c6754a4d7ee2691a2ff5c82072" }
plonky2_evm = { workspace = true }
protocol_decoder = { path = "../protocol_decoder" }
serde = { workspace = true }
44 changes: 44 additions & 0 deletions plonky_block_proof_gen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Plonky block proof generator

Library for generating proofs from proof IR.

For the time being, the only library that produces proof IR is currently [plonky-edge-block-trace-parser](https://github.com/0xPolygonZero/plonky-edge-block-trace-parser). Down the road, the IR will be produced by decoding the proof gen protocol.

# General Usage (Extremely rough, will change)

In [proof_gen.rs](https://github.com/0xPolygonZero/plonky-block-proof-gen/blob/main/src/proof_gen.rs), there are three core functions:

- `generate_txn_proof`
- `generate_agg_proof`
- `generate_block_proof`

Both libraries are currently targeting the latest [plonky2](https://github.com/0xPolygonZero/plonky2). One noteworthy piece of data that all proofs need is this:

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlockHashes {
pub prev_hashes: Vec<H256>,
pub cur_hash: H256,
}
```
Note that `prev_hashes` is going to be `256` elements long (!) most of the time.

`generate_txn_proof` takes in the output from the parser lib (`TxnProofGenIR`).

`generate_agg_proof` takes in the two child proofs (wrapped in `AggregatableProof`` to support txn or agg proofs).

`generate_block_proof` is a bit less obvious. You give it an agg proof that contains all txns in the entire block, but also pass in an optional previous block proof. The previous block proof is able to be `None` on checkpoint heights.

## License

Licensed under either of

* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.


### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
99 changes: 99 additions & 0 deletions plonky_block_proof_gen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! This library is intended to generate proofs with the [plonky2 zkEVM](https://github.com/0xPolygonZero/plonky2/evm), given
//! transactions provided in Intermediate Representation (IR) format.
//!
//! The exact format of this IR is defined by the [GenerationInputs](https://github.com/0xPolygonZero/plonky2/evm/src/generation/mod.rs)
//! used by the zkEVM prover, containing an RLP-encoded transaction along with
//! state metadata prior and post execution of this transaction.
//!
//! # Usage
//!
//! First, a prover needs to initialize its `ProverState`. For this, one can
//! use the `ProverStateBuilder`, which contains the ranges to be used by all
//! internal STARK tables of the zkEVM.
//!
//! The default method contains an initial set of ranges for each table, that
//! can be overriden at will by calling
//! `ProverStateBuilder::set_foo_circuit_size` where `foo` is the name of the
//! targeted table. At the moment, plonky2 zkEVM contains seven tables:
//! `arithmetic`, `byte_packing`, `cpu`, `keccak`, `keccak_sponge`, `logic` and
//! `memory`.
//!
//! ```rust
//! let mut builder = ProverStateBuilder::default();
//!
//! // Change Cpu and Memory tables supported ranges.
//! builder.set_cpu_circuit_size(12..25);
//! builder.set_cpu_circuit_size(18..28);
//!
//! // Generate a `ProverState` from the builder.
//! let prover_state = builder.build();
//! ```
//!
//! ***NOTE***: All the circuits to generate the different kind of proofs, from
//! transaction proofs to block proofs, are specific to the initial set of
//! ranges selected for each table. Changing one of them will require building a
//! new `ProverState`, and will make all previously generated proofs
//! incompatible with the new state. Make sure you select sufficiently large
//! ranges for your application!
//!
//! Once all circuits have been pre-processed, a prover can now generate proofs
//! from inputs passed as Intermediary Representation.
//!
//! This library handles the 3 kinds of proof generations necessary for the
//! zkEVM:
//!
//! ### Transaction proofs
//!
//! From a `ProverState` and a transaction processed with some metadata in
//! Intermediate Representation, one can obtain a transaction proof by calling
//! the method below:
//!
//! ```rust
//! pub fn generate_txn_proof(
//! p_state: &ProverState,
//! start_info: TxnProofGenIR,
//! ) -> ProofGenResult<GeneratedTxnProof> { ... }
//! ```
//!
//! The obtained `GeneratedTxnProof` contains the actual proof and some
//! additional data to be used when aggregating this transaction with others.
//!
//! ### Aggregation proofs
//!
//! Two proofs can be aggregated together with a `ProverState`. These `child`
//! proofs can either be transaction proofs, or aggregated proofs themselves.
//! This library abstracts their type behind an `AggregatableProof` enum.
//!
//! ```rust
//! pub fn generate_agg_proof(
//! p_state: &ProverState,
//! lhs_child: &AggregatableProof,
//! rhs_child: &AggregatableProof,
//! ) -> ProofGenResult<GeneratedAggProof> { ... }
//! ```
//!
//! ### Block proofs
//!
//! Once the prover has obtained a `GeneratedAggProof` corresponding to the
//! entire set of transactions within a block, they can then wrap it into a
//! final `GeneratedBlockProof`. The prover can pass an optional previous
//! block proof as argument to the `generate_block_proof` method, to combine
//! both statement into one, effectively proving an entire chain from genesis
//! through a single final proof.
//!
//! ```rust
//! pub fn generate_block_proof(
//! p_state: &ProverState,
//! prev_opt_parent_b_proof: Option<&GeneratedBlockProof>,
//! curr_block_agg_proof: &GeneratedAggProof,
//! ) -> ProofGenResult<GeneratedBlockProof> { ... }
//! ```
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(missing_docs)]

pub mod proof_gen;
pub mod proof_types;
pub mod prover_state;
pub mod types;
106 changes: 106 additions & 0 deletions plonky_block_proof_gen/src/proof_gen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//! This module defines the proof generation methods corresponding to the three
//! types of proofs the zkEVM internally handles.
use plonky2::util::timing::TimingTree;
use plonky2_evm::{all_stark::AllStark, config::StarkConfig};
use protocol_decoder::types::TxnProofGenIR;

use crate::{
proof_types::{AggregatableProof, GeneratedAggProof, GeneratedBlockProof, GeneratedTxnProof},
prover_state::ProverState,
};

/// A type alias for `Result<T, ProofGenError>`.
pub type ProofGenResult<T> = Result<T, ProofGenError>;

/// A custom error type to handle failure cases during proof generation.
// Plonky2 is still using `anyhow` for proof gen, and since this is a library,
// it's probably best if we at least convert it to a `String`.
#[derive(Debug)]
pub struct ProofGenError(pub String);

impl std::fmt::Display for ProofGenError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:#?}", self.0)
}
}

impl std::error::Error for ProofGenError {}

impl From<String> for ProofGenError {
fn from(v: String) -> Self {
Self(v)
}
}

/// Generates a transaction proof from some IR data.
pub fn generate_txn_proof(
p_state: &ProverState,
start_info: TxnProofGenIR,
) -> ProofGenResult<GeneratedTxnProof> {
let (intern, p_vals) = p_state
.state
.prove_root(
&AllStark::default(),
&StarkConfig::standard_fast_config(),
start_info.gen_inputs,
&mut TimingTree::default(),
)
.map_err(|err| err.to_string())?;

Ok(GeneratedTxnProof { p_vals, intern })
}

/// Generates an aggregation proof from two child proofs.
///
/// Note that the child proofs may be either transaction or aggregation proofs.
pub fn generate_agg_proof(
p_state: &ProverState,
lhs_child: &AggregatableProof,
rhs_child: &AggregatableProof,
) -> ProofGenResult<GeneratedAggProof> {
let (intern, p_vals) = p_state
.state
.prove_aggregation(
lhs_child.is_agg(),
lhs_child.intern(),
lhs_child.public_values(),
rhs_child.is_agg(),
rhs_child.intern(),
rhs_child.public_values(),
)
.map_err(|err| err.to_string())?;

Ok(GeneratedAggProof { p_vals, intern })
}

/// Generates a block proof.
///
/// It takes an optional argument, `prev_opt_parent_b_proof`, that can be set to
/// `None` on checkpoint heights.
pub fn generate_block_proof(
p_state: &ProverState,
prev_opt_parent_b_proof: Option<&GeneratedBlockProof>,
curr_block_agg_proof: &GeneratedAggProof,
) -> ProofGenResult<GeneratedBlockProof> {
let b_height = curr_block_agg_proof
.p_vals
.block_metadata
.block_number
.low_u64();
let parent_intern = prev_opt_parent_b_proof.map(|p| &p.intern);

let (b_proof_intern, _) = p_state
.state
.prove_block(
parent_intern,
&curr_block_agg_proof.intern,
curr_block_agg_proof.p_vals.clone(),
)
.map_err(|err| err.to_string())?;

Ok(GeneratedBlockProof {
b_height,
intern: b_proof_intern,
})
}
87 changes: 87 additions & 0 deletions plonky_block_proof_gen/src/proof_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! This module defines the various proof types used throughout the block proof
//! generation process.
use plonky2_evm::proof::PublicValues;
use protocol_decoder::types::BlockHeight;
use serde::{Deserialize, Serialize};

use crate::types::PlonkyProofIntern;

/// A transaction proof along with its public values, for proper connection with
/// contiguous proofs.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GeneratedTxnProof {
/// Public values of this transaction proof.
pub p_vals: PublicValues,
/// Underlying plonky2 proof.
pub intern: PlonkyProofIntern,
}

/// An aggregation proof along with its public values, for proper connection
/// with contiguous proofs.
///
/// Aggregation proofs can represent any contiguous range of two or more
/// transactions, up to an entire block.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GeneratedAggProof {
/// Public values of this aggregation proof.
pub p_vals: PublicValues,
/// Underlying plonky2 proof.
pub intern: PlonkyProofIntern,
}

/// A block proof along with the block height against which this proof ensures
/// the validity since the last proof checkpoint.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GeneratedBlockProof {
/// Associated block height.
pub b_height: BlockHeight,
/// Underlying plonky2 proof.
pub intern: PlonkyProofIntern,
}

/// Sometimes we don't care about the underlying proof type and instead only if
/// we can combine it into an agg proof. For these cases, we want to abstract
/// away whether or not the proof was a txn or agg proof.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum AggregatableProof {
/// The underlying proof is a transaction proof.
Txn(GeneratedTxnProof),
/// The underlying proof is an aggregation proof.
Agg(GeneratedAggProof),
}

impl AggregatableProof {
pub(crate) fn public_values(&self) -> PublicValues {
match self {
AggregatableProof::Txn(info) => info.p_vals.clone(),
AggregatableProof::Agg(info) => info.p_vals.clone(),
}
}

pub(crate) fn is_agg(&self) -> bool {
match self {
AggregatableProof::Txn(_) => false,
AggregatableProof::Agg(_) => true,
}
}

pub(crate) fn intern(&self) -> &PlonkyProofIntern {
match self {
AggregatableProof::Txn(info) => &info.intern,
AggregatableProof::Agg(info) => &info.intern,
}
}
}

impl From<GeneratedTxnProof> for AggregatableProof {
fn from(v: GeneratedTxnProof) -> Self {
Self::Txn(v)
}
}

impl From<GeneratedAggProof> for AggregatableProof {
fn from(v: GeneratedAggProof) -> Self {
Self::Agg(v)
}
}
Loading

0 comments on commit 044bd5e

Please sign in to comment.