Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 121 additions & 9 deletions BENCHMARKS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# groth16-solana CU Benchmarks

Compute unit costs of Groth16 verification on Solana, measured with [light-program-profiler](https://github.com/Lightprotocol/light-program-profiler) under mollusk against the profiled build of `tests/program`. The matrix covers plain Groth16 (`Groth16Verifier::new`) and BSB22 single-commitment proofs (`Groth16Verifier::new_with_commitment`, gnark lookup circuits), each verified with 1, 2, 4, and 8 public inputs. Proofs and verifying keys are regenerated deterministically by build.rs (seeded gnark setup, see tests/gnark-ffi/gnark-fixture/bench). `verify`/`verify_with_bsb22_commitment` is proof parsing plus Groth16Verifier construction plus `verify()`.
Compute unit costs of Groth16 verification on Solana, measured with [light-program-profiler](https://github.com/Lightprotocol/light-program-profiler) under mollusk against the profiled build of `tests/program`. The matrix covers plain Groth16 (`Groth16Verifier::new`) and BSB22 single-commitment proofs (`Groth16Verifier::new_with_commitment`, gnark lookup circuits), each verified with 1, 2, 4, and 8 public inputs. BSB22 fixtures are checked using both `verify()` and the single-proof `verify_opt()` method, with all combinations of a checked 49-byte hash-reduction hint and a pinned key digest. Proofs and verifying keys are regenerated deterministically by build.rs (seeded gnark setup, see tests/gnark-ffi/gnark-fixture/bench). `verify`/`verify_with_bsb22_commitment` is proof parsing plus Groth16Verifier construction plus the selected verification method.

Regenerate with `cargo build-sbf --manifest-path tests/program/Cargo.toml -- --features profile-program && cargo test -p bsb22-integration-program --test bench_cu -- --ignored --nocapture`.

Expand All @@ -19,52 +19,164 @@ Regenerate with `cargo build-sbf --manifest-path tests/program/Cargo.toml -- --f
6. [Groth16-bsb22 - 2 public inputs](#groth16-bsb22---2-public-inputs)
7. [Groth16-bsb22 - 4 public inputs](#groth16-bsb22---4-public-inputs)
8. [Groth16-bsb22 - 8 public inputs](#groth16-bsb22---8-public-inputs)
9. [Groth16-bsb22-opt - 1 public input](#groth16-bsb22-opt---1-public-input)
10. [Groth16-bsb22-opt - 2 public inputs](#groth16-bsb22-opt---2-public-inputs)
11. [Groth16-bsb22-opt - 4 public inputs](#groth16-bsb22-opt---4-public-inputs)
12. [Groth16-bsb22-opt - 8 public inputs](#groth16-bsb22-opt---8-public-inputs)
13. [Groth16-bsb22-opt-cached - 1 public input](#groth16-bsb22-opt-cached---1-public-input)
14. [Groth16-bsb22-opt-cached - 2 public inputs](#groth16-bsb22-opt-cached---2-public-inputs)
15. [Groth16-bsb22-opt-cached - 4 public inputs](#groth16-bsb22-opt-cached---4-public-inputs)
16. [Groth16-bsb22-opt-cached - 8 public inputs](#groth16-bsb22-opt-cached---8-public-inputs)
17. [Groth16-bsb22-opt-hint - 1 public input](#groth16-bsb22-opt-hint---1-public-input)
18. [Groth16-bsb22-opt-hint - 2 public inputs](#groth16-bsb22-opt-hint---2-public-inputs)
19. [Groth16-bsb22-opt-hint - 4 public inputs](#groth16-bsb22-opt-hint---4-public-inputs)
20. [Groth16-bsb22-opt-hint - 8 public inputs](#groth16-bsb22-opt-hint---8-public-inputs)
21. [Groth16-bsb22-opt-hint-cached - 1 public input](#groth16-bsb22-opt-hint-cached---1-public-input)
22. [Groth16-bsb22-opt-hint-cached - 2 public inputs](#groth16-bsb22-opt-hint-cached---2-public-inputs)
23. [Groth16-bsb22-opt-hint-cached - 4 public inputs](#groth16-bsb22-opt-hint-cached---4-public-inputs)
24. [Groth16-bsb22-opt-hint-cached - 8 public inputs](#groth16-bsb22-opt-hint-cached---8-public-inputs)

## 1. Groth16 - 1 public input

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify` | 78,293 | 78,293 |
| `verify` | 78,324 | 78,324 |

## 2. Groth16 - 2 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify` | 82,704 | 82,704 |
| `verify` | 82,732 | 82,732 |

## 3. Groth16 - 4 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify` | 91,448 | 91,448 |
| `verify` | 91,472 | 91,472 |

## 4. Groth16 - 8 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify` | 108,762 | 108,762 |
| `verify` | 108,789 | 108,789 |

## 5. Groth16-bsb22 - 1 public input

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 134,764 | 134,764 |
| `verify_with_bsb22_commitment` | 134,795 | 134,795 |

## 6. Groth16-bsb22 - 2 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 139,180 | 139,180 |
| `verify_with_bsb22_commitment` | 139,201 | 139,201 |

## 7. Groth16-bsb22 - 4 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 147,921 | 147,921 |
| `verify_with_bsb22_commitment` | 147,939 | 147,939 |

## 8. Groth16-bsb22 - 8 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 165,236 | 165,236 |
| `verify_with_bsb22_commitment` | 165,258 | 165,258 |

## 9. Groth16-bsb22-opt - 1 public input

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 119,286 | 119,286 |

## 10. Groth16-bsb22-opt - 2 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 123,739 | 123,739 |

## 11. Groth16-bsb22-opt - 4 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 132,574 | 132,574 |

## 12. Groth16-bsb22-opt - 8 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 150,085 | 150,085 |

## 13. Groth16-bsb22-opt-cached - 1 public input

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 118,641 | 118,641 |

## 14. Groth16-bsb22-opt-cached - 2 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 123,063 | 123,063 |

## 15. Groth16-bsb22-opt-cached - 4 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 131,833 | 131,833 |

## 16. Groth16-bsb22-opt-cached - 8 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 149,216 | 149,216 |

## 17. Groth16-bsb22-opt-hint - 1 public input

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 118,244 | 118,244 |

## 18. Groth16-bsb22-opt-hint - 2 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 122,700 | 122,700 |

## 19. Groth16-bsb22-opt-hint - 4 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 131,537 | 131,537 |

## 20. Groth16-bsb22-opt-hint - 8 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 149,045 | 149,045 |

## 21. Groth16-bsb22-opt-hint-cached - 1 public input

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 117,600 | 117,600 |

## 22. Groth16-bsb22-opt-hint-cached - 2 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 122,022 | 122,022 |

## 23. Groth16-bsb22-opt-hint-cached - 4 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 130,795 | 130,795 |

## 24. Groth16-bsb22-opt-hint-cached - 8 public inputs

| Function | Total CU | Net CU |
| ------------------------------ | ---------- | ---------- |
| `verify_with_bsb22_commitment` | 148,176 | 148,176 |

14 changes: 12 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Each `failing.rs` test pins the exact `ProgramError` the client sees.
1. `rejects_unknown_selector`
2. `rejects_empty_instruction_data`
3. `rejects_wrong_payload_length` — one byte short and one byte long,
all 8 variants
all 24 variants
4. `rejects_cross_mode_payload` — BSB22 payload on a plain selector
and vice versa
5. `rejects_mutated_public_input`
Expand All @@ -135,7 +135,9 @@ Each `failing.rs` test pins the exact `ProgramError` the client sees.
15. `rejects_swapped_commitment_and_pok`
16. `offsets_match_program_layout` — guards the test-side offsets
against instruction-format drift
17. `bench_cu` (`--ignored`) — executes all 8 variants successfully
17. `optimized_rejects_invalid_inputs_and_commitment_points` — optimized variants with and without hints and pinned key digests
18. `optimized_rejects_mutated_hash_hints` — every byte of every quotient/remainder hint
19. `bench_cu` (`--ignored`) — executes all 24 variants successfully
under mollusk and regenerates BENCHMARKS.md

### Circom end-to-end (tests/rust-vk, requires npm + circom)
Expand All @@ -147,3 +149,11 @@ Each `failing.rs` test pins the exact `ProgramError` the client sees.
compressed-account Merkle-proof witness, proves with circom-prover,
and verifies with the vk const generated by `vk::circom` in
`build.rs`


The BSB22 unit tests compare default and optimized verification. The new
`verify_opt_rejects_cancelling_pairing_residuals` regression demonstrates that
unweighted concatenation accepts inverse residuals while `verify_opt` rejects.
Hash-hint tests compare exact arithmetic against `num-bigint`, mutate every
hint byte, reject oversized quotients, and reject a noncanonical remainder
even when its adjusted quotient satisfies the integer identity.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ sha2 = { version = "0.10", default-features = false, optional = true }


[dev-dependencies]
num-bigint = { version = "0.4.6", default-features = false }
ark-std = "0.5"
ark-ff = { version = "0.5", default-features = false }
ark-bn254 = { version = "0.5", default-features = false, features = ["curve"] }
Expand Down
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

Groth16 zero-knowledge proof verification with Solana alt_bn128 syscalls.

A plain Groth16 verify costs 78,293–108,762 CU and a BSB22 verify
134,764–165,236 CU, for 1 to 8 public inputs (see
A plain Groth16 verify costs 78,324–108,789 CU. BSB22
`verify()` costs 134,795–165,258 CU; `verify_opt()` costs
119,286–150,085 CU. With both optional accelerators it costs
117,600–148,176 CU, for 1 to 8 public inputs (see
[Benchmarks](#benchmarks)).

The syscalls ship with Solana 1.18 onward and are active on mainnet-beta.
Expand All @@ -27,7 +29,7 @@ at your own risk.
## Features

- `bsb22` — verifies gnark proofs that include a single BSB22
(Bowe-Sankaranarayanan-Bonneau 2022) Pedersen commitment, via
(Belling-Soleimanian-Begassat 2022) Pedersen commitment, via
`Groth16Verifier::new_with_commitment`. Every gnark circuit takes this
shape once it uses `std/lookup/logderivlookup` or an emulated-field
range check: gnark's `multicommit` merges the deferred commits into
Expand All @@ -44,15 +46,30 @@ at your own risk.

## Benchmarks

End-to-end verification cost (proof parsing, verifier construction,
`verify()`) in compute units:

| Public inputs | Groth16 | Groth16-BSB22 |
|--------------:|--------:|--------------:|
| 1 | 78,293 | 134,764 |
| 2 | 82,704 | 139,180 |
| 4 | 91,448 | 147,921 |
| 8 | 108,762 | 165,236 |
End-to-end verification cost (proof parsing, verifier construction, verification)
in compute units. Every column verifies one proof at a time.

| Public inputs | Groth16 | BSB22 | verify_opt | With hint | With cached key | With both |
|--------------:|--------:|------:|-----------:|----------:|----------------:|----------:|
| 1 | 78,324 | 134,795 | 119,286 | 118,244 | 118,641 | 117,600 |
| 2 | 82,732 | 139,201 | 123,739 | 122,700 | 123,063 | 122,022 |
| 4 | 91,472 | 147,939 | 132,574 | 131,537 | 131,833 | 130,795 |
| 8 | 108,789 | 165,258 | 150,085 | 149,045 | 149,216 | 148,176 |

`verify_opt()` uses the existing proof and instruction payload. For more
savings, `verify_opt_with_options()` accepts a checked reduction hint and/or
a pinned key digest. The hint appends 49 bytes: a 17-byte big-endian quotient
followed by a 32-byte canonical remainder for gnark's 48-byte SHA-256 XMD
expansion of the commitment with DST `bsb22-commitment`.

Generate the digest with `Groth16Verifyingkey::verify_opt_key_hash()` in a
build script and pin it alongside its matching key. It adds no instruction
data and must not be accepted from the prover. See `tests/program/build.rs`
and `tests/gnark-ffi/gnark-fixture/bench/bench.go` for complete examples.

`verify()` retains its separate pairing checks and error diagnostics.
The optimized path reports `ProofVerificationFailed` when its combined
pairing equation fails; malformed hints report `Bsb22InvalidHashHint`.

<!-- cargo-rdme end -->

Expand Down
6 changes: 6 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ pub enum Groth16Error {
#[cfg(feature = "bsb22")]
#[error("Bsb22InconsistentCommitmentState")]
Bsb22InconsistentCommitmentState,
/// The supplied quotient/remainder does not describe the exact gnark hash reduction.
#[cfg(feature = "bsb22")]
#[error("Bsb22InvalidHashHint")]
Bsb22InvalidHashHint,
}

#[cfg(feature = "circom")]
Expand Down Expand Up @@ -116,6 +120,8 @@ impl From<Groth16Error> for u32 {
Groth16Error::Bsb22InvalidCommitmentPoint => 20,
#[cfg(feature = "bsb22")]
Groth16Error::Bsb22InconsistentCommitmentState => 21,
#[cfg(feature = "bsb22")]
Groth16Error::Bsb22InvalidHashHint => 22,
}
}
}
Loading
Loading