Skip to content

Commit 0de9f33

Browse files
committed
chore(tests): update G1/add G2 msm discount tables ethereum/EIPs#9116
1 parent c1efe8a commit 0de9f33

File tree

5 files changed

+77
-43
lines changed

5 files changed

+77
-43
lines changed

tests/prague/eip2537_bls_12_381_precompiles/msm_discount_table.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/prague/eip2537_bls_12_381_precompiles/spec.py

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
"""
22
Defines EIP-2537 specification constants and functions.
33
"""
4-
import json
54
from dataclasses import dataclass
6-
from typing import Callable, List, Sized, SupportsBytes, Tuple
7-
8-
from .helpers import current_python_script_directory
5+
from enum import Enum, auto
6+
from typing import Callable, Sized, SupportsBytes, Tuple
97

108

119
@dataclass(frozen=True)
@@ -109,11 +107,6 @@ def __bytes__(self) -> bytes:
109107
return self.x.to_bytes(32, byteorder="big")
110108

111109

112-
with open(current_python_script_directory("msm_discount_table.json")) as f:
113-
MSM_DISCOUNT_TABLE: List[int] = json.load(f)
114-
assert type(MSM_DISCOUNT_TABLE) is list
115-
116-
117110
@dataclass(frozen=True)
118111
class Spec:
119112
"""
@@ -149,7 +142,30 @@ class Spec:
149142
P = (X - 1) ** 2 * Q // 3 + X
150143
LEN_PER_PAIR = len(PointG1() + PointG2())
151144
MSM_MULTIPLIER = 1_000
152-
MSM_DISCOUNT_TABLE = MSM_DISCOUNT_TABLE
145+
# fmt: off
146+
G1MSM_DISCOUNT_TABLE = [
147+
0,
148+
1000, 949, 848, 797, 764, 750, 738, 728, 719, 712, 705, 698, 692, 687, 682, 677, 673, 669,
149+
665, 661, 658, 654, 651, 648, 645, 642, 640, 637, 635, 632, 630, 627, 625, 623, 621, 619,
150+
617, 615, 613, 611, 609, 608, 606, 604, 603, 601, 599, 598, 596, 595, 593, 592, 591, 589,
151+
588, 586, 585, 584, 582, 581, 580, 579, 577, 576, 575, 574, 573, 572, 570, 569, 568, 567,
152+
566, 565, 564, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549,
153+
548, 547, 547, 546, 545, 544, 543, 542, 541, 540, 540, 539, 538, 537, 536, 536, 535, 534,
154+
533, 532, 532, 531, 530, 529, 528, 528, 527, 526, 525, 525, 524, 523, 522, 522, 521, 520,
155+
520, 519
156+
]
157+
G2MSM_DISCOUNT_TABLE = [
158+
0,
159+
1000, 1000, 923, 884, 855, 832, 812, 796, 782, 770, 759, 749, 740, 732, 724, 717, 711, 704,
160+
699, 693, 688, 683, 679, 674, 670, 666, 663, 659, 655, 652, 649, 646, 643, 640, 637, 634,
161+
632, 629, 627, 624, 622, 620, 618, 615, 613, 611, 609, 607, 606, 604, 602, 600, 598, 597,
162+
595, 593, 592, 590, 589, 587, 586, 584, 583, 582, 580, 579, 578, 576, 575, 574, 573, 571,
163+
570, 569, 568, 567, 566, 565, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552,
164+
552, 551, 550, 549, 548, 547, 546, 545, 545, 544, 543, 542, 541, 541, 540, 539, 538, 537,
165+
537, 536, 535, 535, 534, 533, 532, 532, 531, 530, 530, 529, 528, 528, 527, 526, 526, 525,
166+
524, 524
167+
]
168+
# fmt: on
153169

154170
# Test constants (from https://github.com/ethereum/bls12-381-tests/tree/eip-2537)
155171
P1 = PointG1( # random point in G1
@@ -217,17 +233,34 @@ class Spec:
217233
INVALID = b""
218234

219235

220-
def msm_discount(k: int) -> int:
236+
class BLS12Group(Enum):
221237
"""
222-
Returns the discount for the G1MSM and G2MSM precompiles.
238+
Helper enum to specify the BLS12 group in discount table helpers.
223239
"""
224-
return Spec.MSM_DISCOUNT_TABLE[min(k, 128)]
225240

241+
G1 = auto()
242+
G2 = auto()
226243

227-
def msm_gas_func_gen(len_per_pair: int, multiplication_cost: int) -> Callable[[int], int]:
244+
245+
def msm_discount(group: BLS12Group, k: int) -> int:
246+
"""
247+
Returns the discount for the G1MSM and G2MSM precompiles.
248+
"""
249+
assert k >= 1, "k must be greater than or equal to 1"
250+
match group:
251+
case BLS12Group.G1:
252+
return Spec.G1MSM_DISCOUNT_TABLE[min(k, 128)]
253+
case BLS12Group.G2:
254+
return Spec.G2MSM_DISCOUNT_TABLE[min(k, 128)]
255+
case _:
256+
raise ValueError(f"Unsupported group: {group}")
257+
258+
259+
def msm_gas_func_gen(
260+
group: BLS12Group, len_per_pair: int, multiplication_cost: int
261+
) -> Callable[[int], int]:
228262
"""
229-
Generates a function that calculates the gas cost for the G1MSM and G2MSM
230-
precompiles.
263+
Generate a function that calculates the gas cost for the G1MSM and G2MSM precompiles.
231264
"""
232265

233266
def msm_gas(input_length: int) -> int:
@@ -238,7 +271,7 @@ def msm_gas(input_length: int) -> int:
238271
if k == 0:
239272
return 0
240273

241-
gas_cost = k * multiplication_cost * msm_discount(k) // Spec.MSM_MULTIPLIER
274+
gas_cost = k * multiplication_cost * msm_discount(group, k) // Spec.MSM_MULTIPLIER
242275

243276
return gas_cost
244277

@@ -256,10 +289,10 @@ def pairing_gas(input_length: int) -> int:
256289
GAS_CALCULATION_FUNCTION_MAP = {
257290
Spec.G1ADD: lambda _: Spec.G1ADD_GAS,
258291
Spec.G1MUL: lambda _: Spec.G1MUL_GAS,
259-
Spec.G1MSM: msm_gas_func_gen(len(PointG1() + Scalar()), Spec.G1MUL_GAS),
292+
Spec.G1MSM: msm_gas_func_gen(BLS12Group.G1, len(PointG1() + Scalar()), Spec.G1MUL_GAS),
260293
Spec.G2ADD: lambda _: Spec.G2ADD_GAS,
261294
Spec.G2MUL: lambda _: Spec.G2MUL_GAS,
262-
Spec.G2MSM: msm_gas_func_gen(len(PointG2() + Scalar()), Spec.G2MUL_GAS),
295+
Spec.G2MSM: msm_gas_func_gen(BLS12Group.G2, len(PointG2() + Scalar()), Spec.G2MUL_GAS),
263296
Spec.PAIRING: pairing_gas,
264297
Spec.MAP_FP_TO_G1: lambda _: Spec.MAP_FP_TO_G1_GAS,
265298
Spec.MAP_FP2_TO_G2: lambda _: Spec.MAP_FP2_TO_G2_GAS,

tests/prague/eip2537_bls_12_381_precompiles/test_bls12_g1msm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
vectors_from_file("multiexp_G1_bls.json")
2727
+ [
2828
pytest.param(
29-
(Spec.P1 + Scalar(Spec.Q)) * (len(Spec.MSM_DISCOUNT_TABLE) - 1),
29+
(Spec.P1 + Scalar(Spec.Q)) * (len(Spec.G1MSM_DISCOUNT_TABLE) - 1),
3030
Spec.INF_G1,
3131
id="max_discount",
3232
),
3333
pytest.param(
34-
(Spec.P1 + Scalar(Spec.Q)) * len(Spec.MSM_DISCOUNT_TABLE),
34+
(Spec.P1 + Scalar(Spec.Q)) * len(Spec.G1MSM_DISCOUNT_TABLE),
3535
Spec.INF_G1,
3636
id="max_discount_plus_1",
3737
),

tests/prague/eip2537_bls_12_381_precompiles/test_bls12_variable_length_input_contracts.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,16 @@ def call_contract_code(
101101
"precompile_gas_list,precompile_data_length_list",
102102
[
103103
pytest.param(
104-
[G1_GAS(i * G1_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
105-
[i * G1_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
104+
[G1_GAS(i * G1_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))],
105+
[i * G1_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))],
106106
id="exact_gas_full_discount_table",
107107
),
108108
pytest.param(
109109
[
110110
G1_GAS(i * G1_MSM_K_INPUT_LENGTH) + 1
111-
for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))
111+
for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))
112112
],
113-
[i * G1_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
113+
[i * G1_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))],
114114
id="one_extra_gas_full_discount_table",
115115
),
116116
],
@@ -149,9 +149,9 @@ def test_valid_gas_g1msm(
149149
pytest.param(
150150
[
151151
G1_GAS(i * G1_MSM_K_INPUT_LENGTH) - 1
152-
for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))
152+
for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))
153153
],
154-
[i * G1_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
154+
[i * G1_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))],
155155
id="insufficient_gas_full_discount_table",
156156
),
157157
],
@@ -188,13 +188,13 @@ def test_invalid_gas_g1msm(
188188
id="zero_length_input",
189189
),
190190
pytest.param(
191-
[G1_GAS(i * G1_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
192-
[(i * G1_MSM_K_INPUT_LENGTH) - 1 for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
191+
[G1_GAS(i * G1_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))],
192+
[(i * G1_MSM_K_INPUT_LENGTH) - 1 for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))],
193193
id="input_one_byte_too_short_full_discount_table",
194194
),
195195
pytest.param(
196-
[G1_GAS(i * G1_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
197-
[(i * G1_MSM_K_INPUT_LENGTH) + 1 for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
196+
[G1_GAS(i * G1_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))],
197+
[(i * G1_MSM_K_INPUT_LENGTH) + 1 for i in range(1, len(Spec.G1MSM_DISCOUNT_TABLE))],
198198
id="input_one_byte_too_long_full_discount_table",
199199
),
200200
],
@@ -226,22 +226,22 @@ def test_invalid_length_g1msm(
226226
"precompile_gas_list,precompile_data_length_list",
227227
[
228228
pytest.param(
229-
[G2_GAS(i * G2_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
230-
[i * G2_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
229+
[G2_GAS(i * G2_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))],
230+
[i * G2_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))],
231231
id="exact_gas_full_discount_table",
232232
),
233233
pytest.param(
234234
[
235235
G2_GAS(i * G2_MSM_K_INPUT_LENGTH) + 1
236-
for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))
236+
for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))
237237
],
238-
[i * G2_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
238+
[i * G2_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))],
239239
id="one_extra_gas_full_discount_table",
240240
),
241241
],
242242
)
243243
@pytest.mark.parametrize("expected_output", [PointG2()], ids=[""])
244-
@pytest.mark.parametrize("tx_gas_limit", [100_000_000], ids=[""])
244+
@pytest.mark.parametrize("tx_gas_limit", [110_000_000], ids=[""])
245245
@pytest.mark.parametrize("precompile_address", [Spec.G2MSM])
246246
def test_valid_gas_g2msm(
247247
state_test: StateTestFiller,
@@ -274,9 +274,9 @@ def test_valid_gas_g2msm(
274274
pytest.param(
275275
[
276276
G2_GAS(i * G2_MSM_K_INPUT_LENGTH) - 1
277-
for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))
277+
for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))
278278
],
279-
[i * G2_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
279+
[i * G2_MSM_K_INPUT_LENGTH for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))],
280280
id="insufficient_gas_full_discount_table",
281281
),
282282
],
@@ -313,13 +313,13 @@ def test_invalid_gas_g2msm(
313313
id="zero_length_input",
314314
),
315315
pytest.param(
316-
[G2_GAS(i * G2_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
317-
[(i * G2_MSM_K_INPUT_LENGTH) - 1 for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
316+
[G2_GAS(i * G2_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))],
317+
[(i * G2_MSM_K_INPUT_LENGTH) - 1 for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))],
318318
id="input_one_byte_too_short_full_discount_table",
319319
),
320320
pytest.param(
321-
[G2_GAS(i * G2_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
322-
[(i * G2_MSM_K_INPUT_LENGTH) + 1 for i in range(1, len(Spec.MSM_DISCOUNT_TABLE))],
321+
[G2_GAS(i * G2_MSM_K_INPUT_LENGTH) for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))],
322+
[(i * G2_MSM_K_INPUT_LENGTH) + 1 for i in range(1, len(Spec.G2MSM_DISCOUNT_TABLE))],
323323
id="input_one_byte_too_long_full_discount_table",
324324
),
325325
],

whitelist.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ filelock
169169
filesystem
170170
fillvalue
171171
firstlineno
172+
fmt
172173
fn
173174
fname
174175
forkchoice
@@ -371,6 +372,7 @@ rpc
371372
ruleset
372373
runtestloop
373374
runtime
375+
S12
374376
sandboxed
375377
secp256k1
376378
secp256k1n

0 commit comments

Comments
 (0)