Small value NeutronNova (with small-value witness generation)#125
Draft
wu-s-john wants to merge 59 commits into
Draft
Small value NeutronNova (with small-value witness generation)#125wu-s-john wants to merge 59 commits into
wu-s-john wants to merge 59 commits into
Conversation
Add support for accumulating field × small_int products (i32, i64, i128) with delayed modular reduction using generic Barrett reduction: - SmallValueField<V> trait for small integer ↔ field conversion - WideMul trait for widening multiplication - BarrettReductionConstants with compile-time computed μ = ⌊2^512/p⌋ - SignedWideLimbs<N> accumulator for signed product sums - DelayedReduction<i32/i64/i128> implementations for all fields
This replaces expensive field multiplications with native integer
arithmetic during the first ℓ₀ rounds when polynomial values are
guaranteed small.
Key components:
Lagrange accumulator infrastructure (src/lagrange_accumulator/):
- LagrangeAccumulators: precomputed A_i(v, u) values for all rounds
- LagrangeIndex/LagrangePoint/LagrangeHatPoint: type-safe domain indices
- LagrangeBasisFactory: barycentric Lagrange basis with O(D) evaluation
- extend_to_lagrange_domain: batch extension from {0,1}^ℓ₀ to U_D^ℓ₀
- EqRoundFactor: tracks α = eq(τ_{<i}, r_{<i}) across rounds
- Csr: compressed sparse row storage (2 allocations vs N+1 for Vec<Vec>)
Performance optimizations:
- Thread-local SpartanThreadState eliminates per-iteration allocations
- Delayed modular reduction via SignedWideLimbs accumulators
- Skip binary betas (Az·Bz = Cz on {0,1}^n for satisfying witnesses)
- Batched eq-weighted binding in transition phase
API:
- SmallValue trait: WideMul + Copy + Zero + Add + Sub + Send + Sync
- SmallValueEngine<SV>: blanket impl consolidates field requirements
- prove_cubic_small_value<E, SV, const LB>: main entry point
The prove_cubic_small_value function produces identical proofs to the
standard prove_cubic_with_three_inputs, verified via equivalence tests.
Splits the small-value accumulator prep/prove path out of neutronnova_zk
into a new small_neutronnova_zk module. Along with the move:
- Consolidates build_accumulators_neutronnova: the full-small (l0 == ell_b)
and partial-small (l0 < ell_b) variants now live in one function;
_partial is removed from the lagrange_accumulator surface.
- Factors the bit-reversed prefix gather + Lagrange-extend pattern into
bit_rev_prefix_table and gather_and_extend_prefix helpers in
lagrange_accumulator::extension, shared by the merged builder,
build_extended_prefix_mle_evals, and the test that compares them.
- Simplifies the small-value casting API: removes
vec_to_small_for_extension_with_context; the call sites in
build_small_abc wrap with .map_err to prepend "accumulator prep
{matrix} layer={idx}" to the context.
- Drops the unused SmallSparseMatrix path from r1cs::sparse.
Generalize WideMul and raw SparseMatrix matvec over coefficient, witness, and output types. Update small NeutronNova, small-value accumulation, provider fields, SHA small tests, and benchmarks to use the generic arithmetic path.
Contributor
Author
|
Here are results on a Macbook Pro M1:
|
…cuits Four fixes, each with a regression test: - SplitMultiRoundR1CSInstance::validate and SplitR1CSInstance::validate now re-check the vector lengths enforced by new() before any indexing, since deserialized proofs bypass new(). Malformed proofs (wrong-length comm_w_per_round, challenges_per_round, or public_values) previously panicked the verifier; they now return ProofVerifyError. - NeutronNova NIFS witness fold takes the truncated fast path only when the step shape has no rest witness (num_rest_unpadded == 0). Step circuits with both precommitted and rest variables previously had their rest segment zeroed out of the folded witness and partial commitment fold, producing proofs that fail verification. Applied to both the field path and the small-accumulator fold helper. - Re-synthesis before each prove now preserves public inputs allocated during the shared/precommitted phases (PrecommittedState::num_prep_inputs, serde-default 0 for old prep states) instead of truncating them away, so circuits may inputize public IO in any phase. The publics extraction in spartan_zk and bellpepper now returns a clear SynthesisError instead of panicking when a circuit inputizes fewer values than the shape expects. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… unified hot loops R1 — single post-NIFS pipeline. finish_zk_proof() now carries the ~350-line tail (batched outer/inner sum-checks, final rounds, NovaNIFS + relaxed Spartan, c_eval folding, PCS prove, proof assembly) for BOTH the field path (NeutronNovaZkSNARK::prove) and the small-accumulator path (prove_small), which previously duplicated it verbatim. Also unifies setup/setup_small via setup_from_shapes() and the NIFS prover head via prepare_nifs_inputs(). prove_small now also strips per-instance shared commitments (smaller proofs; verify already tolerated both forms). R2 — SpartanRoundSchedule / NeutronRoundSchedule (zk.rs) are the single source of truth for multi-round circuit indices and challenge/public-value counts; prover and verifier both derive indices from them instead of hand-computed arithmetic mirrored across three files. R3 — VcDriver (bellpepper/r1cs.rs) bundles the verifier circuit, multi-round state, shape, and commitment key that previously threaded as a quintuple through every sum-check and process_round call site; commit_round() is now the single place enforcing the commit-then-squeeze discipline. R4 — hot-loop dedupe: prove_helper and the AB-only fold-extension variant collapse into one tensor_eq_fold_terms worker with const generics (COMPUTE_E0, WITH_CZ); one set of fold primitives (fold_in_place, fold_quad_chunk, fold_layer_pair_into, fold_final_layer_pairs) replaces eight inline copies of the lo/hi fold pattern across both NIFS files. Benchmarked prove/2048B/t8 across full-field, small-value, and small-accum l0-3/4/5: all deltas within criterion noise, accumulator still beats baseline at every cell. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- StepMatVecCache owns the deterministic step matvec/i64-mirror/ large-positions triple and establishes its zeroed-at-large-positions invariant in one constructor; NeutronNovaPrepZkSNARK collapses three loosely-coupled fields into one Option<StepMatVecCache>, and NeutronNovaNIFS::prove takes the cache as a single argument. - digest::bincode_write replaces the repeated bincode-config boilerplate in both verifier-key Digestible impls (identical bytes, digests unchanged). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…chinery
No backend ever consumed annotations or namespaces (small shapes are purely
structural), so the trait shrinks from 7 methods + Root/SmallNamespace
machinery to alloc/alloc_input/enforce + is_witness_generator. A blanket
impl for &mut CS keeps by-value-generic gadget helpers callable, mirroring
bellpepper's pattern.
- All gadget and circuit call sites drop annotation arguments and
namespace() wrappers; label-only parameters (block_idx/prefix/loop
indices) are removed.
- small_sha256_int_with_prefix and
small_sha256_compression_function_int_with_prefix are folded into their
non-prefix variants: prefixes only fed namespace labels, which no longer
exist.
- The bellpepper bridge synthesizes unique lazy names (sv{n}/sc{n}) since
TestConstraintSystem requires them; production backends never evaluate
the closures.
- NoBatchEq loses its label counters and its now-empty namespace plumbing.
Shapes are unchanged (names never influenced them) — verified by the
field-vs-small-compiler equivalence tests and the full suite (299 passing).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The five build_accumulators_* functions shared ~70% of their bodies. Three shared pieces now exist once: - neutron_eq_setup: tensor-split eq caches, suffix fold weights, and the β→prefix-index tables (NeutronEqSetup) consumed identically by every NeutronNova input-format variant - collect_and_scatter_betas: the reduce-nonzero-βs + scatter-into-rounds tail shared by all five builders (generic over the unreduced product type, so both SpartanThreadState and the ext-workspace ProductState use it) - run_outer_fold: the serial-vs-rayon fold/reduce driver The per-format gather kernels (the hot inner loops) are untouched. build_accumulators_spartan now also gets the small-workload serial path. Verified with alternated A/B benches on prove/small-accum/l0-4 (pre avg 71.3 ms vs post avg 70.4 ms; prep+prove 98.9 vs 99.5 ms) — neutral within machine noise. Full suite passes (299), including the preextended-vs-generic and NIFS polynomial-equivalence cross-checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SmallAbc, PrefixWorkspace, ExtendedPrefixMleEvals, and the prefix/suffix fold helpers that operate on them move to a child module (small_neutronnova_workspace.rs), shrinking small_neutronnova_zk.rs to the prep/prove pipeline and the accumulator NIFS driver. Pure code motion; the no-custom-macros introspection test now covers both files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Runs the most optimized version of small-value NeutronNova.
It works on top of PR #124, where it focuses on running the sumcheck accumulator on NeutronNova.
This PR takes it further an optimize the performance even more so that witness generation of SHA-256 are working with small numbers. It generates the witnesses as boolean and the matrix coefficient as i32. For computing the lagrange extended points of Aw, Bw and Cw, it still remains in i32. We do this to use small values as much as possible at the expense of slightly, increasing the number of constraints and witnesses. The results below demonstrate that the trade off is worthwhile.
The computations where executed on a 32 core AMD Ryzen 9 CPU. No GPU computation was done
You can run the experiments via: