#sage
from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler as d_gauss
flag = bytearray(raw_input())
flag = list(flag)
n = len(flag)
q = 40961
## Finite Field of size q.
F = GF(q)
## Univariate Polynomial Ring in y over Finite Field of size q
R.<y> = PolynomialRing(F)
## Univariate Quotient Polynomial Ring in x over Finite Field of size 40961 with modulus b^n + 1
S.<x> = R.quotient(y^n + 1)
def gen_small_poly():
sigma = 2/sqrt(2*pi)
d = d_gauss(S, n, sigma)
return d()
def gen_large_poly():
return S.random_element()
## Public key 1
a = gen_large_poly()
## Secret key
s = S(flag)
file_out = open("downloads/public_keys.txt", "w")
file_out.write("a: " + str(a) + "\n")
for i in range(100):
## Error
e = gen_small_poly()
## Public key 2
b = a*s + e
file_out.write("b: " + str(b) + "\n")
file_out.close()
通过观察e的生成函数可以发现多项式e上的很多位都为0,这就说明我们可以通过统计b中的相应位上的出现次数最多的 系数作为a*s的值,而a我们又是知道的,所以就可以求出s来.从而绕过e的干扰.
#sage
from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler as d_gauss
keys = open("public_keys.txt", "r").read().split("\n")[:-1]
temp1 = keys[0].find("^")
temp2 = keys[0].find(" ", temp1)
n=int(keys[0][temp1+1:temp2])+1
print(n)
q = 40961
F = GF(q)
R.<y> = PolynomialRing(F)
S.<x> = R.quotient(y^n + 1)
num=[]
for i in range(n):
num.append({
})
#print(num)
a=S(keys[0].replace('a: ',''))
#print(a)
keys=keys[1:]
for key in keys:
b=key.replace('b: ','')
li=list(S(b))
#print(li)
for i in range(len(num)):
try:
num[i][li[i]]+=1
except:
num[i][li[i]]=1
asnum=[]
#print(num)
for i in num:
asnum.append(max(i,key=i.get))
#print(asnum)
aspoly=S(asnum)
flag=aspoly/a
print(list(flag))
flag=''.join(map(chr,flag))
print(flag)
#watevr{rlwe_and_statistics_are_very_trivial_when_you_reuse_same_private_keys#02849jedjdjdj202ie9395u6ky}