feat(CryptoFoundations): add round-by-round knowledge games#475
feat(CryptoFoundations): add round-by-round knowledge games#475eliasjudin wants to merge 3 commits into
Conversation
🤖 PR SummaryMathematical Formalization
Protocols / Soundness
Infrastructure / CI
Documentation
Omissions & Discrepancies
Statistics
Lean Declarations ✏️ Added: 30 declaration(s)
✏️ Affected: 2 declaration(s) (line number changed)
📋 **Additional Analysis**Two new Lean source files were added, but both violate the header/attribution policy by containing a space before the comma in the author names, which should not include 'Harmonic' as a parenthetical. The other files (CI config, VCVio.lean, VCVioTest.lean, EvalDist.lean) are routine edits that correctly preserve existing headers or stay bare. No further style-guide violations were found. 📄 **Per-File Summaries**
Last updated: 2026-07-16 13:08 UTC. |
alexanderlhicks
left a comment
There was a problem hiding this comment.
Note
This review is AI-generated (Claude Code), run and posted at my request. Every claim below was machine-validated against the PR head d26325af (local build, #print axioms, direct reading of the cited sources); line references are exact so each point can be independently checked.
Thanks for this — the formalization checks out on the correctness axis, and the design choice at its core (per-fixed-context, worst-case quantification with a uniform fresh challenge) is the right "paper-strength" layer. Summary of what was validated, followed by suggestions. Code-level points are inline.
Validated ✅
- Build:
lake build VCVio.CryptoFoundations.RoundByRoundat the PR head is clean (no errors/warnings, nosorry). Note that CI on this PR only ran the summarize job — worth triggering the Lean build workflow before merge. - Axioms:
#print axiomson all public declarations reports standard axioms only (propext,Classical.choice,Quot.sound). - Faithfulness to BGTZ Definition 4.2 (ePrint 2023/1256), clause by clause:
InitialCondition↔ "for all inputs x (not necessarily in L_R), (x) ∈ D";TerminalCondition↔ doomed terminal transcript ⇒ reject any final message;ExtractionCondition↔ "Pr_{c←$C_i}[(x,τ,m,c) ∉ D] > ε_i ⇒ Ext(x,τ,m) outputs a valid witness", with the strict inequality direction and the per-fixed-message trigger both matching (the per-message reading is also the one the paper's own §6 proofs use). - Uniformity and failure mass:
SampleableTypecarries the equal-probability law (probOutput_selectElem_eq) andprobFailure_uniformSample = 0, soPr[escapeEvent … | sampleChallenge …]is exactly the paper's uniform-challenge probability.experiment_advantageis also correct in general:guardroutes both "event false" and any failure mass ofsampleinto⊥, soadvantage = Pr[event]holds unconditionally. - Instantiability: the API admits a complete instantiation — a toy one-round protocol satisfies
ExtensionalConditionswith zero error in a short proof (collapsed below), and the probability obligations aresimp-tractable. - One observation, not a defect: the conditions quantify over all contexts, including ones unreachable via
extendfrom anyinitialContext. This is strictly stronger than Def 4.2 but harmless, sincedoomedcan always be restricted to reachable contexts (closed underextend); theIsBoundeddocstring's subtype remark already gestures at this.
Instantiation smoke test (compiles against this PR)
import VCVio.CryptoFoundations.RoundByRound
open RoundByRound OracleComp
noncomputable def toy : KnowledgeExtractionFamily 1 where
Statement := Bool
Witness := Unit
Context := fun _ => Bool
Message := fun _ => Unit
Challenge := fun _ => Bool
FinalMessage := Unit
challengeSampleable := fun _ => inferInstance
statement := fun _ x => x
initialContext := id
extend := fun _ x _ _ => x
statement_initial := fun _ => rfl
statement_extend := fun _ _ _ _ => rfl
doomed := fun stage x => stage.val = 0 ∨ x = false
extract := fun _ _ _ => ()
relation := fun x _ => x = true
rejects := fun x _ => x = false
example : toy.ExtensionalConditions (fun _ => 0) := by
refine ⟨fun input => Or.inl rfl, ?_, ?_⟩
· rintro x m (h | h)
· simp [Fin.last] at h
· exact h
· intro round x m hdoomed hlt
by_cases hx : x = true
· exact hx
· exfalso
simp only [Bool.not_eq_true] at hx
have hzero : Pr[toy.escapeEvent round x m | toy.sampleChallenge round] = 0 := by
simp [KnowledgeExtractionFamily.escapeEvent, toy, hx]
rw [hzero] at hlt
exact lt_irrefl 0 hltMain suggestion: connect the module to its waiting consumers
The quantification style chosen here already has proven consumers on the ArkLib side (ArkLib depends on VCV-io, so this module becomes visible to it). On Verified-zkEVM/ArkLib branch feat/abf26-plan, the ABF26 toy-problem development proves per-round facts in exactly this per-fixed-prefix shape (see the "Quantification note" in ArkLib/ProofSystem/ToyProblem/Spec/General.lean ~L1196, and gamma_transition_prob_le in ToyProblem/SoundnessBounds.lean ~L1064, which is literally a badEvent-style bound), then lifts them into ArkLib's averaged rbrKnowledgeSoundness game via mixture lemmas (probEvent_simulateQ_addLift_getChallenge_bind_le, ArkLib/ToVCVio/OracleComp/RbrGame.lean:81); branch feat/generic-ring-switch has the analogous probEvent_challengeRound_le (Security/ChallengeRound.lean:49). Both pipelines consume bare ∀ prefix, Pr[fun c ↦ E … | $ᵗ _] ≤ ε facts directly.
Two actionable follow-ups that would make this PR immediately load-bearing:
- Add the
probEvent-over-bind mixture lemmas to VCV-io —RbrGame.leanexplicitly docstring-flagsprobEvent_bind_le_probEvent(:177),probEvent_bind_le_probEvent_add(:199), andprobEvent_bind_le_probEvent_convex(:233) as "upstream VCV-io candidates". They are the generic bridge from this module's per-context conditions to full averaged game statements, and they have two independent consumers waiting. - Ship one in-repo consumer for the knowledge layer — most naturally a
SigmaProtocoladapter (rounds := 1instance ofKnowledgeExtractionFamily), or one of the BGTZ implication theorems (e.g. RBR knowledge ⇒ special soundness; the analogous ArkLib statements exist but are currently sorried infeat/abf26-plan'sSecurity/Implications.lean). Either would validate the abstraction against a use case and settle the API.
| variable {Round : Type u} {Context : Round → Type v} | ||
|
|
||
| /-- The failure-based experiment that succeeds exactly when the indexed event occurs. -/ | ||
| def experiment (games : GameFamily Round Context) |
There was a problem hiding this comment.
[AI-generated] def … := by classical exact {…} appears to be the first tactic-block def in the repo (the existing idiom for classical instances in definitions is term-level, e.g. letI := Classical.dec _ in VCVio/ProgramLogic/Relational/QuantitativeDefs.lean:38). Term mode keeps the definition's unfolding transparent, which would also let experiment_advantage below avoid its change steps. Since this file already uses term-level letI in sampleChallenge, the same style works here:
def experiment (games : GameFamily Round Context)
(round : Round) (context : Context round) : SecExp (OptionT ProbComp) :=
letI : DecidablePred (games.event round context) := Classical.decPred _
{ toSPMFSemantics := SPMFSemantics.ofMonadLift (OptionT ProbComp)
main := do
let result ← OptionT.lift (games.sample round context)
guard (games.event round context result) }Easy to validate: swap and rebuild.
|
|
||
| /-- The advantage of the indexed experiment is the probability of its event. -/ | ||
| @[simp] | ||
| theorem experiment_advantage (games : GameFamily Round Context) |
There was a problem hiding this comment.
[AI-generated] The proof is correct (machine-checked), but the two change steps tie it to definitional unfolding through SecExp.advantage / ofMonadLift / the tactic-defined experiment, which makes it fragile under refactors. The library already has the transparent route:
SPMFSemantics.ofMonadLift_probFailure(VCVio/EvalDist/Defs/Semantics.lean:145) replaces the firstchange;probOutput_bind_guard_eq_probEvent(VCVio/OracleComp/EvalDist.lean:394) is exactly the "experiment succeeds iff event holds" bridge forOptionT (OracleComp spec)— it is currentlyprivate, so consider publicizing it (or adding aprobFailure_bind_guard_eq_probEventsibling next to it, alongside the existing@[simp]probOutput_guard/probFailure_guard) and reducing this proof to a couple of rewrites.
That would also serve the two downstream experiment_advantage lemmas, and future SecExp-over-guard constructions get the bridge for free.
|
|
||
| The context at a round is fixed before `sampleChallenge` draws the fresh challenge. The two witness | ||
| types represent knowledge immediately before and after that challenge. -/ | ||
| structure KnowledgeTransitionFamily (Round : Type u) (Context : Round → Type v) where |
There was a problem hiding this comment.
[AI-generated] KnowledgeTransitionFamily is not referenced by anything else in the PR: KnowledgeExtractionFamily.toGameFamily maps directly to GameFamily, and no lemma relates the two specializations. The shape itself is validated by real usage — e.g. ArkLib's proven γ-round bound gamma_transition_prob_le (feat/abf26-plan, ArkLib/ProofSystem/ToyProblem/SoundnessBounds.lean ~L1064) is precisely a badEvent-style statement (no-witness pre-state, ∃ post-challenge live message, bound over a uniform challenge) — so the structure is worth having. Suggestion: make that concrete inside this PR by adding the lemma connecting the two layers (e.g. how a KnowledgeExtractionFamily induces a KnowledgeTransitionFamily whose bounded bad-transition probability corresponds to the extraction clause — the analogue of ArkLib's one-shot ↔ knowledge-state-function bridge), or defer this structure to the follow-up PR that uses it.
| /-- Final prover messages supplied after all interaction rounds. -/ | ||
| FinalMessage : Type | ||
| /-- Canonical uniform-sampling data for each verifier challenge type. -/ | ||
| challengeSampleable : (round : Fin rounds) → SampleableType (Challenge round) |
There was a problem hiding this comment.
[AI-generated] Design note on bundling SampleableType as a field: sampleChallenge then runs under letI := games.challengeSampleable round, which for a user whose challenge types already carry ambient instances (the [∀ i, SampleableType (pSpec.Challenge i)] style used elsewhere, e.g. in ArkLib) is defeq to — but not syntactically — the ambient instance. That mismatch can surface as friction in rw/simp chains against $ᵗ-lemmas stated with the ambient instance. It's handled correctly here because the API's own lemmas are stated through games.sampleChallenge (good); just flagging that if downstream friction appears, lifting Challenge to a structure parameter with instance binders is the standard alternative.
| /-- The protocol context containing only the input statement. -/ | ||
| initialContext : Statement → Context 0 | ||
| /-- Appends the prover message and verifier challenge of an interaction round. -/ | ||
| extend : (round : Fin rounds) → |
There was a problem hiding this comment.
[AI-generated] extend hard-wires exactly one prover message followed by one challenge per round. Strictly alternating protocols fit directly, but consecutive prover messages or a challenge-first round (both common in practice; ArkLib's ProtocolSpec allows arbitrary direction sequences for this reason) only fit via Unit-padding of Message/Challenge. Since BGTZ's IOP model is round-based this is a faithful reading of Def 4.2 — suggestion is just to document it: one sentence in the structure docstring noting the alternation assumption and the Unit-padding encoding for other shapes would save future users a detour.
|
|
||
| For every fixed context and prover message whose preceding state is doomed, an escape probability | ||
| strictly greater than the round's error requires the directly extracted witness to be valid. -/ | ||
| def ExtractionCondition (games : KnowledgeExtractionFamily rounds) |
There was a problem hiding this comment.
[AI-generated] Two notes, one positive and one docstring sharpening. Positive: phrasing ε as a strict trigger threshold (error round < Pr[escape] → …) rather than a bound matches Def 4.2 exactly — ε appears in the paper only as the extraction trigger, and the inequality direction is right. Sharpening: since extract carries no efficiency requirement yet, ExtractionCondition as a hypothesis is equivalent to plain witness existence at every triggering context (any inhabitant of ∃ w, relation stmt w can be repackaged into an extract field by choice). The module docstring already says poly-time is omitted; consider stating this consequence explicitly — that until the admissibility layer lands, the condition pins down soundness-strength content and "knowledge" is not yet claimed — so downstream users don't over-read the guarantee. (As data the extractor is constructive, which is the right call for the eventual efficient version.)
|
[AI-generated] Addendum to the review above: the polynomial-time extractor admissibility that this PR (correctly, and explicitly) defers now has a natural in-repo formulation path via #460, which introduces TM-grounded polytime infrastructure — in particular Since |
|
@quangvdao you may have an opinion on this one. |
b732cc3 to
63f0f45
Compare
Define indexed event games, knowledge-transition families, and the extensional round-by-round extraction interface with experiments, per-round bounds, and initial, terminal, and extraction conditions. Co-authored-by: Aristotle (Harmonic) <aristotle-harmonic@harmonic.fun>
Add failure-complement and guarded-event probability lemmas, compile doomed extraction contexts into transition families, prove extraction equivalent to per-round boundedness, and add a non-vacuous one-round model. Co-authored-by: Aristotle (Harmonic) <aristotle-harmonic@harmonic.fun>
Compile the concrete one-half and zero-error cases in the build workflow and keep the supporting probability-lemma documentation intrinsic. Co-authored-by: Aristotle (Harmonic) <aristotle-harmonic@harmonic.fun>
63f0f45 to
354aba0
Compare
Formalizes round-indexed event games and the extensional doomed-set, uniform-challenge, direct-extractor, and terminal-rejection clauses of round-by-round knowledge in Lean 4.
Polynomial-time extractor admissibility and asymptotic negligibility remain incomplete in this concrete API.
Co-authored-by: Aristotle (Harmonic) aristotle-harmonic@harmonic.fun