Add CLI interface for verifier contract generation (#74)

* add: solidity-verifier workspace member

* chore: Update toolchain to 1.74

* feat: Add basic clap cli interface for solidity verifier

This includes a cli parser that serves as a way to the user to generate the desired Solidity contracts.

* chore: Expose SoldityVerifier template struct

* feat: Finish first working version

* change: Modify some settings

* fix: Fix rebase conflicts

* chore: Leave resolver 2 for workspace

* chore: Rename KZG+G16 template

Now the template refers to Nova + Cyclefold and has a Warning attached to it

* fixup

* chore: Rename to NovaCyclefoldDecider the template

* chore: Change constructors to `new` instead of `from`

* add: ProtocolData trait helper

This trait helps to treat the serialized data required by the Template
as a single element while still allowing a flexible usage.

This is specially interesting as allows the cli to operate considering a
single path of input data where all the data for the selected protocol
co-exists. Reducing the amount of parsing and arguments the user needs
to pass to the cli.

* chore: Create `From` impls formally

Previously we had functions called `from` which had nothing to do with
the trait `From`. This addresses this issue and fixes it.

Now both `new` and `from` are avaliable. But `from` follows the `From`
trait.

* add: Support G16, KZG and Nova+Cyclefold in cli

This adds a `render` fn for `Protocol` which makes it easier to add new
protocols to the CLI as is mainly based in the `ProtocolData` impl
behind the scenes of the selected protocol.

Aside from that, this commit reworks some minor parts of the CLI config
as shorteners for commands or adding `pragma` as an optional parameter.

* chore: Adapt `main.rs` to new cli changes

As seen, this allows to have a much easier `main.rs` which doesn't have
to do any `match` over the selected protocol.

* chore: Make solidity helper fns `cfg(test)`

* chore: Rework folding-schemes-solidity structure

* chore: Remove g1_crs_batch_points_len from KZGData

* add: Serde tests for all template targets

* tmp: Add NovaCyclefold testing

* add: HeaderInclusion template

When we use templates that are composed by others (as happens with
`NovaCyclefold` one) we sadly see that the License and the `pragma`
attributes are rendered once per sub-template.

This generic structure solves this issue by being actually the only item
rendered which has a sub-template the template we indeed want to render
at the end.

* chore: Add tests for NovaCyclefold contract

This also includes small changes to the lib architecture such as adding
constants for GPL3_SDPX_IDENTIFIER or move the default pragma versions
used to `mod.rs`

* chore: Update g16 to use HeaderInclusion template rendering

Now the `ProtocolData` impl falls back to the usage of `HeaderInclusion`
it is easier to handle complex templates like `NovaCyclefold`.

* add: Small builder-pattern to construct HeaderInclusion Templates

As mentioned in previous commits, the idea is that the header is set on
an automatic wrapper template applied to the one that we actually want
to render.

This builder pattern makes it less complex to do such a thing. Specially
avoiding unidiomatic `From` implementations.

* remove: sdpx & pragma from KZG template

Those are externalized and handled by HeaderInclusion template utility

* chore: Update templates to use HeaderInclusion builder

* chore: Update tests to use HeaderInclusion builderPattern

* remove: fixed pragma version in novacyclefold template

* chore: Accept Into<Template> in builder

* tmp: Only KZG return passes. Fix Groth

* fix: Prevent `revert` from paniking for negative tests

* feat: Merge G16 and KZG contract results in NovaCyclefold

* chore: Add assets for quicker/easier testing

Now instead of generating the protocoldata & proofs on each test, we just deserialize

* fix: Address clippy & warnings

* fix: Spelling to prevent PR farmers LOL

* chore: Add about and long_about to CLI tool

* add: README.md

* chore: Revert  asset-based testing approach

* remove: Assets folder

* fix: Rebase issues

* fix: use &mut for Reader

* fix: rebase error with Contract name

* chore: Reduce tests LOC with setup fn

* chore: Set MIT license indentifier for CLI & KZG

* chore: Add extra usage example

* chore: Update novacyclefold contract comments on soundess

* chore: Typo

* chore: Allow type complexity clippy for setup fn

* chore: Address Pierre's comments

* chore: Rename workspace members

- folding-schemes-solidity -> soliity-verifiers
This commit is contained in:
Carlos Pérez
2024-03-18 11:09:22 +01:00
committed by GitHub
parent a4905c8a06
commit 1072b66e92
28 changed files with 1014 additions and 461 deletions

38
cli/Cargo.toml Normal file
View File

@@ -0,0 +1,38 @@
[package]
name = "solidity-verifiers-cli"
version = "0.1.0"
edition = "2021"
[dependencies]
ark-ec = "0.4"
ark-ff = "0.4"
ark-poly = "0.4"
ark-std = "0.4"
ark-groth16 = "0.4"
askama = { version = "0.12.0", features = ["config"], default-features = false }
ark-bn254 = "0.4.0"
ark-poly-commit = "0.4.0"
solidity-verifiers = { path = "../solidity-verifiers" }
itertools = "0.12.1"
ark-serialize = "0.4.1"
clap = { version = "4.4", features = ["derive", "string"] }
clap-verbosity-flag = "2.1"
log = "0.4"
env_logger = "0.10"
[dev-dependencies]
revm = "3.5.0"
tracing = { version = "0.1", default-features = false, features = [ "attributes" ] }
tracing-subscriber = { version = "0.2" }
[features]
default = ["parallel"]
parallel = [
"ark-std/parallel",
"ark-ff/parallel",
"ark-poly/parallel",
]

72
cli/README.md Normal file
View File

@@ -0,0 +1,72 @@
# Solidity Verifier
_____ ______ ______ ______ ______ ______ ______
| |__| || |__| || |__| || |__| || |__| || |__| || |__| |
| () || () || () || () || () || () || () |
|______||______||______||______||______||______||______|
______ ______
| |__| | ____ _ _ _ _ _ | |__| |
| () | / ___| ___ | (_) __| (_) |_ _ _ | () |
|______| \___ \ / _ \| | |/ _` | | __| | | | |______|
______ ___) | (_) | | | (_| | | |_| |_| | ______
| |__| | |____/ \___/|_|_|\__,_|_|\__|\__, | | |__| |
| () | __ __ _ __ _ |___/ | () |
|______| \ \ / /__ _ __(_)/ _(_) ___ _ __ |______|
______ \ \ / / _ \ '__| | |_| |/ _ \ '__| ______
| |__| | \ V / __/ | | | _| | __/ | | |__| |
| () | \_/ \___|_| |_|_| |_|\___|_| | () |
|______| |______|
______ ______ ______ ______ ______ ______ ______
| |__| || |__| || |__| || |__| || |__| || |__| || |__| |
| () || () || () || () || () || () || () |
|______||______||______||______||______||______||______|
Welcome to Solidity Verifier, a powerful Command-Line Interface (CLI) tool designed to simplify the generation of Solidity smart contracts that verify proofs of Zero Knowledge cryptographic protocols. This tool is developed by the collaborative efforts of the PSE (Privacy & Scaling Explorations) and 0XPARC teams.
As an open-source project, Solidity Verifier is released under the GPL3 license.
## Supported Protocols
Solidity Verifier currently supports the generation of Solidity smart contracts for the verification of proofs in the following Zero Knowledge protocols:
- **Groth16:**
- Efficient and succinct zero-knowledge proof system.
- Template credit: [Jordi Baylina - Groth16 Verifier Template](https://github.com/iden3/snarkjs/blob/master/templates/verifier_groth16.sol.ejs)
- **KZG:**
- Uses the Kate-Zaverucha-Goldberg polynomial commitment scheme.
- Example credit: [weijiekoh - KZG10 Verifier Contract](https://github.com/weijiekoh/libkzg/blob/master/sol/KZGVerifier.sol)
- **Nova + CycleFold Decider:**
- Implements the decider circuit verification for the Nova zero-knowledge proof system in conjunction with the CycleFold protocol optimization.
- Template inspiration and setup credit: [Han - revm/Solidity Contract Testing Functions](https://github.com/privacy-scaling-explorations/halo2-solidity-verifier/tree/main)
## Usage
```bash
solidity-verifier [OPTIONS] -p <PROTOCOL> -pd <PROTOCOL_DATA> -o <OUTPUT_PATH>
```
A real use case (which was used to test the tool itself):
`solidity-verifier -p groth16 -pd ./folding-verifier-solidity/assets/G16_test_vk_data`
This would generate a Groth16 verifier contract for the given G16 data (which consists on the G16_Vkey only) and store this contract in `$pwd`.
### Options:
-v, --verbose: Increase logging verbosity
-q, --quiet: Decrease logging verbosity
-p, --protocol <PROTOCOL>: Selects the protocol for which to generate the Decider circuit Solidity Verifier (possible values: groth16, kzg, nova-cyclefold)
-o, --out <OUT>: Sets the output path for all generated artifacts (default: /home/kr0/Desktop/HDD/ethereum/folding-schemes/verifier.sol)
-d, --protocol-data <PROTOCOL_DATA>: Sets the input path for the file containing all the data required by the chosen protocol for verification contract generation
--pragma <PRAGMA>: Selects the Solidity compiler version to be set in the Solidity Verifier contract artifact
-h, --help: Print help (see a summary with '-h')
-V, --version: Print version
## License
Solidity Verifier is released under the GPL3 license for any of the protocols that include `Groth16`. See the LICENSE file in the project repository for more details.
For the rest of contracts/protocols and the CLI itself, this tooling is released under MIT/Apache license.
## Contributing
Feel free to explore, use, and contribute to Solidity Verifier as we strive to enhance privacy and scalability in the blockchain space!
We welcome contributions to Solidity Verifier! If you encounter any issues, have feature requests, or want to contribute to the codebase, please check out the GitHub repository and follow the guidelines outlined in the contributing documentation.

36
cli/src/main.rs Normal file
View File

@@ -0,0 +1,36 @@
use ::clap::Parser;
use ark_serialize::Write;
use settings::Cli;
use std::path::Path;
use std::{fs, io};
mod settings;
fn create_or_open_then_write<T: AsRef<[u8]>>(path: &Path, content: &T) -> Result<(), io::Error> {
let mut file = fs::OpenOptions::new().create(true).write(true).open(path)?;
file.write_all(content.as_ref())
}
fn main() {
let cli = Cli::parse();
// generate a subscriber with the desired log level
env_logger::builder()
.format_timestamp_secs()
.filter_level(cli.verbosity.log_level_filter())
.init();
let out_path = cli.out;
// Fetch the exact protocol for which we need to generate the Decider verifier contract.
let protocol = cli.protocol;
// Fetch the protocol data passed by the user from the file.
let protocol_data = std::fs::read(cli.protocol_data).unwrap();
// Generate the Solidity Verifier contract for the selected protocol with the given data.
create_or_open_then_write(
&out_path,
&protocol.render(&protocol_data, cli.pragma).unwrap(),
)
.unwrap();
}

111
cli/src/settings.rs Normal file
View File

@@ -0,0 +1,111 @@
use ark_serialize::SerializationError;
use clap::{Parser, ValueEnum};
use solidity_verifiers::{Groth16Data, KzgData, NovaCyclefoldData, ProtocolData};
use std::{env, fmt::Display, path::PathBuf};
fn get_default_out_path() -> PathBuf {
let mut path = env::current_dir().unwrap();
path.push("verifier.sol");
path
}
#[derive(Debug, Copy, Clone, ValueEnum)]
pub(crate) enum Protocol {
Groth16,
Kzg,
NovaCyclefold,
}
impl Display for Protocol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
// Would be nice to link this to the `Template` or `ProtocolData` traits.
// Sadly, this requires Boxing with `dyn` or similar which would complicate the code more than is actually required.
impl Protocol {
pub(crate) fn render(
&self,
data: &[u8],
pragma: Option<String>,
) -> Result<Vec<u8>, SerializationError> {
match self {
Self::Groth16 => {
Ok(Groth16Data::deserialize_protocol_data(data)?.render_as_template(pragma))
}
Self::Kzg => Ok(KzgData::deserialize_protocol_data(data)?.render_as_template(pragma)),
Self::NovaCyclefold => {
Ok(NovaCyclefoldData::deserialize_protocol_data(data)?.render_as_template(pragma))
}
}
}
}
const ABOUT: &str = "A powerful Command-Line Interface (CLI) tool designed to simplify the generation of Solidity smart contracts that verify proofs of Zero Knowledge cryptographic protocols.
";
const LONG_ABOUT: &str = "
_____ ______ ______ ______ ______ ______ ______
| |__| || |__| || |__| || |__| || |__| || |__| || |__| |
| () || () || () || () || () || () || () |
|______||______||______||______||______||______||______|
______ ______
| |__| | ____ _ _ _ _ _ | |__| |
| () | / ___| ___ | (_) __| (_) |_ _ _ | () |
|______| \\___ \\ / _ \\| | |/ _` | | __| | | | |______|
______ ___) | (_) | | | (_| | | |_| |_| | ______
| |__| | |____/ \\___/|_|_|\\__,_|_|\\__|\\__, | | |__| |
| () | __ __ _ __ _ |___/ | () |
|______| \\ \\ / /__ _ __(_)/ _(_) ___ _ __ |______|
______ \\ \\ / / _ \\ '__| | |_| |/ _ \\ '__| ______
| |__| | \\ V / __/ | | | _| | __/ | | |__| |
| () | \\_/ \\___|_| |_|_| |_|\\___|_| | () |
|______| |______|
______ ______ ______ ______ ______ ______ ______
| |__| || |__| || |__| || |__| || |__| || |__| || |__| |
| () || () || () || () || () || () || () |
|______||______||______||______||______||______||______|
Welcome to Solidity Verifier, a powerful Command-Line Interface (CLI) tool designed to simplify the generation of Solidity smart contracts that verify proofs of Zero Knowledge cryptographic protocols.
for Zero Knowledge protocols. This tool is developed by the collaborative efforts of the PSE (Privacy & Scaling Explorations) and 0XPARC teams.
As an open-source project, Solidity Verifier is released under the GPL3 license.
Solidity Verifier currently supports the generation of Solidity smart contracts for the verification of proofs in the following Zero Knowledge protocols:
Groth16:
Efficient and succinct zero-knowledge proof system.
KZG:
Uses the Kate-Zaverucha-Goldberg polynomial commitment scheme.
Nova + CycleFold Decider:
Implements the decider circuit verification for the Nova zero-knowledge proof system in conjunction with the CycleFold protocol optimization.
";
#[derive(Debug, Parser)]
#[command(author = "0XPARC & PSE", version, about = ABOUT, long_about = Some(LONG_ABOUT))]
#[command(propagate_version = true)]
/// A tool to create Solidity Contracts which act as verifiers for the major Folding Schemes implemented
/// within the `folding-schemes` repo.
pub(crate) struct Cli {
#[command(flatten)]
pub verbosity: clap_verbosity_flag::Verbosity,
/// Selects the protocol for which we want to generate the Solidity Verifier contract.
#[arg(short = 'p', long, value_enum, rename_all = "lower")]
pub protocol: Protocol,
#[arg(short = 'o', long, default_value=get_default_out_path().into_os_string())]
/// Sets the output path for all the artifacts generated by the command.
pub out: PathBuf,
#[arg(short = 'd', long)]
/// Sets the input path for the file containing all the data required by the protocol chosen such that the verification contract can be generated.
pub protocol_data: PathBuf,
/// Selects the Solidity compiler version to be set in the Solidity Verifier contract artifact.
#[arg(long, default_value=None)]
pub pragma: Option<String>,
}