From edfb15f5ad2493968a83b6e1b0cf1fe45f597d4f Mon Sep 17 00:00:00 2001 From: Giacomo Fenzi Date: Tue, 19 May 2026 09:19:50 +0200 Subject: [PATCH 1/5] Fix SumcheckField --- src/coefficient_sumcheck.rs | 17 +++++++++-------- src/inner_product_sumcheck.rs | 26 +++++++++++++------------- src/multilinear_sumcheck.rs | 26 +++++++++++++------------- src/provers/coefficient.rs | 23 +++++++++++------------ src/provers/coefficient_lsb.rs | 23 +++++++++++------------ src/provers/eq_factored.rs | 3 +-- src/provers/gkr.rs | 5 ++--- src/provers/inner_product.rs | 6 +----- src/provers/inner_product_lsb.rs | 4 +--- src/provers/mod.rs | 6 ------ src/provers/multilinear.rs | 6 +----- src/reductions/pairwise.rs | 9 +++++---- src/reductions/tablewise.rs | 4 ++-- 13 files changed, 70 insertions(+), 88 deletions(-) diff --git a/src/coefficient_sumcheck.rs b/src/coefficient_sumcheck.rs index 6bfadc56..89e56476 100644 --- a/src/coefficient_sumcheck.rs +++ b/src/coefficient_sumcheck.rs @@ -1,4 +1,5 @@ use ark_ff::Field; +use crate::field::SumcheckField; use ark_poly::univariate::DensePolynomial; #[cfg(feature = "parallel")] @@ -46,7 +47,7 @@ pub struct CoefficientSumcheck { /// } /// } /// ``` -pub trait RoundPolyEvaluator: Sync { +pub trait RoundPolyEvaluator: Sync { /// The degree of the round polynomial (number of coefficients = degree + 1). fn degree(&self) -> usize; @@ -79,7 +80,7 @@ pub trait RoundPolyEvaluator: Sync { /// SIMD fast path for degree-1 with a single pairwise table. /// /// Returns `[sum_even, sum_odd - sum_even]` = coefficients of `h(x) = c0 + c1*x`. -fn simd_evaluate_degree1(pw: &[F]) -> Vec { +fn simd_evaluate_degree1(pw: &[F]) -> Vec { // Try SIMD dispatch for Goldilocks #[cfg(all( feature = "simd", @@ -112,7 +113,7 @@ fn simd_evaluate_degree1(pw: &[F]) -> Vec { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { +fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { crate::simd_sumcheck::dispatch::try_simd_evaluate_degree1(pw) } @@ -128,7 +129,7 @@ fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: F) -> Option> { +fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: F) -> Option> { crate::simd_sumcheck::dispatch::try_simd_fused_reduce_evaluate_degree1(pw, challenge) } @@ -139,13 +140,13 @@ fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: F) -> Op all(target_arch = "x86_64", target_feature = "avx512ifma") ) )))] -fn try_simd_fused_reduce_evaluate(_pw: &mut Vec, _challenge: F) -> Option> { +fn try_simd_fused_reduce_evaluate(_pw: &mut Vec, _challenge: F) -> Option> { None } /// Parallel evaluate using rayon (for heavy evaluators). #[cfg(feature = "parallel")] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -184,7 +185,7 @@ fn parallel_evaluate( /// Fallback when parallel feature is disabled. #[cfg(not(feature = "parallel"))] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -209,7 +210,7 @@ fn parallel_evaluate( /// Sequential evaluate (for trivial evaluators where rayon overhead dominates). /// /// Fills `coeffs_out` with accumulated coefficients (zeroes it first). -fn sequential_evaluate_into( +fn sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], diff --git a/src/inner_product_sumcheck.rs b/src/inner_product_sumcheck.rs index bc9b99d4..1a82f4c9 100644 --- a/src/inner_product_sumcheck.rs +++ b/src/inner_product_sumcheck.rs @@ -19,7 +19,7 @@ //! additional cache-locality gains from reading all four strides //! simultaneously. -use ark_ff::Field; +use crate::field::SumcheckField; #[cfg(feature = "parallel")] use rayon::join; #[cfg(feature = "parallel")] @@ -29,7 +29,7 @@ use crate::transcript::ProverTranscript; /// Legacy return type for `inner_product_sumcheck`. #[derive(Debug, PartialEq)] -pub struct ProductSumcheck { +pub struct ProductSumcheck { pub prover_messages: Vec<(F, F)>, pub verifier_messages: Vec, pub final_evaluations: (F, F), @@ -63,7 +63,7 @@ const fn workload_size() -> usize { // ─── Scalar helpers ───────────────────────────────────────────────────────── -fn dot(a: &[F], b: &[F]) -> F { +fn dot(a: &[F], b: &[F]) -> F { debug_assert_eq!(a.len(), b.len()); #[cfg(feature = "parallel")] if a.len() > workload_size::() { @@ -72,7 +72,7 @@ fn dot(a: &[F], b: &[F]) -> F { a.iter().zip(b).map(|(x, y)| *x * *y).sum() } -fn scalar_mul(v: &mut [F], w: F) { +fn scalar_mul(v: &mut [F], w: F) { for x in v.iter_mut() { *x *= w; } @@ -83,8 +83,8 @@ fn scalar_mul(v: &mut [F], w: F) { /// `(c0, c2)` of the round polynomial `q(x) = c0 + c1·x + c2·x²`. /// /// 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) { +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()); @@ -138,8 +138,8 @@ pub fn compute_sumcheck_polynomial(a: &[F], b: &[F]) -> (F, F) { /// /// `values` is implicitly zero-padded to the next power of two. On return, /// the length is a power of two (or zero). -pub fn fold(values: &mut Vec, weight: F) { - fn recurse_both(low: &mut [F], high: &[F], weight: F) { +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; @@ -174,7 +174,7 @@ pub fn fold(values: &mut Vec, weight: F) { } /// Two-pass fold-then-compute; reference version kept for testing. -pub fn fold_and_compute_polynomial(a: &mut Vec, b: &mut Vec, weight: F) -> (F, F) { +pub fn fold_and_compute_polynomial(a: &mut Vec, b: &mut Vec, weight: F) -> (F, F) { fold(a, weight); fold(b, weight); compute_sumcheck_polynomial(a, b) @@ -190,7 +190,7 @@ pub fn fold_and_compute_polynomial(a: &mut Vec, b: &mut Vec, wei /// /// Falls back to the unfused path for small or non-pow2 inputs so the /// implicit-zero tail accounting stays identical. -pub fn fused_fold_and_compute_polynomial( +pub fn fused_fold_and_compute_polynomial( a: &mut Vec, b: &mut Vec, weight: F, @@ -202,7 +202,7 @@ pub fn fused_fold_and_compute_polynomial( } #[allow(clippy::too_many_arguments)] - fn kernel( + fn kernel( a0: &mut [F], a1: &mut [F], a2: &[F], @@ -304,7 +304,7 @@ pub fn inner_product_sumcheck_partial( mut hook: H, ) -> ProductSumcheck where - F: Field, + F: SumcheckField, T: ProverTranscript, H: FnMut(usize, &mut T), { @@ -364,7 +364,7 @@ pub fn inner_product_sumcheck( hook: H, ) -> ProductSumcheck where - F: Field, + F: SumcheckField, T: ProverTranscript, H: FnMut(usize, &mut T), { diff --git a/src/multilinear_sumcheck.rs b/src/multilinear_sumcheck.rs index 8134c20e..05592b08 100644 --- a/src/multilinear_sumcheck.rs +++ b/src/multilinear_sumcheck.rs @@ -17,7 +17,7 @@ //! 4 reads + 2 writes per quadruple (fused) vs. 6 reads + 2 writes //! (fold + compute separately) — a ~33% memory-traffic reduction. -use ark_ff::Field; +use crate::field::SumcheckField; #[cfg(feature = "parallel")] use rayon::join; #[cfg(feature = "parallel")] @@ -27,7 +27,7 @@ use crate::transcript::ProverTranscript; /// Legacy return type for `multilinear_sumcheck`. #[derive(Debug)] -pub struct Sumcheck { +pub struct Sumcheck { pub prover_messages: Vec<(F, F)>, pub verifier_messages: Vec, pub final_evaluation: F, @@ -60,7 +60,7 @@ const fn workload_size() -> usize { // ─── Scalar helpers ───────────────────────────────────────────────────────── -fn sum_slice(v: &[F]) -> F { +fn sum_slice(v: &[F]) -> F { #[cfg(feature = "parallel")] if v.len() > workload_size::() { return v.par_iter().copied().sum(); @@ -68,7 +68,7 @@ fn sum_slice(v: &[F]) -> F { v.iter().copied().sum() } -fn scalar_mul(v: &mut [F], w: F) { +fn scalar_mul(v: &mut [F], w: F) { for x in v.iter_mut() { *x *= w; } @@ -81,8 +81,8 @@ fn scalar_mul(v: &mut [F], w: F) { /// `values` is implicitly zero-extended to the next power of two. /// - `s0 = Σ v[0..L/2]` (low half, possibly with tail contributions) /// - `s1 = Σ v[L/2..L]` -pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { - fn recurse(lo: &[F], hi: &[F]) -> (F, F) { +pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { + fn recurse(lo: &[F], hi: &[F]) -> (F, F) { debug_assert_eq!(lo.len(), hi.len()); #[cfg(feature = "parallel")] @@ -127,7 +127,7 @@ pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { /// /// SIMD-accelerated for Goldilocks base field on NEON and AVX-512 IFMA. /// Falls back to a scalar recursive `rayon::join` fold for other fields. -pub fn fold(values: &mut Vec, weight: F) { +pub fn fold(values: &mut Vec, weight: F) { // SIMD fast path for base-field Goldilocks (MSB layout). #[cfg(all( feature = "simd", @@ -142,7 +142,7 @@ pub fn fold(values: &mut Vec, weight: F) { return; } } - fn recurse_both(low: &mut [F], high: &[F], 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; @@ -176,7 +176,7 @@ pub fn fold(values: &mut Vec, weight: F) { } /// Two-pass fold-then-compute. Reference only. -pub fn fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { +pub fn fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { fold(values, weight); compute_sumcheck_polynomial(values) } @@ -184,13 +184,13 @@ pub fn fold_and_compute_polynomial(values: &mut Vec, weight: F) -> /// Fused fold + compute: folds `values` by `weight` *and* returns the /// next-round `(s0, s1)` in one sweep over the quadruple /// `(v[k], v[k+L/4], v[k+L/2], v[k+3L/4])`. -pub fn fused_fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { +pub fn fused_fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { let l = values.len(); if !l.is_power_of_two() || l < 4 { return fold_and_compute_polynomial(values, weight); } - fn kernel(v0: &mut [F], v1: &mut [F], v2: &[F], v3: &[F], weight: F) -> (F, F) { + fn kernel(v0: &mut [F], v1: &mut [F], v2: &[F], v3: &[F], weight: F) -> (F, F) { debug_assert_eq!(v0.len(), v1.len()); debug_assert_eq!(v0.len(), v2.len()); debug_assert_eq!(v0.len(), v3.len()); @@ -258,7 +258,7 @@ pub fn multilinear_sumcheck_partial( mut hook: H, ) -> Sumcheck where - F: Field, + F: SumcheckField, T: ProverTranscript, H: FnMut(usize, &mut T), { @@ -314,7 +314,7 @@ pub fn multilinear_sumcheck( hook: H, ) -> Sumcheck where - F: Field, + F: SumcheckField, T: ProverTranscript, H: FnMut(usize, &mut T), { diff --git a/src/provers/coefficient.rs b/src/provers/coefficient.rs index afb30378..bd794843 100644 --- a/src/provers/coefficient.rs +++ b/src/provers/coefficient.rs @@ -6,7 +6,7 @@ //! For sequential streaming (Jolt-style), use //! [`CoefficientProverLSB`](super::coefficient_lsb::CoefficientProverLSB). -use ark_ff::Field; +use crate::field::SumcheckField; use crate::coefficient_sumcheck::RoundPolyEvaluator; use crate::sumcheck_prover::SumcheckProver; @@ -15,7 +15,7 @@ use crate::sumcheck_prover::SumcheckProver; use rayon::prelude::*; /// MSB coefficient sumcheck prover (arbitrary degree d, half-split layout). -pub struct CoefficientProver<'a, F: Field, E: RoundPolyEvaluator> { +pub struct CoefficientProver<'a, F: SumcheckField, E: RoundPolyEvaluator> { evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>, @@ -24,7 +24,7 @@ pub struct CoefficientProver<'a, F: Field, E: RoundPolyEvaluator> { deg: usize, } -impl<'a, F: Field, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> { +impl<'a, F: SumcheckField, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> { pub fn new(evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>) -> Self { let n_tw = tablewise.len(); let n_pw = pairwise.len(); @@ -128,7 +128,7 @@ impl<'a, F: Field, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> { // ─── MSB fold helpers ────────────────────────────────────────────────────── /// In-place MSB fold for a flat vector: `new[k] = v[k] + c*(v[k+half] - v[k])`. -fn msb_fold_vec(v: &mut Vec, challenge: F) { +fn msb_fold_vec(v: &mut Vec, challenge: F) { if v.len() <= 1 { return; } @@ -141,7 +141,7 @@ fn msb_fold_vec(v: &mut Vec, challenge: F) { /// MSB fold for tablewise: each row-vector is folded by pairing /// `(table[k], table[k+half])` and producing a new row. -fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { +fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { if table.len() <= 1 { return; } @@ -162,7 +162,7 @@ fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { // ─── MSB evaluate helpers ────────────────────────────────────────────────── /// MSB pairing: pair index `k` with `k + half` (not `2k` with `2k+1`). -fn msb_sequential_evaluate_into( +fn msb_sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -189,7 +189,7 @@ fn msb_sequential_evaluate_into( } #[cfg(feature = "parallel")] -fn msb_parallel_evaluate( +fn msb_parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -222,7 +222,7 @@ fn msb_parallel_evaluate( } #[cfg(not(feature = "parallel"))] -fn msb_parallel_evaluate( +fn msb_parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -247,7 +247,7 @@ fn msb_parallel_evaluate( // ─── Horner evaluation ───────────────────────────────────────────────────── #[inline] -fn eval_poly_at(coeffs: &[F], x: F) -> F { +fn eval_poly_at(coeffs: &[F], x: F) -> F { if coeffs.is_empty() { return F::ZERO; } @@ -260,10 +260,9 @@ fn eval_poly_at(coeffs: &[F], x: F) -> F { // ─── SumcheckProver impl ─────────────────────────────────────────────────── -#[cfg(feature = "arkworks")] impl<'a, F, E> SumcheckProver for CoefficientProver<'a, F, E> where - F: ark_ff::Field, + F: SumcheckField, E: RoundPolyEvaluator, { fn degree(&self) -> usize { @@ -289,7 +288,7 @@ where evals.push(eval_poly_at(&coeffs, F::ZERO)); // h(0) = coeffs[0] evals.push(coeffs[d]); // h(∞) = leading coefficient for i in 2..d { - evals.push(eval_poly_at(&coeffs, F::from(i as u64))); // h(i) + evals.push(eval_poly_at(&coeffs, F::from_u64(i as u64))); // h(i) } evals } diff --git a/src/provers/coefficient_lsb.rs b/src/provers/coefficient_lsb.rs index 98977efa..0b17e08f 100644 --- a/src/provers/coefficient_lsb.rs +++ b/src/provers/coefficient_lsb.rs @@ -8,7 +8,7 @@ //! workloads, prefer [`CoefficientProver`](super::coefficient::CoefficientProver) //! (MSB layout). -use ark_ff::Field; +use crate::field::SumcheckField; use crate::coefficient_sumcheck::RoundPolyEvaluator; use crate::reductions::{pairwise, tablewise}; @@ -34,7 +34,7 @@ use rayon::prelude::*; /// ); /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// ``` -pub struct CoefficientProverLSB<'a, F: Field, E: RoundPolyEvaluator> { +pub struct CoefficientProverLSB<'a, F: SumcheckField, E: RoundPolyEvaluator> { evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>, @@ -47,7 +47,7 @@ pub struct CoefficientProverLSB<'a, F: Field, E: RoundPolyEvaluator> { is_degree1_simd_path: bool, } -impl<'a, F: Field, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, E> { +impl<'a, F: SumcheckField, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, E> { pub fn new(evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>) -> Self { let n_tw = tablewise.len(); let n_pw = pairwise.len(); @@ -168,10 +168,9 @@ impl<'a, F: Field, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, E> { // ─── SumcheckProver impl ─────────────────────────────────────────────────── -#[cfg(feature = "arkworks")] impl<'a, F, E> SumcheckProver for CoefficientProverLSB<'a, F, E> where - F: ark_ff::Field, + F: SumcheckField, E: RoundPolyEvaluator, { fn degree(&self) -> usize { @@ -198,7 +197,7 @@ where evals.push(eval_poly_at(&coeffs, F::ZERO)); // h(0) = coeffs[0] evals.push(coeffs[d]); // h(∞) = leading coefficient for i in 2..d { - evals.push(eval_poly_at(&coeffs, F::from(i as u64))); // h(i) + evals.push(eval_poly_at(&coeffs, F::from_u64(i as u64))); // h(i) } evals } @@ -241,7 +240,7 @@ where /// Evaluate polynomial with coefficients `coeffs` at point `x` via Horner's method. #[inline] -fn eval_poly_at(coeffs: &[F], x: F) -> F { +fn eval_poly_at(coeffs: &[F], x: F) -> F { if coeffs.is_empty() { return F::ZERO; } @@ -254,7 +253,7 @@ fn eval_poly_at(coeffs: &[F], x: F) -> F { // ─── Evaluate strategies (same as coefficient_sumcheck.rs) ───────────────── -fn simd_evaluate_degree1(pw: &[F]) -> Vec { +fn simd_evaluate_degree1(pw: &[F]) -> Vec { #[cfg(all( feature = "simd", any( @@ -276,7 +275,7 @@ fn simd_evaluate_degree1(pw: &[F]) -> Vec { vec![s0, s1 - s0] } -fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: F) -> Option> { +fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: F) -> Option> { #[cfg(all( feature = "simd", any( @@ -301,7 +300,7 @@ fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: F) -> Op } #[cfg(feature = "parallel")] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -334,7 +333,7 @@ fn parallel_evaluate( } #[cfg(not(feature = "parallel"))] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -356,7 +355,7 @@ fn parallel_evaluate( coeffs } -fn sequential_evaluate_into( +fn sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], diff --git a/src/provers/eq_factored.rs b/src/provers/eq_factored.rs index 46dea528..eb30ac6b 100644 --- a/src/provers/eq_factored.rs +++ b/src/provers/eq_factored.rs @@ -240,10 +240,9 @@ pub(crate) fn build_eq_table(w: &[F]) -> Vec { table } -#[cfg(feature = "arkworks")] impl SumcheckProver for EqFactoredProver where - F: ark_ff::Field, + F: SumcheckField, { fn degree(&self) -> usize { 2 diff --git a/src/provers/gkr.rs b/src/provers/gkr.rs index 31e9ba5a..abda053c 100644 --- a/src/provers/gkr.rs +++ b/src/provers/gkr.rs @@ -96,10 +96,9 @@ impl GkrProver { } } -#[cfg(feature = "arkworks")] impl SumcheckProver for GkrProver where - F: ark_ff::Field, + F: SumcheckField, { fn degree(&self) -> usize { 2 @@ -177,7 +176,7 @@ where // Convert {q(0), q(1), q(2)} → {q(0), q(∞)}. // q(∞) = (q(0) + q(2) − 2·q(1)) / 2 - let two_inv = F::from(2u64) + let two_inv = F::from_u64(2) .inverse() .expect("field characteristic must not be 2"); let q_inf = (q0 + q2 - q1.double()) * two_inv; diff --git a/src/provers/inner_product.rs b/src/provers/inner_product.rs index aaef9964..e68459bb 100644 --- a/src/provers/inner_product.rs +++ b/src/provers/inner_product.rs @@ -49,13 +49,9 @@ impl InnerProductProver { } } -// NOTE: The `ark_ff::Field` bound is temporary — required because the -// underlying functions in `inner_product_sumcheck.rs` use `F: Field`. -// It will be removed when those functions are ported to `SumcheckField`. -#[cfg(feature = "arkworks")] impl SumcheckProver for InnerProductProver where - F: ark_ff::Field, + F: SumcheckField, { fn degree(&self) -> usize { 2 diff --git a/src/provers/inner_product_lsb.rs b/src/provers/inner_product_lsb.rs index 14267bf4..46a9c9a3 100644 --- a/src/provers/inner_product_lsb.rs +++ b/src/provers/inner_product_lsb.rs @@ -10,7 +10,6 @@ extern crate alloc; use crate::field::SumcheckField; -#[cfg(feature = "arkworks")] use crate::sumcheck_prover::SumcheckProver; use alloc::vec::Vec; @@ -147,10 +146,9 @@ fn fused_fold_and_compute_lsb( // ─── SumcheckProver impl ─────────────────────────────────────────────────── -#[cfg(feature = "arkworks")] impl SumcheckProver for InnerProductProverLSB where - F: ark_ff::Field, + F: SumcheckField, { fn degree(&self) -> usize { 2 diff --git a/src/provers/mod.rs b/src/provers/mod.rs index 2e27fc2c..30e00b84 100644 --- a/src/provers/mod.rs +++ b/src/provers/mod.rs @@ -1,17 +1,11 @@ //! Concrete [`SumcheckProver`](crate::sumcheck_prover::SumcheckProver) //! implementations for each polynomial shape. -#[cfg(feature = "arkworks")] pub mod coefficient; -#[cfg(feature = "arkworks")] pub mod coefficient_lsb; -#[cfg(feature = "arkworks")] pub mod eq_factored; -#[cfg(feature = "arkworks")] pub mod gkr; -#[cfg(feature = "arkworks")] pub mod inner_product; pub mod inner_product_lsb; -#[cfg(feature = "arkworks")] pub mod multilinear; pub mod multilinear_lsb; diff --git a/src/provers/multilinear.rs b/src/provers/multilinear.rs index 7ba46c7f..9f4d5443 100644 --- a/src/provers/multilinear.rs +++ b/src/provers/multilinear.rs @@ -46,13 +46,9 @@ impl MultilinearProver { } } -// NOTE: The `ark_ff::Field` bound is temporary — required because the -// underlying functions in `multilinear_sumcheck.rs` use `F: Field`. -// It will be removed when those functions are ported to `SumcheckField`. -#[cfg(feature = "arkworks")] impl SumcheckProver for MultilinearProver where - F: ark_ff::Field, + F: SumcheckField, { fn degree(&self) -> usize { 1 diff --git a/src/reductions/pairwise.rs b/src/reductions/pairwise.rs index 0de86c99..0ed6af51 100644 --- a/src/reductions/pairwise.rs +++ b/src/reductions/pairwise.rs @@ -1,3 +1,4 @@ +use crate::field::SumcheckField; use ark_ff::Field; use ark_std::vec::Vec; use ark_std::{cfg_chunks, cfg_into_iter}; @@ -9,7 +10,7 @@ use rayon::{ use crate::streams::Stream; -pub fn evaluate(src: &[F]) -> (F, F) { +pub fn evaluate(src: &[F]) -> (F, F) { let even_sum = cfg_into_iter!(0..src.len()) .step_by(2) .map(|i| src[i]) @@ -34,7 +35,7 @@ pub fn evaluate_from_stream>(src: &S) -> (F, F) { (even_sum, odd_sum) } -pub fn reduce_evaluations(src: &mut Vec, verifier_message: F) { +pub fn reduce_evaluations(src: &mut Vec, verifier_message: F) { /// Below this input size, the serial in-place path wins: rayon's /// fork/join overhead exceeds the actual compute, and we avoid the /// `.collect()` allocation entirely. Above it, parallelism outpaces @@ -92,7 +93,7 @@ pub fn reduce_evaluations_from_stream>( /// round polynomial `q(x) = a + bx + cx²`: /// - `a = Σ f_even · g_even` /// - `b = Σ (f_even · g_odd + f_odd · g_even)` -pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { +pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { let half_len = src[0].len() / 2; let a: F = cfg_into_iter!(0..half_len) .map(|k| { @@ -112,7 +113,7 @@ pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { /// Cross-field reduce: fold `BF` evaluations with an `EF` challenge, producing `Vec`. /// /// For each adjacent pair `(a, b)` in `src`: `EF::from(a) + challenge * (EF::from(b) - EF::from(a))`. -pub fn cross_field_reduce>(src: &[BF], challenge: EF) -> Vec { +pub fn cross_field_reduce>(src: &[BF], challenge: EF) -> Vec { cfg_chunks!(src, 2) .map(|chunk| { let a = EF::from(chunk[0]); diff --git a/src/reductions/tablewise.rs b/src/reductions/tablewise.rs index 34d388b1..0bb8930b 100644 --- a/src/reductions/tablewise.rs +++ b/src/reductions/tablewise.rs @@ -1,9 +1,9 @@ -use ark_ff::Field; +use crate::field::SumcheckField; use ark_std::{cfg_chunks, vec::Vec}; #[cfg(feature = "parallel")] use rayon::{iter::ParallelIterator, prelude::ParallelSlice}; -pub fn reduce_evaluations(src: &mut Vec>, verifier_message: F) { +pub fn reduce_evaluations(src: &mut Vec>, verifier_message: F) { let out: Vec> = cfg_chunks!(src, 2) .map(|chunk| { chunk[0] From 4e864b57082290394aff1b65ae0d47f825ff45b3 Mon Sep 17 00:00:00 2001 From: Giacomo Fenzi Date: Tue, 19 May 2026 09:20:41 +0200 Subject: [PATCH 2/5] fmt --- src/coefficient_sumcheck.rs | 12 +++++++++--- src/inner_product_sumcheck.rs | 6 +++++- src/multilinear_sumcheck.rs | 13 +++++++++++-- src/provers/coefficient_lsb.rs | 5 ++++- src/reductions/pairwise.rs | 5 ++++- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/coefficient_sumcheck.rs b/src/coefficient_sumcheck.rs index 89e56476..49599a89 100644 --- a/src/coefficient_sumcheck.rs +++ b/src/coefficient_sumcheck.rs @@ -1,5 +1,5 @@ -use ark_ff::Field; use crate::field::SumcheckField; +use ark_ff::Field; use ark_poly::univariate::DensePolynomial; #[cfg(feature = "parallel")] @@ -129,7 +129,10 @@ fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: F) -> Option> { +fn try_simd_fused_reduce_evaluate( + pw: &mut Vec, + challenge: F, +) -> Option> { crate::simd_sumcheck::dispatch::try_simd_fused_reduce_evaluate_degree1(pw, challenge) } @@ -140,7 +143,10 @@ fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: all(target_arch = "x86_64", target_feature = "avx512ifma") ) )))] -fn try_simd_fused_reduce_evaluate(_pw: &mut Vec, _challenge: F) -> Option> { +fn try_simd_fused_reduce_evaluate( + _pw: &mut Vec, + _challenge: F, +) -> Option> { None } diff --git a/src/inner_product_sumcheck.rs b/src/inner_product_sumcheck.rs index 1a82f4c9..1257f5b8 100644 --- a/src/inner_product_sumcheck.rs +++ b/src/inner_product_sumcheck.rs @@ -174,7 +174,11 @@ pub fn fold(values: &mut Vec, weight: F) { } /// Two-pass fold-then-compute; reference version kept for testing. -pub fn fold_and_compute_polynomial(a: &mut Vec, b: &mut Vec, weight: F) -> (F, F) { +pub fn fold_and_compute_polynomial( + a: &mut Vec, + b: &mut Vec, + weight: F, +) -> (F, F) { fold(a, weight); fold(b, weight); compute_sumcheck_polynomial(a, b) diff --git a/src/multilinear_sumcheck.rs b/src/multilinear_sumcheck.rs index 05592b08..db11c639 100644 --- a/src/multilinear_sumcheck.rs +++ b/src/multilinear_sumcheck.rs @@ -184,13 +184,22 @@ pub fn fold_and_compute_polynomial(values: &mut Vec, weight /// Fused fold + compute: folds `values` by `weight` *and* returns the /// next-round `(s0, s1)` in one sweep over the quadruple /// `(v[k], v[k+L/4], v[k+L/2], v[k+3L/4])`. -pub fn fused_fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { +pub fn fused_fold_and_compute_polynomial( + values: &mut Vec, + weight: F, +) -> (F, F) { let l = values.len(); if !l.is_power_of_two() || l < 4 { return fold_and_compute_polynomial(values, weight); } - fn kernel(v0: &mut [F], v1: &mut [F], v2: &[F], v3: &[F], weight: F) -> (F, F) { + fn kernel( + v0: &mut [F], + v1: &mut [F], + v2: &[F], + v3: &[F], + weight: F, + ) -> (F, F) { debug_assert_eq!(v0.len(), v1.len()); debug_assert_eq!(v0.len(), v2.len()); debug_assert_eq!(v0.len(), v3.len()); diff --git a/src/provers/coefficient_lsb.rs b/src/provers/coefficient_lsb.rs index 0b17e08f..7b55c59c 100644 --- a/src/provers/coefficient_lsb.rs +++ b/src/provers/coefficient_lsb.rs @@ -275,7 +275,10 @@ fn simd_evaluate_degree1(pw: &[F]) -> Vec { vec![s0, s1 - s0] } -fn try_simd_fused_reduce_evaluate(pw: &mut Vec, challenge: F) -> Option> { +fn try_simd_fused_reduce_evaluate( + pw: &mut Vec, + challenge: F, +) -> Option> { #[cfg(all( feature = "simd", any( diff --git a/src/reductions/pairwise.rs b/src/reductions/pairwise.rs index 0ed6af51..430a9a05 100644 --- a/src/reductions/pairwise.rs +++ b/src/reductions/pairwise.rs @@ -113,7 +113,10 @@ pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { /// Cross-field reduce: fold `BF` evaluations with an `EF` challenge, producing `Vec`. /// /// For each adjacent pair `(a, b)` in `src`: `EF::from(a) + challenge * (EF::from(b) - EF::from(a))`. -pub fn cross_field_reduce>(src: &[BF], challenge: EF) -> Vec { +pub fn cross_field_reduce>( + src: &[BF], + challenge: EF, +) -> Vec { cfg_chunks!(src, 2) .map(|chunk| { let a = EF::from(chunk[0]); From 187c56aa92c2773e56d1d79ce5272c8b1d6bf379 Mon Sep 17 00:00:00 2001 From: Giacomo Fenzi Date: Tue, 19 May 2026 09:33:49 +0200 Subject: [PATCH 3/5] fix no default --- src/inner_product_sumcheck.rs | 2 ++ src/lib.rs | 4 ---- src/multilinear_sumcheck.rs | 2 ++ src/provers/eq_factored.rs | 4 +--- src/provers/gkr.rs | 4 +--- src/provers/inner_product.rs | 1 + src/provers/inner_product_lsb.rs | 3 +-- src/provers/mod.rs | 2 ++ src/provers/multilinear.rs | 1 + src/provers/multilinear_lsb.rs | 4 +--- 10 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/inner_product_sumcheck.rs b/src/inner_product_sumcheck.rs index 1257f5b8..9fa31379 100644 --- a/src/inner_product_sumcheck.rs +++ b/src/inner_product_sumcheck.rs @@ -20,6 +20,7 @@ //! simultaneously. use crate::field::SumcheckField; +use alloc::vec::Vec; #[cfg(feature = "parallel")] use rayon::join; #[cfg(feature = "parallel")] @@ -38,6 +39,7 @@ pub struct ProductSumcheck { // ─── Workload threshold ───────────────────────────────────────────────────── /// Target single-thread workload size for `T`. Close to L1 cache. +#[cfg(feature = "parallel")] const fn workload_size() -> usize { #[cfg(all(target_arch = "aarch64", target_os = "macos"))] const CACHE_SIZE: usize = 1 << 17; diff --git a/src/lib.rs b/src/lib.rs index 0c73fdc2..509557ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,16 +45,12 @@ pub mod transcript; // ─── Arkworks-dependent modules ───────────────────────────────────────────── -#[cfg(feature = "arkworks")] mod inner_product_sumcheck; -#[cfg(feature = "arkworks")] mod multilinear_sumcheck; -#[cfg(feature = "arkworks")] pub use inner_product_sumcheck::{ inner_product_sumcheck, inner_product_sumcheck_partial, ProductSumcheck, }; -#[cfg(feature = "arkworks")] pub use multilinear_sumcheck::{ compute_sumcheck_polynomial, fold, fused_fold_and_compute_polynomial, multilinear_sumcheck, multilinear_sumcheck_partial, Sumcheck, diff --git a/src/multilinear_sumcheck.rs b/src/multilinear_sumcheck.rs index db11c639..8b3b598a 100644 --- a/src/multilinear_sumcheck.rs +++ b/src/multilinear_sumcheck.rs @@ -18,6 +18,7 @@ //! (fold + compute separately) — a ~33% memory-traffic reduction. use crate::field::SumcheckField; +use alloc::vec::Vec; #[cfg(feature = "parallel")] use rayon::join; #[cfg(feature = "parallel")] @@ -35,6 +36,7 @@ pub struct Sumcheck { // ─── Workload threshold ───────────────────────────────────────────────────── +#[cfg(feature = "parallel")] const fn workload_size() -> usize { #[cfg(all(target_arch = "aarch64", target_os = "macos"))] const CACHE_SIZE: usize = 1 << 17; diff --git a/src/provers/eq_factored.rs b/src/provers/eq_factored.rs index eb30ac6b..a3492f4f 100644 --- a/src/provers/eq_factored.rs +++ b/src/provers/eq_factored.rs @@ -43,9 +43,7 @@ use crate::field::SumcheckField; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; -extern crate alloc; -use alloc::vec; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; /// Eq-factored sumcheck prover for `∑_x eq(w, x) · p(x)` (degree 2). /// diff --git a/src/provers/gkr.rs b/src/provers/gkr.rs index abda053c..cbd225ae 100644 --- a/src/provers/gkr.rs +++ b/src/provers/gkr.rs @@ -33,9 +33,7 @@ use crate::field::SumcheckField; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; -extern crate alloc; -use alloc::vec; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; /// GKR round sumcheck prover (degree 2). /// diff --git a/src/provers/inner_product.rs b/src/provers/inner_product.rs index e68459bb..391a9260 100644 --- a/src/provers/inner_product.rs +++ b/src/provers/inner_product.rs @@ -5,6 +5,7 @@ use crate::field::SumcheckField; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; +use alloc::{vec, vec::Vec}; /// Inner-product sumcheck prover (degree 2). /// diff --git a/src/provers/inner_product_lsb.rs b/src/provers/inner_product_lsb.rs index 46a9c9a3..e2c0ee1b 100644 --- a/src/provers/inner_product_lsb.rs +++ b/src/provers/inner_product_lsb.rs @@ -8,10 +8,9 @@ //! workloads, prefer [`InnerProductProver`](super::inner_product::InnerProductProver) //! (MSB layout). -extern crate alloc; use crate::field::SumcheckField; use crate::sumcheck_prover::SumcheckProver; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; /// LSB inner-product sumcheck prover (degree 2, pair-split layout). /// diff --git a/src/provers/mod.rs b/src/provers/mod.rs index 30e00b84..a7fdadcc 100644 --- a/src/provers/mod.rs +++ b/src/provers/mod.rs @@ -1,7 +1,9 @@ //! Concrete [`SumcheckProver`](crate::sumcheck_prover::SumcheckProver) //! implementations for each polynomial shape. +#[cfg(feature = "arkworks")] pub mod coefficient; +#[cfg(feature = "arkworks")] pub mod coefficient_lsb; pub mod eq_factored; pub mod gkr; diff --git a/src/provers/multilinear.rs b/src/provers/multilinear.rs index 9f4d5443..656a7f83 100644 --- a/src/provers/multilinear.rs +++ b/src/provers/multilinear.rs @@ -8,6 +8,7 @@ use crate::multilinear_sumcheck::{ compute_sumcheck_polynomial, fold, fused_fold_and_compute_polynomial, }; use crate::sumcheck_prover::SumcheckProver; +use alloc::{vec, vec::Vec}; /// Multilinear sumcheck prover (degree 1). /// diff --git a/src/provers/multilinear_lsb.rs b/src/provers/multilinear_lsb.rs index bde98848..329fb8f3 100644 --- a/src/provers/multilinear_lsb.rs +++ b/src/provers/multilinear_lsb.rs @@ -9,11 +9,9 @@ //! workloads, prefer [`MultilinearProver`](super::multilinear::MultilinearProver) //! (MSB layout). -extern crate alloc; use crate::field::SumcheckField; use crate::sumcheck_prover::SumcheckProver; -use alloc::vec; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; #[cfg(feature = "parallel")] use rayon::prelude::*; From 6bb0fbc9ffa4f5f4296ca1603f8b5663ac703383 Mon Sep 17 00:00:00 2001 From: Giacomo Fenzi Date: Wed, 20 May 2026 16:50:38 +0200 Subject: [PATCH 4/5] Rename --- CHANGELOG.md | 2 +- SECURITY.md | 4 ++-- docs/compatibility.md | 16 ++++++++-------- docs/design.md | 10 +++++----- docs/slides.md | 20 ++++++++++---------- src/coefficient_sumcheck.rs | 18 +++++++++--------- src/field.rs | 18 +++++++++--------- src/inner_product_sumcheck.rs | 26 +++++++++++++------------- src/lib.rs | 2 +- src/multilinear_sumcheck.rs | 26 +++++++++++++------------- src/polynomial/dense.rs | 8 ++++---- src/polynomial/eval.rs | 12 ++++++------ src/polynomial/mod.rs | 2 +- src/polynomial/sequential_lagrange.rs | 6 +++--- src/proof.rs | 4 ++-- src/provers/coefficient.rs | 20 ++++++++++---------- src/provers/coefficient_lsb.rs | 20 ++++++++++---------- src/provers/eq_factored.rs | 10 +++++----- src/provers/gkr.rs | 8 ++++---- src/provers/inner_product.rs | 8 ++++---- src/provers/inner_product_lsb.rs | 14 +++++++------- src/provers/multilinear.rs | 8 ++++---- src/provers/multilinear_lsb.rs | 14 +++++++------- src/reductions/pairwise.rs | 10 +++++----- src/reductions/tablewise.rs | 4 ++-- src/runner.rs | 4 ++-- src/simd_sumcheck/dispatch.rs | 24 ++++++++++++------------ src/sumcheck_prover.rs | 4 ++-- src/transcript/sanity.rs | 6 +++--- src/verifier.rs | 10 +++++----- tests/plonky3_roundtrip.rs | 8 ++++---- 31 files changed, 173 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d786cacf..8b534fd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ Major revision: unified API, one verifier, one proof type, 7 provers, SIMD accel - **`SumcheckProver` trait** — single extension point for all polynomial shapes. - **7 concrete provers** — `MultilinearProver`, `InnerProductProver`, `CoefficientProver` (each with MSB + LSB variants), `GkrProver`. -- **`SumcheckField` trait** — generic field interface; blanket impl for `ark_ff::Field` behind `feature = "arkworks"`. +- **`SumcheckRing` trait** — generic field interface; blanket impl for `ark_ff::Field` behind `feature = "arkworks"`. - **`SimdRepr` trait** — safe SIMD opt-in with `zerocopy` layout verification. - **`runner::sumcheck()`** — single runner with partial execution and per-round hooks. - **Eq polynomial utilities** — `eq_poly`, `eq_poly_non_binary`, O(2^v) incremental `compute_hypercube_eq_evals`. diff --git a/SECURITY.md b/SECURITY.md index 78a857e6..fd8bb5ba 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -19,7 +19,7 @@ verifier challenges. This library implements plain (non-ZK) sumcheck. side-channel adversaries has not been formally verified**. Fixed-size Montgomery multiplication is inherently data-independent, but this has not been audited, and no constant-time claim is made for arbitrary - `SumcheckField` implementations. Callers in that threat model must + `SumcheckRing` implementations. Callers in that threat model must supply constant-time field operations. ## Oracle check @@ -56,7 +56,7 @@ SIMD subsystem, `unsafe` is confined to two categories: evaluate/reduce loops that call them. 2. **Field ↔ `u64` reinterpretation** — arkworks field types do not yet derive - `zerocopy`, so the blanket `SumcheckField` impl for `ark_ff::Field` uses + `zerocopy`, so the blanket `SumcheckRing` impl for `ark_ff::Field` uses `transmute_copy` and `from_raw_parts` to reinterpret Goldilocks elements as their underlying Montgomery-form `u64` values. These are centralized in five trait methods (`_to_raw_u64`, `_from_raw_u64`, `_as_u64_slice`, diff --git a/docs/compatibility.md b/docs/compatibility.md index f8b8e221..fa7fc9b0 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -1,13 +1,13 @@ # Non-arkworks field support -By default, the library provides a blanket `SumcheckField` implementation for +By default, the library provides a blanket `SumcheckRing` implementation for all `ark_ff::Field` types. Non-arkworks users can compile with `--no-default-features` and implement the trait for their own field type. -## `SumcheckField` trait +## `SumcheckRing` trait ```rust -pub trait SumcheckField: +pub trait SumcheckRing: Copy + Send + Sync + PartialEq + Debug + Add + Sub + Mul + Neg + AddAssign + SubAssign + MulAssign + Sum + 'static @@ -23,7 +23,7 @@ pub trait SumcheckField: See [`tests/plonky3_roundtrip.rs`](../tests/plonky3_roundtrip.rs) for a complete working example — a newtype wrapper around `p3_goldilocks::Goldilocks` that -implements `SumcheckField` and runs a full prove + verify roundtrip with no +implements `SumcheckRing` and runs a full prove + verify roundtrip with no arkworks dependency. ## SIMD opt-in via `SimdRepr` @@ -38,7 +38,7 @@ compile-time layout verification — no `unsafe` needed from the implementor. #[repr(transparent)] struct MyGoldilocks(u64); -impl SumcheckField for MyGoldilocks { +impl SumcheckRing for MyGoldilocks { const ZERO: Self = MyGoldilocks(0); const ONE: Self = MyGoldilocks(1); // Montgomery form of 1 fn from_u64(val: u64) -> Self { /* ... */ } @@ -61,7 +61,7 @@ Extension fields work the same way: #[repr(transparent)] struct MyExt3([u64; 3]); -impl SumcheckField for MyExt3 { +impl SumcheckRing for MyExt3 { fn extension_degree() -> u64 { 3 } fn _simd_field_config() -> Option { Some(SimdFieldConfig { modulus: GOLDILOCKS_P, element_bytes: 8 }) @@ -83,6 +83,6 @@ arkworks = ["ark-ff", "ark-poly", "ark-serialize", "ark-std", "spongefish"] parallel = ["rayon"] ``` -- `arkworks` (default): blanket `SumcheckField` impl for `ark_ff::Field` +- `arkworks` (default): blanket `SumcheckRing` impl for `ark_ff::Field` - `parallel` (default): rayon parallelism for fold and round computation -- `--no-default-features`: pure `SumcheckField` library, no arkworks dependency +- `--no-default-features`: pure `SumcheckRing` library, no arkworks dependency diff --git a/docs/design.md b/docs/design.md index 09ef17e0..efc6142c 100644 --- a/docs/design.md +++ b/docs/design.md @@ -64,7 +64,7 @@ runner parameterized by a prover trait, not three separate functions. /// Implementors define how the round polynomial g_j is computed /// from the prover's internal state. The protocol runner calls /// `round()` once per round, then the caller inspects post-state. -pub trait SumcheckProver { +pub trait SumcheckProver { /// Degree of g_j in the current variable X_j. fn degree(&self) -> usize; @@ -191,12 +191,12 @@ how `round()` computes the polynomial from the data. ```rust // In-memory (MSB, time strategy). -impl MultilinearProver { +impl MultilinearProver { pub fn new(evals: Vec) -> Self; } // Streaming (LSB or MSB, blendy strategy). -impl StreamingMultilinearProver { +impl StreamingMultilinearProver { /// Random-access stream, MSB ordering. Best for mmap'd data. pub fn new_msb>(stream: S, k: usize) -> Self; @@ -277,7 +277,7 @@ trait, whose memory layout guarantee is enforced at compile time by ```rust pub trait SimdRepr: - SumcheckField + zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::Immutable + SumcheckRing + zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::Immutable { fn modulus() -> u64; } @@ -297,7 +297,7 @@ impl SimdRepr for JoltGoldilocks { } ``` -Arkworks types bypass `SimdRepr` — the blanket `SumcheckField` impl +Arkworks types bypass `SimdRepr` — the blanket `SumcheckRing` impl auto-detects Goldilocks from `BasePrimeField::MODULUS` and the detection is const-folded by LLVM. diff --git a/docs/slides.md b/docs/slides.md index c9bfaac7..7d559047 100644 --- a/docs/slides.md +++ b/docs/slides.md @@ -105,7 +105,7 @@ This motivates **one runner + one trait**, not three functions. ## The Prover Trait ```rust -pub trait SumcheckProver { +pub trait SumcheckProver { fn degree(&self) -> usize; fn round(&mut self, challenge: Option) -> Vec; fn finalize(&mut self, last_challenge: F); @@ -129,7 +129,7 @@ final_value() -> g(r_0, ..., r_{v-1}) // oracle value ## The Protocol Runner ```rust -pub fn sumcheck>( +pub fn sumcheck>( prover: &mut impl SumcheckProver, num_rounds: usize, transcript: &mut T, @@ -150,7 +150,7 @@ One function handles: ## The Verifier ```rust -pub fn sumcheck_verify>( +pub fn sumcheck_verify>( claimed_sum: F, expected_degree: usize, num_rounds: usize, @@ -201,7 +201,7 @@ full evaluation table. ## Unified Proof Type ```rust -pub struct SumcheckProof { +pub struct SumcheckProof { pub round_polys: Vec>, // g_j in EvalsInfty wire format pub challenges: Vec, // r_1, ..., r_v pub final_value: F, // g(r_1, ..., r_v) @@ -264,7 +264,7 @@ LLVM const-folds the branch. Zero overhead on non-Goldilocks. ```rust pub trait SimdRepr: - SumcheckField + zerocopy::IntoBytes + zerocopy::FromBytes + SumcheckRing + zerocopy::IntoBytes + zerocopy::FromBytes { fn modulus() -> u64; // GOLDILOCKS_P for SIMD } @@ -277,7 +277,7 @@ Layout safety is **compiler-verified** via zerocopy derives. No `unsafe`. ## Generic Field Trait ```rust -pub trait SumcheckField: +pub trait SumcheckRing: Copy + Send + Sync + PartialEq + Debug + Add + Sub + Mul + Neg + AddAssign + SubAssign + MulAssign @@ -304,7 +304,7 @@ Evaluations in base field BF (e.g., Goldilocks). Challenges from extension field EF (e.g., Goldilocks^3) for soundness. ```rust -pub trait ExtensionOf: SumcheckField + From {} +pub trait ExtensionOf: SumcheckRing + From {} ``` The transition is prover-internal: @@ -556,7 +556,7 @@ parallel = ["rayon", "ark-ff?/parallel", ...] simd = [] ``` -- `--no-default-features`: pure `SumcheckField` library, no arkworks, no SIMD +- `--no-default-features`: pure `SumcheckRing` library, no arkworks, no SIMD - `--features arkworks`: blanket impl for `ark_ff::Field` - `--features parallel`: rayon parallelism for fold and round computation - `--features simd`: SIMD backends (NEON, AVX-512 IFMA) for Goldilocks @@ -676,7 +676,7 @@ verifier challenges. This library implements plain (non-ZK) sumcheck. has not been formally verified**. Fixed-size Montgomery multiplication is inherently data-independent but -unaudited. No constant-time claim for arbitrary `SumcheckField` impls. +unaudited. No constant-time claim for arbitrary `SumcheckRing` impls. Callers in that threat model must supply constant-time field operations. See [SECURITY.md](../SECURITY.md) for the full threat model and reporting policy. @@ -705,7 +705,7 @@ See [SECURITY.md](../SECURITY.md) for the full threat model and reporting policy 6. **Features are orthogonal layers.** `arkworks`, `parallel`, and `simd` can be enabled independently. - The core library works with any `SumcheckField` and zero dependencies. + The core library works with any `SumcheckRing` and zero dependencies. --- diff --git a/src/coefficient_sumcheck.rs b/src/coefficient_sumcheck.rs index 49599a89..fc8bb0d0 100644 --- a/src/coefficient_sumcheck.rs +++ b/src/coefficient_sumcheck.rs @@ -1,4 +1,4 @@ -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use ark_ff::Field; use ark_poly::univariate::DensePolynomial; @@ -47,7 +47,7 @@ pub struct CoefficientSumcheck { /// } /// } /// ``` -pub trait RoundPolyEvaluator: Sync { +pub trait RoundPolyEvaluator: Sync { /// The degree of the round polynomial (number of coefficients = degree + 1). fn degree(&self) -> usize; @@ -80,7 +80,7 @@ pub trait RoundPolyEvaluator: Sync { /// SIMD fast path for degree-1 with a single pairwise table. /// /// Returns `[sum_even, sum_odd - sum_even]` = coefficients of `h(x) = c0 + c1*x`. -fn simd_evaluate_degree1(pw: &[F]) -> Vec { +fn simd_evaluate_degree1(pw: &[F]) -> Vec { // Try SIMD dispatch for Goldilocks #[cfg(all( feature = "simd", @@ -113,7 +113,7 @@ fn simd_evaluate_degree1(pw: &[F]) -> Vec { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { +fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { crate::simd_sumcheck::dispatch::try_simd_evaluate_degree1(pw) } @@ -129,7 +129,7 @@ fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -fn try_simd_fused_reduce_evaluate( +fn try_simd_fused_reduce_evaluate( pw: &mut Vec, challenge: F, ) -> Option> { @@ -143,7 +143,7 @@ fn try_simd_fused_reduce_evaluate( all(target_arch = "x86_64", target_feature = "avx512ifma") ) )))] -fn try_simd_fused_reduce_evaluate( +fn try_simd_fused_reduce_evaluate( _pw: &mut Vec, _challenge: F, ) -> Option> { @@ -152,7 +152,7 @@ fn try_simd_fused_reduce_evaluate( /// Parallel evaluate using rayon (for heavy evaluators). #[cfg(feature = "parallel")] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -191,7 +191,7 @@ fn parallel_evaluate( /// Fallback when parallel feature is disabled. #[cfg(not(feature = "parallel"))] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -216,7 +216,7 @@ fn parallel_evaluate( /// Sequential evaluate (for trivial evaluators where rayon overhead dominates). /// /// Fills `coeffs_out` with accumulated coefficients (zeroes it first). -fn sequential_evaluate_into( +fn sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], diff --git a/src/field.rs b/src/field.rs index b464a155..390351e0 100644 --- a/src/field.rs +++ b/src/field.rs @@ -1,6 +1,6 @@ -//! Generic field trait for sumcheck. +//! Generic ring trait for sumcheck. //! -//! [`SumcheckField`] captures the minimum arithmetic interface needed by the +//! [`SumcheckRing`] captures the minimum arithmetic interface needed by the //! sumcheck protocol. Any type with field-like operations (add, sub, mul, //! negate, invert) and two distinguished constants (zero, one) can implement //! this trait and use the full sumcheck library. @@ -27,7 +27,7 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; /// opt-in via [`_simd_field_config`](Self::_simd_field_config). Non-Goldilocks /// fields leave the default (returns `None`) and the library transparently /// falls back to scalar code. -pub trait SumcheckField: +pub trait SumcheckRing: Sized + Copy + Send @@ -176,7 +176,7 @@ pub const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; /// #[repr(transparent)] /// struct MyGoldilocks(u64); /// -/// impl SumcheckField for MyGoldilocks { +/// impl SumcheckRing for MyGoldilocks { /// // ... arithmetic ... /// fn _simd_field_config() -> Option { /// Some(SimdFieldConfig { modulus: GOLDILOCKS_P, element_bytes: 8 }) @@ -196,7 +196,7 @@ pub const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; /// #[repr(transparent)] /// struct MyExt3([u64; 3]); /// -/// impl SumcheckField for MyExt3 { +/// impl SumcheckRing for MyExt3 { /// fn extension_degree() -> u64 { 3 } /// fn _simd_field_config() -> Option { /// Some(SimdFieldConfig { modulus: GOLDILOCKS_P, element_bytes: 8 }) @@ -209,7 +209,7 @@ pub const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; /// } /// ``` pub trait SimdRepr: - SumcheckField + zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::Immutable + SumcheckRing + zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::Immutable { /// The base prime field modulus as a single `u64` limb. /// @@ -240,7 +240,7 @@ pub struct SimdFieldConfig { /// `zerocopy::IntoBytes + FromBytes + Immutable` — compiler-verified /// layout) and override `_simd_field_config()`. #[inline(always)] -pub fn simd_config() -> Option { +pub fn simd_config() -> Option { F::_simd_field_config() } @@ -248,7 +248,7 @@ pub fn simd_config() -> Option { /// /// The prover starts with evaluations in `BF` and folds into `EF` once /// the first challenge arrives. -pub trait ExtensionOf: SumcheckField + From {} +pub trait ExtensionOf: SumcheckRing + From {} // ─── Arkworks blanket implementation ──────────────────────────────────────── @@ -256,7 +256,7 @@ pub trait ExtensionOf: SumcheckField + From {} mod ark_impl { use super::*; - impl SumcheckField for F + impl SumcheckRing for F where F: ark_ff::Field, { diff --git a/src/inner_product_sumcheck.rs b/src/inner_product_sumcheck.rs index 9fa31379..b977b065 100644 --- a/src/inner_product_sumcheck.rs +++ b/src/inner_product_sumcheck.rs @@ -19,7 +19,7 @@ //! additional cache-locality gains from reading all four strides //! simultaneously. -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use alloc::vec::Vec; #[cfg(feature = "parallel")] use rayon::join; @@ -30,7 +30,7 @@ use crate::transcript::ProverTranscript; /// Legacy return type for `inner_product_sumcheck`. #[derive(Debug, PartialEq)] -pub struct ProductSumcheck { +pub struct ProductSumcheck { pub prover_messages: Vec<(F, F)>, pub verifier_messages: Vec, pub final_evaluations: (F, F), @@ -65,7 +65,7 @@ const fn workload_size() -> usize { // ─── Scalar helpers ───────────────────────────────────────────────────────── -fn dot(a: &[F], b: &[F]) -> F { +fn dot(a: &[F], b: &[F]) -> F { debug_assert_eq!(a.len(), b.len()); #[cfg(feature = "parallel")] if a.len() > workload_size::() { @@ -74,7 +74,7 @@ fn dot(a: &[F], b: &[F]) -> F { a.iter().zip(b).map(|(x, y)| *x * *y).sum() } -fn scalar_mul(v: &mut [F], w: F) { +fn scalar_mul(v: &mut [F], w: F) { for x in v.iter_mut() { *x *= w; } @@ -85,8 +85,8 @@ fn scalar_mul(v: &mut [F], w: F) { /// `(c0, c2)` of the round polynomial `q(x) = c0 + c1·x + c2·x²`. /// /// 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) { +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()); @@ -140,8 +140,8 @@ pub fn compute_sumcheck_polynomial(a: &[F], b: &[F]) -> (F, F) /// /// `values` is implicitly zero-padded to the next power of two. On return, /// the length is a power of two (or zero). -pub fn fold(values: &mut Vec, weight: F) { - fn recurse_both(low: &mut [F], high: &[F], weight: F) { +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; @@ -176,7 +176,7 @@ pub fn fold(values: &mut Vec, weight: F) { } /// Two-pass fold-then-compute; reference version kept for testing. -pub fn fold_and_compute_polynomial( +pub fn fold_and_compute_polynomial( a: &mut Vec, b: &mut Vec, weight: F, @@ -196,7 +196,7 @@ pub fn fold_and_compute_polynomial( /// /// Falls back to the unfused path for small or non-pow2 inputs so the /// implicit-zero tail accounting stays identical. -pub fn fused_fold_and_compute_polynomial( +pub fn fused_fold_and_compute_polynomial( a: &mut Vec, b: &mut Vec, weight: F, @@ -208,7 +208,7 @@ pub fn fused_fold_and_compute_polynomial( } #[allow(clippy::too_many_arguments)] - fn kernel( + fn kernel( a0: &mut [F], a1: &mut [F], a2: &[F], @@ -310,7 +310,7 @@ pub fn inner_product_sumcheck_partial( mut hook: H, ) -> ProductSumcheck where - F: SumcheckField, + F: SumcheckRing, T: ProverTranscript, H: FnMut(usize, &mut T), { @@ -370,7 +370,7 @@ pub fn inner_product_sumcheck( hook: H, ) -> ProductSumcheck where - F: SumcheckField, + F: SumcheckRing, T: ProverTranscript, H: FnMut(usize, &mut T), { diff --git a/src/lib.rs b/src/lib.rs index 509557ff..5b8bd841 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ extern crate alloc; -// ─── Generic field trait ───────────────────────────────────────────────────── +// ─── Generic ring trait ───────────────────────────────────────────────────── pub mod field; pub mod proof; diff --git a/src/multilinear_sumcheck.rs b/src/multilinear_sumcheck.rs index 8b3b598a..b7f054ba 100644 --- a/src/multilinear_sumcheck.rs +++ b/src/multilinear_sumcheck.rs @@ -17,7 +17,7 @@ //! 4 reads + 2 writes per quadruple (fused) vs. 6 reads + 2 writes //! (fold + compute separately) — a ~33% memory-traffic reduction. -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use alloc::vec::Vec; #[cfg(feature = "parallel")] use rayon::join; @@ -28,7 +28,7 @@ use crate::transcript::ProverTranscript; /// Legacy return type for `multilinear_sumcheck`. #[derive(Debug)] -pub struct Sumcheck { +pub struct Sumcheck { pub prover_messages: Vec<(F, F)>, pub verifier_messages: Vec, pub final_evaluation: F, @@ -62,7 +62,7 @@ const fn workload_size() -> usize { // ─── Scalar helpers ───────────────────────────────────────────────────────── -fn sum_slice(v: &[F]) -> F { +fn sum_slice(v: &[F]) -> F { #[cfg(feature = "parallel")] if v.len() > workload_size::() { return v.par_iter().copied().sum(); @@ -70,7 +70,7 @@ fn sum_slice(v: &[F]) -> F { v.iter().copied().sum() } -fn scalar_mul(v: &mut [F], w: F) { +fn scalar_mul(v: &mut [F], w: F) { for x in v.iter_mut() { *x *= w; } @@ -83,8 +83,8 @@ fn scalar_mul(v: &mut [F], w: F) { /// `values` is implicitly zero-extended to the next power of two. /// - `s0 = Σ v[0..L/2]` (low half, possibly with tail contributions) /// - `s1 = Σ v[L/2..L]` -pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { - fn recurse(lo: &[F], hi: &[F]) -> (F, F) { +pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { + fn recurse(lo: &[F], hi: &[F]) -> (F, F) { debug_assert_eq!(lo.len(), hi.len()); #[cfg(feature = "parallel")] @@ -129,7 +129,7 @@ pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { /// /// SIMD-accelerated for Goldilocks base field on NEON and AVX-512 IFMA. /// Falls back to a scalar recursive `rayon::join` fold for other fields. -pub fn fold(values: &mut Vec, weight: F) { +pub fn fold(values: &mut Vec, weight: F) { // SIMD fast path for base-field Goldilocks (MSB layout). #[cfg(all( feature = "simd", @@ -144,7 +144,7 @@ pub fn fold(values: &mut Vec, weight: F) { return; } } - fn recurse_both(low: &mut [F], high: &[F], 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; @@ -178,7 +178,7 @@ pub fn fold(values: &mut Vec, weight: F) { } /// Two-pass fold-then-compute. Reference only. -pub fn fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { +pub fn fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { fold(values, weight); compute_sumcheck_polynomial(values) } @@ -186,7 +186,7 @@ pub fn fold_and_compute_polynomial(values: &mut Vec, weight /// Fused fold + compute: folds `values` by `weight` *and* returns the /// next-round `(s0, s1)` in one sweep over the quadruple /// `(v[k], v[k+L/4], v[k+L/2], v[k+3L/4])`. -pub fn fused_fold_and_compute_polynomial( +pub fn fused_fold_and_compute_polynomial( values: &mut Vec, weight: F, ) -> (F, F) { @@ -195,7 +195,7 @@ pub fn fused_fold_and_compute_polynomial( return fold_and_compute_polynomial(values, weight); } - fn kernel( + fn kernel( v0: &mut [F], v1: &mut [F], v2: &[F], @@ -269,7 +269,7 @@ pub fn multilinear_sumcheck_partial( mut hook: H, ) -> Sumcheck where - F: SumcheckField, + F: SumcheckRing, T: ProverTranscript, H: FnMut(usize, &mut T), { @@ -325,7 +325,7 @@ pub fn multilinear_sumcheck( hook: H, ) -> Sumcheck where - F: SumcheckField, + F: SumcheckRing, T: ProverTranscript, H: FnMut(usize, &mut T), { diff --git a/src/polynomial/dense.rs b/src/polynomial/dense.rs index 1ee51ca0..58359be7 100644 --- a/src/polynomial/dense.rs +++ b/src/polynomial/dense.rs @@ -1,6 +1,6 @@ //! Zero-allocation dense polynomial arithmetic on coefficient slices. -use crate::field::SumcheckField; +use crate::field::SumcheckRing; /// Multiply polynomials `a` and `b`, writing the result into `out`. /// @@ -9,7 +9,7 @@ use crate::field::SumcheckField; /// /// `a = [a_0, a_1, ..., a_m]`, `b = [b_0, b_1, ..., b_n]`. /// `out[k] = Σ_{i+j=k} a_i · b_j`. -pub fn mul_into(out: &mut [F], a: &[F], b: &[F]) { +pub fn mul_into(out: &mut [F], a: &[F], b: &[F]) { if a.is_empty() || b.is_empty() { for o in out.iter_mut() { *o = F::ZERO; @@ -36,7 +36,7 @@ pub fn mul_into(out: &mut [F], a: &[F], b: &[F]) { /// /// If `p` is longer than `out`, the extra terms are ignored. /// No allocation. -pub fn add_scaled(out: &mut [F], scalar: F, p: &[F]) { +pub fn add_scaled(out: &mut [F], scalar: F, p: &[F]) { let len = out.len().min(p.len()); for i in 0..len { out[i] += scalar * p[i]; @@ -47,7 +47,7 @@ pub fn add_scaled(out: &mut [F], scalar: F, p: &[F]) { /// /// Alias for [`eval_horner`](super::eval_horner). #[inline] -pub fn eval_at(coeffs: &[F], x: F) -> F { +pub fn eval_at(coeffs: &[F], x: F) -> F { super::eval_horner(coeffs, x) } diff --git a/src/polynomial/eval.rs b/src/polynomial/eval.rs index 989f007b..60a5881b 100644 --- a/src/polynomial/eval.rs +++ b/src/polynomial/eval.rs @@ -1,7 +1,7 @@ //! Polynomial evaluation: Horner's method and barycentric Lagrange interpolation. extern crate alloc; -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use alloc::vec; use alloc::vec::Vec; @@ -11,7 +11,7 @@ use alloc::vec::Vec; /// /// Cost: `d` multiplications + `d` additions. Zero allocation. #[inline] -pub fn eval_horner(coeffs: &[F], x: F) -> F { +pub fn eval_horner(coeffs: &[F], x: F) -> F { if coeffs.is_empty() { return F::ZERO; } @@ -29,7 +29,7 @@ pub fn eval_horner(coeffs: &[F], x: F) -> F { /// /// Cost: O(d) with precomputed [`BarycentricWeights`], O(d²) without. /// For repeated evaluations at the same degree, precompute weights once. -pub fn eval_from_evals(evals: &[F], x: F) -> F { +pub fn eval_from_evals(evals: &[F], x: F) -> F { let d = evals.len(); if d == 0 { return F::ZERO; @@ -51,12 +51,12 @@ pub fn eval_from_evals(evals: &[F], x: F) -> F { /// /// Weight `w_i = 1 / Π_{j≠i} (i − j)` for `i, j ∈ {0, ..., d}`. /// For consecutive integer nodes these are `(-1)^{d-i} / (i! · (d-i)!)`. -pub struct BarycentricWeights { +pub struct BarycentricWeights { /// Precomputed `w_i` for each node `i ∈ {0, ..., d}`. weights: Vec, } -impl BarycentricWeights { +impl BarycentricWeights { /// Precompute weights for interpolation at `{0, 1, ..., degree}`. pub fn new(degree: usize) -> Self { let d = degree + 1; // number of nodes @@ -131,7 +131,7 @@ impl BarycentricWeights { mod tests { use super::*; - // A simple field-like wrapper for f64 won't work with SumcheckField + // A simple ring-like wrapper for f64 won't work with SumcheckRing // (needs Copy + all the ops). Tests use the arkworks F64 type. #[cfg(feature = "arkworks")] mod ark_tests { diff --git a/src/polynomial/mod.rs b/src/polynomial/mod.rs index f38de81a..f0e4b033 100644 --- a/src/polynomial/mod.rs +++ b/src/polynomial/mod.rs @@ -1,6 +1,6 @@ //! Polynomial evaluation and arithmetic for sumcheck protocols. //! -//! Generic over [`SumcheckField`](crate::field::SumcheckField) — available without the `arkworks` feature. +//! Generic over [`SumcheckRing`](crate::field::SumcheckRing) — available without the `arkworks` feature. //! //! # Evaluation //! diff --git a/src/polynomial/sequential_lagrange.rs b/src/polynomial/sequential_lagrange.rs index ab6fded7..82615a58 100644 --- a/src/polynomial/sequential_lagrange.rs +++ b/src/polynomial/sequential_lagrange.rs @@ -12,7 +12,7 @@ //! The amortized cost per step is O(1) (geometric series: 1 + 1/2 + 1/4 + ... = 2). extern crate alloc; -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use alloc::vec::Vec; /// Sequential Lagrange polynomial `eq(r, ·)` with incremental updates. @@ -32,7 +32,7 @@ use alloc::vec::Vec; /// // use eq_val... /// } /// ``` -pub struct SequentialLagrange { +pub struct SequentialLagrange { /// Precomputed factors: `factor_one[j] = r_j`, `factor_zero[j] = 1 − r_j`. factor_one: Vec, factor_zero: Vec, @@ -44,7 +44,7 @@ pub struct SequentialLagrange { num_vars: usize, } -impl SequentialLagrange { +impl SequentialLagrange { /// Initialize at the origin (index 0): `eq(r, 0) = Π_j (1 − r_j)`. pub fn new(point: &[F]) -> Self { let num_vars = point.len(); diff --git a/src/proof.rs b/src/proof.rs index 980c530a..d3a8a303 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -4,7 +4,7 @@ extern crate alloc; -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use alloc::vec::Vec; use core::fmt; @@ -15,7 +15,7 @@ use core::fmt; /// consistency checks from this data; the final oracle check (verifying /// `final_value == g(r_1, ..., r_v)`) is the caller's responsibility. #[derive(Clone, Debug)] -pub struct SumcheckProof { +pub struct SumcheckProof { /// Round polynomial values, EvalsInfty wire format: `round_polys[j]` /// contains `d = degree` values per round. /// diff --git a/src/provers/coefficient.rs b/src/provers/coefficient.rs index bd794843..76ba9705 100644 --- a/src/provers/coefficient.rs +++ b/src/provers/coefficient.rs @@ -6,7 +6,7 @@ //! For sequential streaming (Jolt-style), use //! [`CoefficientProverLSB`](super::coefficient_lsb::CoefficientProverLSB). -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::coefficient_sumcheck::RoundPolyEvaluator; use crate::sumcheck_prover::SumcheckProver; @@ -15,7 +15,7 @@ use crate::sumcheck_prover::SumcheckProver; use rayon::prelude::*; /// MSB coefficient sumcheck prover (arbitrary degree d, half-split layout). -pub struct CoefficientProver<'a, F: SumcheckField, E: RoundPolyEvaluator> { +pub struct CoefficientProver<'a, F: SumcheckRing, E: RoundPolyEvaluator> { evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>, @@ -24,7 +24,7 @@ pub struct CoefficientProver<'a, F: SumcheckField, E: RoundPolyEvaluator> { deg: usize, } -impl<'a, F: SumcheckField, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> { +impl<'a, F: SumcheckRing, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> { pub fn new(evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>) -> Self { let n_tw = tablewise.len(); let n_pw = pairwise.len(); @@ -128,7 +128,7 @@ impl<'a, F: SumcheckField, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> // ─── MSB fold helpers ────────────────────────────────────────────────────── /// In-place MSB fold for a flat vector: `new[k] = v[k] + c*(v[k+half] - v[k])`. -fn msb_fold_vec(v: &mut Vec, challenge: F) { +fn msb_fold_vec(v: &mut Vec, challenge: F) { if v.len() <= 1 { return; } @@ -141,7 +141,7 @@ fn msb_fold_vec(v: &mut Vec, challenge: F) { /// MSB fold for tablewise: each row-vector is folded by pairing /// `(table[k], table[k+half])` and producing a new row. -fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { +fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { if table.len() <= 1 { return; } @@ -162,7 +162,7 @@ fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { // ─── MSB evaluate helpers ────────────────────────────────────────────────── /// MSB pairing: pair index `k` with `k + half` (not `2k` with `2k+1`). -fn msb_sequential_evaluate_into( +fn msb_sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -189,7 +189,7 @@ fn msb_sequential_evaluate_into( } #[cfg(feature = "parallel")] -fn msb_parallel_evaluate( +fn msb_parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -222,7 +222,7 @@ fn msb_parallel_evaluate( } #[cfg(not(feature = "parallel"))] -fn msb_parallel_evaluate( +fn msb_parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -247,7 +247,7 @@ fn msb_parallel_evaluate( // ─── Horner evaluation ───────────────────────────────────────────────────── #[inline] -fn eval_poly_at(coeffs: &[F], x: F) -> F { +fn eval_poly_at(coeffs: &[F], x: F) -> F { if coeffs.is_empty() { return F::ZERO; } @@ -262,7 +262,7 @@ fn eval_poly_at(coeffs: &[F], x: F) -> F { impl<'a, F, E> SumcheckProver for CoefficientProver<'a, F, E> where - F: SumcheckField, + F: SumcheckRing, E: RoundPolyEvaluator, { fn degree(&self) -> usize { diff --git a/src/provers/coefficient_lsb.rs b/src/provers/coefficient_lsb.rs index 7b55c59c..d2c2193d 100644 --- a/src/provers/coefficient_lsb.rs +++ b/src/provers/coefficient_lsb.rs @@ -8,7 +8,7 @@ //! workloads, prefer [`CoefficientProver`](super::coefficient::CoefficientProver) //! (MSB layout). -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::coefficient_sumcheck::RoundPolyEvaluator; use crate::reductions::{pairwise, tablewise}; @@ -34,7 +34,7 @@ use rayon::prelude::*; /// ); /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// ``` -pub struct CoefficientProverLSB<'a, F: SumcheckField, E: RoundPolyEvaluator> { +pub struct CoefficientProverLSB<'a, F: SumcheckRing, E: RoundPolyEvaluator> { evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>, @@ -47,7 +47,7 @@ pub struct CoefficientProverLSB<'a, F: SumcheckField, E: RoundPolyEvaluator> is_degree1_simd_path: bool, } -impl<'a, F: SumcheckField, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, E> { +impl<'a, F: SumcheckRing, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, E> { pub fn new(evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>) -> Self { let n_tw = tablewise.len(); let n_pw = pairwise.len(); @@ -170,7 +170,7 @@ impl<'a, F: SumcheckField, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, impl<'a, F, E> SumcheckProver for CoefficientProverLSB<'a, F, E> where - F: SumcheckField, + F: SumcheckRing, E: RoundPolyEvaluator, { fn degree(&self) -> usize { @@ -240,7 +240,7 @@ where /// Evaluate polynomial with coefficients `coeffs` at point `x` via Horner's method. #[inline] -fn eval_poly_at(coeffs: &[F], x: F) -> F { +fn eval_poly_at(coeffs: &[F], x: F) -> F { if coeffs.is_empty() { return F::ZERO; } @@ -253,7 +253,7 @@ fn eval_poly_at(coeffs: &[F], x: F) -> F { // ─── Evaluate strategies (same as coefficient_sumcheck.rs) ───────────────── -fn simd_evaluate_degree1(pw: &[F]) -> Vec { +fn simd_evaluate_degree1(pw: &[F]) -> Vec { #[cfg(all( feature = "simd", any( @@ -275,7 +275,7 @@ fn simd_evaluate_degree1(pw: &[F]) -> Vec { vec![s0, s1 - s0] } -fn try_simd_fused_reduce_evaluate( +fn try_simd_fused_reduce_evaluate( pw: &mut Vec, challenge: F, ) -> Option> { @@ -303,7 +303,7 @@ fn try_simd_fused_reduce_evaluate( } #[cfg(feature = "parallel")] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -336,7 +336,7 @@ fn parallel_evaluate( } #[cfg(not(feature = "parallel"))] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -358,7 +358,7 @@ fn parallel_evaluate( coeffs } -fn sequential_evaluate_into( +fn sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], diff --git a/src/provers/eq_factored.rs b/src/provers/eq_factored.rs index a3492f4f..c43e0401 100644 --- a/src/provers/eq_factored.rs +++ b/src/provers/eq_factored.rs @@ -39,7 +39,7 @@ //! EvalsInfty for degree 2: `[q(0), q(∞)]`. The verifier derives //! `q(1) = claim - q(0)` and reconstructs the round polynomial. -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; @@ -64,7 +64,7 @@ use alloc::{vec, vec::Vec}; /// // final_value() = eq(w, r) · p(r) /// let (p_r, eq_wr) = prover.final_factors(); /// ``` -pub struct EqFactoredProver { +pub struct EqFactoredProver { /// `p` evaluations (MSB layout), padded to `2^v` on construction. /// Folded in every round. p: Vec, @@ -82,7 +82,7 @@ pub struct EqFactoredProver { rounds_elapsed: usize, } -impl EqFactoredProver { +impl EqFactoredProver { /// Construct a prover for `∑_x eq(w, x) · p(x)`. /// /// `p_evals.len()` must be `≤ 2^{w.len()}`; shorter inputs are @@ -214,7 +214,7 @@ impl EqFactoredProver { /// /// Runs in `O(2^v)` time with `O(2^v)` space. With `w.len() = v/2` this /// produces one of the split-value half-tables. -pub(crate) fn build_eq_table(w: &[F]) -> Vec { +pub(crate) fn build_eq_table(w: &[F]) -> Vec { let v = w.len(); if v == 0 { return vec![F::ONE]; @@ -240,7 +240,7 @@ pub(crate) fn build_eq_table(w: &[F]) -> Vec { impl SumcheckProver for EqFactoredProver where - F: SumcheckField, + F: SumcheckRing, { fn degree(&self) -> usize { 2 diff --git a/src/provers/gkr.rs b/src/provers/gkr.rs index cbd225ae..4bca5aa6 100644 --- a/src/provers/gkr.rs +++ b/src/provers/gkr.rs @@ -29,7 +29,7 @@ //! let (w_b, w_c) = prover.claimed_w_values(); //! ``` -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; @@ -38,7 +38,7 @@ use alloc::{vec, vec::Vec}; /// GKR round sumcheck prover (degree 2). /// /// See [module docs](self) for details. -pub struct GkrProver { +pub struct GkrProver { /// Gate add predicate: `add_i(r, b, c)`, `2^{2k}` entries. add_evals: Vec, /// Gate mult predicate: `mult_i(r, b, c)`, `2^{2k}` entries. @@ -49,7 +49,7 @@ pub struct GkrProver { w_c: Vec, } -impl GkrProver { +impl GkrProver { /// Construct from gate predicates and witness evaluations. /// /// - `add_evals`: `add_i(r, b, c)` for all `(b, c) in {0,1}^{2k}`. @@ -96,7 +96,7 @@ impl GkrProver { impl SumcheckProver for GkrProver where - F: SumcheckField, + F: SumcheckRing, { fn degree(&self) -> usize { 2 diff --git a/src/provers/inner_product.rs b/src/provers/inner_product.rs index 391a9260..9e267aee 100644 --- a/src/provers/inner_product.rs +++ b/src/provers/inner_product.rs @@ -2,7 +2,7 @@ //! //! Implements [`SumcheckProver`] for the quadratic sumcheck `∑_x f(x)·g(x)`. -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; use alloc::{vec, vec::Vec}; @@ -23,12 +23,12 @@ use alloc::{vec, vec::Vec}; /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// let (f_eval, g_eval) = prover.final_evaluations(); /// ``` -pub struct InnerProductProver { +pub struct InnerProductProver { a: Vec, b: Vec, } -impl InnerProductProver { +impl InnerProductProver { /// Time strategy prover: holds both evaluation vectors in memory. pub fn new(a: Vec, b: Vec) -> Self { assert_eq!(a.len(), b.len(), "a and b must have equal length"); @@ -52,7 +52,7 @@ impl InnerProductProver { impl SumcheckProver for InnerProductProver where - F: SumcheckField, + F: SumcheckRing, { fn degree(&self) -> usize { 2 diff --git a/src/provers/inner_product_lsb.rs b/src/provers/inner_product_lsb.rs index e2c0ee1b..907dea26 100644 --- a/src/provers/inner_product_lsb.rs +++ b/src/provers/inner_product_lsb.rs @@ -8,7 +8,7 @@ //! workloads, prefer [`InnerProductProver`](super::inner_product::InnerProductProver) //! (MSB layout). -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::sumcheck_prover::SumcheckProver; use alloc::{vec, vec::Vec}; @@ -22,12 +22,12 @@ use alloc::{vec, vec::Vec}; /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// let (f_r, g_r) = prover.final_evaluations(); /// ``` -pub struct InnerProductProverLSB { +pub struct InnerProductProverLSB { a: Vec, b: Vec, } -impl InnerProductProverLSB { +impl InnerProductProverLSB { pub fn new(a: Vec, b: Vec) -> Self { assert_eq!(a.len(), b.len(), "a and b must have equal length"); Self { a, b } @@ -52,7 +52,7 @@ impl InnerProductProverLSB { /// /// q(0) = sum a[2k] * b[2k] /// q(∞) = [x²] q(x) = sum (a[2k+1] - a[2k]) * (b[2k+1] - b[2k]) -fn compute_lsb(a: &[F], b: &[F]) -> (F, F) { +fn compute_lsb(a: &[F], b: &[F]) -> (F, F) { debug_assert_eq!(a.len(), b.len()); if a.is_empty() { return (F::ZERO, F::ZERO); @@ -75,7 +75,7 @@ fn compute_lsb(a: &[F], b: &[F]) -> (F, F) { } /// In-place LSB fold: `new[k] = f[2k] + w * (f[2k+1] - f[2k])`. -fn fold_lsb(v: &mut Vec, weight: F) { +fn fold_lsb(v: &mut Vec, weight: F) { if v.len() <= 1 { return; } @@ -90,7 +90,7 @@ fn fold_lsb(v: &mut Vec, weight: F) { /// Fused fold + compute: fold both vectors with `weight`, then compute /// the next round's EvalsInfty `(q(0), q(∞))` in one pass over quads. -fn fused_fold_and_compute_lsb( +fn fused_fold_and_compute_lsb( a: &mut Vec, b: &mut Vec, weight: F, @@ -147,7 +147,7 @@ fn fused_fold_and_compute_lsb( impl SumcheckProver for InnerProductProverLSB where - F: SumcheckField, + F: SumcheckRing, { fn degree(&self) -> usize { 2 diff --git a/src/provers/multilinear.rs b/src/provers/multilinear.rs index 656a7f83..e25d8f31 100644 --- a/src/provers/multilinear.rs +++ b/src/provers/multilinear.rs @@ -3,7 +3,7 @@ //! Wraps the fused fold+compute kernel from `multilinear_sumcheck.rs` //! behind the [`SumcheckProver`] trait. -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::multilinear_sumcheck::{ compute_sumcheck_polynomial, fold, fused_fold_and_compute_polynomial, }; @@ -22,11 +22,11 @@ use alloc::{vec, vec::Vec}; /// let mut prover = MultilinearProver::new(evals); /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// ``` -pub struct MultilinearProver { +pub struct MultilinearProver { evals: Vec, } -impl MultilinearProver { +impl MultilinearProver { /// Time strategy prover: holds all evaluations in memory. pub fn new(evals: Vec) -> Self { Self { evals } @@ -49,7 +49,7 @@ impl MultilinearProver { impl SumcheckProver for MultilinearProver where - F: SumcheckField, + F: SumcheckRing, { fn degree(&self) -> usize { 1 diff --git a/src/provers/multilinear_lsb.rs b/src/provers/multilinear_lsb.rs index 329fb8f3..29aebd18 100644 --- a/src/provers/multilinear_lsb.rs +++ b/src/provers/multilinear_lsb.rs @@ -9,7 +9,7 @@ //! workloads, prefer [`MultilinearProver`](super::multilinear::MultilinearProver) //! (MSB layout). -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::sumcheck_prover::SumcheckProver; use alloc::{vec, vec::Vec}; @@ -26,11 +26,11 @@ use rayon::prelude::*; /// let mut prover = MultilinearProverLSB::new(evals); /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// ``` -pub struct MultilinearProverLSB { +pub struct MultilinearProverLSB { evals: Vec, } -impl MultilinearProverLSB { +impl MultilinearProverLSB { /// Time strategy prover with LSB (pair-split) layout. pub fn new(evals: Vec) -> Self { Self { evals } @@ -57,7 +57,7 @@ impl MultilinearProverLSB { /// /// `s0 = sum of even-indexed elements = sum f[2k]` /// `s1 = sum of odd-indexed elements = sum f[2k+1]` -fn compute_lsb(evals: &[F]) -> (F, F) { +fn compute_lsb(evals: &[F]) -> (F, F) { if evals.is_empty() { return (F::ZERO, F::ZERO); } @@ -96,7 +96,7 @@ fn compute_lsb(evals: &[F]) -> (F, F) { } /// In-place LSB (pair-split) fold: `new[k] = f[2k] + w * (f[2k+1] - f[2k])`. -fn fold_lsb(evals: &mut Vec, weight: F) { +fn fold_lsb(evals: &mut Vec, weight: F) { if evals.len() <= 1 { return; } @@ -125,7 +125,7 @@ fn fold_lsb(evals: &mut Vec, weight: F) { /// Fused fold + compute: fold with `weight`, then compute the next round's /// (s0, s1) from the folded data. Single pass over pairs of pairs. -fn fused_fold_and_compute_lsb(evals: &mut Vec, weight: F) -> (F, F) { +fn fused_fold_and_compute_lsb(evals: &mut Vec, weight: F) -> (F, F) { let n = evals.len(); if n < 4 { fold_lsb(evals, weight); @@ -165,7 +165,7 @@ fn fused_fold_and_compute_lsb(evals: &mut Vec, weight: F) - // ─── SumcheckProver impl ─────────────────────────────────────────────────── -impl SumcheckProver for MultilinearProverLSB { +impl SumcheckProver for MultilinearProverLSB { fn degree(&self) -> usize { 1 } diff --git a/src/reductions/pairwise.rs b/src/reductions/pairwise.rs index 430a9a05..eb95415e 100644 --- a/src/reductions/pairwise.rs +++ b/src/reductions/pairwise.rs @@ -1,4 +1,4 @@ -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use ark_ff::Field; use ark_std::vec::Vec; use ark_std::{cfg_chunks, cfg_into_iter}; @@ -10,7 +10,7 @@ use rayon::{ use crate::streams::Stream; -pub fn evaluate(src: &[F]) -> (F, F) { +pub fn evaluate(src: &[F]) -> (F, F) { let even_sum = cfg_into_iter!(0..src.len()) .step_by(2) .map(|i| src[i]) @@ -35,7 +35,7 @@ pub fn evaluate_from_stream>(src: &S) -> (F, F) { (even_sum, odd_sum) } -pub fn reduce_evaluations(src: &mut Vec, verifier_message: F) { +pub fn reduce_evaluations(src: &mut Vec, verifier_message: F) { /// Below this input size, the serial in-place path wins: rayon's /// fork/join overhead exceeds the actual compute, and we avoid the /// `.collect()` allocation entirely. Above it, parallelism outpaces @@ -93,7 +93,7 @@ pub fn reduce_evaluations_from_stream>( /// round polynomial `q(x) = a + bx + cx²`: /// - `a = Σ f_even · g_even` /// - `b = Σ (f_even · g_odd + f_odd · g_even)` -pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { +pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { let half_len = src[0].len() / 2; let a: F = cfg_into_iter!(0..half_len) .map(|k| { @@ -113,7 +113,7 @@ pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { /// Cross-field reduce: fold `BF` evaluations with an `EF` challenge, producing `Vec`. /// /// For each adjacent pair `(a, b)` in `src`: `EF::from(a) + challenge * (EF::from(b) - EF::from(a))`. -pub fn cross_field_reduce>( +pub fn cross_field_reduce>( src: &[BF], challenge: EF, ) -> Vec { diff --git a/src/reductions/tablewise.rs b/src/reductions/tablewise.rs index 0bb8930b..14789892 100644 --- a/src/reductions/tablewise.rs +++ b/src/reductions/tablewise.rs @@ -1,9 +1,9 @@ -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use ark_std::{cfg_chunks, vec::Vec}; #[cfg(feature = "parallel")] use rayon::{iter::ParallelIterator, prelude::ParallelSlice}; -pub fn reduce_evaluations(src: &mut Vec>, verifier_message: F) { +pub fn reduce_evaluations(src: &mut Vec>, verifier_message: F) { let out: Vec> = cfg_chunks!(src, 2) .map(|chunk| { chunk[0] diff --git a/src/runner.rs b/src/runner.rs index 06efce0c..33703a03 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -10,7 +10,7 @@ //! commit/open). extern crate alloc; -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::proof::SumcheckProof; use crate::sumcheck_prover::SumcheckProver; use crate::transcript::ProverTranscript; @@ -26,7 +26,7 @@ use alloc::vec::Vec; /// If `num_rounds == v` (full execution), `proof.final_value` is the /// prover's claimed evaluation at the random point. For partial execution, /// the caller retains `prover` and can continue or inspect post-state. -pub fn sumcheck>( +pub fn sumcheck>( prover: &mut impl SumcheckProver, num_rounds: usize, transcript: &mut T, diff --git a/src/simd_sumcheck/dispatch.rs b/src/simd_sumcheck/dispatch.rs index ea7345ca..233a36b5 100644 --- a/src/simd_sumcheck/dispatch.rs +++ b/src/simd_sumcheck/dispatch.rs @@ -8,7 +8,7 @@ //! - **aarch64**: NEON backend (2-wide, scalar mul fallback) //! - **x86_64 + AVX-512 IFMA**: AVX-512 backend (8-wide, true IFMA mul) //! -//! Detection uses [`SumcheckField::_simd_field_config()`] — the arkworks +//! Detection uses [`SumcheckRing::_simd_field_config()`] — the arkworks //! blanket impl returns the actual modulus, non-arkworks fields return //! `None` by default (no SIMD). After monomorphization the check is //! constant-folded by LLVM, so the dead branch is eliminated entirely. @@ -16,7 +16,7 @@ //! # Safety //! //! This module contains **no `unsafe` code**. All field ↔ `u64` -//! reinterpretation is delegated to the safe `SumcheckField` trait methods +//! reinterpretation is delegated to the safe `SumcheckRing` trait methods //! (`_to_raw_u64`, `_from_raw_u64`, `_as_u64_slice`, `_as_u64_slice_mut`, //! `_from_u64_components`), whose implementations centralize the necessary //! `unsafe` in the arkworks blanket impl with full SAFETY documentation. @@ -28,7 +28,7 @@ all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -use crate::field::SumcheckField; +use crate::field::SumcheckRing; /// Goldilocks modulus: p = 2^64 − 2^32 + 1. #[cfg(all( @@ -43,7 +43,7 @@ const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; /// Returns `true` when `F` is a Goldilocks prime field stored as a /// single `u64` in Montgomery form. /// -/// Uses [`SumcheckField::_simd_field_config()`] for detection. +/// Uses [`SumcheckRing::_simd_field_config()`] for detection. /// After monomorphization every operand is a compile-time constant, /// so LLVM folds the entire function to `true` or `false`. #[cfg(all( @@ -54,7 +54,7 @@ const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; ) ))] #[inline(always)] -fn is_goldilocks() -> bool { +fn is_goldilocks() -> bool { if F::extension_degree() != 1 { return false; } @@ -78,7 +78,7 @@ fn is_goldilocks() -> bool { ) ))] #[inline(always)] -fn is_goldilocks_based() -> bool { +fn is_goldilocks_based() -> bool { match F::_simd_field_config() { Some(cfg) => { if cfg.modulus != GOLDILOCKS_P || cfg.element_bytes != 8 { @@ -105,7 +105,7 @@ fn is_goldilocks_based() -> bool { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_reduce(evals: &mut Vec, challenge: F) -> bool { +pub(crate) fn try_simd_reduce(evals: &mut Vec, challenge: F) -> bool { if !is_goldilocks::() { return false; } @@ -136,7 +136,7 @@ pub(crate) fn try_simd_reduce(evals: &mut Vec, challenge: F all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_reduce_msb(evals: &mut Vec, challenge: F) -> bool { +pub(crate) fn try_simd_reduce_msb(evals: &mut Vec, challenge: F) -> bool { if !is_goldilocks::() { return false; } @@ -168,7 +168,7 @@ pub(crate) fn try_simd_reduce_msb(evals: &mut Vec, challeng all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_fused_reduce_evaluate_degree1( +pub(crate) fn try_simd_fused_reduce_evaluate_degree1( pw: &mut Vec, challenge: F, ) -> Option> { @@ -209,7 +209,7 @@ pub(crate) fn try_simd_fused_reduce_evaluate_degree1( all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_ext_evaluate(evals: &[EF]) -> Option<(EF, EF)> { +pub(crate) fn try_simd_ext_evaluate(evals: &[EF]) -> Option<(EF, EF)> { if !is_goldilocks_based::() { return None; } @@ -252,7 +252,7 @@ pub(crate) fn try_simd_ext_evaluate(evals: &[EF]) -> Option<( all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { +pub(crate) fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { if !is_goldilocks::() { return None; } @@ -282,6 +282,6 @@ pub(crate) fn try_simd_evaluate_degree1(pw: &[F]) -> Option() -> bool { +pub fn is_goldilocks_pub() -> bool { is_goldilocks::() } diff --git a/src/sumcheck_prover.rs b/src/sumcheck_prover.rs index 2658864d..d3058d5a 100644 --- a/src/sumcheck_prover.rs +++ b/src/sumcheck_prover.rs @@ -8,7 +8,7 @@ //! completes. extern crate alloc; -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use alloc::vec::Vec; /// Prover side of the sum-check protocol (Thaler Proposition 4.1). @@ -33,7 +33,7 @@ use alloc::vec::Vec; /// let proof = sumcheck(&mut prover, n, &mut t, |_, _| {}); /// let (f_eval, g_eval) = prover.final_evaluations(); // prover-specific /// ``` -pub trait SumcheckProver { +pub trait SumcheckProver { /// Maximum degree of the round polynomial in the current variable. fn degree(&self) -> usize; diff --git a/src/transcript/sanity.rs b/src/transcript/sanity.rs index defede55..2d49879a 100644 --- a/src/transcript/sanity.rs +++ b/src/transcript/sanity.rs @@ -1,6 +1,6 @@ use rand_core::RngCore; -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::transcript::{ProverTranscript, VerifierTranscript}; /// Test transcript: sends are no-ops, receives return `Ok(random)`, @@ -24,7 +24,7 @@ impl<'a, R> TestTranscript<'a, R> { // avoiding accidental collisions. impl<'a, F, R> ProverTranscript for TestTranscript<'a, R> where - F: SumcheckField, + F: SumcheckRing, R: RngCore, { fn send(&mut self, _value: F) { @@ -38,7 +38,7 @@ where impl<'a, F, R> VerifierTranscript for TestTranscript<'a, R> where - F: SumcheckField, + F: SumcheckRing, R: RngCore, { type Error = core::convert::Infallible; diff --git a/src/verifier.rs b/src/verifier.rs index 84843393..563da620 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -24,7 +24,7 @@ //! consistency constraint `h(0) + h(1) = claim`. extern crate alloc; -use crate::field::SumcheckField; +use crate::field::SumcheckRing; use crate::proof::SumcheckError; use crate::transcript::VerifierTranscript; use alloc::vec; @@ -35,7 +35,7 @@ use alloc::vec::Vec; /// The caller **must** verify `final_claim` — either by direct comparison, /// PCS opening, or delegation to the next protocol layer. #[derive(Clone, Debug)] -pub struct SumcheckResult { +pub struct SumcheckResult { /// Verifier challenges `r_1, ..., r_v`. pub challenges: Vec, /// The reduced claim after all rounds: `g_v(r_v)`. @@ -58,7 +58,7 @@ pub struct SumcheckResult { /// Returns [`SumcheckResult`] containing the challenges and final claim. /// The caller is responsible for the oracle check — verifying that /// `final_claim == g(r_1, ..., r_v)`. -pub fn sumcheck_verify>( +pub fn sumcheck_verify>( claimed_sum: F, expected_degree: usize, num_rounds: usize, @@ -143,7 +143,7 @@ pub fn sumcheck_verify>( /// /// Uses Lagrange interpolation: /// g(r) = Σ_i g(i) · Π_{j≠i} (r − j) / (i − j) -pub(crate) fn evaluate_from_evals(evals: &[F], r: F) -> F { +pub(crate) fn evaluate_from_evals(evals: &[F], r: F) -> F { let d = evals.len(); // number of interpolation nodes if d == 0 { return F::ZERO; @@ -184,7 +184,7 @@ pub(crate) fn evaluate_from_evals(evals: &[F], r: F) -> F { } /// Barycentric weight: Π_{j≠i, 0≤j(i: usize, d: usize) -> F { +fn barycentric_weight(i: usize, d: usize) -> F { let mut w = F::ONE; for j in 0..d { if j != i { diff --git a/tests/plonky3_roundtrip.rs b/tests/plonky3_roundtrip.rs index 7dbfb87f..36b28660 100644 --- a/tests/plonky3_roundtrip.rs +++ b/tests/plonky3_roundtrip.rs @@ -1,9 +1,9 @@ //! Roundtrip test demonstrating effsc with a Plonky3 field. //! //! Shows that any ecosystem's field type works with the sumcheck library -//! via a thin `SumcheckField` impl — no arkworks dependency required. +//! via a thin `SumcheckRing` impl — no arkworks dependency required. -use effsc::field::SumcheckField; +use effsc::field::SumcheckRing; use effsc::noop_hook; use effsc::provers::multilinear_lsb::MultilinearProverLSB; use effsc::runner::sumcheck; @@ -20,7 +20,7 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; // ─── Newtype wrapper ─────────────────────────────────────────────────────── -/// Thin wrapper around Plonky3's Goldilocks to implement `SumcheckField`. +/// Thin wrapper around Plonky3's Goldilocks to implement `SumcheckRing`. #[derive(Copy, Clone, Debug, PartialEq)] struct P3Goldilocks(Goldilocks); @@ -88,7 +88,7 @@ impl Sum for P3Goldilocks { } } -impl SumcheckField for P3Goldilocks { +impl SumcheckRing for P3Goldilocks { const ZERO: Self = Self(Goldilocks::new(0)); const ONE: Self = Self(Goldilocks::new(1)); From b0e63e7c31212245fec9492748db6a6041ffef55 Mon Sep 17 00:00:00 2001 From: pi Date: Wed, 20 May 2026 15:14:22 +0000 Subject: [PATCH 5/5] Revert "Rename" This reverts commit 6bb0fbc9ffa4f5f4296ca1603f8b5663ac703383. --- CHANGELOG.md | 2 +- SECURITY.md | 4 ++-- docs/compatibility.md | 16 ++++++++-------- docs/design.md | 10 +++++----- docs/slides.md | 20 ++++++++++---------- src/coefficient_sumcheck.rs | 18 +++++++++--------- src/field.rs | 18 +++++++++--------- src/inner_product_sumcheck.rs | 26 +++++++++++++------------- src/lib.rs | 2 +- src/multilinear_sumcheck.rs | 26 +++++++++++++------------- src/polynomial/dense.rs | 8 ++++---- src/polynomial/eval.rs | 12 ++++++------ src/polynomial/mod.rs | 2 +- src/polynomial/sequential_lagrange.rs | 6 +++--- src/proof.rs | 4 ++-- src/provers/coefficient.rs | 20 ++++++++++---------- src/provers/coefficient_lsb.rs | 20 ++++++++++---------- src/provers/eq_factored.rs | 10 +++++----- src/provers/gkr.rs | 8 ++++---- src/provers/inner_product.rs | 8 ++++---- src/provers/inner_product_lsb.rs | 14 +++++++------- src/provers/multilinear.rs | 8 ++++---- src/provers/multilinear_lsb.rs | 14 +++++++------- src/reductions/pairwise.rs | 10 +++++----- src/reductions/tablewise.rs | 4 ++-- src/runner.rs | 4 ++-- src/simd_sumcheck/dispatch.rs | 24 ++++++++++++------------ src/sumcheck_prover.rs | 4 ++-- src/transcript/sanity.rs | 6 +++--- src/verifier.rs | 10 +++++----- tests/plonky3_roundtrip.rs | 8 ++++---- 31 files changed, 173 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b534fd4..d786cacf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ Major revision: unified API, one verifier, one proof type, 7 provers, SIMD accel - **`SumcheckProver` trait** — single extension point for all polynomial shapes. - **7 concrete provers** — `MultilinearProver`, `InnerProductProver`, `CoefficientProver` (each with MSB + LSB variants), `GkrProver`. -- **`SumcheckRing` trait** — generic field interface; blanket impl for `ark_ff::Field` behind `feature = "arkworks"`. +- **`SumcheckField` trait** — generic field interface; blanket impl for `ark_ff::Field` behind `feature = "arkworks"`. - **`SimdRepr` trait** — safe SIMD opt-in with `zerocopy` layout verification. - **`runner::sumcheck()`** — single runner with partial execution and per-round hooks. - **Eq polynomial utilities** — `eq_poly`, `eq_poly_non_binary`, O(2^v) incremental `compute_hypercube_eq_evals`. diff --git a/SECURITY.md b/SECURITY.md index fd8bb5ba..78a857e6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -19,7 +19,7 @@ verifier challenges. This library implements plain (non-ZK) sumcheck. side-channel adversaries has not been formally verified**. Fixed-size Montgomery multiplication is inherently data-independent, but this has not been audited, and no constant-time claim is made for arbitrary - `SumcheckRing` implementations. Callers in that threat model must + `SumcheckField` implementations. Callers in that threat model must supply constant-time field operations. ## Oracle check @@ -56,7 +56,7 @@ SIMD subsystem, `unsafe` is confined to two categories: evaluate/reduce loops that call them. 2. **Field ↔ `u64` reinterpretation** — arkworks field types do not yet derive - `zerocopy`, so the blanket `SumcheckRing` impl for `ark_ff::Field` uses + `zerocopy`, so the blanket `SumcheckField` impl for `ark_ff::Field` uses `transmute_copy` and `from_raw_parts` to reinterpret Goldilocks elements as their underlying Montgomery-form `u64` values. These are centralized in five trait methods (`_to_raw_u64`, `_from_raw_u64`, `_as_u64_slice`, diff --git a/docs/compatibility.md b/docs/compatibility.md index fa7fc9b0..f8b8e221 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -1,13 +1,13 @@ # Non-arkworks field support -By default, the library provides a blanket `SumcheckRing` implementation for +By default, the library provides a blanket `SumcheckField` implementation for all `ark_ff::Field` types. Non-arkworks users can compile with `--no-default-features` and implement the trait for their own field type. -## `SumcheckRing` trait +## `SumcheckField` trait ```rust -pub trait SumcheckRing: +pub trait SumcheckField: Copy + Send + Sync + PartialEq + Debug + Add + Sub + Mul + Neg + AddAssign + SubAssign + MulAssign + Sum + 'static @@ -23,7 +23,7 @@ pub trait SumcheckRing: See [`tests/plonky3_roundtrip.rs`](../tests/plonky3_roundtrip.rs) for a complete working example — a newtype wrapper around `p3_goldilocks::Goldilocks` that -implements `SumcheckRing` and runs a full prove + verify roundtrip with no +implements `SumcheckField` and runs a full prove + verify roundtrip with no arkworks dependency. ## SIMD opt-in via `SimdRepr` @@ -38,7 +38,7 @@ compile-time layout verification — no `unsafe` needed from the implementor. #[repr(transparent)] struct MyGoldilocks(u64); -impl SumcheckRing for MyGoldilocks { +impl SumcheckField for MyGoldilocks { const ZERO: Self = MyGoldilocks(0); const ONE: Self = MyGoldilocks(1); // Montgomery form of 1 fn from_u64(val: u64) -> Self { /* ... */ } @@ -61,7 +61,7 @@ Extension fields work the same way: #[repr(transparent)] struct MyExt3([u64; 3]); -impl SumcheckRing for MyExt3 { +impl SumcheckField for MyExt3 { fn extension_degree() -> u64 { 3 } fn _simd_field_config() -> Option { Some(SimdFieldConfig { modulus: GOLDILOCKS_P, element_bytes: 8 }) @@ -83,6 +83,6 @@ arkworks = ["ark-ff", "ark-poly", "ark-serialize", "ark-std", "spongefish"] parallel = ["rayon"] ``` -- `arkworks` (default): blanket `SumcheckRing` impl for `ark_ff::Field` +- `arkworks` (default): blanket `SumcheckField` impl for `ark_ff::Field` - `parallel` (default): rayon parallelism for fold and round computation -- `--no-default-features`: pure `SumcheckRing` library, no arkworks dependency +- `--no-default-features`: pure `SumcheckField` library, no arkworks dependency diff --git a/docs/design.md b/docs/design.md index efc6142c..09ef17e0 100644 --- a/docs/design.md +++ b/docs/design.md @@ -64,7 +64,7 @@ runner parameterized by a prover trait, not three separate functions. /// Implementors define how the round polynomial g_j is computed /// from the prover's internal state. The protocol runner calls /// `round()` once per round, then the caller inspects post-state. -pub trait SumcheckProver { +pub trait SumcheckProver { /// Degree of g_j in the current variable X_j. fn degree(&self) -> usize; @@ -191,12 +191,12 @@ how `round()` computes the polynomial from the data. ```rust // In-memory (MSB, time strategy). -impl MultilinearProver { +impl MultilinearProver { pub fn new(evals: Vec) -> Self; } // Streaming (LSB or MSB, blendy strategy). -impl StreamingMultilinearProver { +impl StreamingMultilinearProver { /// Random-access stream, MSB ordering. Best for mmap'd data. pub fn new_msb>(stream: S, k: usize) -> Self; @@ -277,7 +277,7 @@ trait, whose memory layout guarantee is enforced at compile time by ```rust pub trait SimdRepr: - SumcheckRing + zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::Immutable + SumcheckField + zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::Immutable { fn modulus() -> u64; } @@ -297,7 +297,7 @@ impl SimdRepr for JoltGoldilocks { } ``` -Arkworks types bypass `SimdRepr` — the blanket `SumcheckRing` impl +Arkworks types bypass `SimdRepr` — the blanket `SumcheckField` impl auto-detects Goldilocks from `BasePrimeField::MODULUS` and the detection is const-folded by LLVM. diff --git a/docs/slides.md b/docs/slides.md index 7d559047..c9bfaac7 100644 --- a/docs/slides.md +++ b/docs/slides.md @@ -105,7 +105,7 @@ This motivates **one runner + one trait**, not three functions. ## The Prover Trait ```rust -pub trait SumcheckProver { +pub trait SumcheckProver { fn degree(&self) -> usize; fn round(&mut self, challenge: Option) -> Vec; fn finalize(&mut self, last_challenge: F); @@ -129,7 +129,7 @@ final_value() -> g(r_0, ..., r_{v-1}) // oracle value ## The Protocol Runner ```rust -pub fn sumcheck>( +pub fn sumcheck>( prover: &mut impl SumcheckProver, num_rounds: usize, transcript: &mut T, @@ -150,7 +150,7 @@ One function handles: ## The Verifier ```rust -pub fn sumcheck_verify>( +pub fn sumcheck_verify>( claimed_sum: F, expected_degree: usize, num_rounds: usize, @@ -201,7 +201,7 @@ full evaluation table. ## Unified Proof Type ```rust -pub struct SumcheckProof { +pub struct SumcheckProof { pub round_polys: Vec>, // g_j in EvalsInfty wire format pub challenges: Vec, // r_1, ..., r_v pub final_value: F, // g(r_1, ..., r_v) @@ -264,7 +264,7 @@ LLVM const-folds the branch. Zero overhead on non-Goldilocks. ```rust pub trait SimdRepr: - SumcheckRing + zerocopy::IntoBytes + zerocopy::FromBytes + SumcheckField + zerocopy::IntoBytes + zerocopy::FromBytes { fn modulus() -> u64; // GOLDILOCKS_P for SIMD } @@ -277,7 +277,7 @@ Layout safety is **compiler-verified** via zerocopy derives. No `unsafe`. ## Generic Field Trait ```rust -pub trait SumcheckRing: +pub trait SumcheckField: Copy + Send + Sync + PartialEq + Debug + Add + Sub + Mul + Neg + AddAssign + SubAssign + MulAssign @@ -304,7 +304,7 @@ Evaluations in base field BF (e.g., Goldilocks). Challenges from extension field EF (e.g., Goldilocks^3) for soundness. ```rust -pub trait ExtensionOf: SumcheckRing + From {} +pub trait ExtensionOf: SumcheckField + From {} ``` The transition is prover-internal: @@ -556,7 +556,7 @@ parallel = ["rayon", "ark-ff?/parallel", ...] simd = [] ``` -- `--no-default-features`: pure `SumcheckRing` library, no arkworks, no SIMD +- `--no-default-features`: pure `SumcheckField` library, no arkworks, no SIMD - `--features arkworks`: blanket impl for `ark_ff::Field` - `--features parallel`: rayon parallelism for fold and round computation - `--features simd`: SIMD backends (NEON, AVX-512 IFMA) for Goldilocks @@ -676,7 +676,7 @@ verifier challenges. This library implements plain (non-ZK) sumcheck. has not been formally verified**. Fixed-size Montgomery multiplication is inherently data-independent but -unaudited. No constant-time claim for arbitrary `SumcheckRing` impls. +unaudited. No constant-time claim for arbitrary `SumcheckField` impls. Callers in that threat model must supply constant-time field operations. See [SECURITY.md](../SECURITY.md) for the full threat model and reporting policy. @@ -705,7 +705,7 @@ See [SECURITY.md](../SECURITY.md) for the full threat model and reporting policy 6. **Features are orthogonal layers.** `arkworks`, `parallel`, and `simd` can be enabled independently. - The core library works with any `SumcheckRing` and zero dependencies. + The core library works with any `SumcheckField` and zero dependencies. --- diff --git a/src/coefficient_sumcheck.rs b/src/coefficient_sumcheck.rs index fc8bb0d0..49599a89 100644 --- a/src/coefficient_sumcheck.rs +++ b/src/coefficient_sumcheck.rs @@ -1,4 +1,4 @@ -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use ark_ff::Field; use ark_poly::univariate::DensePolynomial; @@ -47,7 +47,7 @@ pub struct CoefficientSumcheck { /// } /// } /// ``` -pub trait RoundPolyEvaluator: Sync { +pub trait RoundPolyEvaluator: Sync { /// The degree of the round polynomial (number of coefficients = degree + 1). fn degree(&self) -> usize; @@ -80,7 +80,7 @@ pub trait RoundPolyEvaluator: Sync { /// SIMD fast path for degree-1 with a single pairwise table. /// /// Returns `[sum_even, sum_odd - sum_even]` = coefficients of `h(x) = c0 + c1*x`. -fn simd_evaluate_degree1(pw: &[F]) -> Vec { +fn simd_evaluate_degree1(pw: &[F]) -> Vec { // Try SIMD dispatch for Goldilocks #[cfg(all( feature = "simd", @@ -113,7 +113,7 @@ fn simd_evaluate_degree1(pw: &[F]) -> Vec { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { +fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { crate::simd_sumcheck::dispatch::try_simd_evaluate_degree1(pw) } @@ -129,7 +129,7 @@ fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -fn try_simd_fused_reduce_evaluate( +fn try_simd_fused_reduce_evaluate( pw: &mut Vec, challenge: F, ) -> Option> { @@ -143,7 +143,7 @@ fn try_simd_fused_reduce_evaluate( all(target_arch = "x86_64", target_feature = "avx512ifma") ) )))] -fn try_simd_fused_reduce_evaluate( +fn try_simd_fused_reduce_evaluate( _pw: &mut Vec, _challenge: F, ) -> Option> { @@ -152,7 +152,7 @@ fn try_simd_fused_reduce_evaluate( /// Parallel evaluate using rayon (for heavy evaluators). #[cfg(feature = "parallel")] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -191,7 +191,7 @@ fn parallel_evaluate( /// Fallback when parallel feature is disabled. #[cfg(not(feature = "parallel"))] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -216,7 +216,7 @@ fn parallel_evaluate( /// Sequential evaluate (for trivial evaluators where rayon overhead dominates). /// /// Fills `coeffs_out` with accumulated coefficients (zeroes it first). -fn sequential_evaluate_into( +fn sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], diff --git a/src/field.rs b/src/field.rs index 390351e0..b464a155 100644 --- a/src/field.rs +++ b/src/field.rs @@ -1,6 +1,6 @@ -//! Generic ring trait for sumcheck. +//! Generic field trait for sumcheck. //! -//! [`SumcheckRing`] captures the minimum arithmetic interface needed by the +//! [`SumcheckField`] captures the minimum arithmetic interface needed by the //! sumcheck protocol. Any type with field-like operations (add, sub, mul, //! negate, invert) and two distinguished constants (zero, one) can implement //! this trait and use the full sumcheck library. @@ -27,7 +27,7 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; /// opt-in via [`_simd_field_config`](Self::_simd_field_config). Non-Goldilocks /// fields leave the default (returns `None`) and the library transparently /// falls back to scalar code. -pub trait SumcheckRing: +pub trait SumcheckField: Sized + Copy + Send @@ -176,7 +176,7 @@ pub const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; /// #[repr(transparent)] /// struct MyGoldilocks(u64); /// -/// impl SumcheckRing for MyGoldilocks { +/// impl SumcheckField for MyGoldilocks { /// // ... arithmetic ... /// fn _simd_field_config() -> Option { /// Some(SimdFieldConfig { modulus: GOLDILOCKS_P, element_bytes: 8 }) @@ -196,7 +196,7 @@ pub const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; /// #[repr(transparent)] /// struct MyExt3([u64; 3]); /// -/// impl SumcheckRing for MyExt3 { +/// impl SumcheckField for MyExt3 { /// fn extension_degree() -> u64 { 3 } /// fn _simd_field_config() -> Option { /// Some(SimdFieldConfig { modulus: GOLDILOCKS_P, element_bytes: 8 }) @@ -209,7 +209,7 @@ pub const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; /// } /// ``` pub trait SimdRepr: - SumcheckRing + zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::Immutable + SumcheckField + zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::Immutable { /// The base prime field modulus as a single `u64` limb. /// @@ -240,7 +240,7 @@ pub struct SimdFieldConfig { /// `zerocopy::IntoBytes + FromBytes + Immutable` — compiler-verified /// layout) and override `_simd_field_config()`. #[inline(always)] -pub fn simd_config() -> Option { +pub fn simd_config() -> Option { F::_simd_field_config() } @@ -248,7 +248,7 @@ pub fn simd_config() -> Option { /// /// The prover starts with evaluations in `BF` and folds into `EF` once /// the first challenge arrives. -pub trait ExtensionOf: SumcheckRing + From {} +pub trait ExtensionOf: SumcheckField + From {} // ─── Arkworks blanket implementation ──────────────────────────────────────── @@ -256,7 +256,7 @@ pub trait ExtensionOf: SumcheckRing + From {} mod ark_impl { use super::*; - impl SumcheckRing for F + impl SumcheckField for F where F: ark_ff::Field, { diff --git a/src/inner_product_sumcheck.rs b/src/inner_product_sumcheck.rs index b977b065..9fa31379 100644 --- a/src/inner_product_sumcheck.rs +++ b/src/inner_product_sumcheck.rs @@ -19,7 +19,7 @@ //! additional cache-locality gains from reading all four strides //! simultaneously. -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use alloc::vec::Vec; #[cfg(feature = "parallel")] use rayon::join; @@ -30,7 +30,7 @@ use crate::transcript::ProverTranscript; /// Legacy return type for `inner_product_sumcheck`. #[derive(Debug, PartialEq)] -pub struct ProductSumcheck { +pub struct ProductSumcheck { pub prover_messages: Vec<(F, F)>, pub verifier_messages: Vec, pub final_evaluations: (F, F), @@ -65,7 +65,7 @@ const fn workload_size() -> usize { // ─── Scalar helpers ───────────────────────────────────────────────────────── -fn dot(a: &[F], b: &[F]) -> F { +fn dot(a: &[F], b: &[F]) -> F { debug_assert_eq!(a.len(), b.len()); #[cfg(feature = "parallel")] if a.len() > workload_size::() { @@ -74,7 +74,7 @@ fn dot(a: &[F], b: &[F]) -> F { a.iter().zip(b).map(|(x, y)| *x * *y).sum() } -fn scalar_mul(v: &mut [F], w: F) { +fn scalar_mul(v: &mut [F], w: F) { for x in v.iter_mut() { *x *= w; } @@ -85,8 +85,8 @@ fn scalar_mul(v: &mut [F], w: F) { /// `(c0, c2)` of the round polynomial `q(x) = c0 + c1·x + c2·x²`. /// /// 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) { +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()); @@ -140,8 +140,8 @@ pub fn compute_sumcheck_polynomial(a: &[F], b: &[F]) -> (F, F) /// /// `values` is implicitly zero-padded to the next power of two. On return, /// the length is a power of two (or zero). -pub fn fold(values: &mut Vec, weight: F) { - fn recurse_both(low: &mut [F], high: &[F], weight: F) { +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; @@ -176,7 +176,7 @@ pub fn fold(values: &mut Vec, weight: F) { } /// Two-pass fold-then-compute; reference version kept for testing. -pub fn fold_and_compute_polynomial( +pub fn fold_and_compute_polynomial( a: &mut Vec, b: &mut Vec, weight: F, @@ -196,7 +196,7 @@ pub fn fold_and_compute_polynomial( /// /// Falls back to the unfused path for small or non-pow2 inputs so the /// implicit-zero tail accounting stays identical. -pub fn fused_fold_and_compute_polynomial( +pub fn fused_fold_and_compute_polynomial( a: &mut Vec, b: &mut Vec, weight: F, @@ -208,7 +208,7 @@ pub fn fused_fold_and_compute_polynomial( } #[allow(clippy::too_many_arguments)] - fn kernel( + fn kernel( a0: &mut [F], a1: &mut [F], a2: &[F], @@ -310,7 +310,7 @@ pub fn inner_product_sumcheck_partial( mut hook: H, ) -> ProductSumcheck where - F: SumcheckRing, + F: SumcheckField, T: ProverTranscript, H: FnMut(usize, &mut T), { @@ -370,7 +370,7 @@ pub fn inner_product_sumcheck( hook: H, ) -> ProductSumcheck where - F: SumcheckRing, + F: SumcheckField, T: ProverTranscript, H: FnMut(usize, &mut T), { diff --git a/src/lib.rs b/src/lib.rs index 5b8bd841..509557ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ extern crate alloc; -// ─── Generic ring trait ───────────────────────────────────────────────────── +// ─── Generic field trait ───────────────────────────────────────────────────── pub mod field; pub mod proof; diff --git a/src/multilinear_sumcheck.rs b/src/multilinear_sumcheck.rs index b7f054ba..8b3b598a 100644 --- a/src/multilinear_sumcheck.rs +++ b/src/multilinear_sumcheck.rs @@ -17,7 +17,7 @@ //! 4 reads + 2 writes per quadruple (fused) vs. 6 reads + 2 writes //! (fold + compute separately) — a ~33% memory-traffic reduction. -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use alloc::vec::Vec; #[cfg(feature = "parallel")] use rayon::join; @@ -28,7 +28,7 @@ use crate::transcript::ProverTranscript; /// Legacy return type for `multilinear_sumcheck`. #[derive(Debug)] -pub struct Sumcheck { +pub struct Sumcheck { pub prover_messages: Vec<(F, F)>, pub verifier_messages: Vec, pub final_evaluation: F, @@ -62,7 +62,7 @@ const fn workload_size() -> usize { // ─── Scalar helpers ───────────────────────────────────────────────────────── -fn sum_slice(v: &[F]) -> F { +fn sum_slice(v: &[F]) -> F { #[cfg(feature = "parallel")] if v.len() > workload_size::() { return v.par_iter().copied().sum(); @@ -70,7 +70,7 @@ fn sum_slice(v: &[F]) -> F { v.iter().copied().sum() } -fn scalar_mul(v: &mut [F], w: F) { +fn scalar_mul(v: &mut [F], w: F) { for x in v.iter_mut() { *x *= w; } @@ -83,8 +83,8 @@ fn scalar_mul(v: &mut [F], w: F) { /// `values` is implicitly zero-extended to the next power of two. /// - `s0 = Σ v[0..L/2]` (low half, possibly with tail contributions) /// - `s1 = Σ v[L/2..L]` -pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { - fn recurse(lo: &[F], hi: &[F]) -> (F, F) { +pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { + fn recurse(lo: &[F], hi: &[F]) -> (F, F) { debug_assert_eq!(lo.len(), hi.len()); #[cfg(feature = "parallel")] @@ -129,7 +129,7 @@ pub fn compute_sumcheck_polynomial(values: &[F]) -> (F, F) { /// /// SIMD-accelerated for Goldilocks base field on NEON and AVX-512 IFMA. /// Falls back to a scalar recursive `rayon::join` fold for other fields. -pub fn fold(values: &mut Vec, weight: F) { +pub fn fold(values: &mut Vec, weight: F) { // SIMD fast path for base-field Goldilocks (MSB layout). #[cfg(all( feature = "simd", @@ -144,7 +144,7 @@ pub fn fold(values: &mut Vec, weight: F) { return; } } - fn recurse_both(low: &mut [F], high: &[F], 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; @@ -178,7 +178,7 @@ pub fn fold(values: &mut Vec, weight: F) { } /// Two-pass fold-then-compute. Reference only. -pub fn fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { +pub fn fold_and_compute_polynomial(values: &mut Vec, weight: F) -> (F, F) { fold(values, weight); compute_sumcheck_polynomial(values) } @@ -186,7 +186,7 @@ pub fn fold_and_compute_polynomial(values: &mut Vec, weight: /// Fused fold + compute: folds `values` by `weight` *and* returns the /// next-round `(s0, s1)` in one sweep over the quadruple /// `(v[k], v[k+L/4], v[k+L/2], v[k+3L/4])`. -pub fn fused_fold_and_compute_polynomial( +pub fn fused_fold_and_compute_polynomial( values: &mut Vec, weight: F, ) -> (F, F) { @@ -195,7 +195,7 @@ pub fn fused_fold_and_compute_polynomial( return fold_and_compute_polynomial(values, weight); } - fn kernel( + fn kernel( v0: &mut [F], v1: &mut [F], v2: &[F], @@ -269,7 +269,7 @@ pub fn multilinear_sumcheck_partial( mut hook: H, ) -> Sumcheck where - F: SumcheckRing, + F: SumcheckField, T: ProverTranscript, H: FnMut(usize, &mut T), { @@ -325,7 +325,7 @@ pub fn multilinear_sumcheck( hook: H, ) -> Sumcheck where - F: SumcheckRing, + F: SumcheckField, T: ProverTranscript, H: FnMut(usize, &mut T), { diff --git a/src/polynomial/dense.rs b/src/polynomial/dense.rs index 58359be7..1ee51ca0 100644 --- a/src/polynomial/dense.rs +++ b/src/polynomial/dense.rs @@ -1,6 +1,6 @@ //! Zero-allocation dense polynomial arithmetic on coefficient slices. -use crate::field::SumcheckRing; +use crate::field::SumcheckField; /// Multiply polynomials `a` and `b`, writing the result into `out`. /// @@ -9,7 +9,7 @@ use crate::field::SumcheckRing; /// /// `a = [a_0, a_1, ..., a_m]`, `b = [b_0, b_1, ..., b_n]`. /// `out[k] = Σ_{i+j=k} a_i · b_j`. -pub fn mul_into(out: &mut [F], a: &[F], b: &[F]) { +pub fn mul_into(out: &mut [F], a: &[F], b: &[F]) { if a.is_empty() || b.is_empty() { for o in out.iter_mut() { *o = F::ZERO; @@ -36,7 +36,7 @@ pub fn mul_into(out: &mut [F], a: &[F], b: &[F]) { /// /// If `p` is longer than `out`, the extra terms are ignored. /// No allocation. -pub fn add_scaled(out: &mut [F], scalar: F, p: &[F]) { +pub fn add_scaled(out: &mut [F], scalar: F, p: &[F]) { let len = out.len().min(p.len()); for i in 0..len { out[i] += scalar * p[i]; @@ -47,7 +47,7 @@ pub fn add_scaled(out: &mut [F], scalar: F, p: &[F]) { /// /// Alias for [`eval_horner`](super::eval_horner). #[inline] -pub fn eval_at(coeffs: &[F], x: F) -> F { +pub fn eval_at(coeffs: &[F], x: F) -> F { super::eval_horner(coeffs, x) } diff --git a/src/polynomial/eval.rs b/src/polynomial/eval.rs index 60a5881b..989f007b 100644 --- a/src/polynomial/eval.rs +++ b/src/polynomial/eval.rs @@ -1,7 +1,7 @@ //! Polynomial evaluation: Horner's method and barycentric Lagrange interpolation. extern crate alloc; -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use alloc::vec; use alloc::vec::Vec; @@ -11,7 +11,7 @@ use alloc::vec::Vec; /// /// Cost: `d` multiplications + `d` additions. Zero allocation. #[inline] -pub fn eval_horner(coeffs: &[F], x: F) -> F { +pub fn eval_horner(coeffs: &[F], x: F) -> F { if coeffs.is_empty() { return F::ZERO; } @@ -29,7 +29,7 @@ pub fn eval_horner(coeffs: &[F], x: F) -> F { /// /// Cost: O(d) with precomputed [`BarycentricWeights`], O(d²) without. /// For repeated evaluations at the same degree, precompute weights once. -pub fn eval_from_evals(evals: &[F], x: F) -> F { +pub fn eval_from_evals(evals: &[F], x: F) -> F { let d = evals.len(); if d == 0 { return F::ZERO; @@ -51,12 +51,12 @@ pub fn eval_from_evals(evals: &[F], x: F) -> F { /// /// Weight `w_i = 1 / Π_{j≠i} (i − j)` for `i, j ∈ {0, ..., d}`. /// For consecutive integer nodes these are `(-1)^{d-i} / (i! · (d-i)!)`. -pub struct BarycentricWeights { +pub struct BarycentricWeights { /// Precomputed `w_i` for each node `i ∈ {0, ..., d}`. weights: Vec, } -impl BarycentricWeights { +impl BarycentricWeights { /// Precompute weights for interpolation at `{0, 1, ..., degree}`. pub fn new(degree: usize) -> Self { let d = degree + 1; // number of nodes @@ -131,7 +131,7 @@ impl BarycentricWeights { mod tests { use super::*; - // A simple ring-like wrapper for f64 won't work with SumcheckRing + // A simple field-like wrapper for f64 won't work with SumcheckField // (needs Copy + all the ops). Tests use the arkworks F64 type. #[cfg(feature = "arkworks")] mod ark_tests { diff --git a/src/polynomial/mod.rs b/src/polynomial/mod.rs index f0e4b033..f38de81a 100644 --- a/src/polynomial/mod.rs +++ b/src/polynomial/mod.rs @@ -1,6 +1,6 @@ //! Polynomial evaluation and arithmetic for sumcheck protocols. //! -//! Generic over [`SumcheckRing`](crate::field::SumcheckRing) — available without the `arkworks` feature. +//! Generic over [`SumcheckField`](crate::field::SumcheckField) — available without the `arkworks` feature. //! //! # Evaluation //! diff --git a/src/polynomial/sequential_lagrange.rs b/src/polynomial/sequential_lagrange.rs index 82615a58..ab6fded7 100644 --- a/src/polynomial/sequential_lagrange.rs +++ b/src/polynomial/sequential_lagrange.rs @@ -12,7 +12,7 @@ //! The amortized cost per step is O(1) (geometric series: 1 + 1/2 + 1/4 + ... = 2). extern crate alloc; -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use alloc::vec::Vec; /// Sequential Lagrange polynomial `eq(r, ·)` with incremental updates. @@ -32,7 +32,7 @@ use alloc::vec::Vec; /// // use eq_val... /// } /// ``` -pub struct SequentialLagrange { +pub struct SequentialLagrange { /// Precomputed factors: `factor_one[j] = r_j`, `factor_zero[j] = 1 − r_j`. factor_one: Vec, factor_zero: Vec, @@ -44,7 +44,7 @@ pub struct SequentialLagrange { num_vars: usize, } -impl SequentialLagrange { +impl SequentialLagrange { /// Initialize at the origin (index 0): `eq(r, 0) = Π_j (1 − r_j)`. pub fn new(point: &[F]) -> Self { let num_vars = point.len(); diff --git a/src/proof.rs b/src/proof.rs index d3a8a303..980c530a 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -4,7 +4,7 @@ extern crate alloc; -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use alloc::vec::Vec; use core::fmt; @@ -15,7 +15,7 @@ use core::fmt; /// consistency checks from this data; the final oracle check (verifying /// `final_value == g(r_1, ..., r_v)`) is the caller's responsibility. #[derive(Clone, Debug)] -pub struct SumcheckProof { +pub struct SumcheckProof { /// Round polynomial values, EvalsInfty wire format: `round_polys[j]` /// contains `d = degree` values per round. /// diff --git a/src/provers/coefficient.rs b/src/provers/coefficient.rs index 76ba9705..bd794843 100644 --- a/src/provers/coefficient.rs +++ b/src/provers/coefficient.rs @@ -6,7 +6,7 @@ //! For sequential streaming (Jolt-style), use //! [`CoefficientProverLSB`](super::coefficient_lsb::CoefficientProverLSB). -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::coefficient_sumcheck::RoundPolyEvaluator; use crate::sumcheck_prover::SumcheckProver; @@ -15,7 +15,7 @@ use crate::sumcheck_prover::SumcheckProver; use rayon::prelude::*; /// MSB coefficient sumcheck prover (arbitrary degree d, half-split layout). -pub struct CoefficientProver<'a, F: SumcheckRing, E: RoundPolyEvaluator> { +pub struct CoefficientProver<'a, F: SumcheckField, E: RoundPolyEvaluator> { evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>, @@ -24,7 +24,7 @@ pub struct CoefficientProver<'a, F: SumcheckRing, E: RoundPolyEvaluator> { deg: usize, } -impl<'a, F: SumcheckRing, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> { +impl<'a, F: SumcheckField, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> { pub fn new(evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>) -> Self { let n_tw = tablewise.len(); let n_pw = pairwise.len(); @@ -128,7 +128,7 @@ impl<'a, F: SumcheckRing, E: RoundPolyEvaluator> CoefficientProver<'a, F, E> // ─── MSB fold helpers ────────────────────────────────────────────────────── /// In-place MSB fold for a flat vector: `new[k] = v[k] + c*(v[k+half] - v[k])`. -fn msb_fold_vec(v: &mut Vec, challenge: F) { +fn msb_fold_vec(v: &mut Vec, challenge: F) { if v.len() <= 1 { return; } @@ -141,7 +141,7 @@ fn msb_fold_vec(v: &mut Vec, challenge: F) { /// MSB fold for tablewise: each row-vector is folded by pairing /// `(table[k], table[k+half])` and producing a new row. -fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { +fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { if table.len() <= 1 { return; } @@ -162,7 +162,7 @@ fn msb_fold_tablewise(table: &mut Vec>, challenge: F) { // ─── MSB evaluate helpers ────────────────────────────────────────────────── /// MSB pairing: pair index `k` with `k + half` (not `2k` with `2k+1`). -fn msb_sequential_evaluate_into( +fn msb_sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -189,7 +189,7 @@ fn msb_sequential_evaluate_into( } #[cfg(feature = "parallel")] -fn msb_parallel_evaluate( +fn msb_parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -222,7 +222,7 @@ fn msb_parallel_evaluate( } #[cfg(not(feature = "parallel"))] -fn msb_parallel_evaluate( +fn msb_parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -247,7 +247,7 @@ fn msb_parallel_evaluate( // ─── Horner evaluation ───────────────────────────────────────────────────── #[inline] -fn eval_poly_at(coeffs: &[F], x: F) -> F { +fn eval_poly_at(coeffs: &[F], x: F) -> F { if coeffs.is_empty() { return F::ZERO; } @@ -262,7 +262,7 @@ fn eval_poly_at(coeffs: &[F], x: F) -> F { impl<'a, F, E> SumcheckProver for CoefficientProver<'a, F, E> where - F: SumcheckRing, + F: SumcheckField, E: RoundPolyEvaluator, { fn degree(&self) -> usize { diff --git a/src/provers/coefficient_lsb.rs b/src/provers/coefficient_lsb.rs index d2c2193d..7b55c59c 100644 --- a/src/provers/coefficient_lsb.rs +++ b/src/provers/coefficient_lsb.rs @@ -8,7 +8,7 @@ //! workloads, prefer [`CoefficientProver`](super::coefficient::CoefficientProver) //! (MSB layout). -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::coefficient_sumcheck::RoundPolyEvaluator; use crate::reductions::{pairwise, tablewise}; @@ -34,7 +34,7 @@ use rayon::prelude::*; /// ); /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// ``` -pub struct CoefficientProverLSB<'a, F: SumcheckRing, E: RoundPolyEvaluator> { +pub struct CoefficientProverLSB<'a, F: SumcheckField, E: RoundPolyEvaluator> { evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>, @@ -47,7 +47,7 @@ pub struct CoefficientProverLSB<'a, F: SumcheckRing, E: RoundPolyEvaluator> { is_degree1_simd_path: bool, } -impl<'a, F: SumcheckRing, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, E> { +impl<'a, F: SumcheckField, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, E> { pub fn new(evaluator: &'a E, tablewise: Vec>>, pairwise: Vec>) -> Self { let n_tw = tablewise.len(); let n_pw = pairwise.len(); @@ -170,7 +170,7 @@ impl<'a, F: SumcheckRing, E: RoundPolyEvaluator> CoefficientProverLSB<'a, F, impl<'a, F, E> SumcheckProver for CoefficientProverLSB<'a, F, E> where - F: SumcheckRing, + F: SumcheckField, E: RoundPolyEvaluator, { fn degree(&self) -> usize { @@ -240,7 +240,7 @@ where /// Evaluate polynomial with coefficients `coeffs` at point `x` via Horner's method. #[inline] -fn eval_poly_at(coeffs: &[F], x: F) -> F { +fn eval_poly_at(coeffs: &[F], x: F) -> F { if coeffs.is_empty() { return F::ZERO; } @@ -253,7 +253,7 @@ fn eval_poly_at(coeffs: &[F], x: F) -> F { // ─── Evaluate strategies (same as coefficient_sumcheck.rs) ───────────────── -fn simd_evaluate_degree1(pw: &[F]) -> Vec { +fn simd_evaluate_degree1(pw: &[F]) -> Vec { #[cfg(all( feature = "simd", any( @@ -275,7 +275,7 @@ fn simd_evaluate_degree1(pw: &[F]) -> Vec { vec![s0, s1 - s0] } -fn try_simd_fused_reduce_evaluate( +fn try_simd_fused_reduce_evaluate( pw: &mut Vec, challenge: F, ) -> Option> { @@ -303,7 +303,7 @@ fn try_simd_fused_reduce_evaluate( } #[cfg(feature = "parallel")] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -336,7 +336,7 @@ fn parallel_evaluate( } #[cfg(not(feature = "parallel"))] -fn parallel_evaluate( +fn parallel_evaluate( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], @@ -358,7 +358,7 @@ fn parallel_evaluate( coeffs } -fn sequential_evaluate_into( +fn sequential_evaluate_into( evaluator: &impl RoundPolyEvaluator, tablewise: &[Vec>], pairwise: &[Vec], diff --git a/src/provers/eq_factored.rs b/src/provers/eq_factored.rs index c43e0401..a3492f4f 100644 --- a/src/provers/eq_factored.rs +++ b/src/provers/eq_factored.rs @@ -39,7 +39,7 @@ //! EvalsInfty for degree 2: `[q(0), q(∞)]`. The verifier derives //! `q(1) = claim - q(0)` and reconstructs the round polynomial. -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; @@ -64,7 +64,7 @@ use alloc::{vec, vec::Vec}; /// // final_value() = eq(w, r) · p(r) /// let (p_r, eq_wr) = prover.final_factors(); /// ``` -pub struct EqFactoredProver { +pub struct EqFactoredProver { /// `p` evaluations (MSB layout), padded to `2^v` on construction. /// Folded in every round. p: Vec, @@ -82,7 +82,7 @@ pub struct EqFactoredProver { rounds_elapsed: usize, } -impl EqFactoredProver { +impl EqFactoredProver { /// Construct a prover for `∑_x eq(w, x) · p(x)`. /// /// `p_evals.len()` must be `≤ 2^{w.len()}`; shorter inputs are @@ -214,7 +214,7 @@ impl EqFactoredProver { /// /// Runs in `O(2^v)` time with `O(2^v)` space. With `w.len() = v/2` this /// produces one of the split-value half-tables. -pub(crate) fn build_eq_table(w: &[F]) -> Vec { +pub(crate) fn build_eq_table(w: &[F]) -> Vec { let v = w.len(); if v == 0 { return vec![F::ONE]; @@ -240,7 +240,7 @@ pub(crate) fn build_eq_table(w: &[F]) -> Vec { impl SumcheckProver for EqFactoredProver where - F: SumcheckRing, + F: SumcheckField, { fn degree(&self) -> usize { 2 diff --git a/src/provers/gkr.rs b/src/provers/gkr.rs index 4bca5aa6..cbd225ae 100644 --- a/src/provers/gkr.rs +++ b/src/provers/gkr.rs @@ -29,7 +29,7 @@ //! let (w_b, w_c) = prover.claimed_w_values(); //! ``` -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; @@ -38,7 +38,7 @@ use alloc::{vec, vec::Vec}; /// GKR round sumcheck prover (degree 2). /// /// See [module docs](self) for details. -pub struct GkrProver { +pub struct GkrProver { /// Gate add predicate: `add_i(r, b, c)`, `2^{2k}` entries. add_evals: Vec, /// Gate mult predicate: `mult_i(r, b, c)`, `2^{2k}` entries. @@ -49,7 +49,7 @@ pub struct GkrProver { w_c: Vec, } -impl GkrProver { +impl GkrProver { /// Construct from gate predicates and witness evaluations. /// /// - `add_evals`: `add_i(r, b, c)` for all `(b, c) in {0,1}^{2k}`. @@ -96,7 +96,7 @@ impl GkrProver { impl SumcheckProver for GkrProver where - F: SumcheckRing, + F: SumcheckField, { fn degree(&self) -> usize { 2 diff --git a/src/provers/inner_product.rs b/src/provers/inner_product.rs index 9e267aee..391a9260 100644 --- a/src/provers/inner_product.rs +++ b/src/provers/inner_product.rs @@ -2,7 +2,7 @@ //! //! Implements [`SumcheckProver`] for the quadratic sumcheck `∑_x f(x)·g(x)`. -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::inner_product_sumcheck as ip; use crate::sumcheck_prover::SumcheckProver; use alloc::{vec, vec::Vec}; @@ -23,12 +23,12 @@ use alloc::{vec, vec::Vec}; /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// let (f_eval, g_eval) = prover.final_evaluations(); /// ``` -pub struct InnerProductProver { +pub struct InnerProductProver { a: Vec, b: Vec, } -impl InnerProductProver { +impl InnerProductProver { /// Time strategy prover: holds both evaluation vectors in memory. pub fn new(a: Vec, b: Vec) -> Self { assert_eq!(a.len(), b.len(), "a and b must have equal length"); @@ -52,7 +52,7 @@ impl InnerProductProver { impl SumcheckProver for InnerProductProver where - F: SumcheckRing, + F: SumcheckField, { fn degree(&self) -> usize { 2 diff --git a/src/provers/inner_product_lsb.rs b/src/provers/inner_product_lsb.rs index 907dea26..e2c0ee1b 100644 --- a/src/provers/inner_product_lsb.rs +++ b/src/provers/inner_product_lsb.rs @@ -8,7 +8,7 @@ //! workloads, prefer [`InnerProductProver`](super::inner_product::InnerProductProver) //! (MSB layout). -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::sumcheck_prover::SumcheckProver; use alloc::{vec, vec::Vec}; @@ -22,12 +22,12 @@ use alloc::{vec, vec::Vec}; /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// let (f_r, g_r) = prover.final_evaluations(); /// ``` -pub struct InnerProductProverLSB { +pub struct InnerProductProverLSB { a: Vec, b: Vec, } -impl InnerProductProverLSB { +impl InnerProductProverLSB { pub fn new(a: Vec, b: Vec) -> Self { assert_eq!(a.len(), b.len(), "a and b must have equal length"); Self { a, b } @@ -52,7 +52,7 @@ impl InnerProductProverLSB { /// /// q(0) = sum a[2k] * b[2k] /// q(∞) = [x²] q(x) = sum (a[2k+1] - a[2k]) * (b[2k+1] - b[2k]) -fn compute_lsb(a: &[F], b: &[F]) -> (F, F) { +fn compute_lsb(a: &[F], b: &[F]) -> (F, F) { debug_assert_eq!(a.len(), b.len()); if a.is_empty() { return (F::ZERO, F::ZERO); @@ -75,7 +75,7 @@ fn compute_lsb(a: &[F], b: &[F]) -> (F, F) { } /// In-place LSB fold: `new[k] = f[2k] + w * (f[2k+1] - f[2k])`. -fn fold_lsb(v: &mut Vec, weight: F) { +fn fold_lsb(v: &mut Vec, weight: F) { if v.len() <= 1 { return; } @@ -90,7 +90,7 @@ fn fold_lsb(v: &mut Vec, weight: F) { /// Fused fold + compute: fold both vectors with `weight`, then compute /// the next round's EvalsInfty `(q(0), q(∞))` in one pass over quads. -fn fused_fold_and_compute_lsb( +fn fused_fold_and_compute_lsb( a: &mut Vec, b: &mut Vec, weight: F, @@ -147,7 +147,7 @@ fn fused_fold_and_compute_lsb( impl SumcheckProver for InnerProductProverLSB where - F: SumcheckRing, + F: SumcheckField, { fn degree(&self) -> usize { 2 diff --git a/src/provers/multilinear.rs b/src/provers/multilinear.rs index e25d8f31..656a7f83 100644 --- a/src/provers/multilinear.rs +++ b/src/provers/multilinear.rs @@ -3,7 +3,7 @@ //! Wraps the fused fold+compute kernel from `multilinear_sumcheck.rs` //! behind the [`SumcheckProver`] trait. -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::multilinear_sumcheck::{ compute_sumcheck_polynomial, fold, fused_fold_and_compute_polynomial, }; @@ -22,11 +22,11 @@ use alloc::{vec, vec::Vec}; /// let mut prover = MultilinearProver::new(evals); /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// ``` -pub struct MultilinearProver { +pub struct MultilinearProver { evals: Vec, } -impl MultilinearProver { +impl MultilinearProver { /// Time strategy prover: holds all evaluations in memory. pub fn new(evals: Vec) -> Self { Self { evals } @@ -49,7 +49,7 @@ impl MultilinearProver { impl SumcheckProver for MultilinearProver where - F: SumcheckRing, + F: SumcheckField, { fn degree(&self) -> usize { 1 diff --git a/src/provers/multilinear_lsb.rs b/src/provers/multilinear_lsb.rs index 29aebd18..329fb8f3 100644 --- a/src/provers/multilinear_lsb.rs +++ b/src/provers/multilinear_lsb.rs @@ -9,7 +9,7 @@ //! workloads, prefer [`MultilinearProver`](super::multilinear::MultilinearProver) //! (MSB layout). -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::sumcheck_prover::SumcheckProver; use alloc::{vec, vec::Vec}; @@ -26,11 +26,11 @@ use rayon::prelude::*; /// let mut prover = MultilinearProverLSB::new(evals); /// let proof = sumcheck(&mut prover, num_rounds, &mut transcript, |_, _| {}); /// ``` -pub struct MultilinearProverLSB { +pub struct MultilinearProverLSB { evals: Vec, } -impl MultilinearProverLSB { +impl MultilinearProverLSB { /// Time strategy prover with LSB (pair-split) layout. pub fn new(evals: Vec) -> Self { Self { evals } @@ -57,7 +57,7 @@ impl MultilinearProverLSB { /// /// `s0 = sum of even-indexed elements = sum f[2k]` /// `s1 = sum of odd-indexed elements = sum f[2k+1]` -fn compute_lsb(evals: &[F]) -> (F, F) { +fn compute_lsb(evals: &[F]) -> (F, F) { if evals.is_empty() { return (F::ZERO, F::ZERO); } @@ -96,7 +96,7 @@ fn compute_lsb(evals: &[F]) -> (F, F) { } /// In-place LSB (pair-split) fold: `new[k] = f[2k] + w * (f[2k+1] - f[2k])`. -fn fold_lsb(evals: &mut Vec, weight: F) { +fn fold_lsb(evals: &mut Vec, weight: F) { if evals.len() <= 1 { return; } @@ -125,7 +125,7 @@ fn fold_lsb(evals: &mut Vec, weight: F) { /// Fused fold + compute: fold with `weight`, then compute the next round's /// (s0, s1) from the folded data. Single pass over pairs of pairs. -fn fused_fold_and_compute_lsb(evals: &mut Vec, weight: F) -> (F, F) { +fn fused_fold_and_compute_lsb(evals: &mut Vec, weight: F) -> (F, F) { let n = evals.len(); if n < 4 { fold_lsb(evals, weight); @@ -165,7 +165,7 @@ fn fused_fold_and_compute_lsb(evals: &mut Vec, weight: F) -> // ─── SumcheckProver impl ─────────────────────────────────────────────────── -impl SumcheckProver for MultilinearProverLSB { +impl SumcheckProver for MultilinearProverLSB { fn degree(&self) -> usize { 1 } diff --git a/src/reductions/pairwise.rs b/src/reductions/pairwise.rs index eb95415e..430a9a05 100644 --- a/src/reductions/pairwise.rs +++ b/src/reductions/pairwise.rs @@ -1,4 +1,4 @@ -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use ark_ff::Field; use ark_std::vec::Vec; use ark_std::{cfg_chunks, cfg_into_iter}; @@ -10,7 +10,7 @@ use rayon::{ use crate::streams::Stream; -pub fn evaluate(src: &[F]) -> (F, F) { +pub fn evaluate(src: &[F]) -> (F, F) { let even_sum = cfg_into_iter!(0..src.len()) .step_by(2) .map(|i| src[i]) @@ -35,7 +35,7 @@ pub fn evaluate_from_stream>(src: &S) -> (F, F) { (even_sum, odd_sum) } -pub fn reduce_evaluations(src: &mut Vec, verifier_message: F) { +pub fn reduce_evaluations(src: &mut Vec, verifier_message: F) { /// Below this input size, the serial in-place path wins: rayon's /// fork/join overhead exceeds the actual compute, and we avoid the /// `.collect()` allocation entirely. Above it, parallelism outpaces @@ -93,7 +93,7 @@ pub fn reduce_evaluations_from_stream>( /// round polynomial `q(x) = a + bx + cx²`: /// - `a = Σ f_even · g_even` /// - `b = Σ (f_even · g_odd + f_odd · g_even)` -pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { +pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { let half_len = src[0].len() / 2; let a: F = cfg_into_iter!(0..half_len) .map(|k| { @@ -113,7 +113,7 @@ pub fn pairwise_product_evaluate(src: &[Vec]) -> (F, F) { /// Cross-field reduce: fold `BF` evaluations with an `EF` challenge, producing `Vec`. /// /// For each adjacent pair `(a, b)` in `src`: `EF::from(a) + challenge * (EF::from(b) - EF::from(a))`. -pub fn cross_field_reduce>( +pub fn cross_field_reduce>( src: &[BF], challenge: EF, ) -> Vec { diff --git a/src/reductions/tablewise.rs b/src/reductions/tablewise.rs index 14789892..0bb8930b 100644 --- a/src/reductions/tablewise.rs +++ b/src/reductions/tablewise.rs @@ -1,9 +1,9 @@ -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use ark_std::{cfg_chunks, vec::Vec}; #[cfg(feature = "parallel")] use rayon::{iter::ParallelIterator, prelude::ParallelSlice}; -pub fn reduce_evaluations(src: &mut Vec>, verifier_message: F) { +pub fn reduce_evaluations(src: &mut Vec>, verifier_message: F) { let out: Vec> = cfg_chunks!(src, 2) .map(|chunk| { chunk[0] diff --git a/src/runner.rs b/src/runner.rs index 33703a03..06efce0c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -10,7 +10,7 @@ //! commit/open). extern crate alloc; -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::proof::SumcheckProof; use crate::sumcheck_prover::SumcheckProver; use crate::transcript::ProverTranscript; @@ -26,7 +26,7 @@ use alloc::vec::Vec; /// If `num_rounds == v` (full execution), `proof.final_value` is the /// prover's claimed evaluation at the random point. For partial execution, /// the caller retains `prover` and can continue or inspect post-state. -pub fn sumcheck>( +pub fn sumcheck>( prover: &mut impl SumcheckProver, num_rounds: usize, transcript: &mut T, diff --git a/src/simd_sumcheck/dispatch.rs b/src/simd_sumcheck/dispatch.rs index 233a36b5..ea7345ca 100644 --- a/src/simd_sumcheck/dispatch.rs +++ b/src/simd_sumcheck/dispatch.rs @@ -8,7 +8,7 @@ //! - **aarch64**: NEON backend (2-wide, scalar mul fallback) //! - **x86_64 + AVX-512 IFMA**: AVX-512 backend (8-wide, true IFMA mul) //! -//! Detection uses [`SumcheckRing::_simd_field_config()`] — the arkworks +//! Detection uses [`SumcheckField::_simd_field_config()`] — the arkworks //! blanket impl returns the actual modulus, non-arkworks fields return //! `None` by default (no SIMD). After monomorphization the check is //! constant-folded by LLVM, so the dead branch is eliminated entirely. @@ -16,7 +16,7 @@ //! # Safety //! //! This module contains **no `unsafe` code**. All field ↔ `u64` -//! reinterpretation is delegated to the safe `SumcheckRing` trait methods +//! reinterpretation is delegated to the safe `SumcheckField` trait methods //! (`_to_raw_u64`, `_from_raw_u64`, `_as_u64_slice`, `_as_u64_slice_mut`, //! `_from_u64_components`), whose implementations centralize the necessary //! `unsafe` in the arkworks blanket impl with full SAFETY documentation. @@ -28,7 +28,7 @@ all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -use crate::field::SumcheckRing; +use crate::field::SumcheckField; /// Goldilocks modulus: p = 2^64 − 2^32 + 1. #[cfg(all( @@ -43,7 +43,7 @@ const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; /// Returns `true` when `F` is a Goldilocks prime field stored as a /// single `u64` in Montgomery form. /// -/// Uses [`SumcheckRing::_simd_field_config()`] for detection. +/// Uses [`SumcheckField::_simd_field_config()`] for detection. /// After monomorphization every operand is a compile-time constant, /// so LLVM folds the entire function to `true` or `false`. #[cfg(all( @@ -54,7 +54,7 @@ const GOLDILOCKS_P: u64 = 0xFFFF_FFFF_0000_0001; ) ))] #[inline(always)] -fn is_goldilocks() -> bool { +fn is_goldilocks() -> bool { if F::extension_degree() != 1 { return false; } @@ -78,7 +78,7 @@ fn is_goldilocks() -> bool { ) ))] #[inline(always)] -fn is_goldilocks_based() -> bool { +fn is_goldilocks_based() -> bool { match F::_simd_field_config() { Some(cfg) => { if cfg.modulus != GOLDILOCKS_P || cfg.element_bytes != 8 { @@ -105,7 +105,7 @@ fn is_goldilocks_based() -> bool { all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_reduce(evals: &mut Vec, challenge: F) -> bool { +pub(crate) fn try_simd_reduce(evals: &mut Vec, challenge: F) -> bool { if !is_goldilocks::() { return false; } @@ -136,7 +136,7 @@ pub(crate) fn try_simd_reduce(evals: &mut Vec, challenge: F) all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_reduce_msb(evals: &mut Vec, challenge: F) -> bool { +pub(crate) fn try_simd_reduce_msb(evals: &mut Vec, challenge: F) -> bool { if !is_goldilocks::() { return false; } @@ -168,7 +168,7 @@ pub(crate) fn try_simd_reduce_msb(evals: &mut Vec, challenge all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_fused_reduce_evaluate_degree1( +pub(crate) fn try_simd_fused_reduce_evaluate_degree1( pw: &mut Vec, challenge: F, ) -> Option> { @@ -209,7 +209,7 @@ pub(crate) fn try_simd_fused_reduce_evaluate_degree1( all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_ext_evaluate(evals: &[EF]) -> Option<(EF, EF)> { +pub(crate) fn try_simd_ext_evaluate(evals: &[EF]) -> Option<(EF, EF)> { if !is_goldilocks_based::() { return None; } @@ -252,7 +252,7 @@ pub(crate) fn try_simd_ext_evaluate(evals: &[EF]) -> Option<(E all(target_arch = "x86_64", target_feature = "avx512ifma") ) ))] -pub(crate) fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { +pub(crate) fn try_simd_evaluate_degree1(pw: &[F]) -> Option> { if !is_goldilocks::() { return None; } @@ -282,6 +282,6 @@ pub(crate) fn try_simd_evaluate_degree1(pw: &[F]) -> Option() -> bool { +pub fn is_goldilocks_pub() -> bool { is_goldilocks::() } diff --git a/src/sumcheck_prover.rs b/src/sumcheck_prover.rs index d3058d5a..2658864d 100644 --- a/src/sumcheck_prover.rs +++ b/src/sumcheck_prover.rs @@ -8,7 +8,7 @@ //! completes. extern crate alloc; -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use alloc::vec::Vec; /// Prover side of the sum-check protocol (Thaler Proposition 4.1). @@ -33,7 +33,7 @@ use alloc::vec::Vec; /// let proof = sumcheck(&mut prover, n, &mut t, |_, _| {}); /// let (f_eval, g_eval) = prover.final_evaluations(); // prover-specific /// ``` -pub trait SumcheckProver { +pub trait SumcheckProver { /// Maximum degree of the round polynomial in the current variable. fn degree(&self) -> usize; diff --git a/src/transcript/sanity.rs b/src/transcript/sanity.rs index 2d49879a..defede55 100644 --- a/src/transcript/sanity.rs +++ b/src/transcript/sanity.rs @@ -1,6 +1,6 @@ use rand_core::RngCore; -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::transcript::{ProverTranscript, VerifierTranscript}; /// Test transcript: sends are no-ops, receives return `Ok(random)`, @@ -24,7 +24,7 @@ impl<'a, R> TestTranscript<'a, R> { // avoiding accidental collisions. impl<'a, F, R> ProverTranscript for TestTranscript<'a, R> where - F: SumcheckRing, + F: SumcheckField, R: RngCore, { fn send(&mut self, _value: F) { @@ -38,7 +38,7 @@ where impl<'a, F, R> VerifierTranscript for TestTranscript<'a, R> where - F: SumcheckRing, + F: SumcheckField, R: RngCore, { type Error = core::convert::Infallible; diff --git a/src/verifier.rs b/src/verifier.rs index 563da620..84843393 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -24,7 +24,7 @@ //! consistency constraint `h(0) + h(1) = claim`. extern crate alloc; -use crate::field::SumcheckRing; +use crate::field::SumcheckField; use crate::proof::SumcheckError; use crate::transcript::VerifierTranscript; use alloc::vec; @@ -35,7 +35,7 @@ use alloc::vec::Vec; /// The caller **must** verify `final_claim` — either by direct comparison, /// PCS opening, or delegation to the next protocol layer. #[derive(Clone, Debug)] -pub struct SumcheckResult { +pub struct SumcheckResult { /// Verifier challenges `r_1, ..., r_v`. pub challenges: Vec, /// The reduced claim after all rounds: `g_v(r_v)`. @@ -58,7 +58,7 @@ pub struct SumcheckResult { /// Returns [`SumcheckResult`] containing the challenges and final claim. /// The caller is responsible for the oracle check — verifying that /// `final_claim == g(r_1, ..., r_v)`. -pub fn sumcheck_verify>( +pub fn sumcheck_verify>( claimed_sum: F, expected_degree: usize, num_rounds: usize, @@ -143,7 +143,7 @@ pub fn sumcheck_verify>( /// /// Uses Lagrange interpolation: /// g(r) = Σ_i g(i) · Π_{j≠i} (r − j) / (i − j) -pub(crate) fn evaluate_from_evals(evals: &[F], r: F) -> F { +pub(crate) fn evaluate_from_evals(evals: &[F], r: F) -> F { let d = evals.len(); // number of interpolation nodes if d == 0 { return F::ZERO; @@ -184,7 +184,7 @@ pub(crate) fn evaluate_from_evals(evals: &[F], r: F) -> F { } /// Barycentric weight: Π_{j≠i, 0≤j(i: usize, d: usize) -> F { +fn barycentric_weight(i: usize, d: usize) -> F { let mut w = F::ONE; for j in 0..d { if j != i { diff --git a/tests/plonky3_roundtrip.rs b/tests/plonky3_roundtrip.rs index 36b28660..7dbfb87f 100644 --- a/tests/plonky3_roundtrip.rs +++ b/tests/plonky3_roundtrip.rs @@ -1,9 +1,9 @@ //! Roundtrip test demonstrating effsc with a Plonky3 field. //! //! Shows that any ecosystem's field type works with the sumcheck library -//! via a thin `SumcheckRing` impl — no arkworks dependency required. +//! via a thin `SumcheckField` impl — no arkworks dependency required. -use effsc::field::SumcheckRing; +use effsc::field::SumcheckField; use effsc::noop_hook; use effsc::provers::multilinear_lsb::MultilinearProverLSB; use effsc::runner::sumcheck; @@ -20,7 +20,7 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; // ─── Newtype wrapper ─────────────────────────────────────────────────────── -/// Thin wrapper around Plonky3's Goldilocks to implement `SumcheckRing`. +/// Thin wrapper around Plonky3's Goldilocks to implement `SumcheckField`. #[derive(Copy, Clone, Debug, PartialEq)] struct P3Goldilocks(Goldilocks); @@ -88,7 +88,7 @@ impl Sum for P3Goldilocks { } } -impl SumcheckRing for P3Goldilocks { +impl SumcheckField for P3Goldilocks { const ZERO: Self = Self(Goldilocks::new(0)); const ONE: Self = Self(Goldilocks::new(1));