[watevrCTF 2019]Baby RLWE

encrypt

#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()

decrypt

通过观察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}

你可能感兴趣的:(RLWE)