option 1では との結果を得ることができる。ただし時折 が壊れた値になるらしい
option 2では 任意の平文 に対してを計算してもらえる
まずは楕円曲線上の点を集めて楕円曲線のパラメータを当てるところからやる。
に対して
同様に
この2式に対して次の計算をして、の影響を消すことができる
同様に 計算していって 6個の点から4つの を計算する(ここでそれぞれの式は高々2回しか使っていないことに注意する。こうしないとのの部分に共通の項が現れてGCDで消えなくなる)
ここまでの話をまとめたものを楕円曲線/6点からパラメータを復元するに書いた。
これの結果、 p = 0xfffffffdffffffffffffffffffffffff
がわかる
これと2点があれば、次のようにがわかる
ということでこれをやると次のパラメータが求まる。
p = 0xfffffffdffffffffffffffffffffffff a = 0xd6031998d1b3bbfebf59cc9bbff9aee1 b = 0x5eeefca380d02919dc2c6558bb6d8a5d
これはsecp128r1という有名なパラメータで、こんなのの上ではまず離散対数問題は解けない。
というわけで壊れたとそれの を攻略していく。その前にをとっておく。これは\x01
を暗号化してもいいし、適当に暗号化したやつに対して楕円曲線:逆数をかけるをやっても良い
さてこのような暗号化が成功するには正しい、と壊れたの楕円曲線について、がそれぞれの上に無いといけないわけだが、実はこのとき、だけでなくも異なっている。とにかく異なっている。
の3点から、とを求める
このとき、は素数でない可能性が高い。素数でないとPohlig HellmanみたいなことをしてもCRTでの復元ができない(=実質離散対数が存在しない)ので、いくつかのパラメータをとってきて、の小さい約数に関して離散対数問題を求めて、CRTで復元する
def recover_p(points): """ NOTICE: points must be int or Integer not on ModRing """ xs = [] for i in range(len(points)): xs.append(points[i][0]) xy = [] for i in range(len(points)): xy.append(points[i][0]**3 - points[i][1]**2 ) diffs = [] for i in range(len(xy)-1): diffs.append(xy[i] - xy[i+1]) pk = [] for i in range(len(diffs)-1): pk.append(diffs[i] * (xs[i+1] - xs[i+2]) - diffs[i+1] * (xs[i] - xs[i+1])) return gcd(pk) # p or p * small p = random_prime(1 << 150) a = randint(2, p - 1) b = randint(2, p - 1) EC = EllipticCurve(GF(p), [a, b]) points = [EC.random_point() for _ in range(6)] for i in range(len(points)): points[i] = [Integer(xy) for xy in points[i].xy()] p_ = recover_p(points) print(p_) print(p) a_ = (points[0][1] ** 2 - points[1][1] ** 2 - points[0][0] ** 3 + points[1][0] ** 3) * inverse_mod(points[0][0] - points[1][0], p) % p print(a_) print(a) b_ = (points[0][1] ** 2 - points[0][0] ** 3 - points[0][0] * a_) % p print(b_) print(b)