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