diff options
author | Christian Grothoff <christian@grothoff.org> | 2014-12-09 20:57:07 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2014-12-09 20:57:07 +0000 |
commit | e613b7acfde2427b5ea48f2ac866489f2d9b6589 (patch) | |
tree | d00d04e4a8a10473505156ffea7f38a591413084 /src/util/crypto_paillier.c | |
parent | 82bedb216e21147473795fb43be9cfd48414e7ca (diff) | |
download | gnunet-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.c | 275 |
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 | */ |
103 | int | 115 | int |
104 | GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *public_key, | 116 | GNUNET_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 | */ | ||
209 | int | ||
210 | GNUNET_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 | |||