Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/crypto/public_key/blum_goldwasser.py
8818 views
1
r"""
2
Blum-Goldwasser Probabilistic Encryption
3
4
The Blum-Goldwasser probabilistic public-key encryption scheme. This scheme
5
was originally described in [BlumGoldwasser1985]_. See also section 8.7.2
6
of [MenezesEtAl1996]_ and the
7
`Wikipedia article <http://en.wikipedia.org/wiki/Blum-Goldwasser_cryptosystem>`_
8
on this scheme.
9
10
REFERENCES:
11
12
.. [BlumGoldwasser1985] M. Blum and S. Goldwasser. An Efficient
13
Probabilistic Public-Key Encryption Scheme Which Hides All Partial
14
Information. In *Proceedings of CRYPTO 84 on Advances in Cryptology*,
15
pp. 289--299, Springer, 1985.
16
17
.. [MenezesEtAl1996] A. J. Menezes, P. C. van Oorschot, and S. A. Vanstone.
18
*Handbook of Applied Cryptography*. CRC Press, 1996.
19
20
AUTHORS:
21
22
- Mike Hogan and David Joyner (2009-9-19): initial procedural version
23
released as public domain software.
24
25
- Minh Van Nguyen (2009-12): integrate into Sage as a class and relicense
26
under the GPLv2+. Complete rewrite of the original version to follow
27
the description contained in [MenezesEtAl1996]_.
28
"""
29
30
###########################################################################
31
# Copyright (c) 2009, 2010
32
# Mike Hogan
33
# David Joyner <[email protected]>
34
# Minh Van Nguyen <[email protected]>
35
#
36
# This program is free software; you can redistribute it and/or modify
37
# it under the terms of the GNU General Public License as published by
38
# the Free Software Foundation; either version 2 of the License, or
39
# (at your option) any later version.
40
#
41
# This program is distributed in the hope that it will be useful,
42
# but WITHOUT ANY WARRANTY; without even the implied warranty of
43
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44
# GNU General Public License for more details.
45
#
46
# http://www.gnu.org/licenses/
47
###########################################################################
48
49
from operator import xor
50
51
from sage.crypto.cryptosystem import PublicKeyCryptosystem
52
from sage.crypto.util import is_blum_prime
53
from sage.crypto.util import least_significant_bits
54
from sage.crypto.util import random_blum_prime
55
from sage.functions.log import log
56
from sage.functions.other import Function_floor
57
from sage.monoids.string_monoid import BinaryStrings
58
from sage.rings.arith import gcd
59
from sage.rings.arith import power_mod
60
from sage.rings.arith import xgcd
61
from sage.rings.finite_rings.integer_mod import Mod as mod
62
from sage.rings.finite_rings.integer_mod_ring import IntegerModFactory
63
64
floor = Function_floor()
65
IntegerModRing = IntegerModFactory("IntegerModRing")
66
67
class BlumGoldwasser(PublicKeyCryptosystem):
68
r"""
69
The Blum-Goldwasser probabilistic public-key encryption scheme.
70
71
The Blum-Goldwasser encryption and decryption algorithms as described in
72
:func:`encrypt() <BlumGoldwasser.encrypt>` and
73
:func:`decrypt() <BlumGoldwasser.decrypt>`, respectively, make use of the
74
least significant bit of a binary string. A related concept is the `k`
75
least significant bits of a binary string. For example, given a positive
76
integer `n`, let `b = b_0 b_1 \cdots b_{m-1}` be the binary representation
77
of `n` so that `b` is a binary string of length `m`. Then the least
78
significant bit of `n` is `b_{m-1}`. If `0 < k \leq m`, then the `k` least
79
significant bits of `n` are `b_{m-1-k} b_{m-k} \cdots b_{m-1}`. The least
80
significant bit of an integer is also referred to as its parity bit,
81
because this bit determines whether the integer is even or odd. In the
82
following example, we obtain the least significant bit of an integer::
83
84
sage: n = 123
85
sage: b = n.binary(); b
86
'1111011'
87
sage: n % 2
88
1
89
sage: b[-1]
90
'1'
91
92
Now find the 4 least significant bits of the integer `n = 123`::
93
94
sage: b
95
'1111011'
96
sage: b[-4:]
97
'1011'
98
99
The last two examples could be worked through as follows::
100
101
sage: from sage.crypto.util import least_significant_bits
102
sage: least_significant_bits(123, 1)
103
[1]
104
sage: least_significant_bits(123, 4)
105
[1, 0, 1, 1]
106
107
EXAMPLES:
108
109
The following encryption/decryption example is taken from Example 8.57,
110
pages 309--310 of [MenezesEtAl1996]_::
111
112
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
113
sage: bg = BlumGoldwasser(); bg
114
The Blum-Goldwasser public-key encryption scheme.
115
sage: p = 499; q = 547
116
sage: pubkey = bg.public_key(p, q); pubkey
117
272953
118
sage: prikey = bg.private_key(p, q); prikey
119
(499, 547, -57, 52)
120
sage: P = "10011100000100001100"
121
sage: C = bg.encrypt(P, pubkey, seed=159201); C
122
([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680)
123
sage: M = bg.decrypt(C, prikey); M
124
[[1, 0, 0, 1], [1, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0], [1, 1, 0, 0]]
125
sage: M = "".join(map(lambda x: str(x), flatten(M))); M
126
'10011100000100001100'
127
sage: M == P
128
True
129
130
Generate a pair of random public/private keys. Use the public key to
131
encrypt a plaintext. Then decrypt the resulting ciphertext using the
132
private key. Finally, compare the decrypted message with the original
133
plaintext. ::
134
135
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
136
sage: from sage.crypto.util import bin_to_ascii
137
sage: bg = BlumGoldwasser()
138
sage: pubkey, prikey = bg.random_key(10**4, 10**6)
139
sage: P = "A fixed plaintext."
140
sage: C = bg.encrypt(P, pubkey)
141
sage: M = bg.decrypt(C, prikey)
142
sage: bin_to_ascii(flatten(M)) == P
143
True
144
145
If `(p, q, a, b)` is a private key, then `n = pq` is the corresponding
146
public key. Furthermore, we have `\gcd(p, q) = ap + bq = 1`. ::
147
148
sage: p, q, a, b = prikey
149
sage: pubkey == p * q
150
True
151
sage: gcd(p, q) == a*p + b*q == 1
152
True
153
"""
154
155
def __init__(self):
156
"""
157
Construct the Blum-Goldwasser public-key encryption scheme.
158
159
OUTPUT:
160
161
- A ``BlumGoldwasser`` object representing the Blum-Goldwasser
162
public-key encryption scheme.
163
164
See the class docstring of ``BlumGoldwasser`` for detailed
165
documentation.
166
167
EXAMPLES::
168
169
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
170
sage: bg = BlumGoldwasser()
171
sage: bg == loads(dumps(bg))
172
True
173
"""
174
# no internal data for now; nothing to initialize
175
pass
176
177
def __eq__(self, other):
178
"""
179
Compare this ``BlumGoldwasser`` object with ``other``.
180
181
INPUT:
182
183
- ``other`` -- a ``BlumGoldwasser`` object.
184
185
OUTPUT:
186
187
- ``True`` if both ``self`` and ``other`` are ``BlumGoldwasser``
188
objects. ``False`` otherwise.
189
190
Two objects are ``BlumGoldwasser`` objects if their string
191
representations are the same.
192
193
EXAMPLES::
194
195
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
196
sage: bg1 = BlumGoldwasser()
197
sage: bg2 = BlumGoldwasser()
198
sage: bg1 == bg2
199
True
200
"""
201
if self.__repr__() == other.__repr__():
202
return True
203
else:
204
return False
205
206
def __repr__(self):
207
"""
208
A string representation of this Blum-Goldwasser public-key encryption
209
scheme.
210
211
OUTPUT:
212
213
- A string representation of this Blum-Goldwasser public-key
214
encryption scheme.
215
216
EXAMPLES::
217
218
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
219
sage: BlumGoldwasser()
220
The Blum-Goldwasser public-key encryption scheme.
221
"""
222
return "The Blum-Goldwasser public-key encryption scheme."
223
224
def decrypt(self, C, K):
225
r"""
226
Apply the Blum-Goldwasser scheme to decrypt the ciphertext ``C``
227
using the private key ``K``.
228
229
INPUT:
230
231
- ``C`` -- a ciphertext resulting from encrypting a plaintext using
232
the Blum-Goldwasser encryption algorithm. The ciphertext `C` must
233
be of the form `C = (c_1, c_2, \dots, c_t, x_{t+1})`. Each `c_i`
234
is a sub-block of binary string and `x_{t+1}` is the result of the
235
`t+1`-th iteration of the Blum-Blum-Shub algorithm.
236
237
- ``K`` -- a private key `(p, q, a, b)` where `p` and `q` are
238
distinct Blum primes and `\gcd(p, q) = ap + bq = 1`.
239
240
OUTPUT:
241
242
- The plaintext resulting from decrypting the ciphertext ``C`` using
243
the Blum-Goldwasser decryption algorithm.
244
245
ALGORITHM:
246
247
The Blum-Goldwasser decryption algorithm is described in Algorithm
248
8.56, page 309 of [MenezesEtAl1996]_. The algorithm works as follows:
249
250
#. Let `C` be the ciphertext `C = (c_1, c_2, \dots, c_t, x_{t+1})`.
251
Then `t` is the number of ciphertext sub-blocks and `h` is the
252
length of each binary string sub-block `c_i`.
253
#. Let `(p, q, a, b)` be the private key whose corresponding
254
public key is `n = pq`. Note that `\gcd(p, q) = ap + bq = 1`.
255
#. Compute `d_1 = ((p + 1) / 4)^{t+1} \bmod{(p - 1)}`.
256
#. Compute `d_2 = ((q + 1) / 4)^{t+1} \bmod{(q - 1)}`.
257
#. Let `u = x_{t+1}^{d_1} \bmod p`.
258
#. Let `v = x_{t+1}^{d_2} \bmod q`.
259
#. Compute `x_0 = vap + ubq \bmod n`.
260
#. For `i` from 1 to `t`, do:
261
262
#. Compute `x_i = x_{t-1}^2 \bmod n`.
263
#. Let `p_i` be the `h` least significant bits of `x_i`.
264
#. Compute `m_i = p_i \oplus c_i`.
265
266
#. The plaintext is `m = m_1 m_2 \cdots m_t`.
267
268
EXAMPLES:
269
270
The following decryption example is taken from Example 8.57, pages
271
309--310 of [MenezesEtAl1996]_. Here we decrypt a binary string::
272
273
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
274
sage: bg = BlumGoldwasser()
275
sage: p = 499; q = 547
276
sage: C = ([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680)
277
sage: K = bg.private_key(p, q); K
278
(499, 547, -57, 52)
279
sage: P = bg.decrypt(C, K); P
280
[[1, 0, 0, 1], [1, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0], [1, 1, 0, 0]]
281
282
Convert the plaintext sub-blocks into a binary string::
283
284
sage: bin = BinaryStrings()
285
sage: bin(flatten(P))
286
10011100000100001100
287
288
Decrypt a longer ciphertext and convert the resulting plaintext
289
into an ASCII string::
290
291
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
292
sage: from sage.crypto.util import bin_to_ascii
293
sage: bg = BlumGoldwasser()
294
sage: p = 78307; q = 412487
295
sage: K = bg.private_key(p, q)
296
sage: C = ([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], \
297
... [1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], \
298
... [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], \
299
... [0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1], \
300
... [1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0], \
301
... [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], \
302
... [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0], \
303
... [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], \
304
... [0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], \
305
... [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1], \
306
... [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1], \
307
... [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0], \
308
... [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]], 3479653279)
309
sage: P = bg.decrypt(C, K)
310
sage: bin_to_ascii(flatten(P))
311
'Blum-Goldwasser encryption'
312
313
TESTS:
314
315
The private key `K = (p, q, a, b)` must be such that `p` and `q` are
316
distinct Blum primes. Even if `p` and `q` pass this criterion, they
317
must also satisfy the requirement `\gcd(p, q) = ap + bq = 1`. ::
318
319
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
320
sage: bg = BlumGoldwasser()
321
sage: C = ([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680)
322
sage: K = (7, 7, 1, 2)
323
sage: bg.decrypt(C, K)
324
Traceback (most recent call last):
325
...
326
ValueError: p and q must be distinct Blum primes.
327
sage: K = (7, 23, 1, 2)
328
sage: bg.decrypt(C, K)
329
Traceback (most recent call last):
330
...
331
ValueError: a and b must satisfy gcd(p, q) = ap + bq = 1.
332
sage: K = (11, 29, 8, -3)
333
sage: bg.decrypt(C, K)
334
Traceback (most recent call last):
335
...
336
ValueError: p and q must be distinct Blum primes.
337
"""
338
# ciphertext
339
c = C[0]
340
xt1 = C[-1]
341
# number of ciphertext sub-blocks
342
t = len(c)
343
# length of each ciphertext sub-block
344
h = len(c[0])
345
# private key
346
p, q, a, b = K
347
# public key
348
n = p * q
349
# sanity checks
350
if p == q:
351
raise ValueError("p and q must be distinct Blum primes.")
352
if (a*p + b*q) != 1:
353
raise ValueError("a and b must satisfy gcd(p, q) = ap + bq = 1.")
354
if (not is_blum_prime(p)) or (not is_blum_prime(q)):
355
raise ValueError("p and q must be distinct Blum primes.")
356
# prepare to decrypt
357
d1 = power_mod((p + 1) / 4, t + 1, p - 1)
358
d2 = power_mod((q + 1) / 4, t + 1, q - 1)
359
u = power_mod(xt1, d1, p)
360
v = power_mod(xt1, d2, q)
361
x0 = mod(v*a*p + u*b*q, n).lift()
362
# perform the decryption
363
M = []
364
for i in xrange(t):
365
x1 = power_mod(x0, 2, n)
366
p = least_significant_bits(x1, h)
367
M.append(map(xor, p, c[i]))
368
x0 = x1
369
return M
370
371
def encrypt(self, P, K, seed=None):
372
r"""
373
Apply the Blum-Goldwasser scheme to encrypt the plaintext ``P`` using
374
the public key ``K``.
375
376
INPUT:
377
378
- ``P`` -- a non-empty string of plaintext. The string ``""`` is
379
an empty string, whereas ``" "`` is a string consisting of one
380
white space character. The plaintext can be a binary string or
381
a string of ASCII characters. Where ``P`` is an ASCII string, then
382
``P`` is first encoded as a binary string prior to encryption.
383
384
- ``K`` -- a public key, which is the product of two Blum primes.
385
386
- ``seed`` -- (default: ``None``) if `p` and `q` are Blum primes and
387
`n = pq` is a public key, then ``seed`` is a quadratic residue in
388
the multiplicative group `(\ZZ/n\ZZ)^{\ast}`. If ``seed=None``,
389
then the function would generate its own random quadratic residue
390
in `(\ZZ/n\ZZ)^{\ast}`. Where a value for ``seed`` is provided,
391
it is your responsibility to ensure that the seed is a
392
quadratic residue in the multiplicative group `(\ZZ/n\ZZ)^{\ast}`.
393
394
OUTPUT:
395
396
- The ciphertext resulting from encrypting ``P`` using the public
397
key ``K``. The ciphertext `C` is of the form
398
`C = (c_1, c_2, \dots, c_t, x_{t+1})`. Each `c_i` is a
399
sub-block of binary string and `x_{t+1}` is the result of the
400
`t+1`-th iteration of the Blum-Blum-Shub algorithm.
401
402
ALGORITHM:
403
404
The Blum-Goldwasser encryption algorithm is described in Algorithm
405
8.56, page 309 of [MenezesEtAl1996]_. The algorithm works as follows:
406
407
#. Let `n` be a public key, where `n = pq` is the product of two
408
distinct Blum primes `p` and `q`.
409
#. Let `k = \lfloor \log_2(n) \rfloor` and
410
`h = \lfloor \log_2(k) \rfloor`.
411
#. Let `m = m_1 m_2 \cdots m_t` be the message (plaintext) where
412
each `m_i` is a binary string of length `h`.
413
#. Choose a random seed `x_0`, which is a quadratic residue in
414
the multiplicative group `(\ZZ/n\ZZ)^{\ast}`. That is, choose
415
a random `r \in (\ZZ/n\ZZ)^{\ast}` and compute
416
`x_0 = r^2 \bmod n`.
417
#. For `i` from 1 to `t`, do:
418
419
#. Let `x_i = x_{i-1}^2 \bmod n`.
420
#. Let `p_i` be the `h` least significant bits of `x_i`.
421
#. Let `c_i = p_i \oplus m_i`.
422
423
#. Compute `x_{t+1} = x_t^2 \bmod n`.
424
#. The ciphertext is `c = (c_1, c_2, \dots, c_t, x_{t+1})`.
425
426
The value `h` in the algorithm is the sub-block length. If the
427
binary string representing the message cannot be divided into blocks
428
of length `h` each, then other sub-block lengths would be used
429
instead. The sub-block lengths to fall back on are in the
430
following order: 16, 8, 4, 2, 1.
431
432
EXAMPLES:
433
434
The following encryption example is taken from Example 8.57,
435
pages 309--310 of [MenezesEtAl1996]_. Here, we encrypt a binary
436
string::
437
438
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
439
sage: bg = BlumGoldwasser()
440
sage: p = 499; q = 547; n = p * q
441
sage: P = "10011100000100001100"
442
sage: C = bg.encrypt(P, n, seed=159201); C
443
([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680)
444
445
Convert the ciphertext sub-blocks into a binary string::
446
447
sage: bin = BinaryStrings()
448
sage: bin(flatten(C[0]))
449
00100000110011100100
450
451
Now encrypt an ASCII string. The result is random; no seed is
452
provided to the encryption function so the function generates its
453
own random seed::
454
455
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
456
sage: bg = BlumGoldwasser()
457
sage: K = 32300619509
458
sage: P = "Blum-Goldwasser encryption"
459
sage: bg.encrypt(P, K) # random
460
([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], \
461
[1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], \
462
[0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], \
463
[0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1], \
464
[1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0], \
465
[0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], \
466
[1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0], \
467
[1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], \
468
[0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], \
469
[1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1], \
470
[1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1], \
471
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0], \
472
[0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]], 3479653279)
473
474
TESTS:
475
476
The plaintext cannot be an empty string. ::
477
478
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
479
sage: bg = BlumGoldwasser()
480
sage: bg.encrypt("", 3)
481
Traceback (most recent call last):
482
...
483
ValueError: The plaintext cannot be an empty string.
484
"""
485
# sanity check
486
if P == "":
487
raise ValueError("The plaintext cannot be an empty string.")
488
n = K
489
k = floor(log(n, base=2))
490
h = floor(log(k, base=2))
491
bin = BinaryStrings()
492
M = ""
493
try:
494
# the plaintext is a binary string
495
M = bin(P)
496
except TypeError:
497
# encode the plaintext as a binary string
498
# An exception might be raised here if P cannot be encoded as a
499
# binary string.
500
M = bin.encoding(P)
501
# the number of plaintext sub-blocks; each sub-block has length h
502
t = 0
503
try:
504
# Attempt to use t and h values from the algorithm described
505
# in [MenezesEtAl1996].
506
t = len(M) / h
507
# If the following raises an exception, then we can't use
508
# the t and h values specified by [MenezesEtAl1996].
509
mod(len(M), t)
510
# fall back to using other sub-block lengths
511
except TypeError:
512
# sub-blocks of length h = 16
513
if mod(len(M), 16) == 0:
514
h = 16
515
t = len(M) / h
516
# sub-blocks of length h = 8
517
elif mod(len(M), 8) == 0:
518
h = 8
519
t = len(M) / h
520
# sub-blocks of length h = 4
521
elif mod(len(M), 4) == 0:
522
h = 4
523
t = len(M) / h
524
# sub-blocks of length h = 2
525
elif mod(len(M), 2) == 0:
526
h = 2
527
t = len(M) / h
528
# sub-blocks of length h = 1
529
else:
530
h = 1
531
t = len(M) / h
532
# If no seed is provided, select a random seed.
533
x0 = seed
534
if seed is None:
535
zmod = IntegerModRing(n) # K = n = pq
536
r = zmod.random_element().lift()
537
while gcd(r, n) != 1:
538
r = zmod.random_element().lift()
539
x0 = power_mod(r, 2, n)
540
# perform the encryption
541
to_int = lambda x: int(str(x))
542
C = []
543
for i in xrange(t):
544
x1 = power_mod(x0, 2, n)
545
p = least_significant_bits(x1, h)
546
# xor p with a sub-block of length h. There are t sub-blocks of
547
# length h each.
548
C.append(map(xor, p, map(to_int, M[i*h : (i+1)*h])))
549
x0 = x1
550
x1 = power_mod(x0, 2, n)
551
return (C, x1)
552
553
def private_key(self, p, q):
554
r"""
555
Return the Blum-Goldwasser private key corresponding to the
556
distinct Blum primes ``p`` and ``q``.
557
558
INPUT:
559
560
- ``p`` -- a Blum prime.
561
562
- ``q`` -- a Blum prime.
563
564
OUTPUT:
565
566
- The Blum-Goldwasser private key `(p, q, a, b)` where
567
`\gcd(p, q) = ap + bq = 1`.
568
569
Both ``p`` and ``q`` must be distinct Blum primes. Let `p` be a
570
positive prime. Then `p` is a Blum prime if `p` is congruent to 3
571
modulo 4, i.e. `p \equiv 3 \pmod{4}`.
572
573
EXAMPLES:
574
575
Obtain two distinct Blum primes and compute the Blum-Goldwasser
576
private key corresponding to those two Blum primes::
577
578
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
579
sage: from sage.crypto.util import is_blum_prime
580
sage: bg = BlumGoldwasser()
581
sage: P = primes_first_n(10); P
582
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
583
sage: map(is_blum_prime, P)
584
[False, True, False, True, True, False, False, True, True, False]
585
sage: bg.private_key(19, 23)
586
(19, 23, -6, 5)
587
588
Choose two distinct random Blum primes, compute the Blum-Goldwasser
589
private key corresponding to those two primes, and test that the
590
resulting private key `(p, q, a, b)` satisfies
591
`\gcd(p, q) = ap + bq = 1`::
592
593
sage: from sage.crypto.util import random_blum_prime
594
sage: p = random_blum_prime(10**4, 10**5)
595
sage: q = random_blum_prime(10**4, 10**5)
596
sage: while q == p:
597
... q = random_blum_prime(10**4, 10**5)
598
...
599
sage: p, q, a, b = bg.private_key(p, q)
600
sage: gcd(p, q) == a*p + b*q == 1
601
True
602
603
TESTS:
604
605
Both of the input ``p`` and ``q`` must be distinct Blum primes. ::
606
607
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
608
sage: bg = BlumGoldwasser()
609
sage: bg.private_key(78307, 78307)
610
Traceback (most recent call last):
611
...
612
ValueError: p and q must be distinct Blum primes.
613
sage: bg.private_key(7, 4)
614
Traceback (most recent call last):
615
...
616
ValueError: p and q must be distinct Blum primes.
617
"""
618
if p == q:
619
raise ValueError("p and q must be distinct Blum primes.")
620
if is_blum_prime(p) and is_blum_prime(q):
621
# here gcd(p, q) = ap + bq = 1
622
bezout = xgcd(p, q)
623
a = bezout[1]
624
b = bezout[2]
625
return (p, q, a, b)
626
else:
627
raise ValueError("p and q must be distinct Blum primes.")
628
629
def public_key(self, p, q):
630
r"""
631
Return the Blum-Goldwasser public key corresponding to the
632
distinct Blum primes ``p`` and ``q``.
633
634
INPUT:
635
636
- ``p`` -- a Blum prime.
637
638
- ``q`` -- a Blum prime.
639
640
OUTPUT:
641
642
- The Blum-Goldwasser public key `n = pq`.
643
644
Both ``p`` and ``q`` must be distinct Blum primes. Let `p` be a
645
positive prime. Then `p` is a Blum prime if `p` is congruent to 3
646
modulo 4, i.e. `p \equiv 3 \pmod{4}`.
647
648
EXAMPLES:
649
650
Obtain two distinct Blum primes and compute the Blum-Goldwasser
651
public key corresponding to those two Blum primes::
652
653
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
654
sage: from sage.crypto.util import is_blum_prime
655
sage: bg = BlumGoldwasser()
656
sage: P = primes_first_n(10); P
657
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
658
sage: map(is_blum_prime, P)
659
[False, True, False, True, True, False, False, True, True, False]
660
sage: bg.public_key(3, 7)
661
21
662
663
Choose two distinct random Blum primes, compute the Blum-Goldwasser
664
public key corresponding to those two primes, and test that the
665
public key factorizes into Blum primes::
666
667
sage: from sage.crypto.util import random_blum_prime
668
sage: p = random_blum_prime(10**4, 10**5)
669
sage: q = random_blum_prime(10**4, 10**5)
670
sage: while q == p:
671
... q = random_blum_prime(10**4, 10**5)
672
...
673
sage: n = bg.public_key(p, q)
674
sage: f = factor(n)
675
sage: is_blum_prime(f[0][0]); is_blum_prime(f[1][0])
676
True
677
True
678
sage: p * q == f[0][0] * f[1][0]
679
True
680
681
TESTS:
682
683
The input ``p`` and ``q`` must be distinct Blum primes. ::
684
685
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
686
sage: bg = BlumGoldwasser()
687
sage: bg.public_key(3, 3)
688
Traceback (most recent call last):
689
...
690
ValueError: p and q must be distinct Blum primes.
691
sage: bg.public_key(23, 29)
692
Traceback (most recent call last):
693
...
694
ValueError: p and q must be distinct Blum primes.
695
"""
696
if p == q:
697
raise ValueError("p and q must be distinct Blum primes.")
698
if is_blum_prime(p) and is_blum_prime(q):
699
return p * q
700
else:
701
raise ValueError("p and q must be distinct Blum primes.")
702
703
def random_key(self, lbound, ubound, ntries=100):
704
r"""
705
Return a pair of random public and private keys.
706
707
INPUT:
708
709
- ``lbound`` -- positive integer; the lower bound on how small each
710
random Blum prime `p` and `q` can be. So we have
711
``0 < lower_bound <= p, q <= upper_bound``. The lower bound must
712
be distinct from the upper bound.
713
714
- ``ubound`` -- positive integer; the upper bound on how large each
715
random Blum prime `p` and `q` can be. So we have
716
``0 < lower_bound <= p, q <= upper_bound``. The lower bound must
717
be distinct from the upper bound.
718
719
- ``ntries`` -- (default: ``100``) the number of attempts to generate
720
a random public/private key pair. If ``ntries`` is a positive
721
integer, then perform that many attempts at generating a random
722
public/private key pair.
723
724
OUTPUT:
725
726
- A random public key and its corresponding private key. Each
727
randomly chosen `p` and `q` are guaranteed to be Blum primes. The
728
public key is `n = pq`, and the private key is `(p, q, a, b)` where
729
`\gcd(p, q) = ap + bq = 1`.
730
731
ALGORITHM:
732
733
The key generation algorithm is described in Algorithm 8.55,
734
page 308 of [MenezesEtAl1996]_. The algorithm works as follows:
735
736
#. Let `p` and `q` be distinct large random primes, each congruent
737
to 3 modulo 4. That is, `p` and `q` are Blum primes.
738
#. Let `n = pq` be the product of `p` and `q`.
739
#. Use the extended Euclidean algorithm to compute integers `a` and
740
`b` such that `\gcd(p, q) = ap + bq = 1`.
741
#. The public key is `n` and the corresponding private key is
742
`(p, q, a, b)`.
743
744
.. NOTE::
745
746
Beware that there might not be any primes between the lower and
747
upper bounds. So make sure that these two bounds are
748
"sufficiently" far apart from each other for there to be primes
749
congruent to 3 modulo 4. In particular, there should
750
be at least two distinct primes within these bounds, each prime
751
being congruent to 3 modulo 4.
752
753
EXAMPLES:
754
755
Choosing a random pair of public and private keys. We then test to see
756
if they satisfy the requirements of the Blum-Goldwasser scheme::
757
758
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
759
sage: from sage.crypto.util import is_blum_prime
760
sage: bg = BlumGoldwasser()
761
sage: pubkey, prikey = bg.random_key(10**4, 10**5)
762
sage: p, q, a, b = prikey
763
sage: is_blum_prime(p); is_blum_prime(q)
764
True
765
True
766
sage: p == q
767
False
768
sage: pubkey == p*q
769
True
770
sage: gcd(p, q) == a*p + b*q == 1
771
True
772
773
TESTS:
774
775
Make sure that there is at least one Blum prime between the lower and
776
upper bounds. In the following example, we have ``lbound=24`` and
777
``ubound=30`` with 29 being the only prime within those bounds. But
778
29 is not a Blum prime. ::
779
780
sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser
781
sage: bg = BlumGoldwasser()
782
sage: pubkey, privkey = bg.random_key(24, 30)
783
Traceback (most recent call last):
784
...
785
ValueError: No Blum primes within the specified closed interval.
786
"""
787
# choosing distinct random Blum primes
788
p = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries)
789
q = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries)
790
while p == q:
791
q = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries)
792
# compute the public key
793
n = p * q
794
# compute the private key; here gcd(p, q) = 1 = a*p + b*q
795
bezout = xgcd(p, q)
796
a = bezout[1]
797
b = bezout[2]
798
return (n, (p, q, a, b))
799
800