[1]:
%load_ext autoreload
%autoreload 2
Groth16 in Klefki¶
Bilinear groups¶
We will work over bilinear groups \((p,\mathbb{G}_1,\mathbb{G}_2,\mathbb{G}_T,e,g,h)\) with the following properties:
\(\mathbb{G}_1, \mathbb{G}_2, \mathbb{G}_T\) are groups of prime order p
The pairing \(e\): \(\mathbb{G}_1x\mathbb{G}_2 \rightarrow \mathbb{G}_T\) is a binlinear map
\(g\) is a generator for \(\mathbb{G}_1\), \(h\) is a generator for \(\mathbb{G}_2\) and \(e(g, h)\) is a generator for \(\mathbb{G}_T\)
There are efficient algorithms for computing group operations, evaluating the bilinearmap, deciding membership of the groups, deciding equality of group elements andsampling generators of the groups. We refer to these as the generic group operations.
[3]:
from klefki.curves.barreto_naehrig.bn128 import BN128ScalarFP as FP, ECGBN128 as ECG
from klefki.algebra.utils import randfield
[4]:
g = ECG.G1
h = ECG.G2
We write \([a]_1\) for \(g^a\), \([b]_2\) for \(h^b\), and \([c]_T\) for \(e(g, h)^c\). A vector of group elements will be represented as \([\mathbf{a}]_i\). We defined dot product as \([\mathbf{a}]_1 \circ [\mathbf{b}]_2 = [\mathbf{a}\circ \mathbf{b}]_T\)
NIZK¶
let \(R\) be a relation generator that given a security parameter \(λ\) in unary returns a polynomial time decidable binary relation \(R\). For pairs \((\phi, \omega) \in R\).
For pairs \((\phi, \omega) \ in R\), we call \(\phi\) the statement and \(\omega\) the witness. We defined \(R_{\lambda}\) to be the set of possible relations \(R \). The relation generator may also output someside information, an auxiliary input \(z\), which will be given to the adversary.
An efficient prover publicly verifiable non-interactive argument for \(R\) is a quadruple of probabilistic polynomial algorithms \((Setup,Prove,Vfy,Sim)\) such that
\((\sigma,\tau) \leftarrow Setup(R)\): The setup produces a common reference stringσand a simulationtrapdoorτfor the relationR
\(\pi \leftarrow Prov(R, \sigma, \phi, \omega)\):The prover algorithm takes as input a common reference string σ and \((φ,w)∈R\) and returns an argument π.
\(0/1 \leftarrow Vfy(R, \sigma, \phi, \pi)\): The verification algorithm takes as input a common referencestring σ, a statement φ and an argumentπand returns 0 (reject) or 1 (accept).
\(\pi \leftarrow Sim(R, \tau, \phi)\): The simulator takes as input a simulation trapdoor and statementφand returns an argument π.
QAP¶
Given \(n\) equations we pick arbitrary distinct \(r_1,\cdots,r_n \in \mathbb{F}\) and define
we will be working with quadratic arithmetic programsRthat have thefollowing description
with \(|p|=\lambda\). The realation defineds a field \(\mathbb{Z}_p\) and a language of statement \((a_i,\cdots, a_l) \in \mathbb{Z}_p^l\) and witness \((a_{l+1}, \cdots, a_m) \in \mathbb{Z}_p^{m-l}\) such that with \(a_0=1\)
[5]:
from collections import namedtuple
RationalGenerator = namedtuple("RelationGenerator", ["F", "G1", "G2", "Gt", "e", "g", "h", "l", "U", "V", "W", "T"])
[6]:
from klefki.zkp.r1cs import R1CS
from klefki.zkp.qap import QAP
[7]:
@R1CS.r1cs(FP)
def f(x, k, c):
y = x + c + k
return y ** 3
[8]:
qap = QAP(f.A, f.B, f.C)
U, V, W, T = qap.qap
a = f.witness(FP(89), FP(8), FP(8))
[9]:
R = RationalGenerator(FP, ECG, ECG, ECG, ECG.e, ECG.G1, ECG.G2, 4, U, V, W, T)
\((\sigma,\tau) \leftarrow Setup(R)\):¶
Pick \(\alpha, \beta, \gamma, \delta, x \leftarrow \mathbb{Z}_P^*\), Define \(\tau = (\alpha, \beta, \gamma, \delta, x)\) and compute \(\sigma = ([\mathbf{\sigma_1}]_1, [\mathbf{\sigma_2}]_2\) where
[10]:
from typing import Iterable, Tuple, Type
from operator import add
from functools import reduce
def setup(R, m) -> Tuple[Iterable, Tuple[R.G1, R.G2]]:
tau = alpha, beta, delta, gamma, x = \
randfield(R.F), randfield(R.F), randfield(R.F), randfield(R.F), randfield(R.F)
n = R.U[0].degree
sigma_1 = [alpha, beta, delta] + \
[x ** i for i in range(0, n)] + \
[(R.U[i](x) * beta + R.V[i](x) * alpha + R.W[i](x)) / gamma for i in range(0, R.l)] + \
[(R.U[i](x) * beta + R.V[i](x) * alpha + R.W[i](x)) / delta for i in range(R.l, m)] + \
[(x ** i * R.T(x)) / delta for i in range(0, n-1)]
sigma_2 = [beta, gamma, delta] + \
[x**i for i in (0, n)]
sigma = ([R.g @ s for s in sigma_1], [R.h @ s for s in sigma_2])
return tau, sigma
[11]:
tau, sigma = setup(R, len(a))
\(\pi \leftarrow Prov(R, \tau, \sigma, a_1, \cdots, a_m)\)¶
Pick \(r, s \leftarrow \mathbb{Z}_p\) and compute \(\pi = ([A]_1, [C]_1, [B]_2\) where
[12]:
H = qap.H(a)
[27]:
def prov(R, tau, sigma, a, r=None, s=None) -> Tuple[R.G1, R.G1, R.G2]:
r = r or randfield(R.F)
s = s or randfield(R.F)
alpha, beta, delta, gamma, x = tau
m = len(a)
A = alpha + reduce(add, [a[i] * (R.U[i](x)) for i in range(0, m)]) + r * delta
B = beta + reduce(add, [a[i] * (R.V[i](x)) for i in range(0, m)]) + s * delta
C = (reduce(add,
[a[i]*(beta * (R.U[i](x)) + alpha * (R.V[i](x)) + R.W[i](x)) for i in range(R.l, m)]) \
+ H(x) * R.T(x)) / delta \
+ (A * s + B * r - r * s * delta)
return (R.g @ A, R.g @ C, R.h @ B)
[14]:
pi = prov(R, tau, sigma, a, r, s)
\(0/1 \leftarrow Vfy(R, \tau, a_1, \cdots, a_l, \pi)\)¶
Parse \(\pi = ([A]_1, [C]_1, [B]_2 \in G_1^2 x G_2\). Accept the proof iff:
[15]:
def vfy(R, tau, a, pi):
alpha, beta, delta, gamma, x = tau
A_1, C_1, B_2 = pi
lhs = R.e(A_1, B_2)
D = R.g @ (reduce(add, [
a[i] * (beta * R.U[i](x) + alpha * R.V[i](x) + R.W[i](x))
for i in range(0, R.l)]) / gamma)
rhs = R.e(R.g @ alpha, R.h @ beta) * \
R.e(D, R.h @ gamma) * \
R.e(C_1, R.h @ delta)
return lhs == rhs
[16]:
vfy(R, tau, a, pi)
[16]:
True
Explain¶
On \(Prov\) phase:
[17]:
A_1, C_1, B_2 = prov(R, tau, sigma, a, r, s)
alpha, beta, delta, gamma, x = tau
[18]:
A_qap, B_qap, C_qap, T_qap, H_qap = qap.proof(x, a)
assert A_qap * B_qap == C_qap + T_qap * H_qap
[19]:
A_qap_l2m, B_qap_l2m, C_qap_l2m, T_qap_l2m, H_qap_l2m = qap.proof(x, a, R.l, len(a))
[20]:
A_qap_02l, B_qap_02l, C_qap_02l, T_qap_02l, H_qap_02l = qap.proof(x, a, 0, R.l)
[21]:
assert A_qap_l2m + A_qap_02l == A_qap
[22]:
assert A_1 == R.g @ (alpha + A_qap + r * delta)
assert B_2 == R.h @ (beta + B_qap + s * delta)
assert C_1 == R.g @ (beta / delta * A_qap_l2m + alpha/delta * B_qap_l2m + \
C_qap_l2m / delta + T_qap * H_qap / delta + \
s * alpha + r * beta + s * A_qap + r * B_qap + s * r * delta)
On Vry phase, for RHS
on LHS
We knows that
so