Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
feat: add input/output rlc data check in ecRecover (PoC)
Browse files Browse the repository at this point in the history
  • Loading branch information
KimiWu123 committed Feb 14, 2024
1 parent b5816af commit f3eee6f
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
24 changes: 24 additions & 0 deletions src/zkevm_specs/evm_circuit/execution/precompiles/ecrecover.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
from dataclasses import dataclass
from zkevm_specs.evm_circuit.instruction import Instruction
from zkevm_specs.evm_circuit.table import (
CallContextFieldTag,
FixedTableTag,
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)
Expand All @@ -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))
Expand Down
17 changes: 16 additions & 1 deletion tests/evm/precompiles/test_ecRecover.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down Expand Up @@ -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",
Expand All @@ -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
Expand Down

0 comments on commit f3eee6f

Please sign in to comment.