예제 #1
0
    # Input vars
    X_short = BitVec('X', type_bits)
    Y_short = BitVec('Y', type_bits)

    # Z3's overflow and underflow conditions
    actual_overflow = Not(BVSubNoOverflow(X_short, Y_short))
    actual_underflow = Not(BVSubNoUnderflow(X_short, Y_short, True))

    # cast to full n_bits values
    X = BVSignedUpCast(X_short, n_bits)
    Y = BVSignedUpCast(Y_short, n_bits)
    diff = SUB(X, Y)

    # Constants
    maxValue = BVSignedMax(type_bits, n_bits)
    minValue = BVSignedMin(type_bits, n_bits)

    # Overflow and underflow checks in YulUtilFunction::overflowCheckedIntSubFunction
    if type_bits == 256:
        underflow_check = AND(ISZERO(SLT(Y, 0)), SGT(diff, X))
        overflow_check = AND(SLT(Y, 0), SLT(diff, X))
    else:
        underflow_check = SLT(diff, minValue)
        overflow_check = SGT(diff, maxValue)

    type_bits += 8

    rule.check(actual_underflow, underflow_check != 0)
    rule.check(actual_overflow, overflow_check != 0)
예제 #2
0
Requirements:
"""

rule = Rule()

n_bits = 256

# Input vars
X = BitVec('X', n_bits)
Y = BitVec('Y', n_bits)

# Constants
BitWidth = BitVecVal(n_bits, n_bits)

# Requirements

# Non optimized result
nonopt_1 = AND(AND(X, Y), Y)
nonopt_2 = AND(Y, AND(X, Y))
nonopt_3 = AND(AND(Y, X), Y)
nonopt_4 = AND(Y, AND(Y, X))

# Optimized result
opt_1 = AND(X, Y)
opt_2 = AND(Y, X)

rule.check(nonopt_1, opt_1)
rule.check(nonopt_2, opt_1)
rule.check(nonopt_3, opt_2)
rule.check(nonopt_4, opt_2)
예제 #3
0
from opcodes import BYTE
from rule import Rule
from z3 import BitVec, BitVecVal, Concat, Extract
"""
Checks that the byte opcode (implemented using shift) is equivalent to a
canonical definition of byte using extract.
"""

rule = Rule()

n_bits = 256
x = BitVec('X', n_bits)

for i in range(0, 32):
    # For Byte, i = 0 corresponds to most significant bit
    # But for extract i = 0 corresponds to the least significant bit
    lsb = 31 - i
    rule.check(
        BYTE(BitVecVal(i, n_bits), x),
        Concat(BitVecVal(0, n_bits - 8), Extract(8 * lsb + 7, 8 * lsb, x)))
예제 #4
0
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
Mask = SHL(B, A)
opt = AND(SHL(B, X), Mask)

rule.check(nonopt_1, opt)
rule.check(nonopt_2, opt)
예제 #5
0
from opcodes import SIGNEXTEND, AND
from rule import Rule
from z3 import BitVec, BitVecVal, ULT
"""
Rule:
AND(A, SIGNEXTEND(B, X)) -> AND(A, X)
given
    B < WordSize / 8 - 1 AND
    A & (1 << ((B + 1) * 8) - 1) == A
"""

n_bits = 128

# Input vars
X = BitVec('X', n_bits)
A = BitVec('A', n_bits)
B = BitVec('B', n_bits)

rule = Rule()
# Requirements
rule.require(ULT(B, BitVecVal(n_bits // 8 - 1, n_bits)))
rule.require((A & ((BitVecVal(1, n_bits) << ((B + 1) * 8)) - 1)) == A)
rule.check(AND(A, SIGNEXTEND(B, X)), AND(A, X))
예제 #6
0
from opcodes import BYTE, SHR, DIV
from rule import Rule
from z3 import BitVec, ULT
"""
byte(A, shr(B, X))
given A < B / 8
->
0
"""

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, SHR(B, X))
# Optimized result
opt = 0

rule.require(ULT(A, DIV(B, 8)))

rule.check(nonopt, opt)
예제 #7
0
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)))
예제 #8
0
from rule import Rule
from opcodes import *
"""
byte(A, X) -> 0
given A >= WordSize / 8
"""

rule = Rule()

n_bits = 256

# Input vars
X = BitVec('X', n_bits)
A = BitVec('A', n_bits)

rule.require(A >= n_bits / 8)
rule.check(BYTE(A, X), 0)
예제 #9
0
    X_short = BitVec('X', type_bits)
    Y_short = BitVec('Y', type_bits)

    # Z3's overflow and underflow conditions
    actual_overflow = Not(BVMulNoOverflow(X_short, Y_short, True))
    actual_underflow = Not(BVMulNoUnderflow(X_short, Y_short))

    # cast to full n_bits values
    X = BVSignedUpCast(X_short, n_bits)
    Y = BVSignedUpCast(Y_short, n_bits)

    # Constants
    maxValue = BVSignedMax(type_bits, n_bits)
    minValue = BVSignedMin(type_bits, n_bits)

    # Overflow and underflow checks in YulUtilFunction::overflowCheckedIntMulFunction
    overflow_check_1 = AND(AND(SGT(X, 0), SGT(Y, 0)), GT(X, DIV(maxValue, Y)))
    underflow_check_1 = AND(AND(SGT(X, 0), SLT(Y, 0)),
                            SLT(Y, SDIV(minValue, X)))
    underflow_check_2 = AND(AND(SLT(X, 0), SGT(Y, 0)),
                            SLT(X, SDIV(minValue, Y)))
    overflow_check_2 = AND(AND(SLT(X, 0), SLT(Y, 0)),
                           SLT(X, SDIV(maxValue, Y)))

    rule.check(actual_overflow, Or(overflow_check_1 != 0,
                                   overflow_check_2 != 0))
    rule.check(actual_underflow,
               Or(underflow_check_1 != 0, underflow_check_2 != 0))

    type_bits *= 2
예제 #10
0
from rule import Rule
from opcodes import *
"""
Rules:
SUB(SUB(X, A), Y) -> SUB(SUB(X, Y), A)
SUB(SUB(A, X), Y) -> SUB(A, ADD(X, Y))
SUB(X, SUB(Y, A)) -> ADD(SUB(X, Y), A)
SUB(X, SUB(A, Y)) -> ADD(ADD(X, Y), -A)
"""

rule = Rule()

n_bits = 256

# Input vars
X = BitVec('X', n_bits)
Y = BitVec('Y', n_bits)
A = BitVec('A', n_bits)

rule.check(SUB(SUB(X, A), Y), SUB(SUB(X, Y), A))
rule.check(SUB(SUB(A, X), Y), SUB(A, ADD(X, Y)))
rule.check(SUB(X, SUB(Y, A)), ADD(SUB(X, Y), A))
rule.check(SUB(X, SUB(A, Y)), ADD(ADD(X, Y), SUB(0, A)))
예제 #11
0
2) SIGNEXTEND(X, SIGNEXTEND(X, Y)) -> SIGNEXTEND(X, Y)

3) SIGNEXTEND(A, SIGNEXTEND(B, X)) -> SIGNEXTEND(min(A, B), X)
"""

n_bits = 128

# Input vars
X = BitVec('X', n_bits)
Y = BitVec('Y', n_bits)
A = BitVec('A', n_bits)
B = BitVec('B', n_bits)

rule1 = Rule()
# Requirements
rule1.require(UGE(A, BitVecVal(n_bits // 8 - 1, n_bits)))
rule1.check(SIGNEXTEND(A, X), X)

rule2 = Rule()
rule2.check(
    SIGNEXTEND(X, SIGNEXTEND(X, Y)),
    SIGNEXTEND(X, Y)
)

rule3 = Rule()
rule3.check(
    SIGNEXTEND(A, SIGNEXTEND(B, X)),
    SIGNEXTEND(If(ULT(A, B), A, B), X)
)

n_bits = 256

# Check that YulUtilFunction::cleanupFunction cleanup matches BVSignedCleanupFunction
for type_bits in range(8, 256, 8):

    rule = Rule()

    # Input vars
    X = BitVec('X', n_bits)
    arg = BitVecVal(type_bits / 8 - 1, n_bits)

    cleaned_reference = BVSignedCleanupFunction(X, type_bits)
    cleaned = SIGNEXTEND(arg, X)

    rule.check(cleaned, cleaned_reference)

# Check that BVSignedCleanupFunction properly cleans up values.
for type_bits in range(8, 256, 8):

    rule = Rule()

    # Input vars
    X_short = BitVec('X', type_bits)
    dirt = BitVec('dirt', n_bits - type_bits)

    X = BVSignedUpCast(X_short, n_bits)
    X_dirty = Concat(dirt, X_short)
    X_cleaned = BVSignedCleanupFunction(X_dirty, type_bits)

    rule.check(X, X_cleaned)
예제 #13
0
from rule import Rule
from opcodes import *
"""
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)))
예제 #14
0
from rule import Rule
from opcodes import *
"""
Checking the implementation of SIGNEXTEND using Z3's native SignExt and Extract
"""

rule = Rule()
n_bits = 256

x = BitVec('X', n_bits)


def SIGNEXTEND_native(i, x):
    return SignExt(256 - 8 * i - 8, Extract(8 * i + 7, 0, x))


for i in range(0, 32):
    rule.check(SIGNEXTEND(BitVecVal(i, n_bits), x), SIGNEXTEND_native(i, x))

i = BitVec('I', n_bits)
rule.require(UGT(i, BitVecVal(31, n_bits)))
rule.check(SIGNEXTEND(i, x), x)
예제 #15
0
from rule import Rule
from opcodes import *
"""
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))
예제 #16
0
from rule import Rule
from opcodes import *
from util import *
"""
Checking conversion of exp(-1, X) to sub(isZero(and(X, 1)), and(X, 1))
"""

rule = Rule()
n_bits = 256

X = BitVec('X', n_bits)

exp_neg_one = If(
    MOD(X, 2) == 0, BitVecVal(1, n_bits), BVUnsignedMax(n_bits, n_bits))

rule.check(SUB(ISZERO(AND(X, 1)), AND(X, 1)), exp_neg_one)
예제 #17
0
from opcodes import *
"""
Rule:
AND(OR(AND(X, A), Y), B) -> OR(AND(X, A & B), AND(Y, B))
"""

rule = Rule()

# bit width is irrelevant
n_bits = 128

# Input vars
X = BitVec('X', n_bits)
Y = BitVec('Y', n_bits)
A = BitVec('A', n_bits)
B = BitVec('B', n_bits)

# Non optimized result, explicit form
nonopt = AND(OR(AND(X, A), Y), B)

# Optimized result
opt = OR(AND(X, A & B), AND(Y, B))

rule.check(nonopt, opt)

# Now the forms as they are constructod in the code.
for inner in [AND(X, A), AND(A, X)]:
    for second in [OR(inner, Y), OR(Y, inner)]:
        rule.check(AND(second, B), opt)
        rule.check(AND(B, second), opt)
예제 #18
0
from rule import Rule
from opcodes import *
"""
Rule:
SIGNEXTEND(A, SHR(B, X)) -> SAR(B, X)
given
    B % 8 == 0 AND
    A <= WordSize AND
    B <= wordSize AND
    (WordSize - B) / 8 == A + 1
"""

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(B % 8 == 0)
rule.require(ULE(A, n_bits))
rule.require(ULE(B, n_bits))
rule.require((BitVecVal(n_bits, n_bits) - B) / 8 == A + 1)
rule.check(SIGNEXTEND(A, SHR(B, X)), SAR(B, X))
예제 #19
0
"""

# Approximation with 16-bit base types.
n_bits = 16
type_bits = 8

while type_bits <= n_bits:

    rule = Rule()

    # Input vars
    X_short = BitVec('X', type_bits)
    Y_short = BitVec('Y', type_bits)

    # Z3's overflow condition
    actual_overflow = Not(BVMulNoOverflow(X_short, Y_short, False))

    # cast to full n_bits values
    X = BVUnsignedUpCast(X_short, n_bits)
    Y = BVUnsignedUpCast(Y_short, n_bits)

    # Constants
    maxValue = BVUnsignedMax(type_bits, n_bits)

    # Overflow check in YulUtilFunction::overflowCheckedIntMulFunction
    overflow_check = AND(ISZERO(ISZERO(X)), GT(Y, DIV(maxValue, X)))

    rule.check(overflow_check != 0, actual_overflow)

    type_bits *= 2
예제 #20
0
	# Input vars
	X_short = BitVec('X', type_bits)
	Y_short = BitVec('Y', type_bits)

	# Z3's overflow and underflow conditions
	actual_overflow = Not(BVMulNoOverflow(X_short, Y_short, True))
	actual_underflow = Not(BVMulNoUnderflow(X_short, Y_short))

	# cast to full n_bits values
	X = BVSignedUpCast(X_short, n_bits)
	Y = BVSignedUpCast(Y_short, n_bits)
	product_raw = MUL(X, Y)
	#remove any overflown bits
	product = BVSignedCleanupFunction(product_raw, type_bits)

	# Constants
	min_value = BVSignedMin(type_bits, n_bits)

	# Overflow and underflow checks in YulUtilFunction::overflowCheckedIntMulFunction
	if type_bits > n_bits / 2:
		sol_overflow_check_1 = ISZERO(OR(ISZERO(X), EQ(Y, SDIV(product, X))))
		if type_bits == n_bits:
			sol_overflow_check_2 = AND(SLT(X, 0), EQ(Y, min_value))
			sol_overflow_check = Or(sol_overflow_check_1 != 0, sol_overflow_check_2 != 0)
		else:
			sol_overflow_check = (sol_overflow_check_1 != 0)
	else:
		sol_overflow_check = (ISZERO(EQ(product, product_raw)) != 0)

	rule.check(Or(actual_overflow, actual_underflow), sol_overflow_check)