SeComLib
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Macros Pages
el_gamal.cpp
Go to the documentation of this file.
1 /*
2 SeComLib
3 Copyright 2012-2013 TU Delft, Information Security & Privacy Lab (http://isplab.tudelft.nl/)
4 
5 Contributors:
6 Inald Lagendijk (R.L.Lagendijk@TUDelft.nl)
7 Mihai Todor (todormihai@gmail.com)
8 Thijs Veugen (P.J.M.Veugen@tudelft.nl)
9 Zekeriya Erkin (z.erkin@tudelft.nl)
10 
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14 
15 http://www.apache.org/licenses/LICENSE-2.0
16 
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
31 #include "el_gamal.h"
32 
33 namespace SeComLib {
34 namespace Core {
39  }
40 
45  ElGamalRandomizer::ElGamalRandomizer (const BigInteger &x, const BigInteger &y) : x(x), y(y) {
46  }
47 
53  ElGamal::ElGamal (const bool precomputeDecryptionMap) : CryptoProvider<ElGamalPublicKey, ElGamalPrivateKey, ElGamalCiphertext, ElGamalRandomizer>(Utils::Config::GetInstance().GetParameter("Core.ElGamal.keySize", 1024)),
54  messageSpaceThreshold(BigInteger(2).Pow(Utils::Config::GetInstance().GetParameter<unsigned long>("Core.ElGamal.messageSpaceThresholdBitSize"))),
55  precomputeDecryptionMap(precomputeDecryptionMap) {
56  }
57 
65  ElGamal::ElGamal (const ElGamalPublicKey &publicKey) : CryptoProvider<ElGamalPublicKey, ElGamalPrivateKey, ElGamalCiphertext, ElGamalRandomizer>(publicKey, Utils::Config::GetInstance().GetParameter("Core.ElGamal.keySize", 1024)),
66  messageSpaceThreshold(BigInteger(2).Pow(Utils::Config::GetInstance().GetParameter<unsigned long>("Core.ElGamal.messageSpaceThresholdBitSize"))) {
67  //C++ doesn't allow us to call a virtual method in the constructor of the base class
68  this->doPrecomputations();
69  }
70 
78  ElGamal::ElGamal (const ElGamalPublicKey &publicKey, const ElGamalPrivateKey &privateKey, const bool precomputeDecryptionMap) : CryptoProvider<ElGamalPublicKey, ElGamalPrivateKey, ElGamalCiphertext, ElGamalRandomizer>(publicKey, privateKey, Utils::Config::GetInstance().GetParameter("Core.ElGamal.keySize", 1024)),
79  messageSpaceThreshold(BigInteger(2).Pow(Utils::Config::GetInstance().GetParameter<unsigned long>("Core.ElGamal.messageSpaceThresholdBitSize"))),
80  precomputeDecryptionMap(precomputeDecryptionMap) {
81  //C++ doesn't allow us to call a virtual method in the constructor of the base class
82  this->doPrecomputations();
83  }
84 
106  unsigned int largePrimeFactorSize = Utils::Config::GetInstance().GetParameter("Core.ElGamal.largePrimeFactorSize", 160);
107 
108  if (largePrimeFactorSize >= this->keyLength) {
110  throw std::runtime_error("Please choose a smaller prime factor size.");
111  }
112 
115 
116  BigInteger r, m, n;
117  unsigned int sizeR = this->keyLength - largePrimeFactorSize;
118  unsigned int sizeMN = (sizeR - 1) / 2;
119  do {
120  //pick a random prime @f$ q @f$ of size specified by largePrimeFactorSize
121  this->publicKey.q = RandomProvider::GetInstance().GetMaxLengthRandomPrime(largePrimeFactorSize);
122 
123  //generate two random primes in the interval (0, 2^((sizeR - 1) / 2))
124  m = RandomProvider::GetInstance().GetMaxLengthRandomPrime(sizeMN);
125  n = RandomProvider::GetInstance().GetMaxLengthRandomPrime(sizeMN);
126 
127  //compute r
128  r = m * n * 2;
129 
130  //q and r must divide p - 1
131  this->publicKey.p = this->publicKey.q * r + 1;
132  }
133  while (!this->publicKey.p.IsPrime());
134 
136  do {
137  //generate random g in the interval [0, p)
138  this->g = RandomProvider::GetInstance().GetRandomInteger(this->publicKey.p);
139  }
140  //ensure that g is a generator of Z_{p}^*
141  while (BigInteger::Gcd(this->g, this->publicKey.p) != 1 ||
142  this->g.GetPowModN(this->publicKey.q * m * n, this->publicKey.p) == 1 ||
143  this->g.GetPowModN(this->publicKey.q * m * 2, this->publicKey.p) == 1 ||
144  this->g.GetPowModN(this->publicKey.q * n * 2, this->publicKey.p) == 1 ||
145  this->g.GetPowModN(m * n * 2, this->publicKey.p) == 1);
146 
148  this->publicKey.gq = this->g.GetPowModN(r, this->publicKey.p);
149 
151  do {
152  this->privateKey.s = RandomProvider::GetInstance().GetRandomInteger(this->publicKey.q);
153  }
154  //s must be != 0
155  while (this->privateKey.s == 0);
156 
158  this->publicKey.h = this->publicKey.gq.GetPowModN(this->privateKey.s, this->publicKey.p);
159 
160  //precompute values for optimization purposes
161  this->doPrecomputations();
162 
163  return true;
164  }
165 
174  BigInteger ElGamal::DecryptInteger (const ElGamal::Ciphertext &ciphertext) const {
175  if (!this->hasPrivateKey) {
176  throw std::runtime_error("This operation requires the private key.");
177  }
178 
179  if (!this->precomputeDecryptionMap) {
180  throw std::runtime_error("This operation requires the decryption map.");
181  }
182 
184  BigInteger cyCxPowMinusSModP = (ciphertext.data.y * ciphertext.data.x.GetPowModN(-this->privateKey.s, this->publicKey.p)) % this->publicKey.p;
185 
187  if (cyCxPowMinusSModP == 1) {
188  return 0;
189  }
190 
193  BigInteger output;
194 
195  //get an iterator to the required element
196  DecryptionMap::const_iterator iterator = this->decryptionMap.find(cyCxPowMinusSModP);
197 
198  //make sure the key exists
199  if (this->decryptionMap.end() != iterator) {
200  output = BigInteger(iterator->second);
201  }
202  else {
203  throw std::runtime_error("Can't decrypt ciphertext.");
204  }
205 
206  if (output > this->positiveNegativeBoundary) {
207  output -= this->GetMessageSpaceUpperBound();
208  }
209 
210  return output;
211  }
212 
219  ElGamal::Ciphertext ElGamal::EncryptIntegerNonrandom (const BigInteger &plaintext) const {
221 
223 
225  output.data.x = 1;
226  if (plaintext < 0) {
227  output.data.y = this->publicKey.gq.GetPowModN(this->GetMessageSpaceUpperBound() + plaintext, this->publicKey.p);
228  }
229  else {
230  output.data.y = this->publicKey.gq.GetPowModN(plaintext, this->publicKey.p);
231  }
232 
233  return output;
234  }
235 
242  BigInteger random = RandomProvider::GetInstance().GetRandomInteger(this->publicKey.q);
243 
244  return Randomizer(this->publicKey.gq.GetPowModN(random, this->publicKey.p), this->publicKey.h.GetPowModN(random, this->publicKey.p));
245  }
246 
254  //assign a randomizer to the output
255  Randomizer randomizer = this->randomizerCache->Pop().randomizer;
256  Ciphertext output(this->encryptionModulus);
257 
258  //compose the output with the ciphertext
259  output.data.x = ciphertext.data.x * randomizer.x % this->GetEncryptionModulus();
260  output.data.y = ciphertext.data.y * randomizer.y % this->GetEncryptionModulus();
261 
262  return output;
263  }
264 
265 #ifdef ENABLE_CRYPTO_PROVIDER_HOMOMORPHIC_OPERATIONS
266 
272  ElGamal::Ciphertext ElGamal::HomomorphicAdd (const ElGamal::Ciphertext &lhs, const ElGamal::Ciphertext &rhs) const {
273  ElGamal::Ciphertext output;
274 
275  output.x = (lhs.x * rhs.x) % this->GetEncryptionModulus();
276  output.y = (lhs.y * rhs.y) % this->GetEncryptionModulus();
277 
278  return output;
279  }
280 
286  ElGamal::Ciphertext ElGamal::GetHomomorphicInverse (const ElGamal::Ciphertext &input) const {
287  ElGamal::Ciphertext output;
288 
289  output.x = input.x.GetInverseModN(this->GetEncryptionModulus());
290  output.y = input.y.GetInverseModN(this->GetEncryptionModulus());
291 
292  return output;
293  }
294 
301  ElGamal::Ciphertext ElGamal::HomomorphicSubtract (const ElGamal::Ciphertext &lhs, const ElGamal::Ciphertext &rhs) const {
302  ElGamal::Ciphertext output;
303 
304  output.x = (lhs.x * rhs.x.GetInverseModN(this->GetEncryptionModulus())) % this->GetEncryptionModulus();
305  output.y = (lhs.y * rhs.y.GetInverseModN(this->GetEncryptionModulus())) % this->GetEncryptionModulus();
306 
307  return output;
308  }
309 
317  ElGamal::Ciphertext ElGamal::HomomorphicMultiply (const ElGamal::Ciphertext &lhs, const BigInteger &rhs) const {
318  if (rhs == 0) {
319  throw std::runtime_error("The plaintext term should not be 0.");
320  }
321 
322  ElGamal::Ciphertext output = lhs;
323 
324  output.x = output.x.GetPowModN(rhs, this->GetEncryptionModulus());
325  output.y = output.y.GetPowModN(rhs, this->GetEncryptionModulus());
326 
327  return output;
328  }
329 #endif
330 
334  const BigInteger &ElGamal::GetMessageSpaceUpperBound () const {
335  return this->publicKey.q;
336  }
337 
342  return this->publicKey.q.GetSize();
343  }
344 
353  bool ElGamal::IsEncryptedZero (const Ciphertext &ciphertext) const {
354  if (!this->hasPrivateKey) {
355  throw std::runtime_error("This operation requires the private key.");
356  }
357 
358  BigInteger test = (ciphertext.data.y * ciphertext.data.x.GetPowModN(-this->privateKey.s, this->publicKey.p)) % this->publicKey.p;
359 
360  return test == 1 ? true : false;
361  }
362 
369  if (this->hasPrivateKey) {
371  if (this->precomputeDecryptionMap) {
372  //we handle the first part (for m >= 0)
373  for (BigInteger i = 0; i < this->messageSpaceThreshold; ++i) {
374  this->decryptionMap[this->publicKey.gq.GetPowModN(i, this->publicKey.p)] = i;
375  }
376  //and the second part (for m < 0) - we do one less iteration here, because size(positives \ {0}) = size(negatives)
377  for (BigInteger i = this->publicKey.q - this->messageSpaceThreshold + 1; i < this->publicKey.q; ++i) {
378  this->decryptionMap[this->publicKey.gq.GetPowModN(i, this->publicKey.p)] = i;
379  }
380  }
381  }
382 
383  //set the encryption modulus, @f$ p @f$
384  this->encryptionModulus = std::make_shared<BigInteger>(this->publicKey.p);
385 
387 
389  this->randomizerCache = std::unique_ptr<RandomizerCacheType>(new RandomizerCacheType(*this, "Core.RandomizerCache"));
390 
391  this->encryptedZero = this->EncryptInteger(BigInteger(0));
392 
393  this->encryptedOne = this->EncryptInteger(BigInteger(1));
394  }
395 
396 }//namespace Core
397 }//namespace SeComLib
RandomizerCache< RandomizerContainer< CryptoProvider< ElGamalPublicKey, ElGamalPrivateKey, ElGamalCiphertext, ElGamalRandomizer >, RandomizerCacheParameters > > RandomizerCacheType
Data type of the randomizer cache.
Data data
Cipertext container.
static Config & GetInstance()
Returns a reference to the singleton.
Definition: config.cpp:48
The private key container structure for the ElGamal cryptosystem.
Definition: el_gamal.h:62
DecryptionMap decryptionMap
Contains all possible values of , where , and it is required for decryption.
Definition: el_gamal.h:159
virtual size_t GetMessageSpaceSize() const
Returns the message space bit size.
Definition: el_gamal.cpp:341
virtual ElGamalCiphertext EncryptInteger(const BigInteger &plaintext) const
Encrypt an integer and apply randomization.
ElGamal(const bool precomputeDecryptionMap=false)
Default constructor.
Definition: el_gamal.cpp:53
virtual Ciphertext EncryptIntegerNonrandom(const BigInteger &plaintext) const
Encrypt number without randomization.
Definition: el_gamal.cpp:219
virtual const BigInteger & GetMessageSpaceUpperBound() const
Returns the message space upper bound.
Definition: el_gamal.cpp:334
virtual Ciphertext RandomizeCiphertext(const Ciphertext &ciphertext) const
Randomize encrypted number with a self-generated random value.
Definition: el_gamal.cpp:253
BigInteger messageSpaceThreshold
Definition: el_gamal.h:150
bool precomputeDecryptionMap
If true, full decryptions are enabled and the decryption map is (pre)computed.
Definition: el_gamal.h:156
ElGamalCiphertext encryptedZero
Contains [0] used as initializer for homomorphic addition accumulators. Precompute it for optimizatio...
BigInteger g
A generator of .
Definition: el_gamal.h:153
virtual BigInteger DecryptInteger(const Ciphertext &ciphertext) const
Decrypt number.
Definition: el_gamal.cpp:174
std::unique_ptr< RandomizerCacheType > randomizerCache
Lazy loading randomizer cache.
virtual Randomizer GetRandomizer() const
Compute the random factor required for the encryption operation.
Definition: el_gamal.cpp:241
virtual bool GenerateKeys()
Definition: el_gamal.cpp:104
T GetParameter(const std::string &parameter) const
Template method which returns the value of the specified configuration parameter. ...
Definition: config.hpp:41
BigInteger positiveNegativeBoundary
Contains the delimiter between positive and negative values in the message space (usually ) ...
The randomizer type for Paillier.
Definition: el_gamal.h:71
const BigInteger & GetEncryptionModulus() const
Returns the modulus required for reducing the encryption after randomization.
Definition of class ElGamal.
Template abstract base class for homomorphic encryption primitives.
virtual void doPrecomputations()
Precompute values for speedups.
Definition: el_gamal.cpp:368
bool hasPrivateKey
Boolean flag that enables decryption if the private key is present.
The public key container structure for the ElGamal cryptosystem.
Definition: el_gamal.h:47
ElGamalRandomizer()
Default constructor.
Definition: el_gamal.cpp:38
bool IsEncryptedZero(const Ciphertext &ciphertext) const
Determines if ciphertext contains an encryption of 0 or not.
Definition: el_gamal.cpp:353