aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_paillier.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2014-12-09 20:57:07 +0000
committerChristian Grothoff <christian@grothoff.org>2014-12-09 20:57:07 +0000
commite613b7acfde2427b5ea48f2ac866489f2d9b6589 (patch)
treed00d04e4a8a10473505156ffea7f38a591413084 /src/util/crypto_paillier.c
parent82bedb216e21147473795fb43be9cfd48414e7ca (diff)
downloadgnunet-e613b7acfde2427b5ea48f2ac866489f2d9b6589.tar.gz
gnunet-e613b7acfde2427b5ea48f2ac866489f2d9b6589.zip
-fixing paillier bug, improving testcase
Diffstat (limited to 'src/util/crypto_paillier.c')
-rw-r--r--src/util/crypto_paillier.c275
1 files changed, 219 insertions, 56 deletions
diff --git a/src/util/crypto_paillier.c b/src/util/crypto_paillier.c
index c16706dcb..1104aee62 100644
--- a/src/util/crypto_paillier.c
+++ b/src/util/crypto_paillier.c
@@ -41,51 +41,63 @@ GNUNET_CRYPTO_paillier_create (struct GNUNET_CRYPTO_PaillierPublicKey *public_ke
41{ 41{
42 gcry_mpi_t p; 42 gcry_mpi_t p;
43 gcry_mpi_t q; 43 gcry_mpi_t q;
44
45 gcry_mpi_t phi; 44 gcry_mpi_t phi;
45 gcry_mpi_t mu;
46 gcry_mpi_t n; 46 gcry_mpi_t n;
47 47
48 GNUNET_assert (NULL != (phi = gcry_mpi_new (0))); 48 /* Generate two distinct primes. The probability that the loop body
49 GNUNET_assert (NULL != (n = gcry_mpi_new (0))); 49 is executed more than once is very very low... */
50 50 p = NULL;
51 p = q = NULL; 51 q = NULL;
52
53 // Generate two distinct primes.
54 // The probability that the loop body
55 // is executed more than once is very low.
56 do { 52 do {
57 if (NULL != p) 53 if (NULL != p)
58 gcry_mpi_release (p); 54 gcry_mpi_release (p);
59 if (NULL != q) 55 if (NULL != q)
60 gcry_mpi_release (q); 56 gcry_mpi_release (q);
61 // generate rsa modulus 57 GNUNET_assert (0 ==
62 GNUNET_assert (0 == gcry_prime_generate (&p, GNUNET_CRYPTO_PAILLIER_BITS / 2, 0, NULL, NULL, NULL, 58 gcry_prime_generate (&p,
63 GCRY_STRONG_RANDOM, 0)); 59 GNUNET_CRYPTO_PAILLIER_BITS / 2,
64 GNUNET_assert (0 == gcry_prime_generate (&q, GNUNET_CRYPTO_PAILLIER_BITS / 2, 0, NULL, NULL, NULL, 60 0, NULL, NULL, NULL,
65 GCRY_STRONG_RANDOM, 0)); 61 GCRY_STRONG_RANDOM, 0));
62 GNUNET_assert (0 ==
63 gcry_prime_generate (&q,
64 GNUNET_CRYPTO_PAILLIER_BITS / 2,
65 0, NULL, NULL, NULL,
66 GCRY_STRONG_RANDOM, 0));
66 } 67 }
67 while (0 == gcry_mpi_cmp (p, q)); 68 while (0 == gcry_mpi_cmp (p, q));
68 gcry_mpi_mul (n, p, q); 69 /* n = p * q */
70 GNUNET_assert (NULL != (n = gcry_mpi_new (0)));
71 gcry_mpi_mul (n,
72 p,
73 q);
69 GNUNET_CRYPTO_mpi_print_unsigned (public_key, 74 GNUNET_CRYPTO_mpi_print_unsigned (public_key,
70 sizeof (struct GNUNET_CRYPTO_PaillierPublicKey), 75 sizeof (struct GNUNET_CRYPTO_PaillierPublicKey),
71 n); 76 n);
72 77
73 // compute phi(n) = (p-1)(q-1) 78 /* compute phi(n) = (p-1)(q-1) */
79 GNUNET_assert (NULL != (phi = gcry_mpi_new (0)));
74 gcry_mpi_sub_ui (p, p, 1); 80 gcry_mpi_sub_ui (p, p, 1);
75 gcry_mpi_sub_ui (q, q, 1); 81 gcry_mpi_sub_ui (q, q, 1);
76 gcry_mpi_mul (phi, p, q); 82 gcry_mpi_mul (phi, p, q);
77
78 // lambda equals phi(n) in the simplified key generation
79 GNUNET_CRYPTO_mpi_print_unsigned (private_key->lambda, GNUNET_CRYPTO_PAILLIER_BITS / 8, phi);
80
81 // invert phi and abuse the phi mpi to store the result ...
82 GNUNET_assert (0 != gcry_mpi_invm (phi, phi, n));
83 GNUNET_CRYPTO_mpi_print_unsigned (private_key->mu, GNUNET_CRYPTO_PAILLIER_BITS / 8, phi);
84
85 gcry_mpi_release (p); 83 gcry_mpi_release (p);
86 gcry_mpi_release (q); 84 gcry_mpi_release (q);
85
86 /* lambda equals phi(n) in the simplified key generation */
87 GNUNET_CRYPTO_mpi_print_unsigned (private_key->lambda,
88 GNUNET_CRYPTO_PAILLIER_BITS / 8,
89 phi);
90 /* mu = phi^{-1} mod n, as we use g = n + 1 */
91 GNUNET_assert (NULL != (mu = gcry_mpi_new (0)));
92 GNUNET_assert (0 != gcry_mpi_invm (mu,
93 phi,
94 n));
87 gcry_mpi_release (phi); 95 gcry_mpi_release (phi);
88 gcry_mpi_release (n); 96 gcry_mpi_release (n);
97 GNUNET_CRYPTO_mpi_print_unsigned (private_key->mu,
98 GNUNET_CRYPTO_PAILLIER_BITS / 8,
99 mu);
100 gcry_mpi_release (mu);
89} 101}
90 102
91 103
@@ -101,7 +113,7 @@ GNUNET_CRYPTO_paillier_create (struct GNUNET_CRYPTO_PaillierPublicKey *public_ke
101 * or -1 if less than one homomorphic operation is possible 113 * or -1 if less than one homomorphic operation is possible
102 */ 114 */
103int 115int
104GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *public_key, 116GNUNET_CRYPTO_paillier_encrypt1 (const struct GNUNET_CRYPTO_PaillierPublicKey *public_key,
105 const gcry_mpi_t m, 117 const gcry_mpi_t m,
106 int desired_ops, 118 int desired_ops,
107 struct GNUNET_CRYPTO_PaillierCiphertext *ciphertext) 119 struct GNUNET_CRYPTO_PaillierCiphertext *ciphertext)
@@ -163,12 +175,12 @@ GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *pu
163 while (gcry_mpi_cmp (r, n) >= 0); 175 while (gcry_mpi_cmp (r, n) >= 0);
164 176
165 // c = (n+1)^m mod n^2 177 // c = (n+1)^m mod n^2
166 gcry_mpi_add_ui (c, n, 1); 178 gcry_mpi_add_ui (c, n, 1); // c = n + 1
167 gcry_mpi_powm (c, c, m, n_square); 179 gcry_mpi_powm (c, c, m, n_square); // c = (n+1)^m mod n^2
168 // r <- r^n mod n^2 180 // r <- r^n mod n^2
169 gcry_mpi_powm (r, r, n, n_square); 181 gcry_mpi_powm (r, r, n, n_square); // r = r^n mod n^2
170 // c <- r*c mod n^2 182 // c <- r*c mod n^2
171 gcry_mpi_mulm (c, r, c, n_square); 183 gcry_mpi_mulm (c, r, c, n_square); // c = r*c mod n^2
172 184
173 GNUNET_CRYPTO_mpi_print_unsigned (ciphertext->bits, 185 GNUNET_CRYPTO_mpi_print_unsigned (ciphertext->bits,
174 sizeof ciphertext->bits, 186 sizeof ciphertext->bits,
@@ -184,6 +196,121 @@ GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *pu
184 196
185 197
186/** 198/**
199 * Encrypt a plaintext with a paillier public key.
200 *
201 * @param public_key Public key to use.
202 * @param m Plaintext to encrypt.
203 * @param desired_ops How many homomorphic ops the caller intends to use
204 * @param[out] ciphertext Encrytion of @a plaintext with @a public_key.
205 * @return guaranteed number of supported homomorphic operations >= 1,
206 * or desired_ops, in case that is lower,
207 * or -1 if less than one homomorphic operation is possible
208 */
209int
210GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *public_key,
211 const gcry_mpi_t m,
212 int desired_ops,
213 struct GNUNET_CRYPTO_PaillierCiphertext *ciphertext)
214{
215 int possible_opts;
216 gcry_mpi_t n_square;
217 gcry_mpi_t r;
218 gcry_mpi_t rn;
219 gcry_mpi_t g;
220 gcry_mpi_t gm;
221 gcry_mpi_t c;
222 gcry_mpi_t n;
223 gcry_mpi_t max_num;
224 unsigned int highbit;
225
226 /* set max_num = 2^{GNUNET_CRYPTO_PAILLIER_BITS}, the largest
227 number we can have as a result */
228 GNUNET_assert (NULL != (max_num = gcry_mpi_set_ui (NULL, 1)));
229 gcry_mpi_mul_2exp (max_num,
230 max_num,
231 GNUNET_CRYPTO_PAILLIER_BITS);
232
233 /* Determine how many operations we could allow, assuming the other
234 number has the same length (or is smaller), by counting the
235 number of possible operations. We essentially divide max_num by
236 2 until the result is no longer larger than 'm', incrementing the
237 maximum number of operations in each round, starting at -2 */
238 for (possible_opts = -2; gcry_mpi_cmp (max_num, m) > 0; possible_opts++)
239 gcry_mpi_div (max_num,
240 NULL,
241 max_num,
242 GCRYMPI_CONST_TWO,
243 0);
244 gcry_mpi_release (max_num);
245
246 if (possible_opts < 1)
247 possible_opts = 0;
248 /* Enforce soft-cap by caller */
249 possible_opts = GNUNET_MIN (desired_ops, possible_opts);
250 ciphertext->remaining_ops = htonl (possible_opts);
251
252 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
253 public_key,
254 sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
255
256 /* check public key for number of bits, bail out if key is all zeros */
257 highbit = GNUNET_CRYPTO_PAILLIER_BITS - 1;
258 while ( (! gcry_mpi_test_bit (n, highbit)) &&
259 (0 != highbit) )
260 highbit--;
261 if (0 == highbit)
262 {
263 /* invalid public key */
264 GNUNET_break_op (0);
265 gcry_mpi_release (n);
266 return GNUNET_SYSERR;
267 }
268
269 /* generate r < n (without bias) */
270 GNUNET_assert (0 != (r = gcry_mpi_new (0)));
271 do {
272 gcry_mpi_randomize (r, highbit + 1, GCRY_STRONG_RANDOM);
273 }
274 while (gcry_mpi_cmp (r, n) >= 0);
275
276 /* g = n + 1 */
277 GNUNET_assert (0 != (g = gcry_mpi_new (0)));
278 gcry_mpi_add_ui (g, n, 1);
279
280 /* n_square = n^2 */
281 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
282 gcry_mpi_mul (n_square,
283 n,
284 n);
285
286 /* gm = g^m mod n^2 */
287 GNUNET_assert (0 != (gm = gcry_mpi_new (0)));
288 gcry_mpi_powm (gm, g, m, n_square);
289 gcry_mpi_release (g);
290
291 /* rn <- r^n mod n^2 */
292 GNUNET_assert (0 != (rn = gcry_mpi_new (0)));
293 gcry_mpi_powm (rn, r, n, n_square);
294 gcry_mpi_release (r);
295 gcry_mpi_release (n);
296
297 /* c <- rn * gm mod n^2 */
298 GNUNET_assert (0 != (c = gcry_mpi_new (0)));
299 gcry_mpi_mulm (c, rn, gm, n_square);
300 gcry_mpi_release (n_square);
301 gcry_mpi_release (gm);
302 gcry_mpi_release (rn);
303
304 GNUNET_CRYPTO_mpi_print_unsigned (ciphertext->bits,
305 sizeof (ciphertext->bits),
306 c);
307 gcry_mpi_release (c);
308
309 return possible_opts;
310}
311
312
313/**
187 * Decrypt a paillier ciphertext with a private key. 314 * Decrypt a paillier ciphertext with a private key.
188 * 315 *
189 * @param private_key Private key to use for decryption. 316 * @param private_key Private key to use for decryption.
@@ -202,33 +329,56 @@ GNUNET_CRYPTO_paillier_decrypt (const struct GNUNET_CRYPTO_PaillierPrivateKey *p
202 gcry_mpi_t n; 329 gcry_mpi_t n;
203 gcry_mpi_t n_square; 330 gcry_mpi_t n_square;
204 gcry_mpi_t c; 331 gcry_mpi_t c;
332 gcry_mpi_t cmu;
333 gcry_mpi_t cmum1;
334 gcry_mpi_t mod;
335
336 GNUNET_CRYPTO_mpi_scan_unsigned (&lambda,
337 private_key->lambda,
338 sizeof (private_key->lambda));
339 GNUNET_CRYPTO_mpi_scan_unsigned (&mu,
340 private_key->mu,
341 sizeof (private_key->mu));
342 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
343 public_key,
344 sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
345 GNUNET_CRYPTO_mpi_scan_unsigned (&c,
346 ciphertext->bits,
347 sizeof (ciphertext->bits));
205 348
349 /* n_square = n * n */
206 GNUNET_assert (0 != (n_square = gcry_mpi_new (0))); 350 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
351 gcry_mpi_mul (n_square, n, n);
207 352
208 GNUNET_CRYPTO_mpi_scan_unsigned (&lambda, private_key->lambda, sizeof private_key->lambda); 353 /* cmu = c^lambda mod n^2 */
209 GNUNET_CRYPTO_mpi_scan_unsigned (&mu, private_key->mu, sizeof private_key->mu); 354 GNUNET_assert (0 != (cmu = gcry_mpi_new (0)));
210 GNUNET_CRYPTO_mpi_scan_unsigned (&n, public_key, sizeof *public_key); 355 gcry_mpi_powm (cmu,
211 GNUNET_CRYPTO_mpi_scan_unsigned (&c, ciphertext->bits, sizeof ciphertext->bits); 356 c,
357 lambda,
358 n_square);
359 gcry_mpi_release (n_square);
360 gcry_mpi_release (lambda);
361 gcry_mpi_release (c);
212 362
213 gcry_mpi_mul (n_square, n, n); 363 /* cmum1 = cmu - 1 */
214 // m = c^lambda mod n^2 364 GNUNET_assert (0 != (cmum1 = gcry_mpi_new (0)));
215 gcry_mpi_powm (m, c, lambda, n_square); 365 gcry_mpi_sub_ui (cmum1, cmu, 1);
216 // m = m - 1 366 gcry_mpi_release (cmu);
217 gcry_mpi_sub_ui (m, m, 1); 367
218 // m <- m/n 368 /* mod = cmum1 / n (mod n) */
219 gcry_mpi_div (m, NULL, m, n, 0); 369 GNUNET_assert (0 != (mod = gcry_mpi_new (0)));
220 gcry_mpi_mulm (m, m, mu, n); 370 gcry_mpi_div (mod, NULL, cmum1, n, 0);
221 371
372 /* m = mod * mu mod n */
373 gcry_mpi_mulm (m, mod, mu, n);
222 gcry_mpi_release (mu); 374 gcry_mpi_release (mu);
223 gcry_mpi_release (lambda);
224 gcry_mpi_release (n); 375 gcry_mpi_release (n);
225 gcry_mpi_release (n_square);
226 gcry_mpi_release (c);
227} 376}
228 377
229 378
230/** 379/**
231 * Compute a ciphertext that represents the sum of the plaintext in @a x1 and @a x2 380 * Compute a ciphertext that represents the sum of the plaintext in @a
381 * c1 and @a c2.
232 * 382 *
233 * Note that this operation can only be done a finite number of times 383 * Note that this operation can only be done a finite number of times
234 * before an overflow occurs. 384 * before an overflow occurs.
@@ -249,31 +399,43 @@ GNUNET_CRYPTO_paillier_hom_add (const struct GNUNET_CRYPTO_PaillierPublicKey *pu
249 gcry_mpi_t a; 399 gcry_mpi_t a;
250 gcry_mpi_t b; 400 gcry_mpi_t b;
251 gcry_mpi_t c; 401 gcry_mpi_t c;
402 gcry_mpi_t n;
252 gcry_mpi_t n_square; 403 gcry_mpi_t n_square;
253 int32_t o1; 404 int32_t o1;
254 int32_t o2; 405 int32_t o2;
255 406
256 o1 = ntohl (c1->remaining_ops); 407 o1 = ntohl (c1->remaining_ops);
257 o2 = ntohl (c2->remaining_ops); 408 o2 = ntohl (c2->remaining_ops);
258 if (0 >= o1 || 0 >= o2) 409 if ( (0 >= o1) || (0 >= o2) )
259 return GNUNET_SYSERR; 410 return GNUNET_SYSERR;
260 411
261 GNUNET_assert (0 != (c = gcry_mpi_new (0))); 412 GNUNET_CRYPTO_mpi_scan_unsigned (&a,
413 c1->bits,
414 sizeof (c1->bits));
415 GNUNET_CRYPTO_mpi_scan_unsigned (&b,
416 c2->bits,
417 sizeof (c2->bits));
418 GNUNET_CRYPTO_mpi_scan_unsigned (&n,
419 public_key,
420 sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
262 421
263 GNUNET_CRYPTO_mpi_scan_unsigned (&a, c1->bits, sizeof c1->bits); 422 /* n_square = n * n */
264 GNUNET_CRYPTO_mpi_scan_unsigned (&b, c1->bits, sizeof c2->bits); 423 GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
265 GNUNET_CRYPTO_mpi_scan_unsigned (&n_square, public_key, sizeof *public_key); 424 gcry_mpi_mul (n_square, n, n);
266 gcry_mpi_mul (n_square, n_square, n_square); 425 gcry_mpi_release (n);
426
427 /* c = a * b mod n_square */
428 GNUNET_assert (0 != (c = gcry_mpi_new (0)));
267 gcry_mpi_mulm (c, a, b, n_square); 429 gcry_mpi_mulm (c, a, b, n_square);
430 gcry_mpi_release (n_square);
431 gcry_mpi_release (a);
432 gcry_mpi_release (b);
268 433
269 result->remaining_ops = htonl (((o2 > o1) ? o1 : o2) - 1); 434 result->remaining_ops = htonl (GNUNET_MIN (o1, o2) - 1);
270 GNUNET_CRYPTO_mpi_print_unsigned (result->bits, 435 GNUNET_CRYPTO_mpi_print_unsigned (result->bits,
271 sizeof result->bits, 436 sizeof (result->bits),
272 c); 437 c);
273 gcry_mpi_release (a);
274 gcry_mpi_release (b);
275 gcry_mpi_release (c); 438 gcry_mpi_release (c);
276 gcry_mpi_release (n_square);
277 return ntohl (result->remaining_ops); 439 return ntohl (result->remaining_ops);
278} 440}
279 441
@@ -292,3 +454,4 @@ GNUNET_CRYPTO_paillier_hom_get_remaining (const struct GNUNET_CRYPTO_PaillierCip
292} 454}
293 455
294/* end of crypto_paillier.c */ 456/* end of crypto_paillier.c */
457