Source code for pkenc_gm82
'''
Goldwasser-Micali Public Key Encryption Scheme (Quadratic Residuosity problem)
| From: "S. Goldwasser, S. Micali: Probabilistic encryption and how to play
| mental poker keeping secret all partial information"
| Published in: 14th Symposium on Theory of Computing (1982)
| Available from: http://groups.csail.mit.edu/cis/pubs/shafi/1982-stoc.pdf
| Notes:
* type: encryption (public key)
* setting: Integer
* assumption: Quadratic Residuosity
:Authors: Guillermo Ramos
:Date: 01/2015
'''
from charm.core.math.integer import legendre, gcd
from charm.toolbox.integergroup import RSAGroup, integer
from charm.toolbox.PKEnc import PKEnc
# Upper bound to the number of rounds the keygen is able to make
# to search for a quadratic non-residue
maxtimes = 30
# Is x a quadratic residue of N = p1*p2?
[docs]def isResidue(x, p1, p2):
return legendre(x, p1) == 1 or legendre(x, p2) == 1
# Goldwasser-Micali cryptosystem
[docs]class GM82(PKEnc):
"""
>>> gm82 = GM82()
>>> (pk, sk) = gm82.keygen(512)
>>> zero = gm82.encrypt(pk, 0)
>>> one = gm82.encrypt(pk, 1)
>>> gm82.decrypt(sk, zero)
0
>>> gm82.decrypt(sk, one)
1
>>> gm82.decrypt(sk, gm82.xor(pk, zero, zero))
0
>>> gm82.decrypt(sk, gm82.xor(pk, zero, one))
1
>>> gm82.decrypt(sk, gm82.xor(pk, one, zero))
1
>>> gm82.decrypt(sk, gm82.xor(pk, one, one))
0
"""
def __init__(self):
PKEnc.__init__(self)
self.group = RSAGroup()
[docs] def keygen(self, secparam):
self.group.paramgen(secparam)
# Find a random quadratic non-residue in the group
x = self.group.random()
times = 1
while times < maxtimes and isResidue(x, self.group.p, self.group.q):
x = self.group.random()
times += 1
# If we are not able to find a quadratic non-residue after 'maxtimes'
# trials, abort and output error
if times == maxtimes:
print("ERROR: non-residue not found after {} trials.".format(times))
return None
pk = (self.group.n, x)
sk = (self.group.p, self.group.q)
return (pk, sk)
[docs] def encrypt(self, pk, m):
(n, x) = pk
y = self.group.random()
while gcd(n, y) != 1:
y = self.group.random()
if m == 0:
return y**2 % n
else:
return y**2 * x % n
[docs] def decrypt(self, sk, c):
(p, q) = sk
return 0 if isResidue(c, p, q) else 1
# Homomorphic XOR over ciphertexts
[docs] def xor(self, pk, c1, c2):
(n, _) = pk
return (c1 * c2) % n