From f3eee6f6f45b079af55251945d59e20a0d517b58 Mon Sep 17 00:00:00 2001 From: KimiWu Date: Wed, 14 Feb 2024 16:09:19 +0800 Subject: [PATCH] feat: add input/output rlc data check in ecRecover (PoC) --- .../execution/precompiles/ecrecover.py | 24 +++++++++++++++++++ tests/evm/precompiles/test_ecRecover.py | 17 ++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/zkevm_specs/evm_circuit/execution/precompiles/ecrecover.py b/src/zkevm_specs/evm_circuit/execution/precompiles/ecrecover.py index 779726ada..7d424c4de 100644 --- a/src/zkevm_specs/evm_circuit/execution/precompiles/ecrecover.py +++ b/src/zkevm_specs/evm_circuit/execution/precompiles/ecrecover.py @@ -1,3 +1,4 @@ +from dataclasses import dataclass from zkevm_specs.evm_circuit.instruction import Instruction from zkevm_specs.evm_circuit.table import ( CallContextFieldTag, @@ -5,10 +6,17 @@ RW, ) from zkevm_specs.util import FQ, Word, EcrecoverGas +from zkevm_specs.util.arithmetic import RLC SECP256K1N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 +@dataclass(frozen=True) +class PrecompileRlcData: + input_rlc: FQ + output_rlc: FQ + + def ecRecover(instruction: Instruction): is_success = instruction.call_context_lookup(CallContextFieldTag.IsSuccess, RW.Read) address_word = instruction.call_context_lookup_word(CallContextFieldTag.CalleeAddress) @@ -26,9 +34,25 @@ def ecRecover(instruction: Instruction): sig_r: Word = instruction.curr.aux_data[2] sig_s: Word = instruction.curr.aux_data[3] recovered_addr: FQ = instruction.curr.aux_data[4] + rlc_data: PrecompileRlcData = instruction.curr.aux_data[5] + keccak_randomness: FQ = instruction.curr.aux_data[6] is_recovered = FQ(instruction.is_zero(recovered_addr) != FQ(1)) + # Verify input and output + input_bytes = bytearray(b"") + input_bytes.extend(msg_hash.int_value().to_bytes(32, "little")) + input_bytes.extend(sig_v.int_value().to_bytes(32, "little")) + input_bytes.extend(sig_r.int_value().to_bytes(32, "little")) + input_bytes.extend(sig_s.int_value().to_bytes(32, "little")) + input_rlc = RLC(bytes(reversed(input_bytes)), keccak_randomness, n_bytes=128).expr() + instruction.constrain_equal(rlc_data.input_rlc, input_rlc) + + output_rlc = RLC( + bytes(reversed(recovered_addr.n.to_bytes(32, "little"))), keccak_randomness, n_bytes=32 + ).expr() + instruction.constrain_equal(rlc_data.output_rlc, output_rlc) + # is_success is always true # ref: https://github.com/ethereum/execution-specs/blob/master/src/ethereum/shanghai/vm/precompiled_contracts/ecrecover.py instruction.constrain_equal(is_success, FQ(1)) diff --git a/tests/evm/precompiles/test_ecRecover.py b/tests/evm/precompiles/test_ecRecover.py index 9bf610a46..140fd7d2b 100644 --- a/tests/evm/precompiles/test_ecRecover.py +++ b/tests/evm/precompiles/test_ecRecover.py @@ -14,12 +14,13 @@ Tables, verify_steps, ) -from zkevm_specs.evm_circuit.execution.precompiles.ecrecover import SECP256K1N +from zkevm_specs.evm_circuit.execution.precompiles.ecrecover import PrecompileRlcData, SECP256K1N from zkevm_specs.util import ( Word, FQ, ) from zkevm_specs.evm_circuit.table import SigTableRow +from zkevm_specs.util.arithmetic import RLC def gen_testing_data(): @@ -49,6 +50,8 @@ def gen_testing_data(): TESTING_DATA = gen_testing_data() +randomness_keccak = rand_fq() + @pytest.mark.parametrize( "caller_ctx, msg_hash, v, r, s, address", @@ -72,12 +75,24 @@ def test_ecRecover( return_data_offset = 0 return_data_length = 0x20 if recovered else 0 + input_bytes = bytearray(b"") + input_bytes.extend(msg_hash) + input_bytes.extend((v + 27).to_bytes(32, "little")) + input_bytes.extend(r.to_bytes(32, "little")) + input_bytes.extend(s.to_bytes(32, "little")) + input_rlc = RLC(bytes(reversed(input_bytes)), randomness_keccak, n_bytes=128).expr() + output_bytes = int.from_bytes(address, "big").to_bytes(32, "little") + output_rlc = RLC(bytes(reversed(output_bytes)), randomness_keccak, n_bytes=32).expr() + rlc_data = PrecompileRlcData(input_rlc, output_rlc) + aux_data = [ Word(msg_hash), Word(v + 27), Word(r), Word(s), FQ(int.from_bytes(address, "big")), + rlc_data, + randomness_keccak, ] # assign sig_table