Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Complexity.lean
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,7 @@ public import Complexity.Computability.GenericRAM.Simulation.Turing
public import Complexity.Computability.GenericRAM.SparseMemory.Basic
public import Complexity.Computability.GenericRAM.SparseMemory.Turing
public import Complexity.Computability.Interactive.Basic
public import Complexity.Computability.Interactive.GKR.Layered
public import Complexity.Computability.Interactive.Plain
public import Complexity.Computability.Interactive.Security
public import Complexity.Computability.Interactive.Sequential
Expand Down
192 changes: 192 additions & 0 deletions Complexity/Computability/Interactive/GKR/Layered.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/-
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Samuel Schlesinger
-/

module
-- upstream: candidate

public import Complexity.Foundations.BooleanAnalysis.MultilinearExtension

/-!
# Layered arithmetic circuits and the GKR identity

A *layered arithmetic circuit* of fan-in two (`Cslib.Interactive.GKR.LayeredCircuit`) has its gates
arranged in layers, with the gates of layer `i` labelled by the bit strings of length `width i`.
Layer `0` is the input. Every gate of layer `i + 1` is an addition or a multiplication of two gates
of layer `i`, its left and right in-neighbours. Evaluating the layers in turn gives the gate values
`value x i` on an input `x` (`Cslib.Interactive.GKR.LayeredCircuit.value`). We number the layers
from the input, while [Thaler, §4.6][Thaler2022] numbers them from the output.

The *wiring predicates* `add_i (a, b, c)` and `mult_i (a, b, c)` of layer `i + 1` are `1` exactly
when gate `a` of layer `i + 1` is an addition, respectively a multiplication, with in-neighbours
`b` and `c` (`addPred`, `multPred`). The identity at the heart of the GKR protocol expresses the
multilinear extension of the gate values of a layer through the multilinear extensions of the
wiring predicates and the gate values of the layer below
(`Cslib.Interactive.GKR.LayeredCircuit.eval_multilinearExtension_step`)
[Thaler, Lemma 4.7][Thaler2022], [Goldwasser, Kalai, Rothblum][GoldwasserKalaiRothblum2015]:
`W̃_{i+1}(z) = ∑_{b, c} ãdd_i(z, b, c) (W_i(b) + W_i(c)) + m̃ult_i(z, b, c) W_i(b) W_i(c)`.

## Main definitions

* `Cslib.Interactive.GKR.LayeredCircuit`: a layered arithmetic circuit of fan-in two.
* `Cslib.Interactive.GKR.LayeredCircuit.step`, `Cslib.Interactive.GKR.LayeredCircuit.value`:
evaluation of one layer and of the circuit.
* `Cslib.Interactive.GKR.LayeredCircuit.addPred`, `Cslib.Interactive.GKR.LayeredCircuit.multPred`:
the wiring predicates.

## Main results

* `Cslib.Interactive.GKR.LayeredCircuit.eval_multilinearExtension_wiringPred`: the closed form of
the multilinear extensions of the wiring predicates (`addPred` and `multPred` are its two cases).
* `Cslib.Interactive.GKR.LayeredCircuit.eval_multilinearExtension_step`: the GKR identity.

## References

* [S. Goldwasser, Y. T. Kalai, G. N. Rothblum, *Delegating computation: interactive proofs for
muggles*][GoldwasserKalaiRothblum2015]
* [J. Thaler, *Proofs, Arguments, and Zero-Knowledge*][Thaler2022], Section 4.6
-/

@[expose] public section

namespace Cslib.Interactive.GKR

open MvPolynomial Cslib.BitString

/-- The two kinds of gates of an arithmetic circuit of fan-in two. -/
inductive Gate
/-- An addition gate. -/
| add
/-- A multiplication gate. -/
| mul
deriving DecidableEq

/-- A **layered arithmetic circuit** of fan-in two. The gates of layer `i` are labelled by bit
strings of length `width i`; layer `0` is the input, and each gate of layer `i + 1` combines two
gates of layer `i`. -/
structure LayeredCircuit where
/-- The number of layers above the input. -/
depth : ℕ
/-- Layer `i` has `2 ^ width i` gates. -/
width : ℕ → ℕ
/-- The kind of each gate of layer `i + 1`. -/
gate : (i : ℕ) → (Fin (width (i + 1)) → Bool) → Gate
/-- The left in-neighbour, in layer `i`, of each gate of layer `i + 1`. -/
left : (i : ℕ) → (Fin (width (i + 1)) → Bool) → Fin (width i) → Bool
/-- The right in-neighbour, in layer `i`, of each gate of layer `i + 1`. -/
right : (i : ℕ) → (Fin (width (i + 1)) → Bool) → Fin (width i) → Bool

namespace LayeredCircuit

variable (C : LayeredCircuit) {R : Type*} [CommRing R]

/-- The values of layer `i + 1`, given the values `W` of layer `i`. -/
def step (i : ℕ) (W : (Fin (C.width i) → Bool) → R) (a : Fin (C.width (i + 1)) → Bool) : R :=
match C.gate i a with
| .add => W (C.left i a) + W (C.right i a)
| .mul => W (C.left i a) * W (C.right i a)

/-- The gate values of layer `i` on the input `x`. -/
def value (x : (Fin (C.width 0) → Bool) → R) : (i : ℕ) → (Fin (C.width i) → Bool) → R
| 0 => x
| i + 1 => C.step i (value x i)

/-- The output values of the circuit. -/
def output (x : (Fin (C.width 0) → Bool) → R) : (Fin (C.width C.depth) → Bool) → R :=
C.value x C.depth

/-- The variables of a wiring predicate of layer `i + 1`: a gate `a` of layer `i + 1` and two gates
`b`, `c` of layer `i`. -/
abbrev WiringVar (i : ℕ) : Type := Fin (C.width (i + 1)) ⊕ (Fin (C.width i) ⊕ Fin (C.width i))

/-- The wiring predicate of a gate kind: `1` exactly when gate `a` of layer `i + 1` has that kind
and in-neighbours `b` and `c`. -/
def wiringPred (g : Gate) (i : ℕ) (v : C.WiringVar i → Bool) : R :=
open Classical in
if C.gate i (v ∘ Sum.inl) = g ∧ C.left i (v ∘ Sum.inl) = v ∘ Sum.inr ∘ Sum.inl ∧
C.right i (v ∘ Sum.inl) = v ∘ Sum.inr ∘ Sum.inr then 1 else 0

/-- The addition predicate `add_i`. -/
abbrev addPred (i : ℕ) : (C.WiringVar i → Bool) → R := C.wiringPred .add i

/-- The multiplication predicate `mult_i`. -/
abbrev multPred (i : ℕ) : (C.WiringVar i → Bool) → R := C.wiringPred .mul i

/-- The multilinear extension of a wiring predicate at `(z, y, w)` is the sum, over the gates `a`
of that kind, of the product of the basis polynomials of `a`, its left and its right in-neighbour.
-/
theorem eval_multilinearExtension_wiringPred (g : Gate) (i : ℕ) (z : Fin (C.width (i + 1)) → R)
(y w : Fin (C.width i) → R) :
eval (Sum.elim z (Sum.elim y w)) (multilinearExtension (C.wiringPred (R := R) g i)) =
∑ a, if C.gate i a = g then eval z (indicatorPoly a) * eval y (indicatorPoly (C.left i a)) *
eval w (indicatorPoly (C.right i a))
else 0 := by
simp only [multilinearExtension, map_sum, map_mul, eval_C, eval_indicatorPoly_apply]
rw [← (Equiv.sumArrowEquivProdArrow _ _ Bool).symm.sum_comp, Fintype.sum_prod_type]
refine Finset.sum_congr rfl fun a _ => ?_
rw [← (Equiv.sumArrowEquivProdArrow _ _ Bool).symm.sum_comp, Fintype.sum_prod_type]
simp only [Equiv.sumArrowEquivProdArrow_symm_apply_inl, Fintype.prod_sum_type,
Sum.elim_inl, Sum.elim_inr, wiringPred]
by_cases hg : C.gate i a = g
· rw [ite_eq_left hg]
rw [Finset.sum_eq_single (C.left i a), Finset.sum_eq_single (C.right i a)]
· simp only [Function.comp_def, Equiv.sumArrowEquivProdArrow_symm_apply_inl, hg,
Equiv.sumArrowEquivProdArrow_symm_apply_inr, and_self, ↓reduceIte, one_mul, mul_assoc]
congr 1
· intro c _ hc
simp [Function.comp_def, Ne.symm hc]
· simp
· intro b _ hb
refine Finset.sum_eq_zero fun c _ => ?_
simp [Function.comp_def, Ne.symm hb]
· simp
· rw [ite_eq_right hg]
refine Finset.sum_eq_zero fun b _ => Finset.sum_eq_zero fun c _ => ?_
simp [Function.comp_def, hg]

/-- **The GKR identity** [Thaler, Lemma 4.7][Thaler2022]. The multilinear extension of the values
of layer `i + 1` is a sum over the pairs of gates `b`, `c` of layer `i` of the multilinear
extensions of the wiring predicates times the sum, respectively the product, of the values of `b`
and `c`. -/
theorem eval_multilinearExtension_step (i : ℕ) (W : (Fin (C.width i) → Bool) → R)
(z : Fin (C.width (i + 1)) → R) :
eval z (multilinearExtension (C.step i W)) =
∑ b, ∑ c,
(eval (Sum.elim z (Sum.elim (bitPoint b) (bitPoint c)))
(multilinearExtension (C.addPred (R := R) i)) * (W b + W c) +
eval (Sum.elim z (Sum.elim (bitPoint b) (bitPoint c)))
(multilinearExtension (C.multPred (R := R) i)) * (W b * W c)) := by
rw [eval_multilinearExtension_eq_sum (C.step i W)]
simp only [eval_multilinearExtension_wiringPred, eval_indicatorPoly]
have hinner : ∀ b c, (∑ a, if C.gate i a = .add then eval z (indicatorPoly a) *
(if C.left i a = b then (1 : R) else 0) * (if C.right i a = c then 1 else 0) else 0) *
(W b + W c) +
(∑ a, if C.gate i a = .mul then eval z (indicatorPoly a) *
(if C.left i a = b then (1 : R) else 0) * (if C.right i a = c then 1 else 0) else 0) *
(W b * W c) =
∑ a, (if C.left i a = b ∧ C.right i a = c then eval z (indicatorPoly a) *
(if C.gate i a = .add then W b + W c else W b * W c) else 0) := by
intro b c
rw [Finset.sum_mul, Finset.sum_mul, ← Finset.sum_add_distrib]
refine Finset.sum_congr rfl fun a _ => ?_
by_cases hb : C.left i a = b <;> by_cases hc : C.right i a = c <;>
cases C.gate i a <;> simp [hb, hc]
simp only [hinner]
symm
refine (Finset.sum_congr rfl fun b _ => Finset.sum_comm).trans (Finset.sum_comm.trans ?_)
refine Finset.sum_congr rfl fun a _ => ?_
rw [Finset.sum_eq_single (C.left i a), Finset.sum_eq_single (C.right i a)]
· simp only [and_self, ite_true, step]
cases C.gate i a <;> simp [mul_comm]
· intro c _ hc
simp [Ne.symm hc]
· simp
· intro b _ hb
exact Finset.sum_eq_zero fun c _ => by simp [Ne.symm hb]
· simp

end LayeredCircuit

end Cslib.Interactive.GKR
11 changes: 11 additions & 0 deletions Complexity/Foundations/BooleanAnalysis/MultilinearExtension.lean
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Its total degree is at most the dimension.
## Main results

* `Cslib.BitString.eval_multilinearExtension`: the extension agrees with the function on the cube.
* `Cslib.BitString.eval_multilinearExtension_eq_sum`: the extension at any point, in the indicator
basis.
* `Cslib.BitString.totalDegree_multilinearExtension_le`: its total degree is at most the
dimension.
* `Cslib.BitString.rename_multilinearExtension`: renaming the coordinates along an equivalence
Expand Down Expand Up @@ -74,6 +76,15 @@ theorem eval_indicatorPoly [Fintype ι] (a x : ι → Bool) :
exact Finset.prod_eq_zero (Finset.mem_univ i)
(by cases ha : a i <;> cases hx : x i <;> simp_all)

/-- The point of `R^ι` with the coordinates of the bit string `x`. -/
abbrev bitPoint (x : ι → Bool) : ι → R := fun i => bitVal R (x i)

/-- The multilinear extension at any point is the sum of the values of the function weighted by the
indicator polynomials. -/
theorem eval_multilinearExtension_eq_sum [Fintype ι] [DecidableEq ι] (g : (ι → Bool) → R)
(z : ι → R) : eval z (multilinearExtension g) = ∑ a, g a * eval z (indicatorPoly a) := by
simp [multilinearExtension]

/-- The multilinear extension agrees with the function on the cube. -/
theorem eval_multilinearExtension [Fintype ι] [DecidableEq ι] (g : (ι → Bool) → R)
(x : ι → Bool) : eval (fun i => bitVal R (x i)) (multilinearExtension g) = g x := by
Expand Down
54 changes: 54 additions & 0 deletions ComplexityTests/GKRLayered.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/-
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Samuel Schlesinger
-/

import Complexity.Computability.Interactive.GKR.Layered

/-! # Layered arithmetic circuits and the GKR identity

A one-layer circuit multiplying its two inputs, its value, and an instance of the GKR identity.
-/

namespace ComplexityTests.GKRLayered

open Cslib.Interactive.GKR MvPolynomial Cslib.BitString

/-- One multiplication gate on two inputs: layer `0` has `2 ^ 1` gates, layer `1` has `2 ^ 0`. -/
def mulTwo : LayeredCircuit where
depth := 1
width := fun i => if i = 0 then 1 else 0
gate _ _ := .mul
left _ _ := fun _ => false
right _ _ := fun _ => true

-- The output is the product of the two inputs.
example (x : (Fin 1 → Bool) → ℤ) :
mulTwo.output x (fun _ => false) = x (fun _ => false) * x (fun _ => true) := rfl

-- The GKR identity for the multiplication layer, at any point.
example (W : (Fin (mulTwo.width 0) → Bool) → ℤ) (z : Fin (mulTwo.width 1) → ℤ) :
eval z (multilinearExtension (mulTwo.step 0 W)) =
∑ b, ∑ c,
(eval (Sum.elim z (Sum.elim (bitPoint b) (bitPoint c)))
(multilinearExtension (mulTwo.addPred (R := ℤ) 0)) * (W b + W c) +
eval (Sum.elim z (Sum.elim (bitPoint b) (bitPoint c)))
(multilinearExtension (mulTwo.multPred (R := ℤ) 0)) * (W b * W c)) :=
mulTwo.eval_multilinearExtension_step 0 W z

/--
info: 'Cslib.Interactive.GKR.LayeredCircuit.eval_multilinearExtension_step' depends on axioms:
[propext, Classical.choice, Quot.sound]
-/
#guard_msgs (whitespace := lax) in
#print axioms LayeredCircuit.eval_multilinearExtension_step

/--
info: 'Cslib.Interactive.GKR.LayeredCircuit.eval_multilinearExtension_wiringPred' depends on axioms:
[propext, Classical.choice, Quot.sound]
-/
#guard_msgs (whitespace := lax) in
#print axioms LayeredCircuit.eval_multilinearExtension_wiringPred

end ComplexityTests.GKRLayered
5 changes: 5 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,11 @@ Jukna coverage below is an additional target beyond the V1 port:
components, stated as theory without concrete ciphersuites.

The design is on #643, and the TQBF, PCP and GMW bridges are recorded there.
* **GKR delegation (#892).** [Layered](Complexity/Computability/Interactive/GKR/Layered.lean)
defines layered arithmetic circuits and proves the GKR identity expressing the multilinear
extension of a layer through the wiring predicates and the layer below. Open: the GKR protocol
itself (layer-by-layer sumcheck and the line reduction, with completeness and soundness), its
efficiency under uniformity, and the route to NEXP ⊆ MIP.
* **Classic symmetric constructions (#640, track D).** Proved: PRF-based MACs (#677), keyed
collision-resistant hash families and Merkle–Damgård (#678), universal hashing (#663),
[Carter–Wegman MACs from Δ-universal hashing](Complexity/Crypto/Protocols/MAC/CarterWegman.lean)
Expand Down
22 changes: 22 additions & 0 deletions references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -1667,6 +1667,17 @@ @article{Goldschlager1977
doi = {10.1145/1008354.1008356}
}

@article{GoldwasserKalaiRothblum2015,
author = {Goldwasser, Shafi and Kalai, Yael Tauman and Rothblum, Guy N.},
title = {Delegating Computation: Interactive Proofs for Muggles},
journal = {Journal of the ACM},
volume = {62},
number = {4},
pages = {27:1--27:64},
year = {2015},
doi = {10.1145/2699436}
}

@article{GoldwasserMicaliRackoff1989,
author = {Goldwasser, Shafi and Micali, Silvio and Rackoff, Charles},
title = {The Knowledge Complexity of Interactive Proof Systems},
Expand Down Expand Up @@ -3711,6 +3722,17 @@ @article{Tardos1989
year = {1989}
}

@article{Thaler2022,
author = {Thaler, Justin},
title = {Proofs, Arguments, and Zero-Knowledge},
journal = {Foundations and Trends in Privacy and Security},
volume = {4},
number = {2--4},
pages = {117--660},
year = {2022},
doi = {10.1561/3300000030}
}

@incollection{ Thomas1990,
author = {Wolfgang Thomas},
editor = {Jan van Leeuwen},
Expand Down
Loading