用SMT solver验证程序等价

(2023.12.04 恢复)


过去十年,SMT(Satisfiability modulo theories)求解器在形式化方法、程序语言、软件工程、以及计算机安全、计算机系统等领域得到了广泛应用。。

本文以“验证程序等价性”的例子,介绍SMT 求解器的简单运用。 这里将等价性定义为“给定相同合法输入,有相同输出“。考虑如下2个函数:

int power3_A(int in) {
  int i, out_a;
  out_a = in; 
  for (i = 0; i < 2; i++) 
    out_a = out_a * in;
  return out_a;
}

int power3_B(int in) {
  int out_b;
  out_b = (in * in) * in; 
  return out_b; 
}

如何证明power3_A, power3_B干了同一件事情?一个传统方法是写测试用例,但是这2个程序的输入int型整数取值范围很大....

我们考虑基于形式逻辑的程序验证。这个例子比较简单,可以对power3_A做循环展开,然后用逻辑公式分别编码power3_A, power3_B的程序语义(需要引入中间变量)。以上两个程序分别编码为 \varphi_a, \varphi_b ,也就是

\begin{align} out0_a &= in \ \ \ \ \ \ \ \ \ \ \ \ \land \\ out1_a &= out0_a * in \ \ \land \\ out2_a &= out1_a * in \end{align}

out0_b = (in * in) * in


下面是证明“给定相同输入,有相同输出”。 等价性就转化为判断以下公式是永真的(VALID)

\varphi_a \land \varphi_b \Rightarrow out2_a = out0_b

而要证明任意命题 F 永真,可以对 F 取反,然后证明 \neg F 不可满足(unsatisfiable)。

F \text{ valid} \equiv \neg F \text { unsatisfiable }


于是问题转化为了判断公式的可满足性。SMT solver可以接受特定问题域公式如实数方程约束,判断其可满足性。我们需要建模整数(32位/64位)和乘法*,正巧很多SMT solver支持的bit-vector theory刚好适合。


附上代码,使用z3 SMT solver的Python API的

from z3 import *
# 创建solver和逻辑变量
solver = Solver()
out0a, out1a, out2a, out0b, In = BitVecs("out0a out1a out2a out0b In", 32)

# 编码A程序语义
fa = And(out0a == In, out1a == out0a * In, out2a == out1a * In)

# 编码B程序语义
fb = (out0b == In * In * In)

# 证明程序等价,需要证明G永真(VALID)
G = Implies(And(fa, fb), out2a == out0b)

# 转化为可满足性问题:将G取反后判断其是否不可满足(UNSAT)
solver.add(Not(G))
print solver.check()


附录:“假如我想使用SMT solver娱乐甚至做一些研究,“

  • 需要学习数理逻辑么? 不需要
  • 需要懂得SAT问题么? 不需要
  • 需要了解CSP求解么?不需要
  • 需要接触符号计算么? 不需要
  • ...

编辑于 2023-12-04 19:45・IP 属地浙江