EIP-145 EVM 비트 시프트 명령어 (Bitwise shifting instructions in EVM)

최종 확정 · EVM·실행 · 원문 상태 Final · 2017-02-13 작성

EVM에 비트 시프트 전용 명령어 SHL, SHR, SAR 세 개를 추가합니다. 산술 연산으로 흉내 낼 때 35가스가 들던 시프트 연산을 3가스에 처리합니다.

왜 필요한가

EVM(이더리움 가상머신, Ethereum Virtual Machine)은 스마트 컨트랙트 코드를 실행하는 엔진입니다. 그런데 AND, OR 같은 논리 연산과 곱셈, 나눗셈 같은 산술 연산은 지원하면서 정작 비트를 왼쪽이나 오른쪽으로 미는 시프트 연산 전용 명령어는 없었습니다. 시프트가 필요하면 2의 거듭제곱을 곱하거나 나누는 식으로 돌려서 구현해야 했습니다. 이렇게 하면 EVM을 실행하는 컴퓨터(호스트)가 일을 더 많이 하고 컨트랙트가 내는 수수료도 비싸집니다. 원문에 따르면 산술 연산으로 SHL과 SHR을 흉내 내면 각각 35가스가 들지만, 이 제안이 도입하는 전용 명령어는 3가스면 됩니다. 프로그래밍에서 아주 자주 쓰는 기본 연산을 다른 산술 연산과 비슷한 비용으로 쓸 수 있게 하자는 것이 이 제안의 출발점입니다.

무엇이 바뀌나

지금

EIP-145 이후

누구에게 영향이 있나

심층 설명

SHL(0x1b): 왼쪽 시프트

스택에서 arg1, arg2 순서로 두 값을 꺼내 arg2를 왼쪽으로 arg1비트 민 값을 올립니다. 결과는 (arg2 * 2^arg1) mod 2^256입니다. 값(arg2)과 시프트 양(arg1) 모두 부호 없는 수로 해석합니다. arg1이 256 이상이면 결과는 0입니다. 기존 명령어 조합 PUSH1 2 EXP MUL과 동등합니다.

SHR(0x1c): 논리 오른쪽 시프트

arg2를 오른쪽으로 arg1비트 밀고 비는 상위 비트를 0으로 채웁니다. 결과는 floor(arg2 / 2^arg1)입니다. 두 피연산자 모두 부호 없는 수로 해석하고, arg1이 256 이상이면 결과는 0입니다. PUSH1 2 EXP DIV와 동등합니다.

SAR(0x1d): 산술 오른쪽 시프트

arg2를 오른쪽으로 arg1비트 밀되 부호 확장을 합니다. 즉 arg2를 부호 있는 수로 해석해 음수면 비는 상위 비트를 1로 채웁니다. 결과는 floor(arg2 / 2^arg1)입니다. arg1이 256 이상이면 arg2가 0 이상일 때 0, 음수일 때 -1이 됩니다. PUSH1 2 EXP SDIV와는 동등하지 않습니다. 반올림 방향이 다르기 때문인데, SDIV(-1, 2)는 0이지만 SAR(-1, 1)은 -1입니다.

가스 비용: verylow 등급 3가스

세 시프트 명령어의 비용은 모두 verylow 등급인 3가스로 정해졌습니다. 기존에 산술 연산으로 SHL과 SHR을 구현하면 각각 35가스가 들었으므로 10배 이상 저렴해집니다. 호스트 입장에서도 산술 연산 조합보다 처리 효율이 높습니다.

피연산자 순서가 산술 명령어와 반대인 이유

스택 위에 이미 올라와 있는 값을 미는 쪽이 더 자연스러운 사용 패턴이라서 시프트 양(arg1)을 먼저 꺼내고 값(arg2)을 나중에 꺼내도록 설계했습니다. 그래서 대부분의 산술 명령어와 비교하면 피연산자 순서가 뒤바뀌어 있습니다.

호환성과 구현 현황

새 명령어는 과거에 만들어진 바이트코드에 아무 영향을 주지 않으므로 하위 호환성 문제가 없습니다. 상태는 Final로 확정되었습니다. 원문에는 클라이언트 구현(cpp-ethereum), 컴파일러 지원(Solidity/LLL), 그리고 ethereum/tests 저장소의 stShift 공용 테스트가 링크되어 있고 SHL 11개, SHR 11개, SAR 16개의 테스트 케이스가 본문에 실려 있습니다.

EIP 원문 · ← EIPs