एक inner product argument यह proof है कि prover ने inner product computation को सही ढंग से किया है। यह अध्याय (chapter) दिखाता है कि inner product argument के लिए zero knowledge proof कैसे बनाया जाए।
पिछले अध्याय में, हमने दिखाया था कि दो scalars को zero knowledge तरीके से एक साथ कैसे multiply किया जाए: हम दो degree-one polynomials के लिए commit करते हैं, और साबित करते हैं कि हमने उनके product की सही गणना की है, और फिर दिखाते हैं कि degree one polynomials के constant term उन secret factors के commitments हैं जिन्हें हम multiply कर रहे हैं।
यदि हमारे polynomial के coefficients scalars के बजाय vectors हैं, तो हम यह साबित कर सकते हैं कि हमने vector के inner product की सही गणना की है। अब हम vector polynomial को पेश करते हैं।
Vector polynomials: vectors वाले polynomials बतौर coefficients
नीचे दिए गए दो polynomials हैं जिनमें vector coefficients हैं:
एक vector polynomial को evaluate करने पर एक और vector प्राप्त होता है। उदाहरण के लिए, उत्पन्न करता है:
और 2 पर को evaluate करने पर प्राप्त होता है:
और को bold में लिखा गया है क्योंकि जब उन्हें किसी scalar पर evaluate किया जाता है, तो वे vectors उत्पन्न करते हैं।
Vector polynomials को multiply करना
Vector polynomials को scalar polynomials की तरह एक साथ multiply किया जा सकता है। उदाहरण के लिए, और को multiply करने पर प्राप्त होता है:
जब हम प्रत्येक vectors को एक साथ multiply करते हैं, तो हम Hadamard product (element-wise product, जिसे से दर्शाया जाता है) लेते हैं।
ध्यान दें कि यदि हम परिणामी vector polynomial में डालते हैं, तो हमें निम्नलिखित प्राप्त होता है:
यह उसी के समान है जैसे कि हम गणना करें:
दूसरे शब्दों में, दो vector polynomials को एक साथ multiply करना और फिर किसी बिंदु पर product को evaluate करना, vector polynomials को अलग-अलग evaluate करने और फिर परिणामी vectors पर Hadamard product लेने के समान है।
Vector polynomials का inner product
दो vector polynomials के inner product की गणना करने के लिए, हम उन्हें ऊपर बताए अनुसार एक साथ multiply करते हैं, लेकिन फिर vector entries को जोड़ते हैं ताकि परिणाम एक scalar बन जाए। हम इस operation को के रूप में दर्शाते हैं। Hadamard product का उपयोग करने के बजाय vector coefficients को multiply करते समय inner product का उपयोग करके हम यही चीज़ प्राप्त कर सकते हैं।
ऊपर दिए गए दो उदाहरण polynomials के लिए, यह होगा:
ध्यान दें कि बिल्कुल पर evaluate किए गए के समान है। यानी, और ।
सामान्य रूप से यह क्यों काम करता है
मान लीजिए कि हमने vector polynomials को “सामान्य” तरीके से एक साथ multiply किया – यानी हम inner product के बजाय coefficients का elementwise-product (Hadamard product) लेते हैं। प्रत्येक coefficients का inner product बस प्रत्येक coefficients के Hadamard product के terms का योग (sum) होता है।
इसलिए, हम कह सकते हैं कि यदि हमारे पास दो vector polynomials और हैं, और हम उन्हें के रूप में एक साथ multiply करते हैं, तो का inner product, के coefficients के element-wise योग के बराबर होता है। ध्यान दें कि दो vector polynomials के multiplication से एक vector polynomial प्राप्त होता है, लेकिन दो vector polynomials के inner product से एक ऐसा polynomial प्राप्त होता है जहाँ सभी coefficients scalars होते हैं।
Zero knowledge inner product proof
Zero knowledge multiplication पर पिछले अध्याय में, हमने यह प्रदर्शित किया था कि हमारे पास एक वैध multiplication है, यह साबित करके कि दो linear polynomials के constant terms का product, उन polynomials के product में constant term के बराबर होता है।
Inner product की सही गणना को साबित करने के लिए, हम polynomials को vector polynomials से बदल देते हैं और हम scalar polynomials के multiplication को vector polynomials के inner product से बदल देते हैं।
बाकी सब कुछ समान रहता है।
Algorithm
लक्ष्य यह है कि prover, verifier को यह विश्वास दिलाए कि , और का commitment है, , का commitment है, और यह कि है, बिना , , या को प्रकट किए।
Setup
Prover और verifier इस पर सहमत होते हैं:
- basis vectors और जिनके साथ prover vectors को commit कर सकता है
- elliptic curve point ( से अलग) जिसका उपयोग के coefficients और में commit किए गए inner product को commit करने के लिए किया जाएगा
- blinding terms के लिए elliptic curve point
Prover
Prover blinding terms , , , , और जनरेट करता है और गणना करता है:
ध्यान दें कि इस बार linear coefficients और scalars के बजाय vectors हैं। Prover को verifier के पास भेजता है। Verifier द्वारा एक random के साथ प्रतिक्रिया देने के बाद, prover पर , , और उनके inner product को evaluate करता है।
अंतिम verification चरण
सबसे पहले, verifier जाँचता है कि , पर evaluate किए गए और का inner product है।
यदि prover ईमानदार है तो यह सही होना चाहिए, क्योंकि पर evaluate किए गए polynomials का inner product, पर evaluate किए गए vector polynomials और के inner product के समान होता है।
दूसरा, verifier जाँचता है कि और क्रमशः और के constant और linear terms के commitments हैं।
याद करें कि और क्रमशः और के constant और linear terms के commitments हैं और क्रमशः और में blinding terms और का योग है।
अंत में, verifier जाँचता है कि , पर commit किए गए quadratic polynomial का evaluation है:
Proof size में सुधार करना
जब prover भेजता है, तो prover elements (जो और की लंबाई है) भेजता है जो कि succinct नहीं है।
आने वाले अध्यायों में हम सीखेंगे कि proof के size को कैसे कम किया जाए। size का एक proof बनाना संभव है जो यह बताए कि एक inner product सही है। यानी, यदि हम यह साबित करना चाहते हैं कि हमने लंबाई के दो vectors के inner product की गणना की है, तो proof का size केवल होगा – जो exponentially छोटा है।
विशेष रूप से, हम वास्तविक vectors के बजाय और के लिए एक commitment भेजकर और चरण को optimize करेंगे, साथ ही यह दिखाने के लिए एक logarithmic size proof भेजेंगे कि commitment उन vectors को होल्ड करता है जिनका inner product है।
सारांश
हमने एक protocol का वर्णन किया है जो यह साबित करता है कि , और का commitment है, , का commitment है, और यह कि है, बिना , , या को प्रकट किए। हालाँकि, proof का size linear है, क्योंकि में और प्रत्येक का size है।
Exercise: इस lecture में algorithm को implement करने के लिए missing code भरें। यह साबित करें कि आप एक vector के inner product को उसे प्रकट किए बिना जानते हैं। ध्यान दें कि numpy arrays element-wise addition और multiplication की अनुमति देते हैं। उदाहरण के लिए:
import numpy as np
a = np.array([1,2,3,4])
b = np.array([2,2,2,2])
print(a + b) # np.array([3,4,5,6])
print(a * b) # np.array([2,4,6,8])
print(numpy.inner(a, b)) # 20
# casting a numpy array to numpy doesn't do anything
print(np.array(a) + b) # np.array([3,4,5,6])
निम्नलिखित code भरें:
from py_ecc.bn128 import G1, multiply, add, FQ, eq, Z1
from py_ecc.bn128 import curve_order as p
import numpy as np
from functools import reduce
import random
def random_element():
return random.randint(0, p)
def add_points(*points):
return reduce(add, points, Z1)
# if points = G1, G2, G3, G4 and scalars = a,b,c,d vector_commit returns
# aG1 + bG2 + cG3 + dG4
def vector_commit(points, scalars):
return reduce(add, [multiply(P, i) for P, i in zip(points, scalars)], Z1)
# these EC points have unknown discrete logs:
G = [(FQ(6286155310766333871795042970372566906087502116590250812133967451320632869759), FQ(2167390362195738854837661032213065766665495464946848931705307210578191331138)),
(FQ(6981010364086016896956769942642952706715308592529989685498391604818592148727), FQ(8391728260743032188974275148610213338920590040698592463908691408719331517047)),
(FQ(15884001095869889564203381122824453959747209506336645297496580404216889561240), FQ(14397810633193722880623034635043699457129665948506123809325193598213289127838)),
(FQ(6756792584920245352684519836070422133746350830019496743562729072905353421352), FQ(3439606165356845334365677247963536173939840949797525638557303009070611741415))]
H = [(FQ(13728162449721098615672844430261112538072166300311022796820929618959450231493), FQ(12153831869428634344429877091952509453770659237731690203490954547715195222919)),
(FQ(17471368056527239558513938898018115153923978020864896155502359766132274520000), FQ(4119036649831316606545646423655922855925839689145200049841234351186746829602)),
(FQ(8730867317615040501447514540731627986093652356953339319572790273814347116534), FQ(14893717982647482203420298569283769907955720318948910457352917488298566832491)),
(FQ(419294495583131907906527833396935901898733653748716080944177732964425683442), FQ(14467906227467164575975695599962977164932514254303603096093942297417329342836))]
B = (FQ(12848606535045587128788889317230751518392478691112375569775390095112330602489), FQ(18818936887558347291494629972517132071247847502517774285883500818572856935411))
# scalar multiplication example: multiply(G, 42)
# EC addition example: add(multiply(G, 42), multiply(G, 100))
# remember to do all arithmetic modulo p
def commit(a, sL, b, sR, alpha, beta, gamma, tau_1, tau_2):
pass
# return (A, S, V, T1, T2)
def evaluate(f_0, f_1, f_2, u):
return (f_0 + f_1 * u + f_2 * u**2) % p
def prove(blinding_0, blinding_1, blinding_2, u):
# fill this in
# return pi
pass
## step 0: Prover and verifier agree on G and B
## step 1: Prover creates the commitments
a = np.array([89,15,90,22])
b = np.array([16,18,54,12])
sL = ...
sR = ...
t1 = ...
t2 = ...
### blinding terms
alpha = ...
beta = ...
gamma = ...
tau_1 = ...
tau_2 = ...
A, S, V, T1, T2 = commit(a, sL, b, sR, alpha, beta, gamma, tau_1, tau_2)
## step 2: Verifier picks u
u = ...
## step 3: Prover evaluates l(u), r(u), t(u) and creates evaluation proofs
l_u = evaluate(a, sL, 0, u)
r_u = evaluate(b, sR, 0, u)
t_u = evaluate(np.inner(a, b), t1, t2, u)
pi_lr = prove(alpha, beta, 0, u)
pi_t = prove(gamma, tau_1, tau_2, u)
## step 4: Verifier accepts or rejects
assert t_u == np.mod(np.inner(np.array(l_u), np.array(r_u)), p), "tu !=〈lu, ru〉"
assert eq(add(A, commit(S, u)), add_points(vector_commit(G, l_u), vector_commit(H, r_u), multiply(B, pi_lr))), "l_u or r_u not evaluated correctly"
assert eq(add(multiply(G, t_u), multiply(B, pi_t)), add_points(V, multiply(T1, u), multiply(T2, u**2 % p))), "t_u not evaluated correctly"
यह ट्यूटोरियल ZK Bulletproofs पर एक सीरीज़ का हिस्सा है।