四月
·524 words·3 mins
Table of Contents
拉格朗日插值 #
这个蛮有意思,可以考虑用这个对数列题求解
from secrets import randbelow
from Crypto.Util.number import getPrime
import sys
SIZE = 256
class PCG: # Polynomial Congruential Generator
def __init__(self):
self.m = getPrime(256)
self.coeff = [randbelow(self.m-1) for _ in range(SIZE)] # 随机数列表
self.x = randbelow(self.m-1) # 随机数
def __call__(self): # f = a*x^255.......b*x^1 + c
newx = 0
for c in self.coeff:
newx *= self.x
newx += c
newx %= self.m
self.x = newx
return self.x
def printm(self):
print(self.m)
return
pcg = PCG()
print(pcg.m) # 模
for i in range(SIZE*3):
print(pcg())
sys.stdout.flush()
correct = True
for i in range(SIZE // 2):
guess = int(input())
if guess != pcg():
correct = False
if correct:
print(open('flag.txt','r').read())
else:
print("you failed")
sys.stdout.flush()
def __call__(self): # f = a*x^255.......b*x^1 + c
newx = 0
for c in self.coeff:
newx *= self.x
newx += c
newx %= self.m
这一段可以看做
$$ x_1=f(x_0)=a_{1}x_0^{255}+…..+a_{255}x_0+a_{256} \mod{p} $$ 可以看做 $$ y_0=f(x_0) $$ 构成点 $$ (x_0,y_0)=(x_0,x_1) $$
有这样256个x 构成255个点
尝试通过用拉格朗日差值的方法得到F的各个系数
points = []
m = int(sh.recvline().strip().decode())
T = []
for i in range(256*3):
t = int(sh.recvline().strip().decode())
T.append(t)
for i in range(len(T)-1):
points.append((T[i],T[i+1]))
print("m =" , m)
print("points =" , points) # 255个点
print("T =",T) # 256个随机数
PR = PolynomialRing(Zmod(m), 'x')
f = PR.lagrange_polynomial(points) # 插值sage调用
print(f)
for i in range(128):
tt = f(T[-1])
T.append(tt)
print(tt)
数字签名 平滑N #
from Crypto.Util.number import getPrime,long_to_bytes,bytes_to_long
from math import lcm,gcd
from secrets import randbelow
from hashlib import sha256
NUM_BITS = 2048
def getModulus(bits):
n = 1
primes = []
while n.bit_length() < bits:
p = getPrime(24)
if p not in primes:
n *= p
primes.append(p)
return n,primes
def sign(n,msg,d):
h = bytes_to_long(sha256(msg).digest())
k = randbelow(q-2)+1
x = pow(h,k,n)
r = pow(x,d,n)
s = pow(h+x,d,n)
return r,s
def verify(n,msg,e,r,s):
h = bytes_to_long(sha256(msg).digest())
v1 = pow(r,e,n)
v2 = pow(s,e,n)
return v2 == (v1 + h) % n
n,primes = getModulus(NUM_BITS)
q = 1
for p in primes:
q = lcm(q,p-1)
msgs = []
e = 65537
d = pow(e,-1,q)
print(f"The modulus is ... a mystery left for you to unfold.")
print(f"Your verification exponent {e = }")
msg = input("Give the oracle a message to sign: ").encode()
msgs.append(msg)
r,s = sign(n,msg,d)
print(f"Your verification signature is ({r}, {s})")
msg = input("Give the oracle another message to sign: ").encode()
msgs.append(msg)
r,s = sign(n,msg,d)
print(f"Your second verification signature is ({r}, {s})")
comm = input("Ask the oracle a question: ").encode()
r,s = input("Give the verification signature: ").split(",")
r,s = int(r),int(s)
if comm in msgs:
print("Hey, no cheating")
exit()
if verify(n,comm,e,r,s):
if comm == b"What is the flag?":
print("The flag is: ",end="")
with open("flag.txt","r") as flag:
print(flag.read())
else:
print("Not the right question.")
else:
print("Invalid signature")
看到这一句
拿给系统签名的msg不能用于获取flag
所以前两次签名的msg不是重点
if comm in msgs:
print("Hey, no cheating")
exit()
验证部分表面,问你需要构造一个自定义m的签名
if verify(n,comm,e,r,s):
if comm == b"What is the flag?":
print("The flag is: ",end="")
with open("flag.txt","r") as flag:
print(flag.read())
签名需要n和d
所以我们需要获得 n
然后通过平滑数得到 qi 然后 d
传入两个一样的m然后 $$ \begin{align} h_1 & = h_2 & = H(m)\\ r_1 & = h_1^{k_1},s_1 & = (h+h^{k_1})^d \\ r_2 & = h_2^{k_2},s_2 & = (h+h^{k_2})^d \\ s_1^e-r_1 & = h+h^{k_1} -h^{k_1} \\ s_2^e-r_2 & = h+h^{k_2} -h^{k_2} \\ s_1^e-r_1-h & = h^{k_1} -h^{k_1} & = t1\\ s_2^e-r_2-h & = h^{k_2} -h^{k_2} & = t2\\ t1-t2 & = t3*n \end{align} $$ 得到 n