LWE

 \vec{a} = \lbrace a_1, a_2, \dots, a_n \rbrace

秘密の \vec{s} = \lbrace s_1, s_2, \dots, s_n \rbrace

エラー e

があって、 c = \langle \vec{a}, \vec{s} \rangle + e

判定LWE(Desicional LWE)

 \vec{a} cを受け取って、 c = \langle \vec{a}, \vec{s} \rangle + e c \leftarrow \mathbb{Z} かを判定する問題

探索LWE(Search LWE)

 \vec{a} cを受け取って、 \vec{s}を復元する問題

 \mod qを取る場合もあって、その場合はRing LWEと呼ばれる

判定RLWEをSISを解いて解決する

複数のインスタンス A, \vec{c}, \vec{e}が与えられているときの話

SISの解 \vec{y}を求める

もし \vec{c} = \vec{s}A + eなら  \langle \vec{y},\vec{c} \rangle \equiv  \langle \vec{y},\vec{s}A + \vec{e} \rangle \equiv  \langle A\vec{y}, \vec{s}\rangle + \langle \vec{y}, \vec{e} \rangle \equiv \langle \vec{y}, \vec{e} \rangle \mod q

がなりたつので \langle \vec{y},\vec{c} \rangleすなわち \langle \vec{y}, \vec{e} \rangleは十分に小さくなるはずである

例題と回答

#LLL

#CVP

#babai's_rounding

with open("flag.txt", "rb") as f:
  flag = f.read()

flag = vector(list(flag))
p = 65537

def encrypt(m, noise_size=1):
  n = len(m)
  a = random_vector(GF(p), n)
  e = randint(-noise_size, noise_size)
  return a, a.dot_product(m) + e

A = []
B = []
for _ in range(len(flag) * 2):
  a, b = encrypt(flag)
  A.append(list(a))
  B.append(int(b))

print({"A": A, "B": B})
def babai_closest_vector(M, G, target):
  small = target
  for i in reversed(range(M.nrows())):
    c = ((small * G[i]) / (G[i] * G[i])).round()
    small -=  M[i] * c
  return target - small

with open("output.txt") as f:
  data = eval(f.read())
  A = data["A"]
  B = data["B"]

target = vector(B)
p = 65537

n = len(A[0])
m = len(A)


L = matrix(ZZ, m + n, m)
L.set_block(0, 0, matrix(A).transpose())
L.set_block(n, 0, matrix.identity(m) * p)

B = L.LLL()
G = B.gram_schmidt()[0]
closest = babai_closest_vector(B[-m:, -m:], G, target)

print(closest)

flag = matrix(GF(p), A).solve_right(closest)
print(flag)