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

Commit

Permalink
feat: impl. ecRecover
Browse files Browse the repository at this point in the history
  • Loading branch information
KimiWu123 committed Oct 19, 2023
1 parent 9690c3d commit 1bf4565
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
2 changes: 1 addition & 1 deletion specs/precompile/01ecRecover.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ A constant gas cost: 3000

1. If gas_left < gas_required, then is_success == false and return data is zero.
1. v, r and s are valid
- v is 27 or 28 and the first 31 bytes of v is zero
- v is 27 or 28
- both of r and s are less than `secp256k1N (0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141)`
- both of r and s are greater than `1`
2. `sig_table` lookups
Expand Down
67 changes: 67 additions & 0 deletions src/zkevm_specs/evm_circuit/execution/precompiles/ecrecover.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from instruction import Instruction, Transition
from table import (
CallContextFieldTag,
FixedTableTag,
RW,
)
from zkevm_specs.util import FQ, Word, EcrecoverGas

SECP256K1N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141


def ecRecover(instruction: Instruction):
is_success = instruction.call_context_lookup(CallContextFieldTag.IsSuccess, RW.Read)
address_word = instruction.call_context_lookup_word(CallContextFieldTag.CalleeAddress)
address = instruction.word_to_address(address_word)
instruction.fixed_lookup(
FixedTableTag.PrecompileInfo,
FQ(instruction.curr.execution_state),
address,
FQ(EcrecoverGas),
)

# Get msg_hash, signature and recovered address from aux_data
msg_hash = instruction.curr.aux_data[0]
sig_v = instruction.curr.aux_data[1]
sig_r = instruction.curr.aux_data[2]
sig_s = instruction.curr.aux_data[3]
recovered_addr = instruction.curr.aux_data[4]

is_recovered = FQ(instruction.is_zero_word(recovered_addr) != FQ(0))

# if the address is recovered, this call should be success either
instruction.constrain_equal(is_success, is_recovered)

# verify r and s
sig_r_upper_bound, _ = instruction.compare_word(sig_r, Word(SECP256K1N))
sig_s_upper_bound, _ = instruction.compare_word(sig_s, Word(SECP256K1N))
sig_r_lower_bound, _ = instruction.compare_word(Word(1), sig_r)
sig_s_lower_bound, _ = instruction.compare_word(Word(1), sig_s)
valid_r_s = instruction.is_equal(
sig_r_upper_bound + sig_s_upper_bound + sig_r_lower_bound + sig_s_lower_bound, FQ(4)
)

# verify v
is_equal_27 = instruction.is_equal_word(sig_v, Word(27))
is_equal_28 = instruction.is_equal_word(sig_v, Word(28))
valid_v = instruction.is_equal(is_equal_27 + is_equal_28, FQ(1))

if valid_r_s + valid_v == FQ(2):
# sig table lookups
instruction.sig_lookup(
msg_hash, sig_v - FQ(27).expr(), sig_r, sig_s, recovered_addr, is_recovered
)
else:
instruction.constrain_zero(is_recovered)
instruction.constrain_zero(recovered_addr)

# calculate gas cost
gas_cost = EcrecoverGas if is_success == FQ(1) else instruction.curr.gas_left

# Restore caller state to next StepState
instruction.step_state_transition_to_restored_context(
rw_counter_delta=instruction.rw_counter_offset,
return_data_offset=FQ(0),
return_data_length=32 if is_success == FQ(1) else 0,
gas_left=Transition.delta(-gas_cost),
)
2 changes: 1 addition & 1 deletion src/zkevm_specs/evm_circuit/step.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class StepState:
# not often used.
log_id: FQ

# Auxilary witness data needed by gadgets
# Auxiliary witness data needed by gadgets
aux_data: Any

def __init__(
Expand Down

0 comments on commit 1bf4565

Please sign in to comment.