DIV(X, A) -> SHR(k, X) Requirements: A == 1 << K """ rule = Rule() n_bits = 32 # Input vars X = BitVec('X', n_bits) A = BitVec('A', n_bits) K = BitVec('K', n_bits) # Requirements rule.require(A == SHL(K, 1)) # Non optimized result nonopt_1 = MUL(X, A) nonopt_2 = MUL(A, X) nonopt_3 = DIV(X, A) # Optimized result opt_1 = SHL(K, X) opt_2 = SHL(K, X) opt_3 = SHR(K, X) rule.check(nonopt_1, opt_1) rule.check(nonopt_2, opt_2) rule.check(nonopt_3, opt_3)
from opcodes import AND, SHL from rule import Rule from z3 import BitVec, BitVecVal, ULT """ Rule: SHL(B, AND(X, A)) -> AND(SHL(B, X), A << B) SHL(B, AND(A, X)) -> AND(SHL(B, X), A << B) Requirements: B < BitWidth """ rule = Rule() n_bits = 128 # Input vars X = BitVec('X', n_bits) A = BitVec('A', n_bits) B = BitVec('B', n_bits) # Constants BitWidth = BitVecVal(n_bits, n_bits) # Requirements rule.require(ULT(B, BitWidth)) # Non optimized result nonopt_1 = SHL(B, AND(X, A)) nonopt_2 = SHL(B, AND(A, X)) # Optimized result
from opcodes import DIV, SHL, SHR from rule import Rule from z3 import BitVec """ Rule: DIV(X, SHL(Y, 1)) -> SHR(Y, X) Requirements: """ rule = Rule() n_bits = 32 # Input vars X = BitVec('X', n_bits) Y = BitVec('Y', n_bits) # Non optimized result nonopt = DIV(X, SHL(Y, 1)) # Optimized result opt = SHR(Y, X) rule.check(nonopt, opt)
from opcodes import SHL, MUL from rule import Rule from z3 import BitVec """ Rule: MUL(X, SHL(Y, 1)) -> SHL(Y, X) MUL(SHL(X, 1), Y) -> SHL(X, Y) Requirements: """ rule = Rule() n_bits = 64 # Input vars X = BitVec('X', n_bits) Y = BitVec('Y', n_bits) # Requirements # Non optimized result nonopt_1 = MUL(X, SHL(Y, 1)) nonopt_2 = MUL(SHL(X, 1), Y) # Optimized result opt_1 = SHL(Y, X) opt_2 = SHL(X, Y) rule.check(nonopt_1, opt_1) rule.check(nonopt_2, opt_2)
n_bits = 64 # Input vars X = BitVec('X', n_bits) A = BitVec('A', n_bits) B = BitVec('B', n_bits) # Constants BitWidth = BitVecVal(n_bits, n_bits) # Requirements rule.require(ULT(A, BitWidth)) rule.require(ULT(B, BitWidth)) # Non optimized result nonopt = SHR(B, SHL(A, X)) # Optimized result Mask = SHR(B, SHL(A, Int2BV(IntVal(-1), n_bits))) opt = If( UGT(A, B), AND(SHL(A - B, X), Mask), If( UGT(B, A), AND(SHR(B - A, X), Mask), AND(X, Mask) ) ) rule.check(nonopt, opt)
from opcodes import SHL from rule import Rule from z3 import BitVec, BV2Int, Int2BV, IntVal """ Shift left workaround that Solidity implements due to a bug in Boost. """ rule = Rule() n_bits = 8 bigint_bits = 16 # Input vars X = BitVec('X', n_bits) A = BitVec('A', n_bits) B = BitVec('B', bigint_bits) # Compute workaround workaround = Int2BV( BV2Int((Int2BV(BV2Int(X), bigint_bits) << Int2BV(BV2Int(A), bigint_bits)) & Int2BV(BV2Int(Int2BV(IntVal(-1), n_bits)), bigint_bits)), n_bits) rule.check(workaround, SHL(A, X))
from opcodes import BYTE, SHL from rule import Rule from z3 import BitVec, ULE """ byte(A, shl(B, X)) given B % 8 == 0 && A <= 32 && B <= 256 -> byte(A + B / 8, X) """ rule = Rule() n_bits = 256 # Input vars X = BitVec('X', n_bits) A = BitVec('A', n_bits) B = BitVec('B', n_bits) # Non optimized result nonopt = BYTE(A, SHL(B, X)) # Optimized result opt = BYTE(A + B / 8, X) rule.require(B % 8 == 0) rule.require(ULE(A, 32)) rule.require(ULE(B, 256)) rule.check(nonopt, opt)
from opcodes import SHL, SIGNEXTEND from rule import Rule from z3 import BitVec, LShR, ULE """ Rule: SHL(A, SIGNEXTEND(B, X)) -> SIGNEXTEND((A >> 3) + B, SHL(A, X)) given return A & 7 == 0 AND A <= WordSize AND B <= WordSize / 8 """ n_bits = 256 # Input vars X = BitVec('X', n_bits) Y = BitVec('Y', n_bits) A = BitVec('A', n_bits) B = BitVec('B', n_bits) rule = Rule() rule.require(A & 7 == 0) rule.require(ULE(A, n_bits)) rule.require(ULE(B, n_bits / 8)) rule.check(SHL(A, SIGNEXTEND(B, X)), SIGNEXTEND(LShR(A, 3) + B, SHL(A, X)))
from opcodes import SHL from rule import Rule from z3 import BitVec, If """ Checking conversion of exp(2, X) to shl(X, 1) """ rule = Rule() n_bits = 256 # Proof of exp(2, X) = shl(X, 1) by induction: # # Base case: X = 0, exp(2, 0) = 1 = 1 = shl(0, 1) # Inductive step: assuming exp(2, X) = shl(X, 1) for X <= N # to prove: exp(2, N + 1) = shl(N + 1, 1) # # Notice that exp(2, N + 1) = 2 * exp(2, N) mod 2**256 # since exp(2, N) = shl(N, 1), it is enough to show that # 2 * shl(N, 1) mod 2**256 = shl(N + 1, 1) # # Also note that N + 1 < 2**256 N = BitVec('N', n_bits) inductive_step = 2 * SHL(N, 1) rule.check(inductive_step, If(N == 2**256 - 1, 0, SHL(N + 1, 1)))