Path: blob/master/src/sage/crypto/public_key/blum_goldwasser.py
8818 views
r"""1Blum-Goldwasser Probabilistic Encryption23The Blum-Goldwasser probabilistic public-key encryption scheme. This scheme4was originally described in [BlumGoldwasser1985]_. See also section 8.7.25of [MenezesEtAl1996]_ and the6`Wikipedia article <http://en.wikipedia.org/wiki/Blum-Goldwasser_cryptosystem>`_7on this scheme.89REFERENCES:1011.. [BlumGoldwasser1985] M. Blum and S. Goldwasser. An Efficient12Probabilistic Public-Key Encryption Scheme Which Hides All Partial13Information. In *Proceedings of CRYPTO 84 on Advances in Cryptology*,14pp. 289--299, Springer, 1985.1516.. [MenezesEtAl1996] A. J. Menezes, P. C. van Oorschot, and S. A. Vanstone.17*Handbook of Applied Cryptography*. CRC Press, 1996.1819AUTHORS:2021- Mike Hogan and David Joyner (2009-9-19): initial procedural version22released as public domain software.2324- Minh Van Nguyen (2009-12): integrate into Sage as a class and relicense25under the GPLv2+. Complete rewrite of the original version to follow26the description contained in [MenezesEtAl1996]_.27"""2829###########################################################################30# Copyright (c) 2009, 201031# Mike Hogan32# David Joyner <[email protected]>33# Minh Van Nguyen <[email protected]>34#35# This program is free software; you can redistribute it and/or modify36# it under the terms of the GNU General Public License as published by37# the Free Software Foundation; either version 2 of the License, or38# (at your option) any later version.39#40# This program is distributed in the hope that it will be useful,41# but WITHOUT ANY WARRANTY; without even the implied warranty of42# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the43# GNU General Public License for more details.44#45# http://www.gnu.org/licenses/46###########################################################################4748from operator import xor4950from sage.crypto.cryptosystem import PublicKeyCryptosystem51from sage.crypto.util import is_blum_prime52from sage.crypto.util import least_significant_bits53from sage.crypto.util import random_blum_prime54from sage.functions.log import log55from sage.functions.other import Function_floor56from sage.monoids.string_monoid import BinaryStrings57from sage.rings.arith import gcd58from sage.rings.arith import power_mod59from sage.rings.arith import xgcd60from sage.rings.finite_rings.integer_mod import Mod as mod61from sage.rings.finite_rings.integer_mod_ring import IntegerModFactory6263floor = Function_floor()64IntegerModRing = IntegerModFactory("IntegerModRing")6566class BlumGoldwasser(PublicKeyCryptosystem):67r"""68The Blum-Goldwasser probabilistic public-key encryption scheme.6970The Blum-Goldwasser encryption and decryption algorithms as described in71:func:`encrypt() <BlumGoldwasser.encrypt>` and72:func:`decrypt() <BlumGoldwasser.decrypt>`, respectively, make use of the73least significant bit of a binary string. A related concept is the `k`74least significant bits of a binary string. For example, given a positive75integer `n`, let `b = b_0 b_1 \cdots b_{m-1}` be the binary representation76of `n` so that `b` is a binary string of length `m`. Then the least77significant bit of `n` is `b_{m-1}`. If `0 < k \leq m`, then the `k` least78significant bits of `n` are `b_{m-1-k} b_{m-k} \cdots b_{m-1}`. The least79significant bit of an integer is also referred to as its parity bit,80because this bit determines whether the integer is even or odd. In the81following example, we obtain the least significant bit of an integer::8283sage: n = 12384sage: b = n.binary(); b85'1111011'86sage: n % 287188sage: b[-1]89'1'9091Now find the 4 least significant bits of the integer `n = 123`::9293sage: b94'1111011'95sage: b[-4:]96'1011'9798The last two examples could be worked through as follows::99100sage: from sage.crypto.util import least_significant_bits101sage: least_significant_bits(123, 1)102[1]103sage: least_significant_bits(123, 4)104[1, 0, 1, 1]105106EXAMPLES:107108The following encryption/decryption example is taken from Example 8.57,109pages 309--310 of [MenezesEtAl1996]_::110111sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser112sage: bg = BlumGoldwasser(); bg113The Blum-Goldwasser public-key encryption scheme.114sage: p = 499; q = 547115sage: pubkey = bg.public_key(p, q); pubkey116272953117sage: prikey = bg.private_key(p, q); prikey118(499, 547, -57, 52)119sage: P = "10011100000100001100"120sage: C = bg.encrypt(P, pubkey, seed=159201); C121([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680)122sage: M = bg.decrypt(C, prikey); M123[[1, 0, 0, 1], [1, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0], [1, 1, 0, 0]]124sage: M = "".join(map(lambda x: str(x), flatten(M))); M125'10011100000100001100'126sage: M == P127True128129Generate a pair of random public/private keys. Use the public key to130encrypt a plaintext. Then decrypt the resulting ciphertext using the131private key. Finally, compare the decrypted message with the original132plaintext. ::133134sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser135sage: from sage.crypto.util import bin_to_ascii136sage: bg = BlumGoldwasser()137sage: pubkey, prikey = bg.random_key(10**4, 10**6)138sage: P = "A fixed plaintext."139sage: C = bg.encrypt(P, pubkey)140sage: M = bg.decrypt(C, prikey)141sage: bin_to_ascii(flatten(M)) == P142True143144If `(p, q, a, b)` is a private key, then `n = pq` is the corresponding145public key. Furthermore, we have `\gcd(p, q) = ap + bq = 1`. ::146147sage: p, q, a, b = prikey148sage: pubkey == p * q149True150sage: gcd(p, q) == a*p + b*q == 1151True152"""153154def __init__(self):155"""156Construct the Blum-Goldwasser public-key encryption scheme.157158OUTPUT:159160- A ``BlumGoldwasser`` object representing the Blum-Goldwasser161public-key encryption scheme.162163See the class docstring of ``BlumGoldwasser`` for detailed164documentation.165166EXAMPLES::167168sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser169sage: bg = BlumGoldwasser()170sage: bg == loads(dumps(bg))171True172"""173# no internal data for now; nothing to initialize174pass175176def __eq__(self, other):177"""178Compare this ``BlumGoldwasser`` object with ``other``.179180INPUT:181182- ``other`` -- a ``BlumGoldwasser`` object.183184OUTPUT:185186- ``True`` if both ``self`` and ``other`` are ``BlumGoldwasser``187objects. ``False`` otherwise.188189Two objects are ``BlumGoldwasser`` objects if their string190representations are the same.191192EXAMPLES::193194sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser195sage: bg1 = BlumGoldwasser()196sage: bg2 = BlumGoldwasser()197sage: bg1 == bg2198True199"""200if self.__repr__() == other.__repr__():201return True202else:203return False204205def __repr__(self):206"""207A string representation of this Blum-Goldwasser public-key encryption208scheme.209210OUTPUT:211212- A string representation of this Blum-Goldwasser public-key213encryption scheme.214215EXAMPLES::216217sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser218sage: BlumGoldwasser()219The Blum-Goldwasser public-key encryption scheme.220"""221return "The Blum-Goldwasser public-key encryption scheme."222223def decrypt(self, C, K):224r"""225Apply the Blum-Goldwasser scheme to decrypt the ciphertext ``C``226using the private key ``K``.227228INPUT:229230- ``C`` -- a ciphertext resulting from encrypting a plaintext using231the Blum-Goldwasser encryption algorithm. The ciphertext `C` must232be of the form `C = (c_1, c_2, \dots, c_t, x_{t+1})`. Each `c_i`233is a sub-block of binary string and `x_{t+1}` is the result of the234`t+1`-th iteration of the Blum-Blum-Shub algorithm.235236- ``K`` -- a private key `(p, q, a, b)` where `p` and `q` are237distinct Blum primes and `\gcd(p, q) = ap + bq = 1`.238239OUTPUT:240241- The plaintext resulting from decrypting the ciphertext ``C`` using242the Blum-Goldwasser decryption algorithm.243244ALGORITHM:245246The Blum-Goldwasser decryption algorithm is described in Algorithm2478.56, page 309 of [MenezesEtAl1996]_. The algorithm works as follows:248249#. Let `C` be the ciphertext `C = (c_1, c_2, \dots, c_t, x_{t+1})`.250Then `t` is the number of ciphertext sub-blocks and `h` is the251length of each binary string sub-block `c_i`.252#. Let `(p, q, a, b)` be the private key whose corresponding253public key is `n = pq`. Note that `\gcd(p, q) = ap + bq = 1`.254#. Compute `d_1 = ((p + 1) / 4)^{t+1} \bmod{(p - 1)}`.255#. Compute `d_2 = ((q + 1) / 4)^{t+1} \bmod{(q - 1)}`.256#. Let `u = x_{t+1}^{d_1} \bmod p`.257#. Let `v = x_{t+1}^{d_2} \bmod q`.258#. Compute `x_0 = vap + ubq \bmod n`.259#. For `i` from 1 to `t`, do:260261#. Compute `x_i = x_{t-1}^2 \bmod n`.262#. Let `p_i` be the `h` least significant bits of `x_i`.263#. Compute `m_i = p_i \oplus c_i`.264265#. The plaintext is `m = m_1 m_2 \cdots m_t`.266267EXAMPLES:268269The following decryption example is taken from Example 8.57, pages270309--310 of [MenezesEtAl1996]_. Here we decrypt a binary string::271272sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser273sage: bg = BlumGoldwasser()274sage: p = 499; q = 547275sage: C = ([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680)276sage: K = bg.private_key(p, q); K277(499, 547, -57, 52)278sage: P = bg.decrypt(C, K); P279[[1, 0, 0, 1], [1, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0], [1, 1, 0, 0]]280281Convert the plaintext sub-blocks into a binary string::282283sage: bin = BinaryStrings()284sage: bin(flatten(P))28510011100000100001100286287Decrypt a longer ciphertext and convert the resulting plaintext288into an ASCII string::289290sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser291sage: from sage.crypto.util import bin_to_ascii292sage: bg = BlumGoldwasser()293sage: p = 78307; q = 412487294sage: K = bg.private_key(p, q)295sage: C = ([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], \296... [1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], \297... [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], \298... [0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1], \299... [1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0], \300... [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], \301... [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0], \302... [1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], \303... [0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], \304... [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1], \305... [1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1], \306... [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0], \307... [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]], 3479653279)308sage: P = bg.decrypt(C, K)309sage: bin_to_ascii(flatten(P))310'Blum-Goldwasser encryption'311312TESTS:313314The private key `K = (p, q, a, b)` must be such that `p` and `q` are315distinct Blum primes. Even if `p` and `q` pass this criterion, they316must also satisfy the requirement `\gcd(p, q) = ap + bq = 1`. ::317318sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser319sage: bg = BlumGoldwasser()320sage: C = ([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680)321sage: K = (7, 7, 1, 2)322sage: bg.decrypt(C, K)323Traceback (most recent call last):324...325ValueError: p and q must be distinct Blum primes.326sage: K = (7, 23, 1, 2)327sage: bg.decrypt(C, K)328Traceback (most recent call last):329...330ValueError: a and b must satisfy gcd(p, q) = ap + bq = 1.331sage: K = (11, 29, 8, -3)332sage: bg.decrypt(C, K)333Traceback (most recent call last):334...335ValueError: p and q must be distinct Blum primes.336"""337# ciphertext338c = C[0]339xt1 = C[-1]340# number of ciphertext sub-blocks341t = len(c)342# length of each ciphertext sub-block343h = len(c[0])344# private key345p, q, a, b = K346# public key347n = p * q348# sanity checks349if p == q:350raise ValueError("p and q must be distinct Blum primes.")351if (a*p + b*q) != 1:352raise ValueError("a and b must satisfy gcd(p, q) = ap + bq = 1.")353if (not is_blum_prime(p)) or (not is_blum_prime(q)):354raise ValueError("p and q must be distinct Blum primes.")355# prepare to decrypt356d1 = power_mod((p + 1) / 4, t + 1, p - 1)357d2 = power_mod((q + 1) / 4, t + 1, q - 1)358u = power_mod(xt1, d1, p)359v = power_mod(xt1, d2, q)360x0 = mod(v*a*p + u*b*q, n).lift()361# perform the decryption362M = []363for i in xrange(t):364x1 = power_mod(x0, 2, n)365p = least_significant_bits(x1, h)366M.append(map(xor, p, c[i]))367x0 = x1368return M369370def encrypt(self, P, K, seed=None):371r"""372Apply the Blum-Goldwasser scheme to encrypt the plaintext ``P`` using373the public key ``K``.374375INPUT:376377- ``P`` -- a non-empty string of plaintext. The string ``""`` is378an empty string, whereas ``" "`` is a string consisting of one379white space character. The plaintext can be a binary string or380a string of ASCII characters. Where ``P`` is an ASCII string, then381``P`` is first encoded as a binary string prior to encryption.382383- ``K`` -- a public key, which is the product of two Blum primes.384385- ``seed`` -- (default: ``None``) if `p` and `q` are Blum primes and386`n = pq` is a public key, then ``seed`` is a quadratic residue in387the multiplicative group `(\ZZ/n\ZZ)^{\ast}`. If ``seed=None``,388then the function would generate its own random quadratic residue389in `(\ZZ/n\ZZ)^{\ast}`. Where a value for ``seed`` is provided,390it is your responsibility to ensure that the seed is a391quadratic residue in the multiplicative group `(\ZZ/n\ZZ)^{\ast}`.392393OUTPUT:394395- The ciphertext resulting from encrypting ``P`` using the public396key ``K``. The ciphertext `C` is of the form397`C = (c_1, c_2, \dots, c_t, x_{t+1})`. Each `c_i` is a398sub-block of binary string and `x_{t+1}` is the result of the399`t+1`-th iteration of the Blum-Blum-Shub algorithm.400401ALGORITHM:402403The Blum-Goldwasser encryption algorithm is described in Algorithm4048.56, page 309 of [MenezesEtAl1996]_. The algorithm works as follows:405406#. Let `n` be a public key, where `n = pq` is the product of two407distinct Blum primes `p` and `q`.408#. Let `k = \lfloor \log_2(n) \rfloor` and409`h = \lfloor \log_2(k) \rfloor`.410#. Let `m = m_1 m_2 \cdots m_t` be the message (plaintext) where411each `m_i` is a binary string of length `h`.412#. Choose a random seed `x_0`, which is a quadratic residue in413the multiplicative group `(\ZZ/n\ZZ)^{\ast}`. That is, choose414a random `r \in (\ZZ/n\ZZ)^{\ast}` and compute415`x_0 = r^2 \bmod n`.416#. For `i` from 1 to `t`, do:417418#. Let `x_i = x_{i-1}^2 \bmod n`.419#. Let `p_i` be the `h` least significant bits of `x_i`.420#. Let `c_i = p_i \oplus m_i`.421422#. Compute `x_{t+1} = x_t^2 \bmod n`.423#. The ciphertext is `c = (c_1, c_2, \dots, c_t, x_{t+1})`.424425The value `h` in the algorithm is the sub-block length. If the426binary string representing the message cannot be divided into blocks427of length `h` each, then other sub-block lengths would be used428instead. The sub-block lengths to fall back on are in the429following order: 16, 8, 4, 2, 1.430431EXAMPLES:432433The following encryption example is taken from Example 8.57,434pages 309--310 of [MenezesEtAl1996]_. Here, we encrypt a binary435string::436437sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser438sage: bg = BlumGoldwasser()439sage: p = 499; q = 547; n = p * q440sage: P = "10011100000100001100"441sage: C = bg.encrypt(P, n, seed=159201); C442([[0, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0]], 139680)443444Convert the ciphertext sub-blocks into a binary string::445446sage: bin = BinaryStrings()447sage: bin(flatten(C[0]))44800100000110011100100449450Now encrypt an ASCII string. The result is random; no seed is451provided to the encryption function so the function generates its452own random seed::453454sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser455sage: bg = BlumGoldwasser()456sage: K = 32300619509457sage: P = "Blum-Goldwasser encryption"458sage: bg.encrypt(P, K) # random459([[1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0], \460[1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1], \461[0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], \462[0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1], \463[1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0], \464[0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], \465[1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0], \466[1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1], \467[0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], \468[1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1], \469[1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1], \470[1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0], \471[0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]], 3479653279)472473TESTS:474475The plaintext cannot be an empty string. ::476477sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser478sage: bg = BlumGoldwasser()479sage: bg.encrypt("", 3)480Traceback (most recent call last):481...482ValueError: The plaintext cannot be an empty string.483"""484# sanity check485if P == "":486raise ValueError("The plaintext cannot be an empty string.")487n = K488k = floor(log(n, base=2))489h = floor(log(k, base=2))490bin = BinaryStrings()491M = ""492try:493# the plaintext is a binary string494M = bin(P)495except TypeError:496# encode the plaintext as a binary string497# An exception might be raised here if P cannot be encoded as a498# binary string.499M = bin.encoding(P)500# the number of plaintext sub-blocks; each sub-block has length h501t = 0502try:503# Attempt to use t and h values from the algorithm described504# in [MenezesEtAl1996].505t = len(M) / h506# If the following raises an exception, then we can't use507# the t and h values specified by [MenezesEtAl1996].508mod(len(M), t)509# fall back to using other sub-block lengths510except TypeError:511# sub-blocks of length h = 16512if mod(len(M), 16) == 0:513h = 16514t = len(M) / h515# sub-blocks of length h = 8516elif mod(len(M), 8) == 0:517h = 8518t = len(M) / h519# sub-blocks of length h = 4520elif mod(len(M), 4) == 0:521h = 4522t = len(M) / h523# sub-blocks of length h = 2524elif mod(len(M), 2) == 0:525h = 2526t = len(M) / h527# sub-blocks of length h = 1528else:529h = 1530t = len(M) / h531# If no seed is provided, select a random seed.532x0 = seed533if seed is None:534zmod = IntegerModRing(n) # K = n = pq535r = zmod.random_element().lift()536while gcd(r, n) != 1:537r = zmod.random_element().lift()538x0 = power_mod(r, 2, n)539# perform the encryption540to_int = lambda x: int(str(x))541C = []542for i in xrange(t):543x1 = power_mod(x0, 2, n)544p = least_significant_bits(x1, h)545# xor p with a sub-block of length h. There are t sub-blocks of546# length h each.547C.append(map(xor, p, map(to_int, M[i*h : (i+1)*h])))548x0 = x1549x1 = power_mod(x0, 2, n)550return (C, x1)551552def private_key(self, p, q):553r"""554Return the Blum-Goldwasser private key corresponding to the555distinct Blum primes ``p`` and ``q``.556557INPUT:558559- ``p`` -- a Blum prime.560561- ``q`` -- a Blum prime.562563OUTPUT:564565- The Blum-Goldwasser private key `(p, q, a, b)` where566`\gcd(p, q) = ap + bq = 1`.567568Both ``p`` and ``q`` must be distinct Blum primes. Let `p` be a569positive prime. Then `p` is a Blum prime if `p` is congruent to 3570modulo 4, i.e. `p \equiv 3 \pmod{4}`.571572EXAMPLES:573574Obtain two distinct Blum primes and compute the Blum-Goldwasser575private key corresponding to those two Blum primes::576577sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser578sage: from sage.crypto.util import is_blum_prime579sage: bg = BlumGoldwasser()580sage: P = primes_first_n(10); P581[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]582sage: map(is_blum_prime, P)583[False, True, False, True, True, False, False, True, True, False]584sage: bg.private_key(19, 23)585(19, 23, -6, 5)586587Choose two distinct random Blum primes, compute the Blum-Goldwasser588private key corresponding to those two primes, and test that the589resulting private key `(p, q, a, b)` satisfies590`\gcd(p, q) = ap + bq = 1`::591592sage: from sage.crypto.util import random_blum_prime593sage: p = random_blum_prime(10**4, 10**5)594sage: q = random_blum_prime(10**4, 10**5)595sage: while q == p:596... q = random_blum_prime(10**4, 10**5)597...598sage: p, q, a, b = bg.private_key(p, q)599sage: gcd(p, q) == a*p + b*q == 1600True601602TESTS:603604Both of the input ``p`` and ``q`` must be distinct Blum primes. ::605606sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser607sage: bg = BlumGoldwasser()608sage: bg.private_key(78307, 78307)609Traceback (most recent call last):610...611ValueError: p and q must be distinct Blum primes.612sage: bg.private_key(7, 4)613Traceback (most recent call last):614...615ValueError: p and q must be distinct Blum primes.616"""617if p == q:618raise ValueError("p and q must be distinct Blum primes.")619if is_blum_prime(p) and is_blum_prime(q):620# here gcd(p, q) = ap + bq = 1621bezout = xgcd(p, q)622a = bezout[1]623b = bezout[2]624return (p, q, a, b)625else:626raise ValueError("p and q must be distinct Blum primes.")627628def public_key(self, p, q):629r"""630Return the Blum-Goldwasser public key corresponding to the631distinct Blum primes ``p`` and ``q``.632633INPUT:634635- ``p`` -- a Blum prime.636637- ``q`` -- a Blum prime.638639OUTPUT:640641- The Blum-Goldwasser public key `n = pq`.642643Both ``p`` and ``q`` must be distinct Blum primes. Let `p` be a644positive prime. Then `p` is a Blum prime if `p` is congruent to 3645modulo 4, i.e. `p \equiv 3 \pmod{4}`.646647EXAMPLES:648649Obtain two distinct Blum primes and compute the Blum-Goldwasser650public key corresponding to those two Blum primes::651652sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser653sage: from sage.crypto.util import is_blum_prime654sage: bg = BlumGoldwasser()655sage: P = primes_first_n(10); P656[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]657sage: map(is_blum_prime, P)658[False, True, False, True, True, False, False, True, True, False]659sage: bg.public_key(3, 7)66021661662Choose two distinct random Blum primes, compute the Blum-Goldwasser663public key corresponding to those two primes, and test that the664public key factorizes into Blum primes::665666sage: from sage.crypto.util import random_blum_prime667sage: p = random_blum_prime(10**4, 10**5)668sage: q = random_blum_prime(10**4, 10**5)669sage: while q == p:670... q = random_blum_prime(10**4, 10**5)671...672sage: n = bg.public_key(p, q)673sage: f = factor(n)674sage: is_blum_prime(f[0][0]); is_blum_prime(f[1][0])675True676True677sage: p * q == f[0][0] * f[1][0]678True679680TESTS:681682The input ``p`` and ``q`` must be distinct Blum primes. ::683684sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser685sage: bg = BlumGoldwasser()686sage: bg.public_key(3, 3)687Traceback (most recent call last):688...689ValueError: p and q must be distinct Blum primes.690sage: bg.public_key(23, 29)691Traceback (most recent call last):692...693ValueError: p and q must be distinct Blum primes.694"""695if p == q:696raise ValueError("p and q must be distinct Blum primes.")697if is_blum_prime(p) and is_blum_prime(q):698return p * q699else:700raise ValueError("p and q must be distinct Blum primes.")701702def random_key(self, lbound, ubound, ntries=100):703r"""704Return a pair of random public and private keys.705706INPUT:707708- ``lbound`` -- positive integer; the lower bound on how small each709random Blum prime `p` and `q` can be. So we have710``0 < lower_bound <= p, q <= upper_bound``. The lower bound must711be distinct from the upper bound.712713- ``ubound`` -- positive integer; the upper bound on how large each714random Blum prime `p` and `q` can be. So we have715``0 < lower_bound <= p, q <= upper_bound``. The lower bound must716be distinct from the upper bound.717718- ``ntries`` -- (default: ``100``) the number of attempts to generate719a random public/private key pair. If ``ntries`` is a positive720integer, then perform that many attempts at generating a random721public/private key pair.722723OUTPUT:724725- A random public key and its corresponding private key. Each726randomly chosen `p` and `q` are guaranteed to be Blum primes. The727public key is `n = pq`, and the private key is `(p, q, a, b)` where728`\gcd(p, q) = ap + bq = 1`.729730ALGORITHM:731732The key generation algorithm is described in Algorithm 8.55,733page 308 of [MenezesEtAl1996]_. The algorithm works as follows:734735#. Let `p` and `q` be distinct large random primes, each congruent736to 3 modulo 4. That is, `p` and `q` are Blum primes.737#. Let `n = pq` be the product of `p` and `q`.738#. Use the extended Euclidean algorithm to compute integers `a` and739`b` such that `\gcd(p, q) = ap + bq = 1`.740#. The public key is `n` and the corresponding private key is741`(p, q, a, b)`.742743.. NOTE::744745Beware that there might not be any primes between the lower and746upper bounds. So make sure that these two bounds are747"sufficiently" far apart from each other for there to be primes748congruent to 3 modulo 4. In particular, there should749be at least two distinct primes within these bounds, each prime750being congruent to 3 modulo 4.751752EXAMPLES:753754Choosing a random pair of public and private keys. We then test to see755if they satisfy the requirements of the Blum-Goldwasser scheme::756757sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser758sage: from sage.crypto.util import is_blum_prime759sage: bg = BlumGoldwasser()760sage: pubkey, prikey = bg.random_key(10**4, 10**5)761sage: p, q, a, b = prikey762sage: is_blum_prime(p); is_blum_prime(q)763True764True765sage: p == q766False767sage: pubkey == p*q768True769sage: gcd(p, q) == a*p + b*q == 1770True771772TESTS:773774Make sure that there is at least one Blum prime between the lower and775upper bounds. In the following example, we have ``lbound=24`` and776``ubound=30`` with 29 being the only prime within those bounds. But77729 is not a Blum prime. ::778779sage: from sage.crypto.public_key.blum_goldwasser import BlumGoldwasser780sage: bg = BlumGoldwasser()781sage: pubkey, privkey = bg.random_key(24, 30)782Traceback (most recent call last):783...784ValueError: No Blum primes within the specified closed interval.785"""786# choosing distinct random Blum primes787p = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries)788q = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries)789while p == q:790q = random_blum_prime(lbound=lbound, ubound=ubound, ntries=ntries)791# compute the public key792n = p * q793# compute the private key; here gcd(p, q) = 1 = a*p + b*q794bezout = xgcd(p, q)795a = bezout[1]796b = bezout[2]797return (n, (p, q, a, b))798799800