mirror of
https://github.com/AtHeartEngineer/plonkathon.git
synced 2026-01-09 13:07:56 -05:00
124 lines
4.2 KiB
Python
124 lines
4.2 KiB
Python
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
|