SeComLib
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Macros Pages
dgk.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 "dgk.h"
32 
33 namespace SeComLib {
34 namespace Core {
40  }
41 
46  DgkCiphertext::DgkCiphertext (const std::shared_ptr<BigInteger> &encryptionModulus) :
47  CiphertextBase<DgkCiphertext> (encryptionModulus) {
48  }
49 
55  DgkCiphertext::DgkCiphertext (const BigInteger &data, const std::shared_ptr<BigInteger> &encryptionModulus) :
56  CiphertextBase<DgkCiphertext> (data, encryptionModulus) {
57  }
58 
62  }
63 
68  DgkRandomizer::DgkRandomizer (const BigInteger &data) : RandomizerBase(data) {
69  }
70 
78  Dgk::Dgk (const bool precomputeDecryptionMap) : CryptoProvider<DgkPublicKey, DgkPrivateKey, DgkCiphertext, DgkRandomizer>(Utils::Config::GetInstance().GetParameter("Core.Dgk.k", 1024)),
79  t(Utils::Config::GetInstance().GetParameter("Core.Dgk.t", 160)),
80  l(Utils::Config::GetInstance().GetParameter("Core.Dgk.l", 16)),
81  precomputeDecryptionMap(precomputeDecryptionMap) {
82  this->validateParameters();
83  }
84 
90  Dgk::Dgk (const DgkPublicKey &publicKey) : CryptoProvider<DgkPublicKey, DgkPrivateKey, DgkCiphertext, DgkRandomizer>(publicKey, Utils::Config::GetInstance().GetParameter("Core.Dgk.k", 1024)),
91  t(Utils::Config::GetInstance().GetParameter("Core.Dgk.t", 160)),
92  l(Utils::Config::GetInstance().GetParameter("Core.Dgk.l", 16)) {
93  this->validateParameters();
94 
95  //precompute values for optimization purposes
96  this->doPrecomputations();
97  }
98 
106  Dgk::Dgk (const DgkPublicKey &publicKey, const DgkPrivateKey &privateKey, const bool precomputeDecryptionMap) : CryptoProvider<DgkPublicKey, DgkPrivateKey, DgkCiphertext, DgkRandomizer>(publicKey, privateKey, Utils::Config::GetInstance().GetParameter("Core.Dgk.k", 1024)),
107  t(Utils::Config::GetInstance().GetParameter("Core.Dgk.t", 160)),
108  l(Utils::Config::GetInstance().GetParameter("Core.Dgk.l", 16)),
109  precomputeDecryptionMap(precomputeDecryptionMap) {
110  this->validateParameters();
111 
112  //precompute values for optimization purposes
113  this->doPrecomputations();
114  }
115 
163  this->publicKey.u = BigInteger(2).GetPow(this->l + 2).GetNextPrime();
164 
165  //std::cout << "Message space: " << this->publicKey.u.ToString(10).c_str() << std::endl;
166 
168  this->privateKey.vp = RandomProvider::GetInstance().GetMaxLengthRandomPrime(this->t);
169  do {
170  this->privateKey.vq = RandomProvider::GetInstance().GetMaxLengthRandomPrime(this->t);
171  }
174  while (this->privateKey.vq == this->privateKey.vp);
175 
180  BigInteger pRand, qRand;
181  BigInteger aux;
182  size_t sizeRand;
183 
184  //precompute 2 * u * vp
185  aux = BigInteger(2) * this->publicKey.u * this->privateKey.vp;
186  //compute the required length of the random part of p
187  sizeRand = this->keyLength / 2 - aux.GetSize();
188 
189  if (0 == sizeRand) {
191  throw std::runtime_error("Parameter k is too small.");
192  }
193 
194  do {
195  //generate a prime number in the interval [0, 2^sizeRand)
196  pRand = RandomProvider::GetInstance().GetMaxLengthRandomPrime(sizeRand);
197 
198  //p = pRand * 2 * u * vp + 1
199  this->privateKey.p = pRand * aux + 1;
200  }
201  while (!this->privateKey.p.IsPrime());
202 
203  //precompute 2 * u * vq
204  aux = BigInteger(2) * this->publicKey.u * this->privateKey.vq;
205 
206  sizeRand = this->keyLength / 2 - aux.GetSize();
207 
208  if (0 == sizeRand) {
210  throw std::runtime_error("Parameter k is too small.");
211  }
212 
213  do {
214  //generate a prime number in the interval [0, 2^sizeRand)
215  qRand = RandomProvider::GetInstance().GetMaxLengthRandomPrime(sizeRand);
216 
217  //q = qRand * 2 * u * vq + 1
218  this->privateKey.q = qRand * aux + 1;
219  }
220  while (!this->privateKey.q.IsPrime());
221 
223  this->publicKey.n = this->privateKey.p * this->privateKey.q;
224 
227 
228  BigInteger hRandP;
229  do {
230  //generate a random number in the interval [0, p)
231  hRandP = RandomProvider::GetInstance().GetRandomInteger(this->privateKey.p);
232  }
233  //this loop can be optimized by precomputing the partial products
234  while (hRandP == 1 ||
235  BigInteger::Gcd(hRandP, this->privateKey.p) != 1 ||
236  hRandP.GetPowModN(this->privateKey.vp * this->publicKey.u * 2, this->privateKey.p) == 1 ||
237  hRandP.GetPowModN(pRand * this->publicKey.u * 2, this->privateKey.p) == 1 ||
238  hRandP.GetPowModN(pRand * this->privateKey.vp * 2, this->privateKey.p) == 1 ||
239  hRandP.GetPowModN(pRand * this->privateKey.vp * this->publicKey.u, this->privateKey.p) == 1);
240 
241  BigInteger hRandQ;
242  do {
243  //generate a random number in the interval [0, q)
244  hRandQ = RandomProvider::GetInstance().GetRandomInteger(this->privateKey.q);
245  }
246  //this loop can be optimized by precomputing the partial products
247  while (hRandQ == 1 ||
248  BigInteger::Gcd(hRandQ, this->privateKey.q) != 1 ||
249  hRandQ.GetPowModN(this->privateKey.vq * this->publicKey.u * 2, this->privateKey.q) == 1 ||
250  hRandQ.GetPowModN(qRand * this->publicKey.u * 2, this->privateKey.q) == 1 ||
251  hRandQ.GetPowModN(qRand * this->privateKey.vq * 2, this->privateKey.q) == 1 ||
252  hRandQ.GetPowModN(qRand * this->privateKey.vq * this->publicKey.u, this->privateKey.q) == 1);
253 
254  //construct hRand with the Chinese Remainder Theorem
255  BigInteger hRand = (hRandP * this->privateKey.q * this->privateKey.q.GetInverseModN(this->privateKey.p) + hRandQ * this->privateKey.p * this->privateKey.p.GetInverseModN(this->privateKey.q)) % this->publicKey.n;
256 
258  this->publicKey.h = hRand.GetPowModN(BigInteger(2) * this->publicKey.u * pRand * qRand, this->publicKey.n);
259 
260  BigInteger gRandP;
261  do {
262  //generate a random number in the interval [0, p)
263  gRandP = RandomProvider::GetInstance().GetRandomInteger(this->privateKey.p);
264 
265  }
266  //this loop can be optimized by precomputing the partial products
267  while (gRandP == 1 ||
268  BigInteger::Gcd(gRandP, this->privateKey.p) != 1 ||
269  gRandP.GetPowModN(this->privateKey.vp * this->publicKey.u * 2, this->privateKey.p) == 1 ||
270  gRandP.GetPowModN(pRand * this->publicKey.u * 2, this->privateKey.p) == 1 ||
271  gRandP.GetPowModN(pRand * this->privateKey.vp * 2, this->privateKey.p) == 1 ||
272  gRandP.GetPowModN(pRand * this->privateKey.vp * this->publicKey.u, this->privateKey.p) == 1);
273 
274  BigInteger gRandQ;
275  do {
276  //generate a random number in the interval [0, q)
277  gRandQ = RandomProvider::GetInstance().GetRandomInteger(this->privateKey.q);
278 
279  }
280  //this loop can be optimized by precomputing the partial products
281  while (gRandQ == 1 ||
282  BigInteger::Gcd(gRandQ, this->privateKey.q) != 1 ||
283  gRandQ.GetPowModN(this->privateKey.vq * this->publicKey.u * 2, this->privateKey.q) == 1 ||
284  gRandQ.GetPowModN(qRand * this->publicKey.u * 2, this->privateKey.q) == 1 ||
285  gRandQ.GetPowModN(qRand * this->privateKey.vq * 2, this->privateKey.q) == 1 ||
286  gRandQ.GetPowModN(qRand * this->privateKey.vq * this->publicKey.u, this->privateKey.q) == 1);
287 
288  //construct gRand with the Chinese Remainder Theorem
289  BigInteger gRand = (gRandP * this->privateKey.q * this->privateKey.q.GetInverseModN(this->privateKey.p) + gRandQ * this->privateKey.p * this->privateKey.p.GetInverseModN(this->privateKey.q)) % this->publicKey.n;
290 
292  this->publicKey.g = gRand.GetPowModN(pRand * qRand * 2, this->publicKey.n);
293 
294  //precompute values for optimization purposes
295  this->doPrecomputations();
296 
297  return true;
298  }
299 
309  BigInteger Dgk::DecryptInteger (const Dgk::Ciphertext &ciphertext) const {
310  if (!this->hasPrivateKey) {
311  throw std::runtime_error("This operation requires the private key.");
312  }
313 
314  if (!this->precomputeDecryptionMap) {
315  throw std::runtime_error("This operation requires the decryption map.");
316  }
317 
320 
321  BigInteger cPowVpModP = ciphertext.data.GetPowModN(this->privateKey.vp, this->privateKey.p);
322 
324  if (cPowVpModP == 1) {
325  return 0;
326  }
327 
328  BigInteger output;
329 
330  //get an iterator to the required element
331  DecryptionMap::const_iterator iterator = this->decryptionMap.find(cPowVpModP);
332 
333  //make sure the key exists
334  if (this->decryptionMap.end() != iterator) {
335  output = BigInteger(iterator->second);
336  }
337  else {
338  //@todo custom exception
339  throw std::runtime_error("Can't decrypt ciphertext.");
340  }
341 
343  if (output > this->positiveNegativeBoundary) {
344  output -= this->GetMessageSpaceUpperBound();
345  }
346 
347  return output;
348  }
349 
356  Dgk::Ciphertext Dgk::EncryptIntegerNonrandom (const BigInteger &plaintext) const {
368  Ciphertext output(this->encryptionModulus);
369 
371 
373 
374  if (!this->hasPrivateKey) {
376  if (plaintext < 0) {
377  output.data = this->publicKey.g.GetPowModN(this->GetMessageSpaceUpperBound() + plaintext, this->publicKey.n);
378  }
379  else {
380  output.data = this->publicKey.g.GetPowModN(plaintext, this->publicKey.n);
381  }
382  }
383  else {
385  if (plaintext < 0) {
386  output.data = (this->publicKey.g.GetPowModN(this->GetMessageSpaceUpperBound() + plaintext, this->privateKey.p) * this->qTimesQInvModP + this->publicKey.g.GetPowModN(this->GetMessageSpaceUpperBound() + plaintext, this->privateKey.q) * this->pTimesPInvModQ) % this->publicKey.n;
387  }
388  else {
389  output.data = (this->publicKey.g.GetPowModN(plaintext, this->privateKey.p) * this->qTimesQInvModP + this->publicKey.g.GetPowModN(plaintext, this->privateKey.q) * this->pTimesPInvModQ) % this->publicKey.n;
390  }
391  }
392 
393  return output;
394  }
395 
403  /*
404  Notes from the paper:
405 
406  A final word on performance of encryption: if we want to make sure
407  that h^r mod n is uniform in the group generated by h, we should choose
408  r somewhat longer than 2t bits, say of length 2.5t bits - since in the cor-
409  rected system, the order of h is 2t bits long. This will cause the encryption
410  to take about 25% more time compared to the original system. However, if
411  one is willing to make the additional assumption that raising h to a 2t-bit
412  exponent produces an element that is computationally indistinguishable
413  from uniform in H, then one can keep the original encryption algorithm
414  and this means that using the corrected system in the protocols from
415  [1, 2] will produce exactly the same performance as reported there.
416  */
417 
419  BigInteger random = RandomProvider::GetInstance().GetRandomInteger(2 * this->t);
420 
421  if (!this->hasPrivateKey) {
423  return Randomizer(this->publicKey.h.GetPowModN(random, this->publicKey.n));
424  }
425  else {
427  return Randomizer((this->publicKey.h.GetPowModN(random, this->privateKey.p) * this->qTimesQInvModP + this->publicKey.h.GetPowModN(random, this->privateKey.q) * this->pTimesPInvModQ) % this->publicKey.n);
428  }
429  }
430 
438  return Ciphertext((ciphertext.data * this->randomizerCache->Pop().randomizer.data) % this->GetEncryptionModulus(), this->encryptionModulus);
439  }
440 
444  const BigInteger &Dgk::GetMessageSpaceUpperBound () const {
445  return this->publicKey.u;
446  }
447 
451  size_t Dgk::GetMessageSpaceSize () const {
452  return this->publicKey.u.GetSize();
453  }
454 
463  bool Dgk::IsEncryptedZero (const Ciphertext &ciphertext) const {
464  if (!this->hasPrivateKey) {
465  throw std::runtime_error("This operation requires the private key.");
466  }
467 
468  BigInteger test = ciphertext.data.GetPowModN(this->privateKey.vp, this->privateKey.p);
469 
470  return test == 1 ? true : false;
471  }
472 
478  /* See here https://www.cryptool.org/trac/CrypTool2/browser/trunk/CrypPlugins/DGK/DGKKeyGenerator.cs for the original source of parameter validation */
479  if (this->l < 8 || this->l > 32) {
480  throw std::runtime_error("The l parameter must obey the following constraints: 8 <= l <= 32.");
481  }
482  if (this->t <= this->l) {
483  throw std::runtime_error("Parameter t must be greater than l.");
484  }
485  if (this->keyLength <= this->t) {
486  throw std::runtime_error("Parameter k must be greater than t.");
487  }
488 
489  if (this->keyLength % 2 != 0) {
490  throw std::runtime_error("The k parameter must be even.");
491  }
492  /* These need to be revised...
493  if (!((this->keyLength / 2 > (this->l + 4)) && (this->keyLength / 2 > (this->t + 1)))) {
494  throw std::runtime_error("The k parameter must obey the following constraints: k / 2 > l + 4 and k / 2 > t + 1.");
495  }
496  */
497  if (this->keyLength / 2 < this->l + this->t + 10) {
498  throw std::runtime_error("Choose parameters k, l, t such that k / 2 >= l + t + 10.");
499  }
500  }
501 
508  if (this->hasPrivateKey) {
511  if (this->precomputeDecryptionMap) {
512  for (BigInteger i = 0; i < this->publicKey.u; ++i) {
513  this->decryptionMap[this->publicKey.g.GetPowModN(this->privateKey.vp * i, this->privateKey.p)] = i;
514  }
515  }
516 
518  try {
519  this->pTimesPInvModQ = this->privateKey.p * this->privateKey.p.GetInverseModN(this->privateKey.q);
520  this->qTimesQInvModP = this->privateKey.q * this->privateKey.q.GetInverseModN(this->privateKey.p);
521  }
523  catch (std::runtime_error) {
524  //if gcd(p, q) != 1, throw an error
525  throw std::runtime_error("p and q are not coprime.");
526  }
527  }
528 
529  //set the encryption modulus, @f$ n @f$
530  this->encryptionModulus = std::make_shared<BigInteger>(this->publicKey.n);
531 
532  //precompute the limit between positive and negative values in the message space
534 
536  this->randomizerCache = std::unique_ptr<RandomizerCacheType>(new RandomizerCacheType(*this, "Core.RandomizerCache"));
537 
538  this->encryptedZero = this->EncryptInteger(BigInteger(0));
539 
540  this->encryptedOne = this->EncryptInteger(BigInteger(1));
541  }
542 
543 }//namespace Core
544 }//namespace SeComLib
DgkCiphertext Ciphertext
Provide public access to the T_Ciphertext type.
Definition of class Dgk.
DecryptionMap decryptionMap
Contains all possible values of , where , and it is required for decryption.
Definition: dgk.h:162
virtual void validateParameters()
Validate configuration parameters.
Definition: dgk.cpp:476
Dgk(const bool precomputeDecryptionMap=false)
Definition: dgk.cpp:78
RandomizerCache< RandomizerContainer< CryptoProvider< DgkPublicKey, DgkPrivateKey, DgkCiphertext, DgkRandomizer >, RandomizerCacheParameters > > RandomizerCacheType
Data type of the randomizer cache.
virtual size_t GetMessageSpaceSize() const
Returns the message space bit size.
Definition: dgk.cpp:451
RandomizerBase struct.
BigInteger qTimesQInvModP
Contains .
Definition: dgk.h:167
The public key container structure for the Dgk cryptosystem.
Definition: dgk.h:47
virtual DgkCiphertext EncryptInteger(const BigInteger &plaintext) const
Encrypt an integer and apply randomization.
virtual void doPrecomputations()
Precompute values for speedups.
Definition: dgk.cpp:507
virtual Ciphertext RandomizeCiphertext(const Ciphertext &ciphertext) const
Randomize encrypted number with a self-generated random value.
Definition: dgk.cpp:437
virtual Ciphertext EncryptIntegerNonrandom(const BigInteger &plaintext) const
Encrypt number without randomization.
Definition: dgk.cpp:356
The randomizer type for DGK.
Definition: dgk.h:92
DgkCiphertext encryptedZero
Contains [0] used as initializer for homomorphic addition accumulators. Precompute it for optimizatio...
DgkRandomizer()
Default constructor.
Definition: dgk.cpp:61
virtual const BigInteger & GetMessageSpaceUpperBound() const
Returns the message space upper bound.
Definition: dgk.cpp:444
virtual Randomizer GetRandomizer() const
Compute the random factor required for the encryption operation.
Definition: dgk.cpp:402
const unsigned int l
Parameter .
Definition: dgk.h:156
bool IsEncryptedZero(const Ciphertext &ciphertext) const
Determines if ciphertext contains an encryption of 0 or not.
Definition: dgk.cpp:463
std::unique_ptr< RandomizerCacheType > randomizerCache
Lazy loading randomizer cache.
bool precomputeDecryptionMap
If true, full decryptions are enabled and the decryption map is (pre)computed.
Definition: dgk.h:159
BigInteger data
The ciphertext data.
virtual BigInteger DecryptInteger(const Ciphertext &ciphertext) const
Definition: dgk.cpp:309
virtual bool GenerateKeys()
Generate the public and private keys.
Definition: dgk.cpp:161
CiphertextBase template class.
BigInteger positiveNegativeBoundary
Contains the delimiter between positive and negative values in the message space (usually ) ...
The private key container structure for the Dgk cryptosystem.
Definition: dgk.h:62
DgkRandomizer Randomizer
Provide public access to the T_Randomizer type.
const BigInteger & GetEncryptionModulus() const
Returns the modulus required for reducing the encryption after randomization.
BigInteger u
- The message space upper bound
Definition: dgk.h:56
Template abstract base class for homomorphic encryption primitives.
DgkCiphertext()
Default constructor.
Definition: dgk.cpp:38
DGK cipertext.
Definition: dgk.h:77
bool hasPrivateKey
Boolean flag that enables decryption if the private key is present.
const unsigned int t
Parameter .
Definition: dgk.h:153
BigInteger pTimesPInvModQ
Contains .
Definition: dgk.h:165