forked from ethereum/execution-specs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkzg.py
More file actions
179 lines (143 loc) · 4.79 KB
/
Copy pathkzg.py
File metadata and controls
179 lines (143 loc) · 4.79 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
"""
The KZG Implementation
^^^^^^^^^^^^^^^^^^^^^^
"""
from hashlib import sha256
from typing import Tuple
from eth_typing.bls import BLSPubkey, BLSSignature
from ethereum_types.bytes import Bytes32, Bytes48
from ethereum_types.numeric import U256
from py_ecc.bls import G2ProofOfPossession
from py_ecc.bls.g2_primitives import pubkey_to_G1, signature_to_G2
from py_ecc.fields import optimized_bls12_381_FQ, optimized_bls12_381_FQ2
from py_ecc.fields import optimized_bls12_381_FQ12 as FQ12
from py_ecc.optimized_bls12_381 import add, multiply, neg
from py_ecc.optimized_bls12_381.optimized_curve import G1, G2
from py_ecc.optimized_bls12_381.optimized_pairing import (
final_exponentiate,
pairing,
)
from ethereum.utils.hexadecimal import hex_to_bytes
FQ = Tuple[
optimized_bls12_381_FQ, optimized_bls12_381_FQ, optimized_bls12_381_FQ
]
FQ2 = Tuple[
optimized_bls12_381_FQ2, optimized_bls12_381_FQ2, optimized_bls12_381_FQ2
]
class KZGCommitment(Bytes48):
"""KZG commitment to a polynomial."""
pass
class KZGProof(Bytes48):
"""KZG proof"""
pass
class BLSFieldElement(U256):
"""A field element in the BLS12-381 field."""
pass
class VersionedHash(Bytes32):
"""A versioned hash."""
pass
VERSIONED_HASH_VERSION_KZG = hex_to_bytes("0x01")
BYTES_PER_COMMITMENT = 48
BYTES_PER_PROOF = 48
BYTES_PER_FIELD_ELEMENT = 32
G1_POINT_AT_INFINITY = b"\xc0" + b"\x00" * 47
BLS_MODULUS = BLSFieldElement(
52435875175126190479447740508185965837690552500527637822603658699938581184513 # noqa: E501
)
KZG_SETUP_G2_MONOMIAL_1 = "0xb5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2" # noqa: E501
def kzg_commitment_to_versioned_hash(
kzg_commitment: KZGCommitment,
) -> VersionedHash:
"""
Convert a KZG commitment to a versioned hash.
"""
return VersionedHash(
VERSIONED_HASH_VERSION_KZG
+ Bytes32(sha256(kzg_commitment).digest())[1:]
)
def validate_kzg_g1(b: Bytes48) -> None:
"""
Perform BLS validation required by the types `KZGProof`
and `KZGCommitment`.
"""
if b == G1_POINT_AT_INFINITY:
return
assert G2ProofOfPossession.KeyValidate(BLSPubkey(b))
def bytes_to_kzg_commitment(b: Bytes48) -> KZGCommitment:
"""
Convert untrusted bytes into a trusted and validated KZGCommitment.
"""
validate_kzg_g1(b)
return KZGCommitment(b)
def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement:
"""
Convert untrusted bytes to a trusted and validated BLS scalar
field element. This function does not accept inputs greater than
the BLS modulus.
"""
field_element = int.from_bytes(b, "big")
assert field_element < int(BLS_MODULUS)
return BLSFieldElement(field_element)
def bytes_to_kzg_proof(b: Bytes48) -> KZGProof:
"""
Convert untrusted bytes into a trusted and validated KZGProof.
"""
validate_kzg_g1(b)
return KZGProof(b)
def pairing_check(values: Tuple[Tuple[FQ, FQ2], Tuple[FQ, FQ2]]) -> bool:
"""
Check if the pairings are valid.
"""
p_q_1, p_q_2 = values
final_exponentiation = final_exponentiate(
pairing(p_q_1[1], p_q_1[0], final_exponentiate=False)
* pairing(p_q_2[1], p_q_2[0], final_exponentiate=False)
)
return final_exponentiation == FQ12.one()
def verify_kzg_proof(
commitment_bytes: Bytes48,
z_bytes: Bytes32,
y_bytes: Bytes32,
proof_bytes: Bytes48,
) -> bool:
"""
Verify KZG proof that ``p(z) == y`` where ``p(z)``
is the polynomial represented by ``polynomial_kzg``.
Receives inputs as bytes.
Public method.
"""
assert len(commitment_bytes) == BYTES_PER_COMMITMENT
assert len(z_bytes) == BYTES_PER_FIELD_ELEMENT
assert len(y_bytes) == BYTES_PER_FIELD_ELEMENT
assert len(proof_bytes) == BYTES_PER_PROOF
return verify_kzg_proof_impl(
bytes_to_kzg_commitment(commitment_bytes),
bytes_to_bls_field(z_bytes),
bytes_to_bls_field(y_bytes),
bytes_to_kzg_proof(proof_bytes),
)
def verify_kzg_proof_impl(
commitment: KZGCommitment,
z: BLSFieldElement,
y: BLSFieldElement,
proof: KZGProof,
) -> bool:
"""
Verify KZG proof that ``p(z) == y`` where ``p(z)``
is the polynomial represented by ``polynomial_kzg``.
"""
# Verify: P - y = Q * (X - z)
X_minus_z = add(
signature_to_G2(BLSSignature(hex_to_bytes(KZG_SETUP_G2_MONOMIAL_1))),
multiply(G2, int((BLS_MODULUS - z) % BLS_MODULUS)),
)
P_minus_y = add(
pubkey_to_G1(BLSPubkey(commitment)),
multiply(G1, int((BLS_MODULUS - y) % BLS_MODULUS)),
)
return pairing_check(
(
(P_minus_y, neg(G2)),
(pubkey_to_G1(BLSPubkey(proof)), X_minus_z),
)
)