diff --git a/Cargo.lock b/Cargo.lock index 16e8689cf..5ebe8bbc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1000,6 +1000,18 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-compression" version = "0.4.11" @@ -1824,6 +1836,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console" version = "0.15.8" @@ -2961,6 +2982,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "eyre" version = "0.6.12" @@ -4888,13 +4930,13 @@ version = "0.1.0" source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-field", - "p3-matrix", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", ] [[package]] name = "p3-baby-bear" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" dependencies = [ "num-bigint 0.4.6", "p3-field", @@ -4931,12 +4973,14 @@ dependencies = [ [[package]] name = "p3-challenger" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" dependencies = [ "p3-field", - "p3-maybe-rayon", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", "p3-symmetric", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", + "serde", + "serde_with 3.8.1", "tracing", ] @@ -4948,32 +4992,44 @@ dependencies = [ "itertools 0.12.1", "p3-challenger", "p3-field", - "p3-matrix", - "p3-util", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "serde", ] +[[package]] +name = "p3-dft" +version = "0.1.0" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" +dependencies = [ + "p3-field", + "p3-matrix 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", + "p3-util 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", + "tracing", +] + [[package]] name = "p3-dft" version = "0.1.0" source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "tracing", ] [[package]] name = "p3-field" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" dependencies = [ "itertools 0.12.1", "num-bigint 0.4.6", "num-traits", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", "rand 0.8.5", "serde", ] @@ -4986,12 +5042,12 @@ dependencies = [ "itertools 0.12.1", "p3-challenger", "p3-commit", - "p3-dft", + "p3-dft 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-field", "p3-interpolation", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "serde", "tracing", ] @@ -5002,8 +5058,8 @@ version = "0.1.0" source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" dependencies = [ "p3-field", - "p3-matrix", - "p3-util", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", ] [[package]] @@ -5022,9 +5078,23 @@ source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761 dependencies = [ "p3-air", "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "tracing", +] + +[[package]] +name = "p3-matrix" +version = "0.1.0" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", + "p3-util 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", + "rand 0.8.5", + "serde", "tracing", ] @@ -5035,13 +5105,18 @@ source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761 dependencies = [ "itertools 0.12.1", "p3-field", - "p3-maybe-rayon", - "p3-util", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "rand 0.8.5", "serde", "tracing", ] +[[package]] +name = "p3-maybe-rayon" +version = "0.1.0" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" + [[package]] name = "p3-maybe-rayon" version = "0.1.0" @@ -5053,14 +5128,14 @@ dependencies = [ [[package]] name = "p3-mds" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" dependencies = [ "itertools 0.12.1", - "p3-dft", + "p3-dft 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", "p3-field", - "p3-matrix", + "p3-matrix 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", "p3-symmetric", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Champii/Plonky3.git?branch=serde_patch)", "rand 0.8.5", ] @@ -5072,10 +5147,10 @@ dependencies = [ "itertools 0.12.1", "p3-commit", "p3-field", - "p3-matrix", - "p3-maybe-rayon", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-symmetric", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "serde", "tracing", ] @@ -5083,19 +5158,21 @@ dependencies = [ [[package]] name = "p3-poseidon2" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" dependencies = [ "gcd", "p3-field", "p3-mds", "p3-symmetric", "rand 0.8.5", + "serde", + "serde_with 3.8.1", ] [[package]] name = "p3-symmetric" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07#88ea2b866e41329817e4761429b4a5a2a9751c07" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" dependencies = [ "itertools 0.12.1", "p3-field", @@ -5111,15 +5188,23 @@ dependencies = [ "p3-air", "p3-challenger", "p3-commit", - "p3-dft", + "p3-dft 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "serde", "tracing", ] +[[package]] +name = "p3-util" +version = "0.1.0" +source = "git+https://github.com/Champii/Plonky3.git?branch=serde_patch#786cc3cb1c4dc22a08463abe88f1e68e5119ee54" +dependencies = [ + "serde", +] + [[package]] name = "p3-util" version = "0.1.0" @@ -5173,6 +5258,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.11.2" @@ -8264,7 +8355,7 @@ dependencies = [ [[package]] name = "sp1-core" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "anyhow", "arrayref", @@ -8289,18 +8380,18 @@ dependencies = [ "p3-blake3", "p3-challenger", "p3-commit", - "p3-dft", + "p3-dft 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-field", "p3-fri", "p3-keccak", "p3-keccak-air", - "p3-matrix", - "p3-maybe-rayon", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-merkle-tree", "p3-poseidon2", "p3-symmetric", "p3-uni-stark", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "rand 0.8.5", "rayon-scan", "rrs-lib 0.1.0 (git+https://github.com/GregAC/rrs.git)", @@ -8324,7 +8415,7 @@ dependencies = [ [[package]] name = "sp1-derive" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "proc-macro2", "quote", @@ -8338,18 +8429,30 @@ dependencies = [ "alloy-primitives", "alloy-sol-types", "anyhow", + "async-channel", + "bincode", + "log", "once_cell", + "p3-baby-bear", + "p3-challenger", + "p3-field", + "p3-poseidon2", + "p3-symmetric", "raiko-lib", "serde", "serde_json", "sha3", + "sp1-core", "sp1-sdk", + "tempfile", + "tokio", + "tracing", ] [[package]] name = "sp1-primitives" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "itertools 0.13.0", "lazy_static", @@ -8362,7 +8465,7 @@ dependencies = [ [[package]] name = "sp1-prover" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "anyhow", "backtrace", @@ -8380,7 +8483,7 @@ dependencies = [ "p3-challenger", "p3-commit", "p3-field", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "rand 0.8.5", "rayon", "reqwest 0.12.5", @@ -8407,7 +8510,7 @@ dependencies = [ [[package]] name = "sp1-recursion-circuit" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "bincode", "itertools 0.13.0", @@ -8417,8 +8520,8 @@ dependencies = [ "p3-commit", "p3-field", "p3-fri", - "p3-matrix", - "p3-util", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "serde", "sp1-core", "sp1-recursion-compiler", @@ -8430,7 +8533,7 @@ dependencies = [ [[package]] name = "sp1-recursion-compiler" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "backtrace", "itertools 0.13.0", @@ -8440,10 +8543,10 @@ dependencies = [ "p3-commit", "p3-field", "p3-fri", - "p3-matrix", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-poseidon2", "p3-symmetric", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "serde", "sp1-core", "sp1-recursion-core", @@ -8454,7 +8557,7 @@ dependencies = [ [[package]] name = "sp1-recursion-core" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "arrayref", "backtrace", @@ -8466,15 +8569,15 @@ dependencies = [ "p3-bn254-fr", "p3-challenger", "p3-commit", - "p3-dft", + "p3-dft 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-field", "p3-fri", - "p3-matrix", - "p3-maybe-rayon", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-merkle-tree", "p3-poseidon2", "p3-symmetric", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "serde", "serde_with 3.8.1", "sp1-core", @@ -8488,7 +8591,7 @@ dependencies = [ [[package]] name = "sp1-recursion-derive" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "proc-macro2", "quote", @@ -8498,7 +8601,7 @@ dependencies = [ [[package]] name = "sp1-recursion-gnark-ffi" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "anyhow", "bincode", @@ -8523,22 +8626,22 @@ dependencies = [ [[package]] name = "sp1-recursion-program" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "itertools 0.13.0", "p3-air", "p3-baby-bear", "p3-challenger", "p3-commit", - "p3-dft", + "p3-dft 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-field", "p3-fri", - "p3-matrix", - "p3-maybe-rayon", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", + "p3-maybe-rayon 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "p3-merkle-tree", "p3-poseidon2", "p3-symmetric", - "p3-util", + "p3-util 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "rand 0.8.5", "serde", "sp1-core", @@ -8550,7 +8653,7 @@ dependencies = [ [[package]] name = "sp1-sdk" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#14eb569d41d24721ffbd407d6060e202482d659c" +source = "git+https://github.com/succinctlabs/sp1.git?rev=14eb569d41d24721ffbd407d6060e202482d659c#14eb569d41d24721ffbd407d6060e202482d659c" dependencies = [ "alloy-sol-types", "anyhow", @@ -8567,7 +8670,7 @@ dependencies = [ "num-bigint 0.4.6", "p3-commit", "p3-field", - "p3-matrix", + "p3-matrix 0.1.0 (git+https://github.com/Plonky3/Plonky3.git?rev=88ea2b866e41329817e4761429b4a5a2a9751c07)", "prost", "reqwest 0.12.5", "reqwest-middleware", diff --git a/Cargo.toml b/Cargo.toml index a8130d811..9bc7ca4fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,9 +54,19 @@ risc0-build = { version = "0.21.0" } risc0-binfmt = { version = "0.21.0" } # SP1 -sp1-sdk = { git = "https://github.com/succinctlabs/sp1.git", branch = "main" } -sp1-zkvm = { git = "https://github.com/succinctlabs/sp1.git", branch = "main" } -sp1-helper = { git = "https://github.com/succinctlabs/sp1.git", branch = "main" } +sp1-sdk = { git = "https://github.com/succinctlabs/sp1.git", rev = "14eb569d41d24721ffbd407d6060e202482d659c" } +sp1-zkvm = { git = "https://github.com/succinctlabs/sp1.git", rev = "14eb569d41d24721ffbd407d6060e202482d659c" } +sp1-helper = { git = "https://github.com/succinctlabs/sp1.git", rev = "14eb569d41d24721ffbd407d6060e202482d659c" } +sp1-core = { git = "https://github.com/succinctlabs/sp1.git", rev = "14eb569d41d24721ffbd407d6060e202482d659c" } + + +# Plonky3 +p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-poseidon2 = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } +p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "88ea2b866e41329817e4761429b4a5a2a9751c07" } + # alloy alloy-rlp = { version = "0.3.4", default-features = false } @@ -149,6 +159,7 @@ secp256k1 = { version = "0.29", default-features = false, features = [ "global-context", "recovery", ] } +async-channel = "2.3.1" # macro syn = { version = "1.0", features = ["full"] } @@ -188,3 +199,12 @@ revm-primitives = { git = "https://github.com/taikoxyz/revm.git", branch = "v36- revm-precompile = { git = "https://github.com/taikoxyz/revm.git", branch = "v36-taiko" } secp256k1 = { git = "https://github.com/CeciliaZ030/rust-secp256k1", branch = "sp1-patch" } blst = { git = "https://github.com/CeciliaZ030/blst.git", branch = "v0.3.12-serialize" } + +# Patch Plonky3 for Serialize and Deserialize of DuplexChallenger +[patch."https://github.com/Plonky3/Plonky3.git"] +p3-field = { git = "https://github.com/Champii/Plonky3.git", branch = "serde_patch" } +p3-challenger = { git = "https://github.com/Champii/Plonky3.git", branch = "serde_patch" } +p3-poseidon2 = { git = "https://github.com/Champii/Plonky3.git", branch = "serde_patch" } +p3-baby-bear = { git = "https://github.com/Champii/Plonky3.git", branch = "serde_patch" } +p3-symmetric = { git = "https://github.com/Champii/Plonky3.git", branch = "serde_patch" } + diff --git a/core/src/interfaces.rs b/core/src/interfaces.rs index e07619732..e1141aa4f 100644 --- a/core/src/interfaces.rs +++ b/core/src/interfaces.rs @@ -104,6 +104,10 @@ pub enum ProofType { /// /// Uses the SP1 prover to build the block. Sp1, + /// # Sp1Distributed + /// + /// Uses the SP1 prover to build the block in a distributed way. + Sp1Distributed, /// # Sgx /// /// Builds the block on a SGX supported CPU to create a proof. @@ -119,6 +123,7 @@ impl std::fmt::Display for ProofType { f.write_str(match self { ProofType::Native => "native", ProofType::Sp1 => "sp1", + ProofType::Sp1Distributed => "sp1_distributed", ProofType::Sgx => "sgx", ProofType::Risc0 => "risc0", }) @@ -132,6 +137,7 @@ impl FromStr for ProofType { match s.trim().to_lowercase().as_str() { "native" => Ok(ProofType::Native), "sp1" => Ok(ProofType::Sp1), + "sp1_distributed" => Ok(ProofType::Sp1Distributed), "sgx" => Ok(ProofType::Sgx), "risc0" => Ok(ProofType::Risc0), _ => Err(RaikoError::InvalidProofType(s.to_string())), @@ -159,6 +165,14 @@ impl ProofType { #[cfg(not(feature = "sp1"))] Err(RaikoError::FeatureNotSupportedError(*self)) } + ProofType::Sp1Distributed => { + #[cfg(feature = "sp1")] + return sp1_driver::Sp1DistributedProver::run(input, output, config) + .await + .map_err(|e| e.into()); + #[cfg(not(feature = "sp1"))] + Err(RaikoError::FeatureNotSupportedError(*self)) + } ProofType::Risc0 => { #[cfg(feature = "risc0")] return risc0_driver::Risc0Prover::run(input.clone(), output, config) diff --git a/core/src/preflight.rs b/core/src/preflight.rs index b426de656..a95dc6949 100644 --- a/core/src/preflight.rs +++ b/core/src/preflight.rs @@ -237,7 +237,8 @@ async fn prepare_taiko_chain_input( .await?; // Fetch the tx data from either calldata or blobdata - let (tx_data, blob_commitment) = if proposal_event.meta.blobUsed { + // let (tx_data, blob_commitment) = if proposal_event.meta.blobUsed { + let (tx_data, blob_commitment) = if false { debug!("blob active"); // Get the blob hashes attached to the propose tx let blob_hashes = proposal_tx.blob_versioned_hashes.unwrap_or_default(); diff --git a/host/Cargo.toml b/host/Cargo.toml index 6e997bb34..bab5f9a5c 100644 --- a/host/Cargo.toml +++ b/host/Cargo.toml @@ -82,7 +82,7 @@ ethers-core = { workspace = true } [features] default = [] -sp1 = ["raiko-core/sp1"] +sp1 = ["raiko-core/sp1", "sp1-driver"] risc0 = ["raiko-core/risc0"] sgx = ["raiko-core/sgx"] diff --git a/host/src/lib.rs b/host/src/lib.rs index 80b59fe20..d07bad58a 100644 --- a/host/src/lib.rs +++ b/host/src/lib.rs @@ -39,6 +39,10 @@ fn default_address() -> String { "0.0.0.0:8080".to_string() } +fn default_worker_address() -> String { + "0.0.0.0:8081".to_string() +} + fn default_concurrency_limit() -> usize { 16 } @@ -69,6 +73,17 @@ pub struct Cli { /// [default: 0.0.0.0:8080] address: String, + #[arg(long, require_equals = true, default_value = "0.0.0.0:8081")] + #[serde(default = "default_worker_address")] + /// Distributed SP1 worker listening address + /// [default: 0.0.0.0:8081] + worker_address: String, + + #[arg(long, default_value = None)] + /// Distributed SP1 worker orchestrator address + /// [default: None] + orchestrator_address: Option, + #[arg(long, require_equals = true, default_value = "16")] #[serde(default = "default_concurrency_limit")] /// Limit the max number of in-flight requests diff --git a/host/src/server/mod.rs b/host/src/server/mod.rs index bec5e6914..b4b579ff3 100644 --- a/host/src/server/mod.rs +++ b/host/src/server/mod.rs @@ -5,9 +5,14 @@ use tokio::net::TcpListener; use tracing::info; pub mod api; +#[cfg(feature = "sp1")] +pub mod worker; /// Starts the proverd server. pub async fn serve(state: ProverState) -> anyhow::Result<()> { + #[cfg(feature = "sp1")] + worker::serve(state.clone()).await; + let addr = SocketAddr::from_str(&state.opts.address) .map_err(|_| HostError::InvalidAddress(state.opts.address.clone()))?; let listener = TcpListener::bind(addr).await?; diff --git a/host/src/server/worker.rs b/host/src/server/worker.rs new file mode 100644 index 000000000..65ac85a54 --- /dev/null +++ b/host/src/server/worker.rs @@ -0,0 +1,73 @@ +use crate::ProverState; +use raiko_lib::prover::{ProverError, WorkerError}; +use sp1_driver::{PartialProofRequest, WorkerProtocol, WorkerSocket}; +use tokio::net::TcpListener; +use tracing::{error, info, warn}; + +async fn handle_worker_socket(mut socket: WorkerSocket) -> Result<(), ProverError> { + let protocol = socket.receive().await?; + + info!("Received request from orchestrator: {}", protocol); + + match protocol { + WorkerProtocol::Ping => { + socket.send(WorkerProtocol::Pong).await?; + } + WorkerProtocol::PartialProofRequest(data) => { + process_partial_proof_request(socket, data).await?; + } + _ => Err(WorkerError::InvalidRequest)?, + } + + Ok(()) +} + +async fn process_partial_proof_request( + mut socket: WorkerSocket, + data: PartialProofRequest, +) -> Result<(), ProverError> { + let partial_proof = sp1_driver::Sp1DistributedProver::run_as_worker(data).await?; + + socket + .send(WorkerProtocol::PartialProofResponse(partial_proof)) + .await?; + + Ok(()) +} + +async fn listen_worker(state: ProverState) { + info!( + "Listening as a SP1 worker on: {}", + state.opts.worker_address + ); + + let listener = TcpListener::bind(state.opts.worker_address).await.unwrap(); + + loop { + let Ok((socket, addr)) = listener.accept().await else { + error!("Error while accepting connection from orchestrator: Closing socket"); + + return; + }; + + if let Some(orchestrator_address) = &state.opts.orchestrator_address { + if addr.ip().to_string() != *orchestrator_address { + warn!("Unauthorized orchestrator connection from: {}", addr); + + continue; + } + } + + // We purposely don't spawn the task here, as we want to block to limit the number + // of concurrent connections to one. + if let Err(e) = handle_worker_socket(WorkerSocket::new(socket)).await { + error!("Error while handling worker socket: {:?}", e); + } + } +} + +pub async fn serve(state: ProverState) { + if state.opts.orchestrator_address.is_some() { + tokio::spawn(listen_worker(state)); + } +} diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 0da2f7cc6..e6d68c0e1 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -71,4 +71,4 @@ std = [ sgx = [] sp1 = [] risc0 = [] -sp1-cycle-tracker = [] \ No newline at end of file +sp1-cycle-tracker = [] diff --git a/lib/src/prover.rs b/lib/src/prover.rs index e5d93343d..4e26c30ca 100644 --- a/lib/src/prover.rs +++ b/lib/src/prover.rs @@ -11,6 +11,8 @@ pub enum ProverError { FileIo(#[from] std::io::Error), #[error("ProverError::Param `{0}`")] Param(#[from] serde_json::Error), + #[error("ProverError::Worker `{0}`")] + Worker(#[from] WorkerError), } impl From for ProverError { @@ -37,3 +39,21 @@ pub fn to_proof(proof: ProverResult) -> ProverResult { serde_json::to_value(res).map_err(|err| ProverError::GuestError(err.to_string())) }) } + +#[derive(ThisError, Debug)] +pub enum WorkerError { + #[error("All workers failed")] + AllWorkersFailed, + #[error("Worker IO error: {0}")] + IO(#[from] std::io::Error), + #[error("Worker Serde error: {0}")] + Serde(#[from] bincode::Error), + #[error("Worker invalid magic number")] + InvalidMagicNumber, + #[error("Worker invalid request")] + InvalidRequest, + #[error("Worker invalid response")] + InvalidResponse, + #[error("Worker payload too big")] + PayloadTooBig, +} diff --git a/provers/sp1/driver/Cargo.toml b/provers/sp1/driver/Cargo.toml index b9dff341a..0aecaac49 100644 --- a/provers/sp1/driver/Cargo.toml +++ b/provers/sp1/driver/Cargo.toml @@ -16,10 +16,24 @@ alloy-sol-types = { workspace = true } serde = { workspace = true , optional = true} serde_json = { workspace = true , optional = true } sp1-sdk = { workspace = true, optional = true } +sp1-core = { workspace = true, optional = true } anyhow = { workspace = true, optional = true } once_cell = { workspace = true, optional = true } sha3 = { workspace = true, optional = true, default-features = false} +log = { workspace = true } +tokio = { workspace = true } +async-channel = { workspace = true } +tracing = { workspace = true } +tempfile = { workspace = true } +bincode = { workspace = true } + +p3-field = { workspace = true } +p3-challenger = { workspace = true } +p3-poseidon2 = { workspace = true } +p3-baby-bear = { workspace = true } +p3-symmetric = { workspace = true } + [features] enable = [ @@ -27,6 +41,7 @@ enable = [ "serde_json", "raiko-lib", "sp1-sdk", + "sp1-core", "anyhow", "alloy-primitives", "once_cell", diff --git a/provers/sp1/driver/src/distributed/mod.rs b/provers/sp1/driver/src/distributed/mod.rs new file mode 100644 index 000000000..d12d892e2 --- /dev/null +++ b/provers/sp1/driver/src/distributed/mod.rs @@ -0,0 +1,9 @@ +mod orchestrator; +mod partial_proof_request; +mod prover; +mod sp1_specifics; +mod worker; + +pub use partial_proof_request::PartialProofRequest; +pub use prover::Sp1DistributedProver; +pub use worker::{WorkerEnvelope, WorkerProtocol, WorkerSocket}; diff --git a/provers/sp1/driver/src/distributed/orchestrator/mod.rs b/provers/sp1/driver/src/distributed/orchestrator/mod.rs new file mode 100644 index 000000000..d2d4397cc --- /dev/null +++ b/provers/sp1/driver/src/distributed/orchestrator/mod.rs @@ -0,0 +1,79 @@ +mod worker_client; + +use raiko_lib::prover::WorkerError; +use sp1_core::{runtime::ExecutionState, stark::ShardProof, utils::BabyBearPoseidon2}; +use worker_client::WorkerClient; + +use super::partial_proof_request::PartialProofRequest; + +pub async fn distribute_work( + ip_list: Vec, + checkpoints: Vec, + partial_proof_request: PartialProofRequest, +) -> Result>, WorkerError> { + let mut nb_workers = ip_list.len(); + + let (queue_tx, queue_rx) = async_channel::bounded(nb_workers); + let (answer_tx, answer_rx) = async_channel::bounded(nb_workers); + + // Spawn the workers + for (i, url) in ip_list.iter().enumerate() { + let worker = WorkerClient::new( + i, + url.clone(), + queue_rx.clone(), + answer_tx.clone(), + partial_proof_request.clone(), + ); + + tokio::spawn(async move { + worker.run().await; + }); + } + + // Send the checkpoints to the workers + for (i, checkpoint) in checkpoints.iter().enumerate() { + queue_tx.send((i, checkpoint.clone())).await.unwrap(); + } + + let mut proofs = Vec::new(); + + // Get the partial proofs from the workers + loop { + let (checkpoint_id, partial_proof_result) = answer_rx.recv().await.unwrap(); + + match partial_proof_result { + Ok(partial_proof) => { + proofs.push((checkpoint_id as usize, partial_proof)); + } + Err(_e) => { + // Decrease the number of workers + nb_workers -= 1; + + if nb_workers == 0 { + return Err(WorkerError::AllWorkersFailed); + } + + // Push back the work for it to be done by another worker + queue_tx + .send((checkpoint_id, checkpoints[checkpoint_id as usize].clone())) + .await + .unwrap(); + } + } + + if proofs.len() == checkpoints.len() { + break; + } + } + + proofs.sort_by_key(|(checkpoint_id, _)| *checkpoint_id); + + let proofs = proofs + .into_iter() + .map(|(_, proof)| proof) + .flatten() + .collect(); + + Ok(proofs) +} diff --git a/provers/sp1/driver/src/distributed/orchestrator/worker_client.rs b/provers/sp1/driver/src/distributed/orchestrator/worker_client.rs new file mode 100644 index 000000000..73203b7fa --- /dev/null +++ b/provers/sp1/driver/src/distributed/orchestrator/worker_client.rs @@ -0,0 +1,87 @@ +use async_channel::{Receiver, Sender}; +use raiko_lib::prover::WorkerError; +use sp1_core::{runtime::ExecutionState, stark::ShardProof, utils::BabyBearPoseidon2}; + +use crate::{distributed::partial_proof_request::PartialProofRequest, WorkerSocket}; + +pub struct WorkerClient { + /// The id of the worker + id: usize, + /// The url of the worker + url: String, + /// A queue to receive the checkpoint to compute the partial proof + queue: Receiver<(usize, ExecutionState)>, + /// A channel to send back the id of the checkpoint along with the json strings encoding the computed partial proofs + answer: Sender<( + usize, + Result>, WorkerError>, + )>, + /// The partial proof request containing the checkpoint data and the challenger + partial_proof_request: PartialProofRequest, +} + +impl WorkerClient { + pub fn new( + id: usize, + url: String, + queue: Receiver<(usize, ExecutionState)>, + answer: Sender<( + usize, + Result>, WorkerError>, + )>, + partial_proof_request: PartialProofRequest, + ) -> Self { + WorkerClient { + id, + url, + queue, + answer, + partial_proof_request, + } + } + + pub async fn run(&self) { + while let Ok((i, checkpoint)) = self.queue.recv().await { + let partial_proof_result = self.send_work_tcp(i, checkpoint).await; + + if let Err(e) = partial_proof_result { + log::error!( + "Error while sending checkpoint to worker {}: {}. {}", + self.id, + self.url, + e, + ); + + self.answer.send((i, Err(e))).await.unwrap(); + + return; + } + + self.answer.send((i, partial_proof_result)).await.unwrap(); + } + + log::debug!("Worker {} finished", self.id); + } + + async fn send_work_tcp( + &self, + i: usize, + checkpoint: ExecutionState, + ) -> Result>, WorkerError> { + let mut socket = WorkerSocket::connect(&self.url).await?; + + log::info!( + "Sending checkpoint {} to worker {} at {}", + i, + self.id, + self.url + ); + + let mut request = self.partial_proof_request.clone(); + + request.checkpoint_id = i; + request.checkpoint_data = checkpoint; + + socket.partial_proof_request(request).await + } +} diff --git a/provers/sp1/driver/src/distributed/partial_proof_request.rs b/provers/sp1/driver/src/distributed/partial_proof_request.rs new file mode 100644 index 000000000..3d5bf5491 --- /dev/null +++ b/provers/sp1/driver/src/distributed/partial_proof_request.rs @@ -0,0 +1,17 @@ +use p3_challenger::DuplexChallenger; +use serde::{Deserialize, Serialize}; + +use sp1_core::{ + air::PublicValues, + runtime::ExecutionState, + utils::baby_bear_poseidon2::{Perm, Val}, +}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PartialProofRequest { + pub checkpoint_id: usize, + pub checkpoint_data: ExecutionState, + pub challenger: DuplexChallenger, + pub public_values: PublicValues, + pub shard_batch_size: usize, +} diff --git a/provers/sp1/driver/src/distributed/prover.rs b/provers/sp1/driver/src/distributed/prover.rs new file mode 100644 index 000000000..9c6c268c1 --- /dev/null +++ b/provers/sp1/driver/src/distributed/prover.rs @@ -0,0 +1,144 @@ +use std::env; + +use raiko_lib::{ + input::{GuestInput, GuestOutput}, + prover::{to_proof, Proof, Prover, ProverConfig, ProverError, ProverResult, WorkerError}, +}; +use sp1_core::{runtime::Program, stark::ShardProof, utils::BabyBearPoseidon2}; +use sp1_sdk::{ProverClient, SP1ProofWithPublicValues, SP1Stdin}; + +use crate::{ + distributed::{ + partial_proof_request::PartialProofRequest, + sp1_specifics::{commit, prove_partial}, + }, + Sp1Response, WorkerSocket, ELF, +}; + +pub struct Sp1DistributedProver; + +impl Prover for Sp1DistributedProver { + async fn run( + input: GuestInput, + _output: &GuestOutput, + _config: &ProverConfig, + ) -> ProverResult { + log::info!("Running SP1 Distributed orchestrator"); + + let now = std::time::Instant::now(); + + // Write the input. + let mut stdin = SP1Stdin::new(); + stdin.write(&input); + + // Generate the proof for the given program. + let client = ProverClient::new(); + let (_pk, vk) = client.setup(ELF); + + let proof = Self::run_as_orchestrator(stdin).await?; + + // Verify proof. + client + .verify(&proof, &vk) + .expect("Sp1: verification failed"); + + log::info!( + "Proof generation and verification took: {:?}s", + now.elapsed().as_secs() + ); + + // Save the proof. + let proof_dir = env::current_dir().expect("Sp1: dir error"); + + proof + .save( + proof_dir + .as_path() + .join("proof-with-io.json") + .to_str() + .unwrap(), + ) + .expect("Sp1: saving proof failed"); + + to_proof(Ok(Sp1Response { + proof: serde_json::to_string(&proof).unwrap(), + })) + } +} + +impl Sp1DistributedProver { + pub async fn run_as_orchestrator( + stdin: SP1Stdin, + ) -> ProverResult>>> { + let program = Program::from(ELF); + + let worker_ip_list = Self::read_and_validate_worker_ip_list().await?; + + let (checkpoints, public_values_stream, partial_proof_request) = + commit(program, &stdin, worker_ip_list.len()) + .map_err(|e| ProverError::GuestError(e.to_string()))?; + + let proofs = super::orchestrator::distribute_work( + worker_ip_list, + checkpoints, + partial_proof_request, + ) + .await?; + + Ok(SP1ProofWithPublicValues { + proof: proofs, + stdin, + public_values: public_values_stream, + sp1_version: sp1_core::SP1_CIRCUIT_VERSION.to_string(), + }) + } + + pub async fn run_as_worker( + partial_proof_request: PartialProofRequest, + ) -> ProverResult>> { + log::debug!( + "Running SP1 Distributed worker: Prove shard nb {}", + partial_proof_request.checkpoint_id + ); + + let partial_proof = prove_partial(&partial_proof_request); + + Ok(partial_proof) + } + + async fn read_and_validate_worker_ip_list() -> Result, WorkerError> { + let ip_list_string = std::fs::read_to_string("distributed.json") + .expect("Sp1 Distributed: Need a `distributed.json` file with a list of IP:PORT"); + + let ip_list: Vec = serde_json::from_str(&ip_list_string).expect( + "Sp1 Distributed: Invalid JSON for `distributed.json`. need an array of IP:PORT", + ); + + let mut reachable_ip_list = Vec::new(); + + // try to connect to each worker to make sure they are reachable + for ip in &ip_list { + let Ok(mut socket) = WorkerSocket::connect(ip).await else { + log::warn!("Sp1 Distributed: Worker at {} is not reachable. Removing from the list for this task", ip); + + continue; + }; + + if let Err(_) = socket.ping().await { + log::warn!("Sp1 Distributed: Worker at {} is not sending good response to Ping. Removing from the list for this task", ip); + + continue; + } + + reachable_ip_list.push(ip.clone()); + } + + if reachable_ip_list.is_empty() { + log::error!("Sp1 Distributed: No reachable workers found. Aborting..."); + + return Err(WorkerError::AllWorkersFailed); + } + + Ok(reachable_ip_list) + } +} diff --git a/provers/sp1/driver/src/distributed/sp1_specifics.rs b/provers/sp1/driver/src/distributed/sp1_specifics.rs new file mode 100644 index 000000000..1997d543d --- /dev/null +++ b/provers/sp1/driver/src/distributed/sp1_specifics.rs @@ -0,0 +1,311 @@ +use std::{ + fs::File, + io::{Seek, Write}, + time::Instant, +}; + +use p3_baby_bear::BabyBear; +use p3_challenger::{CanObserve, DuplexChallenger}; + +use sp1_core::{ + air::PublicValues, + runtime::{ExecutionRecord, ExecutionState, Program, Runtime, ShardingConfig}, + stark::{LocalProver, MachineRecord, RiscvAir, ShardProof, StarkGenericConfig, StarkMachine}, + utils::{ + baby_bear_poseidon2::{Perm, Val}, + BabyBearPoseidon2, SP1CoreOpts, SP1CoreProverError, + }, +}; +use sp1_sdk::CoreSC; +use sp1_sdk::{SP1PublicValues, SP1Stdin}; + +use crate::ELF; + +use super::partial_proof_request::PartialProofRequest; + +fn trace_checkpoint( + program: Program, + file: &File, + opts: SP1CoreOpts, +) -> (ExecutionState, ExecutionRecord) { + let mut reader = std::io::BufReader::new(file); + + let state: ExecutionState = + bincode::deserialize_from(&mut reader).expect("failed to deserialize state"); + + let mut runtime = Runtime::recover(program.clone(), state.clone(), opts); + + let (events, _) = + tracing::debug_span!("runtime.trace").in_scope(|| runtime.execute_record().unwrap()); + + (state, events) +} + +fn compute_checkpoints( + runtime: &mut Runtime, +) -> Result<(Vec, Vec, PublicValues), SP1CoreProverError> { + let checkpoints_start = Instant::now(); + + let mut checkpoints_files = Vec::new(); + + // Execute the program, saving checkpoints at the start of every `shard_batch_size` cycle range. + let (public_values_stream, public_values) = loop { + let checkpoint_start = Instant::now(); + + // Execute the runtime until we reach a checkpoint. + let (checkpoint, done) = runtime + .execute_state() + .map_err(SP1CoreProverError::ExecutionError)?; + + log::debug!("Checkpoint took {:?}", checkpoint_start.elapsed()); + + // Save the checkpoint to a temp file. + let mut tempfile = tempfile::tempfile().map_err(SP1CoreProverError::IoError)?; + + let mut writer = std::io::BufWriter::new(&mut tempfile); + + bincode::serialize_into(&mut writer, &checkpoint) + .map_err(SP1CoreProverError::SerializationError)?; + + writer.flush().map_err(SP1CoreProverError::IoError)?; + + drop(writer); + + tempfile + .seek(std::io::SeekFrom::Start(0)) + .map_err(SP1CoreProverError::IoError)?; + + checkpoints_files.push(tempfile); + + // If we've reached the final checkpoint, break out of the loop. + if done { + break ( + std::mem::take(&mut runtime.state.public_values_stream), + runtime.record.public_values, + ); + } + }; + + log::debug!("Total checkpointing took {:?}", checkpoints_start.elapsed()); + + Ok((checkpoints_files, public_values_stream, public_values)) +} + +fn commit_checkpoints( + checkpoints_files: Vec, + program: Program, + opts: SP1CoreOpts, + public_values: PublicValues, + machine: &StarkMachine>, + challenger: &mut DuplexChallenger, +) -> Vec { + let now = Instant::now(); + + let sharding_config = ShardingConfig::default(); + let mut checkpoints_states = Vec::new(); + + // Only keep the first checkpoint file of each batch. + let checkpoints_files = checkpoints_files + .chunks(opts.shard_batch_size) + .map(|chunk| &chunk[0]) + .collect::>(); + + let nb_checkpoints = checkpoints_files.len(); + + // For each checkpoint, generate events, shard them, commit shards, and observe in challenger. + for (i, checkpoint_file) in checkpoints_files.into_iter().enumerate() { + log::info!("Committing checkpoint {}/{}", i + 1, nb_checkpoints); + + let trace_checkpoint_time = Instant::now(); + + let (state, mut record) = trace_checkpoint(program.clone(), checkpoint_file, opts); + record.public_values = public_values; + + checkpoints_states.push(state); + + log::debug!( + "Checkpoint trace took {:?}", + trace_checkpoint_time.elapsed() + ); + + let sharding_time = Instant::now(); + + // Shard the record into shards. + let checkpoint_shards = + tracing::info_span!("shard").in_scope(|| machine.shard(record, &sharding_config)); + + log::debug!("Checkpoint sharding took {:?}", sharding_time.elapsed()); + + let commit_time = Instant::now(); + + // Commit to each shard. + let (commitments, _commit_data) = tracing::info_span!("commit") + .in_scope(|| LocalProver::commit_shards(&machine, &checkpoint_shards, opts)); + + log::debug!("Checkpoint commit took {:?}", commit_time.elapsed()); + + // Observe the commitments. + for (commitment, shard) in commitments.into_iter().zip(checkpoint_shards.iter()) { + challenger.observe(commitment); + challenger.observe_slice(&shard.public_values::()[0..machine.num_pv_elts()]); + } + } + + log::debug!("Checkpoints commitment took {:?}", now.elapsed()); + + checkpoints_states +} + +// Meant to be run by the orchestrator to commit the program and generate the partial proof +// request. +pub fn commit( + program: Program, + stdin: &SP1Stdin, + nb_workers: usize, +) -> Result<(Vec, SP1PublicValues, PartialProofRequest), SP1CoreProverError> { + let proving_start = Instant::now(); + let runtime_setup_start = Instant::now(); + + log::debug!("Starting commit"); + + let config = CoreSC::default(); + let mut opts = SP1CoreOpts::default(); + + // FIXME: Is this the most efficient ? + opts.shard_batch_size = 1; + + // Execute the program. + let mut runtime = Runtime::new(program.clone(), opts); + runtime.write_vecs(&stdin.buffer); + + for proof in stdin.proofs.iter() { + runtime.write_proof(proof.0.clone(), proof.1.clone()); + } + + log::debug!("Runtime setup took {:?}", runtime_setup_start.elapsed()); + + let machine_setup_start = Instant::now(); + + // Setup the machine. + let machine = RiscvAir::machine(config.clone()); + let (_pk, vk) = machine.setup(runtime.program.as_ref()); + + log::debug!("Machine setup took {:?}", machine_setup_start.elapsed()); + + let (checkpoints_files, public_values_stream, public_values) = + compute_checkpoints(&mut runtime)?; + + let mut challenger = machine.config().challenger(); + vk.observe_into(&mut challenger); + + opts.shard_batch_size = (checkpoints_files.len() as f64 / nb_workers as f64).ceil() as usize; + + let checkpoints_states = commit_checkpoints( + checkpoints_files, + program, + opts, + public_values, + &machine, + &mut challenger, + ); + + log::debug!("Total setup took {:?}", proving_start.elapsed()); + + let partial_proof_request = PartialProofRequest { + checkpoint_id: 0, + checkpoint_data: ExecutionState::default(), + challenger, + public_values, + shard_batch_size: opts.shard_batch_size, + }; + + Ok(( + checkpoints_states, + SP1PublicValues::from(&public_values_stream), + partial_proof_request, + )) +} + +// Meant to be run by the worker to generate the partial proof. +pub fn prove_partial(request_data: &PartialProofRequest) -> Vec> { + let prove_partial_start = Instant::now(); + + let program = Program::from(ELF); + let config = CoreSC::default(); + let mut opts = SP1CoreOpts::default(); + + opts.shard_batch_size = request_data.shard_batch_size; + + let machine = RiscvAir::machine(config.clone()); + let (pk, _vk) = machine.setup(&program); + + let sharding_config = ShardingConfig::default(); + let runtime_recover_start = Instant::now(); + let mut shard_proofs = vec![]; + + let events = { + let mut runtime = + Runtime::recover(program.clone(), request_data.checkpoint_data.clone(), opts); + + let (mut events, _) = + tracing::debug_span!("runtime.trace").in_scope(|| runtime.execute_record().unwrap()); + + events.public_values = request_data.public_values; + + events + }; + + log::debug!("Runtime recover took {:?}", runtime_recover_start.elapsed()); + + let now = Instant::now(); + + let checkpoint_shards = + tracing::info_span!("shard").in_scope(|| machine.shard(events, &sharding_config)); + + log::debug!("Checkpoint sharding took {:?}", now.elapsed()); + + let nb_shards = checkpoint_shards.len(); + + let mut proofs = checkpoint_shards + .into_iter() + .enumerate() + .map(|(i, shard)| { + log::info!("Proving shard {}/{}", i + 1, nb_shards); + + let config = machine.config(); + + let commit_main_start = Instant::now(); + + let shard_data = + LocalProver::commit_main(config, &machine, &shard, shard.index() as usize); + + log::debug!("Commit main took {:?}", commit_main_start.elapsed()); + + let chip_ordering = shard_data.chip_ordering.clone(); + let ordered_chips = machine + .shard_chips_ordered(&chip_ordering) + .collect::>() + .to_vec(); + + let prove_shard_start = Instant::now(); + + let proof = LocalProver::prove_shard( + config, + &pk, + &ordered_chips, + shard_data, + &mut request_data.challenger.clone(), + ); + + log::debug!("Prove shard took {:?}", prove_shard_start.elapsed()); + + proof + }) + .collect::>(); + + shard_proofs.append(&mut proofs); + + log::info!("Proving shards took {:?}", prove_partial_start.elapsed()); + + return shard_proofs; +} diff --git a/provers/sp1/driver/src/distributed/worker/envelope.rs b/provers/sp1/driver/src/distributed/worker/envelope.rs new file mode 100644 index 000000000..444c1e85c --- /dev/null +++ b/provers/sp1/driver/src/distributed/worker/envelope.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; + +use crate::WorkerProtocol; + +#[derive(Debug, Serialize, Deserialize)] +pub struct WorkerEnvelope { + pub magic: u64, + pub data: WorkerProtocol, +} + +impl From for WorkerEnvelope { + fn from(data: WorkerProtocol) -> Self { + WorkerEnvelope { + magic: 0xdeadbeef, + data, + } + } +} diff --git a/provers/sp1/driver/src/distributed/worker/mod.rs b/provers/sp1/driver/src/distributed/worker/mod.rs new file mode 100644 index 000000000..898ab648c --- /dev/null +++ b/provers/sp1/driver/src/distributed/worker/mod.rs @@ -0,0 +1,7 @@ +mod envelope; +mod protocol; +mod socket; + +pub use envelope::WorkerEnvelope; +pub use protocol::WorkerProtocol; +pub use socket::WorkerSocket; diff --git a/provers/sp1/driver/src/distributed/worker/protocol.rs b/provers/sp1/driver/src/distributed/worker/protocol.rs new file mode 100644 index 000000000..fcaaecd57 --- /dev/null +++ b/provers/sp1/driver/src/distributed/worker/protocol.rs @@ -0,0 +1,25 @@ +use std::fmt::{Display, Formatter}; + +use serde::{Deserialize, Serialize}; +use sp1_core::{stark::ShardProof, utils::BabyBearPoseidon2}; + +use crate::PartialProofRequest; + +#[derive(Debug, Serialize, Deserialize)] +pub enum WorkerProtocol { + Ping, + Pong, + PartialProofRequest(PartialProofRequest), + PartialProofResponse(Vec>), +} + +impl Display for WorkerProtocol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + WorkerProtocol::Ping => write!(f, "Ping"), + WorkerProtocol::Pong => write!(f, "Pong"), + WorkerProtocol::PartialProofRequest(_) => write!(f, "PartialProofRequest"), + WorkerProtocol::PartialProofResponse(_) => write!(f, "PartialProofResponse"), + } + } +} diff --git a/provers/sp1/driver/src/distributed/worker/socket.rs b/provers/sp1/driver/src/distributed/worker/socket.rs new file mode 100644 index 000000000..da64e3a6f --- /dev/null +++ b/provers/sp1/driver/src/distributed/worker/socket.rs @@ -0,0 +1,118 @@ +use raiko_lib::prover::WorkerError; +use sp1_core::{stark::ShardProof, utils::BabyBearPoseidon2}; +use tokio::io::{AsyncReadExt, AsyncWriteExt, BufWriter}; + +use crate::{PartialProofRequest, WorkerEnvelope, WorkerProtocol}; + +// 64MB +const PAYLOAD_MAX_SIZE: usize = 1 << 26; + +pub struct WorkerSocket { + pub socket: tokio::net::TcpStream, +} + +impl WorkerSocket { + pub async fn connect(url: &str) -> Result { + let stream = tokio::net::TcpStream::connect(url).await?; + + Ok(WorkerSocket { socket: stream }) + } + + pub fn new(socket: tokio::net::TcpStream) -> Self { + WorkerSocket { socket } + } + + pub async fn send(&mut self, packet: WorkerProtocol) -> Result<(), WorkerError> { + let envelope: WorkerEnvelope = packet.into(); + + let data = bincode::serialize(&envelope)?; + + if data.len() > PAYLOAD_MAX_SIZE { + return Err(WorkerError::PayloadTooBig); + } + + self.socket.write_u64(data.len() as u64).await?; + self.socket.write_all(&data).await?; + + Ok(()) + } + + pub async fn receive(&mut self) -> Result { + let data = self.read_data().await?; + + let envelope: WorkerEnvelope = bincode::deserialize(&data)?; + + if envelope.magic != 0xdeadbeef { + return Err(WorkerError::InvalidMagicNumber); + } + + Ok(envelope.data) + } + + // TODO: Add a timeout + pub async fn read_data(&mut self) -> Result, WorkerError> { + let size = self.socket.read_u64().await? as usize; + + if size > PAYLOAD_MAX_SIZE { + return Err(WorkerError::PayloadTooBig); + } + + let mut data = Vec::new(); + + let mut buf_data = BufWriter::new(&mut data); + let mut buf = [0; 1024]; + let mut total_read = 0; + + loop { + match self.socket.read(&mut buf).await { + // socket closed + Ok(n) if n == 0 => return Ok(data), + Ok(n) => { + buf_data.write_all(&buf[..n]).await?; + + total_read += n; + + if total_read == size { + buf_data.flush().await?; + + return Ok(data); + } + + // TODO: handle the case where the data is bigger than expected + } + Err(e) => { + log::error!("failed to read from socket; err = {:?}", e); + + return Err(e.into()); + } + }; + } + } + + pub async fn ping(&mut self) -> Result<(), WorkerError> { + self.send(WorkerProtocol::Ping).await?; + + let response = self.receive().await?; + + match response { + WorkerProtocol::Pong => Ok(()), + _ => Err(WorkerError::InvalidResponse), + } + } + + pub async fn partial_proof_request( + &mut self, + request: PartialProofRequest, + ) -> Result>, WorkerError> { + self.send(WorkerProtocol::PartialProofRequest(request)) + .await?; + + let response = self.receive().await?; + + if let WorkerProtocol::PartialProofResponse(partial_proofs) = response { + Ok(partial_proofs) + } else { + Err(WorkerError::InvalidResponse) + } + } +} diff --git a/provers/sp1/driver/src/lib.rs b/provers/sp1/driver/src/lib.rs index 1ea6b507c..5f1f9bd67 100644 --- a/provers/sp1/driver/src/lib.rs +++ b/provers/sp1/driver/src/lib.rs @@ -1,11 +1,15 @@ #![cfg(feature = "enable")] -use raiko_lib::{ - input::{GuestInput, GuestOutput}, - prover::{to_proof, Proof, Prover, ProverConfig, ProverResult}, -}; + use serde::{Deserialize, Serialize}; -use sp1_sdk::{ProverClient, SP1Stdin}; -use std::env; + +mod distributed; +mod local; + +pub use distributed::{ + PartialProofRequest, Sp1DistributedProver, WorkerEnvelope, WorkerProtocol, WorkerSocket, +}; + +pub use local::Sp1Prover; const ELF: &[u8] = include_bytes!("../../guest/elf/sp1-guest"); @@ -13,62 +17,3 @@ const ELF: &[u8] = include_bytes!("../../guest/elf/sp1-guest"); pub struct Sp1Response { pub proof: String, } - -pub struct Sp1Prover; - -impl Prover for Sp1Prover { - async fn run( - input: GuestInput, - _output: &GuestOutput, - _config: &ProverConfig, - ) -> ProverResult { - // Write the input. - let mut stdin = SP1Stdin::new(); - stdin.write(&input); - - // Generate the proof for the given program. - let client = ProverClient::new(); - let (pk, vk) = client.setup(ELF); - let proof = client.prove(&pk, stdin).expect("Sp1: proving failed"); - - // Verify proof. - client - .verify(&proof, &vk) - .expect("Sp1: verification failed"); - - // Save the proof. - let proof_dir = env::current_dir().expect("Sp1: dir error"); - proof - .save( - proof_dir - .as_path() - .join("proof-with-io.json") - .to_str() - .unwrap(), - ) - .expect("Sp1: saving proof failed"); - - println!("successfully generated and verified proof for the program!"); - to_proof(Ok(Sp1Response { - proof: serde_json::to_string(&proof).unwrap(), - })) - } -} - -#[cfg(test)] -mod test { - use super::*; - const TEST_ELF: &[u8] = include_bytes!("../../guest/elf/test-sp1-guest"); - - #[test] - fn run_unittest_elf() { - // TODO(Cecilia): imple GuestInput::mock() for unit test - let client = ProverClient::new(); - let stdin = SP1Stdin::new(); - let (pk, vk) = client.setup(TEST_ELF); - let proof = client.prove(&pk, stdin).expect("Sp1: proving failed"); - client - .verify(&proof, &vk) - .expect("Sp1: verification failed"); - } -} diff --git a/provers/sp1/driver/src/local.rs b/provers/sp1/driver/src/local.rs new file mode 100644 index 000000000..378ccf553 --- /dev/null +++ b/provers/sp1/driver/src/local.rs @@ -0,0 +1,68 @@ +use std::env; + +use raiko_lib::{ + input::{GuestInput, GuestOutput}, + prover::{to_proof, Proof, Prover, ProverConfig, ProverResult}, +}; +use sp1_sdk::{ProverClient, SP1Stdin}; + +use crate::{Sp1Response, ELF}; + +pub struct Sp1Prover; + +impl Prover for Sp1Prover { + async fn run( + input: GuestInput, + _output: &GuestOutput, + _config: &ProverConfig, + ) -> ProverResult { + // Write the input. + let mut stdin = SP1Stdin::new(); + stdin.write(&input); + + // Generate the proof for the given program. + let client = ProverClient::new(); + let (pk, vk) = client.setup(ELF); + let proof = client.prove(&pk, stdin).expect("Sp1: proving failed"); + + // Verify proof. + client + .verify(&proof, &vk) + .expect("Sp1: verification failed"); + + // Save the proof. + let proof_dir = env::current_dir().expect("Sp1: dir error"); + proof + .save( + proof_dir + .as_path() + .join("proof-with-io.json") + .to_str() + .unwrap(), + ) + .expect("Sp1: saving proof failed"); + + println!("successfully generated and verified proof for the program!"); + to_proof(Ok(Sp1Response { + proof: serde_json::to_string(&proof).unwrap(), + })) + } +} + +#[cfg(test)] +mod test { + use super::*; + const TEST_ELF: &[u8] = include_bytes!("../../guest/elf/test-sp1-guest"); + + #[test] + fn run_unittest_elf() { + // TODO(Cecilia): imple GuestInput::mock() for unit test + let client = ProverClient::new(); + let stdin = SP1Stdin::new(); + let (pk, vk) = client.setup(TEST_ELF); + let proof = client.prove(&pk, stdin).expect("Sp1: proving failed"); + client + .verify(&proof, &vk) + .expect("Sp1: verification failed"); + } +} diff --git a/provers/sp1/guest/elf/sp1-guest b/provers/sp1/guest/elf/sp1-guest index 7aac97bb6..01a83233b 100755 Binary files a/provers/sp1/guest/elf/sp1-guest and b/provers/sp1/guest/elf/sp1-guest differ diff --git a/script/build.sh b/script/build.sh index 69eaafe56..f909acd9c 100755 --- a/script/build.sh +++ b/script/build.sh @@ -150,8 +150,13 @@ if [ -z "$1" ] || [ "$1" == "sp1" ]; then cargo ${TOOLCHAIN_SP1} build ${FLAGS} --features sp1 else if [ -z "${TEST}" ]; then + if [ -n "$ORCHESTRATOR" ]; then + export ARGS="--orchestrator-address $ORCHESTRATOR" + echo "Running in worker mode with orchestrator address $ORCHESTRATOR" + fi + echo "Running Sp1 prover" - cargo ${TOOLCHAIN_SP1} run ${FLAGS} --features sp1 + cargo ${TOOLCHAIN_SP1} run ${FLAGS} --features sp1 -- ${ARGS} else echo "Running Sp1 tests" cargo ${TOOLCHAIN_SP1} test ${FLAGS} --lib sp1-driver --features sp1 -- run_unittest_elf diff --git a/script/prove-block.sh b/script/prove-block.sh index 6a2cc2923..0fbf6d53f 100755 --- a/script/prove-block.sh +++ b/script/prove-block.sh @@ -48,6 +48,10 @@ elif [ "$proof" == "sp1" ]; then proofParam=' "proof_type": "sp1" ' +elif [ "$proof" == "sp1_distributed" ]; then + proofParam=' + "proof_type": "sp1_distributed" + ' elif [ "$proof" == "sgx" ]; then proofParam=' "proof_type": "sgx",