feat: SRS point compression - download 50% less CRS data#21112
Merged
johnathan79717 merged 21 commits intoMar 24, 2026
Conversation
a7f4b6f to
6b57576
Compare
6b57576 to
18a1ab8
Compare
Base automatically changed from
claudebox/hybrid-crs-hash-verification
to
merge-train/barretenberg
March 4, 2026 17:26
1bdb1da to
a78b80a
Compare
Collaborator
|
Damn, talk about a big decentralization win. |
ludamad
reviewed
Mar 4, 2026
ludamad
reviewed
Mar 4, 2026
Remove references to uncompressed g1.dat; all tests now use g1_compressed.dat consistently.
- Add 3 retries with 5s delay to download_with_fallback in both crs/bootstrap.sh and scripts/download_bb_crs.sh - Call crs/bootstrap.sh from run_test.sh to ensure compressed CRS is available (CI AMI may only have old uncompressed g1.dat)
Include the file path and suggest running crs/bootstrap.sh.
…ect parity sign bit The compression script was using y > p/2 to set the sign bit, but bb::affine_element::from_compressed uses LSB of y (parity). This caused the second element verification to fail in ASAN builds. Regenerated all 763 chunk hashes from the correctly compressed 3.2GB file.
Switch prepare_crs to copy bn254_g1_compressed.dat (32 bytes/point) instead of bn254_g1.dat (64 bytes/point), halving the CRS layer size.
No longer needed since compressed CRS is the only format and download_bb_crs.sh already handles it.
47723ab to
9b6a7e8
Compare
Contributor
Author
|
/claudebox why is the CI still failing? |
Collaborator
|
⏳ Run #1 — Session completed (6m) CI fails because |
… tests blake2s and poseidon tests only use hashing functions and don't need CRS/SRS data. With compressed CRS, the WASM decompression of 2^20 points exceeds Jest's 5s beforeAll timeout. Skip SRS init entirely for these tests.
…h/srs-point-compression # Conflicts: # barretenberg/cpp/src/barretenberg/benchmark/chonk_bench/chonk.bench.cpp
ludamad
approved these changes
Mar 24, 2026
ludamad
approved these changes
Mar 24, 2026
1683d61
into
merge-train/barretenberg
20 of 21 checks passed
This was referenced Mar 24, 2026
AztecBot
added a commit
that referenced
this pull request
Mar 24, 2026
…avior) Only the C++ native path and bootstrap scripts change: - C++ downloads compressed, decompresses, stores uncompressed bn254_g1.dat - Bootstrap scripts download uncompressed g1.dat directly - JS/WASM path unchanged from PR #21112 (compressed throughout)
AztecBot
added a commit
that referenced
this pull request
Mar 25, 2026
CI machines may have bn254_g1_compressed.dat (from PR #21112) but not bn254_g1.dat. Check both filenames: uncompressed first, then compressed. New downloads still store as uncompressed bn254_g1.dat.
AztecBot
added a commit
that referenced
this pull request
Mar 25, 2026
Two fixes for debug build: 1. Legacy CRS fallback: when compressed CRS (bn254_g1_compressed.dat) is not available but old uncompressed CRS (bn254_g1.dat) exists, read the uncompressed format directly. This ensures tests work on machines that haven't re-downloaded the CRS after the compression change in #21112. 2. Non-throwing debug pairing checks: the stdlib PairingPoints constructor and aggregate() method perform native pairing verification in debug builds (#ifndef NDEBUG). When mock/dummy data produces invalid points (e.g. during VK generation with cleared witnesses), this threw an uncatchable exception. Wrapped these debug-only checks in try-catch so they log failures without crashing.
4 tasks
github-merge-queue Bot
pushed a commit
that referenced
this pull request
Mar 25, 2026
## Summary - After PR #21112 switched CRS storage to compressed format (32 bytes/point), every CRS load decompresses from scratch. For 2^20 points in a browser that's ~4s on every page load; for 100M points on an 8-core native prover that's ~110s. - This PR makes compression a bandwidth-only optimization: after the first decompression, the uncompressed points (64 bytes/point) are cached and reused on subsequent loads. ### Changes **C++ native** (`get_bn254_crs.cpp`): Check for cached `bn254_g1.dat` (uncompressed) first. On cache miss, decompress from `bn254_g1_compressed.dat` and write the uncompressed cache. On download, cache both compressed and uncompressed. **C++ WASM** (`bbapi_srs.hpp/cpp`): `srsInitSrs` auto-detects input format (32B vs 64B per point). When decompressing compressed input, it returns the uncompressed bytes in the response so the caller can cache them. **Browser** (`cached_net_crs.ts`): Check IndexedDB for uncompressed `g1Data` first. Add `cacheUncompressed()` to persist after first decompression. **Node.js** (`crs/node/index.ts`): Check `bn254_g1.dat` first, fall back to `bn254_g1_compressed.dat`. Add `cacheUncompressed()` to write uncompressed file. **Wiring** (`barretenberg/index.ts`): `initSRSChonk` captures the `srsInitSrs` response and calls `crs.cacheUncompressed()` when uncompressed bytes are returned. ## Test plan - [ ] C++ native: run `bb` with only compressed CRS on disk, verify it creates `bn254_g1.dat` and uses it on second run - [ ] WASM: `./scripts/run_test.sh bbapi/exception_handling.test.js` passes (schema change) - [ ] WASM: `./scripts/run_test.sh barretenberg/blake2s.test.js` passes (skipSrsInit) - [ ] Browser: first load downloads compressed, caches uncompressed in IDB; second load skips decompression
AztecBot
added a commit
that referenced
this pull request
Mar 26, 2026
The SRS compression PR (#21112) changed point format from 64 to 32 bytes but didn't add explicit buffer size validation. With the old uncompressed format, reading past the buffer would hit g1_identity validation and throw. With compressed format, WASM silently reads garbage memory without throwing. Add explicit bounds checks for both points_buf and g2_point before processing. Update TS test to expect the new error message and fix use of undefined fail().
2 tasks
federicobarbacovi
pushed a commit
that referenced
this pull request
Mar 26, 2026
Two fixes for debug build: 1. Legacy CRS fallback: when compressed CRS (bn254_g1_compressed.dat) is not available but old uncompressed CRS (bn254_g1.dat) exists, read the uncompressed format directly. This ensures tests work on machines that haven't re-downloaded the CRS after the compression change in #21112. 2. Non-throwing debug pairing checks: the stdlib PairingPoints constructor and aggregate() method perform native pairing verification in debug builds (#ifndef NDEBUG). When mock/dummy data produces invalid points (e.g. during VK generation with cleared witnesses), this threw an uncatchable exception. Wrapped these debug-only checks in try-catch so they log failures without crashing.
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.
Summary
Switch entirely to compressed BN254 G1 points (32 bytes/point vs 64 bytes/point) everywhere: C++ native, WASM/bb.js, CI scripts, and release images.
from_compressed()usingThreadChunkbn254_g1_compressed.dat, halving the CRS layer size (~3.2GB vs ~6.4GB)skipSrsInitoption toBackendOptionsso hash-only WASM tests skip CRS initializationBrowser wallet startup benchmark
Tested on the playground embedded wallet. Download from local L2 node, measuring G1 download time,
srsInitSrs(WASM deserialization/decompression), and totalcreatePXEtime.Compressed (32 bytes/point,
g1_compressed.dat):Uncompressed baseline (64 bytes/point,
g1.dat, parallelizedfrom_buffer):Key findings:
srsInitSrsis dominated by msgpack serialization and JS-to-WASM data transfer, not point parsing. The rawfrom_compressedcost is masked by this overhead.Note: earlier wasmtime benchmarks showed
from_compressedat ~19s for 2^20 points (single-threaded), but V8's WASM JIT is roughly 5x faster on this field arithmetic workload. The browserfrom_compressedcost is estimated at ~3.9s (after subtracting serialization overhead), well within the existing overhead budget.Native C++ decompression (full 100M point SRS, 3.2GB compressed)
Changes
C++ (bb CLI + WASM)
bbapi_srs.cpp--SrsInitSrsdecompresses 32-byte compressed points via parallelfrom_compressed()get_bn254_crs.cpp-- downloads compressed CRS with CDN fallback, parallel SHA-256 chunk verification, parallel decompressionchonk.bench.cpp-- addedbn254_point_decompressionbenchmarkTypeScript (bb.js)
net_crs.ts-- downloads fromg1_compressed.datendpointcrs/node/index.ts-- caches and loadsbn254_g1_compressed.dat(32 bytes/point)crs/browser/cached_net_crs.ts-- same for browser/IndexedDBbb_backends/index.ts-- addedskipSrsInitoption toBackendOptionsbarretenberg/index.ts-- respectskipSrsInitinBarretenberg.new()blake2s.test.ts,poseidon.bench.test.ts-- useskipSrsInit: true(hash-only, no CRS needed)Release image
release-image/bootstrap.sh--prepare_crsshipsbn254_g1_compressed.datCI scripts
download_bb_crs.sh-- downloads compressed with fallback/retriesTest plan