@@ -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
141222def 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
166249def 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
302385if __name__ == '__main__' :
303386 doctest .testmod () # pragma: no cover
0 commit comments