【Applied Algebra】可满足性模理论(Satisfiability Modulo Theories)入门

【Applied Algebra】可满足性模理论(Satisfiability Modulo Theories)入门

摘要:SMT问题是在特定理论下判定一阶逻辑公式可满足性问题.它在很多领域,尤其是形式验证、程序分析、软件测试等领域,都有重要的应用.本文介绍了SMT问题的基本概念、相关定义以及目前的主流理论.

在这里插入图片描述


从SAT到SMT

SAT(satisfiability)问题指的是命题逻辑公式的可满足性问题.随着研究的深人,人们发现SAT在表达能力上有很大的局限性,许多应用用SAT进行编码并不是很明智的选择,它们需要比SAT更强的表达方式.在这种形势下,将SAT问题扩展为SMT,经过扩展,SMT能比SAT更好地表达一些人工智能和形式化方法领域内的问题,比如在资源规划、时序推理、编译器优化等很多方面用到了SMT.

SMT的全称是Satisfiability Modulo Theories,可被翻译为"可满足性模理论",“多理论下的可满足性问题"或者"特定(背景)理论下的可满足性问题”,其判定算法被称为SMT求解器.简单地说,一个SMT公式是结合了理论背景的逻辑公式,其中的命题变量可以代表理论公式.对于SMT的研究起源于20世纪70年代末80年代初,当时的一些学者为形式化方法设计了一些判定算法,这些算法可以看作最早的SMT求解器;到了20世纪90年代,人们开始研究能处理大规模工业界问题的SMT求解技术.最近几年在工业界和学术界,这类技术均得到了迅猛的发展.而SMT求解器也被集成到一些大型工具中,比如HOL/Isabelle、ESC/Java2、ACL2、UCLID、BLAST、ureka,CUTE和PEX等.

SAT问题回答某个命题逻辑公式的可满足性,如:

A ∧ B ∨ ¬ C A \wedge B \vee \neg C AB¬C

但实际中的公式却往往是这样的(带有谓词,以表达更复杂的问题逻辑):

a + b < c ∧ f ( b ) > c ∨ c > 0 a+b<c \wedge f(b)>c \vee c>0 a+b<cf(b)>cc>0

SMT求解的过程就是探索如何判断这样公式的可满足性;从逻辑学角度来看, a + b < c a+b<c a+b<c或者 𝑓 ( 𝑏 ) > 𝑐 𝑓(𝑏)>𝑐 f(b)>c都是逻辑系统中不包含的符号,计算机需要知道他们的意思;这就引出了理论(Theory)的概念;


理论(Theory)

  • 理论用于对这类符号谓词/函数(比如 > , f ( ⋅ ) , + , . . . >,f(\cdot),+,... >,f(),+,...)赋予含义;
  • 理论包含一组公理和这组公理能推导出的结论;

这里介绍一种常见的理论:EUF(Equality with Uninterpreted Functions),其公理为:

  • 给定相同输入,有相同输出: a i = b i ⇒ f ( a 1 … a n ) = f ( b 1 … b n ) a_{i}=b_{i} \Rightarrow f(a_{1} \ldots a_{n})=f(b_{1} \ldots b_{n}) ai=bif(a1an)=f(b1bn);
  • 等价性对立: a = b ⇔ ¬ ( a ≠ b ) a=b \Leftrightarrow \neg(a \neq b) a=b¬(a=b);

其他常见的公理有:

  • 算术: a + 10 < b a+10<b a+10<b, 2 x + 3 y + 4 z = 10 2 x+3 y+4 z=10 2x+3y+4z=10,…;

  • 数组:read(write ( a , i , v ) , i ) = v (a, i, v), i)=v (a,i,v),i)=v(数组的读写操作);

  • 位向量(Bit Vectors): a [ 0 ] = b [ 1 ] ∧ a = c ∧ b [ 1 ] ≠ c [ 0 ] a[0]=b[1] \wedge a=c \wedge b[1] \neq c[0] a[0]=b[1]a=cb[1]=c[0];

SMT求解器的发展(2000年前后SAT速度大幅提升,转为以SAT为中心的方法):

  • 70/80年代: 出现了基本算法混合不同理论,但求解能力有限;
  • 1999: Eager方法,将SMT问题编码成SAT问题(比如利用EUF理论);
  • 2000: Lazy方法,交互调用SAT求解器和各种专用求解器;
Lazy方法求解SMT示例

带求解问题为: g ( a ) = c ∧ ( f ( g ( a ) ) ≠ f ( c ) ∨ g ( a ) = d ) ∧ c ≠ d g(a)=c \wedge(f(g(a)) \neq f(c) \vee g(a)=d) \wedge c \neq d g(a)=c(f(g(a))=f(c)g(a)=d)c=d;

生成如下公式到SAT求解器:

{ 1 } , { − 2 , 3 } , { − 4 } \{1\},\{-2,3\},\{-4\} {1},{2,3},{4}

(调用)SAT求解器返回SAT和赋值 { 1 , − 2 , − 4 } \{1,-2,-4\} {1,2,4},生成如下公式组到EUF求解器:

  • g ( a ) = c g(a)=c g(a)=c;
  • f ( g ( a ) ) ≠ f ( c ) f(g(a)) \neq f(c) f(g(a))=f(c);
  • c ≠ d c \neq d c=d;

此时EUF求解器返回UNSAT;再次生成如下公式到(再次调用)SAT求解器:

{ 1 } , { − 2 , 3 } , { − 4 } , { − 1 , 2 , 4 } \{1\},\{-2,3\},\{-4\},\{-1,2,4\} {1},{2,3},{4},{1,2,4}

SAT求解器返回SAT和赋值 { 1 , 2 , 3 , − 4 } \{1,2,3,-4\} {1,2,3,4},EUF求解器返回UNSAT,于是SAT求解器发现如下解不可满足:

{ 1 } , { − 2 , 3 } , { − 4 } , { − 1 , 2 , 4 } , { − 1 , − 2 , − 3 , 4 } \{1\},\{-2,3\},\{-4\},\{-1,2,4\},\{-1,-2,-3,4\} {1},{2,3},{4},{1,2,4},{1,2,3,4}

利用python-z3求解一个简单的SMT问题

考虑如下的方程组问题:

3 x + 2 y − z = 1 2 x − 2 y + 4 z = − 2 − x + 1 2 y − z = 0 \begin{array}{l} 3 x+2 y-z=1 \\ 2 x-2 y+4 z=-2 \\ -x+\frac{1}{2} y-z=0 \end{array} 3x+2yz=12x2y+4z=2x+21yz=0

利用python-z3求解:

#!/usr/bin/python
from z3 import *
x = Real('x')
y = Real('y')
z = Real('z')
s = Solver()
s.add(3*x + 2*y - z == 1)
s.add(2*x - 2*y + 4*z == -2)
s.add(-x + 0.5*y - z == 0)
print s.check()
print s.model()

运行程序可得:

sat # 表明可满足;
[z = -2, y = -2, x = 1] # 模型;

综上,SMT的核心问题是:对于一组逻辑理论下的公式集合 α ( x ) \alpha(x) α(x),是否 ∃ x , x ⊨ α \exists x, x \vDash \alpha x,xα?

在这里插入图片描述


SMT和网络安全

DEFCAMP 2017 Misc题:“forgot my key”,题目如下:I forgot my flag & key. Help me recover them.

5616f5962674d26741d2810600a6c5647620c4e3d2870177f09716b2379012c342d3b584c5672195d653722443f1c39254360007010381b721c741a532b03504d2849382d375c0d6806251a2946335a67365020100f160f17640c6a05583f49645d3b557856221b2

function my_encrypt($flag, $key) {
  $key = md5($key);
  $message = $flag . "|" . $key;

  $encrypted = chr(rand(0, 126));
  for($i=0;$i<strlen($message);$i++) {
    $encrypted .= chr((ord($message[$i]) + ord($key[$i % strlen($key)]) + ord($encrypted[$i])) % 126);
  }
  $hexstr = unpack('h*', $encrypted);
  return array_shift($hexstr);
}

这题给定加密函数,要求还原flag和key.观察可以发现,加密串每一位都与明文、key、和加密串的前一位相关.但是由于第一位是随机出来的,所以很难从开头递推出来.但是细心观察message的构成又可以发现,后面32位是key的md5串,倒数第33位又是已知,因此从这里就可以打开突破口.整理思路如下:

  • 第一步:通过倒数第33位明文已知,且密文已知,因此可以求得某一位md5(key)的值;

  • 第二步:根据上一步推出来的值,又可以进一步推另一位message的值;如此往复下去,最终应该能找到所有的值;

思路是有了,然而写起来未必简单,因为人的思维都是正向的,逆向求解特别是还要写出完整求解代码总是麻烦的.于是我们考虑是否可以使用Z3来求解(将约束条件逻辑表述给z3求解器即可).首先题目肯定保证了答案的唯一性,因此Z3求解成功就会得到flag无疑.其次,我们根据题目的变换方式,给Z3所有的正推关系式,把逆推的逻辑让Z3通过约束求解来完成,由于逆推可以一步步进行,因此也不会导致Z3复杂度爆炸求解不出来.如此分析应该Z3"一把梭"问题不大.程序如下:

#!/usr/bin/env python3

from z3 import *
import binascii

s = '5616f5962674d26741d2810600a6c5647620c4e3d2870177f09716b2379012c342d3b584c5672195d653722443f1c39254360007010381b721c741a532b03504d2849382d375c0d6806251a2946335a67365020100f160f17640c6a05583f49645d3b557856221b2'

encrypted = []
for i in range(0, len(s), 2):
    encrypted.append(binascii.unhexlify(s[i+1] + s[i])[0])

print('message len:', len(encrypted)-1)
print(encrypted)
# 声明变量,encrypted 是已知,因此 IntVal 即可
encrypted = [IntVal(i) for i in encrypted]
message = [Int('flag%d' % i) for i in range(len(encrypted)-1)]
# 创建一个求解器,求解全靠它
solver = Solver()

ml = len(encrypted) - 1

# 添加明文字符的约束条件
for i in range(ml):
    if i == ml - 33:
        solver.add(message[i] == ord('|'))
    else:
        # 肯定是可见字符,因此限定范围如下
        solver.add(message[i] < 127)
        solver.add(message[i] >= 32)
# 添加明文和密文对照关系的约束条件
for i in range(ml):
    solver.add(encrypted[i+1] == (message[i] + message[ml-32+i%32] + encrypted[i]) % 126)

if solver.check() == sat:
    m = solver.model()
    s = []
    for i in range(ml):
        s.append(m[message[i]].as_long())
    print(bytes(s))
else:
    print('unsat') 

运行求解:

(z3env) $ time python solve.py 
message len: 103
b'DCTF{0d940de38493d96dc6255cbb2c2ac7a2db1a7792c74859e95215caa6b57c69b2}|6941f4cac9b7784fdd77e11b51cd0d64'

real	0m7.277s
user	0m7.260s
sys	0m0.010s 

参考资料

[1] Z3一把梭:用约束求解搞定一类CTF题(https://zhuanlan.zhihu.com/p/30548907)

[2] 熊英飞:"编程语言的设计原理"课件(https://xiongyingfei.github.io/SA/2018/12_SMT.pdf)

[3] SAT/SMT by Example(https://sat-smt.codes/SAT_SMT_by_example.pdf)

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值