diff --git a/.gitignore b/.gitignore index 33e3eff..a68e333 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ target #.idea/ .DS_Store /contracts/broadcast/* + +# Pico EVM proof artifacts (contains trusted setup keys and proofs) +evm_proof_artifacts/ diff --git a/Cargo.lock b/Cargo.lock index 471230d..83884e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1310,6 +1310,10 @@ dependencies = [ "crossbeam", "lazy_static", "log", + "p3-field 0.1.0", + "pico-methods", + "pico-sdk", + "pico-vm", "risc0-ethereum-contracts", "risc0-methods", "risc0-zkvm", @@ -1929,7 +1933,7 @@ checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941" dependencies = [ "ff 0.12.1", "group 0.12.1", - "pairing", + "pairing 0.22.0", "rand_core 0.6.4", "subtle", ] @@ -2335,6 +2339,27 @@ dependencies = [ "libc", ] +[[package]] +name = "core_affinity" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a034b3a7b624016c6e13f5df875747cc25f884156aad2abd12b6c46797971342" +dependencies = [ + "libc", + "num_cpus", + "winapi", +] + +[[package]] +name = "cpu-time" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e393a7668fe1fad3075085b86c781883000b4ede868f43627b34a87c8b7ded" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -2443,6 +2468,27 @@ dependencies = [ "typenum", ] +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + [[package]] name = "ctrlc" version = "3.4.7" @@ -2453,6 +2499,32 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version 0.4.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "darling" version = "0.20.11" @@ -2950,6 +3022,29 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -3054,6 +3149,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "fixed-hash" version = "0.8.0" @@ -3398,6 +3499,50 @@ dependencies = [ "rayon", ] +[[package]] +name = "halo2curves" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d380afeef3f1d4d3245b76895172018cfb087d9976a7cabcd5597775b2933e07" +dependencies = [ + "blake2", + "digest 0.10.7", + "ff 0.13.1", + "group 0.13.0", + "halo2derive", + "hex", + "lazy_static", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "pairing 0.23.0", + "pasta_curves 0.5.1", + "paste", + "rand 0.8.5", + "rand_core 0.6.4", + "rayon", + "serde", + "serde_arrays", + "sha2 0.10.9", + "static_assertions", + "subtle", + "unroll", +] + +[[package]] +name = "halo2derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb99e7492b4f5ff469d238db464131b86c2eaac814a78715acba369f64d2c76" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -3564,6 +3709,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d35805454dc9f8662a98d6d61886ffe26bd465f5960e0e55345c70d5c0d2a9" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "0.14.32" @@ -3964,6 +4118,30 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "jobserver" version = "0.1.34" @@ -4398,6 +4576,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "rand 0.8.5", ] [[package]] @@ -4546,6 +4725,18 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "nums" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3c74f925fb8cfc49a8022f2afce48a0683b70f9e439885594e84c5edbf5b01" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "rand 0.8.5", +] + [[package]] name = "nybbles" version = "0.4.0" @@ -4704,14 +4895,37 @@ dependencies = [ "sp1-lib 5.2.1", ] +[[package]] +name = "p3-air" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "p3-field 0.1.0", + "p3-matrix 0.1.0", +] + [[package]] name = "p3-air" version = "0.2.3-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05a97452c4b1cfa8626e69181d901fc8231d99ff7d87e9701a2e6b934606615" dependencies = [ - "p3-field", - "p3-matrix", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", +] + +[[package]] +name = "p3-baby-bear" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "p3-field 0.1.0", + "p3-mds 0.1.0", + "p3-monty-31", + "p3-poseidon2 0.1.0", + "p3-symmetric 0.1.0", + "rand 0.8.5", + "serde", ] [[package]] @@ -4721,10 +4935,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7521838ecab2ddf4f7bc4ceebad06ec02414729598485c1ada516c39900820e8" dependencies = [ "num-bigint 0.4.6", - "p3-field", - "p3-mds", - "p3-poseidon2", - "p3-symmetric", + "p3-field 0.2.3-succinct", + "p3-mds 0.2.3-succinct", + "p3-poseidon2 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-blake3" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "blake3", + "p3-symmetric 0.1.0", + "p3-util 0.1.0", +] + +[[package]] +name = "p3-bn254-fr" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "ff 0.13.1", + "halo2curves", + "num-bigint 0.4.6", + "p3-field 0.1.0", + "p3-poseidon2 0.1.0", + "p3-symmetric 0.1.0", "rand 0.8.5", "serde", ] @@ -4737,27 +4976,71 @@ checksum = "c0dd4d095d254783098bd09fc5fdf33fd781a1be54608ab93cb3ed4bd723da54" dependencies = [ "ff 0.13.1", "num-bigint 0.4.6", - "p3-field", - "p3-poseidon2", - "p3-symmetric", + "p3-field 0.2.3-succinct", + "p3-poseidon2 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", "rand 0.8.5", "serde", ] +[[package]] +name = "p3-challenger" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "p3-field 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-symmetric 0.1.0", + "p3-util 0.1.0", + "tracing", +] + [[package]] name = "p3-challenger" version = "0.2.3-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d18c223b7e0177f4ac91070fa3f6cc557d5ee3b279869924c3102fb1b20910" dependencies = [ - "p3-field", - "p3-maybe-rayon", - "p3-symmetric", - "p3-util", + "p3-field 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "p3-util 0.2.3-succinct", "serde", "tracing", ] +[[package]] +name = "p3-circle" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-challenger 0.1.0", + "p3-commit 0.1.0", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-fri 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-util 0.1.0", + "serde", + "tracing", +] + +[[package]] +name = "p3-commit" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-challenger 0.1.0", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-util 0.1.0", + "serde", +] + [[package]] name = "p3-commit" version = "0.2.3-succinct" @@ -4765,23 +5048,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b38fe979d53d4f1d64158c40b3cd9ea1bd6b7bc8f085e489165c542ef914ae28" dependencies = [ "itertools 0.12.1", - "p3-challenger", - "p3-field", - "p3-matrix", - "p3-util", + "p3-challenger 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-util 0.2.3-succinct", "serde", ] +[[package]] +name = "p3-dft" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-util 0.1.0", + "tracing", +] + [[package]] name = "p3-dft" version = "0.2.3-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46414daedd796f1eefcdc1811c0484e4bced5729486b6eaba9521c572c76761a" dependencies = [ - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-util 0.2.3-succinct", + "tracing", +] + +[[package]] +name = "p3-field" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "nums", + "p3-maybe-rayon 0.1.0", + "p3-util 0.1.0", + "rand 0.8.5", + "serde", "tracing", ] @@ -4794,11 +5107,30 @@ dependencies = [ "itertools 0.12.1", "num-bigint 0.4.6", "num-traits", - "p3-util", + "p3-util 0.2.3-succinct", "rand 0.8.5", "serde", ] +[[package]] +name = "p3-fri" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-challenger 0.1.0", + "p3-commit 0.1.0", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-interpolation 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-util 0.1.0", + "rand 0.8.5", + "serde", + "tracing", +] + [[package]] name = "p3-fri" version = "0.2.3-succinct" @@ -4806,27 +5138,79 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c274dab2dcd060cdea9ab3f8f7129f5fa5f08917d6092dc2b297a31d883aa0" dependencies = [ "itertools 0.12.1", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-interpolation", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", + "p3-challenger 0.2.3-succinct", + "p3-commit 0.2.3-succinct", + "p3-dft 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-interpolation 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-util 0.2.3-succinct", "serde", "tracing", ] +[[package]] +name = "p3-goldilocks" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "num-bigint 0.4.6", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-mds 0.1.0", + "p3-poseidon2 0.1.0", + "p3-symmetric 0.1.0", + "p3-util 0.1.0", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-interpolation" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-util 0.1.0", +] + [[package]] name = "p3-interpolation" version = "0.2.3-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed8de7333abb0ad0a17bb78726a43749cc7fcab4763f296894e8b2933841d4d8" dependencies = [ - "p3-field", - "p3-matrix", - "p3-util", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-util 0.2.3-succinct", +] + +[[package]] +name = "p3-keccak" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-field 0.1.0", + "p3-symmetric 0.1.0", + "p3-util 0.1.0", + "tiny-keccak", +] + +[[package]] +name = "p3-keccak-air" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "p3-air 0.1.0", + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-util 0.1.0", + "tracing", ] [[package]] @@ -4835,14 +5219,43 @@ version = "0.2.3-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01c7ec21317c455d39588428e4ec85b96d663ff171ddf102a10e2ca54c942dea" dependencies = [ - "p3-air", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", + "p3-air 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-util 0.2.3-succinct", "tracing", ] +[[package]] +name = "p3-koala-bear" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "p3-field 0.1.0", + "p3-mds 0.1.0", + "p3-monty-31", + "p3-poseidon2 0.1.0", + "p3-symmetric 0.1.0", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-matrix" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-field 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-util 0.1.0", + "rand 0.8.5", + "serde", + "tracing", + "transpose", +] + [[package]] name = "p3-matrix" version = "0.2.3-succinct" @@ -4850,14 +5263,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e4de3f373589477cb735ea58e125898ed20935e03664b4614c7fac258b3c42f" dependencies = [ "itertools 0.12.1", - "p3-field", - "p3-maybe-rayon", - "p3-util", + "p3-field 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-util 0.2.3-succinct", "rand 0.8.5", "serde", "tracing", ] +[[package]] +name = "p3-maybe-rayon" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "rayon", +] + [[package]] name = "p3-maybe-rayon" version = "0.2.3-succinct" @@ -4867,6 +5288,20 @@ dependencies = [ "rayon", ] +[[package]] +name = "p3-mds" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-symmetric 0.1.0", + "p3-util 0.1.0", + "rand 0.8.5", +] + [[package]] name = "p3-mds" version = "0.2.3-succinct" @@ -4874,14 +5309,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2356b1ed0add6d5dfbf7a338ce534a6fde827374394a52cec16a0840af6e97c9" dependencies = [ "itertools 0.12.1", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-symmetric", - "p3-util", + "p3-dft 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "p3-util 0.2.3-succinct", "rand 0.8.5", ] +[[package]] +name = "p3-merkle-tree" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-commit 0.1.0", + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-symmetric 0.1.0", + "p3-util 0.1.0", + "rand 0.8.5", + "serde", + "tracing", +] + [[package]] name = "p3-merkle-tree" version = "0.2.3-succinct" @@ -4889,16 +5341,68 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f159e073afbee02c00d22390bf26ebb9ce03bbcd3e6dcd13c6a7a3811ab39608" dependencies = [ "itertools 0.12.1", - "p3-commit", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-symmetric", - "p3-util", + "p3-commit 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "p3-util 0.2.3-succinct", "serde", "tracing", ] +[[package]] +name = "p3-mersenne-31" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "num-bigint 0.4.6", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-mds 0.1.0", + "p3-poseidon2 0.1.0", + "p3-symmetric 0.1.0", + "p3-util 0.1.0", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-monty-31" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "num-bigint 0.4.6", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-mds 0.1.0", + "p3-poseidon2 0.1.0", + "p3-symmetric 0.1.0", + "p3-util 0.1.0", + "rand 0.8.5", + "serde", + "tracing", + "transpose", +] + +[[package]] +name = "p3-poseidon2" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "gcd", + "p3-field 0.1.0", + "p3-mds 0.1.0", + "p3-symmetric 0.1.0", + "rand 0.8.5", +] + [[package]] name = "p3-poseidon2" version = "0.2.3-succinct" @@ -4906,13 +5410,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da1eec7e1b6900581bedd95e76e1ef4975608dd55be9872c9d257a8a9651c3a" dependencies = [ "gcd", - "p3-field", - "p3-mds", - "p3-symmetric", + "p3-field 0.2.3-succinct", + "p3-mds 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", "rand 0.8.5", "serde", ] +[[package]] +name = "p3-symmetric" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-field 0.1.0", + "serde", +] + [[package]] name = "p3-symmetric" version = "0.2.3-succinct" @@ -4920,10 +5434,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb439bea1d822623b41ff4b51e3309e80d13cadf8b86d16ffd5e6efb9fdc360" dependencies = [ "itertools 0.12.1", - "p3-field", + "p3-field 0.2.3-succinct", "serde", ] +[[package]] +name = "p3-uni-stark" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "itertools 0.13.0", + "p3-air 0.1.0", + "p3-challenger 0.1.0", + "p3-commit 0.1.0", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-util 0.1.0", + "serde", + "tracing", +] + [[package]] name = "p3-uni-stark" version = "0.2.3-succinct" @@ -4931,18 +5463,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a86f29c32bf46fa4acb6547d2065a711e146d4faca388b56d75718c60a0097d" dependencies = [ "itertools 0.12.1", - "p3-air", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", + "p3-air 0.2.3-succinct", + "p3-challenger 0.2.3-succinct", + "p3-commit 0.2.3-succinct", + "p3-dft 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-util 0.2.3-succinct", "serde", "tracing", ] +[[package]] +name = "p3-util" +version = "0.1.0" +source = "git+https://github.com/brevis-network/Plonky3.git?rev=a4d376b#a4d376babf5d09497f1fab1df7f1ffce01260973" +dependencies = [ + "serde", +] + [[package]] name = "p3-util" version = "0.2.3-succinct" @@ -4973,6 +5513,15 @@ dependencies = [ "group 0.12.1", ] +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group 0.13.0", +] + [[package]] name = "parity-scale-codec" version = "3.7.5" @@ -5048,8 +5597,10 @@ dependencies = [ "blake2b_simd", "ff 0.13.1", "group 0.13.0", + "hex", "lazy_static", "rand 0.8.5", + "serde", "static_assertions", "subtle", ] @@ -5102,6 +5653,156 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pico-aggregator" +version = "0.1.0" +dependencies = [ + "aws-nitro-enclave-attestation-verifier", + "pico-sdk", +] + +[[package]] +name = "pico-derive" +version = "0.1.0" +source = "git+https://github.com/automata-network/pico.git?branch=evm_defer_proof#27e6e6c34598471a149ed122d7f91b440f7b646b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pico-methods" +version = "0.1.0" + +[[package]] +name = "pico-patch-libs" +version = "1.1.6" +source = "git+https://github.com/automata-network/pico.git?branch=evm_defer_proof#27e6e6c34598471a149ed122d7f91b440f7b646b" +dependencies = [ + "bincode", + "serde", +] + +[[package]] +name = "pico-sdk" +version = "1.1.6" +source = "git+https://github.com/automata-network/pico.git?branch=evm_defer_proof#27e6e6c34598471a149ed122d7f91b440f7b646b" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "env_logger", + "getrandom 0.2.16", + "hex", + "lazy_static", + "log", + "p3-baby-bear 0.1.0", + "p3-challenger 0.1.0", + "p3-field 0.1.0", + "p3-koala-bear", + "p3-mersenne-31", + "pico-patch-libs", + "pico-vm", + "rand 0.8.5", + "serde", + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "pico-verifier" +version = "0.1.0" +dependencies = [ + "aws-nitro-enclave-attestation-verifier", + "pico-sdk", +] + +[[package]] +name = "pico-vm" +version = "1.1.6" +source = "git+https://github.com/automata-network/pico.git?branch=evm_defer_proof#27e6e6c34598471a149ed122d7f91b440f7b646b" +dependencies = [ + "anyhow", + "arrayref", + "backtrace", + "bincode", + "bytemuck", + "cfg-if", + "clap", + "core_affinity", + "cpu-time", + "crossbeam", + "csv", + "curve25519-dalek", + "dashmap", + "dashu", + "derive_more 2.0.1", + "elf", + "elliptic-curve", + "eyre", + "ff 0.13.1", + "halo2curves", + "hashbrown 0.14.5", + "hex", + "hybrid-array", + "itertools 0.13.0", + "k256", + "lazy_static", + "log", + "num", + "num-bigint 0.4.6", + "num-traits", + "num_cpus", + "once_cell", + "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "p3-air 0.1.0", + "p3-baby-bear 0.1.0", + "p3-blake3", + "p3-bn254-fr 0.1.0", + "p3-challenger 0.1.0", + "p3-circle", + "p3-commit 0.1.0", + "p3-dft 0.1.0", + "p3-field 0.1.0", + "p3-fri 0.1.0", + "p3-goldilocks", + "p3-keccak", + "p3-keccak-air 0.1.0", + "p3-koala-bear", + "p3-matrix 0.1.0", + "p3-maybe-rayon 0.1.0", + "p3-mds 0.1.0", + "p3-merkle-tree 0.1.0", + "p3-mersenne-31", + "p3-poseidon2 0.1.0", + "p3-symmetric 0.1.0", + "p3-uni-stark 0.1.0", + "p3-util 0.1.0", + "paste", + "pico-derive", + "rand 0.8.5", + "rayon", + "rayon-scan", + "rrs-succinct", + "serde", + "serde_json", + "serde_with 3.14.0", + "snowbridge-amcl", + "static_assertions", + "strum 0.26.3", + "strum_macros 0.26.4", + "sysinfo", + "thiserror 1.0.69", + "tiny-keccak", + "tracing", + "tracing-forest", + "tracing-subscriber 0.3.19", + "typenum", + "vec_map", + "zkhash", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -5167,6 +5868,15 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "postcard" version = "1.1.2" @@ -6535,6 +7245,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_arrays" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" +dependencies = [ + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.17" @@ -6684,6 +7403,16 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "git+https://github.com/brevis-network/hashes?tag=pico-patch-v1.0.1-sha2-v0.10.8#ddeaa09a00f17a42e9224d2f9aa20646421da3fc" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.10.8" @@ -6863,10 +7592,10 @@ dependencies = [ "itertools 0.13.0", "nohash-hasher", "num", - "p3-baby-bear", - "p3-field", - "p3-maybe-rayon", - "p3-util", + "p3-baby-bear 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-util 0.2.3-succinct", "rand 0.8.5", "range-set-blaze", "rrs-succinct", @@ -6905,17 +7634,17 @@ dependencies = [ "num", "num_cpus", "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", - "p3-air", - "p3-baby-bear", - "p3-challenger", - "p3-field", - "p3-keccak-air", - "p3-matrix", - "p3-maybe-rayon", - "p3-poseidon2", - "p3-symmetric", - "p3-uni-stark", - "p3-util", + "p3-air 0.2.3-succinct", + "p3-baby-bear 0.2.3-succinct", + "p3-challenger 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-keccak-air 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-poseidon2 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "p3-uni-stark 0.2.3-succinct", + "p3-util 0.2.3-succinct", "pathdiff", "rand 0.8.5", "rayon", @@ -6972,7 +7701,7 @@ dependencies = [ "k256", "num", "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", - "p3-field", + "p3-field 0.2.3-succinct", "serde", "snowbridge-amcl", "sp1-primitives 5.2.1", @@ -7033,10 +7762,10 @@ dependencies = [ "hex", "lazy_static", "num-bigint 0.4.6", - "p3-baby-bear", - "p3-field", - "p3-poseidon2", - "p3-symmetric", + "p3-baby-bear 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-poseidon2 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", "serde", "sha2 0.10.9", ] @@ -7053,10 +7782,10 @@ dependencies = [ "hex", "lazy_static", "num-bigint 0.4.6", - "p3-baby-bear", - "p3-field", - "p3-poseidon2", - "p3-symmetric", + "p3-baby-bear 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-poseidon2 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", "serde", "sha2 0.10.9", ] @@ -7079,14 +7808,14 @@ dependencies = [ "itertools 0.13.0", "lru 0.12.5", "num-bigint 0.4.6", - "p3-baby-bear", - "p3-bn254-fr", - "p3-challenger", - "p3-commit", - "p3-field", - "p3-matrix", - "p3-symmetric", - "p3-util", + "p3-baby-bear 0.2.3-succinct", + "p3-bn254-fr 0.2.3-succinct", + "p3-challenger 0.2.3-succinct", + "p3-commit 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "p3-util 0.2.3-succinct", "rayon", "serde", "serde_json", @@ -7115,18 +7844,18 @@ dependencies = [ "hashbrown 0.14.5", "itertools 0.13.0", "num-traits", - "p3-air", - "p3-baby-bear", - "p3-bn254-fr", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-fri", - "p3-matrix", - "p3-symmetric", - "p3-uni-stark", - "p3-util", + "p3-air 0.2.3-succinct", + "p3-baby-bear 0.2.3-succinct", + "p3-bn254-fr 0.2.3-succinct", + "p3-challenger 0.2.3-succinct", + "p3-commit 0.2.3-succinct", + "p3-dft 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-fri 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "p3-uni-stark 0.2.3-succinct", + "p3-util 0.2.3-succinct", "rand 0.8.5", "rayon", "serde", @@ -7149,10 +7878,10 @@ checksum = "61aa201b49cbdd52be19faec75f648e7e5e2c4930bcea7f4d1f1dbb3882cc518" dependencies = [ "backtrace", "itertools 0.13.0", - "p3-baby-bear", - "p3-bn254-fr", - "p3-field", - "p3-symmetric", + "p3-baby-bear 0.2.3-succinct", + "p3-bn254-fr 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", "serde", "sp1-core-machine", "sp1-primitives 5.2.1", @@ -7178,20 +7907,20 @@ dependencies = [ "hashbrown 0.14.5", "itertools 0.13.0", "num_cpus", - "p3-air", - "p3-baby-bear", - "p3-bn254-fr", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-fri", - "p3-matrix", - "p3-maybe-rayon", - "p3-merkle-tree", - "p3-poseidon2", - "p3-symmetric", - "p3-util", + "p3-air 0.2.3-succinct", + "p3-baby-bear 0.2.3-succinct", + "p3-bn254-fr 0.2.3-succinct", + "p3-challenger 0.2.3-succinct", + "p3-commit 0.2.3-succinct", + "p3-dft 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-fri 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-merkle-tree 0.2.3-succinct", + "p3-poseidon2 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "p3-util 0.2.3-succinct", "pathdiff", "rand 0.8.5", "serde", @@ -7229,9 +7958,9 @@ dependencies = [ "cfg-if", "hex", "num-bigint 0.4.6", - "p3-baby-bear", - "p3-field", - "p3-symmetric", + "p3-baby-bear 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", "serde", "serde_json", "sha2 0.10.9", @@ -7268,9 +7997,9 @@ dependencies = [ "indicatif", "itertools 0.13.0", "k256", - "p3-baby-bear", - "p3-field", - "p3-fri", + "p3-baby-bear 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-fri 0.2.3-succinct", "prost", "reqwest", "reqwest-middleware", @@ -7306,20 +8035,20 @@ dependencies = [ "itertools 0.13.0", "num-bigint 0.4.6", "num-traits", - "p3-air", - "p3-baby-bear", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-fri", - "p3-matrix", - "p3-maybe-rayon", - "p3-merkle-tree", - "p3-poseidon2", - "p3-symmetric", - "p3-uni-stark", - "p3-util", + "p3-air 0.2.3-succinct", + "p3-baby-bear 0.2.3-succinct", + "p3-challenger 0.2.3-succinct", + "p3-commit 0.2.3-succinct", + "p3-dft 0.2.3-succinct", + "p3-field 0.2.3-succinct", + "p3-fri 0.2.3-succinct", + "p3-matrix 0.2.3-succinct", + "p3-maybe-rayon 0.2.3-succinct", + "p3-merkle-tree 0.2.3-succinct", + "p3-poseidon2 0.2.3-succinct", + "p3-symmetric 0.2.3-succinct", + "p3-uni-stark 0.2.3-succinct", + "p3-util 0.2.3-succinct", "rayon-scan", "serde", "sp1-derive", @@ -7351,8 +8080,8 @@ dependencies = [ "getrandom 0.3.3", "lazy_static", "libm", - "p3-baby-bear", - "p3-field", + "p3-baby-bear 0.2.3-succinct", + "p3-field 0.2.3-succinct", "rand 0.8.5", "sha2 0.10.9", "sp1-lib 5.2.1", @@ -7397,6 +8126,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + [[package]] name = "strsim" version = "0.11.1" @@ -8019,6 +8754,16 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -8095,6 +8840,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unroll" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -8729,6 +9484,7 @@ dependencies = [ "rsa 0.9.6 (git+https://github.com/sp1-patches/RustCrypto-RSA?branch=patch-rsa-v0.9.6)", "rsa 0.9.8", "serde_json", + "sha2 0.10.8 (git+https://github.com/brevis-network/hashes?tag=pico-patch-v1.0.1-sha2-v0.10.8)", "sha2 0.10.8 (git+https://github.com/sp1-patches/RustCrypto-hashes?branch=patch-sha2-v0.10.8)", "sha2 0.10.8 (git+https://github.com/risc0/RustCrypto-hashes?rev=sha2-v0.10.8-risczero.0)", "sha2 0.10.9", diff --git a/Cargo.toml b/Cargo.toml index c1eed8b..d06f262 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,10 @@ members = [ "crates/risc0-methods/risc0-aggregator", "crates/sp1-methods", "crates/sp1-methods/sp1-verifier", - "crates/sp1-methods/sp1-aggregator" + "crates/sp1-methods/sp1-aggregator", + "crates/pico-methods", + "crates/pico-methods/pico-verifier", + "crates/pico-methods/pico-aggregator" ] default-members = [ "crates/nitro-attest-cli", @@ -41,6 +44,7 @@ aws-nitro-enclave-attestation-prover = { path = "crates/prover", default-feature x509-verifier-rust-crypto = { path = "crates/x509-verifier-rust-crypto" } risc0-methods = { path = "crates/risc0-methods" } sp1-methods = { path = "crates/sp1-methods" } +pico-methods = { path = "crates/pico-methods" } clap = { version = "4.0", features = ["derive", "env"] } anyhow = { version = "1", features = ["backtrace"] } @@ -58,6 +62,10 @@ risc0-ethereum-contracts = { git = "https://github.com/risc0/risc0-ethereum", ta sp1-zkvm = "5.2.1" sp1-sdk = { version = "5.2.1", default-features = false, features = ["network"] } + +pico-sdk = { git = "https://github.com/automata-network/pico.git", branch = "evm_defer_proof" } +pico-vm = { git = "https://github.com/automata-network/pico.git", branch = "evm_defer_proof" } + alloy-primitives = { version = "1.2" } tokio = { version = "1.35", features = ["full"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 5e1e907..15a2792 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -15,4 +15,9 @@ remappings = [ ] # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options -fs_permissions = [{ access = "read", path = "../samples"}, { access = "readwrite", path = "deployments" }, { access = "read", path = "deploy-config.json" }] +fs_permissions = [ + { access = "read", path = "../samples"}, + { access = "readwrite", path = "deployments" }, + { access = "read", path = "deploy-config.json" }, + { access = "read", path = "test/assets" } +] diff --git a/contracts/src/NitroEnclaveVerifier.sol b/contracts/src/NitroEnclaveVerifier.sol index 7fcbaa2..7bf803c 100644 --- a/contracts/src/NitroEnclaveVerifier.sol +++ b/contracts/src/NitroEnclaveVerifier.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import {Ownable} from "@solady/auth/Ownable.sol"; import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol"; import {IRiscZeroVerifier} from "@risc0-ethereum/IRiscZeroVerifier.sol"; +import {IPicoVerifier} from "./pico/IPicoVerifier.sol"; import { INitroEnclaveVerifier, ZkCoProcessorType, @@ -12,7 +13,6 @@ import { BatchVerifierJournal, VerificationResult } from "./interfaces/INitroEnclaveVerifier.sol"; -import {console} from "forge-std/console.sol"; /** * @title NitroEnclaveVerifier @@ -276,6 +276,12 @@ contract NitroEnclaveVerifier is Ownable, INitroEnclaveVerifier { IRiscZeroVerifier(zkVerifier).verify(proofBytes, programId, sha256(output)); } else if (zkCoprocessor == ZkCoProcessorType.Succinct) { ISP1Verifier(zkVerifier).verifyProof(programId, output, proofBytes); + } else if (zkCoprocessor == ZkCoProcessorType.Pico) { + IPicoVerifier(zkVerifier).verifyPicoProof( + programId, + output, + abi.decode(proofBytes, (uint256[8])) + ); } else { revert Unknown_Zk_Coprocessor(); } diff --git a/contracts/src/interfaces/INitroEnclaveVerifier.sol b/contracts/src/interfaces/INitroEnclaveVerifier.sol index 6866e92..7298166 100644 --- a/contracts/src/interfaces/INitroEnclaveVerifier.sol +++ b/contracts/src/interfaces/INitroEnclaveVerifier.sol @@ -10,7 +10,9 @@ enum ZkCoProcessorType { // RISC Zero zkVM proving system RiscZero, // Succinct SP1 proving system - Succinct + Succinct, + // Pico zkVM proving system + Pico } /** diff --git a/contracts/src/pico/Groth16Verifier.sol b/contracts/src/pico/Groth16Verifier.sol new file mode 100644 index 0000000..8c939b0 --- /dev/null +++ b/contracts/src/pico/Groth16Verifier.sol @@ -0,0 +1,539 @@ + +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/// @title Groth16 verifier template. +/// @author Remco Bloemen +/// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed +/// (256 bytes) and compressed (128 bytes) format. A view function is provided +/// to compress proofs. +/// @notice See for further explanation. +contract Verifier { + + /// Some of the provided public input values are larger than the field modulus. + /// @dev Public input elements are not automatically reduced, as this is can be + /// a dangerous source of bugs. + error PublicInputNotInField(); + + /// The proof is invalid. + /// @dev This can mean that provided Groth16 proof points are not on their + /// curves, that pairing equation fails, or that the proof is not for the + /// provided public input. + error ProofInvalid(); + + // Addresses of precompiles + uint256 constant PRECOMPILE_MODEXP = 0x05; + uint256 constant PRECOMPILE_ADD = 0x06; + uint256 constant PRECOMPILE_MUL = 0x07; + uint256 constant PRECOMPILE_VERIFY = 0x08; + + // Base field Fp order P and scalar field Fr order R. + // For BN254 these are computed as follows: + // t = 4965661367192848881 + // P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1 + // R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1 + uint256 constant P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47; + uint256 constant R = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001; + + uint256 constant MOD_R = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + + // Extension field Fp2 = Fp[i] / (i² + 1) + // Note: This is the complex extension field of Fp with i² = -1. + // Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i. + // Note: The order of Fp2 elements is *opposite* that of the pairing contract, which + // expects Fp2 elements in order (a₁, a₀). This is also the order in which + // Fp2 elements are encoded in the public interface as this became convention. + + // Constants in Fp + uint256 constant FRACTION_1_2_FP = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea4; + uint256 constant FRACTION_27_82_FP = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5; + uint256 constant FRACTION_3_82_FP = 0x2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775; + + // Exponents for inversions and square roots mod P + uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2 + uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4; + + // Groth16 alpha point in G1 + uint256 constant ALPHA_X = 13491508310322644295278574150660374920811253940772186555574957977326729177946; + uint256 constant ALPHA_Y = 18667485566149761035723765919674844513067177393729403891619099217057788019318; + + // Groth16 beta point in G2 in powers of i + uint256 constant BETA_NEG_X_0 = 10258730925664829316985111393434684977925523304619412826569958683237335945373; + uint256 constant BETA_NEG_X_1 = 16406086298456839676322237499404087476256330774346537847321154788888585371930; + uint256 constant BETA_NEG_Y_0 = 18057304796675404348068590337102346062633047334805840333037921397254282702683; + uint256 constant BETA_NEG_Y_1 = 3463125273922255534613956330803616858185458008118744462006586719538806783625; + + // Groth16 gamma point in G2 in powers of i + uint256 constant GAMMA_NEG_X_0 = 8411965783133486716939386501918435031327160280853000083421618129201969116037; + uint256 constant GAMMA_NEG_X_1 = 12411942336164911460745577176329829681610586225824436018085129288624060331274; + uint256 constant GAMMA_NEG_Y_0 = 8926591300133468261668274379832989455969430841346340210211048360873968361514; + uint256 constant GAMMA_NEG_Y_1 = 19572618942081699058959010678925068188473559460860985896884731757183235392691; + + // Groth16 delta point in G2 in powers of i + uint256 constant DELTA_NEG_X_0 = 14060535600528490063063418624276224191572881170809497772067444933586364781059; + uint256 constant DELTA_NEG_X_1 = 13971522237244225378007865548063079274757643526203055670727367387771813434287; + uint256 constant DELTA_NEG_Y_0 = 15981825227030108483363539307011618089117122190858319816883223508521338254403; + uint256 constant DELTA_NEG_Y_1 = 9340137177355189618379331426160476201479313321179694938503616213962240866263; + + // Constant and public input points + uint256 constant CONSTANT_X = 7164402715290199772107947472780450661179779354348577204437909449016142905482; + uint256 constant CONSTANT_Y = 3015347310904939609211473802938645413638145210765666454583654169206180939600; + uint256 constant PUB_0_X = 5964871848520896407255804957577680524560412523375131698367667304556197751529; + uint256 constant PUB_0_Y = 21759242417964902338893608028849707181397722451254253967195581000040091635142; + uint256 constant PUB_1_X = 12774706245669145461845297592172915879111089989321544787161817661562324485188; + uint256 constant PUB_1_Y = 148719366620194416614672606081005145571281098918747253472590117367408573278; + + /// Negation in Fp. + /// @notice Returns a number x such that a + x = 0 in Fp. + /// @notice The input does not need to be reduced. + /// @param a the base + /// @return x the result + function negate(uint256 a) internal pure returns (uint256 x) { + unchecked { + x = (P - (a % P)) % P; // Modulo is cheaper than branching + } + } + + /// Exponentiation in Fp. + /// @notice Returns a number x such that a ^ e = x in Fp. + /// @notice The input does not need to be reduced. + /// @param a the base + /// @param e the exponent + /// @return x the result + function exp(uint256 a, uint256 e) internal view returns (uint256 x) { + bool success; + assembly ("memory-safe") { + let f := mload(0x40) + mstore(f, 0x20) + mstore(add(f, 0x20), 0x20) + mstore(add(f, 0x40), 0x20) + mstore(add(f, 0x60), a) + mstore(add(f, 0x80), e) + mstore(add(f, 0xa0), P) + success := staticcall(gas(), PRECOMPILE_MODEXP, f, 0xc0, f, 0x20) + x := mload(f) + } + if (!success) { + // Exponentiation failed. + // Should not happen. + revert ProofInvalid(); + } + } + + /// Invertsion in Fp. + /// @notice Returns a number x such that a * x = 1 in Fp. + /// @notice The input does not need to be reduced. + /// @notice Reverts with ProofInvalid() if the inverse does not exist + /// @param a the input + /// @return x the solution + function invert_Fp(uint256 a) internal view returns (uint256 x) { + x = exp(a, EXP_INVERSE_FP); + if (mulmod(a, x, P) != 1) { + // Inverse does not exist. + // Can only happen during G2 point decompression. + revert ProofInvalid(); + } + } + + /// Square root in Fp. + /// @notice Returns a number x such that x * x = a in Fp. + /// @notice Will revert with InvalidProof() if the input is not a square + /// or not reduced. + /// @param a the square + /// @return x the solution + function sqrt_Fp(uint256 a) internal view returns (uint256 x) { + x = exp(a, EXP_SQRT_FP); + if (mulmod(x, x, P) != a) { + // Square root does not exist or a is not reduced. + // Happens when G1 point is not on curve. + revert ProofInvalid(); + } + } + + /// Square test in Fp. + /// @notice Returns wheter a number x exists such that x * x = a in Fp. + /// @notice Will revert with InvalidProof() if the input is not a square + /// or not reduced. + /// @param a the square + /// @return x the solution + function isSquare_Fp(uint256 a) internal view returns (bool) { + uint256 x = exp(a, EXP_SQRT_FP); + return mulmod(x, x, P) == a; + } + + /// Square root in Fp2. + /// @notice Fp2 is the complex extension Fp[i]/(i^2 + 1). The input is + /// a0 + a1 ⋅ i and the result is x0 + x1 ⋅ i. + /// @notice Will revert with InvalidProof() if + /// * the input is not a square, + /// * the hint is incorrect, or + /// * the input coefficents are not reduced. + /// @param a0 The real part of the input. + /// @param a1 The imaginary part of the input. + /// @param hint A hint which of two possible signs to pick in the equation. + /// @return x0 The real part of the square root. + /// @return x1 The imaginary part of the square root. + function sqrt_Fp2(uint256 a0, uint256 a1, bool hint) internal view returns (uint256 x0, uint256 x1) { + // If this square root reverts there is no solution in Fp2. + uint256 d = sqrt_Fp(addmod(mulmod(a0, a0, P), mulmod(a1, a1, P), P)); + if (hint) { + d = negate(d); + } + // If this square root reverts there is no solution in Fp2. + x0 = sqrt_Fp(mulmod(addmod(a0, d, P), FRACTION_1_2_FP, P)); + x1 = mulmod(a1, invert_Fp(mulmod(x0, 2, P)), P); + + // Check result to make sure we found a root. + // Note: this also fails if a0 or a1 is not reduced. + if (a0 != addmod(mulmod(x0, x0, P), negate(mulmod(x1, x1, P)), P) + || a1 != mulmod(2, mulmod(x0, x1, P), P)) { + revert ProofInvalid(); + } + } + + /// Compress a G1 point. + /// @notice Reverts with InvalidProof if the coordinates are not reduced + /// or if the point is not on the curve. + /// @notice The point at infinity is encoded as (0,0) and compressed to 0. + /// @param x The X coordinate in Fp. + /// @param y The Y coordinate in Fp. + /// @return c The compresed point (x with one signal bit). + function compress_g1(uint256 x, uint256 y) internal view returns (uint256 c) { + if (x >= P || y >= P) { + // G1 point not in field. + revert ProofInvalid(); + } + if (x == 0 && y == 0) { + // Point at infinity + return 0; + } + + // Note: sqrt_Fp reverts if there is no solution, i.e. the x coordinate is invalid. + uint256 y_pos = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P)); + if (y == y_pos) { + return (x << 1) | 0; + } else if (y == negate(y_pos)) { + return (x << 1) | 1; + } else { + // G1 point not on curve. + revert ProofInvalid(); + } + } + + /// Decompress a G1 point. + /// @notice Reverts with InvalidProof if the input does not represent a valid point. + /// @notice The point at infinity is encoded as (0,0) and compressed to 0. + /// @param c The compresed point (x with one signal bit). + /// @return x The X coordinate in Fp. + /// @return y The Y coordinate in Fp. + function decompress_g1(uint256 c) internal view returns (uint256 x, uint256 y) { + // Note that X = 0 is not on the curve since 0³ + 3 = 3 is not a square. + // so we can use it to represent the point at infinity. + if (c == 0) { + // Point at infinity as encoded in EIP196 and EIP197. + return (0, 0); + } + bool negate_point = c & 1 == 1; + x = c >> 1; + if (x >= P) { + // G1 x coordinate not in field. + revert ProofInvalid(); + } + + // Note: (x³ + 3) is irreducible in Fp, so it can not be zero and therefore + // y can not be zero. + // Note: sqrt_Fp reverts if there is no solution, i.e. the point is not on the curve. + y = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P)); + if (negate_point) { + y = negate(y); + } + } + + /// Compress a G2 point. + /// @notice Reverts with InvalidProof if the coefficients are not reduced + /// or if the point is not on the curve. + /// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1) + /// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i). + /// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0). + /// @param x0 The real part of the X coordinate. + /// @param x1 The imaginary poart of the X coordinate. + /// @param y0 The real part of the Y coordinate. + /// @param y1 The imaginary part of the Y coordinate. + /// @return c0 The first half of the compresed point (x0 with two signal bits). + /// @return c1 The second half of the compressed point (x1 unmodified). + function compress_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1) + internal view returns (uint256 c0, uint256 c1) { + if (x0 >= P || x1 >= P || y0 >= P || y1 >= P) { + // G2 point not in field. + revert ProofInvalid(); + } + if ((x0 | x1 | y0 | y1) == 0) { + // Point at infinity + return (0, 0); + } + + // Compute y^2 + // Note: shadowing variables and scoping to avoid stack-to-deep. + uint256 y0_pos; + uint256 y1_pos; + { + uint256 n3ab = mulmod(mulmod(x0, x1, P), P-3, P); + uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P); + uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P); + y0_pos = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P); + y1_pos = negate(addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P)); + } + + // Determine hint bit + // If this sqrt fails the x coordinate is not on the curve. + bool hint; + { + uint256 d = sqrt_Fp(addmod(mulmod(y0_pos, y0_pos, P), mulmod(y1_pos, y1_pos, P), P)); + hint = !isSquare_Fp(mulmod(addmod(y0_pos, d, P), FRACTION_1_2_FP, P)); + } + + // Recover y + (y0_pos, y1_pos) = sqrt_Fp2(y0_pos, y1_pos, hint); + if (y0 == y0_pos && y1 == y1_pos) { + c0 = (x0 << 2) | (hint ? 2 : 0) | 0; + c1 = x1; + } else if (y0 == negate(y0_pos) && y1 == negate(y1_pos)) { + c0 = (x0 << 2) | (hint ? 2 : 0) | 1; + c1 = x1; + } else { + // G1 point not on curve. + revert ProofInvalid(); + } + } + + /// Decompress a G2 point. + /// @notice Reverts with InvalidProof if the input does not represent a valid point. + /// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1) + /// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i). + /// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0). + /// @param c0 The first half of the compresed point (x0 with two signal bits). + /// @param c1 The second half of the compressed point (x1 unmodified). + /// @return x0 The real part of the X coordinate. + /// @return x1 The imaginary poart of the X coordinate. + /// @return y0 The real part of the Y coordinate. + /// @return y1 The imaginary part of the Y coordinate. + function decompress_g2(uint256 c0, uint256 c1) + internal view returns (uint256 x0, uint256 x1, uint256 y0, uint256 y1) { + // Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square. + // so we can use it to represent the point at infinity. + if (c0 == 0 && c1 == 0) { + // Point at infinity as encoded in EIP197. + return (0, 0, 0, 0); + } + bool negate_point = c0 & 1 == 1; + bool hint = c0 & 2 == 2; + x0 = c0 >> 2; + x1 = c1; + if (x0 >= P || x1 >= P) { + // G2 x0 or x1 coefficient not in field. + revert ProofInvalid(); + } + + uint256 n3ab = mulmod(mulmod(x0, x1, P), P-3, P); + uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P); + uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P); + + y0 = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P); + y1 = negate(addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P)); + + // Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve. + // Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero. + // But y0 or y1 may still independently be zero. + (y0, y1) = sqrt_Fp2(y0, y1, hint); + if (negate_point) { + y0 = negate(y0); + y1 = negate(y1); + } + } + + /// Compute the public input linear combination. + /// @notice Reverts with PublicInputNotInField if the input is not in the field. + /// @notice Computes the multi-scalar-multiplication of the public input + /// elements and the verification key including the constant term. + /// @param input The public inputs. These are elements of the scalar field Fr. + /// @return x The X coordinate of the resulting G1 point. + /// @return y The Y coordinate of the resulting G1 point. + function publicInputMSM(uint256[2] calldata input) + internal view returns (uint256 x, uint256 y) { + // Note: The ECMUL precompile does not reject unreduced values, so we check this. + // Note: Unrolling this loop does not cost much extra in code-size, the bulk of the + // code-size is in the PUB_ constants. + // ECMUL has input (x, y, scalar) and output (x', y'). + // ECADD has input (x1, y1, x2, y2) and output (x', y'). + // We call them such that ecmul output is already in the second point + // argument to ECADD so we can have a tight loop. + bool success = true; + assembly ("memory-safe") { + let f := mload(0x40) + let g := add(f, 0x40) + let s + mstore(f, CONSTANT_X) + mstore(add(f, 0x20), CONSTANT_Y) + mstore(g, PUB_0_X) + mstore(add(g, 0x20), PUB_0_Y) + s := calldataload(input) + mstore(add(g, 0x40), s) + success := and(success, lt(s, R)) + success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) + success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) + mstore(g, PUB_1_X) + mstore(add(g, 0x20), PUB_1_Y) + s := calldataload(add(input, 32)) + mstore(add(g, 0x40), s) + success := and(success, lt(s, R)) + success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40)) + success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40)) + x := mload(f) + y := mload(add(f, 0x20)) + } + if (!success) { + // Either Public input not in field, or verification key invalid. + // We assume the contract is correctly generated, so the verification key is valid. + revert PublicInputNotInField(); + } + } + + /// Compress a proof. + /// @notice Will revert with InvalidProof if the curve points are invalid, + /// but does not verify the proof itself. + /// @param proof The uncompressed Groth16 proof. Elements are in the same order as for + /// verifyProof. I.e. Groth16 points (A, B, C) encoded as in EIP-197. + /// @return compressed The compressed proof. Elements are in the same order as for + /// verifyCompressedProof. I.e. points (A, B, C) in compressed format. + function compressProof(uint256[8] calldata proof) + public view returns (uint256[4] memory compressed) { + compressed[0] = compress_g1(proof[0], proof[1]); + (compressed[2], compressed[1]) = compress_g2(proof[3], proof[2], proof[5], proof[4]); + compressed[3] = compress_g1(proof[6], proof[7]); + } + + /// Verify a Groth16 proof with compressed points. + /// @notice Reverts with InvalidProof if the proof is invalid or + /// with PublicInputNotInField the public input is not reduced. + /// @notice There is no return value. If the function does not revert, the + /// proof was successfully verified. + /// @param compressedProof the points (A, B, C) in compressed format + /// matching the output of compressProof. + /// @param input the public input field elements in the scalar field Fr. + /// Elements must be reduced. + function verifyCompressedProof( + uint256[4] calldata compressedProof, + uint256[2] calldata input + ) public view { + (uint256 Ax, uint256 Ay) = decompress_g1(compressedProof[0]); + (uint256 Bx0, uint256 Bx1, uint256 By0, uint256 By1) = decompress_g2( + compressedProof[2], compressedProof[1]); + (uint256 Cx, uint256 Cy) = decompress_g1(compressedProof[3]); + (uint256 Lx, uint256 Ly) = publicInputMSM(input); + + // Verify the pairing + // Note: The precompile expects the F2 coefficients in big-endian order. + // Note: The pairing precompile rejects unreduced values, so we won't check that here. + uint256[24] memory pairings; + // e(A, B) + pairings[ 0] = Ax; + pairings[ 1] = Ay; + pairings[ 2] = Bx1; + pairings[ 3] = Bx0; + pairings[ 4] = By1; + pairings[ 5] = By0; + // e(C, -δ) + pairings[ 6] = Cx; + pairings[ 7] = Cy; + pairings[ 8] = DELTA_NEG_X_1; + pairings[ 9] = DELTA_NEG_X_0; + pairings[10] = DELTA_NEG_Y_1; + pairings[11] = DELTA_NEG_Y_0; + // e(α, -β) + pairings[12] = ALPHA_X; + pairings[13] = ALPHA_Y; + pairings[14] = BETA_NEG_X_1; + pairings[15] = BETA_NEG_X_0; + pairings[16] = BETA_NEG_Y_1; + pairings[17] = BETA_NEG_Y_0; + // e(L_pub, -γ) + pairings[18] = Lx; + pairings[19] = Ly; + pairings[20] = GAMMA_NEG_X_1; + pairings[21] = GAMMA_NEG_X_0; + pairings[22] = GAMMA_NEG_Y_1; + pairings[23] = GAMMA_NEG_Y_0; + + // Check pairing equation. + bool success; + uint256[1] memory output; + assembly ("memory-safe") { + success := staticcall(gas(), PRECOMPILE_VERIFY, pairings, 0x300, output, 0x20) + } + if (!success || output[0] != 1) { + // Either proof or verification key invalid. + // We assume the contract is correctly generated, so the verification key is valid. + revert ProofInvalid(); + } + } + + /// Verify an uncompressed Groth16 proof. + /// @notice Reverts with InvalidProof if the proof is invalid or + /// with PublicInputNotInField the public input is not reduced. + /// @notice There is no return value. If the function does not revert, the + /// proof was successfully verified. + /// @param proof the points (A, B, C) in EIP-197 format matching the output + /// of compressProof. + /// @param input the public input field elements in the scalar field Fr. + /// Elements must be reduced. + function verifyProof( + uint256[8] calldata proof, + uint256[2] calldata input + ) public view { + (uint256 x, uint256 y) = publicInputMSM(input); + + // Note: The precompile expects the F2 coefficients in big-endian order. + // Note: The pairing precompile rejects unreduced values, so we won't check that here. + + bool success; + assembly ("memory-safe") { + let f := mload(0x40) // Free memory pointer. + + // Copy points (A, B, C) to memory. They are already in correct encoding. + // This is pairing e(A, B) and G1 of e(C, -δ). + calldatacopy(f, proof, 0x100) + + // Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory. + // OPT: This could be better done using a single codecopy, but + // Solidity (unlike standalone Yul) doesn't provide a way to + // to do this. + mstore(add(f, 0x100), DELTA_NEG_X_1) + mstore(add(f, 0x120), DELTA_NEG_X_0) + mstore(add(f, 0x140), DELTA_NEG_Y_1) + mstore(add(f, 0x160), DELTA_NEG_Y_0) + mstore(add(f, 0x180), ALPHA_X) + mstore(add(f, 0x1a0), ALPHA_Y) + mstore(add(f, 0x1c0), BETA_NEG_X_1) + mstore(add(f, 0x1e0), BETA_NEG_X_0) + mstore(add(f, 0x200), BETA_NEG_Y_1) + mstore(add(f, 0x220), BETA_NEG_Y_0) + mstore(add(f, 0x240), x) + mstore(add(f, 0x260), y) + mstore(add(f, 0x280), GAMMA_NEG_X_1) + mstore(add(f, 0x2a0), GAMMA_NEG_X_0) + mstore(add(f, 0x2c0), GAMMA_NEG_Y_1) + mstore(add(f, 0x2e0), GAMMA_NEG_Y_0) + + // Check pairing equation. + success := staticcall(gas(), PRECOMPILE_VERIFY, f, 0x300, f, 0x20) + // Also check returned value (both are either 1 or 0). + success := and(success, mload(f)) + } + if (!success) { + // Either proof or verification key invalid. + // We assume the contract is correctly generated, so the verification key is valid. + revert ProofInvalid(); + } + } +} diff --git a/contracts/src/pico/IPicoVerifier.sol b/contracts/src/pico/IPicoVerifier.sol new file mode 100644 index 0000000..51b9f42 --- /dev/null +++ b/contracts/src/pico/IPicoVerifier.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/// @title Pico Verifier Interface +/// @author Brevis Network +/// @notice This contract is the interface for the Pico Verifier. +interface IPicoVerifier { + /// @notice Verifies a proof with given public values and riscv verification key. + /// @param riscvVkey The verification key for the RISC-V program. + /// @param publicValues The public values encoded as bytes. + /// @param proof The proof of the riscv program execution in the Pico. + function verifyPicoProof( + bytes32 riscvVkey, + bytes calldata publicValues, + uint256[8] calldata proof + ) external view; +} diff --git a/contracts/src/pico/PicoVerifier.sol b/contracts/src/pico/PicoVerifier.sol new file mode 100644 index 0000000..a9ee9e4 --- /dev/null +++ b/contracts/src/pico/PicoVerifier.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IPicoVerifier} from "./IPicoVerifier.sol"; +import {Verifier} from "./Groth16Verifier.sol"; + +/// @title Pico Verifier +/// @author Brevis Network +/// @notice This contracts implements a solidity verifier for Pico. +contract PicoVerifier is Verifier, IPicoVerifier { + /// @notice Thrown when the proof is invalid. + error InvalidProof(); + + /// @notice Hashes the public values to a field elements inside Bn254. + /// @param publicValues The public values. + function hashPublicValues( + bytes calldata publicValues + ) public pure returns (bytes32) { + return sha256(publicValues) & bytes32(uint256((1 << 253) - 1)); + } + + /// @notice Verifies a proof with given public values and riscv verification key. + /// @param riscvVkey The verification key for the RISC-V program. + /// @param publicValues The public values encoded as bytes. + /// @param proof The proof of the riscv program execution in the Pico. + function verifyPicoProof( + bytes32 riscvVkey, + bytes calldata publicValues, + uint256[8] calldata proof + ) external view { + bytes32 publicValuesDigest = hashPublicValues(publicValues); + uint256[2] memory inputs; + inputs[0] = uint256(riscvVkey); + inputs[1] = uint256(publicValuesDigest); + this.verifyProof(proof, inputs); + } +} \ No newline at end of file diff --git a/contracts/test/NitroEnclavePicoTest.t.sol b/contracts/test/NitroEnclavePicoTest.t.sol new file mode 100644 index 0000000..e692380 --- /dev/null +++ b/contracts/test/NitroEnclavePicoTest.t.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {Test} from "forge-std/Test.sol"; +import { + NitroEnclaveVerifier, + ZkCoProcessorType, + ZkCoProcessorConfig, + VerifierJournal +} from "../src/NitroEnclaveVerifier.sol"; +import {PicoVerifier} from "../src/pico/PicoVerifier.sol"; + +contract NitroEnclavePicoTest is Test { + NitroEnclaveVerifier verifier; + PicoVerifier picoVerifier; + address admin = address(0x01); + string picoInputJson = vm.readFile(string.concat(vm.projectRoot(), "/test/assets/inputs.json")); + string picoAggregatedInputJson = vm.readFile(string.concat(vm.projectRoot(), "/test/assets/inputs-aggregated.json")); + + function setUp() public { + vm.startPrank(admin); + + // deploy contracts + verifier = new NitroEnclaveVerifier(admin, 27900202, new bytes32[](0)); + picoVerifier = new PicoVerifier(); + + // add root certificate + bytes memory awsRoot = vm.readFileBinary(string.concat(vm.projectRoot(), "/test/assets/aws_root.der")); + verifier.setRootCert(sha256(awsRoot)); + + // configure Pico zkVerifier + bytes32 nitroPicoVerifierVkey = abi.decode(vm.parseJson(picoInputJson, ".riscvVKey"), (bytes32)); + bytes32 nitroPicoAggregatorVkey = abi.decode(vm.parseJson(picoAggregatedInputJson, ".riscvVKey"), (bytes32)); + ZkCoProcessorConfig memory picoConfig = ZkCoProcessorConfig({ + verifierId: nitroPicoVerifierVkey, + verifierProofId: 0x38a3d34f08d8af64b947e861eb80b8404affdf756add5f577e79931598ba585a, // not in the input.json but you can get this from OnchainProof returned by the CLI + aggregatorId: nitroPicoAggregatorVkey, + zkVerifier: address(picoVerifier) + }); + verifier.setZkConfiguration(ZkCoProcessorType.Pico, picoConfig); + + vm.stopPrank(); + } + + function testVerifyNitroPicoProof() public { + // prevent InvalidTimestamp errors + vm.warp(1723799509); + + (, bytes memory publicValues, uint256[8] memory proofArray) = _parsePicoInput(picoInputJson); + + VerifierJournal memory journal = verifier.verify(publicValues, ZkCoProcessorType.Pico, abi.encode(proofArray)); + + assertEq(uint8(journal.result), uint8(0)); + } + + function testBatchVerifyNitroPicoProof() public { + // prevent InvalidTimestamp errors + vm.warp(1723799509); + + (, bytes memory publicValues, uint256[8] memory proofArray) = _parsePicoInput(picoAggregatedInputJson); + + VerifierJournal[] memory journals = verifier.batchVerify( + publicValues, + ZkCoProcessorType.Pico, + abi.encode(proofArray) + ); + + uint256 n = journals.length; + for (uint256 i = 0; i < n; i++) { + assertEq(uint8(journals[i].result), uint8(0)); + } + } + + function _parsePicoInput(string memory json) private pure returns ( + bytes32 riscvVKey, + bytes memory publicValues, + uint256[8] memory proofArray + ) { + riscvVKey = abi.decode(vm.parseJson(json, ".riscvVKey"), (bytes32)); + publicValues = abi.decode(vm.parseJson(json, ".publicValues"), (bytes)); + + bytes32[] memory proofBytes32 = abi.decode(vm.parseJson(json, ".proof"), (bytes32[])); + for (uint256 i = 0; i < 8; i++) { + proofArray[i] = uint256(proofBytes32[i]); + } + } +} diff --git a/contracts/test/assets/aws_root.der b/contracts/test/assets/aws_root.der new file mode 100644 index 0000000..994d128 Binary files /dev/null and b/contracts/test/assets/aws_root.der differ diff --git a/contracts/test/assets/inputs-aggregated.json b/contracts/test/assets/inputs-aggregated.json new file mode 100644 index 0000000..ee5bae4 --- /dev/null +++ b/contracts/test/assets/inputs-aggregated.json @@ -0,0 +1,14 @@ +{ + "proof": [ + "0x1bcbafa7b5491baf8a519c708d751ef7d7c67c276b68e50ce72db7ecf353a80a", + "0x240b03097f8f039bdac12e757f2411f3e8b3acc73583385cde030a0d17d1fc2e", + "0x0fe1138c02d632ef7b45b5620ad5481b207a17fd26128202f2cacdbb02d2fe99", + "0x2bbb2cf3259274ca4217b32fa8ac1fe19f6ec0dd1286f1a118ff075ae4cb9dc4", + "0x302fdb89dfe303a72566351ab2a91ffbeb05ebd68f1dc9fc9e60ed9b3fa95ab6", + "0x0fb9164459eb9d56e1182100e476cd79d4d41b25c1aec396efc355733075d3ce", + "0x04435827e74c5fa626047252f89d4be0ad409ecd60316cbb983d4d5264869bc8", + "0x210a5c8a9687ad3faf1a65482cf74baccea0734925d72b9811644d026e79e04e" + ], + "publicValues": "0x000000000000000000000000000000000000000000000000000000000000002038a3d34f08d8af64b947e861eb80b8404affdf756add5f577e79931598ba585a00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000001915a7518af000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000005641a0321a3e244efe456463195d606317ed7cdcc3c1756e09893f3c68f79bb5b348cc5b001ba75f7d3733ef512463194fea6781954fd416455699d4deb361acf3792fe9068de61899676dfb2f31bf64a72439cf4883d3216629d3404b727c58db3b18683c518f2c462cd0252034e6a4758c42907add1880bd29a5e0a79aed71b30941d6b61e8cd57b80a6da3705ec072adaa8acb514fbfd9b54ce3393a257e4f00000000000000000000000000000000000000000000000000000000000000114175746f6d617461204d50432044656d6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043132333400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008b5075626c69634b65792834303262613735356133633534633965373764393765623366303566356238323237373232666638363165346563353762313735663463626365613561346334353464343761386331663738646634393137353362393134623131373833333563633432643565333266633732386439393261306433333733366263313733652900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003b0c424e9f3727f78f370d4332f3e6e2bb02a288d9bc3c4697102d70744de0b064366fbb3190402deeb4d144e4ab17d4f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004dcd9866c46ee2878f5fd80f955c12a8c11de276346846579d0d077933757988144c96dc4c5fb708c20c04a4ee34639ab000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027692d30376664346363346466393335656162302d656e633031393135613734653665643461613600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000018adb79cc6d000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000000000000000000000000000000000000000005641a0321a3e244efe456463195d606317ed7cdcc3c1756e09893f3c68f79bb5b713bd836d52e9aa99f2b44ba50727f5a6474c0496390f4ff4da402be374598af203e03b1f89e2663f00d7c495bdaa700beee8da74f7f8681760fc3e7ccdc10e34e3331c907dbb0fe0562c7aadb399e0ed1b71599f234fae53101bd31366dda060b3e91ffc53f7c140336f88fb08e74a68288f721a57aeb9651fbcfc1c7a9831900000000000000000000000000000000000000000000000000000000000001227b22696e7075745f68617368223a22307839366233333338343537303862633830656530613730613033383462666630306331373032643564643630356431663437313032343533653666633161336530222c226f75747075745f68617368223a22307862353961633734303139646438623232653765646434333366326163306664396166616332373862333134633435643563623566323534333931376332663639222c226e6f6e6365223a226537623463376537376339663639666136663032643363383737393666353431222c226d72656e636c617665223a22307866396239653663343732626638313462306235393732363730363166346432326563666431326637636637383935303031356665613765386138396461366561227d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000206537623463376537376339663639666136663032643363383737393666353431000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000ca78fbe0b97bbfe1895dd713639dffcbdd21da5c7e05b8d90fe57a4e122414edc0f677d673df31fee1c16a7b34c16f36000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bcdf05fefccaa8e55bf2c8d6dee9e79bbff31e34bf28a99aa19e6b29c37ee80b214a414b7607236edf26fcb78654e63f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000261d30545473dc728dde6808b502a40face68e7a1bc6cb16515d88cc8ed32c2dd2cc7d8ca69ec2e103fbd4e58e228aace000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d9071dca803e7031edcd2c0376ee88b4a32ebe9187e15a98877d7ad9ae106c20f72b694e9a66d54002d99865a405ad110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044cce4df4a664c9b9431dcb5288f3b539d838a2b00fdbb13b5994c85b82b9c218cb6e86f8dea067d1da7d2a7db2d6ac4b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027692d30313535333166393534633534323937632d656e633031386164623730306133323464333200000000000000000000000000000000000000000000000000", + "riscvVKey": "0x00093dbf39d4986be382e062dcbf34d2bc8105637de89bdaaa588014a9c53e9b" +} \ No newline at end of file diff --git a/contracts/test/assets/inputs.json b/contracts/test/assets/inputs.json new file mode 100644 index 0000000..ec86dd7 --- /dev/null +++ b/contracts/test/assets/inputs.json @@ -0,0 +1,14 @@ +{ + "proof": [ + "0x18c6578b26930a4c98aae31936c788fc1a9ac3c381815dc6b52707e53324542e", + "0x24118ee6049ad6e203b8452cd60c43ee39a6f4eb1e992a174452b671b9e984a1", + "0x1799c5292d6b72575cbc8398e1c25c6a5434ecc0d27c97a9a9badee48bfac09b", + "0x0fc57a247cbbd8c841f03de3f902a86e5e7917b444d18360ba0578a797825d63", + "0x28bd94072b4bbe68fa8ed5b6adf4d5f1acee9c3a94f1a43d8c3af086a7d9c4b6", + "0x0e3ff63ba8ec56dc7e05807a9cca4566458e0ce54affd0a75d3393de9b539259", + "0x18d4b722cff8de42f8aea2f93c0cea5a021d33d2f22a305bb784ed9f0880c125", + "0x19cd85b53888b74538e43063a08ed638e87e758ab80d7e32f543e9e53a254e36" + ], + "publicValues": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000001915a7518af000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000005641a0321a3e244efe456463195d606317ed7cdcc3c1756e09893f3c68f79bb5b348cc5b001ba75f7d3733ef512463194fea6781954fd416455699d4deb361acf3792fe9068de61899676dfb2f31bf64a72439cf4883d3216629d3404b727c58db3b18683c518f2c462cd0252034e6a4758c42907add1880bd29a5e0a79aed71b30941d6b61e8cd57b80a6da3705ec072adaa8acb514fbfd9b54ce3393a257e4f00000000000000000000000000000000000000000000000000000000000000114175746f6d617461204d50432044656d6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043132333400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008b5075626c69634b65792834303262613735356133633534633965373764393765623366303566356238323237373232666638363165346563353762313735663463626365613561346334353464343761386331663738646634393137353362393134623131373833333563633432643565333266633732386439393261306433333733366263313733652900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003b0c424e9f3727f78f370d4332f3e6e2bb02a288d9bc3c4697102d70744de0b064366fbb3190402deeb4d144e4ab17d4f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004dcd9866c46ee2878f5fd80f955c12a8c11de276346846579d0d077933757988144c96dc4c5fb708c20c04a4ee34639ab000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027692d30376664346363346466393335656162302d656e633031393135613734653665643461613600000000000000000000000000000000000000000000000000", + "riscvVKey": "0x009fa7467192bf60230f423dcc0b880ebebbffe955d7f75a8ac9bcbf5a58ba98" +} \ No newline at end of file diff --git a/crates/nitro-attest-cli/Cargo.toml b/crates/nitro-attest-cli/Cargo.toml index 599bf1c..c1a91a6 100644 --- a/crates/nitro-attest-cli/Cargo.toml +++ b/crates/nitro-attest-cli/Cargo.toml @@ -9,6 +9,7 @@ license.workspace = true default = ["risc0", "sp1"] sp1 = ["aws-nitro-enclave-attestation-prover/sp1"] risc0 = ["aws-nitro-enclave-attestation-prover/risc0"] +pico = ["aws-nitro-enclave-attestation-prover/pico"] [dependencies] clap.workspace = true diff --git a/crates/nitro-attest-cli/src/main.rs b/crates/nitro-attest-cli/src/main.rs index cd31ec9..bc9a899 100644 --- a/crates/nitro-attest-cli/src/main.rs +++ b/crates/nitro-attest-cli/src/main.rs @@ -1,7 +1,7 @@ //! # Nitro Attestation CLI //! //! A command-line interface for generating and verifying AWS Nitro Enclave attestation proofs -//! using zero-knowledge proof systems (RISC0 and SP1). +//! using zero-knowledge proof systems (RISC0, SP1, and Pico). //! //! This CLI provides functionality to: //! - Generate ZK proofs for Nitro Enclave attestation reports @@ -15,6 +15,7 @@ //! Generate a proof from an attestation report: //! ```bash //! nitro-attest-cli prove --report attestation.report --sp1 --out proof.json +//! # or use --risc0 or --pico //! ``` //! //! Verify a proof on-chain: diff --git a/crates/nitro-attest-cli/src/utils.rs b/crates/nitro-attest-cli/src/utils.rs index 6b351d3..51863cf 100644 --- a/crates/nitro-attest-cli/src/utils.rs +++ b/crates/nitro-attest-cli/src/utils.rs @@ -11,8 +11,8 @@ use aws_nitro_enclave_attestation_prover::{ use clap::Args; /// Command-line arguments for configuring zero-knowledge proof system settings. -/// -/// Supports both RISC0 and SP1 proof systems with their respective configuration options. +/// +/// Supports RISC0, SP1, and Pico proof systems with their respective configuration options. /// Only one prover type should be specified at a time. #[derive(Args, Clone)] pub struct ProverArgs { @@ -26,6 +26,11 @@ pub struct ProverArgs { #[arg(long)] pub sp1: bool, + #[cfg(feature = "pico")] + /// Use the Pico zkVM for proof generation + #[arg(long)] + pub pico: bool, + /// Enable development mode for mock proof generation #[arg(long, default_value = "false", env = "DEV_MODE")] pub dev: bool, @@ -50,10 +55,21 @@ pub struct ProverArgs { impl ProverArgs { /// Creates a prover configuration based on the specified arguments. pub fn prover_config(&self) -> anyhow::Result { - #[cfg(all(feature = "sp1", feature = "risc0"))] - if self.sp1 && self.risc0 { + // Check for mutual exclusion of prover options + let prover_count = { + let mut count = 0; + #[cfg(feature = "risc0")] + if self.risc0 { count += 1; } + #[cfg(feature = "sp1")] + if self.sp1 { count += 1; } + #[cfg(feature = "pico")] + if self.pico { count += 1; } + count + }; + + if prover_count > 1 { return Err(anyhow!( - "Cannot use both --sp1 and --risc0 at the same time." + "Cannot use multiple provers at the same time. Choose only one: --risc0, --sp1, or --pico" )); } @@ -75,7 +91,13 @@ impl ProverArgs { })); } - bail!("No prover specified. Use --risc0 or --sp1 to select a proof system."); + #[cfg(feature = "pico")] + if self.pico { + use aws_nitro_enclave_attestation_prover::PicoProverConfig; + return Ok(ProverConfig::pico_with(PicoProverConfig::default())); + } + + bail!("No prover specified. Use --risc0, --sp1, or --pico to select a proof system."); } /// Creates a new `NitroEnclaveProver` instance with the configured settings. diff --git a/crates/pico-methods/Cargo.toml b/crates/pico-methods/Cargo.toml new file mode 100644 index 0000000..4b59ef0 --- /dev/null +++ b/crates/pico-methods/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "pico-methods" +version.workspace = true +edition = "2024" \ No newline at end of file diff --git a/crates/pico-methods/pico-aggregator/Cargo.toml b/crates/pico-methods/pico-aggregator/Cargo.toml new file mode 100644 index 0000000..6e509e0 --- /dev/null +++ b/crates/pico-methods/pico-aggregator/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "pico-aggregator" +version = "0.1.0" +edition = "2024" + +[dependencies] +pico-sdk = { workspace = true } +aws-nitro-enclave-attestation-verifier = { workspace = true } \ No newline at end of file diff --git a/crates/pico-methods/pico-aggregator/elf/riscv32im-pico-zkvm-elf b/crates/pico-methods/pico-aggregator/elf/riscv32im-pico-zkvm-elf new file mode 100755 index 0000000..d4ea677 Binary files /dev/null and b/crates/pico-methods/pico-aggregator/elf/riscv32im-pico-zkvm-elf differ diff --git a/crates/pico-methods/pico-aggregator/src/main.rs b/crates/pico-methods/pico-aggregator/src/main.rs new file mode 100644 index 0000000..f47438f --- /dev/null +++ b/crates/pico-methods/pico-aggregator/src/main.rs @@ -0,0 +1,28 @@ +#![no_main] +pico_sdk::entrypoint!(main); +use pico_sdk::{ + io::{commit_bytes, read_vec}, + verify::verify_pico_proof, +}; + +use aws_nitro_enclave_attestation_verifier::stub::{BatchVerifierInput, BatchVerifierJournal}; + +pub fn main() { + let input_bytes = read_vec(); + + let input = + BatchVerifierInput::decode(&input_bytes).expect("Failed to decode BatchVerifierInput"); + + let vk_digest: [u32; 8] = unsafe { std::mem::transmute(input.verifierVk) }; + + for output in &input.outputs { + verify_pico_proof(&vk_digest, &output.digest()); + } + + let journal = BatchVerifierJournal { + verifierVk: input.verifierVk, + outputs: input.outputs, + }; + + commit_bytes(&journal.encode()); +} diff --git a/crates/pico-methods/pico-verifier/Cargo.toml b/crates/pico-methods/pico-verifier/Cargo.toml new file mode 100644 index 0000000..85da8fb --- /dev/null +++ b/crates/pico-methods/pico-verifier/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "pico-verifier" +version = "0.1.0" +edition = "2024" + +[dependencies] +pico-sdk = { workspace = true } +aws-nitro-enclave-attestation-verifier = { workspace = true, features = ["pico"] } \ No newline at end of file diff --git a/crates/pico-methods/pico-verifier/elf/riscv32im-pico-zkvm-elf b/crates/pico-methods/pico-verifier/elf/riscv32im-pico-zkvm-elf new file mode 100755 index 0000000..9e50302 Binary files /dev/null and b/crates/pico-methods/pico-verifier/elf/riscv32im-pico-zkvm-elf differ diff --git a/crates/pico-methods/pico-verifier/src/main.rs b/crates/pico-methods/pico-verifier/src/main.rs new file mode 100644 index 0000000..64b2ede --- /dev/null +++ b/crates/pico-methods/pico-verifier/src/main.rs @@ -0,0 +1,14 @@ +#![no_main] +pico_sdk::entrypoint!(main); +use pico_sdk::io::{commit_bytes, read_vec}; + +use aws_nitro_enclave_attestation_verifier::{verify_attestation_report, stub::VerifierInput}; + +pub fn main() { + let input_bytes = read_vec(); + let input = VerifierInput::decode(&input_bytes).unwrap(); + + let output = verify_attestation_report(&input).unwrap(); + + commit_bytes(&output.encode()); +} \ No newline at end of file diff --git a/crates/pico-methods/src/lib.rs b/crates/pico-methods/src/lib.rs new file mode 100644 index 0000000..41c3082 --- /dev/null +++ b/crates/pico-methods/src/lib.rs @@ -0,0 +1,3 @@ +pub const PICO_VERIFIER_ELF: &[u8] = include_bytes!("../pico-verifier/elf/riscv32im-pico-zkvm-elf"); +pub const PICO_AGGREGATOR_ELF: &[u8] = + include_bytes!("../pico-aggregator/elf/riscv32im-pico-zkvm-elf"); diff --git a/crates/prover/Cargo.toml b/crates/prover/Cargo.toml index b0e99dc..77ca065 100644 --- a/crates/prover/Cargo.toml +++ b/crates/prover/Cargo.toml @@ -9,6 +9,7 @@ license.workspace = true default = ["risc0", "sp1"] sp1 = ["dep:sp1-sdk", "dep:sp1-methods"] risc0 = ["dep:risc0-zkvm", "dep:risc0-methods", "dep:bonsai-sdk"] +pico = ["dep:pico-sdk", "dep:pico-vm", "dep:pico-methods", "dep:p3-field"] [dependencies] anyhow.workspace = true @@ -18,6 +19,10 @@ risc0-zkvm = { workspace = true, optional = true, default-features = true } risc0-methods = { workspace = true, optional = true } sp1-methods = { workspace = true, optional = true } sp1-sdk = { workspace = true, optional = true } +pico-methods = { workspace = true, optional = true } +pico-sdk = { workspace = true, optional = true } +pico-vm = { workspace = true, optional = true } +p3-field = { git = "https://github.com/brevis-network/Plonky3.git", rev = "a4d376b", optional = true } alloy-primitives.workspace = true bonsai-sdk = { workspace = true, optional = true } tokio.workspace = true diff --git a/crates/prover/src/lib.rs b/crates/prover/src/lib.rs index 61f4f7f..b738393 100644 --- a/crates/prover/src/lib.rs +++ b/crates/prover/src/lib.rs @@ -17,6 +17,11 @@ pub mod program_risc0; #[cfg(feature = "risc0")] pub use program_risc0::{ProgramRisc0, RiscZeroProverConfig}; +#[cfg(feature = "pico")] +pub mod program_pico; +#[cfg(feature = "pico")] +pub use program_pico::{ProgramPico, PicoProverConfig}; + pub fn set_prover_dev_mode(_dev_mode: bool) { #[cfg(feature = "sp1")] if _dev_mode { @@ -34,4 +39,11 @@ pub fn set_prover_dev_mode(_dev_mode: bool) { std::env::set_var("RISC0_PROVER", "bonsai"); std::env::set_var("RISC0_DEV_MODE", "0"); } + + #[cfg(feature = "pico")] + if _dev_mode { + std::env::set_var("PICO_DEV_MODE", "1"); + } else { + std::env::set_var("PICO_DEV_MODE", "0"); + } } diff --git a/crates/prover/src/program_pico.rs b/crates/prover/src/program_pico.rs new file mode 100644 index 0000000..1c00e5f --- /dev/null +++ b/crates/prover/src/program_pico.rs @@ -0,0 +1,221 @@ +use std::fs::File; +use std::marker::PhantomData; +use std::path::PathBuf; + +use alloy_primitives::{hex, Bytes, B256, U256}; +use alloy_sol_types::SolValue; +use anyhow::anyhow; +use aws_nitro_enclave_attestation_verifier::stub::{ + BatchVerifierInput, BatchVerifierJournal, VerifierInput, VerifierJournal, ZkCoProcessorType, +}; +use lazy_static::lazy_static; +use p3_field::PrimeField; +use pico_methods::{PICO_AGGREGATOR_ELF, PICO_VERIFIER_ELF}; +use pico_sdk::{client::KoalaBearProverClient, HashableKey}; +use pico_vm::{ + configs::stark_config::KoalaBearPoseidon2, + emulator::stdin::EmulatorStdinBuilder, + machine::{keys::BaseVerifyingKey, proof::MetaProof}, +}; + +use crate::{ + program::{Program, RemoteProverConfig}, + RawProof, RawProofType, +}; + +lazy_static! { + pub static ref PICO_PROGRAM_VERIFIER: ProgramPico = + ProgramPico::new(PICO_VERIFIER_ELF); + pub static ref PICO_PROGRAM_AGGREGATOR: ProgramPico = + ProgramPico::new(PICO_AGGREGATOR_ELF); +} + +#[derive(Debug, Clone)] +pub struct PicoProverConfig { + // Empty for now, extensible for future options (e.g., backend selection) +} + +impl Default for PicoProverConfig { + fn default() -> Self { + PicoProverConfig {} + } +} + +#[derive(Clone)] +pub struct ProgramPico { + elf: &'static [u8], + _marker: PhantomData<(Input, Output)>, +} + +impl ProgramPico { + pub fn new(elf: &'static [u8]) -> Self { + ProgramPico { + elf, + _marker: PhantomData, + } + } + + pub fn gen_raw_proof( + &self, + stdin_builder: EmulatorStdinBuilder, KoalaBearPoseidon2>, + raw_proof_type: RawProofType, + ) -> anyhow::Result { + let client = KoalaBearProverClient::new(self.elf); + let vk = client.riscv_vk(); + + let dev_mode = std::env::var("PICO_DEV_MODE") + .map(|v| v == "1") + .unwrap_or(false); + + let (cycle, pv_stream) = client.emulate(stdin_builder.clone()); + println!("Pico zkVM Emulation completed in {} cycles", cycle); + + let journal: Bytes = pv_stream.into(); + + if !dev_mode { + match raw_proof_type { + RawProofType::Composite => { + // prove_combine returns (riscv_proof, combine_proof) + let (_riscv_proof, combine_proof) = client.prove_combine(stdin_builder)?; + RawProof::from_proof(&(combine_proof, vk), journal) + } + RawProofType::Groth16 => { + // Use permanent artifacts directory + let output_path = PathBuf::from("evm_proof_artifacts"); + std::fs::create_dir_all(&output_path)?; + + // Check if setup is needed (vm_pk doesn't exist) + let vm_pk_path = output_path.join("vm_pk"); + let need_setup = !vm_pk_path.exists(); + + // Prove with EVM backend (KoalaBear) + client.prove_evm_with_deferred(stdin_builder, need_setup, &output_path, "kb")?; + + // Read proof.data - first 8 elements of 32-byte values + let proof_file = output_path.join("proof.data"); + let proof_data: Vec = serde_json::from_reader(File::open(proof_file)?)?; + let proof_bytes: Vec = proof_data[..8] + .iter() + .flat_map(|s| { + hex::decode(s.trim_start_matches("0x")) + .expect("Failed to decode proof hex string") + }) + .collect(); + + RawProof::from_proof(&(proof_bytes, vk), journal) + } + } + } else { + let blank: Vec = vec![]; + RawProof::from_proof(&(blank, vk), journal) + } + } +} + +impl Program for ProgramPico +where + Input: SolValue + Send + Sync, + Output: SolValue + Send + Sync, +{ + type Input = Input; + type Output = Output; + + fn version(&self) -> &'static str { + "v1.1.6" + } + + fn zktype(&self) -> ZkCoProcessorType { + ZkCoProcessorType::Pico + } + + fn onchain_proof(&self, proof: &RawProof) -> anyhow::Result { + if check_encoded_proof_is_empty(&proof.encoded_proof) { + return Ok(Bytes::new()); + } + + let (proof, _) = proof.decode_proof::<(Vec, BaseVerifyingKey)>()?; + // Decode the 8 * 32-byte proof elements + let proof_elements: Vec = proof + .chunks(32) + .take(8) + .map(|chunk| U256::from_be_slice(chunk)) + .collect(); + + // ABI encode as uint256[8] + let proof_array: [U256; 8] = proof_elements + .try_into() + .map_err(|_| anyhow!("Expected exactly 8 proof elements"))?; + Ok(proof_array.abi_encode().into()) + } + + fn upload_image(&self, _cfg: &RemoteProverConfig) -> anyhow::Result<()> { + Err(anyhow!("Remote prover is not supported for Pico zkVM")) + } + + fn program_id(&self) -> B256 { + let client = KoalaBearProverClient::new(self.elf); + let vk = client.riscv_vk(); + let vk_digest_bn254 = vk.hash_bn254(); + let vk_bytes = vk_digest_bn254.as_canonical_biguint().to_bytes_be(); + let mut result = [0u8; 32]; + result[1..].copy_from_slice(&vk_bytes); + B256::from(result) + } + + fn verify_proof_id(&self) -> B256 { + let client = KoalaBearProverClient::new(self.elf); + let vk = client.riscv_vk(); + let vk_digest: [u32; 8] = vk.hash_u32(); + B256::new(unsafe { std::mem::transmute(vk_digest) }) + } + + fn gen_proof( + &self, + input: &Self::Input, + raw_proof_type: RawProofType, + encoded_composite_proofs: Option<&[&Bytes]>, + ) -> anyhow::Result { + let client = KoalaBearProverClient::new(self.elf); + let mut stdin_builder = client.new_stdin_builder(); + + // Write input + stdin_builder.write_slice(&input.abi_encode()); + + // Handle composite proof assumptions for aggregation + if let Some(encoded_composite_proofs) = encoded_composite_proofs { + for proof_bytes in encoded_composite_proofs { + // Skip empty proofs in dev_mode + if check_encoded_proof_is_empty(&proof_bytes) { + // can't write proof because it's empty + // calling verify_pico_proof in the program in DEV_MODE does nothing + // and passes program execution + continue; + } + + let (combine_proof, vk) = bincode::deserialize::<( + MetaProof, + BaseVerifyingKey, + )>(&proof_bytes)?; + + stdin_builder.write_pico_proof(combine_proof, vk); + } + } + + self.gen_raw_proof(stdin_builder, raw_proof_type) + } +} + +fn check_encoded_proof_is_empty(encoded_proof: &Bytes) -> bool { + if encoded_proof.len() < 8 { + return true; + } + + // bincode serializes the proof with an 8-byte length prefix + let proof_len = u64::from_le_bytes( + encoded_proof[0..8] + .try_into() + .expect("Failed to read proof length"), + ) as usize; + + proof_len == 0 +} diff --git a/crates/prover/src/prover.rs b/crates/prover/src/prover.rs index 5e18003..fb89195 100644 --- a/crates/prover/src/prover.rs +++ b/crates/prover/src/prover.rs @@ -71,6 +71,21 @@ impl ProverConfig { } } + #[cfg(feature = "pico")] + pub fn pico() -> Self { + Self::pico_with(Default::default()) + } + + #[cfg(feature = "pico")] + pub fn pico_with(cfg: crate::program_pico::PicoProverConfig) -> Self { + Self { + default_trusted_certs_prefix_length: Self::default_trusted_certs_prefix_length(), + skip_time_validity_check: Self::skip_time_validity_check(), + skip_contract_program_id_check: Self::skip_contract_program_id_check(), + system: ProverSystemConfig::Pico(cfg), + } + } + fn default_trusted_certs_prefix_length() -> u8 { std::env::var("DEFAULT_TRUSTED_CERTS_PREFIX_LENGTH") .ok() @@ -99,6 +114,8 @@ pub enum ProverSystemConfig { Succinct(crate::program_sp1::SP1ProverConfig), #[cfg(feature = "risc0")] RiscZero(crate::program_risc0::RiscZeroProverConfig), + #[cfg(feature = "pico")] + Pico(crate::program_pico::PicoProverConfig), } /// AWS Nitro Enclave attestation prover using zero-knowledge proofs. @@ -295,6 +312,17 @@ impl NitroEnclaveProver { aggregator: Box::new(RISC0_PROGRAM_AGGREGATOR.clone()), } } + #[cfg(feature = "pico")] + ProverSystemConfig::Pico(_) => { + use crate::program_pico::{PICO_PROGRAM_AGGREGATOR, PICO_PROGRAM_VERIFIER}; + NitroEnclaveProver { + contract, + remote_prover_config: Err("Remote prover is not supported for Pico".to_string()), + cfg, + verifier: Box::new(PICO_PROGRAM_VERIFIER.clone()), + aggregator: Box::new(PICO_PROGRAM_AGGREGATOR.clone()), + } + } } } diff --git a/crates/verifier/Cargo.toml b/crates/verifier/Cargo.toml index 5492863..7b65fce 100644 --- a/crates/verifier/Cargo.toml +++ b/crates/verifier/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [features] sp1 = ["x509-verifier-rust-crypto/sp1"] risc0 = ["x509-verifier-rust-crypto/risc0"] +pico = ["x509-verifier-rust-crypto/pico"] [dependencies] serde_cbor.workspace = true diff --git a/crates/x509-verifier-rust-crypto/Cargo.toml b/crates/x509-verifier-rust-crypto/Cargo.toml index 631bff1..ec49387 100644 --- a/crates/x509-verifier-rust-crypto/Cargo.toml +++ b/crates/x509-verifier-rust-crypto/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] +pico = ["dep:sha2_pico"] sp1 = ["dep:p256_sp1", "dep:sha2_sp1", "dep:rsa_sp1"] risc0 = ["dep:sha2_risc0"] risc0_unstable = ["risc0", "dep:p256_risc0", "dep:rsa_risc0"] @@ -17,6 +18,7 @@ p256_sp1 = { git = "https://github.com/sp1-patches/elliptic-curves", rev = "patc p256_risc0 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "p256/v0.13.2-risczero.1", package = "p256", optional = true } sha2 = { version = "0.10.8", features = ['oid'] } +sha2_pico = { git = "https://github.com/brevis-network/hashes", tag = "pico-patch-v1.0.1-sha2-v0.10.8", package = "sha2", features = ['oid'], optional = true } sha2_sp1 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", branch = "patch-sha2-v0.10.8", package = "sha2", features = ['oid'], optional = true } sha2_risc0 = { git = "https://github.com/risc0/RustCrypto-hashes", rev = "sha2-v0.10.8-risczero.0", package = "sha2", features = ['oid'], optional = true } diff --git a/crates/x509-verifier-rust-crypto/src/lib.rs b/crates/x509-verifier-rust-crypto/src/lib.rs index c2d217a..287d582 100644 --- a/crates/x509-verifier-rust-crypto/src/lib.rs +++ b/crates/x509-verifier-rust-crypto/src/lib.rs @@ -1,10 +1,12 @@ // Override the crates by the precompiles +#[cfg(feature = "pico")] +pub extern crate sha2_pico as sha2; #[cfg(feature = "sp1")] pub extern crate sha2_sp1 as sha2; -#[cfg(all(feature = "risc0", not(feature = "sp1")))] +#[cfg(all(feature = "risc0", not(feature = "sp1"), not(feature = "pico")))] pub extern crate sha2_risc0 as sha2; -#[cfg(all(not(feature = "sp1"), not(feature = "risc0")))] +#[cfg(all(not(feature = "sp1"), not(feature = "risc0"), not(feature = "pico")))] pub use sha2; #[cfg(feature = "sp1")]