forked from 0xPARC/plonkathon
-
Notifications
You must be signed in to change notification settings - Fork 1
/
transcript.py
123 lines (96 loc) · 4.21 KB
/
transcript.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
118
119
120
121
122
123
from utils import Scalar
from curve import G1Point
from merlin import MerlinTranscript
from py_ecc.secp256k1.secp256k1 import bytes_to_int
from dataclasses import dataclass
@dataclass
class Message1:
# [a(x)]₁ (commitment to left wire polynomial)
a_1: G1Point
# [b(x)]₁ (commitment to right wire polynomial)
b_1: G1Point
# [c(x)]₁ (commitment to output wire polynomial)
c_1: G1Point
@dataclass
class Message2:
# [z(x)]₁ (commitment to permutation polynomial)
z_1: G1Point
@dataclass
class Message3:
# [t_lo(x)]₁ (commitment to t_lo(X), the low chunk of the quotient polynomial t(X))
t_lo_1: G1Point
# [t_mid(x)]₁ (commitment to t_mid(X), the middle chunk of the quotient polynomial t(X))
t_mid_1: G1Point
# [t_hi(x)]₁ (commitment to t_hi(X), the high chunk of the quotient polynomial t(X))
t_hi_1: G1Point
@dataclass
class Message4:
# Evaluation of a(X) at evaluation challenge ζ
a_eval: Scalar
# Evaluation of b(X) at evaluation challenge ζ
b_eval: Scalar
# Evaluation of c(X) at evaluation challenge ζ
c_eval: Scalar
# Evaluation of the first permutation polynomial S_σ1(X) at evaluation challenge ζ
s1_eval: Scalar
# Evaluation of the second permutation polynomial S_σ2(X) at evaluation challenge ζ
s2_eval: Scalar
# Evaluation of the shifted permutation polynomial z(X) at the shifted evaluation challenge ζω
z_shifted_eval: Scalar
@dataclass
class Message5:
# [W_ζ(X)]₁ (commitment to the opening proof polynomial)
W_z_1: G1Point
# [W_ζω(X)]₁ (commitment to the opening proof polynomial)
W_zw_1: G1Point
class Transcript(MerlinTranscript):
def append(self, label: bytes, item: bytes) -> None:
self.append_message(label, item)
def append_scalar(self, label: bytes, item: Scalar):
self.append_message(label, item.n.to_bytes(32, "big"))
def append_point(self, label: bytes, item: G1Point):
self.append_message(label, item[0].n.to_bytes(32, "big"))
self.append_message(label, item[1].n.to_bytes(32, "big"))
def get_and_append_challenge(self, label: bytes) -> Scalar:
while True:
challenge_bytes = self.challenge_bytes(label, 255)
f = Scalar(bytes_to_int(challenge_bytes))
if f != Scalar.zero(): # Enforce challenge != 0
self.append(label, challenge_bytes)
return f
def round_1(self, message: Message1) -> tuple[Scalar, Scalar]:
self.append_point(b"a_1", message.a_1)
self.append_point(b"b_1", message.b_1)
self.append_point(b"c_1", message.c_1)
# The first two Fiat-Shamir challenges
beta = self.get_and_append_challenge(b"beta")
gamma = self.get_and_append_challenge(b"gamma")
return beta, gamma
def round_2(self, message: Message2) -> tuple[Scalar, Scalar]:
self.append_point(b"z_1", message.z_1)
alpha = self.get_and_append_challenge(b"alpha")
# This value could be anything, it just needs to be unpredictable. Lets us
# have evaluation forms at cosets to avoid zero evaluations, so we can
# divide polys without the 0/0 issue
fft_cofactor = self.get_and_append_challenge(b"fft_cofactor")
return alpha, fft_cofactor
def round_3(self, message: Message3) -> Scalar:
self.append_point(b"t_lo_1", message.t_lo_1)
self.append_point(b"t_mid_1", message.t_mid_1)
self.append_point(b"t_hi_1", message.t_hi_1)
zeta = self.get_and_append_challenge(b"zeta")
return zeta
def round_4(self, message: Message4) -> Scalar:
self.append_scalar(b"a_eval", message.a_eval)
self.append_scalar(b"b_eval", message.b_eval)
self.append_scalar(b"c_eval", message.c_eval)
self.append_scalar(b"s1_eval", message.s1_eval)
self.append_scalar(b"s2_eval", message.s2_eval)
self.append_scalar(b"z_shifted_eval", message.z_shifted_eval)
v = self.get_and_append_challenge(b"v")
return v
def round_5(self, message: Message5) -> Scalar:
self.append_point(b"W_z_1", message.W_z_1)
self.append_point(b"W_zw_1", message.W_zw_1)
u = self.get_and_append_challenge(b"u")
return u