arnaucube
arnaucube/mathPublic Self-hosted repository
math/crypto.sage
crypto.sageRaw
  1from hashlib import sha256
  2
  3def hash_two_points(a, b):
  4    h = sha256((str(a)+str(b)).encode('utf-8'))
  5    return int(h.hexdigest(), 16)
  6
  7def generic_verify(g, X, A, c, z):
  8    return g * int(z) == X * int(c) + A
  9
 10###
 11# Sigma protocol interactive
 12###
 13
 14class Prover_interactive(object):
 15    def __init__(self, F, g):
 16        self.F = F # Z_p
 17        self.g = g # elliptic curve generator
 18
 19    def new_key(self):
 20        self.w = self.F.random_element()
 21        X = self.g * int(self.w)
 22        return X
 23
 24    def new_commitment(self):
 25        self.a = self.F.random_element()
 26        A = self.g * int(self.a)
 27        return A
 28
 29    def gen_proof(self, c):
 30        return int(self.a) + int(c) * int(self.w)
 31
 32class Verifier_interactive(object):
 33    def __init__(self, F, g):
 34        self.F = F
 35        self.g = g
 36
 37    def new_challenge(self, A):
 38        self.A = A
 39        self.c = self.F.random_element()
 40        return self.c
 41    
 42    def verify(self, X, z):
 43        return self.g * int(z) == X * int(self.c) + self.A
 44
 45
 46###
 47# Sigma protocol non-interactive
 48###
 49class Prover(object):
 50    def __init__(self, F, g):
 51        self.F = F # Z_p
 52        self.g = g # elliptic curve generator
 53
 54    def new_key(self):
 55        self.w = self.F.random_element()
 56        X = self.g * int(self.w)
 57        return X
 58
 59    def gen_proof(self, X):
 60        a = self.F.random_element()
 61        A = self.g * int(a)
 62        c = hash_two_points(A, X)
 63        z = int(a) + c * int(self.w)
 64        return A, z
 65
 66
 67class Verifier(object):
 68    def __init__(self, F, g):
 69        self.F = F
 70        self.g = g
 71
 72    def verify(self, X, A, z):
 73        c = hash_two_points(A, X)
 74        return self.g * int(z) == X * c + A
 75
 76class Simulator(object):
 77    def __init__(self, F, g):
 78        self.F = F
 79        self.g = g
 80
 81    def simulate(self, X):
 82        c = self.F.random_element()
 83        z = self.F.random_element()
 84        #  A = g * int(z) + X*(-int(c))
 85        A = g * int(z) - X * int(c)
 86        return A, c, z
 87
 88###
 89# OR proof (with 2 parties)
 90###
 91
 92class ORProver_2parties(object):
 93    def __init__(self, F, g):
 94        self.F = F # Z_p
 95        self.g = g # elliptic curve generator
 96
 97    def new_key(self):
 98        self.w = self.F.random_element()
 99        X = self.g * int(self.w)
100        return X
101
102    def gen_commitments(self, xs):
103        # gen commitment A
104        self.a = self.F.random_element()
105        A = self.g * int(self.a)
106
107        # run the simulator for 1-b
108        sim = Simulator(self.F, self.g)
109        A_1, c_1, z_1 = sim.simulate(xs[1])
110
111        self.A_1 = A_1
112        self.c_1 = c_1
113        self.z_1 = z_1
114
115        return [A, A_1]
116
117    def gen_proof(self, s):
118        # split the challenge s = c xor c_1
119        c = int(s) ^^ int(self.c_1)
120        # compute z
121        z = int(self.a) + int(c) * int(self.w)
122        # note, here the order of the returned elements is always the same, in
123        # a real-world implementation would be shuffled
124        return [c, self.c_1], [z, self.z_1]
125
126class ORVerifier_2parties(object):
127    def __init__(self, F, g):
128        self.F = F
129        self.g = g
130
131    def new_challenge(self, As):
132        self.As = As
133        self.s = self.F.random_element()
134        return self.s
135
136    def verify(self, Xs, cs, zs):
137        assert self.s == int(cs[0]) ^^ int(cs[1])
138        assert self.g * int(zs[0]) == Xs[0] * int(cs[0]) + self.As[0]
139        assert self.g * int(zs[1]) == Xs[1] * int(cs[1]) + self.As[1]
140
141###
142# OR proof (with n parties)
143###
144
145class ORProver(object):
146    def __init__(self, F, g):
147        self.F = F # Z_p
148        self.g = g # elliptic curve generator
149
150    def new_key(self):
151        self.w = self.F.random_element()
152        X = self.g * int(self.w)
153        return X
154
155    def gen_commitments(self, xs):
156        # gen commitment A
157        self.a = self.F.random_element()
158        A = self.g * int(self.a)
159        self.As = [A]
160
161
162        # run the simulator for the rest of Xs
163        sim = Simulator(self.F, self.g)
164        self.cs = []
165        self.zs = []
166        for i in range(1, len(xs)):
167            A_1, c_1, z_1 = sim.simulate(xs[i])
168            self.As.append(A_1)
169            self.cs.append(c_1)
170            self.zs.append(z_1)
171
172        return self.As
173
174    def gen_proof(self, s):
175        # split the challenge s = c xor c_1 xor c_2 xor ... xor c_n
176        c = int(s)
177        for i in range(len(self.cs)):
178            c = c ^^ int(self.cs[i])
179
180        self.cs.insert(0, c) # add c at the beginning of cs array
181
182        # compute z
183        z = int(self.a) + int(c) * int(self.w)
184        self.zs.insert(0, z) # add z at the beginning of zs array
185
186        # note, here the order of the returned elements is always the same, in
187        # a real-world implementation would be shuffled
188        return self.cs, self.zs
189
190class ORVerifier(object):
191    def __init__(self, F, g):
192        self.F = F
193        self.g = g
194
195    def new_challenge(self, As):
196        self.As = As
197        self.s = self.F.random_element()
198        return self.s
199
200    def verify(self, Xs, cs, zs):
201        # check s == c_0 xor c_1 xor c_2 xor ... xor c_n
202        computed_s = int(cs[0])
203        for i in range(1, len(cs)):
204            computed_s = computed_s ^^ int(cs[i])
205
206        assert self.s == computed_s
207
208        # check g*z == X*c + A (in multiplicative notation would g^z ==X^c * A)
209        for i in range(len(Xs)):
210            assert self.g * int(zs[i]) == Xs[i] * int(cs[i]) + self.As[i]