-
Notifications
You must be signed in to change notification settings - Fork 96
feat(Bridge/Clean): FormalCircuit as ConstraintSystem + BehavioralContract #466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
XC0R
wants to merge
4
commits into
Verified-zkEVM:quang/constraint-system
Choose a base branch
from
XC0R:clean-constraint-system-bridge
base: quang/constraint-system
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+130
−12
Open
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
f305f41
feat(ConstraintSystem): universal CS abstraction with Hom and Behavio…
quangvdao 1451492
feat(Bridge/Clean): FormalCircuit as ConstraintSystem + BehavioralCon…
XC0R 0a71a4a
refactor(Bridge/Clean): move output to OStmt per review
XC0R 502c99a
Merge branch 'quang/constraint-system' into clean-constraint-system-b…
alexanderlhicks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| /- | ||
| Copyright (c) 2025 ArkLib Contributors. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: XC0R | ||
| -/ | ||
| import ArkLib.ProofSystem.ConstraintSystem.Basic | ||
| import Clean.Circuit.Foundations | ||
|
|
||
| /-! | ||
| # Clean ↔ ArkLib Bridge via ConstraintSystem | ||
|
|
||
| This module bridges Clean's `FormalCircuit` to ArkLib's `ConstraintSystem` and | ||
| `BehavioralContract` abstractions, transferring circuit-level security guarantees | ||
| (soundness and completeness) to ArkLib's universal constraint system interface. | ||
|
|
||
| A Clean `FormalCircuit F Input Output` maps to: | ||
| - A `ConstraintSystem` where `satisfies` checks input consistency (`eval env inputVar = inp`) | ||
| and circuit constraint satisfaction (`ConstraintsHold`). | ||
| - A `BehavioralContract` where `Assumptions` and `Spec` are transferred directly from the | ||
| circuit, with soundness proved via `original_soundness` and completeness via | ||
| `original_completeness`. | ||
|
|
||
| ## Main definitions | ||
|
|
||
| - `Clean.toConstraintSystem`: wraps a `FormalCircuit` as a `ConstraintSystem` | ||
| - `Clean.toBehavioralContract`: wraps a `FormalCircuit` as a `BehavioralContract`, | ||
| transferring both Clean security properties | ||
|
|
||
| ## Dependencies | ||
|
|
||
| Targets upstream [Verified-zkEVM/clean](https://github.com/Verified-zkEVM/clean) at pinned | ||
| commit `4a013fed` (post toolchain-bump-v4.28 merge via clean#357). | ||
| -/ | ||
|
|
||
| open Circuit | ||
|
|
||
| namespace Clean.Bridge | ||
|
|
||
| variable {F : Type} [Field F] | ||
| {Input Output : TypeMap} [ProvableType Input] [ProvableType Output] | ||
|
|
||
| /-- The canonical variable encoding for the input type, starting at offset 0. -/ | ||
| abbrev canonicalInputVar (Input : TypeMap) (F : Type) [Field F] [ProvableType Input] : | ||
| Var Input F := | ||
| varFromOffset Input 0 | ||
|
|
||
| /-- A Clean `FormalCircuit` viewed as an ArkLib `ConstraintSystem`. | ||
|
|
||
| The single index `Unit` reflects that one circuit is one constraint system (no size family). | ||
| The in-the-clear statement `Stmt` carries the public input. The oracle statement `OStmt` | ||
| carries the committed output — the prover commits to an output value and the constraint | ||
| system verifies consistency. `satisfies` checks input encoding, circuit constraints, and | ||
| output consistency. -/ | ||
| def toConstraintSystem (circuit : FormalCircuit F Input Output) : | ||
| ConstraintSystem where | ||
| Index := Unit | ||
| Stmt := fun _ => Input F | ||
| OStmt := fun _ => Output F | ||
| Wit := fun _ => Environment F | ||
| satisfies := fun _ inp out env => | ||
| eval env (canonicalInputVar Input F) = inp ∧ | ||
| ConstraintsHold env | ||
| (circuit.main (canonicalInputVar Input F) |>.operations 0) ∧ | ||
| eval env (circuit.output (canonicalInputVar Input F) 0) = out | ||
|
|
||
| /-- A Clean `FormalCircuit` viewed as an ArkLib `BehavioralContract`. | ||
|
|
||
| - **Soundness**: Clean's `original_soundness` guarantees that if assumptions hold and | ||
| constraints are satisfied, the circuit output satisfies `Spec`. | ||
| - **Completeness**: Clean's `original_completeness` guarantees that if assumptions hold | ||
| and a witness environment exists (encoding the input with valid local witnesses), | ||
| constraints are satisfied and the output meets the spec. | ||
|
|
||
| The output lives in `OStmt` (oracle/committed statement) rather than `Stmt`, reflecting | ||
| ZK semantics: the prover commits to the output, and completeness existentially quantifies | ||
| over it. | ||
|
|
||
| The `hWitGen` parameter asserts that for every input satisfying `Assumptions`, there exists | ||
| an environment encoding that input and using the circuit's local witness generators. This | ||
| is guaranteed by Clean's circuit construction (witness generators are deterministic functions | ||
| over the input), but is not directly exported as an existence theorem in Clean's API. -/ | ||
| noncomputable def toBehavioralContract (circuit : FormalCircuit F Input Output) | ||
| (hWitGen : ∀ inp, circuit.Assumptions inp → ∃ env : Environment F, | ||
| eval env (canonicalInputVar Input F) = inp ∧ | ||
| env.UsesLocalWitnesses 0 | ||
| (circuit.main (canonicalInputVar Input F) |>.operations 0)) : | ||
|
Comment on lines
+83
to
+86
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok so this assumption is kinda expected because FormalCircuits don't guarantee this. But we do have established a way to prove this quite easily for any given circuit, so the assumption could actually be removed with some massaging of the framework |
||
| ConstraintSystem.BehavioralContract (toConstraintSystem circuit) () where | ||
| Assumptions := fun inp => circuit.Assumptions inp | ||
| Spec := fun inp env => | ||
| circuit.Spec inp (eval env (circuit.output (canonicalInputVar Input F) 0)) | ||
| soundness := fun inp _ env hAssume ⟨hEval, hConstr, _⟩ => | ||
| circuit.original_soundness 0 env (canonicalInputVar Input F) inp hEval hAssume hConstr | ||
| completeness := fun inp hAssume => by | ||
| obtain ⟨env, hEval, hLocalWit⟩ := hWitGen inp hAssume | ||
| have hConstr := circuit.original_completeness 0 env | ||
| (canonicalInputVar Input F) inp hEval hAssume hLocalWit | ||
| have hSpec := circuit.original_soundness 0 env | ||
| (canonicalInputVar Input F) inp hEval hAssume hConstr | ||
| exact ⟨eval env (circuit.output (canonicalInputVar Input F) 0), env, | ||
| ⟨hEval, hConstr, rfl⟩, hSpec⟩ | ||
|
|
||
| end Clean.Bridge | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,222 @@ | ||
| /- | ||
| Copyright (c) 2025 ArkLib Contributors. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Quang Dao | ||
| -/ | ||
|
|
||
| import Mathlib.Data.Set.Defs | ||
|
|
||
| /-! | ||
| # Universal constraint system abstraction | ||
|
|
||
| This file introduces a small theory of constraint systems that provides a uniform interface | ||
| for the various concrete systems used across ArkLib (R1CS, Plonkish, lookups, memory | ||
| checking, AIR, CCS, and DSL-level systems such as Clean's `FormalCircuit`). | ||
|
|
||
| The goals are: | ||
|
|
||
| 1. **Unify**: capture the common shape `(index, statement, oracle statement, witness, | ||
| satisfies)` so that protocols and compilers can be written once and instantiated for any | ||
| concrete CS. | ||
| 2. **Compose**: introduce morphisms `ConstraintSystem.Hom` that transport satisfiability | ||
| along index/statement/witness maps, modelling reductions between constraint systems | ||
| (e.g. Clean gadget → R1CS row block, Plonkish → CCS, Plain R1CS → padded R1CS). | ||
| 3. **Extend with behaviour**: add a `BehavioralContract` layer that pairs a CS with | ||
| user-facing I/O contracts (assumptions + spec), in the style of Clean's `FormalCircuit`. | ||
|
|
||
| ## Design notes | ||
|
|
||
| - The structure is **indexed**: a single `ConstraintSystem` value packages an entire family | ||
| of concrete relations (one per `Index`), so that, e.g., R1CS of every size is a single | ||
| constraint system rather than one per `(m, n, n_w)`. | ||
| - The statement is split into an **in-the-clear** part (`Stmt`) and a **committed/oracle** | ||
| part (`OStmt`). Use `fun _ => PUnit` for `OStmt` if the system is purely non-oracle. If | ||
| multiple oracle slots are needed (as in R1CS with three matrices), bundle them via a | ||
| dependent function type inside `OStmt`. | ||
| - `satisfies` is a `Prop`, not a `Set`, for ergonomic use inside proofs and reductions. | ||
| - Morphisms are one-way (completeness-preserving). Soundness-reflecting variants | ||
| (extractors, embeddings, isos) are future work. | ||
| -/ | ||
|
|
||
| universe u v w | ||
|
|
||
| /-- A **constraint system** packages a family of indexed relations into a single bundle. | ||
|
|
||
| For each `i : Index` there is a `Stmt i` (the in-the-clear statement), an `OStmt i` (the | ||
| committed/oracle-accessible statement data; use `PUnit` if absent), and a `Wit i` (the | ||
| private witness). The predicate `satisfies i s o w` asserts that the triple `(s, o, w)` is | ||
| a valid instance at index `i`. -/ | ||
| structure ConstraintSystem : Type (max (u + 1) (v + 1) (w + 1)) where | ||
| /-- Index type parametrising the family of relations (sizes, shape parameters, etc.). -/ | ||
| Index : Type u | ||
| /-- In-the-clear part of the statement at each index. -/ | ||
| Stmt : Index → Type v | ||
| /-- Committed/oracle-accessible part of the statement. Use `fun _ => PUnit` for a | ||
| purely non-oracle constraint system. Multiple oracle slots can be bundled via a | ||
| dependent function type (e.g. `MatrixIdx → Matrix _ _ R` for R1CS). -/ | ||
| OStmt : Index → Type v | ||
| /-- Private witness. -/ | ||
| Wit : Index → Type w | ||
| /-- The satisfiability predicate at each index. -/ | ||
| satisfies : (i : Index) → Stmt i → OStmt i → Wit i → Prop | ||
|
|
||
| namespace ConstraintSystem | ||
|
|
||
| variable (C : ConstraintSystem.{u, v, w}) | ||
|
|
||
| /-- The underlying set-theoretic relation at a given index. -/ | ||
| def relation (i : C.Index) : Set (C.Stmt i × C.OStmt i × C.Wit i) := | ||
| { t | C.satisfies i t.1 t.2.1 t.2.2 } | ||
|
|
||
| /-- Existence of valid oracle data and witness for a given in-the-clear statement. -/ | ||
| def IsSatisfiable (i : C.Index) (s : C.Stmt i) : Prop := | ||
| ∃ o w, C.satisfies i s o w | ||
|
|
||
| /-- Build a constraint system from a plain indexed relation (no oracle statement slot). -/ | ||
| def ofRelation | ||
| {Idx : Type u} {S : Idx → Type v} {W : Idx → Type w} | ||
| (rel : (i : Idx) → S i → W i → Prop) : ConstraintSystem.{u, v, w} where | ||
| Index := Idx | ||
| Stmt := S | ||
| OStmt := fun _ => PUnit | ||
| Wit := W | ||
| satisfies := fun i s _ w => rel i s w | ||
|
|
||
| /-- Build a witness-free constraint system (assertions purely over the public and oracle | ||
| parts of the statement). -/ | ||
| def ofWitnessFree | ||
| {Idx : Type u} {S O : Idx → Type v} | ||
| (rel : (i : Idx) → S i → O i → Prop) : ConstraintSystem.{u, v, 0} where | ||
| Index := Idx | ||
| Stmt := S | ||
| OStmt := O | ||
| Wit := fun _ => PUnit | ||
| satisfies := fun i s o _ => rel i s o | ||
|
|
||
| end ConstraintSystem | ||
|
|
||
| /-! | ||
| ## Morphisms between constraint systems | ||
|
|
||
| A `ConstraintSystem.Hom` transports valid instances of one constraint system to valid | ||
| instances of another. It consists of: | ||
|
|
||
| - `index` — a map of shape indices (e.g. scale the size of an R1CS instance); | ||
| - `stmt`, `oStmt`, `wit` — compatible maps of statement, oracle-statement, and witness | ||
| data that in general may depend on the input in-the-clear statement; | ||
| - `preserves` — the core axiom that maps satisfying triples to satisfying triples. | ||
|
|
||
| Intuitively, `Hom C D` is a *completeness-preserving* reduction from `C` to `D`: if you can | ||
| satisfy `C` at some index, you can satisfy `D` at the image index, with an explicit | ||
| construction of the needed data. Soundness-reflecting morphisms (with extractors) are a | ||
| strict strengthening and are future work. | ||
|
|
||
| The name `Hom` follows Mathlib convention (`RelHom`, `RingHom`, `LinearMap`). A future | ||
| extension can add `ConstraintSystem.Hom.Embedding` or `ConstraintSystem.Iso` without | ||
| renaming anything. | ||
| -/ | ||
|
|
||
| namespace ConstraintSystem | ||
|
|
||
| /-- A completeness-preserving morphism between constraint systems. -/ | ||
| @[ext] | ||
| structure Hom (C D : ConstraintSystem.{u, v, w}) where | ||
| /-- Map on index types. -/ | ||
| index : C.Index → D.Index | ||
| /-- Map on in-the-clear statements. -/ | ||
| stmt : (i : C.Index) → C.Stmt i → D.Stmt (index i) | ||
| /-- Map on oracle/committed statement data. It may depend on the in-the-clear statement | ||
| as well, which is needed e.g. when the index encodes a global shape and the statement | ||
| fixes public inputs before committed data is computed. -/ | ||
| oStmt : (i : C.Index) → (s : C.Stmt i) → C.OStmt i → D.OStmt (index i) | ||
| /-- Map on witnesses, likewise allowed to depend on the input statement. -/ | ||
| wit : (i : C.Index) → (s : C.Stmt i) → C.Wit i → D.Wit (index i) | ||
| /-- Preservation property: valid instances map to valid instances. -/ | ||
| preserves : ∀ i s o w, | ||
| C.satisfies i s o w → D.satisfies (index i) (stmt i s) (oStmt i s o) (wit i s w) | ||
|
|
||
| namespace Hom | ||
|
|
||
| /-- The identity morphism on a constraint system. -/ | ||
| def id (C : ConstraintSystem.{u, v, w}) : Hom C C where | ||
| index := _root_.id | ||
| stmt := fun _ => _root_.id | ||
| oStmt := fun _ _ => _root_.id | ||
| wit := fun _ _ => _root_.id | ||
| preserves := fun _ _ _ _ h => h | ||
|
|
||
| /-- Composition of two morphisms. Reads right-to-left as usual. -/ | ||
| def comp {C D E : ConstraintSystem.{u, v, w}} (g : Hom D E) (f : Hom C D) : Hom C E where | ||
| index := g.index ∘ f.index | ||
| stmt := fun i s => g.stmt (f.index i) (f.stmt i s) | ||
| oStmt := fun i s o => g.oStmt (f.index i) (f.stmt i s) (f.oStmt i s o) | ||
| wit := fun i s w => g.wit (f.index i) (f.stmt i s) (f.wit i s w) | ||
| preserves := fun i s o w h => | ||
| g.preserves (f.index i) (f.stmt i s) (f.oStmt i s o) (f.wit i s w) (f.preserves i s o w h) | ||
|
|
||
| variable {C D E F : ConstraintSystem.{u, v, w}} | ||
|
|
||
| @[simp] theorem id_comp (f : Hom C D) : (id D).comp f = f := rfl | ||
|
|
||
| @[simp] theorem comp_id (f : Hom C D) : f.comp (id C) = f := rfl | ||
|
|
||
| theorem comp_assoc (h : Hom E F) (g : Hom D E) (f : Hom C D) : | ||
| (h.comp g).comp f = h.comp (g.comp f) := rfl | ||
|
|
||
| end Hom | ||
|
|
||
| /-- Morphisms preserve satisfiability. -/ | ||
| theorem Hom.isSatisfiable_map {C D : ConstraintSystem.{u, v, w}} (f : Hom C D) | ||
| {i : C.Index} {s : C.Stmt i} (hs : C.IsSatisfiable i s) : | ||
| D.IsSatisfiable (f.index i) (f.stmt i s) := by | ||
| obtain ⟨o, w, h⟩ := hs | ||
| exact ⟨f.oStmt i s o, f.wit i s w, f.preserves i s o w h⟩ | ||
|
|
||
| end ConstraintSystem | ||
|
|
||
| /-! | ||
| ## Behavioural contracts | ||
|
|
||
| In DSL-level systems like Clean, a circuit is bundled with a user-facing contract: | ||
| preconditions (`Assumptions`) on the statement and a high-level specification (`Spec`) | ||
| relating statement and witness. A `BehavioralContract` lifts this pattern onto an | ||
| arbitrary constraint system: at a fixed index, one provides such a contract together with | ||
| proofs that the underlying constraints *imply* the spec under the assumptions (soundness | ||
| of the gadget) and that a satisfying witness *exists* under the assumptions (completeness). | ||
|
|
||
| This gives us a clean target for migrating Clean's `FormalCircuit` into ArkLib without a | ||
| Clean-specific protocol bridge. | ||
| -/ | ||
|
|
||
| namespace ConstraintSystem | ||
|
|
||
| /-- A behavioural contract for a constraint system at a fixed index, consisting of an | ||
| `Assumptions` precondition on the in-the-clear statement and a `Spec` postcondition | ||
| relating statement and witness, together with soundness and completeness proofs tying the | ||
| contract to the underlying satisfiability relation. -/ | ||
| structure BehavioralContract (C : ConstraintSystem.{u, v, w}) (i : C.Index) where | ||
| /-- Precondition on the in-the-clear statement under which the contract applies. -/ | ||
| Assumptions : C.Stmt i → Prop | ||
| /-- High-level specification relating the in-the-clear statement and the witness. -/ | ||
| Spec : C.Stmt i → C.Wit i → Prop | ||
| /-- Soundness: if the assumptions hold and the underlying constraints are satisfied, | ||
| the spec holds for the recovered witness. -/ | ||
| soundness : ∀ s o w, Assumptions s → C.satisfies i s o w → Spec s w | ||
| /-- Completeness: if the assumptions hold, there exist oracle and witness data making | ||
| the underlying constraints satisfied *and* the spec true. -/ | ||
| completeness : ∀ s, Assumptions s → ∃ o w, C.satisfies i s o w ∧ Spec s w | ||
|
|
||
| namespace BehavioralContract | ||
|
|
||
| variable {C : ConstraintSystem.{u, v, w}} {i : C.Index} (B : BehavioralContract C i) | ||
|
|
||
| /-- Under the assumptions, the constraint system is satisfiable at `i` for every statement. | ||
| This is the most immediately useful corollary of `completeness`. -/ | ||
| theorem isSatisfiable_of_assumptions {s : C.Stmt i} (hs : B.Assumptions s) : | ||
| C.IsSatisfiable i s := by | ||
| obtain ⟨o, w, hsat, _⟩ := B.completeness s hs | ||
| exact ⟨o, w, hsat⟩ | ||
|
|
||
| end BehavioralContract | ||
|
|
||
| end ConstraintSystem |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think better would be to make the statement an (Input F, Output F) pair