解ける暗号。超増加列を用いた場合に部分和問題が簡単に解けることを利用して復号を行い、超増加列を鍵とすると簡単に解けてしまうため、各をと変換して一般の数列にすることで暗号化鍵からの復号を妨げている。
暗号文は一つの数値に、秘密鍵や公開鍵は数列になる。nbitの平文を暗号化するためにn要素の数列が必要
鍵生成
超増加列 を作る。超増加列は となっている、つまり、それまでの総和より大きい数からなる数列らしい。
である と の を選ぶ。 を素数にすれば は適当に選べる
(( ), q, r)が秘密鍵
として( )が公開鍵
暗号化
nビットの平文mをビット単位で分割して( )とする
暗号文C =
復号
なるsを用意して、 C' = CSとする。
C' =
は0, 1なので、以下の手順で大きい方から順番に平文を復元できる
C'と を比較して なら 、 なら である。
なら
攻撃
CLOS法が今の所一番強そう。よくわかってないが↓のsageスクリプトに突っ込む
https://kimiyuki.net/writeup/ctf/2015/plaidctf-2015-lazy/
b = c = # check the density n = len(b) d = float(n / log(max(b), 2)) assert(d < 0.9048) # low-density attack, CLOS method # prepare a basis MULTIPLIER = 100 B = matrix(ZZ, n + 1, n + 1) B.set_block(0, 0, MULTIPLIER * matrix(n, 1, b)) B.set_block(n, 0, MULTIPLIER * matrix([-c])) B.set_block(0, 1, 2 * identity_matrix(n)) B.set_block(n, 1, matrix([-1] * n)) # LLL algorithm for x in B.LLL(): print(x) if x[0] == 0 and all((x_i in [-1, +1]) for x_i in x[1:]): print('x={}'.format(x)) # decode x m = 0 for x_i in reversed(x[1:]): m *= 2 m += int(x_i == +1) print('m={}'.format(m))
LLLによる攻撃の原理
ナップザック暗号は部分和問題である。暗号文と、公開鍵となる数列が与えられたときに、次の等式を満たすが求めたい平文
http://www.cs.sjsu.edu/faculty/stamp/papers/topics/topic16/Knapsack.pdf が丁寧