-
Notifications
You must be signed in to change notification settings - Fork 8
/
single_mult.py
117 lines (93 loc) · 3.65 KB
/
single_mult.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python3
# WARNING: This implementation may contain bugs and has not been audited.
# It is only for educational purposes. DO NOT use it in production.
from pypcs.curve import Fp, Fr, ec_mul, G1Point
import random
from pedersen import PedersenCommitment
cms = PedersenCommitment.setup(20)
# Implement a single multiplication argument (∑-protocol)
#
# The scheme is from Section 5.3 of [BG12]:
# - Efficient Zero-Knowledge Argument for Correctness of a Shuffle.
# - Stephanie Bayer and Jens Groth:
# - http://www.cs.ucl.ac.uk/staff/J.Groth/MinimalShuffle.pdf
#
class Prover:
a: Fr
b: Fr
c: Fr
A: G1Point
B: G1Point
C: G1Point
def __init__(self, a: Fr, b: Fr, c: Fr):
self.a = a
self.b = b
self.c = c
self.rnd_gen = random.Random("schnorr-prover")
self.a_blinder = Fr.rand(self.rnd_gen)
self.b_blinder = Fr.rand(self.rnd_gen)
self.c_blinder = Fr.rand(self.rnd_gen)
self.A = cms.commit_with_blinder([a], self.a_blinder)
self.B = cms.commit_with_blinder([b], self.b_blinder)
self.C = cms.commit_with_blinder([c], self.c_blinder)
def round1(self) -> tuple[G1Point, G1Point, G1Point]:
ra = Fr.rand(self.rnd_gen)
ra_r = Fr.rand(self.rnd_gen)
rb = Fr.rand(self.rnd_gen)
rb_r = Fr.rand(self.rnd_gen)
rt = Fr.rand(self.rnd_gen)
Ra = cms.commit_with_blinder([ra], ra_r)
Rb = cms.commit_with_blinder([rb], rb_r)
Rt = ec_mul(self.B, ra) + cms.commit_with_blinder([Fr.zero()], -rt)
self.r = (ra, rb, rt, ra_r, rb_r)
return (Ra, Rb, Rt)
def round3(self, e: Fr) -> tuple[Fr, Fr, Fr, Fr, Fr]:
za = self.r[0] + e * self.a
zb = self.r[1] + e * self.b
za_r = self.r[3] + e * self.a_blinder
zb_r = self.r[4] + e * self.b_blinder
zt_r = self.r[2] + e * (self.a * self.b_blinder - self.c_blinder)
return (za, zb, za_r, zb_r, zt_r)
class Verifier:
pk: G1Point
rnd_gen: random.Random
def __init__(self, A: G1Point, B: G1Point, C: G1Point):
self.A = A
self.B = B
self.C = C
self.rnd_gen = random.Random("schnorr-verifier")
def round2(self, R: tuple[G1Point, G1Point, G1Point]) -> Fr:
e = Fr.rand(self.rnd_gen)
return e
def verify(self, R: tuple[G1Point, G1Point, G1Point], e: Fr, zs: tuple[Fr, Fr, Fr, Fr, Fr]) -> bool:
Ra = R[0]
Rb = R[1]
Rt = R[2]
cond0 = cms.commit_with_blinder([zs[0]], zs[2]) == ec_mul(self.A, e) + Ra
cond1 = cms.commit_with_blinder([zs[1]], zs[3]) == ec_mul(self.B, e) + Rb
cond2 = ec_mul(self.B, zs[0]) == ec_mul(self.C, e) + Rt + cms.commit_with_blinder([Fr.zero()], zs[4])
print(f"cond0: {cond0}")
print(f"cond1: {cond1}")
print(f"cond2: {cond2}")
return cond0 and cond1 and cond2
def run_schnorr(prover: Prover, verifier: Verifier) -> bool:
R = prover.round1()
c = verifier.round2(R)
z = prover.round3(c)
return verifier.verify(R, c, z)
def simulate(prover_pk: G1Point, verifier: Verifier) -> Fr:
raise NotImplementedError("Not implemented")
def extract(prover: Prover) -> Fr:
raise NotImplementedError("Not implemented")
if __name__ == "__main__":
a = Fr(4)
b = Fr(5)
c = Fr(20)
prover = Prover(a, b, c)
verifier = Verifier(prover.A, prover.B, prover.C)
print(f"Fr(2)={Fr(2)}")
print(f"Fr(-2)={Fr(-2)}")
print(f"protocol? : {run_schnorr(prover, verifier)}")
# TODO: implement simulator and extractor
# print(f"simulator? : {simulate(prover.pk, verifier)}")
# print(f"extractor? : {extract(Prover(sk))}")