From 4eb49c3fa6d00b834aa20a668b99022d7828d9ff Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sun, 12 Apr 2026 19:41:00 +0200 Subject: [PATCH 01/26] chkpt --- Cargo.toml | 3 ++- src/bin/main.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 926d0cdd..f6716d73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ serde_json = "1.0" spongefish = { git = "https://github.com/z-tech/spongefish", rev = "2613967", features = ["ark-ff"]} rayon = { version = "1.10", optional = true } tracing = { version = "0.1", features = ["attributes"], optional = true } +tracing-subscriber = { version = "0.3.22", features = ["env-filter"], optional = true } hex = "0.4" static_assertions = "1.1.0" ciborium = "0.2" @@ -73,7 +74,7 @@ verifier_panics = [] parallel = ["dep:rayon"] rayon = ["dep:rayon"] asm = ["ark-ff/asm"] -tracing = ["dep:tracing"] +tracing = ["dep:tracing", "dep:tracing-subscriber"] # Do not permute evaluation pointsin RS # This flag is to be removed after whir_zk supports it. rs_in_order = [] diff --git a/src/bin/main.rs b/src/bin/main.rs index 92933f30..e979a42b 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -63,6 +63,18 @@ struct Args { } fn main() { + #[cfg(feature = "tracing")] + { + use tracing_subscriber::{fmt, fmt::format::FmtSpan, EnvFilter}; + + let filter = + EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + fmt() + .with_env_filter(filter) + .with_span_events(FmtSpan::CLOSE) + .init(); + } + use AvailableFields as AF; let args = Args::parse(); let field = args.field; From 5cf31fc522e747a38f8beb640048ea094b5b63b8 Mon Sep 17 00:00:00 2001 From: EC2 Default User Date: Sun, 12 Apr 2026 19:46:26 +0000 Subject: [PATCH 02/26] bench --- .cargo/config.toml | 2 + Cargo.lock | 71 +++++++++++++++++++++++++- Cargo.toml | 8 +++ benches/sumcheck.rs | 105 ++++++++++++++++++++++++++++++++++---- src/protocols/sumcheck.rs | 49 ++++++++++++++---- 5 files changed, 214 insertions(+), 21 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..ddff4407 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "target-cpu=native"] diff --git a/Cargo.lock b/Cargo.lock index b1eb8332..237f3788 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -11,6 +23,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -98,6 +116,7 @@ dependencies = [ "educe", "num-bigint", "num-traits", + "rayon", "zeroize", ] @@ -122,6 +141,21 @@ dependencies = [ "syn", ] +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "git+https://github.com/arkworks-rs/algebra?branch=z-tech%2Fmacro_auto_detect_subgroup#2644053e2fe913b0aba2c89d1fcd8277dbb826e4" +dependencies = [ + "ahash", + "ark-ff", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.16.1", + "rayon", +] + [[package]] name = "ark-serialize" version = "0.5.0" @@ -131,6 +165,7 @@ dependencies = [ "ark-std", "digest", "num-bigint", + "rayon", "serde_with", ] @@ -151,6 +186,7 @@ source = "git+https://github.com/arkworks-rs/std#1693bc56d2ca6657b623f33a3f0b009 dependencies = [ "num-traits", "rand 0.8.5", + "rayon", ] [[package]] @@ -542,6 +578,21 @@ dependencies = [ "syn", ] +[[package]] +name = "efficient-sumcheck" +version = "0.0.2" +source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#3e614f916a28c0b13d110ae14a57df42f30a242c" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "memmap2", + "nohash-hasher", + "rayon", + "spongefish", +] + [[package]] name = "either" version = "1.15.0" @@ -691,6 +742,9 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", +] [[package]] name = "heck" @@ -857,6 +911,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + [[package]] name = "nix" version = "0.31.2" @@ -869,6 +932,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -1553,7 +1622,6 @@ dependencies = [ [[package]] name = "spongefish" version = "0.4.0" -source = "git+https://github.com/z-tech/spongefish?rev=2613967#2613967409998dc4f81ac6f0c1799456f7878b82" dependencies = [ "ark-ff", "ark-serialize", @@ -1943,6 +2011,7 @@ dependencies = [ "const-oid", "derive-where", "digest", + "efficient-sumcheck", "hex", "hex-literal", "ordered-float", diff --git a/Cargo.toml b/Cargo.toml index f6716d73..eb8b5ff4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ clap = { version = "4.4", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" spongefish = { git = "https://github.com/z-tech/spongefish", rev = "2613967", features = ["ark-ff"]} +efficient-sumcheck = { git = "https://github.com/compsec-epfl/efficient-sumcheck.git", branch = "z-tech/simd_goldilocks_experimental", default-features = false, features = ["parallel"] } rayon = { version = "1.10", optional = true } tracing = { version = "0.1", features = ["attributes"], optional = true } tracing-subscriber = { version = "0.3.22", features = ["env-filter"], optional = true } @@ -110,3 +111,10 @@ opt-level = 3 ark-ff = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/macro_auto_detect_subgroup" } ark-std = { git = "https://github.com/arkworks-rs/std" } ark-serialize = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/macro_auto_detect_subgroup" } +ark-poly = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/macro_auto_detect_subgroup" } + +# Force effsc's spongefish (branch smallfp-support, newer tip) to the exact rev whir uses (2613967), +# which predates an incompatibility with the newer ark-ff API. Uses a local path to satisfy cargo's +# "patches must point to different sources" rule. +[patch."https://github.com/z-tech/spongefish.git"] +spongefish = { path = "/tmp/spongefish-local/spongefish" } diff --git a/benches/sumcheck.rs b/benches/sumcheck.rs index 056e4787..869fe1ac 100644 --- a/benches/sumcheck.rs +++ b/benches/sumcheck.rs @@ -1,6 +1,9 @@ use divan::{black_box, AllocProfiler, Bencher}; +use efficient_sumcheck::{ + order_strategy::MSBOrder, simd_ops as effsc_simd, streams::reorder_vec, +}; use whir::algebra::{ - fields::Field64 as F, + fields::{Field64 as G1, Field64_2 as G2, Field64_3 as G3}, sumcheck::{compute_sumcheck_polynomial, fold}, }; @@ -9,20 +12,102 @@ static ALLOC: AllocProfiler = AllocProfiler::system(); const SIZES: &[u64] = &[1 << 16, 1 << 18, 1 << 20]; +// ── Whir baseline kernel: compute_sumcheck_polynomial + fold ─────────────── + +#[divan::bench(args = SIZES)] +fn whir_g1(bencher: Bencher, size: u64) { + run_whir::(bencher, size); +} +#[divan::bench(args = SIZES)] +fn whir_g2(bencher: Bencher, size: u64) { + run_whir::(bencher, size); +} #[divan::bench(args = SIZES)] -fn sumcheck_first_round(bencher: Bencher, size: u64) { +fn whir_g3(bencher: Bencher, size: u64) { + run_whir::(bencher, size); +} + +fn run_whir>(bencher: Bencher, size: u64) { bencher .with_inputs(|| { - // Reset everything on each iteration - let a = (0..size).map(F::from).collect::>(); - let b = (0..size).map(F::from).collect::>(); - let folding_randomness = F::from(42); - (a, b, folding_randomness) + let a: Vec = (0..size).map(F::from).collect(); + let b: Vec = (0..size).map(F::from).collect(); + let r = F::from(42); + (a, b, r) }) - .bench_values(|(mut a, mut b, folding_randomness)| { + .bench_values(|(mut a, mut b, r)| { let poly = compute_sumcheck_polynomial(&a, &b); - fold(&mut a, folding_randomness); - fold(&mut b, folding_randomness); + fold(&mut a, r); + fold(&mut b, r); + black_box((poly, a, b)) + }); +} + +// ── effsc SIMD path: reorder + pairwise_product_sum + fold ───────────────── +// Includes the bit-reversal permutation cost on the first round. + +#[divan::bench(args = SIZES)] +fn effsc_g1(bencher: Bencher, size: u64) { + run_effsc::(bencher, size); +} +#[divan::bench(args = SIZES)] +fn effsc_g2(bencher: Bencher, size: u64) { + run_effsc::(bencher, size); +} +#[divan::bench(args = SIZES)] +fn effsc_g3(bencher: Bencher, size: u64) { + run_effsc::(bencher, size); +} + +fn run_effsc>(bencher: Bencher, size: u64) { + bencher + .with_inputs(|| { + let a: Vec = (0..size).map(F::from).collect(); + let b: Vec = (0..size).map(F::from).collect(); + let r = F::from(42); + (a, b, r) + }) + .bench_values(|(a, b, r)| { + // Bit-reverse to LSB-first so effsc's adjacent-pair kernels + // bind whir's x_0, x_1, ... in order. + let mut a = reorder_vec::(a); + let mut b = reorder_vec::(b); + let poly = effsc_simd::pairwise_product_sum(&a, &b); + effsc_simd::fold(&mut a, r); + effsc_simd::fold(&mut b, r); + black_box((poly, a, b)) + }); +} + +// ── effsc SIMD path WITHOUT the entry permutation ────────────────────────── +// Isolates the kernel speedup from the permutation overhead, simulating +// mid-sumcheck rounds where the data is already in LSB-first layout. + +#[divan::bench(args = SIZES)] +fn effsc_nopermute_g1(bencher: Bencher, size: u64) { + run_effsc_nopermute::(bencher, size); +} +#[divan::bench(args = SIZES)] +fn effsc_nopermute_g2(bencher: Bencher, size: u64) { + run_effsc_nopermute::(bencher, size); +} +#[divan::bench(args = SIZES)] +fn effsc_nopermute_g3(bencher: Bencher, size: u64) { + run_effsc_nopermute::(bencher, size); +} + +fn run_effsc_nopermute>(bencher: Bencher, size: u64) { + bencher + .with_inputs(|| { + let a: Vec = (0..size).map(F::from).collect(); + let b: Vec = (0..size).map(F::from).collect(); + let r = F::from(42); + (a, b, r) + }) + .bench_values(|(mut a, mut b, r)| { + let poly = effsc_simd::pairwise_product_sum(&a, &b); + effsc_simd::fold(&mut a, r); + effsc_simd::fold(&mut b, r); black_box((poly, a, b)) }); } diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 2a82c517..0fd79218 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -4,16 +4,15 @@ use std::fmt; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; +use efficient_sumcheck::{ + order_strategy::MSBOrder, simd_ops as effsc_simd, streams::reorder_vec, +}; use serde::{Deserialize, Serialize}; #[cfg(feature = "tracing")] use tracing::instrument; use crate::{ - algebra::{ - dot, - sumcheck::{compute_sumcheck_polynomial, fold}, - MultilinearPoint, - }, + algebra::{dot, MultilinearPoint}, protocols::proof_of_work, transcript::{ codecs::U64, Codec, Decoding, DuplexSpongeInterface, ProverState, VerificationResult, @@ -79,10 +78,34 @@ impl Config { debug_assert_eq!(dot(a, b), *sum); let mut res = Vec::with_capacity(self.num_rounds); + if self.num_rounds == 0 { + return MultilinearPoint(res); + } + + // Pad to next power of two (zero extension preserves the sum). + let padded = self.initial_size.next_power_of_two(); + if padded > self.initial_size { + a.resize(padded, F::ZERO); + b.resize(padded, F::ZERO); + } + + // Bit-reverse to convert whir's MSB-indexed layout into the LSB-indexed + // (ark-poly / efficient-sumcheck) layout expected by the SIMD kernels. + // After this, adjacent pairs correspond to whir's (low, high) halves, so + // effsc's LSB-first fold binds variables in whir's x_0, x_1, ... order. + if padded > 1 { + *a = reorder_vec::(std::mem::take(a)); + *b = reorder_vec::(std::mem::take(b)); + } + for _ in 0..self.num_rounds { debug_assert!(a.len() > 1); - // Send sumcheck polynomial c0 and c2 - let (c0, c2) = compute_sumcheck_polynomial(a, b); + // effsc returns (c_const, c_linear) of the round poly q(X) in the + // reordered (LSB-first) pairing. c_const = c0 (matches whir's c0); + // c_linear relates to whir's c2 via q(0) + q(1) = claim: + // c2 = claim - c_linear + let (c0, lin) = effsc_simd::pairwise_product_sum(a, b); + let c2 = *sum - lin; let c1 = *sum - c0.double() - c2; prover_state.prover_message(&c0); prover_state.prover_message(&c2); @@ -94,12 +117,18 @@ impl Config { let folding_randomness = prover_state.verifier_message::(); res.push(folding_randomness); - // Fold the inputs - fold(a, folding_randomness); - fold(b, folding_randomness); + // SIMD-accelerated fold (halves length in place). + effsc_simd::fold(a, folding_randomness); + effsc_simd::fold(b, folding_randomness); *sum = (c2 * folding_randomness + c1) * folding_randomness + c0; } + // Restore whir's MSB-indexed layout for downstream consumers. + if a.len() > 1 { + *a = reorder_vec::(std::mem::take(a)); + *b = reorder_vec::(std::mem::take(b)); + } + MultilinearPoint(res) } From 13158f2a6c43cfcd1b1c5448f94695052bcf46dc Mon Sep 17 00:00:00 2001 From: EC2 Default User Date: Tue, 14 Apr 2026 09:20:20 +0000 Subject: [PATCH 03/26] chkpt --- Cargo.lock | 2 +- proptest-regressions/protocols/sumcheck.txt | 7 ++ src/protocols/sumcheck.rs | 102 ++++++++++---------- 3 files changed, 59 insertions(+), 52 deletions(-) create mode 100644 proptest-regressions/protocols/sumcheck.txt diff --git a/Cargo.lock b/Cargo.lock index 237f3788..3416c93c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -581,7 +581,7 @@ dependencies = [ [[package]] name = "efficient-sumcheck" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#3e614f916a28c0b13d110ae14a57df42f30a242c" +source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#432744c21535ca6cb5f9efe5b8b63d132f1e427e" dependencies = [ "ark-ff", "ark-poly", diff --git a/proptest-regressions/protocols/sumcheck.txt b/proptest-regressions/protocols/sumcheck.txt new file mode 100644 index 00000000..72bfbeb6 --- /dev/null +++ b/proptest-regressions/protocols/sumcheck.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 15c34319c1d5d357f51a76e80909f309313ba4e0a317976aa4c9188e6ec7368a # shrinks to seed = 0, config = Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 2, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 1 } diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 0fd79218..3d96f3ed 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -5,9 +5,11 @@ use std::fmt; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; use efficient_sumcheck::{ - order_strategy::MSBOrder, simd_ops as effsc_simd, streams::reorder_vec, + inner_product_sumcheck_partial_with_hook, order_strategy::MSBOrder, streams::reorder_vec, + transcript::Transcript as EffscTranscript, }; use serde::{Deserialize, Serialize}; +use spongefish::NargSerialize; #[cfg(feature = "tracing")] use tracing::instrument; @@ -21,6 +23,32 @@ use crate::{ type_info::Type, }; +#[cfg_attr(feature = "tracing", instrument(skip_all, fields(len = a.len())))] +fn reorder_in(a: &mut Vec, b: &mut Vec) { + *a = reorder_vec::(std::mem::take(a)); + *b = reorder_vec::(std::mem::take(b)); +} + +#[cfg_attr(feature = "tracing", instrument(skip_all, fields(len = a.len())))] +fn reorder_out(a: &mut Vec, b: &mut Vec) { + *a = reorder_vec::(std::mem::take(a)); + *b = reorder_vec::(std::mem::take(b)); +} + +impl EffscTranscript for ProverState +where + H: DuplexSpongeInterface, + R: RngCore + CryptoRng, + F: Codec<[H::U]> + NargSerialize, +{ + fn read(&mut self) -> F { + self.verifier_message::() + } + fn write(&mut self, value: F) { + self.prover_message(&value); + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(bound = "")] pub struct Config @@ -66,7 +94,7 @@ impl Config { where H: DuplexSpongeInterface, R: CryptoRng + RngCore, - F: Codec<[H::U]>, + F: Codec<[H::U]> + NargSerialize, [u8; 32]: Decoding<[H::U]>, U64: Codec<[H::U]>, { @@ -77,59 +105,36 @@ impl Config { assert_eq!(b.len(), self.initial_size); debug_assert_eq!(dot(a, b), *sum); - let mut res = Vec::with_capacity(self.num_rounds); if self.num_rounds == 0 { - return MultilinearPoint(res); + return MultilinearPoint(Vec::new()); } - // Pad to next power of two (zero extension preserves the sum). let padded = self.initial_size.next_power_of_two(); if padded > self.initial_size { a.resize(padded, F::ZERO); b.resize(padded, F::ZERO); } - - // Bit-reverse to convert whir's MSB-indexed layout into the LSB-indexed - // (ark-poly / efficient-sumcheck) layout expected by the SIMD kernels. - // After this, adjacent pairs correspond to whir's (low, high) halves, so - // effsc's LSB-first fold binds variables in whir's x_0, x_1, ... order. if padded > 1 { - *a = reorder_vec::(std::mem::take(a)); - *b = reorder_vec::(std::mem::take(b)); + reorder_in(a, b); } - for _ in 0..self.num_rounds { - debug_assert!(a.len() > 1); - // effsc returns (c_const, c_linear) of the round poly q(X) in the - // reordered (LSB-first) pairing. c_const = c0 (matches whir's c0); - // c_linear relates to whir's c2 via q(0) + q(1) = claim: - // c2 = claim - c_linear - let (c0, lin) = effsc_simd::pairwise_product_sum(a, b); - let c2 = *sum - lin; - let c1 = *sum - c0.double() - c2; - prover_state.prover_message(&c0); - prover_state.prover_message(&c2); - - // Do Proof of Work (if any) - self.round_pow.prove(prover_state); - - // Receive the random evaluation point - let folding_randomness = prover_state.verifier_message::(); - res.push(folding_randomness); - - // SIMD-accelerated fold (halves length in place). - effsc_simd::fold(a, folding_randomness); - effsc_simd::fold(b, folding_randomness); - *sum = (c2 * folding_randomness + c1) * folding_randomness + c0; - } + let result = inner_product_sumcheck_partial_with_hook( + a, + b, + prover_state, + self.num_rounds, + |_, t| self.round_pow.prove(t), + ); - // Restore whir's MSB-indexed layout for downstream consumers. - if a.len() > 1 { - *a = reorder_vec::(std::mem::take(a)); - *b = reorder_vec::(std::mem::take(b)); + if a.len() == 1 { + let (final_a, final_b) = result.final_evaluations; + *sum = final_a * final_b; + } else { + reorder_out(a, b); + *sum = dot(a, b); } - MultilinearPoint(res) + MultilinearPoint(result.verifier_messages) } #[cfg_attr(feature = "tracing", instrument(skip_all))] @@ -149,20 +154,15 @@ impl Config { ); let mut res = Vec::with_capacity(self.num_rounds); for _ in 0..self.num_rounds { - // Receive sumcheck polynomial c0 and c2 - let c0: F = verifier_state.prover_message()?; - let c2: F = verifier_state.prover_message()?; - let c1 = *sum - c0.double() - c2; + let a: F = verifier_state.prover_message()?; + let b: F = verifier_state.prover_message()?; - // Check proof of work (if any) self.round_pow.verify(verifier_state)?; - // Receive the random evaluation point - let folding_randomness = verifier_state.verifier_message::(); - res.push(folding_randomness); + let r = verifier_state.verifier_message::(); + res.push(r); - // Update the sum - *sum = (c2 * folding_randomness + c1) * folding_randomness + c0; + *sum = a + (b - a.double()) * r + (*sum - b) * r.square(); } Ok(MultilinearPoint(res)) From a9964f6606dc333baa102ed5eb38050079449ff9 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Tue, 14 Apr 2026 14:10:16 +0200 Subject: [PATCH 04/26] chkpt --- Cargo.toml | 2 +- src/protocols/sumcheck.rs | 26 ++++++++++++++++++++++++-- src/protocols/whir/prover.rs | 14 +++++++------- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eb8b5ff4..02fb78b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -117,4 +117,4 @@ ark-poly = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/ma # which predates an incompatibility with the newer ark-ff API. Uses a local path to satisfy cargo's # "patches must point to different sources" rule. [patch."https://github.com/z-tech/spongefish.git"] -spongefish = { path = "/tmp/spongefish-local/spongefish" } +spongefish = { path = "/tmp/spongefish-local/spongefish/spongefish" } diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 3d96f3ed..65116170 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -5,8 +5,8 @@ use std::fmt; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; use efficient_sumcheck::{ - inner_product_sumcheck_partial_with_hook, order_strategy::MSBOrder, streams::reorder_vec, - transcript::Transcript as EffscTranscript, + inner_product_sumcheck_partial_with_hook, order_strategy::MSBOrder, simd_ops, + streams::reorder_vec, transcript::Transcript as EffscTranscript, }; use serde::{Deserialize, Serialize}; use spongefish::NargSerialize; @@ -35,6 +35,28 @@ fn reorder_out(a: &mut Vec, b: &mut Vec) { *b = reorder_vec::(std::mem::take(b)); } +/// Sequentially folds a single vector by a list of challenges, using +/// efficient-sumcheck's SIMD-dispatched `fold` (falls back to generic rayon +/// when SIMD doesn't apply). Handles LSB<->MSB ordering and zero-padding to +/// match WHIR's `algebra::sumcheck::fold` semantics. +#[cfg_attr(feature = "tracing", instrument(skip_all, fields(len = values.len(), rounds = challenges.len())))] +pub fn multilinear_fold(values: &mut Vec, challenges: &[F]) { + if challenges.is_empty() || values.len() <= 1 { + return; + } + let padded = values.len().next_power_of_two(); + if padded > values.len() { + values.resize(padded, F::ZERO); + } + *values = reorder_vec::(std::mem::take(values)); + for &c in challenges { + simd_ops::fold(values, c); + } + if values.len() > 1 { + *values = reorder_vec::(std::mem::take(values)); + } +} + impl EffscTranscript for ProverState where H: DuplexSpongeInterface, diff --git a/src/protocols/whir/prover.rs b/src/protocols/whir/prover.rs index 2a463596..66107f94 100644 --- a/src/protocols/whir/prover.rs +++ b/src/protocols/whir/prover.rs @@ -13,11 +13,13 @@ use crate::{ lift, linear_form::{Covector, Evaluate, LinearForm, UnivariateEvaluation}, mixed_scalar_mul_add, - sumcheck::fold, tensor_product, MultilinearPoint, }, hash::Hash, - protocols::{geometric_challenge::geometric_challenge, irs_commit, whir::FinalClaim}, + protocols::{ + geometric_challenge::geometric_challenge, irs_commit, sumcheck::multilinear_fold, + whir::FinalClaim, + }, transcript::{ codecs::U64, Codec, Decoding, DuplexSpongeInterface, ProverMessage, ProverState, VerifierMessage, @@ -207,14 +209,12 @@ where // There are no constraints yet, so we can skip the sumcheck. // (If we did run it, all sumcheck vectors would be constant zero) // TODO: Don't compute evaluations and constraints in the first place. - let folding_randomness = (0..self.initial_sumcheck.num_rounds) + let folding_randomness: Vec = (0..self.initial_sumcheck.num_rounds) .map(|_| prover_state.verifier_message()) .collect(); self.initial_skip_pow.prove(prover_state); - // Fold vector - for &f in &folding_randomness { - fold(&mut vector, f); - } + // Fold vector using effsc's SIMD-dispatched fold + multilinear_fold(&mut vector, &folding_randomness); // Covector must be all zeros. covector = vec![M::Target::ZERO; self.initial_sumcheck.final_size()]; MultilinearPoint(folding_randomness) From bb2b4b7f45d91d3575cf361c211c3300e08398e0 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Tue, 14 Apr 2026 16:58:45 +0200 Subject: [PATCH 05/26] chkpt --- Cargo.lock | 127 ++++++++++++++++++++++++++++++++++++++++++++--------- Cargo.toml | 7 +-- 2 files changed, 107 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3416c93c..12f5cca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,7 +112,7 @@ dependencies = [ "ark-ff-macros", "ark-serialize", "ark-std", - "digest", + "digest 0.10.7", "educe", "num-bigint", "num-traits", @@ -163,7 +163,7 @@ source = "git+https://github.com/arkworks-rs/algebra?branch=z-tech%2Fmacro_auto_ dependencies = [ "ark-serialize-derive", "ark-std", - "digest", + "digest 0.10.7", "num-bigint", "rayon", "serde_with", @@ -245,8 +245,8 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", ] [[package]] @@ -258,6 +258,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -454,6 +463,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "constant_time_eq" version = "0.4.2" @@ -475,6 +490,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -516,6 +540,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + [[package]] name = "deranged" version = "0.5.8" @@ -543,12 +576,23 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.1", +] + [[package]] name = "divan-macros" version = "0.1.17" @@ -581,7 +625,7 @@ dependencies = [ [[package]] name = "efficient-sumcheck" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#432744c21535ca6cb5f9efe5b8b63d132f1e427e" +source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#b525d92e06b033a577b2c5574e06341ace178c62" dependencies = [ "ark-ff", "ark-poly", @@ -764,6 +808,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hybrid-array" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" +dependencies = [ + "typenum", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -854,7 +907,17 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", ] [[package]] @@ -1565,11 +1628,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", "sha2-asm", ] +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.2", +] + [[package]] name = "sha2-asm" version = "0.6.4" @@ -1585,8 +1659,18 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest", - "keccak", + "digest 0.10.7", + "keccak 0.1.6", +] + +[[package]] +name = "sha3" +version = "0.11.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b233a7d59d7bfc027208506a33ffc9532b2acb24ddc61fe7e758dc2250db431" +dependencies = [ + "digest 0.11.2", + "keccak 0.2.0", ] [[package]] @@ -1621,15 +1705,16 @@ dependencies = [ [[package]] name = "spongefish" -version = "0.4.0" +version = "0.6.0" +source = "git+https://github.com/z-tech/spongefish.git?branch=smallfp-support#865678da07c1f8100b7db550a42cbe768bb98ca3" dependencies = [ "ark-ff", "ark-serialize", - "digest", + "digest 0.11.2", "p3-koala-bear", "rand 0.8.5", - "sha2", - "sha3", + "sha2 0.11.0", + "sha3 0.11.0-rc.9", "zeroize", ] @@ -2008,9 +2093,9 @@ dependencies = [ "ciborium", "clap", "codspeed-divan-compat", - "const-oid", + "const-oid 0.9.6", "derive-where", - "digest", + "digest 0.10.7", "efficient-sumcheck", "hex", "hex-literal", @@ -2019,8 +2104,8 @@ dependencies = [ "rayon", "serde", "serde_json", - "sha2", - "sha3", + "sha2 0.10.9", + "sha3 0.10.8", "spongefish", "static_assertions", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 02fb78b6..d130eb8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ sha3 = { version = "0.10.7", features = ["asm", "oid"] } clap = { version = "4.4", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -spongefish = { git = "https://github.com/z-tech/spongefish", rev = "2613967", features = ["ark-ff"]} +spongefish = { git = "https://github.com/z-tech/spongefish.git", branch = "smallfp-support", features = ["ark-ff"]} efficient-sumcheck = { git = "https://github.com/compsec-epfl/efficient-sumcheck.git", branch = "z-tech/simd_goldilocks_experimental", default-features = false, features = ["parallel"] } rayon = { version = "1.10", optional = true } tracing = { version = "0.1", features = ["attributes"], optional = true } @@ -113,8 +113,3 @@ ark-std = { git = "https://github.com/arkworks-rs/std" } ark-serialize = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/macro_auto_detect_subgroup" } ark-poly = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/macro_auto_detect_subgroup" } -# Force effsc's spongefish (branch smallfp-support, newer tip) to the exact rev whir uses (2613967), -# which predates an incompatibility with the newer ark-ff API. Uses a local path to satisfy cargo's -# "patches must point to different sources" rule. -[patch."https://github.com/z-tech/spongefish.git"] -spongefish = { path = "/tmp/spongefish-local/spongefish/spongefish" } From cdf71cb8c1c1a43f7d4d80e31eb10cc3d3c40265 Mon Sep 17 00:00:00 2001 From: EC2 Default User Date: Wed, 15 Apr 2026 11:51:20 +0000 Subject: [PATCH 06/26] chkpt --- benches/sumcheck.rs | 2 +- src/protocols/sumcheck.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/benches/sumcheck.rs b/benches/sumcheck.rs index 869fe1ac..d8368684 100644 --- a/benches/sumcheck.rs +++ b/benches/sumcheck.rs @@ -10,7 +10,7 @@ use whir::algebra::{ #[global_allocator] static ALLOC: AllocProfiler = AllocProfiler::system(); -const SIZES: &[u64] = &[1 << 16, 1 << 18, 1 << 20]; +const SIZES: &[u64] = &[1 << 16, 1 << 18, 1 << 20, 1 << 22]; // ── Whir baseline kernel: compute_sumcheck_polynomial + fold ─────────────── diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 65116170..48c7ec6b 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -145,7 +145,11 @@ impl Config { b, prover_state, self.num_rounds, - |_, t| self.round_pow.prove(t), + |_, t| { + #[cfg(feature = "tracing")] + let _s = tracing::info_span!("round_pow_cb").entered(); + self.round_pow.prove(t) + }, ); if a.len() == 1 { From eb46c86a8d75a5faa68e239f4352ae7f19318522 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:03:28 +0200 Subject: [PATCH 07/26] z-tech/efficient_sumcheck --- Cargo.lock | 2 +- benches/sumcheck.rs | 4 +-- proptest-regressions/protocols/basecase.txt | 1 + proptest-regressions/protocols/sumcheck.txt | 1 + src/bin/main.rs | 3 +- src/protocols/sumcheck.rs | 37 ++++++++------------- src/protocols/whir/prover.rs | 3 +- 7 files changed, 20 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12f5cca4..24581083 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "efficient-sumcheck" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#b525d92e06b033a577b2c5574e06341ace178c62" +source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#a5f1aea9608844ee6480b72145e9d58aec5f6072" dependencies = [ "ark-ff", "ark-poly", diff --git a/benches/sumcheck.rs b/benches/sumcheck.rs index d8368684..4ee38fe7 100644 --- a/benches/sumcheck.rs +++ b/benches/sumcheck.rs @@ -1,7 +1,5 @@ use divan::{black_box, AllocProfiler, Bencher}; -use efficient_sumcheck::{ - order_strategy::MSBOrder, simd_ops as effsc_simd, streams::reorder_vec, -}; +use efficient_sumcheck::{order_strategy::MSBOrder, simd_ops as effsc_simd, streams::reorder_vec}; use whir::algebra::{ fields::{Field64 as G1, Field64_2 as G2, Field64_3 as G3}, sumcheck::{compute_sumcheck_polynomial, fold}, diff --git a/proptest-regressions/protocols/basecase.txt b/proptest-regressions/protocols/basecase.txt index b1160e5a..a461b183 100644 --- a/proptest-regressions/protocols/basecase.txt +++ b/proptest-regressions/protocols/basecase.txt @@ -5,3 +5,4 @@ # It is recommended to check this file in to source control so that # everyone who runs the test benefits from these saved cases. cc 6fd50adb2eacc5a44429f8aeb8bae55b4a05ae2ac74432e184fa91729f375276 # shrinks to seed = 0, config = Config { commit: Config { embedding: Identity { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 } }, num_vectors: 1, vector_size: 0, mask_length: 0, codeword_length: 1, interleaving_depth: 1, matrix_commit: Config { element_type: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, num_cols: 1, leaf_hash_id: 09459020f451874a1b399819d079632cc0f9263b1486c423173c6e15d8e2d61d, merkle_tree: Config { num_leaves: 1, layers: [] } }, johnson_slack: 0.0, in_domain_samples: 0, out_domain_samples: 0, deduplicate_in_domain: false }, sumcheck: Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 0, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 0 }, masked: false } +cc c9ce19b3d47d11843d0bc7136a3899d3d8a4ca0a22662d48b01edf704ec5301b # shrinks to seed = 0, config = Config { commit: Config { embedding: Identity { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 } }, num_vectors: 1, vector_size: 2, mask_length: 0, codeword_length: 2, interleaving_depth: 1, matrix_commit: Config { element_type: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, num_cols: 1, leaf_hash_id: 09459020f451874a1b399819d079632cc0f9263b1486c423173c6e15d8e2d61d, merkle_tree: Config { num_leaves: 2, layers: [LayerConfig { hash_id: 018eaa247cb8957ab1e9fdac885450403c5e7bda1acaaa504e4cc8f2f76bb076 }] } }, johnson_slack: 0.0, in_domain_samples: 0, out_domain_samples: 0, deduplicate_in_domain: false }, sumcheck: Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 2, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 1 }, masked: false } diff --git a/proptest-regressions/protocols/sumcheck.txt b/proptest-regressions/protocols/sumcheck.txt index 72bfbeb6..547c30ca 100644 --- a/proptest-regressions/protocols/sumcheck.txt +++ b/proptest-regressions/protocols/sumcheck.txt @@ -5,3 +5,4 @@ # It is recommended to check this file in to source control so that # everyone who runs the test benefits from these saved cases. cc 15c34319c1d5d357f51a76e80909f309313ba4e0a317976aa4c9188e6ec7368a # shrinks to seed = 0, config = Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 2, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 1 } +cc 8c18a2843ed1bba3f28eae7970bd8cf4ebe19d7e61a610b52e013abcae29da3b # shrinks to seed = 0, config = Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 2, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 1 } diff --git a/src/bin/main.rs b/src/bin/main.rs index e979a42b..d9d7a85f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -67,8 +67,7 @@ fn main() { { use tracing_subscriber::{fmt, fmt::format::FmtSpan, EnvFilter}; - let filter = - EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); fmt() .with_env_filter(filter) .with_span_events(FmtSpan::CLOSE) diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 48c7ec6b..39b045a6 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -4,6 +4,11 @@ use std::fmt; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; +// `inner_product_sumcheck_partial_with_hook` is half-split (folds top var +// first); `simd_ops::fold` is pair-split (folds bottom var first). WHIR is +// MSB-first, so the protocol calls the half-split kernel on lex-ordered +// data directly; `multilinear_fold` wraps the pair-split kernel in a +// bit-reversal sandwich to present MSB-first semantics. use efficient_sumcheck::{ inner_product_sumcheck_partial_with_hook, order_strategy::MSBOrder, simd_ops, streams::reorder_vec, transcript::Transcript as EffscTranscript, @@ -23,22 +28,11 @@ use crate::{ type_info::Type, }; -#[cfg_attr(feature = "tracing", instrument(skip_all, fields(len = a.len())))] -fn reorder_in(a: &mut Vec, b: &mut Vec) { - *a = reorder_vec::(std::mem::take(a)); - *b = reorder_vec::(std::mem::take(b)); -} - -#[cfg_attr(feature = "tracing", instrument(skip_all, fields(len = a.len())))] -fn reorder_out(a: &mut Vec, b: &mut Vec) { - *a = reorder_vec::(std::mem::take(a)); - *b = reorder_vec::(std::mem::take(b)); -} - -/// Sequentially folds a single vector by a list of challenges, using -/// efficient-sumcheck's SIMD-dispatched `fold` (falls back to generic rayon -/// when SIMD doesn't apply). Handles LSB<->MSB ordering and zero-padding to -/// match WHIR's `algebra::sumcheck::fold` semantics. +/// Sequentially folds a single vector by a list of challenges. +/// +/// Uses efficient-sumcheck's SIMD-dispatched `fold` (falls back to generic +/// rayon when SIMD doesn't apply). Handles LSB<->MSB ordering and +/// zero-padding to match WHIR's `algebra::sumcheck::fold` semantics. #[cfg_attr(feature = "tracing", instrument(skip_all, fields(len = values.len(), rounds = challenges.len())))] pub fn multilinear_fold(values: &mut Vec, challenges: &[F]) { if challenges.is_empty() || values.len() <= 1 { @@ -136,9 +130,6 @@ impl Config { a.resize(padded, F::ZERO); b.resize(padded, F::ZERO); } - if padded > 1 { - reorder_in(a, b); - } let result = inner_product_sumcheck_partial_with_hook( a, @@ -156,7 +147,6 @@ impl Config { let (final_a, final_b) = result.final_evaluations; *sum = final_a * final_b; } else { - reorder_out(a, b); *sum = dot(a, b); } @@ -180,15 +170,16 @@ impl Config { ); let mut res = Vec::with_capacity(self.num_rounds); for _ in 0..self.num_rounds { - let a: F = verifier_state.prover_message()?; - let b: F = verifier_state.prover_message()?; + let c0: F = verifier_state.prover_message()?; + let c2: F = verifier_state.prover_message()?; + let c1 = *sum - c0.double() - c2; self.round_pow.verify(verifier_state)?; let r = verifier_state.verifier_message::(); res.push(r); - *sum = a + (b - a.double()) * r + (*sum - b) * r.square(); + *sum = (c2 * r + c1) * r + c0; } Ok(MultilinearPoint(res)) diff --git a/src/protocols/whir/prover.rs b/src/protocols/whir/prover.rs index 66107f94..0493157d 100644 --- a/src/protocols/whir/prover.rs +++ b/src/protocols/whir/prover.rs @@ -12,8 +12,7 @@ use crate::{ embedding::Embedding, lift, linear_form::{Covector, Evaluate, LinearForm, UnivariateEvaluation}, - mixed_scalar_mul_add, - tensor_product, MultilinearPoint, + mixed_scalar_mul_add, tensor_product, MultilinearPoint, }, hash::Hash, protocols::{ From d29d5ba8fe4c2952cb4fa5c3be797793371efb01 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:07:04 +0200 Subject: [PATCH 08/26] rebase --- src/protocols/sumcheck.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 39b045a6..52c18c29 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -139,7 +139,7 @@ impl Config { |_, t| { #[cfg(feature = "tracing")] let _s = tracing::info_span!("round_pow_cb").entered(); - self.round_pow.prove(t) + self.round_pow.prove(t); }, ); From 121bb590d1b76fd93b7183184214c7473705e193 Mon Sep 17 00:00:00 2001 From: EC2 Default User Date: Thu, 16 Apr 2026 16:12:28 +0000 Subject: [PATCH 09/26] fix benches --- benches/sumcheck.rs | 123 +++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 70 deletions(-) diff --git a/benches/sumcheck.rs b/benches/sumcheck.rs index 4ee38fe7..70aedf1d 100644 --- a/benches/sumcheck.rs +++ b/benches/sumcheck.rs @@ -1,5 +1,9 @@ +use ark_std::rand::{rngs::StdRng, SeedableRng}; use divan::{black_box, AllocProfiler, Bencher}; -use efficient_sumcheck::{order_strategy::MSBOrder, simd_ops as effsc_simd, streams::reorder_vec}; +use efficient_sumcheck::{ + inner_product_sumcheck_partial_with_hook, + transcript::{SanityTranscript, Transcript}, +}; use whir::algebra::{ fields::{Field64 as G1, Field64_2 as G2, Field64_3 as G3}, sumcheck::{compute_sumcheck_polynomial, fold}, @@ -8,105 +12,84 @@ use whir::algebra::{ #[global_allocator] static ALLOC: AllocProfiler = AllocProfiler::system(); -const SIZES: &[u64] = &[1 << 16, 1 << 18, 1 << 20, 1 << 22]; - -// ── Whir baseline kernel: compute_sumcheck_polynomial + fold ─────────────── - -#[divan::bench(args = SIZES)] -fn whir_g1(bencher: Bencher, size: u64) { - run_whir::(bencher, size); -} -#[divan::bench(args = SIZES)] -fn whir_g2(bencher: Bencher, size: u64) { - run_whir::(bencher, size); -} -#[divan::bench(args = SIZES)] -fn whir_g3(bencher: Bencher, size: u64) { - run_whir::(bencher, size); -} - -fn run_whir>(bencher: Bencher, size: u64) { - bencher - .with_inputs(|| { - let a: Vec = (0..size).map(F::from).collect(); - let b: Vec = (0..size).map(F::from).collect(); - let r = F::from(42); - (a, b, r) - }) - .bench_values(|(mut a, mut b, r)| { - let poly = compute_sumcheck_polynomial(&a, &b); - fold(&mut a, r); - fold(&mut b, r); - black_box((poly, a, b)) - }); -} +const SIZES: &[u64] = &[1 << 20, 1 << 24]; +const SEED: u64 = 0xA110C8ED; -// ── effsc SIMD path: reorder + pairwise_product_sum + fold ───────────────── -// Includes the bit-reversal permutation cost on the first round. +// ── Whir baseline: full sumcheck via compute_sumcheck_polynomial + fold + fold +// looped log2(n) times. Challenges drawn from the same SanityTranscript +// shape as effsc so both sides do identical work per round. #[divan::bench(args = SIZES)] -fn effsc_g1(bencher: Bencher, size: u64) { - run_effsc::(bencher, size); +fn whir_full_g1(bencher: Bencher, size: u64) { + run_whir_full::(bencher, size); } #[divan::bench(args = SIZES)] -fn effsc_g2(bencher: Bencher, size: u64) { - run_effsc::(bencher, size); +fn whir_full_g2(bencher: Bencher, size: u64) { + run_whir_full::(bencher, size); } #[divan::bench(args = SIZES)] -fn effsc_g3(bencher: Bencher, size: u64) { - run_effsc::(bencher, size); +fn whir_full_g3(bencher: Bencher, size: u64) { + run_whir_full::(bencher, size); } -fn run_effsc>(bencher: Bencher, size: u64) { +fn run_whir_full>(bencher: Bencher, size: u64) { + let num_rounds = (size as u64).trailing_zeros() as usize; bencher .with_inputs(|| { let a: Vec = (0..size).map(F::from).collect(); let b: Vec = (0..size).map(F::from).collect(); - let r = F::from(42); - (a, b, r) + (a, b) }) - .bench_values(|(a, b, r)| { - // Bit-reverse to LSB-first so effsc's adjacent-pair kernels - // bind whir's x_0, x_1, ... in order. - let mut a = reorder_vec::(a); - let mut b = reorder_vec::(b); - let poly = effsc_simd::pairwise_product_sum(&a, &b); - effsc_simd::fold(&mut a, r); - effsc_simd::fold(&mut b, r); - black_box((poly, a, b)) + .bench_values(|(mut a, mut b)| { + let mut rng = StdRng::seed_from_u64(SEED); + let mut t = SanityTranscript::::new(&mut rng); + for _ in 0..num_rounds { + let poly = compute_sumcheck_polynomial(&a, &b); + black_box(poly); + let r: F = t.read(); + fold(&mut a, r); + fold(&mut b, r); + } + black_box((a, b)) }); } -// ── effsc SIMD path WITHOUT the entry permutation ────────────────────────── -// Isolates the kernel speedup from the permutation overhead, simulating -// mid-sumcheck rounds where the data is already in LSB-first layout. +// ── effsc MSB fused path: inner_product_sumcheck_partial_with_hook runs all +// rounds internally — round 0 = compute_sumcheck_polynomial, rounds ≥1 = +// fused_fold_and_compute_polynomial (the 8R+4W-per-quadruple kernel). #[divan::bench(args = SIZES)] -fn effsc_nopermute_g1(bencher: Bencher, size: u64) { - run_effsc_nopermute::(bencher, size); +fn effsc_full_g1(bencher: Bencher, size: u64) { + run_effsc_full::(bencher, size); } #[divan::bench(args = SIZES)] -fn effsc_nopermute_g2(bencher: Bencher, size: u64) { - run_effsc_nopermute::(bencher, size); +fn effsc_full_g2(bencher: Bencher, size: u64) { + run_effsc_full::(bencher, size); } #[divan::bench(args = SIZES)] -fn effsc_nopermute_g3(bencher: Bencher, size: u64) { - run_effsc_nopermute::(bencher, size); +fn effsc_full_g3(bencher: Bencher, size: u64) { + run_effsc_full::(bencher, size); } -fn run_effsc_nopermute>(bencher: Bencher, size: u64) { +fn run_effsc_full>(bencher: Bencher, size: u64) { + let num_rounds = (size as u64).trailing_zeros() as usize; bencher .with_inputs(|| { let a: Vec = (0..size).map(F::from).collect(); let b: Vec = (0..size).map(F::from).collect(); - let r = F::from(42); - (a, b, r) + (a, b) }) - .bench_values(|(mut a, mut b, r)| { - let poly = effsc_simd::pairwise_product_sum(&a, &b); - effsc_simd::fold(&mut a, r); - effsc_simd::fold(&mut b, r); - black_box((poly, a, b)) + .bench_values(|(mut a, mut b)| { + let mut rng = StdRng::seed_from_u64(SEED); + let mut t = SanityTranscript::::new(&mut rng); + let result = inner_product_sumcheck_partial_with_hook( + &mut a, + &mut b, + &mut t, + num_rounds, + |_, _| {}, + ); + black_box((result, a, b)) }); } From 525f71c70f7f984b06ec767b18228757e038e27e Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:30:48 +0200 Subject: [PATCH 10/26] remove dead code --- .claude/settings.json | 7 ++ benches/sumcheck.rs | 44 +-------- src/algebra/mod.rs | 1 - src/algebra/multilinear.rs | 12 ++- src/algebra/sumcheck.rs | 182 ------------------------------------- 5 files changed, 19 insertions(+), 227 deletions(-) create mode 100644 .claude/settings.json delete mode 100644 src/algebra/sumcheck.rs diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..17f90522 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(git remote *)" + ] + } +} diff --git a/benches/sumcheck.rs b/benches/sumcheck.rs index 70aedf1d..eb57e11b 100644 --- a/benches/sumcheck.rs +++ b/benches/sumcheck.rs @@ -4,10 +4,7 @@ use efficient_sumcheck::{ inner_product_sumcheck_partial_with_hook, transcript::{SanityTranscript, Transcript}, }; -use whir::algebra::{ - fields::{Field64 as G1, Field64_2 as G2, Field64_3 as G3}, - sumcheck::{compute_sumcheck_polynomial, fold}, -}; +use whir::algebra::fields::{Field64 as G1, Field64_2 as G2, Field64_3 as G3}; #[global_allocator] static ALLOC: AllocProfiler = AllocProfiler::system(); @@ -15,45 +12,6 @@ static ALLOC: AllocProfiler = AllocProfiler::system(); const SIZES: &[u64] = &[1 << 20, 1 << 24]; const SEED: u64 = 0xA110C8ED; -// ── Whir baseline: full sumcheck via compute_sumcheck_polynomial + fold + fold -// looped log2(n) times. Challenges drawn from the same SanityTranscript -// shape as effsc so both sides do identical work per round. - -#[divan::bench(args = SIZES)] -fn whir_full_g1(bencher: Bencher, size: u64) { - run_whir_full::(bencher, size); -} -#[divan::bench(args = SIZES)] -fn whir_full_g2(bencher: Bencher, size: u64) { - run_whir_full::(bencher, size); -} -#[divan::bench(args = SIZES)] -fn whir_full_g3(bencher: Bencher, size: u64) { - run_whir_full::(bencher, size); -} - -fn run_whir_full>(bencher: Bencher, size: u64) { - let num_rounds = (size as u64).trailing_zeros() as usize; - bencher - .with_inputs(|| { - let a: Vec = (0..size).map(F::from).collect(); - let b: Vec = (0..size).map(F::from).collect(); - (a, b) - }) - .bench_values(|(mut a, mut b)| { - let mut rng = StdRng::seed_from_u64(SEED); - let mut t = SanityTranscript::::new(&mut rng); - for _ in 0..num_rounds { - let poly = compute_sumcheck_polynomial(&a, &b); - black_box(poly); - let r: F = t.read(); - fold(&mut a, r); - fold(&mut b, r); - } - black_box((a, b)) - }); -} - // ── effsc MSB fused path: inner_product_sumcheck_partial_with_hook runs all // rounds internally — round 0 = compute_sumcheck_polynomial, rounds ≥1 = // fused_fold_and_compute_polynomial (the 8R+4W-per-quadruple kernel). diff --git a/src/algebra/mod.rs b/src/algebra/mod.rs index 5f5e4cfc..40446973 100644 --- a/src/algebra/mod.rs +++ b/src/algebra/mod.rs @@ -4,7 +4,6 @@ pub mod linear_form; mod multilinear; mod multilinear_point; pub mod ntt; -pub mod sumcheck; use ark_ff::{AdditiveGroup, Field}; use ark_std::rand::{distributions::Standard, prelude::Distribution, Rng}; diff --git a/src/algebra/multilinear.rs b/src/algebra/multilinear.rs index c9108299..9da853d4 100644 --- a/src/algebra/multilinear.rs +++ b/src/algebra/multilinear.rs @@ -188,10 +188,20 @@ mod tests { use proptest::proptest; use super::*; - use crate::algebra::{random_vector, sumcheck::tests::zero_pad}; + use crate::algebra::random_vector; pub type F = crate::algebra::fields::Field64; + /// Zero-pad to the next power of two. + fn zero_pad(values: &[G]) -> Vec { + if values.is_empty() { + return Vec::new(); + } + let mut vec = values.to_vec(); + vec.resize(vec.len().next_power_of_two(), G::ZERO); + vec + } + #[test] fn test_multilinear_zero_extend() { proptest!(|(seed:u64, length in 0_usize..(1 << 14))| { diff --git a/src/algebra/sumcheck.rs b/src/algebra/sumcheck.rs deleted file mode 100644 index 3b9627ac..00000000 --- a/src/algebra/sumcheck.rs +++ /dev/null @@ -1,182 +0,0 @@ -use ark_ff::Field; -#[cfg(feature = "parallel")] -use rayon::join; - -use crate::algebra::{dot, embedding::Embedding, scalar_mul}; -#[cfg(feature = "parallel")] -use crate::utils::workload_size; - -/// Computes the constant and quadratic coefficient of the sumcheck polynomial. -/// -/// Vectors `a` and `b` are implicitly zero-extended to the next power of two. -pub fn compute_sumcheck_polynomial(a: &[F], b: &[F]) -> (F, F) { - fn recurse(a0: &[F], a1: &[F], b0: &[F], b1: &[F]) -> (F, F) { - debug_assert_eq!(a0.len(), b0.len()); - debug_assert_eq!(a1.len(), b1.len()); - debug_assert!(a0.len() == a1.len()); - - #[cfg(feature = "parallel")] - if a0.len() * 4 > workload_size::() { - let mid = a0.len() / 2; - let (a0l, a0r) = a0.split_at(mid); - let (b0l, b0r) = b0.split_at(mid); - let (a1l, a1r) = a1.split_at(mid); - let (b1l, b1r) = b1.split_at(mid); - let (left, right) = join( - || recurse(a0l, a1l, b0l, b1l), - || recurse(a0r, a1r, b0r, b1r), - ); - return (left.0 + right.0, left.1 + right.1); - } - let mut acc0 = F::ZERO; - let mut acc2 = F::ZERO; - for ((&a0, &a1), (&b0, &b1)) in a0.iter().zip(a1).zip(b0.iter().zip(b1)) { - acc0 += a0 * b0; - acc2 += (a1 - a0) * (b1 - b0); - } - (acc0, acc2) - } - - let non_padded = a.len().min(b.len()); - let a = &a[..non_padded]; - let b = &b[..non_padded]; - if a.is_empty() { - return (F::ZERO, F::ZERO); - } - if a.len() == 1 { - return (a[0] * b[0], F::ZERO); - } - - let half = a.len().next_power_of_two() >> 1; - let (a0, a1) = a.split_at(half); - let (b0, b1) = b.split_at(half); - debug_assert!(a0.len() >= a1.len()); - let (a0, a0_tail) = a0.split_at(a1.len()); - let (b0, b0_tail) = b0.split_at(a1.len()); - let (acc0, acc2) = recurse(a0, a1, b0, b1); - - // Handle the tail part where a1, b1 is implicit zero padding, - // When a1, b1 = 0, then acc0 = acc2 = a0 * b0: - let acc = dot(a0_tail, b0_tail); - - (acc0 + acc, acc2 + acc) -} - -/// Folds evaluations by linear interpolation at the given weight, in place. -/// -/// The `values` are implicitly zero-padded to the next power of two. On return, -/// the length of `values` will always be a power of two. -pub fn fold(values: &mut Vec, weight: F) { - fn recurse_both(low: &mut [F], high: &[F], weight: F) { - #[cfg(feature = "parallel")] - if low.len() > workload_size::() { - let split = low.len() / 2; - let (ll, lr) = low.split_at_mut(split); - let (hl, hr) = high.split_at(split); - rayon::join( - || recurse_both(ll, hl, weight), - || recurse_both(lr, hr, weight), - ); - return; - } - - for (low, high) in low.iter_mut().zip(high) { - *low += (*high - *low) * weight; - } - } - - if values.len() <= 1 { - return; - } - - let half = values.len().next_power_of_two() >> 1; - let (low, high) = values.split_at_mut(half); - debug_assert!(low.len() >= high.len()); - let (low, tail) = low.split_at_mut(high.len()); - recurse_both(low, high, weight); - - // Tail part where `high` is implicit zero padding - // When high = 0 we have *low *= 1 - weight. - scalar_mul(tail, F::ONE - weight); - - values.truncate(half); - values.shrink_to_fit(); -} - -/// Evaluate a coefficient vector at a multilinear point in the target field. -pub fn mixed_eval( - embedding: &M, - coeff: &[M::Source], - eval: &[M::Target], - scalar: M::Target, -) -> M::Target { - debug_assert_eq!(coeff.len(), 1 << eval.len()); - - if let Some((&x, tail)) = eval.split_first() { - let (low, high) = coeff.split_at(coeff.len() / 2); - - #[cfg(feature = "parallel")] - if low.len() > workload_size::() { - let (a, b) = join( - || mixed_eval(embedding, low, tail, scalar), - || mixed_eval(embedding, high, tail, scalar * x), - ); - return a + b; - } - - mixed_eval(embedding, low, tail, scalar) + mixed_eval(embedding, high, tail, scalar * x) - } else { - embedding.mixed_mul(scalar, coeff[0]) - } -} - -#[cfg(test)] -pub(crate) mod tests { - use ark_std::rand::{rngs::StdRng, Rng, SeedableRng}; - use proptest::proptest; - - use super::*; - use crate::algebra::{fields::Field64, random_vector}; - - type F = Field64; - - /// Zero-pad to the next power of two. - pub fn zero_pad(values: &[F]) -> Vec { - if values.is_empty() { - return Vec::new(); - } - let mut vec = values.to_vec(); - vec.resize(vec.len().next_power_of_two(), F::ZERO); - vec - } - - #[test] - fn sumcheck_poly_zero_extend() { - proptest!(|(seed:u64, length in 0_usize..(1 << 14))| { - let mut rng = StdRng::seed_from_u64(seed); - let vector: Vec = random_vector(&mut rng, length); - let covector: Vec = random_vector(&mut rng, length); - let extended_vector = zero_pad(&vector); - let extended_covector = zero_pad(&covector); - let expected = compute_sumcheck_polynomial(&extended_vector, &extended_covector); - assert_eq!(compute_sumcheck_polynomial(&vector, &covector), expected); - assert_eq!(compute_sumcheck_polynomial(&extended_vector, &covector), expected); - assert_eq!(compute_sumcheck_polynomial(&vector, &extended_covector), expected); - }); - } - - #[test] - fn fold_zero_extend() { - proptest!(|(seed:u64, length in 0_usize..(1 << 14))| { - let mut rng = StdRng::seed_from_u64(seed); - let mut vector: Vec = random_vector(&mut rng, length); - let mut extended_vector = zero_pad(&vector); - let weight = rng.gen::(); - - fold(&mut vector, weight); - assert!(vector.is_empty() || vector.len().is_power_of_two()); - fold(&mut extended_vector, weight); - assert_eq!(vector, extended_vector); - }); - } -} From 63f9a3a0269bb6233e5e9d4afe8e2a229acaf4b2 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:12:44 +0200 Subject: [PATCH 11/26] gitignore --- .claude/settings.json | 7 ------- .gitignore | 2 ++ proptest-regressions/protocols/basecase.txt | 8 -------- proptest-regressions/protocols/sumcheck.txt | 8 -------- 4 files changed, 2 insertions(+), 23 deletions(-) delete mode 100644 .claude/settings.json delete mode 100644 proptest-regressions/protocols/basecase.txt delete mode 100644 proptest-regressions/protocols/sumcheck.txt diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 17f90522..00000000 --- a/.claude/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(git remote *)" - ] - } -} diff --git a/.gitignore b/.gitignore index b9bcfb09..ba0a8d1d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ outputs/ .flake rustc-ice-*.txt profile.json.gz +.claude/ +proptest-regressions/ diff --git a/proptest-regressions/protocols/basecase.txt b/proptest-regressions/protocols/basecase.txt deleted file mode 100644 index a461b183..00000000 --- a/proptest-regressions/protocols/basecase.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 6fd50adb2eacc5a44429f8aeb8bae55b4a05ae2ac74432e184fa91729f375276 # shrinks to seed = 0, config = Config { commit: Config { embedding: Identity { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 } }, num_vectors: 1, vector_size: 0, mask_length: 0, codeword_length: 1, interleaving_depth: 1, matrix_commit: Config { element_type: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, num_cols: 1, leaf_hash_id: 09459020f451874a1b399819d079632cc0f9263b1486c423173c6e15d8e2d61d, merkle_tree: Config { num_leaves: 1, layers: [] } }, johnson_slack: 0.0, in_domain_samples: 0, out_domain_samples: 0, deduplicate_in_domain: false }, sumcheck: Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 0, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 0 }, masked: false } -cc c9ce19b3d47d11843d0bc7136a3899d3d8a4ca0a22662d48b01edf704ec5301b # shrinks to seed = 0, config = Config { commit: Config { embedding: Identity { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 } }, num_vectors: 1, vector_size: 2, mask_length: 0, codeword_length: 2, interleaving_depth: 1, matrix_commit: Config { element_type: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, num_cols: 1, leaf_hash_id: 09459020f451874a1b399819d079632cc0f9263b1486c423173c6e15d8e2d61d, merkle_tree: Config { num_leaves: 2, layers: [LayerConfig { hash_id: 018eaa247cb8957ab1e9fdac885450403c5e7bda1acaaa504e4cc8f2f76bb076 }] } }, johnson_slack: 0.0, in_domain_samples: 0, out_domain_samples: 0, deduplicate_in_domain: false }, sumcheck: Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 2, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 1 }, masked: false } diff --git a/proptest-regressions/protocols/sumcheck.txt b/proptest-regressions/protocols/sumcheck.txt deleted file mode 100644 index 547c30ca..00000000 --- a/proptest-regressions/protocols/sumcheck.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 15c34319c1d5d357f51a76e80909f309313ba4e0a317976aa4c9188e6ec7368a # shrinks to seed = 0, config = Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 2, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 1 } -cc 8c18a2843ed1bba3f28eae7970bd8cf4ebe19d7e61a610b52e013abcae29da3b # shrinks to seed = 0, config = Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 2, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 1 } From d35927e096373e6238b5e9e559f359dae08e656d Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:26:08 +0200 Subject: [PATCH 12/26] cleanup --- Cargo.lock | 2 +- src/protocols/sumcheck.rs | 35 ++++++++--------------------------- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24581083..ffbeeec0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "efficient-sumcheck" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#a5f1aea9608844ee6480b72145e9d58aec5f6072" +source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#5fde362a76ee3a3d537de6d87dcbd54f5a306da5" dependencies = [ "ark-ff", "ark-poly", diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 52c18c29..53e8aef7 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -4,14 +4,8 @@ use std::fmt; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; -// `inner_product_sumcheck_partial_with_hook` is half-split (folds top var -// first); `simd_ops::fold` is pair-split (folds bottom var first). WHIR is -// MSB-first, so the protocol calls the half-split kernel on lex-ordered -// data directly; `multilinear_fold` wraps the pair-split kernel in a -// bit-reversal sandwich to present MSB-first semantics. use efficient_sumcheck::{ - inner_product_sumcheck_partial_with_hook, order_strategy::MSBOrder, simd_ops, - streams::reorder_vec, transcript::Transcript as EffscTranscript, + inner_product_sumcheck_partial, simd_ops, transcript::Transcript as EffscTranscript, }; use serde::{Deserialize, Serialize}; use spongefish::NargSerialize; @@ -28,11 +22,8 @@ use crate::{ type_info::Type, }; -/// Sequentially folds a single vector by a list of challenges. -/// -/// Uses efficient-sumcheck's SIMD-dispatched `fold` (falls back to generic -/// rayon when SIMD doesn't apply). Handles LSB<->MSB ordering and -/// zero-padding to match WHIR's `algebra::sumcheck::fold` semantics. +/// Folds a single vector by a list of challenges using effsc's +/// SIMD-dispatched fold (MSB half-split layout, matching WHIR). #[cfg_attr(feature = "tracing", instrument(skip_all, fields(len = values.len(), rounds = challenges.len())))] pub fn multilinear_fold(values: &mut Vec, challenges: &[F]) { if challenges.is_empty() || values.len() <= 1 { @@ -42,13 +33,9 @@ pub fn multilinear_fold(values: &mut Vec, challenges: &[F]) { if padded > values.len() { values.resize(padded, F::ZERO); } - *values = reorder_vec::(std::mem::take(values)); for &c in challenges { simd_ops::fold(values, c); } - if values.len() > 1 { - *values = reorder_vec::(std::mem::take(values)); - } } impl EffscTranscript for ProverState @@ -131,17 +118,11 @@ impl Config { b.resize(padded, F::ZERO); } - let result = inner_product_sumcheck_partial_with_hook( - a, - b, - prover_state, - self.num_rounds, - |_, t| { - #[cfg(feature = "tracing")] - let _s = tracing::info_span!("round_pow_cb").entered(); - self.round_pow.prove(t); - }, - ); + let result = inner_product_sumcheck_partial(a, b, prover_state, self.num_rounds, |_, t| { + #[cfg(feature = "tracing")] + let _s = tracing::info_span!("round_pow_cb").entered(); + self.round_pow.prove(t); + }); if a.len() == 1 { let (final_a, final_b) = result.final_evaluations; From 58fd69c0b14ca8be2187ca8623d93c18a50378b8 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:48:49 +0200 Subject: [PATCH 13/26] cleanup --- Cargo.lock | 2 +- src/protocols/sumcheck.rs | 18 +----------------- src/protocols/whir/prover.rs | 16 ++++++++++------ 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffbeeec0..2319f4f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "efficient-sumcheck" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#5fde362a76ee3a3d537de6d87dcbd54f5a306da5" +source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#e4acb388d30e8fae675122243f6c42bcbf6f4ca1" dependencies = [ "ark-ff", "ark-poly", diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 53e8aef7..5bb3b731 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -5,7 +5,7 @@ use std::fmt; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; use efficient_sumcheck::{ - inner_product_sumcheck_partial, simd_ops, transcript::Transcript as EffscTranscript, + inner_product_sumcheck_partial, transcript::Transcript as EffscTranscript, }; use serde::{Deserialize, Serialize}; use spongefish::NargSerialize; @@ -22,22 +22,6 @@ use crate::{ type_info::Type, }; -/// Folds a single vector by a list of challenges using effsc's -/// SIMD-dispatched fold (MSB half-split layout, matching WHIR). -#[cfg_attr(feature = "tracing", instrument(skip_all, fields(len = values.len(), rounds = challenges.len())))] -pub fn multilinear_fold(values: &mut Vec, challenges: &[F]) { - if challenges.is_empty() || values.len() <= 1 { - return; - } - let padded = values.len().next_power_of_two(); - if padded > values.len() { - values.resize(padded, F::ZERO); - } - for &c in challenges { - simd_ops::fold(values, c); - } -} - impl EffscTranscript for ProverState where H: DuplexSpongeInterface, diff --git a/src/protocols/whir/prover.rs b/src/protocols/whir/prover.rs index 0493157d..63f26b13 100644 --- a/src/protocols/whir/prover.rs +++ b/src/protocols/whir/prover.rs @@ -2,6 +2,7 @@ use std::{any::Any, borrow::Cow, mem}; use ark_ff::{AdditiveGroup, FftField, Field}; use ark_std::rand::{distributions::Standard, prelude::Distribution, CryptoRng, RngCore}; +use efficient_sumcheck::fold as effsc_fold; #[cfg(feature = "tracing")] use tracing::instrument; @@ -15,10 +16,7 @@ use crate::{ mixed_scalar_mul_add, tensor_product, MultilinearPoint, }, hash::Hash, - protocols::{ - geometric_challenge::geometric_challenge, irs_commit, sumcheck::multilinear_fold, - whir::FinalClaim, - }, + protocols::{geometric_challenge::geometric_challenge, irs_commit, whir::FinalClaim}, transcript::{ codecs::U64, Codec, Decoding, DuplexSpongeInterface, ProverMessage, ProverState, VerifierMessage, @@ -212,8 +210,14 @@ where .map(|_| prover_state.verifier_message()) .collect(); self.initial_skip_pow.prove(prover_state); - // Fold vector using effsc's SIMD-dispatched fold - multilinear_fold(&mut vector, &folding_randomness); + // Fold vector using effsc's SIMD-dispatched fold. + let padded = vector.len().next_power_of_two(); + if padded > vector.len() { + vector.resize(padded, M::Target::ZERO); + } + for &c in &folding_randomness { + effsc_fold(&mut vector, c); + } // Covector must be all zeros. covector = vec![M::Target::ZERO; self.initial_sumcheck.final_size()]; MultilinearPoint(folding_randomness) From 24137bec82de60b147966eb10ae357e3cb9bea87 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:58:13 +0200 Subject: [PATCH 14/26] cleanup --- src/protocols/sumcheck.rs | 16 +++------------- src/protocols/whir/prover.rs | 5 ----- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 5bb3b731..9219d00e 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -96,24 +96,14 @@ impl Config { return MultilinearPoint(Vec::new()); } - let padded = self.initial_size.next_power_of_two(); - if padded > self.initial_size { - a.resize(padded, F::ZERO); - b.resize(padded, F::ZERO); - } - + // effsc folds a, b in place and handles the transcript (c0, c2 per + // round + PoW hook + verifier challenges). It does not update `sum`. let result = inner_product_sumcheck_partial(a, b, prover_state, self.num_rounds, |_, t| { #[cfg(feature = "tracing")] let _s = tracing::info_span!("round_pow_cb").entered(); self.round_pow.prove(t); }); - - if a.len() == 1 { - let (final_a, final_b) = result.final_evaluations; - *sum = final_a * final_b; - } else { - *sum = dot(a, b); - } + *sum = dot(a, b); MultilinearPoint(result.verifier_messages) } diff --git a/src/protocols/whir/prover.rs b/src/protocols/whir/prover.rs index 63f26b13..9ab6a5ba 100644 --- a/src/protocols/whir/prover.rs +++ b/src/protocols/whir/prover.rs @@ -210,11 +210,6 @@ where .map(|_| prover_state.verifier_message()) .collect(); self.initial_skip_pow.prove(prover_state); - // Fold vector using effsc's SIMD-dispatched fold. - let padded = vector.len().next_power_of_two(); - if padded > vector.len() { - vector.resize(padded, M::Target::ZERO); - } for &c in &folding_randomness { effsc_fold(&mut vector, c); } From 52165b20de336df889b399bf9fdbd51a8aacee6c Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:04:44 +0200 Subject: [PATCH 15/26] bump patch --- Cargo.lock | 162 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 6 +- 2 files changed, 84 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2319f4f9..6f5a6a59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,7 +106,7 @@ dependencies = [ [[package]] name = "ark-ff" version = "0.5.0" -source = "git+https://github.com/arkworks-rs/algebra?branch=z-tech%2Fmacro_auto_detect_subgroup#39464f8deadee46e27e1b8de57bcab203297bbea" +source = "git+https://github.com/arkworks-rs/algebra?branch=master#4cec9f0e7a9a4f0d26433917980b1d4d5d8e521c" dependencies = [ "ark-ff-asm", "ark-ff-macros", @@ -123,7 +123,7 @@ dependencies = [ [[package]] name = "ark-ff-asm" version = "0.5.0" -source = "git+https://github.com/arkworks-rs/algebra?branch=z-tech%2Fmacro_auto_detect_subgroup#39464f8deadee46e27e1b8de57bcab203297bbea" +source = "git+https://github.com/arkworks-rs/algebra?branch=master#4cec9f0e7a9a4f0d26433917980b1d4d5d8e521c" dependencies = [ "quote", "syn", @@ -132,7 +132,7 @@ dependencies = [ [[package]] name = "ark-ff-macros" version = "0.5.0" -source = "git+https://github.com/arkworks-rs/algebra?branch=z-tech%2Fmacro_auto_detect_subgroup#39464f8deadee46e27e1b8de57bcab203297bbea" +source = "git+https://github.com/arkworks-rs/algebra?branch=master#4cec9f0e7a9a4f0d26433917980b1d4d5d8e521c" dependencies = [ "num-bigint", "num-traits", @@ -144,7 +144,7 @@ dependencies = [ [[package]] name = "ark-poly" version = "0.5.0" -source = "git+https://github.com/arkworks-rs/algebra?branch=z-tech%2Fmacro_auto_detect_subgroup#2644053e2fe913b0aba2c89d1fcd8277dbb826e4" +source = "git+https://github.com/arkworks-rs/algebra?branch=master#4cec9f0e7a9a4f0d26433917980b1d4d5d8e521c" dependencies = [ "ahash", "ark-ff", @@ -152,14 +152,14 @@ dependencies = [ "ark-std", "educe", "fnv", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "rayon", ] [[package]] name = "ark-serialize" version = "0.5.0" -source = "git+https://github.com/arkworks-rs/algebra?branch=z-tech%2Fmacro_auto_detect_subgroup#39464f8deadee46e27e1b8de57bcab203297bbea" +source = "git+https://github.com/arkworks-rs/algebra?branch=master#4cec9f0e7a9a4f0d26433917980b1d4d5d8e521c" dependencies = [ "ark-serialize-derive", "ark-std", @@ -172,7 +172,7 @@ dependencies = [ [[package]] name = "ark-serialize-derive" version = "0.5.0" -source = "git+https://github.com/arkworks-rs/algebra?branch=z-tech%2Fmacro_auto_detect_subgroup#39464f8deadee46e27e1b8de57bcab203297bbea" +source = "git+https://github.com/arkworks-rs/algebra?branch=master#4cec9f0e7a9a4f0d26433917980b1d4d5d8e521c" dependencies = [ "proc-macro2", "quote", @@ -185,7 +185,7 @@ version = "0.5.0" source = "git+https://github.com/arkworks-rs/std#1693bc56d2ca6657b623f33a3f0b009d0ffeb892" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", "rayon", ] @@ -230,9 +230,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "blake3" @@ -275,9 +275,9 @@ checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "cc" -version = "1.2.58" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "shlex", @@ -336,9 +336,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -359,9 +359,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -377,9 +377,9 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "codspeed" -version = "4.4.1" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b684e94583e85a5ca7e1a6454a89d76a5121240f2fb67eb564129d9bafdb9db0" +checksum = "c83592369519f73d5731f9c91aa562e213a33cc14bb0f27ac2f5730fd1ecbcec" dependencies = [ "anyhow", "cc", @@ -395,9 +395,9 @@ dependencies = [ [[package]] name = "codspeed-divan-compat" -version = "4.4.1" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e4bf8c7793c170fd0fcf3be97b9032b2ae39c2b9e8818aba3cc10ca0f0c6c0" +checksum = "a717deb83a7472e31b38244f836c92947ac17890970f61a083495b3a6653bf1b" dependencies = [ "clap", "codspeed", @@ -408,9 +408,9 @@ dependencies = [ [[package]] name = "codspeed-divan-compat-macros" -version = "4.4.1" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78aae02f2a278588e16e8ca62ea1915b8ab30f8230a09926671bba19ede801a4" +checksum = "eed8dc7bd913f259c57e2b94657a4c9fd20b3bded18462b22c647877feb43b53" dependencies = [ "divan-macros", "itertools", @@ -422,9 +422,9 @@ dependencies = [ [[package]] name = "codspeed-divan-compat-walltime" -version = "4.4.1" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ffd32c0c59ab8b674b15be65ba7c59aebac047036cfa7fa1e11bc2c178b81f" +checksum = "96500330271308ca89e68e1885951716cf2d3895ef9508192376dd125321a8f2" dependencies = [ "cfg-if", "clap", @@ -681,9 +681,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "find-msvc-tools" @@ -783,9 +783,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" dependencies = [ "allocator-api2", ] @@ -860,12 +860,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -893,9 +893,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.92" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ "once_cell", "wasm-bindgen", @@ -934,9 +934,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "linux-raw-sys" @@ -1063,7 +1063,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.8.6", "serde", ] @@ -1107,7 +1107,7 @@ dependencies = [ "p3-maybe-rayon", "p3-util", "paste", - "rand 0.10.0", + "rand 0.10.1", "serde", "tracing", ] @@ -1125,7 +1125,7 @@ dependencies = [ "p3-poseidon1", "p3-poseidon2", "p3-symmetric", - "rand 0.10.0", + "rand 0.10.1", ] [[package]] @@ -1138,7 +1138,7 @@ dependencies = [ "p3-field", "p3-maybe-rayon", "p3-util", - "rand 0.10.0", + "rand 0.10.1", "serde", "tracing", ] @@ -1159,7 +1159,7 @@ dependencies = [ "p3-field", "p3-symmetric", "p3-util", - "rand 0.10.0", + "rand 0.10.1", ] [[package]] @@ -1180,7 +1180,7 @@ dependencies = [ "p3-symmetric", "p3-util", "paste", - "rand 0.10.0", + "rand 0.10.1", "serde", "spin", "tracing", @@ -1194,7 +1194,7 @@ checksum = "6a018b618e3fa0aec8be933b1d8e404edd23f46991f6bf3f5c2f3f95e9413fe9" dependencies = [ "p3-field", "p3-symmetric", - "rand 0.10.0", + "rand 0.10.1", ] [[package]] @@ -1207,7 +1207,7 @@ dependencies = [ "p3-mds", "p3-symmetric", "p3-util", - "rand 0.10.0", + "rand 0.10.1", ] [[package]] @@ -1297,7 +1297,7 @@ dependencies = [ "bit-vec", "bitflags", "num-traits", - "rand 0.9.2", + "rand 0.9.4", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -1335,9 +1335,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -1347,9 +1347,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -1357,11 +1357,11 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -1405,9 +1405,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rand_xorshift" @@ -1420,9 +1420,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -1556,9 +1556,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -1613,7 +1613,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.0", + "indexmap 2.14.0", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -1712,7 +1712,7 @@ dependencies = [ "ark-serialize", "digest 0.11.2", "p3-koala-bear", - "rand 0.8.5", + "rand 0.8.6", "sha2 0.11.0", "sha3 0.11.0-rc.9", "zeroize", @@ -1828,20 +1828,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.25.8+spec-1.1.0" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16bff38f1d86c47f9ff0647e6838d7bb362522bdf44006c7068c2b1e606f1f3c" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "toml_datetime", "toml_parser", "winnow", @@ -1849,9 +1849,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.1.0+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ "winnow", ] @@ -2004,9 +2004,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.115" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -2017,9 +2017,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.115" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2027,9 +2027,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.115" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -2040,9 +2040,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.115" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] @@ -2064,7 +2064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.13.0", + "indexmap 2.14.0", "wasm-encoder", "wasmparser", ] @@ -2077,7 +2077,7 @@ checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ "bitflags", "hashbrown 0.15.5", - "indexmap 2.13.0", + "indexmap 2.14.0", "semver", ] @@ -2256,9 +2256,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" dependencies = [ "memchr", ] @@ -2291,7 +2291,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap 2.13.0", + "indexmap 2.14.0", "prettyplease", "syn", "wasm-metadata", @@ -2322,7 +2322,7 @@ checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", "bitflags", - "indexmap 2.13.0", + "indexmap 2.14.0", "log", "serde", "serde_derive", @@ -2341,7 +2341,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.13.0", + "indexmap 2.14.0", "log", "semver", "serde", diff --git a/Cargo.toml b/Cargo.toml index d130eb8f..e04df5aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,8 +108,8 @@ lto = "thin" # LTO breaks line attribution. opt-level = 3 [patch.crates-io] -ark-ff = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/macro_auto_detect_subgroup" } +ark-ff = { git = "https://github.com/arkworks-rs/algebra", branch = "master" } ark-std = { git = "https://github.com/arkworks-rs/std" } -ark-serialize = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/macro_auto_detect_subgroup" } -ark-poly = { git = "https://github.com/arkworks-rs/algebra", branch = "z-tech/macro_auto_detect_subgroup" } +ark-serialize = { git = "https://github.com/arkworks-rs/algebra", branch = "master" } +ark-poly = { git = "https://github.com/arkworks-rs/algebra", branch = "master" } From d1b87fcedddd67a513a8869e537ea720502ec9ff Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:10:18 +0200 Subject: [PATCH 16/26] clean bench --- Cargo.toml | 4 ---- benches/sumcheck.rs | 56 --------------------------------------------- 2 files changed, 60 deletions(-) delete mode 100644 benches/sumcheck.rs diff --git a/Cargo.toml b/Cargo.toml index e04df5aa..ab317617 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,10 +84,6 @@ rs_in_order = [] name = "expand_from_coeff" harness = false -[[bench]] -name = "sumcheck" -harness = false - # Disable untill fixed. # [[bench]] # name = "zk_whir" diff --git a/benches/sumcheck.rs b/benches/sumcheck.rs deleted file mode 100644 index eb57e11b..00000000 --- a/benches/sumcheck.rs +++ /dev/null @@ -1,56 +0,0 @@ -use ark_std::rand::{rngs::StdRng, SeedableRng}; -use divan::{black_box, AllocProfiler, Bencher}; -use efficient_sumcheck::{ - inner_product_sumcheck_partial_with_hook, - transcript::{SanityTranscript, Transcript}, -}; -use whir::algebra::fields::{Field64 as G1, Field64_2 as G2, Field64_3 as G3}; - -#[global_allocator] -static ALLOC: AllocProfiler = AllocProfiler::system(); - -const SIZES: &[u64] = &[1 << 20, 1 << 24]; -const SEED: u64 = 0xA110C8ED; - -// ── effsc MSB fused path: inner_product_sumcheck_partial_with_hook runs all -// rounds internally — round 0 = compute_sumcheck_polynomial, rounds ≥1 = -// fused_fold_and_compute_polynomial (the 8R+4W-per-quadruple kernel). - -#[divan::bench(args = SIZES)] -fn effsc_full_g1(bencher: Bencher, size: u64) { - run_effsc_full::(bencher, size); -} -#[divan::bench(args = SIZES)] -fn effsc_full_g2(bencher: Bencher, size: u64) { - run_effsc_full::(bencher, size); -} -#[divan::bench(args = SIZES)] -fn effsc_full_g3(bencher: Bencher, size: u64) { - run_effsc_full::(bencher, size); -} - -fn run_effsc_full>(bencher: Bencher, size: u64) { - let num_rounds = (size as u64).trailing_zeros() as usize; - bencher - .with_inputs(|| { - let a: Vec = (0..size).map(F::from).collect(); - let b: Vec = (0..size).map(F::from).collect(); - (a, b) - }) - .bench_values(|(mut a, mut b)| { - let mut rng = StdRng::seed_from_u64(SEED); - let mut t = SanityTranscript::::new(&mut rng); - let result = inner_product_sumcheck_partial_with_hook( - &mut a, - &mut b, - &mut t, - num_rounds, - |_, _| {}, - ); - black_box((result, a, b)) - }); -} - -fn main() { - divan::main(); -} From 83bd90cea54c0ba1459b91a041e3502465005ed9 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:15:01 +0200 Subject: [PATCH 17/26] re add proptests --- .gitignore | 1 - proptest-regressions/protocols/basecase.txt | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 proptest-regressions/protocols/basecase.txt diff --git a/.gitignore b/.gitignore index ba0a8d1d..732c8354 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,3 @@ outputs/ rustc-ice-*.txt profile.json.gz .claude/ -proptest-regressions/ diff --git a/proptest-regressions/protocols/basecase.txt b/proptest-regressions/protocols/basecase.txt new file mode 100644 index 00000000..b1160e5a --- /dev/null +++ b/proptest-regressions/protocols/basecase.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 6fd50adb2eacc5a44429f8aeb8bae55b4a05ae2ac74432e184fa91729f375276 # shrinks to seed = 0, config = Config { commit: Config { embedding: Identity { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 } }, num_vectors: 1, vector_size: 0, mask_length: 0, codeword_length: 1, interleaving_depth: 1, matrix_commit: Config { element_type: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, num_cols: 1, leaf_hash_id: 09459020f451874a1b399819d079632cc0f9263b1486c423173c6e15d8e2d61d, merkle_tree: Config { num_leaves: 1, layers: [] } }, johnson_slack: 0.0, in_domain_samples: 0, out_domain_samples: 0, deduplicate_in_domain: false }, sumcheck: Config { field: FieldInfo { characteristic: [255, 255, 255, 255, 0, 0, 0, 1], extension_degree: 1 }, initial_size: 0, round_pow: Config { hash_id: 03e01749ebcc0477924254eb482066b864a8dd4d77252464ca6f5b6f5cc05b4c, threshold: 18446744073709551615 }, num_rounds: 0 }, masked: false } From 520cded728b4d69d593189fe996bd2dc5f578c73 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:35:45 +0200 Subject: [PATCH 18/26] cleanup tracing --- Cargo.lock | 81 +----------------------------------------------------- Cargo.toml | 6 ++-- 2 files changed, 3 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f5a6a59..ee2983b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "efficient-sumcheck" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#e4acb388d30e8fae675122243f6c42bcbf6f4ca1" +source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#82e99119f0c4daf62b975b8d9a7de1da29127d48" dependencies = [ "ark-ff", "ark-poly", @@ -959,15 +959,6 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - [[package]] name = "memchr" version = "2.8.0" @@ -1001,15 +992,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -1673,27 +1655,12 @@ dependencies = [ "keccak 0.2.0", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - [[package]] name = "spin" version = "0.10.0" @@ -1786,15 +1753,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - [[package]] name = "time" version = "0.3.47" @@ -1885,36 +1843,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", ] [[package]] @@ -1957,12 +1885,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - [[package]] name = "version_check" version = "0.9.5" @@ -2109,7 +2031,6 @@ dependencies = [ "spongefish", "static_assertions", "tracing", - "tracing-subscriber", "zerocopy", ] diff --git a/Cargo.toml b/Cargo.toml index ab317617..0d824843 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,8 +44,7 @@ serde_json = "1.0" spongefish = { git = "https://github.com/z-tech/spongefish.git", branch = "smallfp-support", features = ["ark-ff"]} efficient-sumcheck = { git = "https://github.com/compsec-epfl/efficient-sumcheck.git", branch = "z-tech/simd_goldilocks_experimental", default-features = false, features = ["parallel"] } rayon = { version = "1.10", optional = true } -tracing = { version = "0.1", features = ["attributes"], optional = true } -tracing-subscriber = { version = "0.3.22", features = ["env-filter"], optional = true } +tracing = { version = "0.1.41", optional = true } hex = "0.4" static_assertions = "1.1.0" ciborium = "0.2" @@ -62,7 +61,6 @@ ordered-float = { version = "5.1.0", features = ["serde"] } proptest = "1.0" serde_json = "1.0" divan = { version = "4.2", package = "codspeed-divan-compat" } -tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } [profile.release] debug = "line-tables-only" @@ -75,7 +73,7 @@ verifier_panics = [] parallel = ["dep:rayon"] rayon = ["dep:rayon"] asm = ["ark-ff/asm"] -tracing = ["dep:tracing", "dep:tracing-subscriber"] +tracing = ["dep:tracing"] # Do not permute evaluation pointsin RS # This flag is to be removed after whir_zk supports it. rs_in_order = [] From 7b98c1f5f6f000ffc4b011ac413a28a67e705aaf Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:39:35 +0200 Subject: [PATCH 19/26] more cleanup --- src/protocols/whir/prover.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/whir/prover.rs b/src/protocols/whir/prover.rs index 9ab6a5ba..5dd0b0aa 100644 --- a/src/protocols/whir/prover.rs +++ b/src/protocols/whir/prover.rs @@ -206,7 +206,7 @@ where // There are no constraints yet, so we can skip the sumcheck. // (If we did run it, all sumcheck vectors would be constant zero) // TODO: Don't compute evaluations and constraints in the first place. - let folding_randomness: Vec = (0..self.initial_sumcheck.num_rounds) + let folding_randomness = (0..self.initial_sumcheck.num_rounds) .map(|_| prover_state.verifier_message()) .collect(); self.initial_skip_pow.prove(prover_state); From 5031ab84da6200fe65292599daefc47701ab0121 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sat, 18 Apr 2026 15:08:12 +0200 Subject: [PATCH 20/26] integrate new API --- Cargo.lock | 7 ++++--- Cargo.toml | 2 +- src/protocols/sumcheck.rs | 2 +- src/protocols/whir/prover.rs | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee2983b5..3db8f3cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -623,9 +623,9 @@ dependencies = [ ] [[package]] -name = "efficient-sumcheck" +name = "effsc" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/efficient-sumcheck.git?branch=z-tech%2Fsimd_goldilocks_experimental#82e99119f0c4daf62b975b8d9a7de1da29127d48" +source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite#104643774b7291f0981c37ac2f2000daaa861231" dependencies = [ "ark-ff", "ark-poly", @@ -635,6 +635,7 @@ dependencies = [ "nohash-hasher", "rayon", "spongefish", + "zerocopy", ] [[package]] @@ -2018,7 +2019,7 @@ dependencies = [ "const-oid 0.9.6", "derive-where", "digest 0.10.7", - "efficient-sumcheck", + "effsc", "hex", "hex-literal", "ordered-float", diff --git a/Cargo.toml b/Cargo.toml index 0d824843..c5dbb8b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ clap = { version = "4.4", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" spongefish = { git = "https://github.com/z-tech/spongefish.git", branch = "smallfp-support", features = ["ark-ff"]} -efficient-sumcheck = { git = "https://github.com/compsec-epfl/efficient-sumcheck.git", branch = "z-tech/simd_goldilocks_experimental", default-features = false, features = ["parallel"] } +effsc = { git = "https://github.com/compsec-epfl/space-efficient-sumcheck.git", branch = "z-tech/rewrite", default-features = false, features = ["arkworks", "parallel"] } rayon = { version = "1.10", optional = true } tracing = { version = "0.1.41", optional = true } hex = "0.4" diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 9219d00e..5de08b63 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -4,7 +4,7 @@ use std::fmt; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; -use efficient_sumcheck::{ +use effsc::{ inner_product_sumcheck_partial, transcript::Transcript as EffscTranscript, }; use serde::{Deserialize, Serialize}; diff --git a/src/protocols/whir/prover.rs b/src/protocols/whir/prover.rs index 5dd0b0aa..05bf7161 100644 --- a/src/protocols/whir/prover.rs +++ b/src/protocols/whir/prover.rs @@ -2,7 +2,7 @@ use std::{any::Any, borrow::Cow, mem}; use ark_ff::{AdditiveGroup, FftField, Field}; use ark_std::rand::{distributions::Standard, prelude::Distribution, CryptoRng, RngCore}; -use efficient_sumcheck::fold as effsc_fold; +use effsc::fold as effsc_fold; #[cfg(feature = "tracing")] use tracing::instrument; From e0062159d7b27032587d6c60516cb33a0eb3a140 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:09:39 +0200 Subject: [PATCH 21/26] integrate effsc z-tech/rewrite (split Transcript, ?-propagating verify) --- Cargo.lock | 2 +- src/protocols/sumcheck.rs | 59 +++++++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3db8f3cb..44a8de37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "effsc" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite#104643774b7291f0981c37ac2f2000daaa861231" +source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite#1f72c064af142efedb46150a41cc53c145738cd0" dependencies = [ "ark-ff", "ark-poly", diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 5de08b63..644852c0 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -5,10 +5,12 @@ use std::fmt; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; use effsc::{ - inner_product_sumcheck_partial, transcript::Transcript as EffscTranscript, + inner_product_sumcheck_partial, inner_product_sumcheck_verify, + proof::SumcheckError, + transcript::{ProverTranscript, VerifierTranscript}, }; use serde::{Deserialize, Serialize}; -use spongefish::NargSerialize; +use spongefish::{NargDeserialize, NargSerialize, VerificationError}; #[cfg(feature = "tracing")] use tracing::instrument; @@ -22,17 +24,37 @@ use crate::{ type_info::Type, }; -impl EffscTranscript for ProverState +impl ProverTranscript for ProverState where H: DuplexSpongeInterface, R: RngCore + CryptoRng, F: Codec<[H::U]> + NargSerialize, { - fn read(&mut self) -> F { + fn send(&mut self, value: F) { + self.prover_message(&value); + } + fn challenge(&mut self) -> F { self.verifier_message::() } - fn write(&mut self, value: F) { - self.prover_message(&value); +} + +impl VerifierTranscript for VerifierState<'_, H> +where + H: DuplexSpongeInterface, + F: Codec<[H::U]> + NargDeserialize, +{ + type Error = VerificationError; + + fn send(&mut self, _value: F) { + // Re-absorbing known prover data is not exercised by effsc's current + // verify paths; spongefish doesn't expose a public absorb primitive. + unreachable!("VerifierTranscript::send is unused by effsc's legacy verify") + } + fn receive(&mut self) -> Result { + self.prover_message::() + } + fn challenge(&mut self) -> F { + self.verifier_message::() } } @@ -123,21 +145,16 @@ impl Config { assert!( self.num_rounds == 0 || self.initial_size.next_power_of_two() >= 1 << self.num_rounds ); - let mut res = Vec::with_capacity(self.num_rounds); - for _ in 0..self.num_rounds { - let c0: F = verifier_state.prover_message()?; - let c2: F = verifier_state.prover_message()?; - let c1 = *sum - c0.double() - c2; - - self.round_pow.verify(verifier_state)?; - - let r = verifier_state.verifier_message::(); - res.push(r); - - *sum = (c2 * r + c1) * r + c0; - } - - Ok(MultilinearPoint(res)) + let round_pow = &self.round_pow; + let challenges = + inner_product_sumcheck_verify(verifier_state, sum, self.num_rounds, |round, vs| { + round_pow.verify(vs).map_err(|_| SumcheckError::HookError { + round, + detail: "proof-of-work verification failed".into(), + }) + }) + .map_err(|_| VerificationError)?; + Ok(MultilinearPoint(challenges)) } } From 9276aec5c07fe102013d75f48bb76edd24e94488 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sun, 19 Apr 2026 15:20:22 +0200 Subject: [PATCH 22/26] cleanup --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/protocols/sumcheck.rs | 12 +++--------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44a8de37..2e418cfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "effsc" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite#1f72c064af142efedb46150a41cc53c145738cd0" +source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite-v2#95f5ce92f94b2ae690cb481ff9572bfea7646fb7" dependencies = [ "ark-ff", "ark-poly", diff --git a/Cargo.toml b/Cargo.toml index c5dbb8b2..e3a3e7c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ clap = { version = "4.4", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" spongefish = { git = "https://github.com/z-tech/spongefish.git", branch = "smallfp-support", features = ["ark-ff"]} -effsc = { git = "https://github.com/compsec-epfl/space-efficient-sumcheck.git", branch = "z-tech/rewrite", default-features = false, features = ["arkworks", "parallel"] } +effsc = { git = "https://github.com/compsec-epfl/space-efficient-sumcheck.git", branch = "z-tech/rewrite-v2", default-features = false, features = ["arkworks", "parallel"] } rayon = { version = "1.10", optional = true } tracing = { version = "0.1.41", optional = true } hex = "0.4" diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 644852c0..71ed1ed7 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -45,11 +45,6 @@ where { type Error = VerificationError; - fn send(&mut self, _value: F) { - // Re-absorbing known prover data is not exercised by effsc's current - // verify paths; spongefish doesn't expose a public absorb primitive. - unreachable!("VerifierTranscript::send is unused by effsc's legacy verify") - } fn receive(&mut self) -> Result { self.prover_message::() } @@ -148,10 +143,9 @@ impl Config { let round_pow = &self.round_pow; let challenges = inner_product_sumcheck_verify(verifier_state, sum, self.num_rounds, |round, vs| { - round_pow.verify(vs).map_err(|_| SumcheckError::HookError { - round, - detail: "proof-of-work verification failed".into(), - }) + round_pow + .verify(vs) + .map_err(|_| SumcheckError::HookError { round }) }) .map_err(|_| VerificationError)?; Ok(MultilinearPoint(challenges)) From 27acb99ad46d44e6a40697e40be6325d4ee455d5 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sun, 19 Apr 2026 16:41:13 +0200 Subject: [PATCH 23/26] integrate canonical verifier --- Cargo.lock | 2 +- src/protocols/sumcheck.rs | 55 +++++++++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e418cfb..e5e7c065 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "effsc" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite-v2#95f5ce92f94b2ae690cb481ff9572bfea7646fb7" +source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite-v2#884fcb204623bc199806edd8afab939b80b580a3" dependencies = [ "ark-ff", "ark-poly", diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 71ed1ed7..3431beb2 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -1,13 +1,15 @@ //! Quadratic sumcheck protocol. -use std::fmt; +use std::{fmt, mem}; use ark_ff::Field; use ark_std::rand::{CryptoRng, RngCore}; use effsc::{ - inner_product_sumcheck_partial, inner_product_sumcheck_verify, proof::SumcheckError, + provers::inner_product::InnerProductProver, + runner::sumcheck, transcript::{ProverTranscript, VerifierTranscript}, + verifier::sumcheck_verify, }; use serde::{Deserialize, Serialize}; use spongefish::{NargDeserialize, NargSerialize, VerificationError}; @@ -113,16 +115,28 @@ impl Config { return MultilinearPoint(Vec::new()); } - // effsc folds a, b in place and handles the transcript (c0, c2 per - // round + PoW hook + verifier challenges). It does not update `sum`. - let result = inner_product_sumcheck_partial(a, b, prover_state, self.num_rounds, |_, t| { - #[cfg(feature = "tracing")] - let _s = tracing::info_span!("round_pow_cb").entered(); - self.round_pow.prove(t); - }); + // Hand vectors to the InnerProductProver, drive the canonical runner. + // The prover writes (g(0), g(1), g(2)) per round (value form) to the + // transcript and folds a, b internally. The hook runs PoW grinding. + let mut ip_prover = InnerProductProver::new(mem::take(a), mem::take(b)); + let proof = sumcheck( + &mut ip_prover, + self.num_rounds, + prover_state, + |_round, t| { + #[cfg(feature = "tracing")] + let _s = tracing::info_span!("round_pow_cb").entered(); + self.round_pow.prove(t); + }, + ); + + // Pull folded vectors back so the caller can continue working with them. + let (folded_a, folded_b) = ip_prover.evaluations(); + *a = folded_a.to_vec(); + *b = folded_b.to_vec(); *sum = dot(a, b); - MultilinearPoint(result.verifier_messages) + MultilinearPoint(proof.challenges) } #[cfg_attr(feature = "tracing", instrument(skip_all))] @@ -141,13 +155,26 @@ impl Config { self.num_rounds == 0 || self.initial_size.next_power_of_two() >= 1 << self.num_rounds ); let round_pow = &self.round_pow; - let challenges = - inner_product_sumcheck_verify(verifier_state, sum, self.num_rounds, |round, vs| { + let mut final_claim: Option = None; + let challenges = sumcheck_verify( + *sum, + 2, + self.num_rounds, + verifier_state, + |round, vs| { round_pow .verify(vs) .map_err(|_| SumcheckError::HookError { round }) - }) - .map_err(|_| VerificationError)?; + }, + |claim, _challenges| { + // Composed protocol: the oracle check is deferred to the outer + // WHIR rounds, so we just capture the reduced claim here. + final_claim = Some(claim); + Ok(()) + }, + ) + .map_err(|_| VerificationError)?; + *sum = final_claim.expect("oracle_check runs on success"); Ok(MultilinearPoint(challenges)) } } From b5127bb6377ab56edcb1b75432a03de44c12c18e Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sun, 19 Apr 2026 17:08:45 +0200 Subject: [PATCH 24/26] rm oracle check thing --- Cargo.lock | 2 +- src/protocols/sumcheck.rs | 30 ++++++++++-------------------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5e7c065..02b960b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "effsc" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite-v2#884fcb204623bc199806edd8afab939b80b580a3" +source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite-v2#c3676428c2b47b32646e5fdc20f2a755a9c48149" dependencies = [ "ark-ff", "ark-poly", diff --git a/src/protocols/sumcheck.rs b/src/protocols/sumcheck.rs index 3431beb2..3b21f73d 100644 --- a/src/protocols/sumcheck.rs +++ b/src/protocols/sumcheck.rs @@ -155,27 +155,17 @@ impl Config { self.num_rounds == 0 || self.initial_size.next_power_of_two() >= 1 << self.num_rounds ); let round_pow = &self.round_pow; - let mut final_claim: Option = None; - let challenges = sumcheck_verify( - *sum, - 2, - self.num_rounds, - verifier_state, - |round, vs| { - round_pow - .verify(vs) - .map_err(|_| SumcheckError::HookError { round }) - }, - |claim, _challenges| { - // Composed protocol: the oracle check is deferred to the outer - // WHIR rounds, so we just capture the reduced claim here. - final_claim = Some(claim); - Ok(()) - }, - ) + let result = sumcheck_verify(*sum, 2, self.num_rounds, verifier_state, |round, vs| { + round_pow + .verify(vs) + .map_err(|_| SumcheckError::HookError { round }) + }) .map_err(|_| VerificationError)?; - *sum = final_claim.expect("oracle_check runs on success"); - Ok(MultilinearPoint(challenges)) + // Composed protocol: the reduced claim flows into the next WHIR layer, + // which performs the equivalent oracle check (next sumcheck's round-0 + // consistency, or final direct-send comparison). + *sum = result.final_claim; + Ok(MultilinearPoint(result.challenges)) } } From ad75a269582537d00ba28bd9200c22ee94a527f1 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:04:43 +0200 Subject: [PATCH 25/26] rm tracing not needed --- src/bin/main.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index d9d7a85f..92933f30 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -63,17 +63,6 @@ struct Args { } fn main() { - #[cfg(feature = "tracing")] - { - use tracing_subscriber::{fmt, fmt::format::FmtSpan, EnvFilter}; - - let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); - fmt() - .with_env_filter(filter) - .with_span_events(FmtSpan::CLOSE) - .init(); - } - use AvailableFields as AF; let args = Args::parse(); let field = args.field; From a19190b289456f1171f98142101cc98073e33f62 Mon Sep 17 00:00:00 2001 From: Andrew Z <1497456+z-tech@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:34:38 +0200 Subject: [PATCH 26/26] effsc main in cargo toml --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02b960b2..3987422b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -625,7 +625,7 @@ dependencies = [ [[package]] name = "effsc" version = "0.0.2" -source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=z-tech%2Frewrite-v2#c3676428c2b47b32646e5fdc20f2a755a9c48149" +source = "git+https://github.com/compsec-epfl/space-efficient-sumcheck.git?branch=main#9153e8f7d29788159af9791d8262f20b8864fd15" dependencies = [ "ark-ff", "ark-poly", diff --git a/Cargo.toml b/Cargo.toml index e3a3e7c8..fbd9ac9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ clap = { version = "4.4", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" spongefish = { git = "https://github.com/z-tech/spongefish.git", branch = "smallfp-support", features = ["ark-ff"]} -effsc = { git = "https://github.com/compsec-epfl/space-efficient-sumcheck.git", branch = "z-tech/rewrite-v2", default-features = false, features = ["arkworks", "parallel"] } +effsc = { git = "https://github.com/compsec-epfl/space-efficient-sumcheck.git", branch = "main", default-features = false, features = ["arkworks", "parallel"] } rayon = { version = "1.10", optional = true } tracing = { version = "0.1.41", optional = true } hex = "0.4"