给定一个简单的shift-and-XOR运算,其中'input'是符号:
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
我们被告知这个等式是不可解的。如果打印,s
包含:
[4294967295 &
((input ^ 134520112) << 8 | (input ^ 134520112) >> 24) ^
3405691582 ==
134520840]
但是,我可以轻而易举地创建一个解释“输入”这个等式的例子。
want = 0x804a008
want ^= 0xcafebabe
want = 0xffffffff & ((want >> 8) | (want << 24))
want ^= 0x8049d30
print hex(want)
# 0xbec6672a
将我们的解决方案输入到Z3的等式中,我们发现我们可以满足它。
input = 0xbec6672a
[4294967295 &
((input ^ 134520112) << 8 | (input ^ 134520112) >> 24) ^
3405691582 ==
134520840]
# True
为什么Z3找不到这个解决方案?
答案 0 :(得分:3)
事实证明,在Z3中,移位运算符是算术移位而不是逻辑移位。
这意味着右移>>
用符号位填充,而不是用零填充。
您必须使用逻辑右移(LShR
)功能才能获得正常行为。
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
在此特定示例中,移位操作实际上是旋转。 Z3有一个直接进行旋转的机制(在这种情况下,它将是RotateLeft(shiftreg, 8)
。
答案 1 :(得分:1)
我相信“(shiftreg&gt;&gt; 24)”在z3 python API中被解释为算术右移:http://research.microsoft.com/en-us/um/redmond/projects/z3/z3.html(参见rshift)。我认为你期待合理的正确转变。首先,让我们将其重新编码为smt2。
(declare-fun input () (_ BitVec 32))
(define-fun feedback () (_ BitVec 32) #x08049d30)
(define-fun shiftreg0 () (_ BitVec 32)
(bvxor feedback input))
(define-fun shiftreg1 () (_ BitVec 32)
(bvand #xffffffff
(bvor (bvshl shiftreg0 #x00000008)
(bvlshr shiftreg0 #x00000018))))
(define-fun shiftreg2 () (_ BitVec 32)
(bvxor shiftreg1 #xcafebabe))
(assert (= shiftreg2 #x0804a008))
(check-sat)
我们可以使用您最喜欢的QFBV解算器(z3,cvc4等)检查确实是这样。它是坐着的,它坐着“(=输入#xbec6672a)”断言。现在将“(bvlshr shiftreg0#x00000018)”更改为“(bvashr shiftreg0#x00000018)”。这是不可能的。改变转变。接下来,让我们检查shiftreg0的最高位是否需要为1.添加以下断言确实使问题不能解决。
(assert (not (= ((_ extract 31 31) shiftreg0) #b1)))
因此我们知道“(bvashr shiftreg0#x00000018)”将被强制转换为前14位的1s。因此,我们知道bvlshr和bvashr在此示例中的行为必须不同。
至于为什么最终的评价是真的,我只是猜测。 (我怀疑z3在python接口中无法推断出所有常量运算符的宽度,并且在内部有一个0在一个33 +位宽的常量中挂起。转Z3开发人员可以对此发表评论吗?)