UltraPlonk: Part I

Crypto Study Club

14th Sept 2022

Plookup: Main Idea

  • Plookup is essentially a subset check protocol
\in
  • That is: \(\forall i \in [m], \ \exists j \in [d],\) we have: \(f_i =t_j\), assume \(m < d\).
  • Assume \(f,t\) are sorted, let's construct a vector \(s\) such that
\underbrace{\hspace{5.6cm}}
m
\underbrace{\hspace{12.49cm}}
d
f_1
f_2
f_3
f_4
t_1
t_2
t_3
t_4
t_5
t_6
t_7
t_8
t_9
t_1
t_2
t_3
t_4
t_5
t_6
t_7
t_8
t_9
f_1
f_2
f_3
f_4

Plookup: Main Idea

  • Plookup is essentially a subset check protocol
\in
  • That is: \(\forall i \in [m], \ \exists j \in [d],\) we have: \(f_i =t_j\), assume \(m < d\).
  • Assume \(f,t\) are sorted, let's construct a vector \(s\) such that
\underbrace{\hspace{5.6cm}}
m
\underbrace{\hspace{12.49cm}}
d
f_1
f_2
f_3
f_4
t_1
t_2
t_3
t_4
t_5
t_6
t_7
t_8
t_9
t_1
t_2
t_3
t_4
t_5
t_6
t_7
t_8
t_9
f_1
f_2
f_3
f_4

Plookup: Main Idea

  • Plookup is essentially a subset check protocol
\in
  • That is: \(\forall i \in [m], \ \exists j \in [d],\) we have: \(f_i =t_j\), assume \(m < d\).
  • Assume \(f,t\) are sorted, let's construct a vector \(s\) such that
\underbrace{\hspace{5.6cm}}
m
\underbrace{\hspace{12.49cm}}
d
f_1
f_2
f_3
f_4
t_1
t_2
t_3
t_4
t_5
t_6
t_7
t_8
t_9
f_1
f_2
f_3
f_4
t_1
t_2
t_3
t_4
t_5
t_6
t_7
t_8
t_9
0
  • Note that the differences in the vectors \(s\) and \(t\) are the same! (barring \(0\)s)
  • To prove this relation between \(s\) and \(t\), take a random \(\beta\) and compare:
d_1
d_2
0
d_3
d_4
d_5
d_6
0
0
d_7
d_8
\{t_i + \textcolor{grey}{\beta} t_{i+1}\}_{i \in [d-1]}
\{s_i + \textcolor{grey}{\beta} s_{i+1}\}_{i \in [m+d-1]}

Plookup: Main Idea

f_1
f_2
f_3
f_4
t_1
t_2
t_3
t_4
t_5
t_6
t_7
t_8
t_9
(\textcolor{orange}{t_1} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_2} + \textcolor{grey}{\gamma})
(1 + \textcolor{grey}{\beta}) (\textcolor{lightgreen}{f_1} + \textcolor{grey}{\gamma})
(\textcolor{orange}{t_2} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_3} + \textcolor{grey}{\gamma})
(1 + \textcolor{grey}{\beta}) (\textcolor{lightgreen}{f_2} + \textcolor{grey}{\gamma})
(\textcolor{orange}{t_3} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_4} + \textcolor{grey}{\gamma})
(\textcolor{orange}{t_4} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_5} + \textcolor{grey}{\gamma})
(\textcolor{orange}{t_5} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_6} + \textcolor{grey}{\gamma})
(\textcolor{orange}{t_6} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_7} + \textcolor{grey}{\gamma})
(1 + \textcolor{grey}{\beta}) (\textcolor{lightgreen}{f_3} + \textcolor{grey}{\gamma})
(1 + \textcolor{grey}{\beta}) (\textcolor{lightgreen}{f_4} + \textcolor{grey}{\gamma})
(\textcolor{orange}{t_7} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_8} + \textcolor{grey}{\gamma})
(\textcolor{orange}{t_8} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_9} + \textcolor{grey}{\gamma})
\begin{aligned} F(\textcolor{grey}{\beta}, \textcolor{grey}{\gamma}) &= \prod_{i \in [m]} (1 + \textcolor{grey}{\beta})(\textcolor{lightgreen}{f_i} + \textcolor{grey}{\gamma}) \cdot \\ & \ \ \ \prod_{i \in [d-1]} \left( (\textcolor{orange}{t_i} + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (\textcolor{orange}{t_{i+1}} + \textcolor{grey}{\gamma}) \right) \end{aligned}
\begin{aligned} G(\textcolor{grey}{\beta}, \textcolor{grey}{\gamma}) &= \prod_{i \in [m+d-1]} \left( (s_i + \textcolor{grey}{\gamma}) + \textcolor{grey}{\beta} (s_{i+1} + \textcolor{grey}{\gamma}) \right) \end{aligned}
  • Use something similar to permutation argument!
  • Therefore, \(\{\textcolor{lightgreen}{f_i}\}_{i \in [m]} \in \{\textcolor{orange}{t_i}\}_{i\in[d]} \iff F \equiv G\)
  • Degree of \(F\) and \(G\) is \((m+d-1)\) 
  • The prover work would be linear in \((m+d)\)
  • Thus, prover is linear in the lookup table size
  • Note: \(s\) is witness, \(t\) is a selector

Recap: Plonk Arithmetisation

\textcolor{gray}{2.} a_1 \textcolor{gray}{+3.}b_1 \textcolor{gray}{+1.}c_1 \textcolor{gray}{-1.}d_1 \textcolor{gray}{+5} = 0
\textcolor{gray}{0.} a_3 \textcolor{gray}{+0.}b_3 \textcolor{gray}{+1.}a_3b_3 \textcolor{gray}{-1.}c_3 \textcolor{gray}{+0} = 0
(a_i,b_i) \ \textcolor{grey}{+_{\text{ecc}}} \ (c_i, d_i) = (a_{i+1},b_{i+1})
\textsf{ecc gate}:
\underbrace{\hspace{2cm}}

StandardPlonk

\underbrace{\hspace{1cm}}

TurboPlonk

\textsf{a}
\textsf{b}
\textsf{c}
\textsf{d}
i
1
a_1
b_1
c_1
d_1
2
a_2
b_2
c_2
d_2
3
a_3
b_3
c_3
d_3
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
i
a_{i}
b_{i}
c_{i}
d_{i}
i+1
a_{i+1}
b_{i+1}
c_{i+1}
d_{i+1}
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
n-1
a_{n-1}
b_{n-1}
c_{n-1}
d_{n-1}
n
a_{n}
b_{n}
c_{n}
d_{n}
\textsf{add gate}:
\textsf{mult gate}:

Width = \(4\)

Circuit size = \(n\)

c_1 = a_i,
d_2 = b_i,
a_{i+1} = c_{n-1},
b_{i+1} = d_{n-1},
\underbrace{\hspace{1cm}}

Copy constraints

Cell-wise permutation

Plookup in Plonk

\textsf{a}
\textsf{b}
\textsf{c}
\textsf{d}
i
1
a_1
b_1
c_1
d_1
2
a_2
b_2
c_2
d_2
3
a_3
b_3
c_3
0
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
i
a_{i}
b_{i}
c_{i}
0
i+1
a_{i+1}
b_{i+1}
c_{i+1}
d_{i+1}
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
n-1
a_{n-1}
b_{n-1}
c_{n-1}
0
n
a_{n}
b_{n}
c_{n}
d_{n}

Width = \(4\)

Circuit size = \(n\)

\textsf{key}_1
\textsf{key}_2
\textsf{val}
\textsf{idx}
t_1^{(1)}
t_1^{(2)}
v_1
0
t_2^{(1)}
t_2^{(2)}
v_2
0
t_{m_1}^{(1)}
t_{m_1}^{(2)}
v_{m_1}
0

SHA-256

\vdots
\vdots
\vdots
\vdots

Lookup argument:

(a_3,b_3,c_3) \in T
\vdots
\vdots
\vdots
\vdots
t_{m_1+1}^{(1)}
t_{m_1+1}^{(2)}
v_{m_1+1}
1
t_{m_1+2}^{(1)}
t_{m_1+2}^{(2)}
v_{m_1+2}
1
t_{m_2}^{(1)}
t_{m_2}^{(2)}
v_{m_2}
1

XOR

\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
t_{m_1+3}^{(1)}
t_{m_1+3}^{(2)}
v_{m_1+3}
1
(a_i,b_i,c_i) \in T
(a_{n-1},b_{n-1},c_{n-1}) \in T

Lookup gates:

\{3,i,n-1\}

Now, let's construct \(s\) vector!

Plookup in Plonk

\textsf{a}
\textsf{b}
\textsf{c}
\textsf{d}
i
1
a_1
b_1
c_1
d_1
2
a_2
b_2
c_2
d_2
3
a_3
b_3
c_3
0
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
i
a_{i}
b_{i}
c_{i}
0
i+1
a_{i+1}
b_{i+1}
c_{i+1}
d_{i+1}
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
n-1
a_{n-1}
b_{n-1}
c_{n-1}
0
n
a_{n}
b_{n}
c_{n}
d_{n}
\textsf{key}_1
\textsf{key}_2
\textsf{val}
\textsf{idx}
t_1^{(1)}
t_1^{(2)}
v_1
0
t_2^{(1)}
t_2^{(2)}
v_2
0
t_{m_1}^{(1)}
t_{m_1}^{(2)}
v_{m_1}
0

SHA-256

\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
t_{m_1+1}^{(1)}
t_{m_1+1}^{(2)}
v_{m_1+1}
1
t_{m_1+2}^{(1)}
t_{m_1+2}^{(2)}
v_{m_1+2}
1
t_{m_2}^{(1)}
t_{m_2}^{(2)}
v_{m_2}
1

XOR

\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
t_{m_1+3}^{(1)}
t_{m_1+3}^{(2)}
v_{m_1+3}
1
  • To construct \(s\), copy lookup gates to the table.
a_3
b_3
c_3
0
a_{i}
b_{i}
c_{i}
0
a_{n-1}
b_{n-1}
c_{n-1}
0

Plookup in Plonk

\textsf{a}
\textsf{b}
\textsf{c}
\textsf{d}
i
1
a_1
b_1
c_1
d_1
2
a_2
b_2
c_2
d_2
3
a_3
b_3
c_3
0
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
i
a_{i}
b_{i}
c_{i}
0
i+1
a_{i+1}
b_{i+1}
c_{i+1}
d_{i+1}
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
n-1
a_{n-1}
b_{n-1}
c_{n-1}
0
n
a_{n}
b_{n}
c_{n}
d_{n}
\textsf{key}_1
\textsf{key}_2
\textsf{val}
\textsf{idx}
t_1^{(1)}
t_1^{(2)}
v_1
0
t_2^{(1)}
t_2^{(2)}
v_2
0
t_{m_1}^{(1)}
t_{m_1}^{(2)}
v_{m_1}
0

SHA-256

\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
t_{m_1+1}^{(1)}
t_{m_1+1}^{(2)}
v_{m_1+1}
1
t_{m_1+2}^{(1)}
t_{m_1+2}^{(2)}
v_{m_1+2}
1
t_{m_2}^{(1)}
t_{m_2}^{(2)}
v_{m_2}
1

XOR

\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
\vdots
t_{m_1+3}^{(1)}
t_{m_1+3}^{(2)}
v_{m_1+3}
1
  • To construct \(s\), copy lookup gates to the table.
a_3
b_3
c_3
0
a_{i}
b_{i}
c_{i}
1
a_{n-1}
b_{n-1}
c_{n-1}
1
  • Total lookups: \(L=\sum_j n_{l_j}\)
  • Table size: \(M=\sum_j m_j\)
  • We have: \(s^{(k)}\in \mathbb{F}^{(M + L)}\)
  • Multiset check to subset check:
s_i = s^{(1)}_i + \textcolor{grey}{\eta} s^{(2)}_i + \textcolor{grey}{\eta^2} s^{(3)}_i + \textcolor{grey}{\eta^3} s^{(4)}_i
f_i = a_i + \textcolor{grey}{\eta} b_i + \textcolor{grey}{\eta^2} c_i + \textcolor{grey}{\eta^3} \textsf{idx}_i
t_i = t^{(1)}_i + \textcolor{grey}{\eta} t^{(2)}_i + \textcolor{grey}{\eta^2} t^{(3)}_i + \textcolor{grey}{\eta^3} t^{(4)}_i
\implies \Big\{\textcolor{lightgreen}{f_i}\Big\}_{i \in [L]} \in \Big\{\textcolor{orange}{t_i}\Big\}_{i \in [M]}

Wait, Why Plookup?

  • Lets take a peek into the SHA-256 internals

XOR

AND

Right-rotate

Shift-right

  • Tons of bitwise operations! Very fast on CPUs!

UltraPlonk Example

a = \textcolor{grey}{10100110} \ \textcolor{grey}{10100110}
b = \textcolor{grey}{10110001} \ \textcolor{grey}{10011001}
  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
a \oplus b = \textcolor{grey}{00010111} \ \textcolor{grey}{01011010}
\textsf{ROTR}_{11}(a \oplus b) =
\textcolor{brown}{111} \ \textcolor{brown}{01011010}
\textcolor{grey}{00010}

UltraPlonk Example

a = \textcolor{grey}{10100110} \ \textcolor{grey}{10100110}
b = \textcolor{grey}{10110001} \ \textcolor{grey}{10011001}
  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
a \oplus b = \textcolor{grey}{00010111} \ \textcolor{grey}{01011010}
\textsf{ROTR}_{11}(a \oplus b) =
\textcolor{brown}{111} \ \textcolor{brown}{01011010}
\textcolor{grey}{00010}

UltraPlonk Example

a = \textcolor{grey}{10100110} \ \textcolor{grey}{10100110}
b = \textcolor{grey}{10110001} \ \textcolor{grey}{10011001}
  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
a \oplus b = \textcolor{grey}{00010111} \ \textcolor{grey}{01011010}
\textsf{ROTR}_{11}(a \oplus b) =
\textcolor{brown}{111} \ \textcolor{brown}{01011010}
\textcolor{grey}{00010}

UltraPlonk Example

a = \textcolor{grey}{10100110} \ \textcolor{grey}{10100110}
b = \textcolor{grey}{10110001} \ \textcolor{grey}{10011001}
  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
a \oplus b = \textcolor{grey}{00010111} \ \textcolor{grey}{01011010}
\textsf{ROTR}_{11}(a \oplus b) =
\textcolor{brown}{111} \ \textcolor{brown}{01011010}
\textcolor{grey}{00010}
  • This is easy on a CPU. What about lookup tables?
  • Lets split the XOR result in 8-bit slices (casted as 16-bit numbers)
\textcolor{gray}{00010111}
\textcolor{grey}{01011010}

UltraPlonk Example

a = \textcolor{grey}{10100110} \ \textcolor{grey}{10100110}
b = \textcolor{grey}{10110001} \ \textcolor{grey}{10011001}
  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
a \oplus b = \textcolor{grey}{00010111} \ \textcolor{grey}{01011010}
\textsf{ROTR}_{11}(a \oplus b) =
\textcolor{brown}{111} \ \textcolor{brown}{01011010}
\textcolor{grey}{00010}
  • This is easy on a CPU. What about lookup tables?
  • Lets split the XOR result in 8-bit slices (casted as 16-bit numbers)
\textcolor{lightgrey}{00010111}
\textcolor{lightgrey}{01011010}
\textcolor{grey}{00000000}
\textcolor{grey}{00000000}
\textcolor{grey}{000} \textcolor{orange}{01011010} \textcolor{grey}{00000}
\textcolor{orange}{111} \textcolor{grey}{00000000} \textcolor{orange}{00010}
\texttt{\textcolor{grey}{// left-shift by 5}}
\texttt{\textcolor{grey}{// right-rotate by 3}}
  • Therefore, lets use lookup tables for 8-bit slices

UltraPlonk Example

a = \textcolor{blue}{10100110} \ \textcolor{red}{10100110}
b = \textcolor{blue}{10110001} \ \textcolor{red}{10011001}
  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
\textcolor{grey}{00000000}
\textcolor{grey}{00000000}
\textcolor{orange}{00000000}
\textcolor{grey}{00000000}
\textcolor{grey}{00000001}
\textcolor{orange}{00000001}
\textcolor{grey}{00101101}
\textcolor{grey}{00001010}
\textcolor{orange}{00100111}
\textcolor{grey}{10100110}
\textcolor{grey}{10110001}
\textcolor{orange}{01011010}
\textcolor{grey}{11111111}
\textcolor{grey}{11111110}
\textcolor{orange}{00000001}
\textcolor{grey}{11111111}
\textcolor{grey}{11111111}
\textcolor{orange}{00000000}
\textcolor{grey}{00000000}
\textcolor{grey}{00000000}
\textcolor{orange}{000} \textcolor{grey}{00000000} \textcolor{orange}{00000}
\textcolor{grey}{00000000}
\textcolor{grey}{00000001}
\textcolor{orange}{001} \textcolor{grey}{00000000} \textcolor{orange}{00000}
\textcolor{grey}{00011011}
\textcolor{grey}{10001001}
\textcolor{orange}{010} \textcolor{grey}{00000000} \textcolor{orange}{10010}
\textcolor{grey}{10100110}
\textcolor{grey}{10011001}
\textcolor{orange}{111} \textcolor{grey}{00000000} \textcolor{orange}{00010}
\textcolor{grey}{11111111}
\textcolor{grey}{11111110}
\textcolor{orange}{001} \textcolor{grey}{00000000} \textcolor{orange}{00000}
\textcolor{grey}{11111111}
\textcolor{grey}{11111111}
\textcolor{orange}{000} \textcolor{grey}{00000000} \textcolor{orange}{00000}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{blue}{a}
\textcolor{blue}{b}
( \textcolor{blue}{a} \oplus \textcolor{blue}{b} )
\textcolor{red}{a}
\textcolor{red}{b}
\textsf{\textcolor{grey}{ROTR}}_3( \textcolor{red}{a} \oplus \textcolor{red}{b} )
2^{16}

UltraPlonk Example

a = \textcolor{blue}{10100110} \ \textcolor{red}{10100110}
b = \textcolor{blue}{10110001} \ \textcolor{red}{10011001}
  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
\textcolor{grey}{00000000}
\textcolor{grey}{00000000}
\textcolor{orange}{00000000}
\textcolor{grey}{00000000}
\textcolor{grey}{00000001}
\textcolor{orange}{00000001}
\textcolor{grey}{00101101}
\textcolor{grey}{00001010}
\textcolor{orange}{00100111}
\textcolor{grey}{10100110}
\textcolor{grey}{10110001}
\textcolor{orange}{01011010}
\textcolor{grey}{11111111}
\textcolor{grey}{11111110}
\textcolor{orange}{00000001}
\textcolor{grey}{11111111}
\textcolor{grey}{11111111}
\textcolor{orange}{00000000}
\textcolor{grey}{00000000}
\textcolor{grey}{00000000}
\textcolor{orange}{000} \textcolor{grey}{00000000} \textcolor{orange}{00000}
\textcolor{grey}{00000000}
\textcolor{grey}{00000001}
\textcolor{orange}{001} \textcolor{grey}{00000000} \textcolor{orange}{00000}
\textcolor{grey}{00011011}
\textcolor{grey}{10001001}
\textcolor{orange}{010} \textcolor{grey}{00000000} \textcolor{orange}{10010}
\textcolor{grey}{10100110}
\textcolor{grey}{10011001}
\textcolor{orange}{111} \textcolor{grey}{00000000} \textcolor{orange}{00010}
\textcolor{grey}{11111111}
\textcolor{grey}{11111110}
\textcolor{orange}{001} \textcolor{grey}{00000000} \textcolor{orange}{00000}
\textcolor{grey}{11111111}
\textcolor{grey}{11111111}
\textcolor{orange}{000} \textcolor{grey}{00000000} \textcolor{orange}{00000}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{grey}{\vdots}
\textcolor{blue}{a}
\textcolor{blue}{b}
( \textcolor{blue}{a} \oplus \textcolor{blue}{b} )
\textcolor{red}{a}
\textcolor{red}{b}
\textsf{\textcolor{grey}{ROTR}}_3( \textcolor{red}{a} \oplus \textcolor{red}{b} )
2^{16}
\textcolor{grey}{10100110}
\textcolor{grey}{10110001}
\textcolor{orange}{01011010}
\textcolor{grey}{10100110}
\textcolor{grey}{10011001}
\textcolor{orange}{111} \textcolor{grey}{00000000} \textcolor{orange}{00010}

UltraPlonk Example

  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
a = \textcolor{blue}{10100110} \ \textcolor{red}{10100110}
b = \textcolor{blue}{10110001} \ \textcolor{red}{10011001}
\textcolor{grey}{10100110}
\textcolor{grey}{10110001}
\textcolor{orange}{01011010}
\textcolor{grey}{10100110}
\textcolor{grey}{10011001}
\textcolor{orange}{111} \textcolor{grey}{00000000} \textcolor{orange}{00010}

Gate \(i\)

Gate \(i+1\)

\(0\)

\(0\)

w_1
w_2
w_3
w_4
  • Since we looked-up twice, we need two lookup gates
  • To reconstruct the inputs \(a, b\) and the output \(\textsf{ROTR}_{11}(a \oplus b)\):
a = ( \textcolor{red}{w_{1,i}} + \textcolor{grey}{2^{8}} \textcolor{blue}{w_{1,i+1}} )
b = ( \textcolor{red}{w_{2,i}} + \textcolor{grey}{2^{8}} \textcolor{blue}{w_{2,i}} )
c = ( w_{3,i} + \textcolor{grey}{2^{5}} w_{3,i+1})
  • This arithmetic to recover inputs and output might take additional gates
  • Hence, we store the cumulative sums in the lookup gates
  • The constants \((\textcolor{grey}{2^8, 2^8, 2^5})\) are called as column coefficients

UltraPlonk Example

  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
a = \textcolor{blue}{10100110} \ \textcolor{red}{10100110}
b = \textcolor{blue}{10110001} \ \textcolor{red}{10011001}
\textcolor{blue}{10100110}
\textcolor{blue}{10110001}
\textcolor{orange}{01011010}
\textcolor{blue}{10100110}
\textcolor{blue}{10110001}
\textcolor{orange}{01011010}
\textcolor{red}{10100110}
\textcolor{red}{10011001}
\textcolor{orange}{111} \textcolor{grey}{00000000} \textcolor{orange}{00010}

Gate \(i\)

Gate \(i+1\)

\(0\)

\(0\)

w_1
w_2
w_3
w_4
  • Since we looked-up twice, we need two lookup gates
  • To reconstruct the inputs \(a, b\) and the output \(\textsf{ROTR}_{11}(a \oplus b)\):
a = ( \textcolor{red}{w_{1,i}} + \textcolor{grey}{2^{8}} \textcolor{blue}{w_{1,i+1}} )
b = ( \textcolor{red}{w_{2,i}} + \textcolor{grey}{2^{8}} \textcolor{blue}{w_{2,i}} )
c = ( w_{3,i} + \textcolor{grey}{2^{5}} w_{3,i+1})
  • This arithmetic to recover inputs and output might take additional gates
  • Hence, we store the cumulative sums in the lookup gates
  • The constants \((\textcolor{grey}{2^8, 2^8, 2^5})\) are called as column coefficients

UltraPlonk Example

  • Compute \(\textsf{ROTR}_{11}(a \oplus b)\) for \(a, b \in \{0,1\}^{16}\)
a = \textcolor{blue}{10100110} \ \textcolor{red}{10100110}
b = \textcolor{blue}{10110001} \ \textcolor{red}{10011001}

Gate \(i\)

Gate \(i+1\)

\(0\)

\(0\)

  • Since we looked-up twice, we need two lookup gates
  • To reconstruct the inputs \(a, b\) and the output \(\textsf{ROTR}_{11}(a \oplus b)\):
a = ( \textcolor{red}{w_{1,i}} + \textcolor{grey}{2^{8}} \textcolor{blue}{w_{1,i+1}} )
b = ( \textcolor{red}{w_{2,i}} + \textcolor{grey}{2^{8}} \textcolor{blue}{w_{2,i}} )
c = ( w_{3,i} + \textcolor{grey}{2^{5}} w_{3,i+1})
  • This arithmetic to recover inputs and output might take additional gates
  • Hence, we store the cumulative sums in the lookup gates
  • The constants \((\textcolor{grey}{2^8, 2^8, 2^5})\) are called as column coefficients
\textcolor{blue}{10100110}
\textcolor{blue}{10110001}
\textcolor{orange}{01011010}
\textcolor{red}{10100110}
\textcolor{red}{10011001}
\textcolor{orange}{111} \textcolor{grey}{00000000} \textcolor{orange}{00010}
\textcolor{blue}{10100110}
\textcolor{blue}{10110001}
\textcolor{orange}{01011010}
w_1
w_2
w_3
w_4
+ \ \textcolor{grey}{2^8 \cdot}
+ \ \textcolor{grey}{2^8 \cdot}
+ \ \textcolor{grey}{2^5 \cdot}

Summary

  • Simple subset check and its math
  • Plookup in Plonk
    • Lookups as a multiset check
    • Multiset to subset check
    • Why Plookup?
  • UltraPlonk notation and example
  • Next:
    • Code walkthrough of Blake2s using lookups
    • Range constraints with lookup tables
    • Memory implementation using lookup tables

UltraPlonk: Part 1

By Suyash Bagad

UltraPlonk: Part 1

Ultraplonk basics.

  • 344