Esempio n. 1
0
    def test_arithmetic_simplify(self):
        cs = ConstraintSet()
        arr = cs.new_array(name="MEM")
        a = cs.new_bitvec(32, name="VARA")
        b = cs.new_bitvec(32, name="VARB")
        c = a * 2 + b
        self.assertEqual(translate_to_smtlib(c), "(bvadd (bvmul VARA #x00000002) VARB)")
        self.assertEqual(
            translate_to_smtlib((c + 4) - 4),
            "(bvsub (bvadd (bvadd (bvmul VARA #x00000002) VARB) #x00000004) #x00000004)",
        )

        d = c + 4
        s = arithmetic_simplify(d - c)
        self.assertIsInstance(s, Constant)
        self.assertEqual(s.value, 4)
        # size = arithmetic_simplify(size

        cs2 = ConstraintSet()
        exp = cs2.new_bitvec(32)
        exp |= 0
        exp &= 1
        exp |= 0
        self.assertEqual(get_depth(exp), 4)
        self.assertEqual(
            translate_to_smtlib(exp), "(bvor (bvand (bvor BIVEC #x00000000) #x00000001) #x00000000)"
        )
        exp = arithmetic_simplify(exp)
        self.assertTrue(get_depth(exp) < 4)
        self.assertEqual(translate_to_smtlib(exp), "(bvand BIVEC #x00000001)")
Esempio n. 2
0
    def testBasicArrayProxySymbIdx2(self):
        cs = ConstraintSet()
        array = cs.new_array(index_bits=32, value_bits=32, name="array")
        key = cs.new_bitvec(32, name="key")
        index = cs.new_bitvec(32, name="index")

        array[0] = 1  # Write 1 to first location
        array[key] = 2  # Write 2 to a symbolic (potentially any (potentially 0))location

        solutions = self.solver.get_all_values(cs, array[0])  # get a concrete solution for index
        self.assertItemsEqual(solutions, (1, 2))

        solutions = self.solver.get_all_values(
            cs, array.get(0, 100)
        )  # get a concrete solution for index 0
        self.assertItemsEqual(solutions, (1, 2))

        solutions = self.solver.get_all_values(
            cs, array.get(1, 100)
        )  # get a concrete solution for index 1 (default 100)
        self.assertItemsEqual(solutions, (100, 2))

        self.assertTrue(
            self.solver.can_be_true(cs, array[1] == 12345)
        )  # no default so it can be anything
Esempio n. 3
0
 def testBitvector_add2(self):
     cs = ConstraintSet()
     a = cs.new_bitvec(32)
     b = cs.new_bitvec(32)
     c = cs.new_bitvec(32)
     cs.add(11 == a + 10)
     self.assertTrue(self.solver.check(cs))
     self.assertEqual(self.solver.get_value(cs, a), 1)
Esempio n. 4
0
    def test_addmod(self):
        """
        (declare-fun BV () (_ BitVec 256))
        (declare-fun BV_2 () (_ BitVec 256))
        (declare-fun BV_1 () (_ BitVec 256))
        (declare-fun a_1 () (_ BitVec 256))(assert (= a_1 (bvmul BV BV_1)))
        (declare-fun a_2 () (_ BitVec 512))(assert (= a_2 ((_ zero_extend 256) BV)))
        (declare-fun a_3 () (_ BitVec 512))(assert (= a_3 ((_ zero_extend 256) BV_1)))
        (declare-fun a_4 () (_ BitVec 512))(assert (= a_4 (bvmul a_2 a_3)))
        (declare-fun a_5 () (_ BitVec 512))(assert (= a_5 ((_ zero_extend 256) BV_2)))
        (declare-fun a_6 () (_ BitVec 512))(assert (= a_6 (bvsmod a_4 a_5)))
        (declare-fun a_7 () (_ BitVec 256))(assert (= a_7 ((_ extract 255 0) a_6)))
        (declare-fun a_8 () (_ BitVec 256))(assert (= a_8 (bvsmod a_1 BV_2)))
        (declare-fun a_9 () Bool)(assert (= a_9 (= a_7 a_8)))
        (assert (not a_9))

        (check-sat)
        """
        from manticore.platforms import evm
        from manticore.core.smtlib import ConstraintSet, Z3Solver, Operators

        constraints = ConstraintSet()

        address = 0x41414141414141414141
        data = b""
        caller = 0x42424242424242424242
        value = 0
        bytecode = ""
        vm = evm.EVM(constraints, address, data, caller, value, bytecode)

        self.assertEqual(vm.ADDMOD(12323, 2343, 20), 6)
        self.assertEqual(vm.ADDMOD(12323, 2343, 0), 0)

        A, B, C = (
            0x780000002090309A004201626B1400041D318000000200008A0080089C042DA7,
            0xF000000740403F7007C012807BED003BE2CE800000060000FFFFBFF7E4087033,
            0x338000080FFFFF64AAAACFFCF7DBFA408000000000000270120000001E7C2ACF,
        )
        self.assertEqual(
            vm.ADDMOD(A, B, C),
            23067954172474524581131069693479689311231082562138745684554374357070230297856,
        )
        a, b, c = (
            constraints.new_bitvec(256),
            constraints.new_bitvec(256),
            constraints.new_bitvec(256),
        )
        constraints.add(a == A)
        constraints.add(b == B)
        constraints.add(c == C)
        result = vm.ADDMOD(a, b, c)
        # 0x32ffffd700d073ae080133f517d922bd000000000007f1611e003fffc9239d00
        self.assertEqual(
            Z3Solver.instance().get_all_values(constraints, result),
            [
                0x32FFFFD700D073AE080133F517D922BD000000000007F1611E003FFFC9239D00
            ],
        )
Esempio n. 5
0
 def testBitvector_add1(self):
     cs = ConstraintSet()
     a = cs.new_bitvec(32)
     b = cs.new_bitvec(32)
     c = cs.new_bitvec(32)
     cs.add(c == a + 10)
     cs.add(a == 1)
     self.assertEqual(self.solver.check(cs), True)
     self.assertEqual(self.solver.get_value(cs, c), 11)
Esempio n. 6
0
    def test_mulmod(self):
        """
        (declare-fun BV () (_ BitVec 256))
        (declare-fun BV_2 () (_ BitVec 256))
        (declare-fun BV_1 () (_ BitVec 256))
        (declare-fun a_1 () (_ BitVec 256))(assert (= a_1 (bvmul BV BV_1)))
        (declare-fun a_2 () (_ BitVec 512))(assert (= a_2 ((_ zero_extend 256) BV)))
        (declare-fun a_3 () (_ BitVec 512))(assert (= a_3 ((_ zero_extend 256) BV_1)))
        (declare-fun a_4 () (_ BitVec 512))(assert (= a_4 (bvmul a_2 a_3)))
        (declare-fun a_5 () (_ BitVec 512))(assert (= a_5 ((_ zero_extend 256) BV_2)))
        (declare-fun a_6 () (_ BitVec 512))(assert (= a_6 (bvsmod a_4 a_5)))
        (declare-fun a_7 () (_ BitVec 256))(assert (= a_7 ((_ extract 255 0) a_6)))
        (declare-fun a_8 () (_ BitVec 256))(assert (= a_8 (bvsmod a_1 BV_2)))
        (declare-fun a_9 () Bool)(assert (= a_9 (= a_7 a_8)))
        (assert (not a_9))

        (check-sat)
        """
        from manticore.platforms import evm
        from manticore.core.smtlib import ConstraintSet, Z3Solver, Operators

        constraints = ConstraintSet()

        address = 0x41414141414141414141
        data = b""
        caller = 0x42424242424242424242
        value = 0
        bytecode = ""
        vm = evm.EVM(constraints,
                     address,
                     data,
                     caller,
                     value,
                     bytecode,
                     gas=23000)

        self.assertEqual(vm.MULMOD(12323, 2343, 20), 9)
        self.assertEqual(vm.MULMOD(12323, 2343, 0), 0)

        A, B, C = (
            110427941548649020598956093796432407239217743554726184882600387580788736,
            1048576,
            4194319,
        )
        self.assertEqual(vm.MULMOD(A, B, C), 2423129)
        a, b, c = (
            constraints.new_bitvec(256),
            constraints.new_bitvec(256),
            constraints.new_bitvec(256),
        )
        constraints.add(a == A)
        constraints.add(b == B)
        constraints.add(c == C)
        result = vm.MULMOD(a, b, c)
        # 0x8000000000000000000000000000000000000000000000000000000082000011
        self.assertEqual(
            Z3Solver.instance().get_all_values(constraints, result), [2423129])
Esempio n. 7
0
    def test_cs_new_bitvec_invalid_size(self):
        cs = ConstraintSet()
        with self.assertRaises(ValueError) as e:
            cs.new_bitvec(size=0)

        self.assertEqual(str(e.exception), "Bitvec size (0) can't be equal to or less than 0")

        with self.assertRaises(ValueError) as e:
            cs.new_bitvec(size=-23)

        self.assertEqual(str(e.exception), "Bitvec size (-23) can't be equal to or less than 0")
Esempio n. 8
0
    def test_ITEBV_2(self):
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        b = cs.new_bitvec(8)
        c = cs.new_bitvec(8)

        cs.add(b == 0x44)
        cs.add(c == 0x44)
        cs.add(a == Operators.ITEBV(8, b == c, b, c))

        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), 0x44)
Esempio n. 9
0
    def test_CONCAT(self):
        solver = self.solver
        cs = ConstraintSet()
        a = cs.new_bitvec(16)
        b = cs.new_bitvec(8)
        c = cs.new_bitvec(8)

        cs.add(b == 0x41)
        cs.add(c == 0x42)
        cs.add(a == Operators.CONCAT(a.size, b, c))

        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), Operators.CONCAT(a.size, 0x41, 0x42))
Esempio n. 10
0
    def testBasicArraySymbIdx(self):
        cs = ConstraintSet()
        array = cs.new_array(index_bits=32, value_bits=32, name="array")
        key = cs.new_bitvec(32, name="key")
        index = cs.new_bitvec(32, name="index")

        array[key] = 1  # Write 1 to a single location

        cs.add(array.get(index, default=0) != 0)  # Constrain index so it selects that location

        cs.add(index != key)
        # key and index are the same there is only one slot in 1
        self.assertFalse(self.solver.check(cs))
Esempio n. 11
0
    def testBasicArrayProxySymbIdx(self):
        cs = ConstraintSet()
        array = cs.new_array(index_bits=32, value_bits=32, name="array", default=0)
        key = cs.new_bitvec(32, name="key")
        index = cs.new_bitvec(32, name="index")

        array[key] = 1  # Write 1 to a single location
        cs.add(array.get(index) != 0)  # Constrain index so it selects that location
        a_index = self.solver.get_value(cs, index)  # get a concrete solution for index

        cs.add(array.get(a_index) != 0)  # now storage must have something at that location
        cs.add(a_index != index)  # remove it from the solutions
        # It should not be another solution for index
        self.assertFalse(self.solver.check(cs))
Esempio n. 12
0
    def test_SREM(self):
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        b = cs.new_bitvec(8)
        c = cs.new_bitvec(8)
        d = cs.new_bitvec(8)

        cs.add(b == 0x86)  #-122
        cs.add(c == 0x11)  #17
        cs.add(a == Operators.SREM(b, c))
        cs.add(d == b.srem(c))
        cs.add(a == d)

        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), -3 & 0xFF)
Esempio n. 13
0
    def test_SDIV(self):
        solver = self.solver
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        b = cs.new_bitvec(8)
        c = cs.new_bitvec(8)
        d = cs.new_bitvec(8)

        cs.add(b == 0x86)  # -122
        cs.add(c == 0x11)  # 17
        cs.add(a == Operators.SDIV(b, c))
        cs.add(d == (b // c))
        cs.add(a == d)
        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), -7 & 0xFF)
Esempio n. 14
0
    def test_SAR(self):
        solver = self.solver
        A = 0xBADF00D
        for B in range(32):
            cs = ConstraintSet()
            a = cs.new_bitvec(32)
            b = cs.new_bitvec(32)
            c = cs.new_bitvec(32)

            cs.add(c == Operators.SAR(32, a, b))
            cs.add(a == A)
            cs.add(b == B)

            self.assertTrue(solver.check(cs))
            self.assertEqual(solver.get_value(cs, c), Operators.SAR(32, A, B))
Esempio n. 15
0
    def test_UDIV(self):
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        b = cs.new_bitvec(8)
        c = cs.new_bitvec(8)
        d = cs.new_bitvec(8)

        cs.add(b == 0x86)  #134
        cs.add(c == 0x11)  #17
        cs.add(a == Operators.UDIV(b, c))
        cs.add(d == b.udiv(c))
        cs.add(a == d)

        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), 7)
Esempio n. 16
0
    def test_visitors(self):
        solver = Z3Solver.instance()
        cs = ConstraintSet()
        arr = cs.new_array(name="MEM")
        a = cs.new_bitvec(32, name="VAR")
        self.assertEqual(get_depth(a), 1)
        cond = Operators.AND(a < 200, a > 100)
        arr[0] = ord("a")
        arr[1] = ord("b")

        self.assertEqual(get_depth(cond), 3)
        self.assertEqual(get_depth(arr[a + 1]), 4)
        self.assertEqual(
            translate_to_smtlib(arr[a + 1]),
            "(select (store (store MEM #x00000000 #x61) #x00000001 #x62) (bvadd VAR #x00000001))",
        )

        arr[3] = arr[a + 1]
        aux = arr[a + Operators.ZEXTEND(arr[a], 32)]

        self.assertEqual(get_depth(aux), 9)
        self.maxDiff = 1500
        self.assertEqual(
            translate_to_smtlib(aux),
            "(select (store (store (store MEM #x00000000 #x61) #x00000001 #x62) #x00000003 (select (store (store MEM #x00000000 #x61) #x00000001 #x62) (bvadd VAR #x00000001))) (bvadd VAR ((_ zero_extend 24) (select (store (store (store MEM #x00000000 #x61) #x00000001 #x62) #x00000003 (select (store (store MEM #x00000000 #x61) #x00000001 #x62) (bvadd VAR #x00000001))) VAR))))",
        )

        values = arr[0:2]
        self.assertEqual(len(values), 2)
        self.assertItemsEqual(solver.get_all_values(cs, values[0]), [ord("a")])
        self.assertItemsEqual(solver.get_all_values(cs, values[1]), [ord("b")])
        arr[1:3] = "cd"

        values = arr[0:3]
        self.assertEqual(len(values), 3)
        self.assertItemsEqual(solver.get_all_values(cs, values[0]), [ord("a")])
        self.assertItemsEqual(solver.get_all_values(cs, values[1]), [ord("c")])
        self.assertItemsEqual(solver.get_all_values(cs, values[2]), [ord("d")])
        self.assertEqual(
            pretty_print(aux, depth=2),
            "ArraySelect\n  ArrayStore\n    ...\n  BitVecAdd\n    ...\n")
        self.assertEqual(pretty_print(Operators.EXTRACT(a, 0, 8), depth=1),
                         "BitVecExtract{0:7}\n  ...\n")
        self.assertEqual(pretty_print(a, depth=2), "VAR\n")

        x = BitVecConstant(32, 100, taint=("important", ))
        y = BitVecConstant(32, 200, taint=("stuff", ))
        z = constant_folder(x + y)
        self.assertItemsEqual(z.taint, ("important", "stuff"))
        self.assertEqual(z.value, 300)

        self.assertRaises(Exception, translate_to_smtlib, 1)

        self.assertEqual(
            translate_to_smtlib(simplify(Operators.ZEXTEND(a, 32))), "VAR")
        self.assertEqual(
            translate_to_smtlib(
                simplify(Operators.EXTRACT(Operators.EXTRACT(a, 0, 8), 0, 8))),
            "((_ extract 7 0) VAR)",
        )
Esempio n. 17
0
    def testBasicArrayStore(self):
        name = "bitarray"
        cs = ConstraintSet()
        # make array of 32->8 bits
        array = cs.new_array(32, name=name)
        # make free 32bit bitvector
        key = cs.new_bitvec(32)

        # assert that the array is 'A' at key position
        array = array.store(key, ord("A"))
        # let's restrict key to be greater than 1000
        cs.add(key.ugt(1000))

        # 1001 position of array can be 'A'
        self.assertTrue(self.solver.can_be_true(cs, array.select(1001) == ord("A")))

        # 1001 position of array can be 'B'
        self.assertTrue(self.solver.can_be_true(cs, array.select(1001) == ord("B")))

        # name is correctly proxied
        self.assertEqual(array.name, name)

        with cs as temp_cs:
            # but if it is 'B' ...
            temp_cs.add(array.select(1001) == ord("B"))
            # then key can not be 1001
            temp_cs.add(key == 1001)
            self.assertFalse(self.solver.check(temp_cs))

        with cs as temp_cs:
            # If 1001 position is 'B' ...
            temp_cs.add(array.select(1001) == ord("B"))
            # then key can be 1002 for ex..
            temp_cs.add(key != 1002)
            self.assertTrue(self.solver.check(temp_cs))
Esempio n. 18
0
    def testBasicArray256(self):
        cs = ConstraintSet()
        # make array of 32->8 bits
        array = cs.new_array(32, value_bits=256)
        # make free 32bit bitvector
        key = cs.new_bitvec(32)

        # assert that the array is 111...111 at key position
        cs.add(array[key] == 11111111111111111111111111111111111111111111)
        # let's restrict key to be greater than 1000
        cs.add(key.ugt(1000))

        with cs as temp_cs:
            # 1001 position of array can be 111...111
            temp_cs.add(array[1001] == 11111111111111111111111111111111111111111111)
            self.assertTrue(self.solver.check(temp_cs))

        with cs as temp_cs:
            # 1001 position of array can also be 222...222
            temp_cs.add(array[1001] == 22222222222222222222222222222222222222222222)
            self.assertTrue(self.solver.check(temp_cs))

        with cs as temp_cs:
            # but if it is 222...222 ...
            temp_cs.add(array[1001] == 22222222222222222222222222222222222222222222)
            # then key can not be 1001
            temp_cs.add(key == 1001)
            self.assertFalse(self.solver.check(temp_cs))

        with cs as temp_cs:
            # If 1001 position is 222...222 ...
            temp_cs.add(array[1001] == 22222222222222222222222222222222222222222222)
            # then key can be 1002 for ex..
            temp_cs.add(key == 1002)
            self.assertTrue(self.solver.check(temp_cs))
Esempio n. 19
0
    def test_CHR(self):
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        cs.add(Operators.CHR(a) == Operators.CHR(0x41))

        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), 0x41)
Esempio n. 20
0
    def test_UREM(self):
        solver = Z3Solver.instance()
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        b = cs.new_bitvec(8)
        c = cs.new_bitvec(8)
        d = cs.new_bitvec(8)

        cs.add(b == 0x86)  # 134
        cs.add(c == 0x11)  # 17
        cs.add(a == Operators.UREM(b, c))
        cs.add(d == b.urem(c))
        cs.add(a == d)

        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), 0xF)
Esempio n. 21
0
    def test_ORD(self):
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        cs.add(Operators.ORD(a) == Operators.ORD('Z'))

        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), ord('Z'))
Esempio n. 22
0
 def testBitvector_max1(self):
     cs = ConstraintSet()
     a = cs.new_bitvec(32)
     cs.add(a < 200)
     cs.add(a > 100)
     self.assertTrue(self.solver.check(cs))
     self.assertEqual(self.solver.minmax(cs, a), (101, 199))
Esempio n. 23
0
 def test_simple_types_ints_symbolic1(self):
     cs = ConstraintSet()
     x = cs.new_bitvec(256, name="x")
     # Something is terribly wrong x,y = 10,20
     my_ser = ABI.serialize('uint', x)
     self.assertTrue(
         solver.must_be_true(cs,
                             my_ser[0] == operators.EXTRACT(x, 256 - 8, 8)))
Esempio n. 24
0
    def test_ORD_proper_extract(self):
        solver = self.solver
        cs = ConstraintSet()
        a = cs.new_bitvec(32)
        cs.add(Operators.ORD(a) == Operators.ORD("\xff"))

        self.assertTrue(solver.check(cs))
        self.assertEqual(solver.get_value(cs, a), ord("\xff"))
Esempio n. 25
0
    def testBitvector_max(self):
        cs = ConstraintSet()
        a = cs.new_bitvec(32)
        cs.add(a <= 200)
        cs.add(a >= 100)
        self.assertTrue(self.solver.check(cs))
        self.assertEqual(self.solver.minmax(cs, a), (100, 200))
        from manticore import config

        consts = config.get_group("smt")
        consts.optimize = False
        cs = ConstraintSet()
        a = cs.new_bitvec(32)
        cs.add(a <= 200)
        cs.add(a >= 100)
        self.assertTrue(self.solver.check(cs))
        self.assertEqual(self.solver.minmax(cs, a), (100, 200))
        consts.optimize = True
Esempio n. 26
0
 def test_simple_types_ints_symbolic(self):
     cs = ConstraintSet()
     x = cs.new_bitvec(256, name="x")
     y = cs.new_bitvec(256, name="y")
     # Something is terribly wrong x,y = 10,20
     my_ser = ABI.serialize('(uint,uint)', x, y)
     x_, y_ = ABI.deserialize('(uint,uint)', my_ser)
     self.assertTrue(solver.must_be_true(cs, x == x_))
     self.assertTrue(solver.must_be_true(cs, y == y_))
Esempio n. 27
0
    def test_arithmetic_simplify_udiv(self):
        cs = ConstraintSet()
        a = cs.new_bitvec(32, name="VARA")
        b = a + Operators.UDIV(BitVecConstant(size=32, value=0), BitVecConstant(size=32, value=2))
        self.assertEqual(translate_to_smtlib(b), "(bvadd VARA (bvudiv #x00000000 #x00000002))")
        self.assertEqual(translate_to_smtlib(simplify(b)), "VARA")

        c = a + Operators.UDIV(BitVecConstant(size=32, value=2), BitVecConstant(size=32, value=2))
        self.assertEqual(translate_to_smtlib(c), "(bvadd VARA (bvudiv #x00000002 #x00000002))")
        self.assertEqual(translate_to_smtlib(simplify(c)), "(bvadd VARA #x00000001)")
Esempio n. 28
0
    def test_NOT(self):
        solver = self.solver
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        b = cs.new_bitvec(8)

        cs.add(a == 0x1)  # 1
        cs.add(b == 0x86)  # -122
        self.assertTrue(solver.must_be_true(cs, Operators.NOT(False)))
        self.assertTrue(solver.must_be_true(cs, Operators.NOT(a == b)))
Esempio n. 29
0
    def testBasicMigration(self):
        solver = self.solver
        cs1 = ConstraintSet()
        cs2 = ConstraintSet()
        var1 = cs1.new_bitvec(32, "var")
        var2 = cs2.new_bitvec(32, "var")
        cs1.add(Operators.ULT(var1, 3))  # var1 can be 0, 1, 2

        # make a migration map dict
        migration_map1 = {}

        # this expression is composed with variables of both cs
        expression = var1 > var2
        migrated_expression = cs1.migrate(expression, migration_map1)
        cs1.add(migrated_expression)

        expression = var2 > 0
        migrated_expression = cs1.migrate(expression, migration_map1)
        cs1.add(migrated_expression)

        self.assertItemsEqual(solver.get_all_values(cs1, var1), [2])  # should only be [2]
Esempio n. 30
0
    def test_ULT(self):
        solver = self.solver
        cs = ConstraintSet()
        a = cs.new_bitvec(8)
        b = cs.new_bitvec(8)
        c = cs.new_bitvec(8)

        cs.add(a == 0x1)  # 1
        cs.add(b == 0x86)  # -122
        cs.add(c == 0x11)  # 17
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(a, b)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(a, c)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(c, b)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(a, 0xF2)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(b, 0x99)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(c, 0x12)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(3, 0xF2)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(3, 4)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(0, a)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(0x85, b)))
        self.assertTrue(solver.must_be_true(cs, Operators.ULT(0x10, c)))