From 3d27159d781cd96517a8e047431b307cc4c1578a Mon Sep 17 00:00:00 2001 From: Peter Davies Date: Thu, 18 Jul 2024 15:59:35 +0100 Subject: [PATCH] Add G1 hash to curve precompile --- setup.cfg | 2 +- .../vm/precompiled_contracts/__init__.py | 2 ++ .../bls12_381/__init__.py | 36 +++++++++++++++++++ .../bls12_381/bls12_381_g1.py | 35 ++++++++++++++++++ .../vm/precompiled_contracts/mapping.py | 3 ++ tests/prague/test_state_transition.py | 1 + whitelist.txt | 1 + 7 files changed, 79 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 5cd9b6bfd5..ee48724687 100644 --- a/setup.cfg +++ b/setup.cfg @@ -120,7 +120,7 @@ install_requires = pycryptodome>=3,<4 coincurve>=18,<19 typing_extensions>=4 - py_ecc>=7,<8 + py_ecc @ git+https://github.com/petertdavies/py_ecc.git@127184f4c57b1812da959586d0fe8f43bb1a2389 [options.package_data] ethereum = diff --git a/src/ethereum/prague/vm/precompiled_contracts/__init__.py b/src/ethereum/prague/vm/precompiled_contracts/__init__.py index e770e6c11b..a2b323cab2 100644 --- a/src/ethereum/prague/vm/precompiled_contracts/__init__.py +++ b/src/ethereum/prague/vm/precompiled_contracts/__init__.py @@ -33,6 +33,7 @@ "BLS12_G2_MULTIPLY_ADDRESS", "BLS12_G2_MSM_ADDRESS", "BLS12_PAIRING_ADDRESS", + "BLS12_MAP_FP_TO_G1_ADDRESS", "BLS12_MAP_FP2_TO_G2_ADDRESS", ) @@ -53,4 +54,5 @@ BLS12_G2_MULTIPLY_ADDRESS = hex_to_address("0x0f") BLS12_G2_MSM_ADDRESS = hex_to_address("0x10") BLS12_PAIRING_ADDRESS = hex_to_address("0x11") +BLS12_MAP_FP_TO_G1_ADDRESS = hex_to_address("0x12") BLS12_MAP_FP2_TO_G2_ADDRESS = hex_to_address("0x13") diff --git a/src/ethereum/prague/vm/precompiled_contracts/bls12_381/__init__.py b/src/ethereum/prague/vm/precompiled_contracts/bls12_381/__init__.py index 6348c26499..616289ee56 100644 --- a/src/ethereum/prague/vm/precompiled_contracts/bls12_381/__init__.py +++ b/src/ethereum/prague/vm/precompiled_contracts/bls12_381/__init__.py @@ -22,6 +22,7 @@ is_on_curve, multiply, ) +from py_ecc.optimized_bls12_381.optimized_curve import FQ as OPTIMIZED_FQ from py_ecc.optimized_bls12_381.optimized_curve import FQ2 as OPTIMIZED_FQ2 from py_ecc.typing import Point2D @@ -262,6 +263,41 @@ def decode_G1_scalar_pair(data: Bytes) -> Tuple[Point2D, int]: return p, m +def bytes_to_FQ( + data: Bytes, optimized: bool = False +) -> Union[FQ2, OPTIMIZED_FQ2]: + """ + Decode 64 bytes to a FQ2 element. + + Parameters + ---------- + data : + The bytes data to decode. + optimized : + Whether to use the optimized FQ2 implementation. + + Returns + ------- + fq : FQ + The FQ2 element. + + Raises + ------ + InvalidParameter + If the field element is invalid. + """ + assert len(data) == 64 + c = int.from_bytes(data[:64], "big") + + if c >= P: + raise InvalidParameter("Invalid field element") + + if optimized: + return OPTIMIZED_FQ(c) + else: + return FQ(c) + + def bytes_to_FQ2( data: Bytes, optimized: bool = False ) -> Union[FQ2, OPTIMIZED_FQ2]: diff --git a/src/ethereum/prague/vm/precompiled_contracts/bls12_381/bls12_381_g1.py b/src/ethereum/prague/vm/precompiled_contracts/bls12_381/bls12_381_g1.py index e91dd8e555..728f5488e3 100644 --- a/src/ethereum/prague/vm/precompiled_contracts/bls12_381/bls12_381_g1.py +++ b/src/ethereum/prague/vm/precompiled_contracts/bls12_381/bls12_381_g1.py @@ -12,6 +12,9 @@ Implementation of pre-compiles in G1 (curve over base prime field). """ from py_ecc.bls12_381.bls12_381_curve import add, multiply +from py_ecc.bls.hash_to_curve import clear_cofactor_G1, map_to_curve_G1 +from py_ecc.optimized_bls12_381.optimized_curve import FQ as OPTIMIZED_FQ +from py_ecc.optimized_bls12_381.optimized_curve import normalize from ethereum.base_types import U256, Uint @@ -24,6 +27,7 @@ MAX_DISCOUNT, MULTIPLIER, G1_to_bytes, + bytes_to_FQ, bytes_to_G1, decode_G1_scalar_pair, ) @@ -135,3 +139,34 @@ def bls12_g1_msm(evm: Evm) -> None: result = add(result, product) evm.output = G1_to_bytes(result) + + +def bls12_map_fp_to_g1(evm: Evm) -> None: + """ + Precompile to map field element to G1. + + Parameters + ---------- + evm : + The current EVM frame. + + Raises + ------ + InvalidParameter + If the input length is invalid. + """ + data = evm.message.data + if len(data) != 64: + raise InvalidParameter("Invalid Input Length") + + # GAS + charge_gas(evm, Uint(5500)) + + # OPERATION + field_element = bytes_to_FQ(data, True) + assert isinstance(field_element, OPTIMIZED_FQ) + + g1_uncompressed = clear_cofactor_G1(map_to_curve_G1(field_element)) + g1_normalised = normalize(g1_uncompressed) + + evm.output = G1_to_bytes(g1_normalised) diff --git a/src/ethereum/prague/vm/precompiled_contracts/mapping.py b/src/ethereum/prague/vm/precompiled_contracts/mapping.py index 6475197ba5..155055d49e 100644 --- a/src/ethereum/prague/vm/precompiled_contracts/mapping.py +++ b/src/ethereum/prague/vm/precompiled_contracts/mapping.py @@ -26,6 +26,7 @@ BLS12_G2_MSM_ADDRESS, BLS12_G2_MULTIPLY_ADDRESS, BLS12_MAP_FP2_TO_G2_ADDRESS, + BLS12_MAP_FP_TO_G1_ADDRESS, BLS12_PAIRING_ADDRESS, ECRECOVER_ADDRESS, IDENTITY_ADDRESS, @@ -40,6 +41,7 @@ bls12_g1_add, bls12_g1_msm, bls12_g1_multiply, + bls12_map_fp_to_g1, ) from .bls12_381.bls12_381_g2 import ( bls12_g2_add, @@ -73,5 +75,6 @@ BLS12_G2_MULTIPLY_ADDRESS: bls12_g2_multiply, BLS12_G2_MSM_ADDRESS: bls12_g2_msm, BLS12_PAIRING_ADDRESS: bls12_pairing, + BLS12_MAP_FP_TO_G1_ADDRESS: bls12_map_fp_to_g1, BLS12_MAP_FP2_TO_G2_ADDRESS: bls12_map_fp2_to_g2, } diff --git a/tests/prague/test_state_transition.py b/tests/prague/test_state_transition.py index 35113844b6..b682271644 100644 --- a/tests/prague/test_state_transition.py +++ b/tests/prague/test_state_transition.py @@ -112,6 +112,7 @@ def test_general_state_tests(test_case: Dict) -> None: "tests/fixtures/latest_fork_tests/fixtures/blockchain_tests/prague/eip2537_bls_12_381_precompiles/bls12_pairing", "tests/fixtures/latest_fork_tests/fixtures/blockchain_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1msm", "tests/fixtures/latest_fork_tests/fixtures/blockchain_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2msm", + "tests/fixtures/latest_fork_tests/fixtures/blockchain_tests/prague/eip2537_bls_12_381_precompiles/bls12_map_fp_to_g1", "tests/fixtures/latest_fork_tests/fixtures/blockchain_tests/prague/eip2537_bls_12_381_precompiles/bls12_map_fp2_to_g2", ) diff --git a/whitelist.txt b/whitelist.txt index f7af522d4f..16abde8131 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -448,6 +448,7 @@ coeffs b2 FQ12 +FP FP2 cofactor