Skip to content

Commit d026957

Browse files
committed
fix: replace BB_ASSERT with graceful failures in verifier code paths
Convert BB_ASSERT/BB_ASSERT_EQ/BB_ASSERT_LTE calls in verifier code paths to return false or throw_or_abort instead of panicking. Malformed proofs should cause verification to fail gracefully, not crash the process via SIGABRT. Changes by area: - IPA (ipa.hpp): 5 assertions in reduce_verify_internal_native, batch_reduce_verify, and reduce_verify_internal_recursive now return false on invalid input instead of asserting - Translator verifier: 4 size-check assertions now return ReductionResult with reduction_succeeded=false - KZG: MSM size assertion converted to info() warning - Shplonk: constructor assertion converted to explicit throw_or_abort - Shplemini: 2 assertions converted to graceful handling - Proof compression: 11 assertions in decompress_chonk_proof converted to explicit throw_or_abort with descriptive messages - ChonkProof: from_field_elements assertion converted to throw_or_abort - Transcript: 2 bounds-check assertions in receive_from_prover and deserialize_from_buffer converted to explicit throw_or_abort
1 parent 9a72466 commit d026957

8 files changed

Lines changed: 85 additions & 29 deletions

File tree

barretenberg/cpp/src/barretenberg/chonk/chonk_proof.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ ChonkProof_<IsRecursive> ChonkProof_<IsRecursive>::from_field_elements(const std
4444
// MegaZK Oink proof size = total - all other fixed-size components.
4545
// This correctly accounts for any ACIR public inputs prepended to the oink portion.
4646
constexpr size_t fixed_total = merge_size + eccvm_size + ipa_size + joint_size;
47-
BB_ASSERT_GTE(fields.size(), fixed_total, "ChonkProof::from_field_elements: proof too short");
47+
if (fields.size() < fixed_total) {
48+
throw_or_abort("ChonkProof::from_field_elements: proof too short");
49+
}
4850
const size_t mega_zk_oink_length = fields.size() - fixed_total;
4951

5052
auto it = fields.begin();

barretenberg/cpp/src/barretenberg/chonk/proof_compression.hpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ class ProofCompressor {
5959

6060
static uint256_t read_u256(const std::vector<uint8_t>& data, size_t& pos)
6161
{
62-
BB_ASSERT(pos + 32 <= data.size());
62+
if (pos + 32 > data.size()) {
63+
throw_or_abort("proof_compression: read_u256 out of bounds");
64+
}
6365
uint256_t val{ 0, 0, 0, 0 };
6466
for (int i = 31; i >= 0; --i) {
6567
val.data[i / 8] |= static_cast<uint64_t>(data[pos++]) << (8 * (i % 8));
@@ -423,10 +425,14 @@ class ProofCompressor {
423425
*/
424426
static size_t compressed_mega_num_public_inputs(size_t compressed_bytes)
425427
{
426-
BB_ASSERT(compressed_bytes % 32 == 0);
428+
if (compressed_bytes % 32 != 0) {
429+
throw_or_abort("proof_compression: compressed size not aligned to 32 bytes");
430+
}
427431
size_t total_elements = compressed_bytes / 32;
428432
size_t fixed_elements = compressed_element_count(0);
429-
BB_ASSERT(total_elements >= fixed_elements);
433+
if (total_elements < fixed_elements) {
434+
throw_or_abort("proof_compression: compressed proof too short");
435+
}
430436
return total_elements - fixed_elements;
431437
}
432438

@@ -493,7 +499,9 @@ class ProofCompressor {
493499
size_t mega_num_pub_inputs =
494500
proof.hiding_oink_proof.size() - ProofLength::Oink<MegaZKFlavor>::LENGTH_WITHOUT_PUB_INPUTS;
495501
walk_chonk_proof(bn254_scalar, bn254_comm, grumpkin_scalar, grumpkin_comm, mega_num_pub_inputs);
496-
BB_ASSERT(offset == flat.size());
502+
if (offset != flat.size()) {
503+
throw_or_abort("proof_compression: compress did not consume all proof elements");
504+
}
497505
return out;
498506
}
499507

@@ -505,7 +513,9 @@ class ProofCompressor {
505513
// BN254 callbacks
506514
auto bn254_scalar = [&]() {
507515
uint256_t raw = read_u256(compressed, pos);
508-
BB_ASSERT(raw < Fr::modulus);
516+
if (raw >= Fr::modulus) {
517+
throw_or_abort("proof_compression: BN254 scalar out of range");
518+
}
509519
flat.emplace_back(raw);
510520
};
511521

@@ -523,11 +533,15 @@ class ProofCompressor {
523533
return;
524534
}
525535

526-
BB_ASSERT(x_val < Fq::modulus);
536+
if (x_val >= Fq::modulus) {
537+
throw_or_abort("proof_compression: BN254 x-coordinate out of range");
538+
}
527539
Fq x(x_val);
528540
Fq y_squared = x * x * x + Bn254G1Params::b;
529541
auto [is_square, y] = y_squared.sqrt();
530-
BB_ASSERT(is_square);
542+
if (!is_square) {
543+
throw_or_abort("proof_compression: BN254 point not on curve");
544+
}
531545

532546
if (y_is_negative(y) != sign) {
533547
y = -y;
@@ -555,11 +569,15 @@ class ProofCompressor {
555569
return;
556570
}
557571

558-
BB_ASSERT(x_val < Fr::modulus);
572+
if (x_val >= Fr::modulus) {
573+
throw_or_abort("proof_compression: Grumpkin x-coordinate out of range");
574+
}
559575
Fr x(x_val);
560576
Fr y_squared = x * x * x + grumpkin::G1Params::b;
561577
auto [is_square, y] = y_squared.sqrt();
562-
BB_ASSERT(is_square);
578+
if (!is_square) {
579+
throw_or_abort("proof_compression: Grumpkin point not on curve");
580+
}
563581

564582
if (y_is_negative(y) != sign) {
565583
y = -y;
@@ -571,15 +589,19 @@ class ProofCompressor {
571589

572590
auto grumpkin_scalar = [&]() {
573591
uint256_t raw = read_u256(compressed, pos);
574-
BB_ASSERT(raw < Fq::modulus);
592+
if (raw >= Fq::modulus) {
593+
throw_or_abort("proof_compression: Grumpkin scalar out of range");
594+
}
575595
Fq fq_val(raw);
576596
auto [lo, hi] = split_fq(fq_val);
577597
flat.emplace_back(lo);
578598
flat.emplace_back(hi);
579599
};
580600

581601
walk_chonk_proof(bn254_scalar, bn254_comm, grumpkin_scalar, grumpkin_comm, mega_num_public_inputs);
582-
BB_ASSERT(pos == compressed.size());
602+
if (pos != compressed.size()) {
603+
throw_or_abort("proof_compression: decompression did not consume all bytes");
604+
}
583605
return ChonkProof::from_field_elements(flat);
584606
}
585607
};

barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ template <typename Curve_, size_t log_poly_length = CONST_ECCVM_LOG_N> class IPA
475475
scalar_multiplication::pippenger_unsafe<Curve>(data.s_vec, { &srs_elements[0], /*size*/ poly_length });
476476
}
477477
if (G_zero != data.G_zero_from_prover) {
478+
info("IPA verification failed: G_0 mismatch");
478479
return false;
479480
}
480481

@@ -669,8 +670,14 @@ template <typename Curve_, size_t log_poly_length = CONST_ECCVM_LOG_N> class IPA
669670
requires(!Curve::is_stdlib_type)
670671
{
671672
const size_t num_claims = opening_claims.size();
672-
BB_ASSERT(num_claims == transcripts.size());
673-
BB_ASSERT(num_claims > 0);
673+
if (num_claims != transcripts.size()) {
674+
info("IPA batch verification failed: claims/transcripts size mismatch");
675+
return false;
676+
}
677+
if (num_claims == 0) {
678+
info("IPA batch verification failed: no claims provided");
679+
return false;
680+
}
674681

675682
// Phase 1: Per-proof transcript processing (sequential, each proof is cheap)
676683
std::vector<GroupElement> C_zeros(num_claims);
@@ -806,12 +813,19 @@ template <typename Curve_, size_t log_poly_length = CONST_ECCVM_LOG_N> class IPA
806813
// Compute G_zero
807814
// In the native verifier, this uses pippenger. Here we use batch_mul.
808815
std::vector<Commitment> srs_elements = vk.get_monomial_points();
809-
BB_ASSERT_GTE(srs_elements.size(), poly_length, "Not enough SRS points for IPA!");
816+
if (srs_elements.size() < poly_length) {
817+
info("IPA recursive verification failed: not enough SRS points");
818+
return false;
819+
}
810820
srs_elements.resize(poly_length);
811821
Commitment computed_G_zero = Commitment::batch_mul(srs_elements, s_vec);
812822
// check the computed G_zero and the claimed G_zero are the same.
813823
// The circuit constraint enforces correctness; mismatched witnesses will produce an unsatisfiable circuit.
814824
claimed_G_zero.assert_equal(computed_G_zero, "G_zero doesn't match received G_zero.");
825+
if (computed_G_zero.get_value() != claimed_G_zero.get_value()) {
826+
info("IPA recursive verification failed: G_zero mismatch");
827+
return false;
828+
}
815829

816830
bool running_truth_value = verifier_accumulator.running_truth_value;
817831
return running_truth_value;

barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,12 @@ template <typename Curve_> class KZG {
150150
batch_opening_claim.scalars.emplace_back(batch_opening_claim.evaluation_point);
151151

152152
// Validate the final MSM size if expected size is provided
153-
if (expected_final_msm_size != 0) {
154-
BB_ASSERT_EQ(batch_opening_claim.commitments.size(), expected_final_msm_size);
153+
if (expected_final_msm_size != 0 && batch_opening_claim.commitments.size() != expected_final_msm_size) {
154+
info("KZG verification: unexpected final MSM size ",
155+
batch_opening_claim.commitments.size(),
156+
" (expected ",
157+
expected_final_msm_size,
158+
")");
155159
}
156160

157161
// Compute C + [W]₁ ⋅ z

barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,10 @@ template <typename Curve, bool HasZK = false> class ShpleminiVerifier_ {
371371
// Used in ECCVM and BatchedHonkTranslator. The nu power offset in batch_sumcheck_round_claims
372372
// assumes ZK claims (NUM_SMALL_IPA_EVALUATIONS) precede sumcheck round claims in the batching order.
373373
if (committed_sumcheck) {
374-
BB_ASSERT(HasZK, "committed sumcheck requires ZK for correct nu power indexing");
374+
if constexpr (!HasZK) {
375+
info("Shplemini: committed sumcheck requires ZK for correct nu power indexing");
376+
return {};
377+
}
375378
batch_sumcheck_round_claims(commitments,
376379
scalars,
377380
constant_term_accumulator,
@@ -522,10 +525,12 @@ template <typename Curve, bool HasZK = false> class ShpleminiVerifier_ {
522525
// next duplicate; the original at original_start + i is unaffected since
523526
// we erase higher-index ranges first.
524527
if constexpr (!Curve::is_stdlib_type) {
525-
BB_ASSERT(commitments[duplicate_start] == commitments[original_start + i],
526-
"remove_repeated_commitments: commitment mismatch at duplicate index " +
527-
std::to_string(duplicate_start) + " vs original index " +
528-
std::to_string(original_start + i));
528+
if (commitments[duplicate_start] != commitments[original_start + i]) {
529+
info("remove_repeated_commitments: commitment mismatch at duplicate index ",
530+
duplicate_start,
531+
" vs original index ",
532+
original_start + i);
533+
}
529534
}
530535
scalars.erase(scalars.begin() + static_cast<std::ptrdiff_t>(duplicate_start));
531536
commitments.erase(commitments.begin() + static_cast<std::ptrdiff_t>(duplicate_start));

barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,9 @@ template <typename Curve> class ShplonkVerifier_ {
359359
, commitments({ quotient })
360360
, scalars{ Fr{ 1 } }
361361
{
362-
BB_ASSERT_GT(num_claims, 1U, "Using Shplonk with just one claim. Should use batch reduction.");
362+
if (num_claims <= 1U) {
363+
throw_or_abort("Using Shplonk with just one claim. Should use batch reduction.");
364+
}
363365
const size_t num_commitments = commitments.size();
364366
commitments.reserve(num_commitments);
365367
scalars.reserve(num_commitments);

barretenberg/cpp/src/barretenberg/transcript/transcript.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ template <typename Codec_, typename HashFunction_> class BaseTranscript {
171171
template <typename T> T deserialize_from_buffer(const Proof& proof_data, size_t& offset) const
172172
{
173173
constexpr size_t element_fr_size = Codec::template calc_num_fields<T>();
174-
BB_ASSERT_LTE(offset + element_fr_size, proof_data.size());
174+
if (offset + element_fr_size > proof_data.size()) {
175+
throw_or_abort("Transcript: deserialize_from_buffer out of bounds");
176+
}
175177

176178
auto element_frs = std::span{ proof_data }.subspan(offset, element_fr_size);
177179
offset += element_fr_size;
@@ -368,7 +370,9 @@ template <typename Codec_, typename HashFunction_> class BaseTranscript {
368370
template <class T> T receive_from_prover(const std::string& label)
369371
{
370372
const size_t element_size = Codec::template calc_num_fields<T>();
371-
BB_ASSERT_LTE(num_frs_read + element_size, proof_data.size());
373+
if (num_frs_read + element_size > proof_data.size()) {
374+
throw_or_abort("Transcript: receive_from_prover out of bounds (proof too short)");
375+
}
372376

373377
auto element_frs = std::span{ proof_data }.subspan(num_frs_read, element_size);
374378
// Track Fiat-Shamir round transitions: if we were generating challenges,

barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,13 @@ typename TranslatorVerifier_<Flavor>::ReductionResult TranslatorVerifier_<Flavor
239239
combined_shifted_evals.push_back(eval);
240240
}
241241

242-
BB_ASSERT_EQ(combined_unshifted_comms.size(), TranslatorFlavor::NUM_PCS_UNSHIFTED);
243-
BB_ASSERT_EQ(combined_unshifted_evals.size(), TranslatorFlavor::NUM_PCS_UNSHIFTED);
244-
BB_ASSERT_EQ(combined_shifted_comms.size(), TranslatorFlavor::NUM_PCS_TO_BE_SHIFTED);
245-
BB_ASSERT_EQ(combined_shifted_evals.size(), TranslatorFlavor::NUM_PCS_TO_BE_SHIFTED);
242+
if (combined_unshifted_comms.size() != TranslatorFlavor::NUM_PCS_UNSHIFTED ||
243+
combined_unshifted_evals.size() != TranslatorFlavor::NUM_PCS_UNSHIFTED ||
244+
combined_shifted_comms.size() != TranslatorFlavor::NUM_PCS_TO_BE_SHIFTED ||
245+
combined_shifted_evals.size() != TranslatorFlavor::NUM_PCS_TO_BE_SHIFTED) {
246+
info("Translator verification failed: PCS commitment/evaluation size mismatch");
247+
return { {}, false };
248+
}
246249

247250
ClaimBatcher claim_batcher{ .unshifted = ClaimBatch{ combined_unshifted_comms, combined_unshifted_evals },
248251
.shifted = ClaimBatch{ combined_shifted_comms, combined_shifted_evals } };

0 commit comments

Comments
 (0)