diff --git a/Cargo.lock b/Cargo.lock index c2ccf78f4..4d354e7b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,7 +87,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -97,7 +97,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -318,8 +318,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clio" version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7fc6734af48458f72f5a3fa7b840903606427d98a710256e808f76a965047d9" +source = "git+https://github.com/0xmozak/clio.git#a5a47f19470ee6991cf7200751eae8d2e3ac07af" dependencies = [ "cfg-if", "clap", @@ -327,7 +326,7 @@ dependencies = [ "libc", "tempfile", "walkdir", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -607,12 +606,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -790,7 +789,7 @@ checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -924,6 +923,8 @@ dependencies = [ "itertools 0.12.1", "log", "mozak-circuits-derive", + "mozak-cli-args", + "mozak-examples", "mozak-runner", "mozak-sdk", "plonky2", @@ -953,15 +954,13 @@ name = "mozak-cli" version = "0.1.0" dependencies = [ "anyhow", - "clap", - "clap-verbosity-flag", - "clap_derive", "clio", "criterion", "env_logger", "itertools 0.12.1", "log", "mozak-circuits", + "mozak-cli-args", "mozak-examples", "mozak-node", "mozak-runner", @@ -977,6 +976,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "mozak-cli-args" +version = "0.1.0" +dependencies = [ + "clap", + "clap-verbosity-flag", + "clap_derive", + "clio", +] + [[package]] name = "mozak-examples" version = "0.1.0" @@ -1057,9 +1066,9 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] name = "num" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -1082,9 +1091,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", "rand", @@ -1118,11 +1127,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -1505,7 +1513,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -1537,9 +1545,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.200" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] @@ -1557,9 +1565,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.200" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", @@ -1568,9 +1576,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -1733,7 +1741,7 @@ dependencies = [ "cfg-if", "fastrand", "rustix", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -2081,7 +2089,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -2093,21 +2101,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -2123,46 +2116,28 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.52.5" @@ -2175,48 +2150,24 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.52.5" @@ -2243,18 +2194,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.33" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "087eca3c1eaf8c47b94d02790dd086cd594b912d2043d4de4bfdd466b3befb7c" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.33" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4b6c273f496d8fd4eaf18853e6b448760225dc030ff2c485a786859aea6393" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 20151305e..16ccb30b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ [workspace] exclude = ["sdk"] members = [ + "args", "circuits", "cli", "examples-builder", @@ -56,6 +57,7 @@ plonky2_crypto = { git = "https://github.com/0xmozak/plonky2-crypto.git" } criterion = { version = "0.5", default-features = false, features = ["html_reports", "plotters", "cargo_bench_support"] } [patch.crates-io] +clio = { git = "https://github.com/0xmozak/clio.git" } plonky2 = { git = "https://github.com/0xmozak/plonky2.git" } plonky2_maybe_rayon = { git = "https://github.com/0xmozak/plonky2.git" } starky = { git = "https://github.com/0xmozak/plonky2.git" } diff --git a/args/Cargo.toml b/args/Cargo.toml new file mode 100644 index 000000000..c9aff02a8 --- /dev/null +++ b/args/Cargo.toml @@ -0,0 +1,23 @@ +[package] +categories = ["cryptography"] +description = "MozakVM cli" +edition = "2021" +keywords = ["crypto", "zero-knowledge", "vm"] +license = "All rights reserved" +name = "mozak-cli-args" +readme = "README.md" +repository = "https://github.com/0xmozak/mozak-vm" +version = "0.1.0" + +[dependencies] +clap = { version = "4.5", features = [ + "derive", + "cargo", + "env", + "unicode", +] } +# TODO(Matthias): implement shell completion for CLI via clap_complete +# clap_complete = "4.3" +clap-verbosity-flag = "2.2" +clap_derive = "4.5" +clio = { version = "0.3", features = ["clap-parse"] } diff --git a/args/src/bench_args.rs b/args/src/bench_args.rs new file mode 100644 index 000000000..42f943bb7 --- /dev/null +++ b/args/src/bench_args.rs @@ -0,0 +1,31 @@ +use clap::{Args as Args_, Subcommand}; + +#[derive(Debug, Args_, Clone)] +#[command(args_conflicts_with_subcommands = true)] +pub struct BenchArgs { + #[command(subcommand)] + pub function: BenchFunction, +} + +#[derive(PartialEq, Debug, Subcommand, Clone)] +pub enum BenchFunction { + XorBench { + iterations: u32, + }, + NopBench { + iterations: u32, + }, + Poseidon2Bench { + input_len: u32, + }, + /// Benchmarks (almost) every instruction. + OmniBench { + iterations: u32, + }, + SortBench { + n: u32, + }, + SortBenchRecursive { + n: u32, + }, +} diff --git a/args/src/lib.rs b/args/src/lib.rs new file mode 100644 index 000000000..3d1981a16 --- /dev/null +++ b/args/src/lib.rs @@ -0,0 +1,76 @@ +#![deny(clippy::pedantic)] +#![deny(clippy::cargo)] +#![allow(clippy::multiple_crate_versions)] +pub mod bench_args; + +use bench_args::BenchArgs; +use clap::{Parser, Subcommand}; +use clap_derive::Args; +use clio::{Input, Output}; + +#[derive(Parser, Debug, Clone)] +#[command(author, version, about, long_about = None)] +pub struct Cli { + #[clap(flatten)] + pub verbose: clap_verbosity_flag::Verbosity, + #[command(subcommand)] + pub command: Command, + /// Debug API, default is OFF, currently only `prove` command is supported + #[arg(short, long)] + pub debug: bool, +} + +#[derive(Clone, Debug, Args)] +pub struct RunArgs { + pub elf: Input, + #[arg(long)] + pub system_tape: Option, + #[arg(long)] + pub self_prog_id: Option, +} + +#[derive(Clone, Debug, Args)] +pub struct ProveArgs { + pub elf: Input, + pub proof: Output, + #[arg(long)] + pub system_tape: Option, + #[arg(long)] + pub self_prog_id: Option, + pub recursive_proof: Option, +} + +#[derive(Clone, Debug, Subcommand)] +pub enum Command { + /// Decode a given ELF and prints the program + Decode { elf: Input }, + /// Decode and execute a given ELF. Prints the final state of + /// the registers + Run(RunArgs), + /// Prove and verify the execution of a given ELF + ProveAndVerify(RunArgs), + /// Prove the execution of given ELF and write proof to file. + Prove(ProveArgs), + /// Verify the given proof from file. + Verify { proof: Input }, + /// Verify the given recursive proof from file. + VerifyRecursiveProof { proof: Input, verifier_key: Input }, + /// Builds a transaction bundle. + BundleTransaction { + /// System tape generated from native execution. + #[arg(long, required = true)] + system_tape: Input, + /// Output file path of the serialized bundle. + #[arg(long, default_value = "bundle")] + bundle: Output, + }, + /// Compute the Program Rom Hash of the given ELF. + ProgramRomHash { elf: Input }, + /// Compute the Memory Init Hash of the given ELF. + MemoryInitHash { elf: Input }, + /// Bench the function with given parameters + Bench(BenchArgs), +} + +#[allow(non_upper_case_globals)] +pub const parse: fn() -> Cli = Cli::parse; diff --git a/circuits/Cargo.toml b/circuits/Cargo.toml index 74efdb20d..5e24ecc00 100644 --- a/circuits/Cargo.toml +++ b/circuits/Cargo.toml @@ -18,6 +18,8 @@ expr = { path = "../expr" } itertools = "0.12" log = "0.4" mozak-circuits-derive = { path = "./derive" } +mozak-cli-args = { path = "../args" } +mozak-examples = { path = "../examples-builder" } mozak-runner = { path = "../runner" } mozak-sdk = { path = "../sdk" } plonky2 = { workspace = true, default-features = false } diff --git a/circuits/src/benches/mod.rs b/circuits/src/benches/mod.rs new file mode 100644 index 000000000..7938eb37c --- /dev/null +++ b/circuits/src/benches/mod.rs @@ -0,0 +1,47 @@ +pub mod nop; +pub mod omni; +pub mod poseidon2; +pub mod sort; +pub mod xor; + +use std::time::Duration; + +use anyhow::Result; +pub use mozak_cli_args::bench_args::{BenchArgs, BenchFunction}; +use nop::NopBench; +use omni::OmniBench; +use poseidon2::Poseidon2Bench; +use sort::{SortBench, SortBenchRecursive}; +use xor::XorBench; + +pub(crate) trait Bench { + type Args; + type Prepared; + + /// method to be executed to prepare the benchmark + fn prepare(&self, args: &Self::Args) -> Self::Prepared; + + /// actual benchmark function, whose execution time is + /// to be measured + fn execute(&self, prepared: Self::Prepared) -> Result<()>; + + /// benchmark the `execute` function implemented through the + /// trait `Bench` + fn bench(&self, args: &Self::Args) -> Result { + let prepared = self.prepare(args); + let start = std::time::Instant::now(); + self.execute(prepared)?; + Ok(start.elapsed()) + } +} + +pub fn bench(args: &BenchArgs) -> Result { + match &args.function { + BenchFunction::XorBench { iterations } => XorBench.bench(iterations), + BenchFunction::NopBench { iterations } => NopBench.bench(iterations), + BenchFunction::OmniBench { iterations } => OmniBench.bench(iterations), + BenchFunction::Poseidon2Bench { input_len } => Poseidon2Bench.bench(input_len), + BenchFunction::SortBench { n } => SortBench.bench(n), + BenchFunction::SortBenchRecursive { n } => SortBenchRecursive.bench(n), + } +} diff --git a/circuits/src/benches/nop.rs b/circuits/src/benches/nop.rs new file mode 100644 index 000000000..2322f5c13 --- /dev/null +++ b/circuits/src/benches/nop.rs @@ -0,0 +1,52 @@ +use mozak_runner::code; +use mozak_runner::elf::Program; +use mozak_runner::instruction::{Args, Instruction, Op, NOP}; +use mozak_runner::vm::ExecutionRecord; +use starky::config::StarkConfig; + +use super::Bench; +use crate::test_utils::{prove_and_verify_mozak_stark, F}; + +pub(crate) struct NopBench; + +impl Bench for NopBench { + type Args = u32; + type Prepared = (Program, ExecutionRecord); + + fn prepare(&self, &iterations: &u32) -> Self::Prepared { + let instructions = [ + Instruction { + op: Op::ADD, + args: Args { + rd: 1, + rs1: 1, + imm: 1_u32.wrapping_neg(), + ..Args::default() + }, + }, + NOP, + Instruction { + op: Op::BLT, + args: Args { + rs1: 0, + rs2: 1, + imm: 0, + ..Args::default() + }, + }, + ]; + code::execute(instructions, &[], &[(1, iterations)]) + } + + fn execute(&self, (program, record): (Program, ExecutionRecord)) -> anyhow::Result<()> { + prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) + } +} +#[cfg(test)] +mod tests { + use super::NopBench; + use crate::benches::Bench; + + #[test] + fn test_nop_bench() -> anyhow::Result<()> { NopBench {}.execute(NopBench {}.prepare(&10)) } +} diff --git a/circuits/src/benches/omni.rs b/circuits/src/benches/omni.rs new file mode 100644 index 000000000..e5747cf4c --- /dev/null +++ b/circuits/src/benches/omni.rs @@ -0,0 +1,284 @@ +use mozak_runner::code; +use mozak_runner::elf::Program; +use mozak_runner::instruction::{Args, Instruction, Op}; +use mozak_runner::vm::ExecutionRecord; +use starky::config::StarkConfig; + +use super::Bench; +use crate::test_utils::{prove_and_verify_mozak_stark, F}; + +pub(crate) struct OmniBench; + +impl Bench for OmniBench { + type Args = u32; + type Prepared = (Program, ExecutionRecord); + + /// Benchmark almost every instruction. + /// + /// Important: when extending, don't mess with register 1, because we need + /// it as the loop variable. + #[allow(clippy::too_many_lines)] + fn prepare(&self, &iterations: &u32) -> Self::Prepared { + let instructions = [ + Instruction { + op: Op::ADD, + args: Args { + rd: 2, + rs1: 1, + imm: 1_u32.wrapping_neg(), + ..Args::default() + }, + }, + Instruction { + op: Op::SUB, + args: Args { + rd: 3, + rs1: 1, + imm: 1_u32.wrapping_neg(), + ..Args::default() + }, + }, + Instruction { + op: Op::XOR, + args: Args { + rd: 3, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::OR, + args: Args { + rd: 3, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::AND, + args: Args { + rd: 3, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::SLL, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::SRL, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::SRA, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::SLT, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::SLTU, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::LB, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::LH, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::LW, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::LBU, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::SB, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::SH, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::SW, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + // TODO(Matthias): add branches, jumps and ecalls later. + Instruction { + op: Op::MUL, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::MULH, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::MULHU, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::MULHSU, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::DIV, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::DIVU, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::REM, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + Instruction { + op: Op::REMU, + args: Args { + rd: 4, + rs1: 1, + rs2: 2, + ..Args::default() + }, + }, + // The instructions for the loop: count-down and a branch back to the start. + Instruction { + op: Op::ADD, + args: Args { + rd: 1, + rs1: 1, + imm: 1_u32.wrapping_neg(), + ..Args::default() + }, + }, + Instruction { + op: Op::BLT, + args: Args { + rs1: 0, + rs2: 1, + imm: 0, + ..Args::default() + }, + }, + ]; + code::execute(instructions, &[], &[(1, iterations)]) + } + + fn execute(&self, (program, record): (Program, ExecutionRecord)) -> anyhow::Result<()> { + prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) + } +} + +#[cfg(test)] +mod tests { + use super::OmniBench; + use crate::benches::Bench; + + #[test] + fn test_omni_bench() -> anyhow::Result<()> { OmniBench {}.execute(OmniBench {}.prepare(&10)) } +} diff --git a/circuits/src/benches/poseidon2.rs b/circuits/src/benches/poseidon2.rs new file mode 100644 index 000000000..e63145175 --- /dev/null +++ b/circuits/src/benches/poseidon2.rs @@ -0,0 +1,37 @@ +use mozak_runner::elf::Program; +use mozak_runner::vm::ExecutionRecord; +use starky::config::StarkConfig; + +use super::Bench; +use crate::test_utils::{create_poseidon2_test, prove_and_verify_mozak_stark, Poseidon2Test, F}; + +pub(crate) struct Poseidon2Bench; + +impl Bench for Poseidon2Bench { + type Args = u32; + type Prepared = (Program, ExecutionRecord); + + fn prepare(&self, &input_len: &u32) -> (Program, ExecutionRecord) { + let s: String = "dead_beef_feed_c0de".repeat(input_len as usize); + create_poseidon2_test(&[Poseidon2Test { + data: s, + input_start_addr: 1024, + output_start_addr: 1024 + input_len, + }]) + } + + fn execute(&self, (program, record): (Program, ExecutionRecord)) -> anyhow::Result<()> { + prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) + } +} + +#[cfg(test)] +mod tests { + use super::Poseidon2Bench; + use crate::benches::Bench; + + #[test] + fn test_poseidon2_bench() -> anyhow::Result<()> { + Poseidon2Bench {}.execute(Poseidon2Bench {}.prepare(&10)) + } +} diff --git a/circuits/src/benches/sort.rs b/circuits/src/benches/sort.rs new file mode 100644 index 000000000..7920fd63f --- /dev/null +++ b/circuits/src/benches/sort.rs @@ -0,0 +1,101 @@ +use anyhow::Result; +use mozak_examples::MOZAK_SORT_ELF; +use mozak_runner::elf::Program; +use mozak_runner::state::{RawTapes, State}; +use mozak_runner::vm::{step, ExecutionRecord}; +use plonky2::field::types::Field; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::util::timing::TimingTree; +use starky::config::StarkConfig; + +use super::Bench; +use crate::stark::mozak_stark::{MozakStark, PublicInputs}; +use crate::stark::proof::AllProof; +use crate::stark::prover::prove; +use crate::stark::recursive_verifier::{recursive_mozak_stark_circuit, MozakStarkVerifierCircuit}; +use crate::stark::verifier::verify_proof; +use crate::test_utils::{prove_and_verify_mozak_stark, C, D, F}; + +pub(crate) struct SortBench; + +impl Bench for SortBench { + type Args = u32; + type Prepared = Result<(Program, ExecutionRecord)>; + + fn prepare(&self, &n: &u32) -> Self::Prepared { + let program = Program::vanilla_load_elf(MOZAK_SORT_ELF)?; + let raw_tapes = RawTapes { + public_tape: n.to_le_bytes().to_vec(), + ..Default::default() + }; + let state = State::new(program.clone(), raw_tapes); + let record = step(&program, state)?; + Ok((program, record)) + } + + fn execute(&self, result: Result<(Program, ExecutionRecord)>) -> Result<()> { + let (program, record) = result?; + prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) + } +} + +pub(crate) struct SortBenchRecursive; + +impl Bench for SortBenchRecursive { + type Args = u32; + type Prepared = Result<(MozakStarkVerifierCircuit, AllProof)>; + + /// Returns the stark proof for `MOZAK_SORT_ELF`, and its corresponding + /// `RecursiveVerifierCircuit`. + fn prepare(&self, &n: &u32) -> Self::Prepared { + let mozak_stark = MozakStark::default(); + let stark_config = StarkConfig::standard_fast_config(); + let (program, record) = SortBench {}.prepare(&n)?; + let public_inputs = PublicInputs { + entry_point: F::from_canonical_u32(program.entry_point), + }; + let mozak_proof = prove::( + &program, + &record, + &mozak_stark, + &stark_config, + public_inputs, + &mut TimingTree::default(), + )?; + verify_proof(&mozak_stark, mozak_proof.clone(), &stark_config)?; + let circuit_config = CircuitConfig::standard_recursion_config(); + let mozak_stark_circuit = recursive_mozak_stark_circuit::( + &mozak_stark, + &mozak_proof.degree_bits(&stark_config), + &circuit_config, + &stark_config, + ); + Ok((mozak_stark_circuit, mozak_proof)) + } + + /// Recursively verifies the stark proof for `MOZAK_SORT_ELF`, with + /// its `MozakStarkVerifierCircuit` + fn execute( + &self, + circuit_with_proof: Result<(MozakStarkVerifierCircuit, AllProof)>, + ) -> Result<()> { + let (mozak_stark_circuit, mozak_proof) = circuit_with_proof?; + let recursive_proof = mozak_stark_circuit.prove(&mozak_proof)?; + mozak_stark_circuit.circuit.verify(recursive_proof) + } +} +#[cfg(test)] +mod tests { + use anyhow::Result; + + use super::{SortBench, SortBenchRecursive}; + use crate::benches::Bench; + + #[test] + fn test_sort_bench() -> Result<()> { SortBench {}.execute(SortBench {}.prepare(&10)) } + + #[test] + fn test_recursive_sort_bench() -> Result<()> { + SortBenchRecursive {}.execute(SortBenchRecursive {}.prepare(&10)) + } +} diff --git a/circuits/src/benches/xor.rs b/circuits/src/benches/xor.rs new file mode 100644 index 000000000..7e1c3ffdb --- /dev/null +++ b/circuits/src/benches/xor.rs @@ -0,0 +1,60 @@ +use mozak_runner::code; +use mozak_runner::elf::Program; +use mozak_runner::instruction::{Args, Instruction, Op}; +use mozak_runner::vm::ExecutionRecord; +use starky::config::StarkConfig; + +use super::Bench; +use crate::test_utils::{prove_and_verify_mozak_stark, F}; + +pub(crate) struct XorBench; + +impl Bench for XorBench { + type Args = u32; + type Prepared = (Program, ExecutionRecord); + + fn prepare(&self, &iterations: &u32) -> Self::Prepared { + let instructions = [ + Instruction { + op: Op::ADD, + args: Args { + rd: 1, + rs1: 1, + imm: 1_u32.wrapping_neg(), + ..Args::default() + }, + }, + Instruction { + op: Op::XOR, + args: Args { + rd: 2, + rs1: 1, + imm: 0xDEAD_BEEF, + ..Args::default() + }, + }, + Instruction { + op: Op::BLT, + args: Args { + rs1: 0, + rs2: 1, + imm: 0, + ..Args::default() + }, + }, + ]; + code::execute(instructions, &[], &[(1, iterations)]) + } + + fn execute(&self, (program, record): (Program, ExecutionRecord)) -> anyhow::Result<()> { + prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) + } +} +#[cfg(test)] +mod tests { + use super::XorBench; + use crate::benches::Bench; + + #[test] + fn test_xor_bench() -> anyhow::Result<()> { XorBench {}.execute(XorBench {}.prepare(&10)) } +} diff --git a/circuits/src/lib.rs b/circuits/src/lib.rs index 59fbeb163..c5c917df8 100644 --- a/circuits/src/lib.rs +++ b/circuits/src/lib.rs @@ -6,6 +6,7 @@ #![allow(clippy::missing_errors_doc)] #![feature(const_trait_impl)] +pub mod benches; pub mod bitshift; pub mod columns_view; pub mod cpu; diff --git a/circuits/tests/riscv_tests.rs b/circuits/tests/riscv_tests.rs index dd79f3978..6e825fd5c 100644 --- a/circuits/tests/riscv_tests.rs +++ b/circuits/tests/riscv_tests.rs @@ -1,6 +1,6 @@ use std::include_bytes; -use anyhow::Result; +use anyhow::{Ok, Result}; use mozak_circuits::test_utils::prove_and_verify_mozak_stark; use mozak_runner::elf::Program; use mozak_runner::state::State; @@ -8,18 +8,18 @@ use mozak_runner::vm::step; use plonky2::field::goldilocks_field::GoldilocksField; use starky::config::StarkConfig; -/// This function takes the contents of a compiled ELF and runs it through the -/// Mozak VM runner to ensure correctness of the base RISC-V implementation. -/// Afterwards, we prove and verify the execution. +/// This function takes the contents of a compiled ELF and runs it through +/// the Mozak VM runner to ensure correctness of the base RISC-V +/// implementation. Afterwards, we prove and verify the execution. /// -/// Below, we use a set of test files compiled from https://github.com/riscv-software-src/riscv-tests, +/// Below, we use a set of test files compiled from . /// specifically the rv32ui and rv32um tests. /// /// These files are generated on the first `cargo build` using Docker which /// downloads the RISC-V toolchain and compiles these test files into ELFs. /// /// To use these tests, this function specifically asserts that the value of -/// x10 == 0 at the end of a run, as defined by RVTEST_PASS here: https://github.com/riscv/riscv-test-env/blob/4fabfb4e0d3eacc1dc791da70e342e4b68ea7e46/p/riscv_test.h#L247-L252 +/// x10 == 0 at the end of a run, as defined by `RVTEST_PASS` here: /// Custom tests may be added as long as the assertion is respected. fn run_test(elf: &[u8]) -> Result<()> { let _ = env_logger::try_init(); diff --git a/cli/Cargo.toml b/cli/Cargo.toml index ef5bda002..01fc6d636 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -10,26 +10,17 @@ repository = "https://github.com/0xmozak/mozak-vm" version = "0.1.0" [dependencies] -clap = { version = "4.5", features = [ - "derive", - "cargo", - "env", - "unicode", -] } -mozak-circuits = { path = "../circuits", features = ["test"] } -mozak-node = { path = "../node", features = ["std"] } -mozak-runner = { path = "../runner", features = ["test"] } -mozak-sdk = { path = "../sdk", features = ["std"] } -# TODO(Matthias): implement shell completion for CLI via clap_complete -# clap_complete = "4.3" anyhow = "1.0" -clap-verbosity-flag = "2.2" -clap_derive = "4.5" -clio = { version = "0.3", features = ["clap-parse"] } +clio = { version = "0.3" } env_logger = "0.11" itertools = "0.12" log = "0.4" +mozak-circuits = { path = "../circuits", features = ["test"] } +mozak-cli-args = { path = "../args" } mozak-examples = { path = "../examples-builder", features = ["mozak-sort"] } +mozak-node = { path = "../node", features = ["std"] } +mozak-runner = { path = "../runner", features = ["test"] } +mozak-sdk = { path = "../sdk", features = ["std"] } plonky2 = { workspace = true, default-features = false } plonky2_maybe_rayon = { workspace = true, default-features = false } rkyv = { version = "=0.8.0-alpha.1", default-features = false, features = ["pointer_width_32", "alloc"] } diff --git a/cli/src/cli_benches/benches.rs b/cli/src/cli_benches/benches.rs deleted file mode 100644 index dfe75d120..000000000 --- a/cli/src/cli_benches/benches.rs +++ /dev/null @@ -1,74 +0,0 @@ -use std::time::Duration; - -use anyhow::Result; -use clap::{Args as Args_, Subcommand}; - -use super::nop::NopBench; -use super::omni::OmniBench; -use super::poseidon2::Poseidon2Bench; -use super::sort::{SortBench, SortBenchRecursive}; -use super::xor::XorBench; - -#[derive(Debug, Args_, Clone)] -#[command(args_conflicts_with_subcommands = true)] -pub struct BenchArgs { - #[command(subcommand)] - pub function: BenchFunction, -} - -pub(crate) trait Bench { - type Args; - type Prepared; - - /// method to be executed to prepare the benchmark - fn prepare(&self, args: &Self::Args) -> Self::Prepared; - - /// actual benchmark function, whose execution time is - /// to be measured - fn execute(&self, prepared: Self::Prepared) -> Result<()>; - - /// benchmark the `execute` function implemented through the - /// trait `Bench` - fn bench(&self, args: &Self::Args) -> Result { - let prepared = self.prepare(args); - let start = std::time::Instant::now(); - self.execute(prepared)?; - Ok(start.elapsed()) - } -} - -#[derive(PartialEq, Debug, Subcommand, Clone)] -pub enum BenchFunction { - XorBench { - iterations: u32, - }, - NopBench { - iterations: u32, - }, - Poseidon2Bench { - input_len: u32, - }, - /// Benchmarks (almost) every instruction. - OmniBench { - iterations: u32, - }, - SortBench { - n: u32, - }, - SortBenchRecursive { - n: u32, - }, -} - -impl BenchArgs { - pub fn bench(&self) -> Result { - match &self.function { - BenchFunction::XorBench { iterations } => XorBench.bench(iterations), - BenchFunction::NopBench { iterations } => NopBench.bench(iterations), - BenchFunction::OmniBench { iterations } => OmniBench.bench(iterations), - BenchFunction::Poseidon2Bench { input_len } => Poseidon2Bench.bench(input_len), - BenchFunction::SortBench { n } => SortBench.bench(n), - BenchFunction::SortBenchRecursive { n } => SortBenchRecursive.bench(n), - } - } -} diff --git a/cli/src/cli_benches/mod.rs b/cli/src/cli_benches/mod.rs deleted file mode 100644 index 354332982..000000000 --- a/cli/src/cli_benches/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod benches; -pub mod nop; -pub mod omni; -pub mod poseidon2; -pub mod sort; -pub mod xor; diff --git a/cli/src/cli_benches/nop.rs b/cli/src/cli_benches/nop.rs deleted file mode 100644 index 8d60587db..000000000 --- a/cli/src/cli_benches/nop.rs +++ /dev/null @@ -1,58 +0,0 @@ -use mozak_circuits::test_utils::{prove_and_verify_mozak_stark, F}; -use mozak_runner::code; -use mozak_runner::elf::Program; -use mozak_runner::instruction::{Args, Instruction, Op, NOP}; -use mozak_runner::vm::ExecutionRecord; -use starky::config::StarkConfig; - -use super::benches::Bench; - -#[allow(clippy::module_name_repetitions)] -pub fn nop_execute((program, record): (Program, ExecutionRecord)) -> Result<(), anyhow::Error> { - prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) -} -pub fn nop_prepare(iterations: u32) -> (Program, ExecutionRecord) { - let instructions = [ - Instruction { - op: Op::ADD, - args: Args { - rd: 1, - rs1: 1, - imm: 1_u32.wrapping_neg(), - ..Args::default() - }, - }, - NOP, - Instruction { - op: Op::BLT, - args: Args { - rs1: 0, - rs2: 1, - imm: 0, - ..Args::default() - }, - }, - ]; - code::execute(instructions, &[], &[(1, iterations)]) -} - -pub(crate) struct NopBench; - -impl Bench for NopBench { - type Args = u32; - type Prepared = (Program, ExecutionRecord); - - fn prepare(&self, args: &Self::Args) -> Self::Prepared { nop_prepare(*args) } - - fn execute(&self, prepared: Self::Prepared) -> anyhow::Result<()> { nop_execute(prepared) } -} -#[cfg(test)] -mod tests { - use super::{nop_execute, nop_prepare}; - - #[test] - fn test_nop_bench() -> anyhow::Result<()> { - let iterations = 10; - nop_execute(nop_prepare(iterations)) - } -} diff --git a/cli/src/cli_benches/omni.rs b/cli/src/cli_benches/omni.rs deleted file mode 100644 index 3573abd43..000000000 --- a/cli/src/cli_benches/omni.rs +++ /dev/null @@ -1,290 +0,0 @@ -use mozak_circuits::test_utils::{prove_and_verify_mozak_stark, F}; -use mozak_runner::code; -use mozak_runner::elf::Program; -use mozak_runner::instruction::{Args, Instruction, Op}; -use mozak_runner::vm::ExecutionRecord; -use starky::config::StarkConfig; - -use super::benches::Bench; - -pub fn omni_execute((program, record): (Program, ExecutionRecord)) -> Result<(), anyhow::Error> { - prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) -} - -#[allow(clippy::module_name_repetitions)] -/// Benchmark almost every instruction. -/// -/// Important: when extending, don't mess with register 1, because we need it as -/// the loop variable. -pub fn omni_prepare(iterations: u32) -> (Program, ExecutionRecord) { - let instructions = [ - Instruction { - op: Op::ADD, - args: Args { - rd: 2, - rs1: 1, - imm: 1_u32.wrapping_neg(), - ..Args::default() - }, - }, - Instruction { - op: Op::SUB, - args: Args { - rd: 3, - rs1: 1, - imm: 1_u32.wrapping_neg(), - ..Args::default() - }, - }, - Instruction { - op: Op::XOR, - args: Args { - rd: 3, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::OR, - args: Args { - rd: 3, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::AND, - args: Args { - rd: 3, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::SLL, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::SRL, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::SRA, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::SLT, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::SLTU, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::LB, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::LH, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::LW, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::LBU, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::SB, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::SH, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::SW, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - // TODO(Matthias): add branches, jumps and ecalls later. - Instruction { - op: Op::MUL, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::MULH, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::MULHU, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::MULHSU, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::DIV, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::DIVU, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::REM, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - Instruction { - op: Op::REMU, - args: Args { - rd: 4, - rs1: 1, - rs2: 2, - ..Args::default() - }, - }, - // The instructions for the loop: count-down and a branch back to the start. - Instruction { - op: Op::ADD, - args: Args { - rd: 1, - rs1: 1, - imm: 1_u32.wrapping_neg(), - ..Args::default() - }, - }, - Instruction { - op: Op::BLT, - args: Args { - rs1: 0, - rs2: 1, - imm: 0, - ..Args::default() - }, - }, - ]; - code::execute(instructions, &[], &[(1, iterations)]) -} - -pub(crate) struct OmniBench; - -impl Bench for OmniBench { - type Args = u32; - type Prepared = (Program, ExecutionRecord); - - fn prepare(&self, args: &Self::Args) -> Self::Prepared { omni_prepare(*args) } - - fn execute(&self, prepared: Self::Prepared) -> anyhow::Result<()> { omni_execute(prepared) } -} - -#[cfg(test)] -mod tests { - use super::{omni_execute, omni_prepare}; - - #[test] - fn test_omni_bench() -> anyhow::Result<()> { - let iterations = 10; - omni_execute(omni_prepare(iterations)) - } -} diff --git a/cli/src/cli_benches/poseidon2.rs b/cli/src/cli_benches/poseidon2.rs deleted file mode 100644 index 32fb3ef0c..000000000 --- a/cli/src/cli_benches/poseidon2.rs +++ /dev/null @@ -1,46 +0,0 @@ -use mozak_circuits::test_utils::{ - create_poseidon2_test, prove_and_verify_mozak_stark, Poseidon2Test, F, -}; -use mozak_runner::elf::Program; -use mozak_runner::vm::ExecutionRecord; -use starky::config::StarkConfig; - -use super::benches::Bench; - -pub fn poseidon2_execute( - (program, record): (Program, ExecutionRecord), -) -> Result<(), anyhow::Error> { - prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) -} -pub fn poseidon2_prepare(input_len: u32) -> (Program, ExecutionRecord) { - let s: String = "dead_beef_feed_c0de".repeat(input_len as usize); - create_poseidon2_test(&[Poseidon2Test { - data: s, - input_start_addr: 1024, - output_start_addr: 1024 + input_len, - }]) -} - -pub(crate) struct Poseidon2Bench; - -impl Bench for Poseidon2Bench { - type Args = u32; - type Prepared = (Program, ExecutionRecord); - - fn prepare(&self, args: &Self::Args) -> Self::Prepared { poseidon2_prepare(*args) } - - fn execute(&self, prepared: Self::Prepared) -> anyhow::Result<()> { - poseidon2_execute(prepared) - } -} - -#[cfg(test)] -mod tests { - use super::{poseidon2_execute, poseidon2_prepare}; - - #[test] - fn test_poseidon2_bench() -> anyhow::Result<()> { - let input_len = 10; - poseidon2_execute(poseidon2_prepare(input_len)) - } -} diff --git a/cli/src/cli_benches/sort.rs b/cli/src/cli_benches/sort.rs deleted file mode 100644 index 7104b1c45..000000000 --- a/cli/src/cli_benches/sort.rs +++ /dev/null @@ -1,114 +0,0 @@ -use anyhow::Result; -use mozak_circuits::stark::mozak_stark::{MozakStark, PublicInputs}; -use mozak_circuits::stark::proof::AllProof; -use mozak_circuits::stark::prover::prove; -use mozak_circuits::stark::recursive_verifier::{ - recursive_mozak_stark_circuit, MozakStarkVerifierCircuit, -}; -use mozak_circuits::stark::verifier::verify_proof; -use mozak_circuits::test_utils::{prove_and_verify_mozak_stark, C, D, F}; -use mozak_examples::MOZAK_SORT_ELF; -use mozak_runner::elf::Program; -use mozak_runner::state::{RawTapes, State}; -use mozak_runner::vm::{step, ExecutionRecord}; -use plonky2::field::types::Field; -use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::util::timing::TimingTree; -use starky::config::StarkConfig; - -use super::benches::Bench; - -pub fn sort_execute(result: Result<(Program, ExecutionRecord)>) -> Result<()> { - let (program, record) = result?; - prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) -} - -pub fn sort_prepare(n: u32) -> Result<(Program, ExecutionRecord)> { - let program = Program::vanilla_load_elf(MOZAK_SORT_ELF)?; - let raw_tapes = RawTapes { - public_tape: n.to_le_bytes().to_vec(), - ..Default::default() - }; - let state = State::new(program.clone(), raw_tapes); - let record = step(&program, state)?; - Ok((program, record)) -} - -/// Returns the stark proof for `MOZAK_SORT_ELF`, and its corresponding -/// `RecursiveVerifierCircuit`. -pub fn sort_recursive_prepare( - n: u32, -) -> Result<(MozakStarkVerifierCircuit, AllProof)> { - let mozak_stark = MozakStark::default(); - let stark_config = StarkConfig::standard_fast_config(); - let (program, record) = sort_prepare(n)?; - let public_inputs = PublicInputs { - entry_point: F::from_canonical_u32(program.entry_point), - }; - let mozak_proof = prove::( - &program, - &record, - &mozak_stark, - &stark_config, - public_inputs, - &mut TimingTree::default(), - )?; - verify_proof(&mozak_stark, mozak_proof.clone(), &stark_config)?; - let circuit_config = CircuitConfig::standard_recursion_config(); - let mozak_stark_circuit = recursive_mozak_stark_circuit::( - &mozak_stark, - &mozak_proof.degree_bits(&stark_config), - &circuit_config, - &stark_config, - ); - Ok((mozak_stark_circuit, mozak_proof)) -} - -/// Recursively verifies the stark proof for `MOZAK_SORT_ELF`, with -/// its `MozakStarkVerifierCircuit` -pub fn sort_recursive_execute( - circuit_with_proof: Result<(MozakStarkVerifierCircuit, AllProof)>, -) -> Result<()> { - let (mozak_stark_circuit, mozak_proof) = circuit_with_proof?; - let recursive_proof = mozak_stark_circuit.prove(&mozak_proof)?; - mozak_stark_circuit.circuit.verify(recursive_proof) -} - -pub(crate) struct SortBench; - -impl Bench for SortBench { - type Args = u32; - type Prepared = Result<(Program, ExecutionRecord)>; - - fn prepare(&self, args: &Self::Args) -> Self::Prepared { sort_prepare(*args) } - - fn execute(&self, prepared: Self::Prepared) -> Result<()> { sort_execute(prepared) } -} - -pub(crate) struct SortBenchRecursive; - -impl Bench for SortBenchRecursive { - type Args = u32; - type Prepared = Result<(MozakStarkVerifierCircuit, AllProof)>; - - fn prepare(&self, args: &Self::Args) -> Self::Prepared { sort_recursive_prepare(*args) } - - fn execute(&self, prepared: Self::Prepared) -> Result<()> { sort_recursive_execute(prepared) } -} -#[cfg(test)] -mod tests { - use anyhow::Result; - - use super::{sort_execute, sort_prepare, sort_recursive_execute, sort_recursive_prepare}; - - #[test] - fn test_sort_bench() -> Result<()> { - let n = 10; - sort_execute(sort_prepare(n)) - } - #[test] - fn test_recursive_sort_bench() -> Result<()> { - let n = 10; - sort_recursive_execute(sort_recursive_prepare(n)) - } -} diff --git a/cli/src/cli_benches/xor.rs b/cli/src/cli_benches/xor.rs deleted file mode 100644 index cc4d3af84..000000000 --- a/cli/src/cli_benches/xor.rs +++ /dev/null @@ -1,67 +0,0 @@ -use mozak_circuits::test_utils::{prove_and_verify_mozak_stark, F}; -use mozak_runner::code; -use mozak_runner::elf::Program; -use mozak_runner::instruction::{Args, Instruction, Op}; -use mozak_runner::vm::ExecutionRecord; -use starky::config::StarkConfig; - -use super::benches::Bench; - -#[allow(clippy::module_name_repetitions)] -pub fn xor_execute((program, record): (Program, ExecutionRecord)) -> Result<(), anyhow::Error> { - prove_and_verify_mozak_stark(&program, &record, &StarkConfig::standard_fast_config()) -} - -pub fn xor_prepare(iterations: u32) -> (Program, ExecutionRecord) { - let instructions = [ - Instruction { - op: Op::ADD, - args: Args { - rd: 1, - rs1: 1, - imm: 1_u32.wrapping_neg(), - ..Args::default() - }, - }, - Instruction { - op: Op::XOR, - args: Args { - rd: 2, - rs1: 1, - imm: 0xDEAD_BEEF, - ..Args::default() - }, - }, - Instruction { - op: Op::BLT, - args: Args { - rs1: 0, - rs2: 1, - imm: 0, - ..Args::default() - }, - }, - ]; - code::execute(instructions, &[], &[(1, iterations)]) -} - -pub(crate) struct XorBench; - -impl Bench for XorBench { - type Args = u32; - type Prepared = (Program, ExecutionRecord); - - fn prepare(&self, args: &Self::Args) -> Self::Prepared { xor_prepare(*args) } - - fn execute(&self, prepared: Self::Prepared) -> anyhow::Result<()> { xor_execute(prepared) } -} -#[cfg(test)] -mod tests { - use super::{xor_execute, xor_prepare}; - - #[test] - fn test_xor_bench() -> anyhow::Result<()> { - let iterations = 10; - xor_execute(xor_prepare(iterations)) - } -} diff --git a/cli/src/lib.rs b/cli/src/lib.rs index c30e7ac46..e174d82fc 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -1,4 +1,3 @@ -pub mod cli_benches; pub mod runner; #[cfg(test)] mod tests; diff --git a/cli/src/main.rs b/cli/src/main.rs index 55bbf90c3..179b1d494 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,18 +1,15 @@ #![deny(clippy::pedantic)] #![deny(clippy::cargo)] -// TODO(bing): `clio` uses an older `windows-sys` vs other dependencies. -// Remove when `clio` updates, or if `clio` is no longer needed. -#![allow(clippy::multiple_crate_versions)] + use std::collections::HashMap; use std::io::{Read, Write}; use std::path::PathBuf; use anyhow::Result; -use clap::{Parser, Subcommand}; -use clap_derive::Args; -use clio::{Input, Output}; +use clio::Input; use itertools::Itertools; use log::debug; +use mozak_circuits::benches::bench; use mozak_circuits::generation::memoryinit::generate_elf_memory_init_trace; use mozak_circuits::generation::storage_device::generate_call_tape_trace; use mozak_circuits::program::generation::generate_program_rom_trace; @@ -27,8 +24,8 @@ use mozak_circuits::stark::recursive_verifier::{ use mozak_circuits::stark::utils::trace_rows_to_poly_values; use mozak_circuits::stark::verifier::verify_proof; use mozak_circuits::test_utils::{prove_and_verify_mozak_stark, C, D, F, S}; -use mozak_cli::cli_benches::benches::BenchArgs; use mozak_cli::runner::{deserialize_system_tape, load_program, raw_tapes_from_system_tape}; +use mozak_cli_args::{parse, Command, ProveArgs, RunArgs}; use mozak_node::types::{Attestation, Transaction}; use mozak_runner::state::{RawTapes, State}; use mozak_runner::vm::step; @@ -42,75 +39,11 @@ use starky::config::StarkConfig; const PROGRAMS_MAP_JSON: &str = "examples/programs_map.json"; -#[derive(Parser, Debug, Clone)] -#[command(author, version, about, long_about = None)] -struct Cli { - #[clap(flatten)] - verbose: clap_verbosity_flag::Verbosity, - #[command(subcommand)] - command: Command, - /// Debug API, default is OFF, currently only `prove` command is supported - #[arg(short, long)] - debug: bool, -} - -#[derive(Clone, Debug, Args)] -pub struct RunArgs { - elf: Input, - #[arg(long)] - system_tape: Option, - #[arg(long)] - self_prog_id: Option, -} - -#[derive(Clone, Debug, Args)] -pub struct ProveArgs { - elf: Input, - proof: Output, - #[arg(long)] - system_tape: Option, - #[arg(long)] - self_prog_id: Option, - recursive_proof: Option, -} - -#[derive(Clone, Debug, Subcommand)] -enum Command { - /// Decode a given ELF and prints the program - Decode { elf: Input }, - /// Decode and execute a given ELF. Prints the final state of - /// the registers - Run(RunArgs), - /// Prove and verify the execution of a given ELF - ProveAndVerify(RunArgs), - /// Prove the execution of given ELF and write proof to file. - Prove(ProveArgs), - /// Verify the given proof from file. - Verify { proof: Input }, - /// Verify the given recursive proof from file. - VerifyRecursiveProof { proof: Input, verifier_key: Input }, - /// Builds a transaction bundle. - BundleTransaction { - /// System tape generated from native execution. - #[arg(long, required = true)] - system_tape: Input, - /// Output file path of the serialized bundle. - #[arg(long, default_value = "bundle")] - bundle: Output, - }, - /// Compute the Program Rom Hash of the given ELF. - ProgramRomHash { elf: Input }, - /// Compute the Memory Init Hash of the given ELF. - MemoryInitHash { elf: Input }, - /// Bench the function with given parameters - Bench(BenchArgs), -} - /// Run me eg like `cargo run -- -vvv run vm/tests/testdata/rv32ui-p-addi /// iotape.txt` #[allow(clippy::too_many_lines)] fn main() -> Result<()> { - let cli = Cli::parse(); + let cli = parse(); let config = StarkConfig::standard_fast_config(); env_logger::Builder::new() .filter_level(cli.verbose.log_level_filter()) @@ -415,8 +348,8 @@ fn main() -> Result<()> { let trace_cap = trace_commitment.merkle_tree.cap; println!("{trace_cap:?}"); } - Command::Bench(bench) => { - let time_taken = bench.bench()?.as_secs_f64(); + Command::Bench(args) => { + let time_taken = bench(&args)?.as_secs_f64(); println!("{time_taken}"); } }