Skip to content

Commit 955f8c0

Browse files
authored
Fix issues with overflows (#73)
* Fix issues with overflows * Minor: PEP8 * Test that we actually fixed #62 * Get rid of a bunch of code by using the standard library... * Minor: unused imports * Minor: helpful comment
1 parent fe24881 commit 955f8c0

2 files changed

Lines changed: 26 additions & 3 deletions

File tree

phe/encoding.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fractions
12
import math
23
import sys
34

@@ -186,7 +187,9 @@ def encode(cls, public_key, scalar, precision=None, max_exponent=None):
186187
else:
187188
exponent = min(max_exponent, prec_exponent)
188189

189-
int_rep = int(round(scalar * pow(cls.BASE, -exponent)))
190+
# Use rationals instead of floats to avoid overflow.
191+
int_rep = round(fractions.Fraction(scalar)
192+
* fractions.Fraction(cls.BASE) ** -exponent)
190193

191194
if abs(int_rep) > public_key.max_int:
192195
raise ValueError('Integer needs to be within +/- %d but got %d'
@@ -217,7 +220,17 @@ def decode(self):
217220
else:
218221
raise OverflowError('Overflow detected in decrypted number')
219222

220-
return mantissa * pow(self.BASE, self.exponent)
223+
if self.exponent >= 0:
224+
# Integer multiplication. This is exact.
225+
return mantissa * self.BASE ** self.exponent
226+
else:
227+
# BASE ** -e is an integer, so below is a division of ints.
228+
# Not coercing mantissa to float prevents some overflows.
229+
try:
230+
return mantissa / self.BASE ** -self.exponent
231+
except OverflowError as e:
232+
raise OverflowError(
233+
'decoded result too large for a float') from e
221234

222235
def decrease_exponent_to(self, new_exp):
223236
"""Return an `EncodedNumber` with same value but lower exponent.
@@ -249,4 +262,4 @@ def decrease_exponent_to(self, new_exp):
249262
'old exponent %i' % (new_exp, self.exponent))
250263
factor = pow(self.BASE, self.exponent - new_exp)
251264
new_enc = self.encoding * factor % self.public_key.n
252-
return self.__class__(self.public_key, new_enc, new_exp)
265+
return self.__class__(self.public_key, new_enc, new_exp)

phe/tests/paillier_test.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,16 @@ def testKeyring(self):
10851085
self.assertRaises(KeyError, keyring1.decrypt, ciphertext1)
10861086

10871087

1088+
class TestIssue62(unittest.TestCase):
1089+
def testIssue62(self):
1090+
pub, priv = paillier.generate_paillier_keypair()
1091+
a = pub.encrypt(445)
1092+
# Force big exponent.
1093+
b = pub.encrypt(0.16413409062205825) + pub.encrypt(2 ** -965)
1094+
# This will raise OverflowError without bugfix #73.
1095+
priv.decrypt(a + b)
1096+
1097+
10881098
def main():
10891099
unittest.main()
10901100

0 commit comments

Comments
 (0)