Search code examples
mathz3xorsolversmt

Why does Z3 say that this equation is not satisfiable, when I have input that is correct?


Given a simple shift-and-XOR operation, where 'input' is symbolic:

input    = BitVec('input',32)
feedback = 0x8049d30
shiftreg = input ^ feedback
shiftreg = 0xffffffff & ((shiftreg << 8) | (shiftreg >> 24))
shiftreg = shiftreg ^ 0xcafebabe

s = Solver()
s.add(shiftreg == 0x804a008)
s.check()
# unsat

We are told that this equation is not solvable. If printed, s contains:

[4294967295 &
 ((input ^ 134520112) << 8 | (input ^ 134520112) >> 24) ^
 3405691582 ==
 134520840]

However, I can trivially create an example that solves this equation for 'input'.

want = 0x804a008
want ^= 0xcafebabe
want = 0xffffffff & ((want >> 8) | (want << 24))
want ^= 0x8049d30
print hex(want)
# 0xbec6672a

Entering our solution into Z3's equation, we see that we can satisfy it.

input = 0xbec6672a
[4294967295 &
 ((input ^ 134520112) << 8 | (input ^ 134520112) >> 24) ^
 3405691582 ==
 134520840]
# True

Why can Z3 not find this solution?


Solution

  • It turns out that in Z3, the shift operators are arithmetic shifts rather than logical shifts.

    This means that a right shift >> is filled with the sign bit, rather than filled with zeroes.

    You must use the Logical Shift Right (LShR) function in order to get normal behavior.

    input    = BitVec('input',32)
    feedback = 0x8049d30
    shiftreg = input ^ feedback
    shiftreg = (shiftreg << 8) | LShR(shiftreg, 24)
    shiftreg = shiftreg ^ 0xcafebabe
    
    s = Solver()
    s.add(shiftreg == 0x804a008)
    s.check()
    hex(s.model()[input].as_long())
    # 0xbec6672a
    

    In this particular example, the shift operation is actually a rotate. Z3 has a mechanism for doing the rotate directly (in this case, it would be RotateLeft(shiftreg, 8).