Ejemplo n.º 1
0
 def CALLDATACOPY(self, gstate, dest_offset, offset, length):
     length_concrete = svm_utils.is_bv_concrete(length)
     if not length_concrete:
         logging.warning('Symbolic calldata size')
         length = z3.BitVecVal(64, 256)
     if gstate.environment.calldata_type == CalldataType.UNDEFINED:
         length = svm_utils.get_concrete_int(length)
         if svm_utils.is_bv_concrete(offset):
             offset = svm_utils.get_concrete_int(offset)
             for i in range(length):
                 data_word = self.svm.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA,
                                                                      gstate.wstate.gen,
                                                                      index=offset+(i//32))
                 slot = i % 32
                 data_bytes = svm_utils.split_bv_into_bytes(data_word)
                 data = data_bytes[slot]
                 gstate.mstate.memory = z3.Store(gstate.mstate.memory, dest_offset+i, data)
         else:
             for i in range(length):
                 data = self.svm.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA,
                                                                 gstate.wstate.gen,
                                                                 unique=True,
                                                                 bv_size=8)
                 gstate.mstate.memory = z3.Store(gstate.mstate.memory, dest_offset+i, data)
     elif gstate.environment.calldata_type == CalldataType.DEFINED:
         length = svm_utils.get_concrete_int(length)
         offset_concrete = svm_utils.is_bv_concrete(offset)
         calldata_bytes = svm_utils.split_bv_into_bytes(gstate.environment.calldata)
         offset_concrete = svm_utils.is_bv_concrete(offset)
         for i in range(length):
             gstate.mstate.memory = z3.Store(gstate.mstate.memory, dest_offset+i, calldata_bytes[offset_concrete+i])
     else:
         raise SVMRuntimeError('Unknown calldata type')
def opcode_return_data_copy(returndata,
                            memory,
                            target_memory,
                            return_offset,
                            return_length=32):
    if not is_z3_express(return_length):
        for i in range(format_to_int(return_length)):
            index = opcode_add(return_length, i)
            pos = opcode_add(target_memory, i)
            memory = z3.Store(memory, pos, returndata[index])

        return z3.simplify(memory)

    for i in range(opcode_memory.LENGTH):
        check_write_express = z3.And(i >= target_memory,
                                     i < target_memory + return_length)

        pos = z3.If(check_write_express, return_offset + i - target_memory, -1)

        check_get_calldata = z3.If(pos > opcode_call_data_config.LENGTH, 0,
                                   returndata[pos])

        get_data = z3.If(check_write_express, check_get_calldata, memory[i])

        memory = z3.Store(memory, i, get_data)

    return z3.simplify(memory)
Ejemplo n.º 3
0
    def ConditionalStore(self, index, value, cond):
        if isinstance(index, int):
            index = BVV(index, self.index_width)
        else:
            assert index.size == self.index_width
        if isinstance(value, int):
            value = BVV(value, self.value_width)
        else:
            assert value.size == self.value_width
        if isinstance(cond, bool):
            cond = BoolV(cond)

        if isinstance(cond, BoolV):
            if cond.value:
                self.Store(index, value)
            return

        if (self._conc_store is not None and isinstance(index, BVV)
                and index.value in self._conc_store
                and self._conc_store[index.value].eq(value)):
            # the condition is symbolic, but the value is already in memory
            # we can safetely skip the store
            return

        self._switch_to_symbolic()
        self._z3obj = z3.If(cond.z3obj,
                            z3.Store(self._z3obj, index.z3obj, value.z3obj),
                            self._z3obj)
        # this can be quite inefficient.
        # Let's try to simplfy the expression.
        self._z3obj = z3.simplify(self._z3obj)
Ejemplo n.º 4
0
    def getEq(self, mvars):

        r = []

        #print self.src, self.dst

        if (self.src.isReg()):
            src = self.src.name
        #  self.src.size = self.size
        #  srcs = self.getOperands([self.src])
        #  print srcs
        else:
            assert (0)

        old_sname, new_sname, offset = Memvars.write(self.dst)

        old_array = mkArray(old_sname)
        array = mkArray(new_sname)

        for i in range(self.size):

            dst_op = Operand(self.dst.mem_source + "@" + str(offset + i),
                             "BYTE")
            src_var = z3.BitVec(src + ":" + str(i) + "(0)", 8)

            if (dst_op in mvars):
                array = z3.Store(array, offset + i, src_var)

            r.append(src_var <> 0)

        r.append((old_array == array))

        return r
Ejemplo n.º 5
0
    def getEq(self):

        src = self.read_operands[0]

        if src.isVar():
            srcs = mkByteListVar(src)
        else:
            srcs = mkByteListConst(src)

        #endianness
        srcs.reverse()

        dst = self.write_operands[0]
        dsts = dst.getLocations()

        conds = []

        old_sname, new_sname = Memvars.write(dsts[0])

        #array = mkArray(old_sname)
        #new_array = mkArray(new_sname)

        old_array = mkArray(old_sname)
        array = mkArray(new_sname)

        for (src, dst) in zip(srcs, dsts):
            array = z3.Store(array, dst.getIndex(), src)

        conds = [(old_array == array)]

        return conds
Ejemplo n.º 6
0
    def getEq(self):

        src = (self.read_operands)[0]
        if src.isVar():
            srcs = map(lambda b: z3.BitVec(b, 8), src.get_bytes())
        else:
            srcs = map(lambda b: z3.BitVecVal(int(b, 16), 8), src.get_bytes())

        srcs.reverse()

        conds = []
        offset = Memvars.getOffset(self.write_operands[0])
        old_sname, new_sname, offset = Memvars.write(self.write_operands[0])

        old_array = mkArray(old_sname)
        array = mkArray(new_sname)

        #for (i,src) in zip(range(offset,offset-(src.size),-1), srcs):
        #for (i,src) in zip(range(offset,offset+(src.size)+1), srcs):
        for (i, src) in zip(range(src.size), srcs):
            array = z3.Store(array, offset + i, src)

        conds = [(old_array == array)]

        return conds
Ejemplo n.º 7
0
    def getEq(self, mlocs):

        src = InputOp("stdin", 1)
        src.size_in_bytes = self.size

        srcs = mkByteListVar(src)

        dst = self.dst  #self.func.write_operands[0]
        dsts = dst.getLocations()

        conds = []

        old_sname, new_sname = Memvars.write(dsts[0])

        #array = mkArray(old_sname)
        #new_array = mkArray(new_sname)

        old_array = mkArray(old_sname)
        array = mkArray(new_sname)

        for (src, dst) in zip(srcs, dsts):
            if dst in mlocs:
                array = z3.Store(array, dst.getIndex(), src)

            conds.append(src <> 10)
            conds.append(src <> 0)

        conds.append((old_array == array))
        return conds
Ejemplo n.º 8
0
    def Store(self, index, value):
        if isinstance(index, int):
            index = BVV(index, self.index_width)
        else:
            assert index.size == self.index_width
        if isinstance(value, int):
            value = BVV(value, self.value_width)
        else:
            assert value.size == self.value_width
        
        # invalidate cache
        self._z3objConcCache = None

        if (
            isinstance(index, BVV) and 
            self._conc_store is not None
        ):
            # concrete mode
            self._conc_store[index.value] = value
        else:
            # symbolic mode
            self._switch_to_symbolic()
            self._z3obj = z3.Store(
                self._z3obj,
                index.z3obj,
                value.z3obj
            )
Ejemplo n.º 9
0
 def RETURNDATACOPY(self, gstate, dest_offset, offset, length):
     offset = svm_utils.get_concrete_int(offset)
     length = svm_utils.get_concrete_int(length)
     if length == 0:
         return
     return_data_bytes = svm_utils.split_bv_into_bytes(gstate.return_data)
     for i in range(length):
         gstate.mstate.memory = z3.Store(gstate.mstate.memory, dest_offset+i, return_data_bytes[offset+i])
Ejemplo n.º 10
0
 def MSTORE(self, gstate, index, value):
     if isinstance(value, z3.BoolRef):
         value = z3.If(value, z3.BitVecVal(1, 256), z3.BitVecVal(0, 256))
     value_bytes = svm_utils.split_bv_into_bytes(value)
     for i in range(32):
         if svm_utils.is_bv_concrete(index):
             gstate.mstate.memory_dict[svm_utils.get_concrete_int(index)+i] = value_bytes[i]
         gstate.mstate.memory = z3.Store(gstate.mstate.memory, index+i, value_bytes[i])
Ejemplo n.º 11
0
Archivo: mem.py Proyecto: tcrs/evm-sym
 def overlay(self, chunk, base_off, chunk_off, length):
     slen = z3.simplify(length)
     if z3.is_bv_value(slen):
         for i in range(slen.as_long()):
             if isinstance(chunk, Memory):
                 sel = chunk.select(chunk_off + i)
             else:
                 sel = z3.Select(chunk, chunk_off + i)
             self._mem = z3.Store(self._mem, base_off + i, sel)
     else:
         if self._idx is None:
             self._idx = z3.BitVec('idx', 256)
         if isinstance(chunk, Memory):
             chunk_val = chunk.select(self._idx - base_off + chunk_off)
         else:
             chunk_val = z3.Select(chunk, self._idx - base_off + chunk_off)
         self._mem = z3.If(
             z3.And(self._idx >= base_off, self._idx < base_off + length),
             z3.Store(state.MemoryEmpty, self._idx, chunk_val), self._mem)
Ejemplo n.º 12
0
def z3_set_memory(memory, address, value, arch):
  size = value.size()
  num_bytes = size/8
  new_memory = memory
  for i in range(0, num_bytes):
    if arch.memory_endness == 'Iend_LE':
      upper = ((i + 1) * 8) - 1
    else:
      upper = ((num_bytes - i) * 8) - 1
    new_memory = z3.Store(new_memory, address + i, z3.Extract(upper, upper - 7, value))
  return new_memory
Ejemplo n.º 13
0
    def _switch_to_symbolic(self):
        if self._conc_store is not None:
            assert self._z3obj is None
            self._z3obj = z3.Array(self.name, z3.BitVecSort(self.index_width),
                                   z3.BitVecSort(self.value_width))
            for index in self._conc_store:
                self._z3obj = z3.Store(self._z3obj,
                                       z3.BitVecVal(index, self.index_width),
                                       self._conc_store[index].z3obj)

            self._conc_store = None
Ejemplo n.º 14
0
def f2():
    a, b, c, d = z3.BitVecs('a b c d', 3)  # 4 bitvectors variable

    tuple = z3.Datatype('tuple')  # new data type 'tuple'
    tuple.declare(
        'tuple', ('f1', z3.BitVecSort(3)),
        ('f2', z3.BitVecSort(3)))  # f1, f2 are for accessing element in tuples
    tuple = tuple.create()
    tuple1 = tuple.tuple(a, b)  # tuple1 -> (a, b)
    tuple2 = tuple.tuple(b, c)  # tuple2 -> (b, c)

    tuple1_f2 = tuple.f2(tuple1)  # a
    #tuple1_f2 = tuple.f2(tuple1) # b
    tuple2_f1 = tuple.f1(tuple2)  # c

    print(tuple1_f2, tuple2_f1)

    if (tuple1_f2 == tuple2_f1):
        print("hi")

    arr0 = z3.K(tuple, False)  # arr0 -> arr0[tuple]  = false
    arr1 = z3.Store(arr0, tuple1, True)  # arr1 -> arr0[tuple1] = true
    arr2 = z3.Store(arr1, tuple2, True)  # arr  -> arr0[tuple2] = true
    print(arr0)
    print(arr1)
    print(arr2)

    #print(arr1[tuple1])
    #print(arr2[tuple2])

    #print(arr0)
    #print(arr1)
    #print(arr2)

    s = z3.Solver()

    s.add(tuple1_f1 == tuple2_f2)  # a = c
    s.add(tuple1_f1 == tuple1_f2)  # a = b
Ejemplo n.º 15
0
    def _try_build_reduced_array(self, index_min, index_max):
        if self._z3obj is not None:
            # symbolic mode
            return self._z3obj
        if index_max - index_min >= 2**self.index_width:
            return self.z3obj

        res = z3.Array(self.name, z3.BitVecSort(self.index_width),
                       z3.BitVecSort(self.value_width))
        for i in range(index_min, index_max + 1):
            if i in self._conc_store:
                res = z3.Store(res, z3.BitVecVal(i, self.index_width),
                               self._conc_store[i].z3obj)
        return res
Ejemplo n.º 16
0
def get_z3_equality_list(stmt_node, z3_vars, direct_equality= False):
    global all_z3_vars
    z3_asserts = []
    if not direct_equality:
        stmt_node = stmt_node.children[0]  ## get the equalitystmt first

    left = stmt_node.children[0]
    right = stmt_node.children[1]
    zright = get_z3_expr(right, z3_vars)

    name = "stmt_rhs_{}".format(stmt_node.line)
    i = 0
    temp_name = name
    while (temp_name in all_z3_vars):
        temp_name = name + "_" + str(i)
        i += 1
    name = temp_name
    zright_temp = z3.Int(name)  
    z3_asserts.append(zright_temp == zright)
    all_z3_vars[name] = zright_temp

    if left.data == "select":
        # we need to update the z3_vars
        array_name = left.children[0].children[0].value
        current_label = z3_vars[array_name][1]
        current_array = z3_vars[array_name][0]
        new_label = current_label + 1
        new_name = "{}_{}".format(array_name, new_label)
        new_array = z3.Array(new_name, z3.IntSort(), z3.IntSort())
        all_z3_vars[new_name] = new_array
        if (left.children[1].data == "var"):
            index = z3_vars[left.children[1].children[0].value][0]
        else: #left children is num
            index = left.children[1].children[0].value

        store = z3.Store(current_array, index, zright_temp)
        z3_vars[array_name] = (new_array, new_label)
        z3_asserts.append(new_array == store)  #LHS equal to new variable

    if left.data == "var":
        var_name = left.children[0].value
        var_label = z3_vars[var_name][1]
        new_name = "{}_{}".format(var_name, var_label+1)
        new_var = z3.Int(new_name)
        all_z3_vars[new_name] = new_var # add the new variable to global list
        z3_vars[var_name] = (new_var, var_label + 1)
        z3_asserts.append(new_var == zright_temp)
    
    return [(assertion, stmt_node) for assertion in z3_asserts]
def opcode_init_call_data(calldata, init_data):
    if init_data[:2] == '0x':
        init_data = init_data[2:]

    length = len(init_data) / 2
    low = 0
    high = low + 2

    for i in range(length):
        data = int(init_data[low:high], 16)
        calldata = z3.Store(calldata, i, z3.BitVecVal(data, 8))
        low += 2
        high = low + 2

    return z3.simplify(calldata)
Ejemplo n.º 18
0
    def z3obj(self):
        if self._z3obj is not None:
            # symbolic mode
            return self._z3obj

        # concrete mode
        if self._z3objConcCache is not None:
            return self._z3objConcCache
        res = z3.Array(self.name, z3.BitVecSort(self.index_width),
                       z3.BitVecSort(self.value_width))
        for index in self._conc_store:
            res = z3.Store(res, z3.BitVecVal(index, self.index_width),
                           self._conc_store[index].z3obj)
        self._z3objConcCache = res
        return res
Ejemplo n.º 19
0
def main():
    b, c = z3.Ints("b c")
    a = z3.Array("a", z3.IntSort(), z3.IntSort())
    f = z3.Function("f", z3.IntSort(), z3.IntSort())
    solver = z3.Solver()
    solver.add(c == b + z3.IntVal(2))
    lhs = f(z3.Store(a, b, 3)[c - 2])
    rhs = f(c - b + 1)
    solver.add(lhs != rhs)
    res = solver.check()
    if res == z3.sat:
        print("sat")
    elif res == z3.unsat:
        print("unsat")
    else:
        print("unknown")
Ejemplo n.º 20
0
def main():
    b, c = z3.Ints('b c')
    a = z3.Array('a', z3.IntSort(), z3.IntSort())
    f = z3.Function('f', z3.IntSort(), z3.IntSort())
    solver = z3.Solver()
    solver.add(c == b + z3.IntVal(2))
    lhs = f(z3.Store(a, b, 3)[c - 2])
    rhs = f(c - b + 1)
    solver.add(lhs <> rhs)
    res = solver.check()
    if res == z3.sat:
        print 'sat'
    elif res == z3.unsat:
        print 'unsat'
    else:
        print 'unknown'
Ejemplo n.º 21
0
    def CODECOPY(self, gstate, dest_offset, offset, length):
        active_address = gstate.environment.active_address
        active_account = gstate.wstate.address_to_account[active_address]

        offset = svm_utils.get_concrete_int(offset)
        if svm_utils.is_bv_concrete(length):
            length = svm_utils.get_concrete_int(length)
        else:
            length = 0
        assert isinstance(gstate.environment.runtime_bytecode_bytes, list)
        bytecode_bytes = gstate.environment.runtime_bytecode_bytes
        for i in range(length):
            if offset + i < len(bytecode_bytes):
                data_byte = bytecode_bytes[offset+i]
            else:
                data_byte = z3.BitVecVal(0, 8)
            gstate.mstate.memory = z3.Store(gstate.mstate.memory, dest_offset+i, data_byte)
            gstate.mstate.memory_dict[svm_utils.get_concrete_int(dest_offset+i)] = data_byte
Ejemplo n.º 22
0
    def proc_apply(self, expr, state):
        f = self.context.reduce(expr['func'])
        args = expr['args']
        if f['what'] == 'expr:special':
            if f['id'] == 'gmap_lookup':
                state, k = self.proc(args[0], state)
                state, m = self.proc(args[1], state)
                return state, m[k]
            elif f['id'] == 'map_insert':
                state, k = self.proc(args[0], state)
                state, v = self.proc(args[1], state)
                state, m = self.proc(args[2], state)

                rangesort = m.range()
                vsome = constructor_by_name(rangesort, "Some")(v)

                return state, z3.Store(m, k, vsome)
            elif f['id'] == 'len_buf':
                state, buf = self.proc(args[0], state)
                return state, z3.Int2BV(z3.Length(buf), 64)
            elif f['id'] == 'resize_buf':
                state, newlen = self.proc(args[0], state)
                state, buf = self.proc(args[1], state)
                ## XXX should be of length newlen, not empty..
                return state, z3.Empty(buf.sort())
            elif f['id'] == 'uint64_gt':
                state, a0 = self.proc(args[0], state)
                state, a1 = self.proc(args[1], state)
                return state, z3.If(a0 > a1,
                                    self.bool_sort.constructor(0)(),
                                    self.bool_sort.constructor(1)())
            elif f['id'] == 'eqDec_time':
                state, a0 = self.proc(args[0], state)
                state, a1 = self.proc(args[1], state)
                return state, z3.If(a0 == a1,
                                    self.sumbool_sort.constructor(0)(),
                                    self.sumbool_sort.constructor(1)())
            else:
                raise Exception('unknown special function', f['id'])
        else:
            print expr
            raise Exception('unknown apply on', f['what'])
Ejemplo n.º 23
0
def mk_eqs_from_model(m, consts, model_completion=False):
    eqs = []
    for const in consts:
        # treat arrays specially due to the else_value
        sort = const.sort()
        if isinstance(sort, z3.ArraySortRef):
            val_interp = m[const]
            if (val_interp is not None) and isinstance(val_interp,
                                                       z3.FuncInterp):
                idx_sort = sort.domain()
                val_sort = sort.range()
                val = z3.K(val_sort, val_interp.else_value())
                for i in range(val_interp.num_entries()):
                    entry = val_interp.entry(i)
                    val = z3.Store(val, entry.arg_value(0), entry.value())
            else:
                val = m.eval(const, model_completion=model_completion)
        else:
            val = m.eval(const, model_completion=model_completion)
        eqs.append(const == val)
    return eqs
def opcode_write_memory(memory, offset, data, length=32):
    parts = []
    if not is_z3_express(length):
        length = format_to_int(length)
        for i in range(length):
            index = opcode_add(offset, i)

            if type(data) == list:
                write_data = z3.BitVecVal(data[i], 8)
            else:
                high = (length - i) * 8 - 1
                low = high - 7
                write_data = z3.Extract(high, low, data)

            memory = z3.Store(memory, index, write_data)

        return z3.simplify(memory)

    print length
    exit()
    return z3.Concat(parts)
Ejemplo n.º 25
0
    def getEq(self, mvars):

        r = []

        old_sname, new_sname, offset = Memvars.write(self.dst)

        old_array = mkArray(old_sname)
        array = mkArray(new_sname)

        for i in range(self.size):

            op = Operand(self.dst.mem_source + "@" + str(offset + i), "BYTE")

            if (op in mvars):
                array = z3.Store(array, offset + i,
                                 z3.BitVec("stdin:" + str(i) + "(0)", 8))

            r.append(z3.BitVec("stdin:" + str(i) + "(0)", 8) <> 10)
            r.append(z3.BitVec("stdin:" + str(i) + "(0)", 8) <> 0)

        r.append((old_array == array))

        return r
Ejemplo n.º 26
0
    def __setitem__(self, key: BitVec, value: BitVec) -> None:
        """Sets an item in the array, key can be symbolic."""
        if isinstance(value, Bool):
            value = If(value, 1, 0)

        self.raw = z3.Store(self.raw, key.raw, value.raw)  # type: ignore
Ejemplo n.º 27
0
def mem_from_str(text, base=symevm.state.MemoryEmpty):
    b = symevm.util.hex_to_bytes(text)
    m = base
    for i, v in enumerate(b):
        m = z3.Store(m, z3.BitVecVal(i, 256), z3.BitVecVal(v, 8))
    return symevm.mem.Memory(base=m), len(b)
Ejemplo n.º 28
0
    def proc_apply(self, expr, state):
        f = self.context.reduce(expr['func'])
        args = expr['args']

        if f['what'] == 'expr:special':
            # for converting Z to u32
            if f['id'] == 'u3' or f['id'] == 'u2':
                arg = args[0]
                # be able to distinguish between Z->u32 and Z->u64
                if f['id'] == 'u3':
                    arg['name'] = 'u32'
                else:
                    arg['name'] = 'u64'
                state, val = self.proc(arg, state)
                return state, z3.Const(anon(), val)

            elif f['id'] == 'gtb':
                arg0 = args[0]['cases'][0]['body']['args'][0]
                nstate, arg1 = self.proc(
                    args[1]['cases'][0]['body']['args'][0], state)
                return nstate, z3.If(arg0 > arg1,
                                     self.bool_sort.constructor(0)(),
                                     self.bool_sort.constructor(1)())

            elif f['id'] == 'gmap_lookup':
                state, k = self.proc(args[0], state)
                state, m = self.proc(args[1], state)
                return state, m[k]

            elif f['id'] == 'map_insert':
                state, k = self.proc(args[0], state)
                state, v = self.proc(args[1], state)
                state, m = self.proc(args[2], state)

                rangesort = m.range()
                vsome = constructor_by_name(rangesort, "Some")(v)

                return state, z3.Store(m, k, vsome)

            elif f['id'] == 'reads':
                return state, state

            elif f['id'] == 'modify':
                _, newstate = self.proc(args[0]['body'], state)
                return newstate, self.unit_tt

            elif f['id'] == 'ret':
                state, res = self.proc(args[0], state)
                return state, res

            elif f['id'] == 'len_buf':
                state, buf = self.proc(args[0], state)
                return state, z3.Int2BV(z3.Length(buf), 64)

            elif f['id'] == 'resize_buf':
                state, newlen = self.proc(args[0], state)
                state, buf = self.proc(args[1], state)
                ## XXX should be of length newlen, not empty..
                return state, z3.Empty(buf.sort())

            elif f['id'] == 'eqDec_time':
                state, a0 = self.proc(args[0], state)
                state, a1 = self.proc(args[1], state)
                return state, z3.If(a0 == a1,
                                    self.sumbool_sort.constructor(0)(),
                                    self.sumbool_sort.constructor(1)())

            elif f['id'] == 'time_ge':
                state, a0 = self.proc(args[0], state)
                state, a1 = self.proc(args[1], state)
                # constructor 0 is true, 1 is false
                return state, z3.If(a0 >= a1,
                                    self.bool_sort.constructor(0)(),
                                    self.bool_sort.constructor(1)())

            elif f['id'] == 'symAssert':
                state, a = self.proc(args[0], state)
                return state, z3.And(a == self.bool_sort.constructor(0)())

            else:
                raise Exception('unknown special function', f['id'])
        else:
            raise Exception('unknown apply on', f['what'])
Ejemplo n.º 29
0
    def VertexOperationToSmt(self):
        assert (self.type != VertexNode.VertexType.NONE)

        if self.type == VertexNode.VertexType.VAR:
            # Possible Vertex : input Variable, name = operand1
            # input variable: there is nothing to do.
            # assigned Variable: name = operands[0]

            # It's an input variable if there is no operand :
            if self.operands == None: return None
            # otherwise, it's an assigned variable, but make sure just in case
            assert (self.operator == VertexNode.OpCode.ASSIGN)
            return self.VertexNameToSmt() == self.operands[0].VertexNameToSmt()

        elif self.type == VertexNode.VertexType.TEMP:
            # Possible Vertex : Function Call, Array Load, Binary Operation, Comparison,
            #                   Conditional Assignment, Unary Operation
            # function call: name = func_name(arguments)
            # array load: name = array[index]
            # binary operation: name = operand1 op operand2
            # comparison: name = operand1 comp operand2
            # conditional assignment: name = ite(operand1, operand2, operand3)
            # unary operation: name = op operand1

            # It's a function call
            if self.operator == VertexNode.OpCode.FUNCCALL:
                assert (self.operands[0].type == VertexNode.VertexType.FUNC)
                # There are four possible functions that can last until now:
                if self.operands[0].name == "merge":
                    args = []
                    for op in self.operands[1:]:
                        args.append(op.VertexNameToSmt())
                    return self.VertexNameToSmt() == z3.Concat(args)
                elif self.operands[0].name == "split":
                    toSplit = self.operands[1].VertexNameToSmt()
                    # Extract requires actual numerical value.
                    lowerBound = self.operands[2].value
                    upperBound = self.operands[3].value
                    return self.VertexNameToSmt() == z3.Extract(
                        upperBound, lowerBound, toSplit)
                elif self.operands[0].name == "zeroext":
                    toExtend = self.operands[1].VertexNameToSmt()
                    # ZeroExt requires actual numerical value
                    n = self.operands[2].value
                    return self.VertexNameToSmt() == z3.ZeroExt(n, toExtend)
                elif self.operands[0].name == "concat":
                    args = []
                    for op in self.operands[1:]:
                        args.append(op.VertexNameToSmt())
                    return self.VertexNameToSmt() == z3.Concat(args)

            # It's an array load
            elif self.operator == VertexNode.OpCode.LOAD:
                array = self.operands[0].VertexNameToSmt()
                arrayIndex = self.operands[1].VertexNameToSmt()
                return self.VertexNameToSmt() == z3.Select(array, arrayIndex)

            # It's a conditional statement
            elif self.operator == VertexNode.OpCode.CONDITIONAL:
                cond = self.operands[0].VertexNameToSmt()
                truePath = self.operands[1].VertexNameToSmt()
                falsePath = self.operands[2].VertexNameToSmt()
                return self.VertexNameToSmt() == z3.If(cond, truePath,
                                                       falsePath)

            # It's a comparison (x < y)
            elif VertexNode.OpCode.IsComparison(self.operator):
                lhs = self.operands[0].VertexNameToSmt()
                rhs = self.operands[1].VertexNameToSmt()
                if self.operator == VertexNode.OpCode.GT:
                    return self.VertexNameToSmt() == z3.UGT(lhs, rhs)
                elif self.operator == VertexNode.OpCode.GE:
                    return self.VertexNameToSmt() == z3.UGE(lhs, rhs)
                elif self.operator == VertexNode.OpCode.LT:
                    return self.VertexNameToSmt() == z3.ULT(lhs, rhs)
                elif self.operator == VertexNode.OpCode.LE:
                    return self.VertexNameToSmt() == z3.ULE(lhs, rhs)
                elif self.operator == VertexNode.OpCode.EQ:
                    return self.VertexNameToSmt() == (lhs == rhs)
                elif self.operator == VertexNode.OpCode.NE:
                    return self.VertexNameToSmt() == (lhs != rhs)

            # It's a binary operation
            elif VertexNode.OpCode.IsBinaryOp(self.operator):
                lhs = self.operands[0].VertexNameToSmt()
                rhs = self.operands[1].VertexNameToSmt()
                if self.operator == VertexNode.OpCode.PLUS:
                    return self.VertexNameToSmt() == (lhs + rhs)
                elif self.operator == VertexNode.OpCode.MINUS:
                    return self.VertexNameToSmt() == (lhs - rhs)
                elif self.operator == VertexNode.OpCode.AND:
                    return self.VertexNameToSmt() == (lhs & rhs)
                elif self.operator == VertexNode.OpCode.OR:
                    return self.VertexNameToSmt() == (lhs | rhs)
                elif self.operator == VertexNode.OpCode.XOR:
                    return self.VertexNameToSmt() == (lhs ^ rhs)
                elif self.operator == VertexNode.OpCode.SHL:
                    return self.VertexNameToSmt() == (lhs << rhs)
                elif self.operator == VertexNode.OpCode.SHR:
                    return self.VertexNameToSmt() == (z3.LShR(lhs, rhs))
                elif self.operator == VertexNode.OpCode.ROL:
                    return self.VertexNameToSmt() == (z3.RotateLeft(lhs, rhs))
                elif self.operator == VertexNode.OpCode.ROR:
                    return self.VertexNameToSmt() == (z3.RotateRight(lhs, rhs))
                elif self.operator == VertexNode.OpCode.MUL:
                    return self.VertexNameToSmt() == (lhs * rhs)
                elif self.operator == VertexNnode.OpCode.DIV:
                    return self.VertexNameToSmt() == (lhs / rhs)

            # It's a unary operation
            elif VertexNode.OpCode.IsUnaryOp(self.operator):
                rhs = self.operands[0].VertexNameToSmt()
                if self.operator == VertexNode.OpCode.NOT:
                    return self.VertexNameToSmt() == ~rhs

        elif self.type == VertexNode.VertexType.IMM:
            # Possible Vertex : Immediate Value
            return None
        elif self.type == VertexNode.VertexType.ARR:
            # Possible Vertex : Input array, array store
            # input array: there is nothing to do
            # array store: newarray = store(array, index, value)

            # if operator == None, it's an "input" array
            if self.operator == None: return None
            if self.operator == VertexNode.OpCode.NONE: return None
            # Otherwise, it must be an array store operation vertex
            assert (self.operator == VertexNode.OpCode.STORE)
            oldArray = self.operands[0].VertexNameToSmt()
            index = self.operands[1].VertexNameToSmt()
            value = self.operands[2].VertexNameToSmt()
            newArray = self.VertexNameToSmt()
            return newArray == z3.Store(oldArray, index, value)

        elif self.type == VertexNode.VertexType.FUNC:
            # Possible Vertex : Name of the function
            return None
def opcode_init_memory(memory, length):

    for i in range(length):
        memory = z3.Store(memory, i, z3.BitVecVal(0, 8))

    return z3.simplify(memory)