Skip to content

Speed up SHA-256 constraint and witness synthesis - #512

Open
Leandro Rometsch (leandro-ro) wants to merge 1 commit into
microsoft:mainfrom
leandro-ro:perf/multieq-uint32-lc-allocs
Open

Speed up SHA-256 constraint and witness synthesis#512
Leandro Rometsch (leandro-ro) wants to merge 1 commit into
microsoft:mainfrom
leandro-ro:perf/multieq-uint32-lc-allocs

Conversation

@leandro-ro

@leandro-ro Leandro Rometsch (leandro-ro) commented Aug 27, 2026

Copy link
Copy Markdown

What

This PR removes three sources of overhead in the frontend gadgets used by SHA-256. In the benchmark below, the fitted per-block proving cost shows a 4.2× reduction (without changing the generated constraints or witness).

1. Avoid cloning MultiEq accumulators

MultiEq::enforce_equal cloned its growing accumulators whenever an equality was packed:

self.lhs = self.lhs.clone() + (coeff, lhs);
self.rhs = self.rhs.clone() + (coeff, rhs);

Using mem::take preserves the result while eliminating repeated copying. The same unnecessary clones were removed from MultiEq::accumulate.

2. Skip unused work during witness generation

WitnessCS::enforce discards constraints, so constructing linear combinations during witness generation is unnecessary.

MultiEq::enforce_equal now returns early in witness-only mode, and UInt32::addmany skips constructing lc and result_lc. Variable allocation, ordering, and assignment computation are unchanged.

3. Avoid an intermediate LinearCombination per bit

UInt32::addmany previously constructed a temporary one-term LinearCombination through Boolean::lc for every bit. The new push_bool helper adds the equivalent term directly to the destination.

Correctness

For constraint-generating systems, the same linear combinations are produced in the same order. For witness generators, the same variables are allocated in the same order with the same assignments; only linear combinations that would be discarded are omitted.

Validation:

cargo fmt --all -- --check
cargo clippy --lib --tests -- -D warnings
cargo test
cargo test --release --features experimental neutron   

Benchmarks

cargo bench --features test-utils --bench sha256

Configuration:

  • Apple M4 Pro, 12 cores (8 performance, 4 efficiency)
  • 48 GB memory
  • macOS 26.5.2 (arm64)
  • Rust 1.97.0, Cargo 1.97.0
  • BN254/Grumpkin with KZG
  • Criterion sample size: 10
  • Target: Prove
Bytes Blocks Before After Speedup
64 2 28.93 ms 22.74 ms 1.27×
128 3 33.54 ms 23.55 ms 1.42×
256 5 41.88 ms 25.98 ms 1.61×
512 9 58.66 ms 29.04 ms 2.02×
1024 17 94.12 ms 38.27 ms 2.46×

Criterion reported a statistically significant improvement at every size (p < 0.05). The speedup grows with the number of SHA-256 blocks.

A linear fit gives:

before: 20.24 ms fixed + 4.331 ms/block
after:  20.51 ms fixed + 1.028 ms/block

This is consistent with unchanged fixed overhead and an approximately 4.2× reduction in per-block cost.

@leandro-ro

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant