EIP-145: giving a 256-bit machine a shift instruction
The EVM had AND, OR, XOR, and NOT from day one — but no bit-shift. Contracts faked shifting with multiplication and division by powers of two: costlier, bulkier, and unable to shift signed numbers correctly. EIP-145 adds native SHL, SHR, and SAR.
- the EVM's word & bitwise operations
Constantinople, February 2019. The EVM works in 256-bit words and, since genesis, has had the usual bitwise operators — AND, OR, XOR, NOT. But it was missing one that any assembly programmer would reach for immediately: the bit shift. Shifting bits left or right is how you pack several fields into one word, walk a bitmap, do fixed-point arithmetic, or implement a hash. On a machine built around 256-bit words, its absence is conspicuous — and the workaround was to press arithmetic into service. EIP-145 finally gives the machine the instruction it should have had all along. Let’s derive it.
The problem: no shift, so multiply and divide instead
Without a shift opcode, contracts leaned on a number-theory identity: shifting left by n bits is the same as multiplying by 2ⁿ, and shifting right by n is dividing by 2ⁿ. So a left shift became a MUL and a right shift a DIV — each of which also requires first pushing the 2ⁿ constant onto the stack, adding bytecode and gas. It works for unsigned values, but it’s the long way round for something a CPU does in one cycle. Worse, there was no clean way to express an arithmetic right shift A right shift that preserves the sign bit, so shifting a negative number right keeps it negative (equivalent to floor-dividing by a power of two). DIV rounds toward zero rather than flooring, so it can't reproduce a correct signed shift — you had to special-case the sign by hand. : DIV rounds toward zero, not toward negative infinity, so shifting a signed (negative) number right gave the wrong result unless you special-cased the sign yourself.
→ Step 2: add the three shifts directly.
EIP-145: three native shift opcodes
The fix adds exactly the three shifts a signed/unsigned machine needs. SHL Shift Left (0x1b): pops a shift amount and a value, shifts the value left by that many bits, filling with zeros. Equivalent to the old MUL-by-2ⁿ, but one native instruction at 3 gas. (0x1b) shifts left; SHR Logical Shift Right (0x1c): shifts right, filling the top with zeros — the unsigned right shift, equivalent to DIV-by-2ⁿ for non-negative values. (0x1c) is the logical (zero-filling) right shift; and SAR Arithmetic Shift Right (0x1d): shifts right while preserving the sign bit, so negative numbers stay negative (floor-division semantics). This is the operation DIV could never express cleanly. (0x1d) is the arithmetic (sign-preserving) right shift that the old DIV trick couldn’t do. Each pops a shift amount and a value, shifts directly, and costs the base 3 gas like the other bitwise ops — no MUL/DIV, no constant to push.
→ Step 3: everything that shifts bits gets leaner.
The payoff: cheaper, smaller, and correct
Bit shifting is everywhere below the surface — packing multiple values into one 256-bit slot, reading and writing bitmaps, fixed-point math, and especially cryptographic routines that shuffle bits by the thousand. Making it a single 3-gas instruction (instead of a MUL/DIV plus a pushed constant) trims gas and bytecode across all of it, and SAR removes a whole class of signed-shift bugs. As with every “missing primitive” EIP — PUSH0, MCOPY — the win is quiet and automatic: compilers emit the new opcodes wherever they used to emit the arithmetic workaround, so contracts get cheaper and smaller just by recompiling.