lean4-htt/tests/elab/mvcgenWitnessType.lean
Sebastian Graf a32be44f90
feat: add @[mvcgen_witness_type] attribute for extensible witness classification (#12882)
This PR adds an `@[mvcgen_witness_type]` tag attribute, analogous to
`@[mvcgen_invariant_type]`, that allows users to mark types as witness
types. Goals whose type is an application of a tagged type are
classified as witnesses rather than verification conditions, and appear
in a new `witnesses` section in the `mvcgen` tactic syntax (before
`invariants`).

Witnesses are concrete values the prover supplies (inspired by
zero-knowledge proofs), as opposed to invariants (predicates maintained
across iterations) or verification conditions (propositions to prove).
The test uses a ZK-inspired example where a `SquareRootWitness` value
must be provided by the prover, with the resulting constraint
auto-discharged.

Changes:
- `src/Lean/Elab/Tactic/Do/Attr.lean`: register `@[mvcgen_witness_type]`
tag attribute and `isMVCGenWitnessType` helper
- `src/Lean/Elab/Tactic/Do/VCGen/Basic.lean`: add `witnesses` field to
`State`, three-way classification in `addSubGoalAsVC`
- `src/Std/Tactic/Do/Syntax.lean`: add `witnesses` section syntax
(before `invariants`), extract shared `goalDotAlt`/`goalCaseAlt` syntax
kinds
- `src/Lean/Elab/Tactic/Do/VCGen.lean`: extract shared
`elabGoalSection`, add `elabWitnesses`, wire up witness labeling and
elaboration
- `tests/elab/mvcgenWitnessType.lean`: end-to-end tests for
witness-only, witness with `-leave`, and combined witness+invariant
scenarios

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:38:05 +00:00

71 lines
2.5 KiB
Text

import Std.Tactic.Do
import Std
set_option backward.do.legacy false
open Std Do
set_option grind.warning false
set_option mvcgen.warning false
-- Test that `@[mvcgen_witness_type]` works end-to-end.
--
-- In zero-knowledge proofs, a witness is a concrete value the prover privately knows
-- (e.g. a field element), as opposed to an invariant (a predicate maintained across
-- iterations) or a verification condition (a proposition to prove).
--
-- We model this by axiomatizing a circuit-like computation that requires a concrete
-- witness value. The `mvcgen` tactic classifies the witness goal as `witness1` and
-- the constraint as `vc1`.
-- A witness type: a concrete value the prover supplies (not a predicate).
@[mvcgen_witness_type]
structure SquareRootWitness where
root : Nat
-- An axiomatized circuit that verifies a square root claim.
opaque checkSquareRoot (n : Nat) : Id Bool
-- Spec: given a witness w whose root squares to n, the circuit returns true.
-- When mvcgen applies this spec, `w` becomes a metavariable of witness type,
-- and the precondition `w.root * w.root = n` becomes a verification condition.
@[spec]
axiom checkSquareRoot_spec {n : Nat} (w : SquareRootWitness) :
Triple (checkSquareRoot n) ⌜w.root * w.root = n⌝ (⇓ r => ⌜r = true⌝)
def verifySquareRoot : Id Bool := do
checkSquareRoot 9
-- mvcgen produces:
-- witness1 : SquareRootWitness (concrete value to provide)
-- vc1 : 3 * 3 = 9 (constraint, auto-solved after witness instantiation)
-- The prover supplies ⟨3⟩ as the witness; the constraint is then trivially true.
theorem verifySquareRoot_correct :
⦃⌜True⌝⦄ verifySquareRoot ⦃⇓ r => ⌜r = true⌝⦄ := by
mvcgen [verifySquareRoot] witnesses
· ⟨3⟩
-- With -leave, the VC remains for manual discharge.
theorem verifySquareRoot_manual :
⦃⌜True⌝⦄ verifySquareRoot ⦃⇓ r => ⌜r = true⌝⦄ := by
mvcgen -leave [verifySquareRoot] witnesses
· ⟨3⟩
with omega
-- Demonstrate that witnesses and invariants can coexist, with witnesses first.
-- A program that first checks a witness and then loops over a list.
def witnessAndLoop (xs : List Nat) : Id Nat := do
let mut s := 0
let _ ← checkSquareRoot 9
for x in xs do
s := s + x
pure s
-- Both witnesses (before invariants) in the mvcgen syntax.
theorem witnessAndLoop_correct (xs : List Nat) :
⦃⌜True⌝⦄ witnessAndLoop xs ⦃⇓ _ => ⌜True⌝⦄ := by
mvcgen [witnessAndLoop] witnesses
· ⟨3⟩
invariants
· ⇓ _ => ⌜True⌝
with grind