1+ import math
2+ import sys
3+
4+
5+ class EncodedNumber (object ):
6+ """Represents a float or int encoded for Paillier encryption.
7+
8+ For end users, this class is mainly useful for specifying precision
9+ when adding/multiplying an :class:`EncryptedNumber` by a scalar.
10+
11+ If you want to manually encode a number for Paillier encryption,
12+ then use :meth:`encode`, if de-serializing then use
13+ :meth:`__init__`.
14+
15+
16+ .. note::
17+ If working with other Paillier libraries you will have to agree on
18+ a specific :attr:`BASE` and :attr:`LOG2_BASE` - inheriting from this
19+ class and overriding those two attributes will enable this.
20+
21+ Notes:
22+ Paillier encryption is only defined for non-negative integers less
23+ than :attr:`PaillierPublicKey.n`. Since we frequently want to use
24+ signed integers and/or floating point numbers (luxury!), values
25+ should be encoded as a valid integer before encryption.
26+
27+ The operations of addition and multiplication [1]_ must be
28+ preserved under this encoding. Namely:
29+
30+ 1. Decode(Encode(a) + Encode(b)) = a + b
31+ 2. Decode(Encode(a) * Encode(b)) = a * b
32+
33+ for any real numbers a and b.
34+
35+ Representing signed integers is relatively easy: we exploit the
36+ modular arithmetic properties of the Paillier scheme. We choose to
37+ represent only integers between
38+ +/-:attr:`~PaillierPublicKey.max_int`, where `max_int` is
39+ approximately :attr:`~PaillierPublicKey.n`/3 (larger integers may
40+ be treated as floats). The range of values between `max_int` and
41+ `n` - `max_int` is reserved for detecting overflows. This encoding
42+ scheme supports properties #1 and #2 above.
43+
44+ Representing floating point numbers as integers is a harder task.
45+ Here we use a variant of fixed-precision arithmetic. In fixed
46+ precision, you encode by multiplying every float by a large number
47+ (e.g. 1e6) and rounding the resulting product. You decode by
48+ dividing by that number. However, this encoding scheme does not
49+ satisfy property #2 above: upon every multiplication, you must
50+ divide by the large number. In a Paillier scheme, this is not
51+ possible to do without decrypting. For some tasks, this is
52+ acceptable or can be worked around, but for other tasks this can't
53+ be worked around.
54+
55+ In our scheme, the "large number" is allowed to vary, and we keep
56+ track of it. It is:
57+
58+ :attr:`BASE` ** :attr:`exponent`
59+
60+ One number has many possible encodings; this property can be used
61+ to mitigate the leak of information due to the fact that
62+ :attr:`exponent` is never encrypted.
63+
64+ For more details, see :meth:`encode`.
65+
66+ .. rubric:: Footnotes
67+
68+ .. [1] Technically, since Paillier encryption only supports
69+ multiplication by a scalar, it may be possible to define a
70+ secondary encoding scheme `Encode'` such that property #2 is
71+ relaxed to:
72+
73+ Decode(Encode(a) * Encode'(b)) = a * b
74+
75+ We don't do this.
76+
77+
78+ Args:
79+ public_key (PaillierPublicKey): public key for which to encode
80+ (this is necessary because :attr:`~PaillierPublicKey.max_int`
81+ varies)
82+ encoding (int): The encoded number to store. Must be positive and
83+ less than :attr:`~PaillierPublicKey.max_int`.
84+ exponent (int): Together with :attr:`BASE`, determines the level
85+ of fixed-precision used in encoding the number.
86+
87+ Attributes:
88+ public_key (PaillierPublicKey): public key for which to encode
89+ (this is necessary because :attr:`~PaillierPublicKey.max_int`
90+ varies)
91+ encoding (int): The encoded number to store. Must be positive and
92+ less than :attr:`~PaillierPublicKey.max_int`.
93+ exponent (int): Together with :attr:`BASE`, determines the level
94+ of fixed-precision used in encoding the number.
95+ """
96+ BASE = 16
97+ """Base to use when exponentiating. Larger `BASE` means
98+ that :attr:`exponent` leaks less information. If you vary this,
99+ you'll have to manually inform anyone decoding your numbers.
100+ """
101+ LOG2_BASE = math .log (BASE , 2 )
102+ FLOAT_MANTISSA_BITS = sys .float_info .mant_dig
103+
104+ def __init__ (self , public_key , encoding , exponent ):
105+ self .public_key = public_key
106+ self .encoding = encoding
107+ self .exponent = exponent
108+
109+ @classmethod
110+ def encode (cls , public_key , scalar , precision = None , max_exponent = None ):
111+ """Return an encoding of an int or float.
112+
113+ This encoding is carefully chosen so that it supports the same
114+ operations as the Paillier cryptosystem.
115+
116+ If *scalar* is a float, first approximate it as an int, `int_rep`:
117+
118+ scalar = int_rep * (:attr:`BASE` ** :attr:`exponent`),
119+
120+ for some (typically negative) integer exponent, which can be
121+ tuned using *precision* and *max_exponent*. Specifically,
122+ :attr:`exponent` is chosen to be equal to or less than
123+ *max_exponent*, and such that the number *precision* is not
124+ rounded to zero.
125+
126+ Having found an integer representation for the float (or having
127+ been given an int `scalar`), we then represent this integer as
128+ a non-negative integer < :attr:`~PaillierPublicKey.n`.
129+
130+ Paillier homomorphic arithemetic works modulo
131+ :attr:`~PaillierPublicKey.n`. We take the convention that a
132+ number x < n/3 is positive, and that a number x > 2n/3 is
133+ negative. The range n/3 < x < 2n/3 allows for overflow
134+ detection.
135+
136+ Args:
137+ public_key (PaillierPublicKey): public key for which to encode
138+ (this is necessary because :attr:`~PaillierPublicKey.n`
139+ varies).
140+ scalar: an int or float to be encrypted.
141+ If int, it must satisfy abs(*value*) <
142+ :attr:`~PaillierPublicKey.n`/3.
143+ If float, it must satisfy abs(*value* / *precision*) <<
144+ :attr:`~PaillierPublicKey.n`/3
145+ (i.e. if a float is near the limit then detectable
146+ overflow may still occur)
147+ precision (float): Choose exponent (i.e. fix the precision) so
148+ that this number is distinguishable from zero. If `scalar`
149+ is a float, then this is set so that minimal precision is
150+ lost. Lower precision leads to smaller encodings, which
151+ might yield faster computation.
152+ max_exponent (int): Ensure that the exponent of the returned
153+ `EncryptedNumber` is at most this.
154+
155+ Returns:
156+ EncodedNumber: Encoded form of *scalar*, ready for encryption
157+ against *public_key*.
158+ """
159+ # Calculate the maximum exponent for desired precision
160+ if precision is None :
161+ if isinstance (scalar , int ):
162+ prec_exponent = 0
163+ elif isinstance (scalar , float ):
164+ # Encode with *at least* as much precision as the python float
165+ # What's the base-2 exponent on the float?
166+ bin_flt_exponent = math .frexp (scalar )[1 ]
167+
168+ # What's the base-2 exponent of the least significant bit?
169+ # The least significant bit has value 2 ** bin_lsb_exponent
170+ bin_lsb_exponent = bin_flt_exponent - cls .FLOAT_MANTISSA_BITS
171+
172+ # What's the corresponding base BASE exponent? Round that down.
173+ prec_exponent = math .floor (bin_lsb_exponent / cls .LOG2_BASE )
174+ else :
175+ raise TypeError ("Don't know the precision of type %s."
176+ % type (scalar ))
177+ else :
178+ prec_exponent = math .floor (math .log (precision , cls .BASE ))
179+
180+ # Remember exponents are negative for numbers < 1.
181+ # If we're going to store numbers with a more negative
182+ # exponent than demanded by the precision, then we may
183+ # as well bump up the actual precision.
184+ if max_exponent is None :
185+ exponent = prec_exponent
186+ else :
187+ exponent = min (max_exponent , prec_exponent )
188+
189+ int_rep = int (round (scalar * pow (cls .BASE , - exponent )))
190+
191+ if abs (int_rep ) > public_key .max_int :
192+ raise ValueError ('Integer needs to be within +/- %d but got %d'
193+ % (public_key .max_int , int_rep ))
194+
195+ # Wrap negative numbers by adding n
196+ return cls (public_key , int_rep % public_key .n , exponent )
197+
198+ def decode (self ):
199+ """Decode plaintext and return the result.
200+
201+ Returns:
202+ an int or float: the decoded number. N.B. if the number
203+ returned is an integer, it will not be of type float.
204+
205+ Raises:
206+ OverflowError: if overflow is detected in the decrypted number.
207+ """
208+ if self .encoding >= self .public_key .n :
209+ # Should be mod n
210+ raise ValueError ('Attempted to decode corrupted number' )
211+ elif self .encoding <= self .public_key .max_int :
212+ # Positive
213+ mantissa = self .encoding
214+ elif self .encoding >= self .public_key .n - self .public_key .max_int :
215+ # Negative
216+ mantissa = self .encoding - self .public_key .n
217+ else :
218+ raise OverflowError ('Overflow detected in decrypted number' )
219+
220+ return mantissa * pow (self .BASE , self .exponent )
221+
222+ def decrease_exponent_to (self , new_exp ):
223+ """Return an `EncodedNumber` with same value but lower exponent.
224+
225+ If we multiply the encoded value by :attr:`BASE` and decrement
226+ :attr:`exponent`, then the decoded value does not change. Thus
227+ we can almost arbitrarily ratchet down the exponent of an
228+ :class:`EncodedNumber` - we only run into trouble when the encoded
229+ integer overflows. There may not be a warning if this happens.
230+
231+ This is necessary when adding :class:`EncodedNumber` instances,
232+ and can also be useful to hide information about the precision
233+ of numbers - e.g. a protocol can fix the exponent of all
234+ transmitted :class:`EncodedNumber` to some lower bound(s).
235+
236+ Args:
237+ new_exp (int): the desired exponent.
238+
239+ Returns:
240+ EncodedNumber: Instance with the same value and desired
241+ exponent.
242+
243+ Raises:
244+ ValueError: You tried to increase the exponent, which can't be
245+ done without decryption.
246+ """
247+ if new_exp > self .exponent :
248+ raise ValueError ('New exponent %i should be more negative than'
249+ 'old exponent %i' % (new_exp , self .exponent ))
250+ factor = pow (self .BASE , self .exponent - new_exp )
251+ new_enc = self .encoding * factor % self .public_key .n
252+ return self .__class__ (self .public_key , new_enc , new_exp )
0 commit comments