-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathverifier.py
More file actions
203 lines (153 loc) · 7 KB
/
verifier.py
File metadata and controls
203 lines (153 loc) · 7 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from vole import Vole
class Verifier:
"""Verifier in a Vector Oblivious Linear Evaluation (VOLE) based commitment scheme
The verifier maintains the q vector where q[i] = v[i] + Delta * w[i] for a secret
Delta known only to the verifier. The verifier can verify operations on committed
values without learning the actual values.
"""
def __init__(self, vole: "Vole") -> None:
"""Initialize the verifier with a VOLE instance
Args:
vole (Vole): VOLE instance that provides the underlying commitment infrastructure
"""
self.vole = vole
self.field = vole.field
self.vole_length: int = vole.vole_length
self.total_length: int = vole.total_length
self.delta: int = -1
self.q: list[int] = []
# Index for fresh committed values (used by commit and mul)
self.vole_index: int = 0
# Index for temporary values (used by add, sub, etc.)
self.temp_index: int = self.vole_length
vole.initialize_verifier(self)
def set_delta(self, delta: int) -> None:
"""Set the secret Delta value for the verification scheme
Args:
delta (int): secret field element known only to the verifier
"""
self.delta = delta
def set_q(self, q: list[int]) -> None:
"""Set the q vector for the commitment scheme
Args:
q (list[int]): vector of field elements where q[i] = v[i] + Delta * w[i]
"""
self.q = q
def update_q(self, index: int, di: int) -> None:
"""Update q[i] with a correction value from the prover
When the prover commits to a new value, it sends a correction di that allows
the verifier to update q[i] = q[i] + di * Delta without learning the committed value.
Args:
index (int): the index to update
di (int): correction value from the prover
"""
i: int = index
qi: int = self.field.add(self.q[i], self.field.mul(di, self.delta))
self.q[i] = qi
if i == self.vole_index:
self.vole_index += 1
def check_open(self, wi: int, vi: int, index: int) -> bool:
"""Verify that an opened commitment is valid
Checks that q[index] = v[index] + w[index] * Delta by recomputing the
expected q value from the revealed w and v values.
Args:
wi (int): the revealed w value
vi (int): the revealed v value
index (int): the commitment index
Returns:
bool: True if the opening is valid, False otherwise
"""
original_qi: int = self.q[index]
new_qi = self.field.add(vi, self.field.mul(wi, self.delta))
if original_qi == new_qi:
return True
return False
def add(self, index_a: int, index_b: int) -> None:
"""Add two committed values and return the result index
Performs homomorphic addition: q[c] = q[a] + q[b]
This works because addition is linear in the commitment scheme.
Args:
index_a (int): index of the first value
index_b (int): index of the second value
"""
c = self.temp_index
self.temp_index += 1
# q[c] = q[a] + q[b] (addition is linear, no correction needed)
self.q[c] = self.field.add(self.q[index_a], self.q[index_b])
def sub(self, index_a: int, index_b: int) -> None:
"""Subtract two committed values (a - b) and return the result index
Performs homomorphic subtraction: q[c] = q[a] - q[b]
This works because subtraction is linear in the commitment scheme.
Args:
index_a (int): index of the first value (minuend)
index_b (int): index of the second value (subtrahend)
"""
c = self.temp_index
self.temp_index += 1
# q[c] = q[a] - q[b] (subtraction is linear, no correction needed)
self.q[c] = self.field.sub(self.q[index_a], self.q[index_b])
def add_constant(self, index_a: int, constant: int) -> None:
"""Add a public constant to a committed value
This is a linear operation requiring no communication with the prover.
Computes q[c] = q[a] + Delta * constant since:
q[c] = v[c] + Delta * u[c]
= v[a] + Delta * (u[a] + constant)
= v[a] + Delta * u[a] + Delta * constant
= q[a] + Delta * constant
Args:
index_a (int): index of the value to add to
constant (int): public constant to add
"""
c = self.temp_index
self.temp_index += 1
# q[c] = q[a] + Delta * constant
self.q[c] = self.field.add(self.q[index_a], self.field.mul(self.delta, constant))
def scalar_mul(self, index_a: int, scalar: int) -> None:
"""Multiply a committed value by a public constant (scalar)
This is a linear operation requiring no communication with the prover.
Computes q[c] = scalar * q[a] since:
q[c] = v[c] + Delta * u[c]
= scalar * v[a] + Delta * (scalar * u[a])
= scalar * (v[a] + Delta * u[a])
= scalar * q[a]
Args:
index_a (int): index of the value to multiply
scalar (int): public constant to multiply by
"""
c = self.temp_index
self.temp_index += 1
# q[c] = scalar * q[a] (scalar multiplication is linear, no correction needed)
self.q[c] = self.field.mul(scalar, self.q[index_a])
def mul(self, correction: int) -> None:
"""Allocate result index and apply correction for multiplication
Multiplication is not linear, so the prover must send a correction value.
This method updates q[c] using the correction without learning the actual values.
Args:
correction (int): correction value from the prover
"""
c = self.vole_index
self.vole_index += 1
# Apply the correction to q[c]
self.update_q(c, correction)
def check_mul(self, index_a: int, index_b: int, index_c: int, d: int, e: int) -> bool:
"""Verify that a multiplication was performed correctly
Checks that q[a] * q[b] - Delta * q[c] = Delta * d + e
This verifies that w[c] = w[a] * w[b] without the verifier learning the values.
Args:
index_a (int): index of the first value
index_b (int): index of the second value
index_c (int): index of the product
d (int): linear verification component from prover
e (int): quadratic verification component from prover
Returns:
bool: True if the multiplication is valid, False otherwise
"""
delta: int = self.delta
lhs: int = self.field.sub(
self.field.mul(self.q[index_a], self.q[index_b]), self.field.mul(delta, self.q[index_c])
)
b = self.vole.get_random_vole_verifier(delta)
rhs: int = self.field.sub(self.field.add(self.field.mul(d, delta), e), b)
return lhs == rhs