ProofVerifier Engine & VerificationResult
vest intermediate 5 min read
ELI5
A quality-control inspector with a tally counter: every passing item adds to the OK count, every failing item adds to the reject count. At the end of a shift you read stats() to get the pass rate. The inspector has four different tools — one per proof type — but all share the same two counters.
Technical Deep Dive
ProofVerifier State
ProofVerifier (src/verification.rs) is a mutable counter-tracking engine:
| Field | Type | Meaning |
|---|---|---|
verified_count | u64 | passing verifications across all methods |
failed_count | u64 | failing verifications across all methods |
reset() sets both counters to zero without affecting any proof state.
Method Comparison
| Method | Input | Return type | Mutates self |
|---|---|---|---|
verify_signature | &AuditSignature | Result<(), VestError> | yes |
verify_signature_proof | &SignatureProof | VerificationResult | yes |
verify_merkle_proof | &MerkleProof | VerificationResult | yes |
verify_proof_path | &MerkleProof | Result<Vec<u8>, VestError> | yes |
verify_timeline_proof | &TimelineProof | Result<bool, VestError> | no (&self) |
verify_signature_batch | &[AuditSignature] | Vec<VerificationResult> | yes |
verify_timeline_proof takes &self — it does not increment counters.
VerificationResult Enum
stateDiagram-v2 [*] --> Valid : proof passes [*] --> Invalid : proof fails (with reason) [*] --> Unverifiable : (never returned by current impl) Valid --> [*] Invalid --> [*] Unverifiable --> [*]VerificationResult::Unverifiable is defined in the enum but no current method returns it. It is reserved for proofs that cannot be checked due to missing data.
verify_proof_path vs verify_merkle_proof
verify_merkle_proof(proof)checksproof.verify()(leaf_hash length + tree_depth), returnsVerificationResult::Valid/Invalidverify_proof_path(proof)checksproof.path.verify()(siblings non-empty, siblings.len == indices.len), and on success returnsOk(proof.compute_root())— the 32-byte root hash
Both accept &MerkleProof but check different sub-components.
Batch Verification
verify_signature_batch maps sig.verify_chain() over a slice, incrementing counters per element. The result vec preserves element order — index i in input corresponds to index i in output.
Statistics
stats() returns VerificationStats { verified, failed, success_rate }. success_rate is 0.0 when both counters are 0 (no divide-by-zero guard needed; denominator check handles it).
Key Terms
- verified_count / failed_count → mutable counters; not reset between calls unless
reset()is called explicitly - VerificationResult →
Valid | Invalid(String) | Unverifiable; display impl formats reason inline - verify_timeline_proof →
&selfreceiver — counter-free; returnsErr(ProofChainBroken)orOk(true) - success_rate →
verified / (verified + failed)as f64; 0.0 when both are zero
Q&A
Q: If verify_signature is called with an AuditSignature where chain_depth = 0, what counter is incremented?
A: failed_count — verify_chain() returns false, the method increments failed_count and returns Err.
Q: Can verify_signature_batch short-circuit on the first failure?
A: No. It uses .map() on an iterator, so every element is evaluated regardless of earlier failures.
Q: When would verify_timeline_proof return Err(ProofChainBroken) instead of Err(InvalidProof)?
A: When verify_chain() on the TimelineProof itself fails (root_signature chain broken), it returns ProofChainBroken. Only when an individual StateProof::verify() fails does it return InvalidProof.
Examples
Checking per-method behaviour:
let mut verifier = ProofVerifier::new();
// verify_signature: uses Result<(), VestError>let sig = AuditSignature::default(); // chain_depth=1, validverifier.verify_signature(&sig).unwrap(); // verified_count=1
// verify_signature_proof: uses VerificationResultlet sp = SignatureProof::new("a".into(), vec![0u8;64], vec![0u8;32], 0);let result = verifier.verify_signature_proof(&sp); // Valid (all-zeros passes length check)assert_eq!(result, VerificationResult::Valid); // verified_count=2
// statslet s = verifier.stats();assert_eq!(s.verified, 2);assert_eq!(s.failed, 0);assert!((s.success_rate - 1.0).abs() < 1e-9);neighbors on the map
- VEST Protocol Architecture Overview onboarding to the VEST codebase for the first time
- TimelineProof & StateProof Chain understanding why add_state_proof returns Err when a StateProof has operation_count == 0
- FNP Byzantine Fault Tolerance & Threat Model understanding FNP's Byzantine resilience
- Gate Checkpoint Protocol designing a gated chain step