phe
Advanced tools
| from __future__ import absolute_import, division, print_function | ||
| __all__ = [ | ||
| "__title__", "__summary__", "__uri__", "__version__", "__author__", | ||
| "__email__", "__license__", "__copyright__", | ||
| ] | ||
| __title__ = "phe" | ||
| __summary__ = "Partially Homomorphic Encryption library for Python" | ||
| __uri__ = "https://github.com/n1analytics/python-paillier" | ||
| # We use semantic versioning - semver.org | ||
| __version__ = "1.3.1-dev0" | ||
| __author__ = "N1 Analytics developers" | ||
| __email__ = "info@n1analytics.com" | ||
| __license__ = "GPLv3" | ||
| __copyright__ = "Copyright 2013-2018 {0}".format(__author__) |
+252
| import math | ||
| import sys | ||
| class EncodedNumber(object): | ||
| """Represents a float or int encoded for Paillier encryption. | ||
| For end users, this class is mainly useful for specifying precision | ||
| when adding/multiplying an :class:`EncryptedNumber` by a scalar. | ||
| If you want to manually encode a number for Paillier encryption, | ||
| then use :meth:`encode`, if de-serializing then use | ||
| :meth:`__init__`. | ||
| .. note:: | ||
| If working with other Paillier libraries you will have to agree on | ||
| a specific :attr:`BASE` and :attr:`LOG2_BASE` - inheriting from this | ||
| class and overriding those two attributes will enable this. | ||
| Notes: | ||
| Paillier encryption is only defined for non-negative integers less | ||
| than :attr:`PaillierPublicKey.n`. Since we frequently want to use | ||
| signed integers and/or floating point numbers (luxury!), values | ||
| should be encoded as a valid integer before encryption. | ||
| The operations of addition and multiplication [1]_ must be | ||
| preserved under this encoding. Namely: | ||
| 1. Decode(Encode(a) + Encode(b)) = a + b | ||
| 2. Decode(Encode(a) * Encode(b)) = a * b | ||
| for any real numbers a and b. | ||
| Representing signed integers is relatively easy: we exploit the | ||
| modular arithmetic properties of the Paillier scheme. We choose to | ||
| represent only integers between | ||
| +/-:attr:`~PaillierPublicKey.max_int`, where `max_int` is | ||
| approximately :attr:`~PaillierPublicKey.n`/3 (larger integers may | ||
| be treated as floats). The range of values between `max_int` and | ||
| `n` - `max_int` is reserved for detecting overflows. This encoding | ||
| scheme supports properties #1 and #2 above. | ||
| Representing floating point numbers as integers is a harder task. | ||
| Here we use a variant of fixed-precision arithmetic. In fixed | ||
| precision, you encode by multiplying every float by a large number | ||
| (e.g. 1e6) and rounding the resulting product. You decode by | ||
| dividing by that number. However, this encoding scheme does not | ||
| satisfy property #2 above: upon every multiplication, you must | ||
| divide by the large number. In a Paillier scheme, this is not | ||
| possible to do without decrypting. For some tasks, this is | ||
| acceptable or can be worked around, but for other tasks this can't | ||
| be worked around. | ||
| In our scheme, the "large number" is allowed to vary, and we keep | ||
| track of it. It is: | ||
| :attr:`BASE` ** :attr:`exponent` | ||
| One number has many possible encodings; this property can be used | ||
| to mitigate the leak of information due to the fact that | ||
| :attr:`exponent` is never encrypted. | ||
| For more details, see :meth:`encode`. | ||
| .. rubric:: Footnotes | ||
| .. [1] Technically, since Paillier encryption only supports | ||
| multiplication by a scalar, it may be possible to define a | ||
| secondary encoding scheme `Encode'` such that property #2 is | ||
| relaxed to: | ||
| Decode(Encode(a) * Encode'(b)) = a * b | ||
| We don't do this. | ||
| Args: | ||
| public_key (PaillierPublicKey): public key for which to encode | ||
| (this is necessary because :attr:`~PaillierPublicKey.max_int` | ||
| varies) | ||
| encoding (int): The encoded number to store. Must be positive and | ||
| less than :attr:`~PaillierPublicKey.max_int`. | ||
| exponent (int): Together with :attr:`BASE`, determines the level | ||
| of fixed-precision used in encoding the number. | ||
| Attributes: | ||
| public_key (PaillierPublicKey): public key for which to encode | ||
| (this is necessary because :attr:`~PaillierPublicKey.max_int` | ||
| varies) | ||
| encoding (int): The encoded number to store. Must be positive and | ||
| less than :attr:`~PaillierPublicKey.max_int`. | ||
| exponent (int): Together with :attr:`BASE`, determines the level | ||
| of fixed-precision used in encoding the number. | ||
| """ | ||
| BASE = 16 | ||
| """Base to use when exponentiating. Larger `BASE` means | ||
| that :attr:`exponent` leaks less information. If you vary this, | ||
| you'll have to manually inform anyone decoding your numbers. | ||
| """ | ||
| LOG2_BASE = math.log(BASE, 2) | ||
| FLOAT_MANTISSA_BITS = sys.float_info.mant_dig | ||
| def __init__(self, public_key, encoding, exponent): | ||
| self.public_key = public_key | ||
| self.encoding = encoding | ||
| self.exponent = exponent | ||
| @classmethod | ||
| def encode(cls, public_key, scalar, precision=None, max_exponent=None): | ||
| """Return an encoding of an int or float. | ||
| This encoding is carefully chosen so that it supports the same | ||
| operations as the Paillier cryptosystem. | ||
| If *scalar* is a float, first approximate it as an int, `int_rep`: | ||
| scalar = int_rep * (:attr:`BASE` ** :attr:`exponent`), | ||
| for some (typically negative) integer exponent, which can be | ||
| tuned using *precision* and *max_exponent*. Specifically, | ||
| :attr:`exponent` is chosen to be equal to or less than | ||
| *max_exponent*, and such that the number *precision* is not | ||
| rounded to zero. | ||
| Having found an integer representation for the float (or having | ||
| been given an int `scalar`), we then represent this integer as | ||
| a non-negative integer < :attr:`~PaillierPublicKey.n`. | ||
| Paillier homomorphic arithemetic works modulo | ||
| :attr:`~PaillierPublicKey.n`. We take the convention that a | ||
| number x < n/3 is positive, and that a number x > 2n/3 is | ||
| negative. The range n/3 < x < 2n/3 allows for overflow | ||
| detection. | ||
| Args: | ||
| public_key (PaillierPublicKey): public key for which to encode | ||
| (this is necessary because :attr:`~PaillierPublicKey.n` | ||
| varies). | ||
| scalar: an int or float to be encrypted. | ||
| If int, it must satisfy abs(*value*) < | ||
| :attr:`~PaillierPublicKey.n`/3. | ||
| If float, it must satisfy abs(*value* / *precision*) << | ||
| :attr:`~PaillierPublicKey.n`/3 | ||
| (i.e. if a float is near the limit then detectable | ||
| overflow may still occur) | ||
| precision (float): Choose exponent (i.e. fix the precision) so | ||
| that this number is distinguishable from zero. If `scalar` | ||
| is a float, then this is set so that minimal precision is | ||
| lost. Lower precision leads to smaller encodings, which | ||
| might yield faster computation. | ||
| max_exponent (int): Ensure that the exponent of the returned | ||
| `EncryptedNumber` is at most this. | ||
| Returns: | ||
| EncodedNumber: Encoded form of *scalar*, ready for encryption | ||
| against *public_key*. | ||
| """ | ||
| # Calculate the maximum exponent for desired precision | ||
| if precision is None: | ||
| if isinstance(scalar, int): | ||
| prec_exponent = 0 | ||
| elif isinstance(scalar, float): | ||
| # Encode with *at least* as much precision as the python float | ||
| # What's the base-2 exponent on the float? | ||
| bin_flt_exponent = math.frexp(scalar)[1] | ||
| # What's the base-2 exponent of the least significant bit? | ||
| # The least significant bit has value 2 ** bin_lsb_exponent | ||
| bin_lsb_exponent = bin_flt_exponent - cls.FLOAT_MANTISSA_BITS | ||
| # What's the corresponding base BASE exponent? Round that down. | ||
| prec_exponent = math.floor(bin_lsb_exponent / cls.LOG2_BASE) | ||
| else: | ||
| raise TypeError("Don't know the precision of type %s." | ||
| % type(scalar)) | ||
| else: | ||
| prec_exponent = math.floor(math.log(precision, cls.BASE)) | ||
| # Remember exponents are negative for numbers < 1. | ||
| # If we're going to store numbers with a more negative | ||
| # exponent than demanded by the precision, then we may | ||
| # as well bump up the actual precision. | ||
| if max_exponent is None: | ||
| exponent = prec_exponent | ||
| else: | ||
| exponent = min(max_exponent, prec_exponent) | ||
| int_rep = int(round(scalar * pow(cls.BASE, -exponent))) | ||
| if abs(int_rep) > public_key.max_int: | ||
| raise ValueError('Integer needs to be within +/- %d but got %d' | ||
| % (public_key.max_int, int_rep)) | ||
| # Wrap negative numbers by adding n | ||
| return cls(public_key, int_rep % public_key.n, exponent) | ||
| def decode(self): | ||
| """Decode plaintext and return the result. | ||
| Returns: | ||
| an int or float: the decoded number. N.B. if the number | ||
| returned is an integer, it will not be of type float. | ||
| Raises: | ||
| OverflowError: if overflow is detected in the decrypted number. | ||
| """ | ||
| if self.encoding >= self.public_key.n: | ||
| # Should be mod n | ||
| raise ValueError('Attempted to decode corrupted number') | ||
| elif self.encoding <= self.public_key.max_int: | ||
| # Positive | ||
| mantissa = self.encoding | ||
| elif self.encoding >= self.public_key.n - self.public_key.max_int: | ||
| # Negative | ||
| mantissa = self.encoding - self.public_key.n | ||
| else: | ||
| raise OverflowError('Overflow detected in decrypted number') | ||
| return mantissa * pow(self.BASE, self.exponent) | ||
| def decrease_exponent_to(self, new_exp): | ||
| """Return an `EncodedNumber` with same value but lower exponent. | ||
| If we multiply the encoded value by :attr:`BASE` and decrement | ||
| :attr:`exponent`, then the decoded value does not change. Thus | ||
| we can almost arbitrarily ratchet down the exponent of an | ||
| :class:`EncodedNumber` - we only run into trouble when the encoded | ||
| integer overflows. There may not be a warning if this happens. | ||
| This is necessary when adding :class:`EncodedNumber` instances, | ||
| and can also be useful to hide information about the precision | ||
| of numbers - e.g. a protocol can fix the exponent of all | ||
| transmitted :class:`EncodedNumber` to some lower bound(s). | ||
| Args: | ||
| new_exp (int): the desired exponent. | ||
| Returns: | ||
| EncodedNumber: Instance with the same value and desired | ||
| exponent. | ||
| Raises: | ||
| ValueError: You tried to increase the exponent, which can't be | ||
| done without decryption. | ||
| """ | ||
| if new_exp > self.exponent: | ||
| raise ValueError('New exponent %i should be more negative than' | ||
| 'old exponent %i' % (new_exp, self.exponent)) | ||
| factor = pow(self.BASE, self.exponent - new_exp) | ||
| new_enc = self.encoding * factor % self.public_key.n | ||
| return self.__class__(self.public_key, new_enc, new_exp) |
| Metadata-Version: 1.1 | ||
| Name: phe | ||
| Version: 1.3.0 | ||
| Version: 1.3.1.dev0 | ||
| Summary: Partially Homomorphic Encryption library for Python | ||
| Home-page: https://github.com/NICTA/python-paillier | ||
| Author: Data61 | CSIRO | ||
| Author-email: brian.thorne@nicta.com.au | ||
| Home-page: https://github.com/n1analytics/python-paillier | ||
| Author: N1 Analytics developers | ||
| Author-email: info@n1analytics.com | ||
| License: GPLv3 | ||
@@ -18,8 +18,6 @@ Download-URL: https://pypi.python.org/pypi/phe/#downloads | ||
| +---------------------+ | ||
| | |coverageM| | | ||
| +---------------------+ | ||
| | |reqM| | | ||
| +---------------------+ | ||
| A library for Partially Homomorphic Encryption in Python. | ||
| A Python 3 library for Partially Homomorphic Encryption. | ||
@@ -75,10 +73,5 @@ The homomorphic properties of the paillier crypto system are: | ||
| .. |coverageM| image:: https://coveralls.io/repos/n1analytics/python-paillier/badge.svg?branch=master&service=github | ||
| :target: https://coveralls.io/github/n1analytics/python-paillier?branch=master | ||
| Keywords: cryptography encryption homomorphic | ||
| Platform: UNKNOWN | ||
| Classifier: Development Status :: 4 - Beta | ||
| Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) | ||
@@ -85,0 +78,0 @@ Classifier: Natural Language :: English |
@@ -5,1 +5,4 @@ gmpy2 | ||
| click | ||
| [examples] | ||
| sklearn |
| README.rst | ||
| setup.cfg | ||
| setup.py | ||
| benchmarks/__init__.py | ||
| phe/__about__.py | ||
| phe/__init__.py | ||
| phe/command_line.py | ||
| phe/encoding.py | ||
| phe/paillier.py | ||
@@ -7,0 +10,0 @@ phe/util.py |
@@ -0,1 +1,2 @@ | ||
| benchmarks | ||
| phe |
+2
-1
@@ -0,3 +1,4 @@ | ||
| from phe.__about__ import * | ||
| from phe.encoding import EncodedNumber | ||
| from phe.paillier import generate_paillier_keypair | ||
| from phe.paillier import EncodedNumber | ||
| from phe.paillier import EncryptedNumber | ||
@@ -4,0 +5,0 @@ from phe.paillier import PaillierPrivateKey, PaillierPublicKey |
| #!/usr/bin/env python3 | ||
| from __future__ import print_function | ||
| import datetime | ||
@@ -4,0 +4,0 @@ import json |
+12
-263
@@ -22,5 +22,3 @@ #!/usr/bin/env python3 | ||
| import random | ||
| import hashlib | ||
| import math | ||
| import sys | ||
| try: | ||
@@ -31,2 +29,3 @@ from collections.abc import Mapping | ||
| from phe import EncodedNumber | ||
| from phe.util import invert, powmod, getprimeover, isqrt | ||
@@ -70,2 +69,3 @@ | ||
| class PaillierPublicKey(object): | ||
@@ -93,5 +93,3 @@ """Contains a public key and associated encryption methods. | ||
| def __repr__(self): | ||
| nsquare = self.nsquare.to_bytes(1024, 'big') | ||
| g = self.g.to_bytes(1024, 'big') | ||
| publicKeyHash = hashlib.sha1(nsquare + g).hexdigest() | ||
| publicKeyHash = hex(hash(self))[2:] | ||
| return "<PaillierPublicKey {}>".format(publicKeyHash[:10]) | ||
@@ -222,3 +220,4 @@ | ||
| raise ValueError('given public key does not match the given p and q.') | ||
| if p == q: #check that p and q are different, otherwise we can't compute p^-1 mod q | ||
| if p == q: | ||
| # check that p and q are different, otherwise we can't compute p^-1 mod q | ||
| raise ValueError('p and q have to be different') | ||
@@ -236,4 +235,4 @@ self.public_key = public_key | ||
| self.p_inverse = invert(self.p, self.q) | ||
| self.hp = self.h_function(self.p, self.psquare); | ||
| self.hq = self.h_function(self.q, self.qsquare); | ||
| self.hp = self.h_function(self.p, self.psquare) | ||
| self.hq = self.h_function(self.q, self.qsquare) | ||
@@ -358,4 +357,3 @@ @staticmethod | ||
| return invert(self.l_function(powmod(self.public_key.g, x - 1, xsquare),x), x) | ||
| def l_function(self, x, p): | ||
@@ -376,3 +374,3 @@ """Computes the L function as defined in Paillier's paper. That is: L(x,p) = (x-1)/p""" | ||
| def __eq__(self, other): | ||
| return (self.p == other.p and self.q == other.q) | ||
| return self.p == other.p and self.q == other.q | ||
@@ -382,2 +380,3 @@ def __hash__(self): | ||
| class PaillierPrivateKeyring(Mapping): | ||
@@ -442,252 +441,2 @@ """Holds several private keys and can decrypt using any of them. | ||
| class EncodedNumber(object): | ||
| """Represents a float or int encoded for Paillier encryption. | ||
| For end users, this class is mainly useful for specifying precision | ||
| when adding/multiplying an :class:`EncryptedNumber` by a scalar. | ||
| If you want to manually encode a number for Paillier encryption, | ||
| then use :meth:`encode`, if de-serializing then use | ||
| :meth:`__init__`. | ||
| .. note:: | ||
| If working with other Paillier libraries you will have to agree on | ||
| a specific :attr:`BASE` and :attr:`LOG2_BASE` - inheriting from this | ||
| class and overriding those two attributes will enable this. | ||
| Notes: | ||
| Paillier encryption is only defined for non-negative integers less | ||
| than :attr:`PaillierPublicKey.n`. Since we frequently want to use | ||
| signed integers and/or floating point numbers (luxury!), values | ||
| should be encoded as a valid integer before encryption. | ||
| The operations of addition and multiplication [1]_ must be | ||
| preserved under this encoding. Namely: | ||
| 1. Decode(Encode(a) + Encode(b)) = a + b | ||
| 2. Decode(Encode(a) * Encode(b)) = a * b | ||
| for any real numbers a and b. | ||
| Representing signed integers is relatively easy: we exploit the | ||
| modular arithmetic properties of the Paillier scheme. We choose to | ||
| represent only integers between | ||
| +/-:attr:`~PaillierPublicKey.max_int`, where `max_int` is | ||
| approximately :attr:`~PaillierPublicKey.n`/3 (larger integers may | ||
| be treated as floats). The range of values between `max_int` and | ||
| `n` - `max_int` is reserved for detecting overflows. This encoding | ||
| scheme supports properties #1 and #2 above. | ||
| Representing floating point numbers as integers is a harder task. | ||
| Here we use a variant of fixed-precision arithmetic. In fixed | ||
| precision, you encode by multiplying every float by a large number | ||
| (e.g. 1e6) and rounding the resulting product. You decode by | ||
| dividing by that number. However, this encoding scheme does not | ||
| satisfy property #2 above: upon every multiplication, you must | ||
| divide by the large number. In a Paillier scheme, this is not | ||
| possible to do without decrypting. For some tasks, this is | ||
| acceptable or can be worked around, but for other tasks this can't | ||
| be worked around. | ||
| In our scheme, the "large number" is allowed to vary, and we keep | ||
| track of it. It is: | ||
| :attr:`BASE` ** :attr:`exponent` | ||
| One number has many possible encodings; this property can be used | ||
| to mitigate the leak of information due to the fact that | ||
| :attr:`exponent` is never encrypted. | ||
| For more details, see :meth:`encode`. | ||
| .. rubric:: Footnotes | ||
| .. [1] Technically, since Paillier encryption only supports | ||
| multiplication by a scalar, it may be possible to define a | ||
| secondary encoding scheme `Encode'` such that property #2 is | ||
| relaxed to: | ||
| Decode(Encode(a) * Encode'(b)) = a * b | ||
| We don't do this. | ||
| Args: | ||
| public_key (PaillierPublicKey): public key for which to encode | ||
| (this is necessary because :attr:`~PaillierPublicKey.max_int` | ||
| varies) | ||
| encoding (int): The encoded number to store. Must be positive and | ||
| less than :attr:`~PaillierPublicKey.max_int`. | ||
| exponent (int): Together with :attr:`BASE`, determines the level | ||
| of fixed-precision used in encoding the number. | ||
| Attributes: | ||
| public_key (PaillierPublicKey): public key for which to encode | ||
| (this is necessary because :attr:`~PaillierPublicKey.max_int` | ||
| varies) | ||
| encoding (int): The encoded number to store. Must be positive and | ||
| less than :attr:`~PaillierPublicKey.max_int`. | ||
| exponent (int): Together with :attr:`BASE`, determines the level | ||
| of fixed-precision used in encoding the number. | ||
| """ | ||
| BASE = 16 | ||
| """Base to use when exponentiating. Larger `BASE` means | ||
| that :attr:`exponent` leaks less information. If you vary this, | ||
| you'll have to manually inform anyone decoding your numbers. | ||
| """ | ||
| LOG2_BASE = math.log(BASE, 2) | ||
| FLOAT_MANTISSA_BITS = sys.float_info.mant_dig | ||
| def __init__(self, public_key, encoding, exponent): | ||
| self.public_key = public_key | ||
| self.encoding = encoding | ||
| self.exponent = exponent | ||
| @classmethod | ||
| def encode(cls, public_key, scalar, precision=None, max_exponent=None): | ||
| """Return an encoding of an int or float. | ||
| This encoding is carefully chosen so that it supports the same | ||
| operations as the Paillier cryptosystem. | ||
| If *scalar* is a float, first approximate it as an int, `int_rep`: | ||
| scalar = int_rep * (:attr:`BASE` ** :attr:`exponent`), | ||
| for some (typically negative) integer exponent, which can be | ||
| tuned using *precision* and *max_exponent*. Specifically, | ||
| :attr:`exponent` is chosen to be equal to or less than | ||
| *max_exponent*, and such that the number *precision* is not | ||
| rounded to zero. | ||
| Having found an integer representation for the float (or having | ||
| been given an int `scalar`), we then represent this integer as | ||
| a non-negative integer < :attr:`~PaillierPublicKey.n`. | ||
| Paillier homomorphic arithemetic works modulo | ||
| :attr:`~PaillierPublicKey.n`. We take the convention that a | ||
| number x < n/3 is positive, and that a number x > 2n/3 is | ||
| negative. The range n/3 < x < 2n/3 allows for overflow | ||
| detection. | ||
| Args: | ||
| public_key (PaillierPublicKey): public key for which to encode | ||
| (this is necessary because :attr:`~PaillierPublicKey.n` | ||
| varies). | ||
| scalar: an int or float to be encrypted. | ||
| If int, it must satisfy abs(*value*) < | ||
| :attr:`~PaillierPublicKey.n`/3. | ||
| If float, it must satisfy abs(*value* / *precision*) << | ||
| :attr:`~PaillierPublicKey.n`/3 | ||
| (i.e. if a float is near the limit then detectable | ||
| overflow may still occur) | ||
| precision (float): Choose exponent (i.e. fix the precision) so | ||
| that this number is distinguishable from zero. If `scalar` | ||
| is a float, then this is set so that minimal precision is | ||
| lost. Lower precision leads to smaller encodings, which | ||
| might yield faster computation. | ||
| max_exponent (int): Ensure that the exponent of the returned | ||
| `EncryptedNumber` is at most this. | ||
| Returns: | ||
| EncodedNumber: Encoded form of *scalar*, ready for encryption | ||
| against *public_key*. | ||
| """ | ||
| # Calculate the maximum exponent for desired precision | ||
| if precision is None: | ||
| if isinstance(scalar, int): | ||
| prec_exponent = 0 | ||
| elif isinstance(scalar, float): | ||
| # Encode with *at least* as much precision as the python float | ||
| # What's the base-2 exponent on the float? | ||
| bin_flt_exponent = math.frexp(scalar)[1] | ||
| # What's the base-2 exponent of the least significant bit? | ||
| # The least significant bit has value 2 ** bin_lsb_exponent | ||
| bin_lsb_exponent = bin_flt_exponent - cls.FLOAT_MANTISSA_BITS | ||
| # What's the corresponding base BASE exponent? Round that down. | ||
| prec_exponent = math.floor(bin_lsb_exponent / cls.LOG2_BASE) | ||
| else: | ||
| raise TypeError("Don't know the precision of type %s." | ||
| % type(scalar)) | ||
| else: | ||
| prec_exponent = math.floor(math.log(precision, cls.BASE)) | ||
| # Remember exponents are negative for numbers < 1. | ||
| # If we're going to store numbers with a more negative | ||
| # exponent than demanded by the precision, then we may | ||
| # as well bump up the actual precision. | ||
| if max_exponent is None: | ||
| exponent = prec_exponent | ||
| else: | ||
| exponent = min(max_exponent, prec_exponent) | ||
| int_rep = int(round(scalar * pow(cls.BASE, -exponent))) | ||
| if abs(int_rep) > public_key.max_int: | ||
| raise ValueError('Integer needs to be within +/- %d but got %d' | ||
| % (public_key.max_int, int_rep)) | ||
| # Wrap negative numbers by adding n | ||
| return cls(public_key, int_rep % public_key.n, exponent) | ||
| def decode(self): | ||
| """Decode plaintext and return the result. | ||
| Returns: | ||
| an int or float: the decoded number. N.B. if the number | ||
| returned is an integer, it will not be of type float. | ||
| Raises: | ||
| OverflowError: if overflow is detected in the decrypted number. | ||
| """ | ||
| if self.encoding >= self.public_key.n: | ||
| # Should be mod n | ||
| raise ValueError('Attempted to decode corrupted number') | ||
| elif self.encoding <= self.public_key.max_int: | ||
| # Positive | ||
| mantissa = self.encoding | ||
| elif self.encoding >= self.public_key.n - self.public_key.max_int: | ||
| # Negative | ||
| mantissa = self.encoding - self.public_key.n | ||
| else: | ||
| raise OverflowError('Overflow detected in decrypted number') | ||
| return mantissa * pow(self.BASE, self.exponent) | ||
| def decrease_exponent_to(self, new_exp): | ||
| """Return an `EncodedNumber` with same value but lower exponent. | ||
| If we multiply the encoded value by :attr:`BASE` and decrement | ||
| :attr:`exponent`, then the decoded value does not change. Thus | ||
| we can almost arbitrarily ratchet down the exponent of an | ||
| :class:`EncodedNumber` - we only run into trouble when the encoded | ||
| integer overflows. There may not be a warning if this happens. | ||
| This is necessary when adding :class:`EncodedNumber` instances, | ||
| and can also be useful to hide information about the precision | ||
| of numbers - e.g. a protocol can fix the exponent of all | ||
| transmitted :class:`EncodedNumber` to some lower bound(s). | ||
| Args: | ||
| new_exp (int): the desired exponent. | ||
| Returns: | ||
| EncodedNumber: Instance with the same value and desired | ||
| exponent. | ||
| Raises: | ||
| ValueError: You tried to increase the exponent, which can't be | ||
| done without decryption. | ||
| """ | ||
| if new_exp > self.exponent: | ||
| raise ValueError('New exponent %i should be more negative than' | ||
| 'old exponent %i' % (new_exp, self.exponent)) | ||
| factor = pow(self.BASE, self.exponent - new_exp) | ||
| new_enc = self.encoding * factor % self.public_key.n | ||
| return self.__class__(self.public_key, new_enc, new_exp) | ||
| class EncryptedNumber(object): | ||
@@ -892,3 +641,3 @@ """Represents the Paillier encryption of a float or int. | ||
| encoded = EncodedNumber.encode(self.public_key, scalar, | ||
| max_exponent=self.exponent) | ||
| max_exponent=self.exponent) | ||
@@ -895,0 +644,0 @@ return self._add_encoded(encoded) |
| #!/usr/bin/env python | ||
| # Portions Copyright 2012 Google Inc. All Rights Reserved. | ||
| # This file has been modified by NICTA | ||
| import phe.encoding | ||
| from phe.paillier import PaillierPrivateKey, PaillierPublicKey | ||
@@ -171,3 +172,3 @@ | ||
| super().setUp() | ||
| self.EncodedNumberCls = paillier.EncodedNumber | ||
| self.EncodedNumberCls = phe.encoding.EncodedNumber | ||
@@ -395,3 +396,3 @@ | ||
| class AltEncodedNumber(paillier.EncodedNumber): | ||
| class AltEncodedNumber(phe.encoding.EncodedNumber): | ||
| BASE = 64 | ||
@@ -410,3 +411,3 @@ LOG2_BASE = math.log(BASE, 2) | ||
| class AltEncodedNumber(paillier.EncodedNumber): | ||
| class AltEncodedNumber(phe.encoding.EncodedNumber): | ||
| BASE = 2 | ||
@@ -425,3 +426,3 @@ LOG2_BASE = math.log(BASE, 2) | ||
| class AltEncodedNumber(paillier.EncodedNumber): | ||
| class AltEncodedNumber(phe.encoding.EncodedNumber): | ||
| BASE = 13 | ||
@@ -489,3 +490,3 @@ LOG2_BASE = math.log(BASE, 2) | ||
| ciphertext1 = self.public_key.encrypt(-15) | ||
| ciphertext2 = paillier.EncodedNumber(self.other_public_key, 1, ciphertext1.exponent) | ||
| ciphertext2 = phe.encoding.EncodedNumber(self.other_public_key, 1, ciphertext1.exponent) | ||
| self.assertRaises(ValueError, ciphertext1.__add__, ciphertext2) | ||
@@ -653,3 +654,3 @@ | ||
| ciphertext1 = self.public_key.encrypt(15) | ||
| encoded2 = paillier.EncodedNumber.encode(self.public_key, 1) | ||
| encoded2 = phe.encoding.EncodedNumber.encode(self.public_key, 1) | ||
| ciphertext3 = ciphertext1 + encoded2 | ||
@@ -662,3 +663,3 @@ decryption = self.private_key.decrypt(ciphertext3) | ||
| ciphertext1 = self.public_key.encrypt(15) | ||
| encoded2 = paillier.EncodedNumber.encode(self.public_key, 1, max_exponent=-50) | ||
| encoded2 = phe.encoding.EncodedNumber.encode(self.public_key, 1, max_exponent=-50) | ||
| assert encoded2.exponent > -200 | ||
@@ -675,3 +676,3 @@ assert ciphertext1.exponent > -200 | ||
| ciphertext2 = ciphertext1.decrease_exponent_to(-10) | ||
| encoded1 = paillier.EncodedNumber.encode(self.public_key, 1) | ||
| encoded1 = phe.encoding.EncodedNumber.encode(self.public_key, 1) | ||
| encoded2 = encoded1.decrease_exponent_to(-10) | ||
@@ -688,3 +689,3 @@ ciphertext = ciphertext1.decrease_exponent_to(-200) | ||
| ciphertext1 = self.public_key.encrypt(-3) | ||
| encoded2 = paillier.EncodedNumber.encode(self.public_key, -25) | ||
| encoded2 = phe.encoding.EncodedNumber.encode(self.public_key, -25) | ||
| ciphertext3 = ciphertext1 * encoded2 | ||
@@ -922,3 +923,3 @@ decryption = self.private_key.decrypt(ciphertext3) | ||
| self.assertNotEqual(ciphertext2.exponent, ciphertext1.exponent) | ||
| exp_of_314 = paillier.EncodedNumber.encode(self.public_key, -31.4).exponent | ||
| exp_of_314 = phe.encoding.EncodedNumber.encode(self.public_key, -31.4).exponent | ||
| self.assertEqual(ciphertext2.exponent, ciphertext1.exponent +exp_of_314) | ||
@@ -929,4 +930,4 @@ | ||
| ciphertext1 = self.public_key.encrypt(1.2345678e-12, precision=1e-14) | ||
| encoded1 = paillier.EncodedNumber.encode(self.public_key, 1.38734864, | ||
| precision=1e-2) | ||
| encoded1 = phe.encoding.EncodedNumber.encode(self.public_key, 1.38734864, | ||
| precision=1e-2) | ||
| ciphertext2 = ciphertext1 * encoded1 | ||
@@ -955,3 +956,3 @@ self.assertAlmostEqual(1.71e-12, self.private_key.decrypt(ciphertext2), places=3) | ||
| self.assertNotEqual(ciphertext2.exponent, ciphertext1.exponent) | ||
| exp_of_314 = paillier.EncodedNumber.encode(self.public_key, -31.4).exponent | ||
| exp_of_314 = phe.encoding.EncodedNumber.encode(self.public_key, -31.4).exponent | ||
| self.assertEqual(ciphertext2.exponent, ciphertext1.exponent +exp_of_314) | ||
@@ -962,4 +963,4 @@ | ||
| ciphertext1 = self.public_key.encrypt(1.2345678e-12, precision=1e-14) | ||
| encoded1 = paillier.EncodedNumber.encode(self.public_key, -1.38734864, | ||
| precision=1e-2) | ||
| encoded1 = phe.encoding.EncodedNumber.encode(self.public_key, -1.38734864, | ||
| precision=1e-2) | ||
| ciphertext2 = ciphertext1 * encoded1 | ||
@@ -1001,4 +1002,4 @@ self.assertAlmostEqual(-1.71e-12, self.private_key.decrypt(ciphertext2), places=3) | ||
| ciphertext1 = self.public_key.encrypt(0.1, precision=1e-3) | ||
| encoded1 = paillier.EncodedNumber.encode(self.public_key, 0.2, | ||
| precision=1e-20) | ||
| encoded1 = phe.encoding.EncodedNumber.encode(self.public_key, 0.2, | ||
| precision=1e-20) | ||
| self.assertNotEqual(ciphertext1.exponent, encoded1.exponent) | ||
@@ -1018,7 +1019,7 @@ old_exponent = ciphertext1.exponent | ||
| ciphertext1 = self.public_key.encrypt(-0.1) | ||
| encoded1 = paillier.EncodedNumber.encode(self.public_key, -31.4) | ||
| encoded1 = phe.encoding.EncodedNumber.encode(self.public_key, -31.4) | ||
| ciphertext2 = ciphertext1 * encoded1 | ||
| self.assertEqual(3.14, self.private_key.decrypt(ciphertext2)) | ||
| self.assertNotEqual(ciphertext2.exponent, ciphertext1.exponent) | ||
| exp_of_314 = paillier.EncodedNumber.encode(self.public_key, -31.4).exponent | ||
| exp_of_314 = phe.encoding.EncodedNumber.encode(self.public_key, -31.4).exponent | ||
| self.assertEqual(ciphertext2.exponent, ciphertext1.exponent +exp_of_314) | ||
@@ -1025,0 +1026,0 @@ |
+5
-12
| Metadata-Version: 1.1 | ||
| Name: phe | ||
| Version: 1.3.0 | ||
| Version: 1.3.1.dev0 | ||
| Summary: Partially Homomorphic Encryption library for Python | ||
| Home-page: https://github.com/NICTA/python-paillier | ||
| Author: Data61 | CSIRO | ||
| Author-email: brian.thorne@nicta.com.au | ||
| Home-page: https://github.com/n1analytics/python-paillier | ||
| Author: N1 Analytics developers | ||
| Author-email: info@n1analytics.com | ||
| License: GPLv3 | ||
@@ -18,8 +18,6 @@ Download-URL: https://pypi.python.org/pypi/phe/#downloads | ||
| +---------------------+ | ||
| | |coverageM| | | ||
| +---------------------+ | ||
| | |reqM| | | ||
| +---------------------+ | ||
| A library for Partially Homomorphic Encryption in Python. | ||
| A Python 3 library for Partially Homomorphic Encryption. | ||
@@ -75,10 +73,5 @@ The homomorphic properties of the paillier crypto system are: | ||
| .. |coverageM| image:: https://coveralls.io/repos/n1analytics/python-paillier/badge.svg?branch=master&service=github | ||
| :target: https://coveralls.io/github/n1analytics/python-paillier?branch=master | ||
| Keywords: cryptography encryption homomorphic | ||
| Platform: UNKNOWN | ||
| Classifier: Development Status :: 4 - Beta | ||
| Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) | ||
@@ -85,0 +78,0 @@ Classifier: Natural Language :: English |
+1
-7
@@ -9,8 +9,6 @@ python-paillier |release| | ||
| +---------------------+ | ||
| | |coverageM| | | ||
| +---------------------+ | ||
| | |reqM| | | ||
| +---------------------+ | ||
| A library for Partially Homomorphic Encryption in Python. | ||
| A Python 3 library for Partially Homomorphic Encryption. | ||
@@ -66,5 +64,1 @@ The homomorphic properties of the paillier crypto system are: | ||
| .. |coverageM| image:: https://coveralls.io/repos/n1analytics/python-paillier/badge.svg?branch=master&service=github | ||
| :target: https://coveralls.io/github/n1analytics/python-paillier?branch=master | ||
+2
-3
| [metadata] | ||
| description-file = README.md | ||
| description-file = README.rst | ||
@@ -8,5 +8,4 @@ [bdist_wheel] | ||
| [egg_info] | ||
| tag_build = | ||
| tag_date = 0 | ||
| tag_svn_revision = 0 | ||
| tag_build = | ||
+12
-14
@@ -22,21 +22,18 @@ | ||
| about = {} | ||
| with open(os.path.join(here, "phe", "__about__.py")) as f: | ||
| exec(f.read(), about) | ||
| def find_version(): | ||
| # Note the version is also in the docs/conf.py file | ||
| # We use semantic versioning - semver.org | ||
| return "1.3.0" | ||
| setup( | ||
| name="phe", | ||
| version=find_version(), | ||
| description="Partially Homomorphic Encryption library for Python", | ||
| name=about['__title__'], | ||
| version=about['__version__'], | ||
| description=about['__summary__'], | ||
| long_description=open(os.path.join(here, "README.rst")).read(), | ||
| url="https://github.com/NICTA/python-paillier", | ||
| url=about['__uri__'], | ||
| download_url="https://pypi.python.org/pypi/phe/#downloads", | ||
| author="Data61 | CSIRO", | ||
| author_email="brian.thorne@nicta.com.au", | ||
| license="GPLv3", | ||
| author=about['__author__'], | ||
| author_email=about['__email__'], | ||
| license=about['__license__'], | ||
| classifiers=[ | ||
| 'Development Status :: 4 - Beta', | ||
| 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', | ||
@@ -62,3 +59,4 @@ 'Natural Language :: English', | ||
| extras_require={ | ||
| 'cli': ['click'] | ||
| 'cli': ['click'], | ||
| 'examples': ['sklearn'] | ||
| }, | ||
@@ -65,0 +63,0 @@ install_requires=['gmpy2'], |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
22
15.79%2503
0.56%127414
-0.23%