along with GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
-*/
+ */
/**
* @file util/crypto_paillier.c
gcry_mpi_t phi;
gcry_mpi_t n;
- GNUNET_assert (NULL != (phi = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS)));
- GNUNET_assert (NULL != (n = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS)));
+ GNUNET_assert (NULL != (phi = gcry_mpi_new (0)));
+ GNUNET_assert (NULL != (n = gcry_mpi_new (0)));
p = q = NULL;
GCRY_WEAK_RANDOM, 0));
GNUNET_assert (0 == gcry_prime_generate (&q, GNUNET_CRYPTO_PAILLIER_BITS / 2, 0, NULL, NULL, NULL,
GCRY_WEAK_RANDOM, 0));
- } while (0 == gcry_mpi_cmp (p, q));
+ }
+ while (0 == gcry_mpi_cmp (p, q));
gcry_mpi_mul (n, p, q);
GNUNET_CRYPTO_mpi_print_unsigned (public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey), n);
*
* @param public_key Public key to use.
* @param m Plaintext to encrypt.
+ * @param desired_ops How many homomorphic ops the caller intends to use
* @param[out] ciphertext Encrytion of @a plaintext with @a public_key.
- * @return guaranteed number of supported homomorphic operations >= 1, -1 for failure
+ * @return guaranteed number of supported homomorphic operations >= 1,
+ * or desired_ops, in case that is lower,
+ * or -1 if less than one homomorphic operation is possible
*/
int
GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *public_key,
const gcry_mpi_t m,
+ int desired_ops,
struct GNUNET_CRYPTO_PaillierCiphertext *ciphertext)
{
int possible_opts;
gcry_mpi_t n_square;
gcry_mpi_t r;
- gcry_mpi_t g;
gcry_mpi_t c;
gcry_mpi_t n;
gcry_mpi_t tmp1;
gcry_mpi_t tmp2;
-
+
// determine how many operations we could allow, if the other number
// has the same length.
- GNUNET_assert (NULL != (tmp1 = gcry_mpi_set_ui(NULL, 1)));
- GNUNET_assert (NULL != (tmp2 = gcry_mpi_set_ui(NULL, 2)));
- gcry_mpi_mul_2exp(tmp1,tmp1,GNUNET_CRYPTO_PAILLIER_BITS);
- for (possible_opts = 0; gcry_mpi_cmp(tmp1,m) > 0; possible_opts++){
- gcry_mpi_div(tmp1, NULL, tmp1, tmp2 ,0);
- }
- gcry_mpi_release(tmp1);
- gcry_mpi_release(tmp2);
- if (0 >= possible_opts)
- {
- return -1;
+ GNUNET_assert (NULL != (tmp1 = gcry_mpi_set_ui (NULL, 1)));
+ GNUNET_assert (NULL != (tmp2 = gcry_mpi_set_ui (NULL, 2)));
+ gcry_mpi_mul_2exp (tmp1, tmp1, GNUNET_CRYPTO_PAILLIER_BITS);
+
+ // count number of possible operations
+ // this would be nicer with gcry_mpi_get_nbits, however it does not return
+ // the BITLENGTH of the given MPI's value, but the bits required
+ // to represent the number as MPI.
+ for (possible_opts = -2; gcry_mpi_cmp (tmp1, m) > 0; possible_opts++) {
+ gcry_mpi_div (tmp1, NULL, tmp1, tmp2, 0);
}
- else
- // reduce by one to guarantee the final homomorphic operation
- ciphertext->remaining_ops = htonl(possible_opts);
+ gcry_mpi_release (tmp1);
+ gcry_mpi_release (tmp2);
+
+ if (possible_opts < 1)
+ possible_opts = 0;
+ //soft-cap by caller
+ possible_opts = (desired_ops < possible_opts)? desired_ops : possible_opts;
+ ciphertext->remaining_ops = htonl (possible_opts);
+
GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
GNUNET_assert (0 != (r = gcry_mpi_new (0)));
- GNUNET_assert (0 != (g = gcry_mpi_new (0)));
GNUNET_assert (0 != (c = gcry_mpi_new (0)));
GNUNET_CRYPTO_mpi_scan_unsigned (&n, public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
gcry_mpi_mul (n_square, n, n);
// generate r < n
- do
- {
+ do {
gcry_mpi_randomize (r, GNUNET_CRYPTO_PAILLIER_BITS, GCRY_WEAK_RANDOM);
}
while (gcry_mpi_cmp (r, n) >= 0);
// c <- r*c mod n^2
gcry_mpi_mulm (c, r, c, n_square);
- GNUNET_CRYPTO_mpi_print_unsigned (ciphertext->bits,
- sizeof ciphertext->bits,
+ GNUNET_CRYPTO_mpi_print_unsigned (ciphertext->bits,
+ sizeof ciphertext->bits,
c);
gcry_mpi_release (n_square);
+ gcry_mpi_release (n);
gcry_mpi_release (r);
gcry_mpi_release (c);
-
+
return possible_opts;
}
GNUNET_CRYPTO_mpi_scan_unsigned (&lambda, private_key->lambda, sizeof private_key->lambda);
GNUNET_CRYPTO_mpi_scan_unsigned (&mu, private_key->mu, sizeof private_key->mu);
GNUNET_CRYPTO_mpi_scan_unsigned (&n, public_key, sizeof *public_key);
- GNUNET_CRYPTO_mpi_scan_unsigned (&c, ciphertext, sizeof *ciphertext);
+ GNUNET_CRYPTO_mpi_scan_unsigned (&c, ciphertext->bits, sizeof ciphertext->bits);
gcry_mpi_mul (n_square, n, n);
// m = c^lambda mod n^2
gcry_mpi_t n_square;
int32_t o1;
int32_t o2;
-
- o1 = ntohl(c1->remaining_ops);
- o2 = ntohl(c2->remaining_ops);
+
+ o1 = ntohl (c1->remaining_ops);
+ o2 = ntohl (c2->remaining_ops);
if (0 >= o1 || 0 >= o2)
return GNUNET_SYSERR;
-
+
GNUNET_assert (0 != (c = gcry_mpi_new (0)));
-
+
GNUNET_CRYPTO_mpi_scan_unsigned (&a, c1->bits, sizeof c1->bits);
GNUNET_CRYPTO_mpi_scan_unsigned (&b, c1->bits, sizeof c2->bits);
GNUNET_CRYPTO_mpi_scan_unsigned (&n_square, public_key, sizeof *public_key);
- gcry_mpi_mul(n_square, n_square,n_square);
- gcry_mpi_mulm(c,a,b,n_square);
-
- result->remaining_ops = htonl(((o2 > o1) ? o1 : o2) - 1);
- GNUNET_CRYPTO_mpi_print_unsigned (result->bits,
- sizeof result->bits,
+ gcry_mpi_mul (n_square, n_square, n_square);
+ gcry_mpi_mulm (c, a, b, n_square);
+
+ result->remaining_ops = htonl (((o2 > o1) ? o1 : o2) - 1);
+ GNUNET_CRYPTO_mpi_print_unsigned (result->bits,
+ sizeof result->bits,
c);
gcry_mpi_release (a);
gcry_mpi_release (b);
gcry_mpi_release (c);
gcry_mpi_release (n_square);
- return ntohl(result->remaining_ops);
+ return ntohl (result->remaining_ops);
}
int
GNUNET_CRYPTO_paillier_hom_get_remaining (const struct GNUNET_CRYPTO_PaillierCiphertext *c)
{
- GNUNET_assert(NULL != c);
- return ntohl(c->remaining_ops);
+ GNUNET_assert (NULL != c);
+ return ntohl (c->remaining_ops);
}
/* end of crypto_paillier.c */