POD-Mini and POD-AS¶
I Intro¶
[1]:
%load_ext autoreload
%autoreload 2
This is a Python implementaton of Pod-Mini of zkPod via klefki, for more details, just check the technial Paper.
[2]:
from klefki.types.algebra.concrete import (
EllipticCurveGroupSecp256k1 as ECG,
EllipticCurveCyclicSubgroupSecp256k1 as CG,
FiniteFieldSecp256k1 as F,
FiniteFieldCyclicSecp256k1 as CF
)
from operator import add
G = CG.G
[3]:
import random
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
random_f = lambda: CF(random.randint(1, N) % CF.P)
q = random_f()
H = G @ q
[4]:
from hashlib import sha256
hash = lambda x, y: CF(int(sha256(str(x.value + y).encode()).hexdigest(), 16) % N)
hash2 = lambda x, y, z: CF(int(sha256(str(x.value + y + z).encode()).hexdigest(), 16) % N)
II POD-Mini¶
Initializer Phase¶
[5]:
data = 123456789
tag = 6
[6]:
m = CF(data)
o = CF(tag)
[7]:
sigma = G @ m + H @ o
Deliver Phase¶
[8]:
k_w = random_f()
k = hash(k_w, 1)
k_ = hash(k_w, 2)
k0 = hash(k_w, 3)
k0_ = hash(k_w, 4)
[9]:
K = G @ k + H @ k_
K0 = G @ k0 + H @ k0_
(K, K0)
[9]:
(EllipticCurveGroupSecp256k1::(FiniteFieldSecp256k1::60833088545442599426394672598201640952972051730298604958359191447690851122096, FiniteFieldSecp256k1::48051097886287326595482477027746542056422212554885787335326880757550380565553),
EllipticCurveGroupSecp256k1::(FiniteFieldSecp256k1::109757020878345036275695788298328814894135468587935766610813179219963914817284, FiniteFieldSecp256k1::3503186752654184182707842700539194665709151565486434874163610016019483430925))
\(S \rightarrow R\): \((K, K_0)\)
[10]:
c = random_f()
\(R \rightarrow S\): \(c\)
[11]:
m_ = k + c * m
o_ = k_ + c * o
z = k0 + c * k
z_ = k0_ + c * k_
(m_, o_, z, z_)
[11]:
(FiniteFieldCyclicSecp256k1::4188847662850428514190277999937279562610735694457763843035367735100439750049,
FiniteFieldCyclicSecp256k1::113829453438446661247390864254644542435892738603979657221855887955677525600276,
FiniteFieldCyclicSecp256k1::108203930121791436016800137198409918309056563447049654576428359618878344960306,
FiniteFieldCyclicSecp256k1::83764309071589516840408152095024667788508464591543119082668639417611269829753)
\(S \rightarrow R: (\bar{m}, \bar{o}, z, z')\)
R should verify that:
[12]:
assert sigma @ c + K == G @ m_ + H @ o_
[13]:
assert K0 + (K @ c) == G @ z + H @ z_
Reveal-phase¶
\(R \rightarrow J: \rho\)
\(S \rightarrow J: k_{\omega}\)
[14]:
assert z == hash(k_w, 3) + c @ hash(k_w, 1)
[15]:
assert m == (m_ - hash(k_w, 1)) / c
[16]:
(m_ - hash(k_w, 1)) / c
[16]:
FiniteFieldCyclicSecp256k1::123456789
POD-AS¶
[17]:
from IPython.display import Image
[18]:
f = Image("lena-mini.jpg")
Init Phase¶
In the init-phase, the data file is splitted into a block matrix of \(n × s\) . Each row of the matrix is called a \(block\), which consists of \(s\) slices. The initializer adds one additional column of random slices \(m_{0i}\) to the matrix for padding. The slices of \(m_{0i}\) are used for blind factors as o in PoD-Mini.
[19]:
import numpy as np
[20]:
Image(f.data)
[20]:
[21]:
M = np.array(list(map(CF, f.data))).reshape(-1, 5)
[22]:
M.shape
[22]:
(205, 5)
[23]:
w, h = M.shape
[24]:
Pad = np.matrix([random_f() for _ in range(0, h)])
[25]:
Pm = np.concatenate((Pad.T, M.T), axis=1).T.tolist()
[26]:
n, s = np.matrix(Pm).shape
[27]:
np.matrix(Pm).shape
[27]:
(206, 5)
The initializer needs to generate \(s + 1\) group elements randomly.
[28]:
U = [G @ random_f() for _ in range(0, s)]
[29]:
from functools import reduce
def v_multi(g: [ECG], a: [CF]) -> [ECG]:
return reduce(lambda x,y: x+y,
list(map(lambda a: a[0] @ a[1], zip(g, a))))
[30]:
sigma = [v_multi(U, Pm[i]) for i in range(0, n)]
Deliver Phase¶
[31]:
kw = random_f()
[32]:
k = [[hash2(kw, i, j) for j in range(0, s+1)] for i in range(0, n+1)]
[33]:
assert np.matrix(k).shape == (n + 1, s + 1)
The topmost row \(k_{0j}\) is for hiding keys in the same column, the leftmost \(k_{i0}\) is for encrypting padding slices.
Then \(S\) constructs commitments \(K\) i to \(i\)-th row of keys, including the leftmost key \(k_{i0}\) on each row.
[34]:
K = [reduce(add, [U[j]@k[i][j] for j in range(0, s)]) for i in range(0, n)]
\(S \rightarrow R: \mathbf{K}_[0, n]\)
\(R \rightarrow S: c\)
[35]:
c = random_f()
[36]:
M_ = [[k[i][j] + Pm[i][j]*(c**i) for j in range(0, s)] for i in range(1, n)]
[37]:
np.matrix(M_).shape == (n - 1, s)
[37]:
True
[38]:
z = [reduce(add, [k[i][j] * c**i for i in range(0, n)]) for j in range(0, s)]
\(S \rightarrow R: \bar{m}_{[1,n][0,s]}, z_{[0,s]}\)
[39]:
assert reduce(add, [sigma[i] @ CF(c ** i) + K[i] for i in range(1, n)]) == \
reduce(add, [v_multi(U, M_[i]) for i in range(0, n - 1)])
[40]:
assert reduce(add, [K[i] @ CF(c ** i) for i in range(0, n)]) == \
reduce(add, [U[j] @ z[j] for j in range (0, s)])
If \(R\) accepts the keys and data, he has to submit a delivery receipt to \(J\) \((\mathbf{z},c)\), where \(\mathbf{z}\) is the aggregation of \(z_{[0,s]}\) :
\(R \rightarrow J: \rho(\mathbf{z}, c)\)
[41]:
Z = reduce(add, z)
[42]:
assert (Z, c) == (reduce(add, z), c)
\(f \rightarrow R: k_{\omega}\)
[43]:
Data = [[(M_[i][j] - k[i+1][j])/(c**(i+1)) for j in range(0, s)] for i in range(0, n-1)]
[44]:
assert Data == Pm[1:]
[45]:
Image(reduce(add, (map(lambda x: bytes([x.value]), reduce(add, Data)))))
[45]: