forked from DecentralizedClimateFoundation/DCIPs
378 lines
11 KiB
Markdown
378 lines
11 KiB
Markdown
---
|
|
eip: 145
|
|
title: Bitwise shifting instructions in EVM
|
|
author: Alex Beregszaszi (@axic), Paweł Bylica (@chfast)
|
|
type: Standards Track
|
|
category: Core
|
|
status: Final
|
|
created: 2017-02-13
|
|
---
|
|
|
|
## Simple Summary
|
|
|
|
To provide native bitwise shifting with cost on par with other arithmetic operations.
|
|
|
|
## Abstract
|
|
|
|
Native bitwise shifting instructions are introduced, which are more efficient processing wise on the host and are cheaper to use by a contract.
|
|
|
|
## Motivation
|
|
|
|
EVM is lacking bitwise shifting operators, but supports other logical and arithmetic operators. Shift operations can be implemented via arithmetic operators, but that has a higher cost and requires more processing time from the host. Implementing `SHL` and `SHR` using arithmetic cost each 35 gas, while the proposed instructions take 3 gas.
|
|
|
|
## Specification
|
|
|
|
The following instructions are introduced:
|
|
|
|
### `0x1b`: `SHL` (shift left)
|
|
|
|
The `SHL` instruction (shift left) pops 2 values from the stack, first `arg1` and then `arg2`, and pushes on the stack `arg2` shifted to the left by `arg1` number of bits. The result is equal to
|
|
|
|
```
|
|
(arg2 * 2^arg1) mod 2^256
|
|
```
|
|
|
|
Notes:
|
|
- The value (`arg2`) is interpreted as an unsigned number.
|
|
- The shift amount (`arg1`) is interpreted as an unsigned number.
|
|
- If the shift amount (`arg1`) is greater or equal 256 the result is 0.
|
|
- This is equivalent to `PUSH1 2 EXP MUL`.
|
|
|
|
### `0x1c`: `SHR` (logical shift right)
|
|
|
|
The `SHR` instruction (logical shift right) pops 2 values from the stack, first `arg1` and then `arg2`, and pushes on the stack `arg2` shifted to the right by `arg1` number of bits with zero fill. The result is equal to
|
|
|
|
```
|
|
floor(arg2 / 2^arg1)
|
|
```
|
|
|
|
Notes:
|
|
- The value (`arg2`) is interpreted as an unsigned number.
|
|
- The shift amount (`arg1`) is interpreted as an unsigned number.
|
|
- If the shift amount (`arg1`) is greater or equal 256 the result is 0.
|
|
- This is equivalent to `PUSH1 2 EXP DIV`.
|
|
|
|
### `0x1d`: `SAR` (arithmetic shift right)
|
|
|
|
The `SAR` instruction (arithmetic shift right) pops 2 values from the stack, first `arg1` and then `arg2`, and pushes on the stack `arg2` shifted to the right by `arg1` number of bits with sign extension. The result is equal to
|
|
|
|
```
|
|
floor(arg2 / 2^arg1)
|
|
```
|
|
|
|
Notes:
|
|
- The value (`arg2`) is interpreted as a signed number.
|
|
- The shift amount (`arg1`) is interpreted as an unsigned number.
|
|
- If the shift amount (`arg1`) is greater or equal 256 the result is 0 if `arg2` is non-negative or -1 if `arg2` is negative.
|
|
- This is **not** equivalent to `PUSH1 2 EXP SDIV`, since it rounds differently. See `SDIV(-1, 2) == 0`, while `SAR(-1, 1) == -1`.
|
|
|
|
The cost of the shift instructions is set at `verylow` tier (3 gas).
|
|
|
|
## Rationale
|
|
|
|
Instruction operands were chosen to fit the more natural use case of shifting a value already on the stack. This means the operand order is swapped compared to most arithmetic insturctions.
|
|
|
|
## Backwards Compatibility
|
|
|
|
The newly introduced instructions have no effect on bytecode created in the past.
|
|
|
|
## Test Cases
|
|
|
|
### `SHL` (shift left)
|
|
|
|
1. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0x00
|
|
SHL
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000001
|
|
```
|
|
2. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0x01
|
|
SHL
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000002
|
|
```
|
|
3. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0xff
|
|
SHL
|
|
---
|
|
0x8000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
4. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0x0100
|
|
SHL
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
5. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0x0101
|
|
SHL
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
6. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x00
|
|
SHL
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
7. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x01
|
|
SHL
|
|
---
|
|
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
|
|
```
|
|
8. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0xff
|
|
SHL
|
|
---
|
|
0x8000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
9. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x0100
|
|
SHL
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
10. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x01
|
|
SHL
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
11. ```
|
|
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x01
|
|
SHL
|
|
---
|
|
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
|
|
```
|
|
|
|
|
|
### `SHR` (logical shift right)
|
|
|
|
1. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0x00
|
|
SHR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000001
|
|
```
|
|
2. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0x01
|
|
SHR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
3. ```
|
|
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x01
|
|
SHR
|
|
---
|
|
0x4000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
4. ```
|
|
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0xff
|
|
SHR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000001
|
|
```
|
|
5. ```
|
|
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x0100
|
|
SHR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
6. ```
|
|
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x0101
|
|
SHR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
7. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x00
|
|
SHR
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
8. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x01
|
|
SHR
|
|
---
|
|
0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
9. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0xff
|
|
SHR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000001
|
|
```
|
|
10. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x0100
|
|
SHR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
11. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x01
|
|
SHR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
|
|
### `SAR` (arithmetic shift right)
|
|
|
|
1. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0x00
|
|
SAR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000001
|
|
```
|
|
2. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001
|
|
PUSH 0x01
|
|
SAR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
3. ```
|
|
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x01
|
|
SAR
|
|
---
|
|
0xc000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
4. ```
|
|
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0xff
|
|
SAR
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
5. ```
|
|
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x0100
|
|
SAR
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
6. ```
|
|
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x0101
|
|
SAR
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
7. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x00
|
|
SAR
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
8. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x01
|
|
SAR
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
9. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0xff
|
|
SAR
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
10. ```
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x0100
|
|
SAR
|
|
---
|
|
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
```
|
|
11. ```
|
|
PUSH 0x0000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0x01
|
|
SAR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
12. ```
|
|
PUSH 0x4000000000000000000000000000000000000000000000000000000000000000
|
|
PUSH 0xfe
|
|
SAR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000001
|
|
```
|
|
13. ```
|
|
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0xf8
|
|
SAR
|
|
---
|
|
0x000000000000000000000000000000000000000000000000000000000000007f
|
|
```
|
|
14. ```
|
|
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0xfe
|
|
SAR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000001
|
|
```
|
|
15. ```
|
|
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0xff
|
|
SAR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
16. ```
|
|
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
PUSH 0x0100
|
|
SAR
|
|
---
|
|
0x0000000000000000000000000000000000000000000000000000000000000000
|
|
```
|
|
|
|
|
|
## Implementation
|
|
|
|
Client support:
|
|
- cpp-ethereum: https://github.com/ethereum/cpp-ethereum/pull/4054
|
|
|
|
Compiler support:
|
|
- Solidity/LLL: https://github.com/ethereum/solidity/pull/2541
|
|
|
|
## Tests
|
|
|
|
Sources:
|
|
- https://github.com/ethereum/tests/tree/develop/src/GeneralStateTestsFiller/stShift
|
|
|
|
Filled Tests:
|
|
- https://github.com/ethereum/tests/tree/develop/GeneralStateTests/stShift
|
|
- https://github.com/ethereum/tests/tree/develop/BlockchainTests/GeneralStateTests/stShift
|
|
|
|
## Copyright
|
|
|
|
Copyright and related rights waived via [CC0](../LICENSE.md).
|