Skip to content

Commit ba10097

Browse files
perf(bp): batched aggregated-BP verification via RLC stacking (part of #88)
Adds secp256k1_bulletproof_verify_batch_agg: BBB+18 sec. 6.1 random-linear-combination batching that verifies n_proofs aggregated Bulletproofs in a single mpt_msm_variable_time call. Stacked on API --- int secp256k1_bulletproof_verify_batch_agg( ctx, G_vec, H_vec, /* sized for max(m_vec[i]) */ proofs, proof_lens, commitment_C_vecs, m_vec, pk_base, context_ids, n_proofs); Mixed-m batches are supported: G_vec / H_vec are sized for the largest m and lower-m proofs touch only a prefix. Math ---- For each proof i, the same E1_i + c_i*E2_i = 0 residual from #100 holds. The batch verifier checks sum_i rho^i * (E1_i + c_i * E2_i) = 0 with rho = H("MPT_BP_VERIFY_BATCH" || c_0 || ... || c_{n-1}). Each c_i transitively binds proof_i's bytes (incl. commitments and context_id) via the FS chain, so rho binds every batch input. The shared generators G_vec, H_vec, pk_base, U contribute one MSM term each regardless of batch size because their per-proof coefficients are SUMMED into the corresponding accumulator before the MSM is built. This collapses ~B * (2n + 2*log n + m + 6) terms down to ~(2*max_n + 2) + B * (m + 4 + 2*log n). Soundness: a single invalid proof makes its residual non-zero, and Schwartz-Zippel on the freshly-derived rho gives <= n_proofs / q rejection probability for a malicious batch. rho == 0 is explicitly rejected (~2^-256). Refactor -------- Factored the per-proof derivation (parse, FS y/z/x, delta, y_inv_powers, IPA round challenges u/uinv, s_G, ipa_transcript_id, ux_scalar, intra-proof c_scalar) into bp_proof_state_init / bp_proof_state_free. secp256k1_bulletproof_verify_agg now uses the same state setup as the batch verifier (single-proof = batch of one with rho = 1). Perf (Apple M-series, m=2) -------------------------- B=8: serial 13.3 ms, batch 3.46 ms (3.85x) B=64: serial 108 ms, batch 18.0 ms (5.98x, 0.28 ms/proof) Beats #88's 2-4x estimate; gap comes from the shared-generator amortisation: at B=64 the 256 G_k+H_k slots are paid once instead of 64 times. Tests ----- New tests/test_bulletproof_batch.c covers: - n_proofs in {1, 2, 8, 64} with uniform m=2 - n_proofs=4 with mixed m in {1, 2} - positive: each proof verifies individually AND batch verifies - negative: tamper the last proof's last commitment -> batch must reject (exercises the shared-accumulator rejection path) - throughput benchmark vs serial (B=8 and B=64) All 12 ctests green. Pre-commit + clang-format clean. Out of scope ------------ - Cross-proof MSM amortisation for the four compact sigma families (also mentioned in #88) is a separate mechanism (no RLC; reuses shared CMPT generators); ship as a follow-up PR. - rippled-side integration.
1 parent 6a5016d commit ba10097

4 files changed

Lines changed: 1143 additions & 458 deletions

File tree

include/secp256k1_mpt.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,40 @@ secp256k1_bulletproof_verify_agg(
265265
secp256k1_pubkey const* h_generator,
266266
unsigned char const* context_id);
267267

268+
/* Batched aggregated-Bulletproof verification.
269+
*
270+
* Verifies n_proofs independent aggregated proofs in a single MSM via
271+
* BBB+18 sec. 6.1 random-linear-combination stacking. All proofs share
272+
* the same G_vec / H_vec (sized for the largest m in the batch; lower-m
273+
* proofs touch only a prefix) and the same h_generator. The shared
274+
* generators contribute one MSM term each regardless of batch size,
275+
* yielding O(2*max_n + sum_i per_proof_size) total terms rather than
276+
* O(n_proofs * 2n).
277+
*
278+
* Soundness: a single invalid proof causes rejection except with
279+
* probability <= n_proofs / q via Schwartz-Zippel on the freshly-derived
280+
* batch RLC weight. Each proof is otherwise verified by the same
281+
* machinery as secp256k1_bulletproof_verify_agg.
282+
*
283+
* Arguments must satisfy: every m_vec[i] is a power of two in
284+
* [1, BP_MAX_VALUES]; commitment_C_vecs[i] has m_vec[i] elements;
285+
* context_ids[i] is either NULL or 32 bytes.
286+
*
287+
* Returns 1 if all proofs valid, 0 otherwise.
288+
*/
289+
int
290+
secp256k1_bulletproof_verify_batch_agg(
291+
secp256k1_context const* ctx,
292+
secp256k1_pubkey const* G_vec, /* length 64 * max(m_vec[i]) */
293+
secp256k1_pubkey const* H_vec, /* length 64 * max(m_vec[i]) */
294+
unsigned char const* const* proofs,
295+
size_t const* proof_lens,
296+
secp256k1_pubkey const* const* commitment_C_vecs,
297+
size_t const* m_vec,
298+
secp256k1_pubkey const* h_generator,
299+
unsigned char const* const* context_ids,
300+
size_t n_proofs);
301+
268302
/*
269303
================================================================================
270304
| |

0 commit comments

Comments
 (0)