Part III · Chapter 13 of 43 · Constantinople

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.

Updated Jul 2, 2026 · 6 min
Assumed
  • 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.

1 step Shifting with arithmetic

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.

the EVM had AND/OR/XOR/NOT — but no shift shift left 00010110 a multiply/divide + a pushed constant, for a basic bit shift and DIV can't do a correct signed (arithmetic) right shift a fundamental CPU operation, simulated with arithmetic
The EVM had AND/OR/XOR/NOT but no shift, so contracts emulated a left shift as MUL by 2ⁿ and a right shift as DIV by 2ⁿ — paying for a multiply/divide plus pushing the constant. And DIV can't express a correct arithmetic (sign-preserving) right shift. A basic CPU operation, simulated with arithmetic.

→ Step 2: add the three shifts directly.

2 step SHL, SHR, SAR

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.

EIP-145: three native shift opcodes input output SHL left 0 1 1 0 1 0 1 1 0 1 0 0 SHR logical 0 1 1 0 1 0 0 0 1 1 0 1 SAR signed 1 0 1 1 0 0 1 1 0 1 1 0 SAR keeps the sign bit (orange) — signed shifts finally correct
EIP-145 adds SHL (left), SHR (logical right), and SAR (arithmetic, sign-preserving right). Each pops the amount and value and shifts directly at 3 gas, with no constant to push — and SAR finally gives a correct signed right shift.

→ Step 3: everything that shifts bits gets leaner.

3 step Leaner bit-twiddling

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.

every shift gets cheaper and smaller PUSH1 0x10 MUL SHL packing structs, bitmaps, fixed-point, cryptography — all leaner compilers emit them; the same 'add the missing primitive' story
Native shifts make packing, bitmaps, fixed-point math, and cryptography cheaper and smaller, and give a correct signed shift via SAR. Compilers emit them automatically — the same 'add the missing primitive' story as PUSH0 and MCOPY.
04 Go Deeper Where to take it from here