1 of 98

Intro to PLONKish/halo2

0xPARC Halo2 Learning Group

13 Jun 2022

2 of 98

arithmetisation

polynomial commitment scheme

accumulation scheme

3 of 98

arithmetisation

polynomial commitment scheme

accumulation scheme

satisfying witness

relation

low-degree polynomial

4 of 98

PLONKish arithmetisation

polynomial commitment scheme

accumulation scheme

satisfying witness

relation

low-degree polynomial

deep dive: 22 Jun

5 of 98

PLONKish arithmetisation

polynomial commitment scheme

accumulation scheme

satisfying witness

relation

low-degree polynomial

commitment opening proof

commit to polynomial, and provably evaluate it at arbitrary points

6 of 98

PLONKish arithmetisation

inner product argument

accumulation scheme

satisfying witness

relation

low-degree polynomial

commitment opening proof

commit to polynomial, and provably evaluate it at arbitrary points

7 of 98

PLONKish arithmetisation

inner product argument

accumulation scheme

satisfying witness

relation

low-degree polynomial

commitment opening proof

commitment opening proof

Θ(log d) accumulator size; amortised Θ(d) final check cost

8 of 98

PLONKish arithmetisation

inner product argument

accumulation scheme

satisfying witness

relation

low-degree polynomial

commitment opening proof

commitment opening proof

Θ(log d) accumulator size; amortised Θ(d) final check cost

9 of 98

PLONKish arithmetisation

UltraPLONK [halo2]

TurboPLONK [GW19]

lookup tables

TurboPLONK [GW19]

custom constraints

PLONK [GWC19]

10 of 98

PLONKish arithmetisation (vanilla)

PLONK [GWC19]

+

w0[0]

w1[0]

w1[1]

w0[1]

w2[1]

w2[0]

  • gates take two values as inputs, either add or multiply them, and then emit the result through an output wire;

11 of 98

PLONKish arithmetisation (vanilla)

PLONK [GWC19]

+

w0[0]

w1[0]

w1[1]

w0[1]

w2[1]

w2[0]

  • gates take two values as inputs, either add or multiply them, and then emit the result through an output wire;

"local" consistency check: are all gate equations satisfied?

12 of 98

PLONKish arithmetisation (vanilla)

PLONK [GWC19]

+

w0[0]

w1[0]

w1[1]

w0[1]

w2[1]

w2[0]

  • gates take two values as inputs, either add or multiply them, and then emit the result through an output wire;

"local" consistency check: are all gate equations satisfied?

qL·xa + qR·xb + qO·xc + qM·(xaxb) = 0

13 of 98

PLONKish arithmetisation (vanilla)

PLONK [GWC19]

+

w0[0]

w1[0]

w1[1]

w0[1]

w2[1]

w2[0]

  • gates take two values as inputs, either add or multiply them, and then emit the result through an output wire;

"local" consistency check: are all gate equations satisfied?

qL·xa + qR·xb + qO·xc + qM·(xaxb) = 0

preprocessed selector polynomials

14 of 98

PLONKish arithmetisation (vanilla)

PLONK [GWC19]

+

w0[0]

w1[0]

w1[1]

w0[1]

w2[1]

w2[0]

  • gates take two values as inputs, either add or multiply them, and then emit the result through an output wire;

"local" consistency check: are all gate equations satisfied?

add: 1·xa + 1·xb + (-1)·xc + 0·(xaxb) = 0

qL·xa + qR·xb + qO·xc + qM·(xaxb) = 0

15 of 98

PLONKish arithmetisation (vanilla)

PLONK [GWC19]

+

w0[0]

w1[0]

w1[1]

w0[1]

w2[1]

w2[0]

  • gates take two values as inputs, either add or multiply them, and then emit the result through an output wire;

"local" consistency check: are all gate equations satisfied?

add: 1·xa + 1·xb + (-1)·xc + 0·(xaxb) = 0

mul: 0·xa + 0·xb + (-1)·xc + 1·(xaxb) = 0

qL·xa + qR·xb + qO·xc + qM·(xaxb) = 0

16 of 98

PLONKish arithmetisation (custom gates)

TurboPLONK [GW19]

vanilla PLONK gate: qL·xa + qR·xb + qO·xc + qM·(xaxb) = 0

qadd·(a0 + a1 - a2) = 0

add gate

custom gates (arbitrary linear combinations):

17 of 98

PLONKish arithmetisation (custom gates)

TurboPLONK [GW19]

vanilla PLONK gate: qL·xa + qR·xb + qO·xc + qM·(xaxb) = 0

qadd·(a0 + a1 - a2) + qmul·(a0 · a1 - a2) = 0

add gate

mul gate

custom gates (arbitrary linear combinations):

18 of 98

PLONKish arithmetisation (custom gates)

TurboPLONK [GW19]

vanilla PLONK gate: qL·xa + qR·xb + qO·xc + qM·(xaxb) = 0

qadd·(a0 + a1 - a2) + qmul·(a0 · a1 - a2) + qbool·(a0·a0 - a0) = 0

add gate

mul gate

bool gate

custom gates (arbitrary linear combinations):

19 of 98

PLONKish arithmetisation (custom gates)

TurboPLONK [GW19]

vanilla PLONK gate: qL·xa + qR·xb + qO·xc + qM·(xaxb) = 0

custom gates (arbitrary linear combinations):

verifier challenge to keep gates linearly independent

qadd·(a0 + a1 - a2) + y ·qmul·(a0 · a1 - a2) + y2· qbool·(a0·a0 - a0) = 0

add gate

mul gate

bool gate

20 of 98

PLONKish arithmetisation (permutation)

PLONK [GWC19]

+

w0[0]

w1[0]

w1[1]

w0[1]

w2[1]

w2[0]

  • wires carry values into and out of gates

21 of 98

PLONKish arithmetisation (permutation)

PLONK [GWC19]

+

w0[0]

w1[0]

w1[1]

w0[1]

w2[1]

w2[0]

  • wires carry values into and out of gates

"global" consistency check: do the wires correctly join the gates together?

* in Groth16, routing is baked into the trusted setup; we can't do this for universal SNARKs

22 of 98

PLONKish arithmetisation (permutation)

PLONK [GWC19]

w0

w1

w2

gate

w0[0]

w1[0]

w2[0]

+

w0[1]

w1[1]

w2[1]

each wire (column i) is encoded as a Lagrange polynomial wi over the powers (rows) of an nth root of unity {1, ⍵, …,⍵n-1}, where ⍵n = 1:

wi(⍵j) = wi[j]

23 of 98

PLONKish arithmetisation (permutation)

PLONK [GWC19]

w0

w1

w2

gate

w0[0]

w1[0]

w2[0]

+

w0[1]

w1[1]

w2[1]

each wire (column i) is encoded as a Lagrange polynomial wi over the powers (rows) of an nth root of unity {1, ⍵, …,⍵n-1}, where ⍵n = 1:

wi(⍵j) = wi[j]

to enforce equality of wires, use permutation argument (deep-dive); show that swapping w2(⍵0) with w0(⍵1) doesn't change the polynomials.

24 of 98

PLONKish arithmetisation (lookup)

w0

w1

42

SHA(42)

0

0

69

SHA(69)

0

0

UltraPLONK [halo2]

problem: SHA is expensive to do in-circuit

25 of 98

PLONKish arithmetisation (lookup)

w0

w1

qlookup

t0

t1

42

SHA(42)

1

0

SHA(0)

0

0

0

1

SHA(1)

69

SHA(69)

1

2

SHA(2)

0

0

0

255

SHA(255)

UltraPLONK [halo2]

solution: load precomputed SHA (e.g. for 8-bit values) as lookup table

26 of 98

PLONKish arithmetisation (lookup)

w0

w1

qlookup

t0

t1

42

SHA(42)

1

0

SHA(0)

0

0

0

1

SHA(1)

69

SHA(69)

1

2

SHA(2)

0

0

0

255

SHA(255)

UltraPLONK [halo2]

(qlookup·w0, t0)

(qlookup·w1, t1)

27 of 98

PLONKish arithmetisation (lookup)

w0

w1

qlookup

t0

t1

42

SHA(42)

1

0

SHA(0)

0

0

0

1

SHA(1)

69

SHA(69)

1

2

SHA(2)

0

0

0

255

SHA(255)

UltraPLONK [halo2]

(qlookup·w0 + (1 - qlookup)·0, t0)

(qlookup·w1 + (1 - qlookup)·SHA(0), t1)

lookup default value when qlookup is not enabled, so that lookup argument passes on every row

28 of 98

PLONKish arithmetisation (lookup)

w0

w1

qlookup

t0

t1

42

SHA(42)

1

0

SHA(0)

0

0

0

1

SHA(1)

69

SHA(69)

1

2

SHA(2)

0

0

0

255

SHA(255)

UltraPLONK [halo2]

the lookup argument is a more permissive version of the permutation argument. it enforces that:�

every cell in a set of input columns is equal to� some cell in a set of table columns

29 of 98

PLONKish arithmetisation (lookup)

w0

w1

qlookup

t0

t1

42

SHA(42)

1

0

SHA(0)

0

0

0

1

SHA(1)

69

SHA(69)

1

2

SHA(2)

0

0

0

255

SHA(255)

UltraPLONK [halo2]

the lookup argument is a more permissive version of the permutation argument. it enforces that:�

every expression in a set of input columns is equal to� some expression in a set of table columns

more on this in the deep-dive!

30 of 98

PLONKish arithmetisation

we conceptualise the circuit as a matrix of m columns and n rows

31 of 98

PLONKish arithmetisation

we conceptualise the circuit as a matrix of m columns and n rows,�over a given finite field 𝔽 (so the cells contain elements of 𝔽)

32 of 98

PLONKish arithmetisation

each column j corresponds to a Lagrange interpolation polynomial pj(X)

33 of 98

PLONKish arithmetisation

each column j corresponds to a Lagrange interpolation polynomial pj(X)�evaluating to pj(⍵i) = xij, where ⍵ is the nth primitive root of unity.

xij

34 of 98

PLONKish arithmetisation

instance columns contain inputs shared between prover/verifier (e.g. public inputs)

35 of 98

PLONKish arithmetisation

advice columns contain private values witnessed by the prover

36 of 98

PLONKish arithmetisation

fixed columns contain preprocessed values set at key generation

37 of 98

example: Fibonacci sequence

i0

a0

a1

a2

qfib

1

1

1

2

1

2

3

5

1

13

5

8

13

0

write this in tomorrow's session!

38 of 98

example: Fibonacci sequence

i0

a0

a1

a2

qfib

1

1

1

2

1

2

3

5

1

13

5

8

13

0

qfib·(a0,cur + a1,cur - a2,cur) = 0

+ =

39 of 98

example: Fibonacci sequence

i0

a0

a1

a2

qfib

1

1

1

2

1

2

3

5

1

13

5

8

13

0

qfib·(a0,cur + a1,cur - a0,next) = 0

qfib·(a0,cur + a1,cur - a2,cur) = 0

40 of 98

example: Fibonacci sequence

i0

a0

a1

a2

qfib

1

1

1

2

1

2

3

5

1

13

5

8

13

0

qfib·(a0,cur + a1,cur - a0,next) = 0

qfib·(a0,cur + a1,cur - a2,cur) = 0

qfib·(a1,cur + a2,cur - a1,next) = 0

41 of 98

example: Fibonacci sequence

i0

a0

a1

a2

qfib

1

1

1

2

1

2

3

5

1

13

5

8

13

0

qfib·(a0,cur + a1,cur - a0,next) = 0

qfib·(a0,cur + a1,cur - a2,cur) = 0

qfib·(a1,cur + a2,cur - a1,next) = 0

global permutation: a2[i] = a0[i + 1]

42 of 98

example: Fibonacci sequence

i0

a0

a1

a2

qfib

1

1

1

2

1

2

3

5

1

13

5

8

13

0

qfib·(a0,cur + a1,cur - a0,next) = 0

qfib·(a0,cur + a1,cur - a2,cur) = 0

qfib·(a1,cur + a2,cur - a1,next) = 0

global permutation: a2[i] = a0[i + 1]

exercise: can you see how to constrain this locally (using qfib)?

43 of 98

example: Fibonacci sequence

i0

a0

a1

a2

qfib

1

1

1

2

1

2

3

5

1

13

5

8

13

0

qfib·(a0,cur + a1,cur - a0,next) = 0

qfib·(a0,cur + a1,cur - a2,cur) = 0

qfib·(a1,cur + a2,cur - a1,next) = 0

global permutation:

  • i0[0] = a0[0] // initialisation
  • i0[0] = a1[0] // initialisation
  • i0[2] = a2[2] // output

44 of 98

PLONKish arithmetisation

how do we optimise global layout while reasoning about local offsets?

45 of 98

PLONKish arithmetisation

regions!

46 of 98

regions

"regions" are the boundary between gates and the global circuit layouter

  • a block of assignments preserving relative offsets: easy to reason about how gates apply within the region�
  • not affected by offsets in other regions: can be freely rearranged to optimise global space usage

47 of 98

layouter

single-pass layouter (212 rows)

48 of 98

layouter

dual-pass layouter (211 rows)

single-pass layouter (212 rows)

49 of 98

halo2_gadgets

Sinsemilla

Poseidon

210 lookup table of indexed Sinsemilla generators:

(i, P[i]x, P[i]y)

50 of 98

halo2_gadgets

ECC

SHA256 (experimental)

51 of 98

open problems / wishlist

  • DSL / intermediate representation
    • add an API to construct a Halo 2 circuit from a set of constraints (halo2#550)
    • improve connection between gate configuration and assignment (halo2#365)
  • multi-phase prover (halo2#593)
  • dynamic lookup tables (halo2#534)

  • what other features would you like to see?

52 of 98

arithmetisation (cont.)

  1. arithmetise statement using UltraPLONK circuit

53 of 98

arithmetisation (cont.)

  • arithmetise statement using UltraPLONK circuit
  • commit to polynomials encoding the main components of the circuit;

Commit(p) = ∑n [p[i]]Gi,

where i = [0..=n], and Gi's are commitments to the Lagrange basis polynomials

ai(X)

advice polys

fi(X)

fixed polys

54 of 98

arithmetisation (cont.)

  • arithmetise statement using UltraPLONK circuit
  • commit to polynomials encoding the main components of the circuit;
  • construct vanishing argument to constrain all circuit relations to zero;

h(X) =

gate0(X) + y·gate1(X) + … + yn·gaten(X)

t(X)

where t(X) is the vanishing polynomial on the domain {ω0,…,ωn-1}; in other words, t(X) = Xn-1

55 of 98

arithmetisation (cont.)

  • arithmetise statement using UltraPLONK circuit
  • commit to polynomials encoding the main components of the circuit;
  • construct vanishing argument to constrain all circuit relations to zero;
  • evaluate the above polynomials at all necessary points;

h(x) =

gate0(x) + y·gate1(x) + … + yn·gaten(x)

t(x)

a0(x), a0(⍵x), a1(⍵x),…

f0(x), f1(⍵x), f1(⍵-1x),…

56 of 98

arithmetisation (cont.)

  • arithmetise statement using UltraPLONK circuit
  • commit to polynomials encoding the main components of the circuit;
  • construct vanishing argument to constrain all circuit relations to zero;
  • evaluate the above polynomials at all necessary points;
  • construct the multipoint opening argument to check that all evaluations are consistent with their respective commitments;

57 of 98

  1. group commitments by the sets of points at which they were queried:���
  2. construct polynomials to accumulate polynomials at each point set; sample x1 to keep them linearly independent:�� q0(X) = A0(X) + x1·A1(X)� q1(X) = A2(X) + x1·A3(X)�
  3. evaluate the qi's at their respective points: q0(x), q1(x), q1(⍵x)

multipoint opening argument

{x}

A0

A1

{x, ⍵x}

A2

A3

58 of 98

  • at each query point, interpolate the relevant qi evaluations:� r0(X) s.t. r0(x) = A0(x) + x1·A1(x);�� r1(X) s.t.�
  • construct polynomials to check the correctness of qi polynomials�� f0(X) =�� f1(X) =�
  • construct f(X) = f0(X) + x2·f1(X), with random x2 to keep fi polynomials linearly independent

multipoint opening argument

r1(x) = A2(x) + x1·A3(x)

r1(x) = A2(x) + x1·A3(x)

q0(X) - r0(X)

X - x

q1(X) - r1(X)

(X - x)(X - x)

59 of 98

multipoint opening argument

  • construct�� final_poly(X) = f(X) + x4·q0(X) + x42·q1(X),��with random x4 challenge to keep polynomials linearly independent.��this checks that all evaluations are consistent with their respective commitments.

60 of 98

polynomial commitment scheme

Setup(): generates a setup pk

Commit(pk, P): creates a commitment c to P

VerifyPoly(pk, c, P): checks c is a valid commitment to P

Open(pk, P, x): generates an opening proof π

VerifyOpen(pk, c, x, y, π): checks if y = P(x) using π

added in "Math Building Blocks" (15 Jun)

61 of 98

arithmetisation

polynomial commitment scheme

accumulation scheme

satisfying witness

relation

low-degree polynomial

commitment opening proof

commitment opening proof

Θ(log d) accumulator size; amortised Θ(d) final check cost

62 of 98

PLONKish arithmetisation +�vanishing argument, multipoint opening argument

inner product argument

accumulation scheme

satisfying witness

relation

final_poly

commitment opening proof

commitment opening proof

Θ(log d) accumulator size; amortised Θ(d) final check cost

63 of 98

inner product argument

Setup(1λ,d) produces a crs σ = (𝔾, 𝔽p, G, H) for group 𝔾 of � prime order p, with random G ∈ 𝔾d and H ∈ 𝔾.

Commit(σ, p(X); r): P =a, G〉 + [r]H, where ai∈𝔽 is the coeff � for the ith deg term in p(X), i ∈ [0,d)

VerifyPoly(pk, P, p): checks that P =〈a, G〉 + [r]H

Open(pk, p, x): generates an opening proof π for y = p(x)� =〈a, (1,x,…,xd-1)〉

VerifyOpen(pk, C, x, y, π): checks y =〈a, (1,x,…,xd-1)〉using π

added in "Math Building Blocks" (15 Jun)

NOT trusted!

64 of 98

inner product argument

Setup(1λ,d) produces a crs σ = (𝔾, 𝔽p, G, H) for group 𝔾 of � prime order p, with random G ∈ 𝔾d and H ∈ 𝔾.

Commit(σ, p(X); r): P =a, G〉 + [r]H, where ai∈𝔽 is the coeff � for the ith deg term in p(X), i ∈ [0,d)

VerifyPoly(pk, P, p): checks that P =〈a, G〉 + [r]H

Open(pk, p, x): generates an opening proof π for y = p(x)� =〈a, (1,x,…,xd-1)〉

VerifyOpen(pk, C, x, y, π): checks y =〈a, (1,x,…,xd-1)〉using π

naive opening proof: send a (O(n) communication)

want: π with O(log d) communication

added in "Math Building Blocks" (15 Jun)

65 of 98

inner product argument�(originally from [Bootle et al, 2016])

we have vectors a, b each of length d = 2k. we want to prove that a given inner product c and a commitment P are related as:

y = ⟨a, b

P = ⟨a, G⟩ + ⟨b, H

where G, H are length-n vectors of random group elements.�

we can combine this into a single commitment Pk using a random group element U:

Pk = P + [y]U = ⟨a, G⟩ + ⟨b, H⟩ + [⟨a, b⟩]U

the naive solution would be to send the verifier a, b — but this requires sending 2d scalars. instead, the inner product argument uses O(log(d)) = O(k) communication cost.

a(k)

b(k)

added in "Math Building Blocks" (15 Jun)

66 of 98

modified inner product argument

we have vectors a, b each of length d = 2k.

fix b = (1, x, x2,…,xd-1) for a chosen evaluation point x, known to both prover and verifier. since b is known, no random vector H is needed.

we want to prove that v, which is an evaluation of a at x, and a commitment P are related as:

v = ⟨a, (1, x, x2,…,xd-1)⟩

P = ⟨a, G⟩ + [r]H

where G is a length-n vector of random group elements.

we can combine this into a single commitment Pk using a random group element U:

Pk = P + [v]U = ⟨a, G⟩ + [r]H + [⟨a, b⟩]U

a(k)

b(k)

added in "Math Building Blocks" (15 Jun)

67 of 98

modified inner product argument

we start at the kth round, where we split a, b, G into lo and hi halves. we introduce a random challenge uk and compress the vectors by adding the left and the right halves separated by uk:�

a(k-1) = uk · alo(k) + uk-1 · ahi(k)

b(k-1) = uk-1 · blo(k) + uk · bhi(k)

G(k-1) = uk-1 · Glo(k) + uk · Ghi(k)

�now, we can write a commitment Pk-1 (of the same form as Pk) using the compressed vectors:

Pk-1 = ⟨a(k-1), G(k-1)⟩ + [⟨a(k-1), b(k-1)⟩] U

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

added in "Math Building Blocks" (15 Jun)

68 of 98

modified inner product argument

we can examine the compressed Pk-1 equation in terms of the original vectors:

Pk-1 = ⟨a(k-1), G(k-1)⟩ + [⟨a(k-1), b(k-1)⟩]U

= ⟨uk·alo + uk-1·ahi, uk-1·Glo + uk·Ghi⟩ +

[⟨uk·alo+ uk-1·ahi, uk-1·blo + uk·bhi⟩]U

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

added in "Math Building Blocks" (15 Jun)

69 of 98

modified inner product argument

we can examine the compressed Pk-1 equation in terms of the original vectors:

Pk-1 = ⟨a(k-1), G(k-1)⟩ + [⟨a(k-1), b(k-1)⟩]U

= ⟨uk·alo + uk-1·ahi, uk-1·Glo + uk·Ghi⟩ +

[⟨uk·alo+ uk-1·ahi, uk-1·blo + uk·bhi⟩]U

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

uk-2Rk

uk2Lk

Pk-1 = ⟨alo,Glo⟩ + ⟨ahi,Ghi⟩ + uk2alo,Ghi⟩ + uk-2ahi,Glo⟩ +

[⟨alo,blo⟩ + ⟨ahi,bhi⟩)]U + [uk2alo,bhi⟩ + uk-2ahi,blo⟩]U

= Pk + [uk2] Lk + [uk-2] Rk

added in "Math Building Blocks" (15 Jun)

70 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

Pk-1 = Pk + [uk2]Lk + [uk-2]Rk

Pk-1 is the sum of Pk and the cross-terms Lk, Rk (with coefficients from the round challenge uk)

uk-2Rk

uk2Lk

added in "Math Building Blocks" (15 Jun)

71 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

a(k-1)

b(k-1)

round k-1

we repeat this in the k-1st round, defining the new compressed eqn

Pk-2 = ⟨a(k-2),G(k-2)⟩ + [⟨a(k-2),b(k-2)⟩]U

uk-2Rk

uk2Lk

uk-1·alo(k-1)

uk-1-1·ahi(k-1)

uk-1-1·blo(k-1)

uk-1·bhi(k-1)

added in "Math Building Blocks" (15 Jun)

72 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

a(k-1)

b(k-1)

we repeat this in the k-1st round, defining the new compressed eqn

Pk-2 = ⟨a(k-2),G(k-2)⟩ + [⟨a(k-2),b(k-2)⟩]U

uk-2Rk

uk2Lk

uk-1-2Rk-1

uk-12Lk-1

uk-1-1·ahi(k-1)

uk-1·alo(k-1)

uk-1-1·blo(k-1)

uk-1·bhi(k-1)

and deriving new cross-terms

Lk-1, Rk-1 such that

Pk-2 = Pk-1 + [uk-12]Lk-1 + [uk-1-2]Rk-1

round k-1

added in "Math Building Blocks" (15 Jun)

73 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

a(k-1)

b(k-1)

we repeat this in the k-1st round, defining the new compressed eqn

Pk-2 = ⟨a(k-2),G(k-2)⟩ + [⟨a(k-2),b(k-2)⟩]U

uk-2Rk

uk2Lk

uk-1-2Rk-1

uk-12Lk-1

uk-1-1·ahi(k-1)

uk-1·alo(k-1)

uk-1-1·blo(k-1)

uk-1·bhi(k-1)

and deriving new cross-terms

Lk-1, Rk-1 such that

Pk-2 = Pk-1 + [uk-12]Lk-1 + [uk-1-2]Rk-1

� = Pk + [uk2]Lk + [uk-2]Rk

+ [uk-12]Lk-1 + [uk-1-2]Rk-1

round k-1

added in "Math Building Blocks" (15 Jun)

74 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

a(k-1)

b(k-1)

uk-2Rk

uk2Lk

uk-1-2Rk-1

uk-12Lk-1

uk-1-1·ahi(k-1)

uk-1·alo(k-1)

uk-1-1·blo(k-1)

uk-1·bhi(k-1)

a(k-2)

b(k-2)

round k-1

round k-2

added in "Math Building Blocks" (15 Jun)

75 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

a(k-1)

b(k-1)

uk-2Rk

uk2Lk

uk-1-2Rk-1

uk-12Lk-1

uk-1-1·ahi(k-1)

uk-1·alo(k-1)

uk-1-1·blo(k-1)

uk-1·bhi(k-1)

a(k-2)

b(k-2)

round k-1

round k-2

added in "Math Building Blocks" (15 Jun)

76 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

a(k-1)

b(k-1)

uk-2Rk

uk2Lk

uk-1-2Rk-1

uk-12Lk-1

uk-1-1·ahi(k-1)

uk-1·alo(k-1)

uk-1-1·blo(k-1)

uk-1·bhi(k-1)

a(k-2)

b(k-2)

round k-1

round k-2

round 1

�a(0)

�b(0)

u1-2R1

u12L1

added in "Math Building Blocks" (15 Jun)

77 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

a(k-1)

b(k-1)

uk-2Rk

uk2Lk

uk-1-2Rk-1

uk-12Lk-1

uk-1-1·ahi(k-1)

uk-1·alo(k-1)

uk-1-1·blo(k-1)

uk-1·bhi(k-1)

a(k-2)

b(k-2)

round k-1

round k-2

round 1

�a(0)

�b(0)

u1-2R1

u12L1

added in "Math Building Blocks" (15 Jun)

78 of 98

modified inner product argument

a(k)

b(k)

�uk·alo(k)

�uk-1·ahi(k)

�uk·bhi(k)

�uk-1·blo(k)

round k

a(k-1)

b(k-1)

uk-2Rk

uk2Lk

uk-1-2Rk-1

uk-12Lk-1

uk-1-1·ahi(k-1)

uk-1·alo(k-1)

uk-1-1·blo(k-1)

uk-1·bhi(k-1)

a(k-2)

b(k-2)

round k-1

round k-2

round 1

�a(0)

�b(0)

u1-2R1

u12L1

our proof is now just 2k - 1 field elements!

added in "Math Building Blocks" (15 Jun)

79 of 98

modified inner product argument

P0 = [a(0)]G(0) + [a(0)·b(0)] U

but P0 = ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

verifier checks this equivalence

[a]G + [a·b] U == ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

added in "Math Building Blocks" (15 Jun)

80 of 98

modified inner product argument

P0 = [a(0)]G(0) + [a(0)·b(0)] U

but P0 = ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

verifier checks this equivalence

[a]G + [a·b] U == ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

from prover

added in "Math Building Blocks" (15 Jun)

81 of 98

modified inner product argument

P0 = [a(0)]G(0) + [a(0)·b(0)] U

but P0 = ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

verifier checks this equivalence

[a]G + [a·b] U == ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

from prover

calculated by verifier

added in "Math Building Blocks" (15 Jun)

82 of 98

modified inner product argument

P0 = [a(0)]G(0) + [a(0)·b(0)] U

but P0 = ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

verifier checks this equivalence

[a]G + [a·b] U == ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

= g(x, u1, …, uk)

where g(X, u1, …, uk) = ∏k(ui + ui-1X2 )

(can compute in O(log(d) steps)

G,s

b,s

where s =

(u1-1 u2-1 u3-1 … uk-1,

u1 u2-1 u3 … uk-1,

u1-1 u2 u3-1 … uk ,

u1 u2 u3 … uk )

added in "Math Building Blocks" (15 Jun)

83 of 98

modified inner product argument

P0 = [a(0)]G(0) + [a(0)·b(0)] U

but P0 = ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

verifier checks this equivalence

[a]G + [a·b] U == ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

G,s

where s =

(u1-1 u2-1 u3-1 … uk-1,

u1 u2-1 u3 … uk-1,

u1-1 u2 u3-1 … uk ,

u1 u2 u3 … uk )

needs a linear-time multi-scalar multiplication.

this is a problem for recursive proof composition: a linear-size verification circuit will yield fixed-depth recursion at best.

instead, we use an accumulation scheme to amortise this linear cost across a batch of proof instances.

added in "Math Building Blocks" (15 Jun)

84 of 98

PLONKish arithmetisation +�vanishing argument, multipoint opening argument

inner product argument

accumulation scheme

satisfying witness

relation

final_poly

commitment opening proof

commitment opening proof

Θ(log d) accumulator size; amortised Θ(d) final check cost

added in "Math Building Blocks" (15 Jun)

85 of 98

PLONKish arithmetisation +�vanishing argument, multipoint opening argument

inner product argument

accumulation scheme

satisfying witness

relation

final_poly

commitment opening proof

commitment opening proof

Θ(log d) accumulator size; amortised Θ(d) final check cost

added in "Math Building Blocks" (15 Jun)

86 of 98

modified inner product argument

P0 = [a(0)]G(0) + [a(0)·b(0)] U

but P0 = ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

verifier checks this equivalence

[a]G + [a·b] U == ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

G,s

where s =

(u1-1 u2-1 u3-1 … uk-1,

u1 u2-1 u3 … uk-1,

u1-1 u2 u3-1 … uk ,

u1 u2 u3 … uk )

can itself be rewritten as a polynomial commitment:

G = G(0) = Commit(𝜎, g(X,u1,…,uk))

g(X,u1,…,uk) = ∏k(ui + ui-1X2 )

added in "Math Building Blocks" (15 Jun)

87 of 98

modified inner product argument

P0 = [a(0)]G(0) + [a(0)·b(0)] U

but P0 = ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

verifier checks this equivalence

[a]G + [a·b] U == ∑k([uj2] Lj) + Pk + ∑k([uj-2] Rj)

G,s

where s =

(u1-1 u2-1 u3-1 … uk-1,

u1 u2-1 u3 … uk-1,

u1-1 u2 u3-1 … uk ,

u1 u2 u3 … uk )

can itself be rewritten as a polynomial commitment:

G = G(0) = Commit(𝜎, g(X,u1,…,uk))

which means we can invoke an inner product argument for G.

g(X,u1,…,uk) = ∏k(ui + ui-1X2 )

added in "Math Building Blocks" (15 Jun)

88 of 98

accumulation scheme

in an accumulation scheme, it is expensive to “decide” validity of an instance, but cheap to combine two (or more) instances.

π evaluation proof for the claim that P(x) = v

added in "Math Building Blocks" (15 Jun)

accumulator

accumulation step

decider

P, x, v,

a, G, L, R {u1,u2,…,uk}

polynomial commitment opening of G (O(log(d) field operations)

the old accumulator and new instance (same form as the accumulator) are accumulated into a new accumulator

check (in O(d) time) that

G = Commit(g(X,u1,u2,…,uk))

= ⟨s,G

89 of 98

accumulation scheme

in an accumulation scheme, it is expensive to “decide” validity of an instance, but cheap to combine two (or more) instances.

accumulator

accumulation step

decider

P, x, v,

a, G, L, R {u1,u2,…,uk}

polynomial commitment opening of G (O(log(d) field operations)

the old accumulator and new instance (same form as the accumulator) are accumulated into a new accumulator

check (in O(d) time) that

G = Commit(g(X,u1,u2,…,uk))

= ⟨s,G

π evaluation proof for the claim that P(x) = v

instead of trying to compute G = ⟨s, G⟩ in the circuit, the verifier instead asks the prover to supply the purported G as part of their witness.

the recursive verifier then checks (in O(log(d) field operations) that G opens at some random point to the expected value for the given challenges {u1,u2,…,uk}.

added in "Math Building Blocks" (15 Jun)

90 of 98

accumulation scheme

zi

zi+1

IVC prover

πi

πi+1

ai

ai+1

IVC proof

IVC proof consists of:

  • SNARK proof πi,
  • accumulator ai

added in "Math Building Blocks" (15 Jun)

91 of 98

accumulation scheme

F

zi

zi+1

IVC prover

πi

πi+1

ai

ai+1

IVC proof

compute state transition function

added in "Math Building Blocks" (15 Jun)

92 of 98

accumulation scheme

F

zi

zi+1

IVC prover

πi

πi+1

ai

ai+1

IVC proof

accumulate previous inputs (zi, πi, ai) into a new accumulator ai+1

P

accumulation prover

added in "Math Building Blocks" (15 Jun)

93 of 98

accumulation scheme

F

zi

zi+1

IVC prover

πi

πi+1

ai

ai+1

IVC proof

verify that new accumulator was updated correctly

P

V

accumulation verifier

added in "Math Building Blocks" (15 Jun)

94 of 98

accumulation scheme

F

zi

zi+1

IVC prover

πi

πi+1

ai

ai+1

IVC proof

apply SNARK prover to the circuit R

P

V

R

SNARK.Prove

added in "Math Building Blocks" (15 Jun)

95 of 98

accumulation scheme

F

zi

zi+1

IVC prover

πi

πi+1

ai

ai+1

IVC proof

P

V

R

SNARK.Prove

IVC verifier

IVC verifier takes in some z, π, a

added in "Math Building Blocks" (15 Jun)

96 of 98

accumulation scheme

F

zi

zi+1

IVC prover

πi

πi+1

ai

ai+1

IVC proof

P

V

R

SNARK.Prove

IVC verifier

D

IVC verifier runs decider D to check that accumulator is well-formed

added in "Math Building Blocks" (15 Jun)

97 of 98

accumulation scheme

F

zi

zi+1

IVC prover

πi

πi+1

ai

ai+1

IVC proof

P

V

R

SNARK.Prove

IVC verifier

D

IVC verifier runs SNARK verifier

SNARK.Verify

added in "Math Building Blocks" (15 Jun)

98 of 98

thank you!

any questions?