Goldwasser-Micali cryptosystemの拡張? みたいな感じ
鍵生成
と を選ぶ(秘密鍵)
(公開鍵)
暗号化
(ブロックサイズ)
平文 をサイズ のブロック に分割する
をランダムに選ぶ
for from to
暗号文
復号
extended euclidean algorithm で なる と を計算する
として計算できる
証明
特にの証明
まず、はでquadratic residueになるように作っている(適当なを選んでとしているのだからそれはそう)。したがって、はでもquadratic residueである(これはjacobi記号のところに書いてある)
同様にすべてのがとでquadratic residueである。
したがって、が成り立つ(これはjacobi記号をみるとそう書いてある)
したがって、下記が成り立つ
同様に下記も成立する(のでこれを使って逆順にと遡ることもできそう)
ということはであり、
である
これがに相当する
あとは中国人剰余定理でを復元するだけだが、それをやっているのがというわけ
from Crypto.Util.number import getPrime, getRandomRange from math import log2 import gmpy2 from typing import Tuple, Sequence def keygen(size: int) -> Tuple[int, Tuple[int, int]]: while True: p = getPrime(size//2) if p % 4 == 3: break while True: q = getPrime(size//2) if q % 4 == 3: break n = p*q return n, (p, q) def encrypt(n: int, m: int)->Tuple[Sequence[int], int]: h = int(log2(log2(n))) ms = [] while m: m, block = divmod(m, 1 << h) ms.append(block) r = getRandomRange(2, n) x = pow(r, 2, n) cs = [] for i in range(len(ms)): x = pow(x, 2, n) cs.append(ms[i] ^ x) return cs, pow(x, 2, n) def decrypt(p: int, q: int, cs: Sequence[int], x: int)->int: t = len(cs) dp = pow((p+1) // 4, t+1, p-1) dq = pow((q+1) // 4, t+1, q-1) up = pow(x, dp, p) uq = pow(x, dq, q) n = p * q # up == x % p, uq == x % q _, rp, rq = gmpy2.gcdext(p, q) x = int(uq*rp*p + up*rq*q) % n h = int(log2(log2(n))) m = 0 for i in range(len(cs)): x = pow(x, 2, n) m += (cs[i] ^ x) << (h * i) return m n, (p, q) = keygen(1024) m = getRandomRange(2, n) cs, x = encrypt(n, m) m_ = decrypt(p, q, cs, x) assert m == m_