refactor(stm): combine pairing checks ivc verify - #3454
Conversation
2a4c47e to
5433b3a
Compare
cd079a5 to
b75f104
Compare
There was a problem hiding this comment.
Pull request overview
This PR refactors IvcProof::verify to batch the dual MSM (KZG opening) and folded accumulator pairing equations into a single combined pairing check, reducing verifier time by avoiding a second multi-Miller loop + final exponentiation.
Changes:
- Convert the folded accumulator equation into a
DualMSM, scale it by a transcript-derived challenger, and add it to the proof’sdual_msmbefore running a single pairing check. - Replace the two distinct verification failure variants with a single
IvcProofError::MsmPairingCheckFailed. - Update verification tests and add a test asserting the combined check holds for multiple candidate scalars.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| mithril-stm/src/proof_system/ivc_halo2_snark/proof.rs | Implements the combined pairing check in verify and updates/adds tests accordingly. |
| mithril-stm/src/proof_system/ivc_halo2_snark/errors.rs | Collapses prior error variants into MsmPairingCheckFailed for the new combined check path. |
Suppressed comments (6)
mithril-stm/src/proof_system/ivc_halo2_snark/proof.rs:222
- The PR description says to keep (or rerun) an individual pairing check on failure to identify whether the dual MSM or the accumulator caused the failure. The current implementation always returns
MsmPairingCheckFailedwithout re-checking individual equations, so the error source is lost and the PR behavior no longer matches the stated intent/issue acceptance criteria.
if !combined.check(verifier_setup.verifier_params()) {
return Err(IvcProofError::MsmPairingCheckFailed.into());
}
mithril-stm/src/proof_system/ivc_halo2_snark/proof.rs:751
- This assertion message still claims the failure is specifically the “KZG opening check”, but the error is now
MsmPairingCheckFailedfrom the combined pairing check. Update the message to match the new behavior.
Some(&IvcProofError::MsmPairingCheckFailed),
"different protocol message must fail the KZG opening check, got: {err}"
mithril-stm/src/proof_system/ivc_halo2_snark/proof.rs:778
- This assertion message still refers to the “KZG opening check”, but the code now reports
MsmPairingCheckFailedfrom the combined pairing check. Adjust the message to prevent confusion when the test fails.
Some(&IvcProofError::MsmPairingCheckFailed),
"mismatched state corrupts public inputs and must fail the KZG opening check, got: {err}"
mithril-stm/src/proof_system/ivc_halo2_snark/proof.rs:805
- This assertion message still refers to the “KZG opening check”, but verification now reports
MsmPairingCheckFailedfrom the combined pairing check. Update the message to match the new error semantics.
Some(&IvcProofError::MsmPairingCheckFailed),
"mismatched accumulator corrupts public inputs and must fail the KZG opening check, got: {err}"
mithril-stm/src/proof_system/ivc_halo2_snark/proof.rs:830
- This assertion message still mentions the “KZG opening check”, but the code now fails via the combined pairing check and returns
MsmPairingCheckFailed. Update the message to reflect the combined-check behavior.
Some(&IvcProofError::MsmPairingCheckFailed),
"Poseidon bytes via Blake2b path must fail the KZG opening check, got: {err}"
mithril-stm/src/proof_system/ivc_halo2_snark/proof.rs:874
- This assertion message still claims the failure is specifically the “accumulator check (not the KZG check)”, but verification now returns a single
MsmPairingCheckFailedfor the combined check, so the distinction no longer exists. Update the message to avoid implying separate error paths.
Some(&IvcProofError::MsmPairingCheckFailed),
"wrong fixed bases must fail the accumulator check (not the KZG check), got: {err}"
| /// `global` and `verifier_setup` must be built from the same certificate and IVC verifying | ||
| /// keys. If they differ, the public inputs fed to the KZG opening check will not match the | ||
| /// proof transcript and verification will return [`IvcProofError::KzgOpeningFailed`]. | ||
| /// proof transcript and verification will return [`IvcProofError::MsmPairingCheckFailed`]. |
| verifier_setup.combined_fixed_bases(), | ||
| ) { | ||
| return Err(IvcProofError::AccumulatorFailed.into()); | ||
| // `r` must depend both `dual_msm` and `self.accumulator` to make sure the combination can't be manipulated. |
| } | ||
| transcript.common(&accumulator_lhs)?; | ||
| transcript.common(&accumulator_rhs)?; | ||
| let r: CircuitBase = transcript.squeeze_challenge(); |
| /// Combined accumulator and dual MSM pairing equation did not verify. | ||
| #[error("IVC proof rejected: combined accumulator and dual MSM pairing check failed")] | ||
| MsmPairingCheckFailed, |
| Some(&IvcProofError::MsmPairingCheckFailed), | ||
| "tampered bytes must fail the KZG opening check, got: {err}" |
| } | ||
|
|
||
| #[test] | ||
| fn ivc_proof_verify_combined_check_holds_for_any_scalar_r() { |
There was a problem hiding this comment.
We probably need a test to make sure we don't use any value for r (the golden test we were talking about). This means that its computation will need to be extracted to a pub(crate) function so that it can be easily tested.
Content
This PR includes an update to the verification function of the recursive proof to combine the two pairing checks (dual MSM and accumulator) into one to speed up the verification.
Changes
rto combine as: combined_msm = dual_msm + r * acc_msmMeasured gain
Pre-submit checklist
Issue(s)
Closes #3420