2023-08-25 02:40:40 +08:00

196 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
前置知识(建议要看,非常自信可以不看)
https://zhuanlan.zhihu.com/p/448198789
信息论的一些基础
可以结合这份ppt来看
https://web.xidian.edu.cn/jwliu/files/20190521_003040.pdf
同时b站上的国防科技大学-信息论与编码基础也可以学习一下
https://www.bilibili.com/video/BV1pJ411U7G8?p=61
读题可知我们需要获取一个7bit的有效信息每次返回的信息可以看作1bit共15bit。
而其中1-2次的说谎我们可以视为1-2bit的传输错误。
因此我们需要一种最少可以纠正2bit的编码也就是循环冗余校验
根据题目描述我们需要构造一个157循环码也就是15bit的编码数7bit的有效信息数
"""
# 首先定义伽罗瓦域
R.<x> = PolynomialRing(GF(2))
"""
然后寻找生成元g
根据定理nk循环码的生成元g一定是x^n+1的n-k次因子
ppt中说是x^n-1,这里因为是GF(2),所以+1和-1是等价的
带入计算得知g应当为x^15+1的8次因子
"""
ff = x^15+1
g = factor(ff)
# (x + 1) * (x^2 + x + 1) * (x^4 + x + 1) * (x^4 + x^3 + 1) * (x^4 + x^3 + x^2 + x + 1)
factors = []
for i in range(len(g)):
factors.append(g[i][0])
possible_g = []
# x + 2 * y + 4 * z == 8
# root = [(8,0,0),(6,1,0),(4,2,0),(4,0,1),(2,3,0),(2,1,1),(0,4,0),(0,2,1),(0,0,2)]
possible_g.append(factors[0]^8)
possible_g.append(factors[0]^6 * factors[1])
possible_g.append(factors[0]^4 * factors[1]^2)
possible_g.append(factors[0]^4 * factors[2])
possible_g.append(factors[0]^4 * factors[3])
possible_g.append(factors[0]^4 * factors[4])
possible_g.append(factors[0]^2 * factors[1]^3)
possible_g.append(factors[0]^2 * factors[1] * factors[2])
possible_g.append(factors[0]^2 * factors[1] * factors[3])
possible_g.append(factors[0]^2 * factors[1] * factors[4])
possible_g.append(factors[1]^4)
possible_g.append(factors[1]^2 * factors[2])
possible_g.append(factors[1]^2 * factors[3])
possible_g.append(factors[1]^2 * factors[4])
possible_g.append(factors[2] * factors[2])
possible_g.append(factors[2] * factors[3])
possible_g.append(factors[2] * factors[4])
possible_g.append(factors[3] * factors[3])
possible_g.append(factors[3] * factors[4])
possible_g.append(factors[4] * factors[4])
"""
至此我们已经找出所有的生成元了,但是不要忘了还有纠错的要求。
纠正2bit的要求则是 假设用d表示码组的最小汉明距离纠正错误时设可纠正t位的错误则d >= 2t+1
也就是保证任一点A的错误状态不落到其余点B并且A的错误状态离A更近
带入公式则是d >= 5
"""
# 定义函数 n2p将二进制数转换为多项式的形式
def n2p(a):
a = bin(a)[2:]
p = 0
for i in range(len(a)):
if a[len(a) - i - 1] == '1':
p += x^i
return p
# 定义函数enc将7bit的信息编码成循环码
def enc(i):
m = n2p(i)
c = (x^8) * m + (((x^8) * m) % g)
return "".join([str(int(i in c.exponents())) for i in range(15)])[::-1]
# 定义函数dif计算ab之间的汉明距离
def dif(a, b):
cnt = 0
for i in range(len(a)):
if a[i] != b[i]:
cnt += 1
return cnt
"""
通过构造校验表来检查所有的生成元是否满足条件
"""
for g in possible_g:
# 创建一个列表 dic存储不同输入值的编码
dic = []
for i in range(2**7):
dic.append(enc(i))
minHD = 15
for i in dic:
for j in dic:
if i == j:
continue
if dif(i,j) <= minHD:
minHD = dif(i,j)
#if minHD >= 5:
#print(g)
# x^8 + x^7 + x^6 + x^4 + 1
# x^8 + x^4 + x^2 + x + 1
# 下面两个随便挑一个作为生成元就好了
# g = x^8 + x^7 + x^6 + x^4 + 1
g = x^8 + x^4 + x^2 + x + 1
dic = []
for i in range(2^7):
dic.append(enc(i))
"""
构造问题这个地方有点巧妙。
我们可以发现系统码是一个对称互补的码也就是说0和1271和126的系统码每一位都相反。
那么对于所有系统码来说0和1就是平均分布的。因为成对来看30个bit中必有15bit的0和15bit的1
对于系统码的任意一位为0的概率就是0.5为1的概率也是0.5
因此我们可以把questions[i]和j[i]等价来看,
我们可以找出所有令j[i]==1的信息码情况共64种把这些进行or运算。
把这个问题发送出去如果返回true那么证明j[i]就是1。
以此类推我们就可以得到一串15bit的返回值。
但是因为存在最多2bit的错误我们需要跟码表进行对比找出汉明距离小于等于2的系统码。
然后这个系统码对应的信息码就是正确的信息码
"""
# 定义字符串模板 part用于后面构造问题
part = "( C0 == {} and C1 == {} and C2 == {} and C3 == {} and C4 == {} and C5 == {} and C6 == {} ) "
# 创建问题列表 questions用于存储构造的问题模板
questions = []
for i in range(15):
question = ""
nums = [j[:7] for j in dic if j[i] == '1']
for j in range(64):
n = nums[j]
question += part.format(n[0], n[1], n[2], n[3], n[4], n[5], n[6]) + "or "
questions.append(question[:-4])
# 导入 pwn 模块,用于与远程或本地进程进行交互
from pwn import *
# 设置日志级别为 debug以便在执行过程中输出详细日志信息
#context.log_level = 'debug'
r = process(['python3', 'main_local.py'])
#r = remote("localhost", "10011")
for i in range(1):
msg = ''
# 逐个发送问题并接收答案
for j in range(15):
r.sendlineafter(b"Shannon:", questions[j].encode())
r.recvuntil(b"answers:")
if b'True' in r.recvuntil(b"!"):
msg += '1'
else:
msg += '0'
# 查找与收到的答案最接近的编码,这里答案肯定只会有一个
for j in range(128):
if (dif(msg, dic[j]) <= 2):
break
ans = ""
for k in dic[j][:7]:
ans += k + " "
# 发送解码后的答案
r.sendlineafter(b"chests:", ans.encode())
flag = r.recvall()
print(flag)
r.close()