This repository was archived by the owner on Jul 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 270
Spec for opcode SHL
#225
Merged
Merged
Spec for opcode SHL
#225
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
9b1d145
Add test case for `SHL`.
silathdiir 35f66e0
Implement opcode `SHL`.
silathdiir 1939133
Fix to validate `a64s_hi[idx] < p_hi`, and add Markdown doc for `SHL`.
silathdiir 897ad08
Move some code from `SHR` to make it work with `master` branch.
silathdiir af1c403
Merge remote-tracking branch 'origin/master' into feat/opcode-shl
silathdiir 5f01718
Replace key `code_source` with `code_hash` in test code.
silathdiir 929610d
Merge remote-tracking branch 'origin/master' into feat/opcode-shl
silathdiir 8633f59
Fix to use `mul_add_words` for `SHL`.
silathdiir ad0ed96
Merge previous `SHR` into `SHL`.
silathdiir 1469896
Merge both `SHL` and `SHR` into `mul_div_mod_shl_shr`.
silathdiir b45da81
Delete separate Markdown doc of `SHL` and `SHR`.
silathdiir 3ad5b22
Fix constraints.
silathdiir 9b95227
Update Markdown doc for `MUL`, `DIV`, `MOD`, `SHL` and `SHR`.
silathdiir 450db8c
Merge remote-tracking branch 'origin/master' into feat/opcode-shl
silathdiir 4598e5f
Fix the wrong argument sequence of `SHL` and `SHR`.
silathdiir 7a7f5b9
Add function `is_op_mul`, `is_op_div`, `is_op_mod`, `is_op_shl` and
silathdiir 76f92ab
Delete `ExecutionState::SHL_SHR` and update Markdown doc according to
silathdiir 358f20e
Update spec code according to circuit, and add `Pow2` lookup for shift
silathdiir c57b4d0
Fix `Pow2` lookup table and update to use `shf0` for lookup.
silathdiir e39f590
Merge remote-tracking branch 'upstream/master' into feat/opcode-shl
silathdiir db14f27
Merge remote-tracking branch 'upstream/master' into feat/opcode-shl
silathdiir a387fd7
Merge remote-tracking branch 'upstream/master' into feat/opcode-shl
silathdiir c3fbf40
Revert to commit "Merge previous `SHR` into `SHL`."
silathdiir 5003434
Merge remote-tracking branch 'upstream/master' into feat/opcode-shl
silathdiir 443538d
Update for failed test cases.
silathdiir c053421
Update `SHL & SHR` implementation.
silathdiir 913c9d7
Add new Markdown `1bSHL_1cSHR.md`.
silathdiir 1e4362f
Merge remote-tracking branch 'upstream/master' into feat/opcode-shl
silathdiir 90c9344
Update specs/opcode/1bSHL_1cSHR.md
silathdiir 413cb21
Update specs/opcode/1bSHL_1cSHR.md
silathdiir d53de49
Fix to always constrain `push` to zero if divisor == 0 (shift > 255).
silathdiir File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # SHL and SHR opcodes | ||
|
|
||
| ## Procedure | ||
|
|
||
| ### EVM behavior | ||
|
|
||
| Pop two EVM words `shift` and `a` from the stack, and push `b` to the stack, where `b` is computed as | ||
|
|
||
| - for opcode SHL, `shift` is a number of bits to shift to the left, compute `b = (a * 2^shift) % 2^256` when `shift < 256` otherwise `b = 0` | ||
| - for opcode SHR, `shift` is a number of bits to shift to the right, compute `b = a // 2^shift` when `shift < 256` otherwise `b = 0` | ||
|
|
||
| ### Circuit behavior | ||
|
|
||
| To prove the SHL and SHR opcodes, we first construct a `MulAddWordsGadget` that proves `quotient * divisor + remainder = dividend (% 2^256)` where quotient, divisor, remainder and dividend are all 256-bit words. Reference `02MUL_04DIV_06MOD.md` for details about `MulAddWordsGadget`. | ||
|
|
||
| Based on different opcode cases, we constrain the stack pops and pushes as follows | ||
|
|
||
| - for opcode SHL, two stack pops are shift and quotient, when `divisor = 2^shift` if `shift < 256` and 0 otherwise. The stack push is dividend if `shift < 256` and 0 otherwise. | ||
| - for opcode SHR, two stack pops are shift and dividend, when `divisor = 2^shift` if `shift < 256` and 0 otherwise. The stack push is quotient if `shift < 256` and 0 otherwise. | ||
|
|
||
| The opcode circuit also adds some extra constraints: | ||
|
|
||
| - contrain `shift == shift.cells[0]` when `divisor != 0`. | ||
| - use a `LtWordGadget` to constrain `remainder < divisor` when `divisor != 0`. | ||
| - if the opcode is SHL, constrain `remainder == 0`. | ||
| - if the opcode is SHR, constrain `overflow == 0` in `MulAddWordsGadget`. | ||
|
|
||
| ## Constraints | ||
|
|
||
| 1. opcodeId checks | ||
| - opId === OpcodeId(0x1b) for SHL | ||
| - opId === OpcodeId(0x1c) for SHR | ||
| 2. state transition: | ||
| - gc + 3 | ||
| - stack_pointer + 1 | ||
| - pc + 1 | ||
| - gas + 3 | ||
| 3. Lookups: 1 pow2 lookup + 3 busmapping lookups | ||
| - divisor lookup in pow2 table (where 0≤shf0<256) | ||
| - when `shf0 < 128`, constrain `divisor_lo == 2^shf0`. | ||
| - when `shf0 >= 128`, constrain `divisor_hi == 2^(shf0 - 128)`. | ||
| - top of the stack | ||
| - when opcode is SHL, quotient is at the top of the stack. | ||
| - when opcode is SHR, dividend is at the top of the stack. | ||
| - shift is at the second position of the stack when `divisor = 2^shift`. | ||
| - new top of the stack | ||
| - when opcode is SHL, dividend is at the new top of the stack. | ||
| - when opcode is SHR, quotient is at the new top of the stack if `divisor != 0` otherwise 0. | ||
|
|
||
| ## Exceptions | ||
|
|
||
| 1. stack underflow: `1023 <= stack_pointer <= 1024` | ||
| 2. out of gas: remaining gas is not enough | ||
|
|
||
| ## Code | ||
|
|
||
| See `src/zkevm_specs/evm/execution/shl_shr.py` |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| from ...util import FQ, RLC | ||
| from ..instruction import Instruction, Transition | ||
| from ..opcode import Opcode | ||
|
|
||
|
|
||
| def shl_shr(instruction: Instruction): | ||
| opcode = instruction.opcode_lookup(True) | ||
|
|
||
| pop1 = instruction.stack_pop() | ||
| pop2 = instruction.stack_pop() | ||
| push = instruction.stack_push() | ||
|
|
||
| ( | ||
| is_shl, | ||
| shf0, | ||
| shift, | ||
| dividend, | ||
| divisor, | ||
| quotient, | ||
| remainder, | ||
| ) = gen_witness(opcode, pop1, pop2, push) | ||
| check_witness( | ||
| instruction, | ||
| is_shl, | ||
| shf0, | ||
| shift, | ||
| dividend, | ||
| divisor, | ||
| quotient, | ||
| remainder, | ||
| pop1, | ||
| pop2, | ||
| push, | ||
| ) | ||
|
|
||
| instruction.step_state_transition_in_same_context( | ||
| opcode, | ||
| rw_counter=Transition.delta(3), | ||
| program_counter=Transition.delta(1), | ||
| stack_pointer=Transition.delta(1), | ||
| ) | ||
|
|
||
|
|
||
| def check_witness( | ||
| instruction: Instruction, | ||
| is_shl: FQ, | ||
| shf0: FQ, | ||
| shift: RLC, | ||
| dividend: RLC, | ||
| divisor: RLC, | ||
| quotient: RLC, | ||
| remainder: RLC, | ||
| pop1: RLC, | ||
| pop2: RLC, | ||
| push: RLC, | ||
| ): | ||
| is_shr = 1 - is_shl | ||
| divisor_is_zero = instruction.word_is_zero(divisor) | ||
|
|
||
| # Constrain stack pops and pushes as: | ||
| # - for SHL, two pops are shift and quotient, and push is dividend. | ||
| # - for SHR, two pops are shift and dividend, and push is quotient. | ||
| instruction.constrain_equal(pop1.expr(), shift.expr()) | ||
| instruction.constrain_equal( | ||
| pop2.expr(), | ||
| is_shl * quotient.expr() + is_shr * dividend.expr(), | ||
| ) | ||
| instruction.constrain_equal( | ||
| push.expr(), (is_shl * dividend.expr() + is_shr * quotient.expr()) * (1 - divisor_is_zero) | ||
| ) | ||
|
|
||
| # Constrain shift == shift.cells[0] when divisor != 0. | ||
| instruction.constrain_zero( | ||
| (1 - divisor_is_zero) * (shift.expr() - shift.le_bytes[0]), | ||
| ) | ||
|
|
||
| # Constrain remainder < divisor when divisor != 0. | ||
| remainder_lt_divisor, _ = instruction.compare_word(remainder, divisor) | ||
| instruction.constrain_zero((1 - divisor_is_zero) * (1 - remainder_lt_divisor)) | ||
|
|
||
| # Constrain remainder == 0 for SHL. | ||
| remainder_is_zero = instruction.word_is_zero(remainder) | ||
| instruction.constrain_zero(is_shl * (1 - remainder_is_zero)) | ||
|
|
||
| # Constrain overflow == 0 for SHR. | ||
| overflow = instruction.mul_add_words(quotient, divisor, remainder, dividend) | ||
| instruction.constrain_zero(is_shr * overflow) | ||
|
|
||
| # Constrain divisor_lo == 2^shf0 when shf0 < 128, and | ||
| # divisor_hi == 2^(128 - shf0) otherwise. | ||
| divisor_lo = instruction.bytes_to_fq(divisor.le_bytes[:16]) | ||
| divisor_hi = instruction.bytes_to_fq(divisor.le_bytes[16:]) | ||
| if (1 - divisor_is_zero) == 1: | ||
| instruction.pow2_lookup(shf0, divisor_lo, divisor_hi) | ||
|
|
||
|
|
||
| def gen_witness(opcode: FQ, pop1: RLC, pop2: RLC, push: RLC): | ||
| is_shl = Opcode.SHR - opcode | ||
| shift = pop1 | ||
| shf0 = shift.le_bytes[0] | ||
| divisor = RLC(1 << shf0) if shf0 == shift.int_value else RLC(0) | ||
| if is_shl.n == 1: | ||
| dividend = push | ||
| quotient = pop2 | ||
| remainder = RLC(0) | ||
| else: # SHR | ||
| dividend = pop2 | ||
| quotient = push | ||
| remainder = RLC(dividend.int_value - quotient.int_value * divisor.int_value) | ||
|
|
||
| return ( | ||
| is_shl, | ||
| shf0, | ||
| shift, | ||
| dividend, | ||
| divisor, | ||
| quotient, | ||
| remainder, | ||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.