测试影响Z3效率的原因

一、问题产生的原因

之前打比赛的时候尝试angr强力求解tea加密,发现跑不出来,以为是angr编写有误,赛后直接尝试使用z3解tea,发现z3一直处于运行状态,他也不报unsat无解,就搁哪一直运行
我感觉可能是z3的速度受到了某种逻辑运算的限制
遂来研究一下到底是什么影响了z3的速度

二、浅浅的实验一下

tea中的逻辑运算有: >> , << , ^ , & , 常规的加减乘除
测试代码如下:
# from ctypes import * # 实验原因,使用 & 0xffffffff 代替使用 ctypes def encrypt(v, k): v0, v1 = v[0], v[1] delta = 0x9e3779b9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] total = 0 for i in range(4): total += delta total = total & 0xffffffff v0 += ((((v1<<4)&0xffffffff) + k0)&0xffffffff) ^ ((v1 + total)&0xffffffff) ^ (((v1>>5) + k1) & 0xffffffff) v0 = v0 & 0xffffffff v1 += ((((v0<<4)&0xffffffff) + k2)&0xffffffff) ^ ((v0 + total)&0xffffffff) ^ (((v0>>5) + k3) & 0xffffffff) v1 = v1 & 0xffffffff return v0, v1 def decrypt(v, k): v0, v1 = c_uint32(v[0]), c_uint32(v[1]) delta = 0x9e3779b9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] total = c_uint32(delta * 32) for i in range(32): v1.value -= ((v0.value<<4) + k2) ^ (v0.value + total.value) ^ ((v0.value>>5) + k3) v0.value -= ((v1.value<<4) + k0) ^ (v1.value + total.value) ^ ((v1.value>>5) + k1) total.value -= delta return v0.value, v1.value # test if __name__ == "__main__": # 待加密的明文,两个32位整型,即64bit的明文数据 value = [0x12345678, 0x78563412] # 四个key,每个是32bit,即密钥长度为128bit key = [0x1, 0x2, 0x3, 0x4] print("Data is : ", hex(value[0]), hex(value[1])) res = encrypt(value, key) print("Encrypted data is : ", hex(res[0]), hex(res[1])) res = decrypt(res, key) print("Decrypted data is : ", hex(res[0]), hex(res[1])) from z3 import * import time def encrypt(v, k): v0, v1 = v[0], v[1] delta = 0x9e3779b9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] total = 0 for i in range(4): total += delta total = total & 0xffffffff v0 += ((((v1<<4)&0xffffffff) + k0)&0xffffffff) ^ ((v1 + total)&0xffffffff) ^ (((LShR(v1,5)) + k1) & 0xffffffff) v0 = v0 & 0xffffffff v1 += ((((v0<<4)&0xffffffff) + k2)&0xffffffff) ^ ((v0 + total)&0xffffffff) ^ (((LShR(v0,5)) + k3) & 0xffffffff) v1 = v1 & 0xffffffff return v0, v1 # test if __name__ == "__main__": # 待加密的明文,两个32位整型,即64bit的明文数据 value = [BitVec('v[%d]' % i, 32) for i in range(2)] # 四个key,每个是32bit,即密钥长度为128bit key = [0x1, 0x2, 0x3, 0x4] res = encrypt(value, key) ti = time.time() x = Solver() x.add(res[0] == 0xa078b305) x.add(res[1] == 0xb99977fd) print(x.check()) print(x.model()) ti = time.time() - ti print(ti)

 

实验发现,当循环取两重循环即以内的时候,z3会将tea加密其秒解,但当循环数等于三的时候 ,用时: 110.46944308280945 s.. 当循环数等于四时,用时: 1067.981635093689s  一千多秒,很夸张的...
猜测,可能是 & ffffffff 带来的问题
尝试把tea 加密中的 & 0xffffffff 去掉,再来实验
# from ctypes import * def encrypt(v, k): v0, v1 = v[0], v[1] delta = 0x9e3779b9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] total = 0 for i in range(4): total += delta total = total v0 += ((((v1<<4)) + k0)) ^ ((v1 + total)) ^ (((v1>>5) + k1)) v1 += ((((v0<<4)) + k2)) ^ ((v0 + total)) ^ (((v0>>5) + k3) ) return v0, v1 def decrypt(v, k): v0, v1 = c_uint32(v[0]), c_uint32(v[1]) delta = 0x9e3779b9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] total = c_uint32(delta * 32) for i in range(32): v1.value -= ((v0.value<<4) + k2) ^ (v0.value + total.value) ^ ((v0.value>>5) + k3) v0.value -= ((v1.value<<4) + k0) ^ (v1.value + total.value) ^ ((v1.value>>5) + k1) total.value -= delta return v0.value, v1.value # test if __name__ == "__main__": # 待加密的明文,两个32位整型,即64bit的明文数据 value = [0x12345678, 0x78563412] # 四个key,每个是32bit,即密钥长度为128bit key = [0x1, 0x2, 0x3, 0x4] print("Data is : ", hex(value[0]), hex(value[1])) res = encrypt(value, key) print("Encrypted data is : ", hex(res[0]), hex(res[1])) res = decrypt(res, key) print("Decrypted data is : ", hex(res[0]), hex(res[1])) from z3 import * import time def encrypt(v, k): v0, v1 = v[0], v[1] delta = 0x9e3779b9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] total = 0 for i in range(4): total += delta total = total v0 += ((((v1<<4)) + k0)) ^ ((v1 + total)) ^ (((LShR(v1,5)) + k1) ) v1 += ((((v0<<4)) + k2)) ^ ((v0 + total)) ^ (((LShR(v0,5)) + k3) ) return v0, v1 # test if __name__ == "__main__": # 待加密的明文,两个32位整型,即64bit的明文数据 value = [BitVec('v[%d]' % i, 32) for i in range(2)] # 四个key,每个是32bit,即密钥长度为128bit key = [0x1, 0x2, 0x3, 0x4] res = encrypt(value, key) ti = time.time() x = Solver() x.add(res[0] == 0xa078b305) x.add(res[1] == 0xb99977fd) print(x.check()) print(x.model()) ti = time.time() - ti print(ti)
 循环为数1: 0.12765717506408691      循环数为2 : 1.7862217426300049             循环数为3:  471 s 寄
 看来 &0xffffffff 是对z3求解影响不大
 猜测,应该只能是堆叠的逻辑特别多的原因,这可能只能从z3源码、从其本质上找了....
而当我尝试把tea加密中的移位运算全换成加法 运算
from ctypes import * from z3 import * import time def encrypt(v, k): v0, v1 = v[0], v[1] delta = 0x9e3779b9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] total = 0 for i in range(3): total += delta total = total v0 += ((((v1<<4)) + k0)) + ((v1 + total)) + (((v1>>5) + k1) ) v1 += ((((v0<<4)) + k2)) + ((v0 + total)) + (((v0>>5) + k3) ) return v0, v1 # test if __name__ == "__main__": # 待加密的明文,两个32位整型,即64bit的明文数据 value = [0x38508261ba70, 0x5b21fc55c525] # 四个key,每个是32bit,即密钥长度为128bit key = [0x1, 0x2, 0x3, 0x4] print("Data is : ", hex(value[0]), hex(value[1])) res = encrypt(value, key) print("Encrypted data is : ", hex(res[0]), hex(res[1])) from ctypes import * def encrypt(v, k): v0, v1 = v[0], v[1] delta = 0x9e3779b9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] total = 0 for i in range(3): total += delta total = total v0 += ((((v1<<4)) + k0)) + ((v1 + total)) + (((v1>>5) + k1) ) v1 += ((((v0<<4)) + k2)) + ((v0 + total)) + (((v0>>5) + k3) ) return v0, v1 # test if __name__ == "__main__": value = [BitVec('v[%d]' % i, 128) for i in range(2)] key = [0x1, 0x2, 0x3, 0x4] x = Solver() ti = time.time() res = encrypt(value, key) x.add(res[0] == 0x82d3b64ea3da88a78) x.add(res[1] == 0x8bbcd799c0779d9ed9) print(x.check()) print(x.model()) ti = time.time() - ti print(ti)
3重循环用时 0.9733951091766357s   10重循环用时 6.563446521759033s    20重循环: 8.32275104522705s  32重循环: 14.628233671188354 s,可以发现,z3的效率极高
而但我们把tea加密中的 ^ 换掉,换成 +  3重循环用时: 3h+(运行三小时没出结果)...                

三、最终结论

导致z3 求解爆炸的主要原因是 层层嵌套 ,而移位操作和其他逻辑操作产生的化学反应或许是影响z3求解速率的根本原因

 

__EOF__

本文作者_TLSN
本文链接https://www.cnblogs.com/lordtianqiyi/articles/16683107.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   TLSN  阅读(129)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示