Skip to content

Commit 60b6297

Browse files
committed
Add overloaded operators for ciphertexts; explicitly export classes/functions.
1 parent 4358160 commit 60b6297

File tree

3 files changed

+109
-8
lines changed

3 files changed

+109
-8
lines changed

docs/conf.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@
6262

6363
# Options to configure autodoc extension behavior.
6464
autodoc_member_order = 'bysource'
65+
autodoc_default_options = {
66+
'special-members': True,
67+
'exclude-members': ','.join([
68+
'__parameters__',
69+
'__orig_bases__',
70+
'__annotations__',
71+
'__new__',
72+
'__init__',
73+
'__weakref__',
74+
'__module__',
75+
'__hash__',
76+
'__dict__'
77+
])
78+
}
6579
autodoc_preserve_defaults = True
6680

6781
# Allow references/links to definitions found in the Python documentation

src/pailliers/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
"""Allow users to access the classes and functions directly."""
2-
from pailliers.pailliers import *
2+
from pailliers.pailliers import \
3+
secret, public, \
4+
plain, cipher, \
5+
encrypt, decrypt, \
6+
add, mul

src/pailliers/pailliers.py

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class secret(Tuple[int, int, int, int]):
5252
"""
5353
Wrapper class for a tuple of four integers that represents a secret key.
5454
55-
>>> secret_key = secret(256)
55+
>>> secret_key = secret(2048)
5656
>>> public_key = public(secret_key)
5757
>>> isinstance(secret_key, secret)
5858
True
@@ -97,7 +97,7 @@ class public(Tuple[int, int]):
9797
"""
9898
Wrapper class for a pair of integers that represents a public key.
9999
100-
>>> public_key = public(secret(256))
100+
>>> public_key = public(secret(2048))
101101
>>> isinstance(public_key, public)
102102
True
103103
@@ -131,12 +131,93 @@ class cipher(int):
131131
"""
132132
Wrapper class for an integer that represents a ciphertext.
133133
134-
>>> secret_key = secret(256)
134+
>>> secret_key = secret(2048)
135135
>>> public_key = public(secret_key)
136136
>>> ciphertext = encrypt(public_key, plain(123))
137137
>>> isinstance(ciphertext, cipher)
138138
True
139139
"""
140+
def __init__(self: cipher, integer: int): # pylint: disable=unused-argument
141+
super(type(self))
142+
self._public_key = None
143+
144+
def __add__(self: cipher, other: cipher) -> cipher:
145+
"""
146+
Perform addition of encrypted values to produce the encrypted
147+
result.
148+
149+
>>> secret_key = secret(2048)
150+
>>> public_key = public(secret_key)
151+
>>> c = encrypt(public_key, 22)
152+
>>> d = encrypt(public_key, 33)
153+
>>> r = c + d
154+
>>> int(decrypt(secret_key, r))
155+
55
156+
"""
157+
ciphertext = add(self._public_key, self, other)
158+
setattr(ciphertext, '_public_key', self._public_key)
159+
return ciphertext
160+
161+
def __iadd__(self: cipher, other: cipher) -> cipher:
162+
"""
163+
Add an encrypted value to an existing encrypted value.
164+
165+
>>> secret_key = secret(2048)
166+
>>> public_key = public(secret_key)
167+
>>> c = encrypt(public_key, 22)
168+
>>> d = encrypt(public_key, 33)
169+
>>> c += d
170+
>>> int(decrypt(secret_key, c))
171+
55
172+
"""
173+
ciphertext = add(self._public_key, self, other)
174+
setattr(ciphertext, '_public_key', self._public_key)
175+
return ciphertext
176+
177+
def __mul__(self: cipher, scalar: int) -> cipher:
178+
"""
179+
Perform multiplication of an encrypted value by a scalar to produce
180+
the encrypted result.
181+
182+
>>> secret_key = secret(2048)
183+
>>> public_key = public(secret_key)
184+
>>> c = encrypt(public_key, 22)
185+
>>> r = c * 3
186+
>>> int(decrypt(secret_key, r))
187+
66
188+
"""
189+
ciphertext = mul(self._public_key, self, scalar)
190+
setattr(ciphertext, '_public_key', self._public_key)
191+
return ciphertext
192+
193+
def __rmul__(self: cipher, scalar: int) -> cipher:
194+
"""
195+
Perform multiplication of an encrypted value by a scalar (that appears
196+
on the left side of the operator) to produce the encrypted result.
197+
198+
>>> secret_key = secret(2048)
199+
>>> public_key = public(secret_key)
200+
>>> c = encrypt(public_key, 22)
201+
>>> r = 3 * c
202+
>>> int(decrypt(secret_key, r))
203+
66
204+
"""
205+
return self.__mul__(scalar)
206+
207+
def __imul__(self: cipher, scalar: int) -> cipher:
208+
"""
209+
Perform multiplication of an encrypted value by a scalar.
210+
211+
>>> secret_key = secret(2048)
212+
>>> public_key = public(secret_key)
213+
>>> c = encrypt(public_key, 22)
214+
>>> c *= 3
215+
>>> int(decrypt(secret_key, c))
216+
66
217+
"""
218+
ciphertext = mul(self._public_key, self, scalar)
219+
setattr(ciphertext, '_public_key', self._public_key)
220+
return ciphertext
140221

141222
def encrypt(public_key: public, plaintext: Union[plain, int]) -> cipher:
142223
"""
@@ -161,7 +242,9 @@ def encrypt(public_key: public, plaintext: Union[plain, int]) -> cipher:
161242

162243
(n, g) = public_key
163244
r = _generator(n)
164-
return cipher(pow(g, plaintext % n, n ** 2) * pow(r, n, n ** 2))
245+
ciphertext = cipher(pow(g, plaintext % n, n ** 2) * pow(r, n, n ** 2))
246+
setattr(ciphertext, '_public_key', public_key)
247+
return ciphertext
165248

166249
def decrypt(secret_key: secret, ciphertext: cipher) -> plain:
167250
"""
@@ -252,11 +335,11 @@ def add(public_key: public, *ciphertexts: cipher) -> cipher:
252335

253336
modulus: int = public_key[0] ** 2
254337
ciphertexts = iter(ciphertexts)
255-
result = next(ciphertexts)
338+
result = int(next(ciphertexts))
256339
for ciphertext in ciphertexts:
257340
if not isinstance(ciphertext, cipher):
258341
raise TypeError('can only add ciphertexts')
259-
result = (result * ciphertext) % modulus
342+
result = (result * int(ciphertext)) % modulus
260343

261344
return cipher(result)
262345

@@ -297,7 +380,7 @@ def mul(public_key: public, ciphertext: cipher, scalar: int) -> cipher:
297380
if not isinstance(scalar, int):
298381
raise TypeError('can only multiply by an integer scalar')
299382

300-
return cipher((ciphertext ** scalar) % (public_key[0] ** 2))
383+
return cipher((int(ciphertext) ** scalar) % (public_key[0] ** 2))
301384

302385
if __name__ == '__main__':
303386
doctest.testmod() # pragma: no cover

0 commit comments

Comments
 (0)