ethereum.forks.prague.vm.precompiled_contracts.bls12_381
BLS12 381 Precompile.
.. contents:: Table of Contents :backlinks: none :local:
Introduction
Precompile for BLS12-381 curve operations.
G1_K_DISCOUNT
37 | G1_K_DISCOUNT = [ |
---|---|
38 | 1000, |
39 | 949, |
40 | 848, |
41 | 797, |
42 | 764, |
43 | 750, |
44 | 738, |
45 | 728, |
46 | 719, |
47 | 712, |
48 | 705, |
49 | 698, |
50 | 692, |
51 | 687, |
52 | 682, |
53 | 677, |
54 | 673, |
55 | 669, |
56 | 665, |
57 | 661, |
58 | 658, |
59 | 654, |
60 | 651, |
61 | 648, |
62 | 645, |
63 | 642, |
64 | 640, |
65 | 637, |
66 | 635, |
67 | 632, |
68 | 630, |
69 | 627, |
70 | 625, |
71 | 623, |
72 | 621, |
73 | 619, |
74 | 617, |
75 | 615, |
76 | 613, |
77 | 611, |
78 | 609, |
79 | 608, |
80 | 606, |
81 | 604, |
82 | 603, |
83 | 601, |
84 | 599, |
85 | 598, |
86 | 596, |
87 | 595, |
88 | 593, |
89 | 592, |
90 | 591, |
91 | 589, |
92 | 588, |
93 | 586, |
94 | 585, |
95 | 584, |
96 | 582, |
97 | 581, |
98 | 580, |
99 | 579, |
100 | 577, |
101 | 576, |
102 | 575, |
103 | 574, |
104 | 573, |
105 | 572, |
106 | 570, |
107 | 569, |
108 | 568, |
109 | 567, |
110 | 566, |
111 | 565, |
112 | 564, |
113 | 563, |
114 | 562, |
115 | 561, |
116 | 560, |
117 | 559, |
118 | 558, |
119 | 557, |
120 | 556, |
121 | 555, |
122 | 554, |
123 | 553, |
124 | 552, |
125 | 551, |
126 | 550, |
127 | 549, |
128 | 548, |
129 | 547, |
130 | 547, |
131 | 546, |
132 | 545, |
133 | 544, |
134 | 543, |
135 | 542, |
136 | 541, |
137 | 540, |
138 | 540, |
139 | 539, |
140 | 538, |
141 | 537, |
142 | 536, |
143 | 536, |
144 | 535, |
145 | 534, |
146 | 533, |
147 | 532, |
148 | 532, |
149 | 531, |
150 | 530, |
151 | 529, |
152 | 528, |
153 | 528, |
154 | 527, |
155 | 526, |
156 | 525, |
157 | 525, |
158 | 524, |
159 | 523, |
160 | 522, |
161 | 522, |
162 | 521, |
163 | 520, |
164 | 520, |
165 | 519, |
166 | ] |
G2_K_DISCOUNT
168 | G2_K_DISCOUNT = [ |
---|---|
169 | 1000, |
170 | 1000, |
171 | 923, |
172 | 884, |
173 | 855, |
174 | 832, |
175 | 812, |
176 | 796, |
177 | 782, |
178 | 770, |
179 | 759, |
180 | 749, |
181 | 740, |
182 | 732, |
183 | 724, |
184 | 717, |
185 | 711, |
186 | 704, |
187 | 699, |
188 | 693, |
189 | 688, |
190 | 683, |
191 | 679, |
192 | 674, |
193 | 670, |
194 | 666, |
195 | 663, |
196 | 659, |
197 | 655, |
198 | 652, |
199 | 649, |
200 | 646, |
201 | 643, |
202 | 640, |
203 | 637, |
204 | 634, |
205 | 632, |
206 | 629, |
207 | 627, |
208 | 624, |
209 | 622, |
210 | 620, |
211 | 618, |
212 | 615, |
213 | 613, |
214 | 611, |
215 | 609, |
216 | 607, |
217 | 606, |
218 | 604, |
219 | 602, |
220 | 600, |
221 | 598, |
222 | 597, |
223 | 595, |
224 | 593, |
225 | 592, |
226 | 590, |
227 | 589, |
228 | 587, |
229 | 586, |
230 | 584, |
231 | 583, |
232 | 582, |
233 | 580, |
234 | 579, |
235 | 578, |
236 | 576, |
237 | 575, |
238 | 574, |
239 | 573, |
240 | 571, |
241 | 570, |
242 | 569, |
243 | 568, |
244 | 567, |
245 | 566, |
246 | 565, |
247 | 563, |
248 | 562, |
249 | 561, |
250 | 560, |
251 | 559, |
252 | 558, |
253 | 557, |
254 | 556, |
255 | 555, |
256 | 554, |
257 | 553, |
258 | 552, |
259 | 552, |
260 | 551, |
261 | 550, |
262 | 549, |
263 | 548, |
264 | 547, |
265 | 546, |
266 | 545, |
267 | 545, |
268 | 544, |
269 | 543, |
270 | 542, |
271 | 541, |
272 | 541, |
273 | 540, |
274 | 539, |
275 | 538, |
276 | 537, |
277 | 537, |
278 | 536, |
279 | 535, |
280 | 535, |
281 | 534, |
282 | 533, |
283 | 532, |
284 | 532, |
285 | 531, |
286 | 530, |
287 | 530, |
288 | 529, |
289 | 528, |
290 | 528, |
291 | 527, |
292 | 526, |
293 | 526, |
294 | 525, |
295 | 524, |
296 | 524, |
297 | ] |
G1_MAX_DISCOUNT
299 | G1_MAX_DISCOUNT = 519 |
---|
G2_MAX_DISCOUNT
300 | G2_MAX_DISCOUNT = 524 |
---|
MULTIPLIER
301 | MULTIPLIER = Uint(1000) |
---|
_bytes_to_g1_cached
Internal cached version of bytes_to_g1
that works with hashable bytes
.
308 | @lru_cache(maxsize=128) |
---|
def _bytes_to_g1_cached(data: bytes, subgroup_check: bool) -> Point3D[FQ]:
313 | """ |
---|---|
314 | Internal cached version of `bytes_to_g1` that works with hashable `bytes`. |
315 | """ |
316 | if len(data) != 128: |
317 | raise InvalidParameter("Input should be 128 bytes long") |
318 | |
319 | x = bytes_to_fq(data[:64]) |
320 | y = bytes_to_fq(data[64:]) |
321 | |
322 | if x >= FQ.field_modulus: |
323 | raise InvalidParameter("x >= field modulus") |
324 | if y >= FQ.field_modulus: |
325 | raise InvalidParameter("y >= field modulus") |
326 | |
327 | z = 1 |
328 | if x == 0 and y == 0: |
329 | z = 0 |
330 | point = FQ(x), FQ(y), FQ(z) |
331 | |
332 | if not is_on_curve(point, b): |
333 | raise InvalidParameter("G1 point is not on curve") |
334 | |
335 | if subgroup_check and not is_inf(bls12_multiply(point, curve_order)): |
336 | raise InvalidParameter("Subgroup check failed for G1 point.") |
337 | |
338 | return point |
bytes_to_g1
Decode 128 bytes to a G1 point with or without subgroup check.
Parameters
data : The bytes data to decode. subgroup_check : bool Whether to perform a subgroup check on the G1 point.
Returns
point : Point3D[FQ] The G1 point.
Raises
InvalidParameter If a field element is invalid, the point is not on the curve, or the subgroup check fails.
def bytes_to_g1(data: Bytes, subgroup_check: bool) -> Point3D[FQ]:
345 | """ |
---|---|
346 | Decode 128 bytes to a G1 point with or without subgroup check. |
347 |
|
348 | Parameters |
349 | ---------- |
350 | data : |
351 | The bytes data to decode. |
352 | subgroup_check : bool |
353 | Whether to perform a subgroup check on the G1 point. |
354 |
|
355 | Returns |
356 | ------- |
357 | point : Point3D[FQ] |
358 | The G1 point. |
359 |
|
360 | Raises |
361 | ------ |
362 | InvalidParameter |
363 | If a field element is invalid, the point is not on the curve, or the |
364 | subgroup check fails. |
365 |
|
366 | """ |
367 | # This is needed bc when we slice `Bytes` we get a `bytearray`, |
368 | # which is not hashable |
369 | return _bytes_to_g1_cached(bytes(data), subgroup_check) |
g1_to_bytes
Encode a G1 point to 128 bytes.
Parameters
g1_point : The G1 point to encode.
Returns
data : Bytes The encoded data.
def g1_to_bytes(g1_point: Point3D[FQ]) -> Bytes:
375 | """ |
---|---|
376 | Encode a G1 point to 128 bytes. |
377 |
|
378 | Parameters |
379 | ---------- |
380 | g1_point : |
381 | The G1 point to encode. |
382 |
|
383 | Returns |
384 | ------- |
385 | data : Bytes |
386 | The encoded data. |
387 |
|
388 | """ |
389 | g1_normalized = normalize(g1_point) |
390 | x, y = g1_normalized |
391 | return int(x).to_bytes(64, "big") + int(y).to_bytes(64, "big") |
decode_g1_scalar_pair
Decode 160 bytes to a G1 point and a scalar.
Parameters
data : The bytes data to decode.
Returns
point : Tuple[Point3D[FQ], int] The G1 point and the scalar.
Raises
InvalidParameter If the subgroup check failed.
def decode_g1_scalar_pair(data: Bytes) -> Tuple[Point3D[FQ], int]:
397 | """ |
---|---|
398 | Decode 160 bytes to a G1 point and a scalar. |
399 |
|
400 | Parameters |
401 | ---------- |
402 | data : |
403 | The bytes data to decode. |
404 |
|
405 | Returns |
406 | ------- |
407 | point : Tuple[Point3D[FQ], int] |
408 | The G1 point and the scalar. |
409 |
|
410 | Raises |
411 | ------ |
412 | InvalidParameter |
413 | If the subgroup check failed. |
414 |
|
415 | """ |
416 | if len(data) != 160: |
417 | InvalidParameter("Input should be 160 bytes long") |
418 | |
419 | point = bytes_to_g1(data[:128], subgroup_check=True) |
420 | |
421 | m = int.from_bytes(buffer_read(data, U256(128), U256(32)), "big") |
422 | |
423 | return point, m |
bytes_to_fq
Decode 64 bytes to a FQ element.
Parameters
data : The bytes data to decode.
Returns
fq : FQ The FQ element.
Raises
InvalidParameter If the field element is invalid.
def bytes_to_fq(data: Bytes) -> FQ:
427 | """ |
---|---|
428 | Decode 64 bytes to a FQ element. |
429 |
|
430 | Parameters |
431 | ---------- |
432 | data : |
433 | The bytes data to decode. |
434 |
|
435 | Returns |
436 | ------- |
437 | fq : FQ |
438 | The FQ element. |
439 |
|
440 | Raises |
441 | ------ |
442 | InvalidParameter |
443 | If the field element is invalid. |
444 |
|
445 | """ |
446 | if len(data) != 64: |
447 | raise InvalidParameter("FQ should be 64 bytes long") |
448 | |
449 | c = int.from_bytes(data[:64], "big") |
450 | |
451 | if c >= FQ.field_modulus: |
452 | raise InvalidParameter("Invalid field element") |
453 | |
454 | return FQ(c) |
bytes_to_fq2
Decode 128 bytes to an FQ2 element.
Parameters
data : The bytes data to decode.
Returns
fq2 : FQ2 The FQ2 element.
Raises
InvalidParameter If the field element is invalid.
def bytes_to_fq2(data: Bytes) -> FQ2:
458 | """ |
---|---|
459 | Decode 128 bytes to an FQ2 element. |
460 |
|
461 | Parameters |
462 | ---------- |
463 | data : |
464 | The bytes data to decode. |
465 |
|
466 | Returns |
467 | ------- |
468 | fq2 : FQ2 |
469 | The FQ2 element. |
470 |
|
471 | Raises |
472 | ------ |
473 | InvalidParameter |
474 | If the field element is invalid. |
475 |
|
476 | """ |
477 | if len(data) != 128: |
478 | raise InvalidParameter("FQ2 input should be 128 bytes long") |
479 | c_0 = int.from_bytes(data[:64], "big") |
480 | c_1 = int.from_bytes(data[64:], "big") |
481 | |
482 | if c_0 >= FQ.field_modulus: |
483 | raise InvalidParameter("Invalid field element") |
484 | if c_1 >= FQ.field_modulus: |
485 | raise InvalidParameter("Invalid field element") |
486 | |
487 | return FQ2((c_0, c_1)) |
_bytes_to_g2_cached
Internal cached version of bytes_to_g2
that works with hashable bytes
.
494 | @lru_cache(maxsize=128) |
---|
def _bytes_to_g2_cached(data: bytes, subgroup_check: bool) -> Point3D[FQ2]:
499 | """ |
---|---|
500 | Internal cached version of `bytes_to_g2` that works with hashable `bytes`. |
501 | """ |
502 | if len(data) != 256: |
503 | raise InvalidParameter("G2 should be 256 bytes long") |
504 | |
505 | x = bytes_to_fq2(data[:128]) |
506 | y = bytes_to_fq2(data[128:]) |
507 | |
508 | z = (1, 0) |
509 | if x == FQ2((0, 0)) and y == FQ2((0, 0)): |
510 | z = (0, 0) |
511 | |
512 | point = x, y, FQ2(z) |
513 | |
514 | if not is_on_curve(point, b2): |
515 | raise InvalidParameter("Point is not on curve") |
516 | |
517 | if subgroup_check and not is_inf(bls12_multiply(point, curve_order)): |
518 | raise InvalidParameter("Subgroup check failed for G2 point.") |
519 | |
520 | return point |
bytes_to_g2
Decode 256 bytes to a G2 point with or without subgroup check.
Parameters
data : The bytes data to decode. subgroup_check : bool Whether to perform a subgroup check on the G2 point.
Returns
point : Point3D[FQ2] The G2 point.
Raises
InvalidParameter If a field element is invalid, the point is not on the curve, or the subgroup check fails.
def bytes_to_g2(data: Bytes, subgroup_check: bool) -> Point3D[FQ2]:
527 | """ |
---|---|
528 | Decode 256 bytes to a G2 point with or without subgroup check. |
529 |
|
530 | Parameters |
531 | ---------- |
532 | data : |
533 | The bytes data to decode. |
534 | subgroup_check : bool |
535 | Whether to perform a subgroup check on the G2 point. |
536 |
|
537 | Returns |
538 | ------- |
539 | point : Point3D[FQ2] |
540 | The G2 point. |
541 |
|
542 | Raises |
543 | ------ |
544 | InvalidParameter |
545 | If a field element is invalid, the point is not on the curve, or the |
546 | subgroup check fails. |
547 |
|
548 | """ |
549 | # This is needed bc when we slice `Bytes` we get a `bytearray`, |
550 | # which is not hashable |
551 | return _bytes_to_g2_cached(data, subgroup_check) |
fq2_to_bytes
Encode a FQ2 point to 128 bytes.
Parameters
fq2 : The FQ2 point to encode.
Returns
data : Bytes The encoded data.
def fq2_to_bytes(fq2: FQ2) -> Bytes:
555 | """ |
---|---|
556 | Encode a FQ2 point to 128 bytes. |
557 |
|
558 | Parameters |
559 | ---------- |
560 | fq2 : |
561 | The FQ2 point to encode. |
562 |
|
563 | Returns |
564 | ------- |
565 | data : Bytes |
566 | The encoded data. |
567 |
|
568 | """ |
569 | coord0, coord1 = fq2.coeffs |
570 | return int(coord0).to_bytes(64, "big") + int(coord1).to_bytes(64, "big") |
g2_to_bytes
Encode a G2 point to 256 bytes.
Parameters
g2_point : The G2 point to encode.
Returns
data : Bytes The encoded data.
def g2_to_bytes(g2_point: Point3D[FQ2]) -> Bytes:
576 | """ |
---|---|
577 | Encode a G2 point to 256 bytes. |
578 |
|
579 | Parameters |
580 | ---------- |
581 | g2_point : |
582 | The G2 point to encode. |
583 |
|
584 | Returns |
585 | ------- |
586 | data : Bytes |
587 | The encoded data. |
588 |
|
589 | """ |
590 | x_coords, y_coords = normalize(g2_point) |
591 | return fq2_to_bytes(x_coords) + fq2_to_bytes(y_coords) |
decode_g2_scalar_pair
Decode 288 bytes to a G2 point and a scalar.
Parameters
data : The bytes data to decode.
Returns
point : Tuple[Point3D[FQ2], int] The G2 point and the scalar.
Raises
InvalidParameter If the subgroup check failed.
def decode_g2_scalar_pair(data: Bytes) -> Tuple[Point3D[FQ2], int]:
597 | """ |
---|---|
598 | Decode 288 bytes to a G2 point and a scalar. |
599 |
|
600 | Parameters |
601 | ---------- |
602 | data : |
603 | The bytes data to decode. |
604 |
|
605 | Returns |
606 | ------- |
607 | point : Tuple[Point3D[FQ2], int] |
608 | The G2 point and the scalar. |
609 |
|
610 | Raises |
611 | ------ |
612 | InvalidParameter |
613 | If the subgroup check failed. |
614 |
|
615 | """ |
616 | if len(data) != 288: |
617 | InvalidParameter("Input should be 288 bytes long") |
618 | |
619 | point = bytes_to_g2(data[:256], subgroup_check=True) |
620 | n = int.from_bytes(data[256 : 256 + 32], "big") |
621 | |
622 | return point, n |