-fix time assertion introduce in last patch
[oweals/gnunet.git] / src / util / crypto_paillier.c
index 4ae42e21a250e058d1fd0715a117f9031b994b92..80ad25f1ffaa2c75884d93f767ef2f786e9fcc80 100644 (file)
@@ -16,7 +16,7 @@
      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
@@ -45,8 +45,8 @@ GNUNET_CRYPTO_paillier_create (struct GNUNET_CRYPTO_PaillierPublicKey *public_ke
   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;
 
@@ -63,7 +63,8 @@ GNUNET_CRYPTO_paillier_create (struct GNUNET_CRYPTO_PaillierPublicKey *public_ke
                                              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);
 
@@ -91,22 +92,51 @@ GNUNET_CRYPTO_paillier_create (struct GNUNET_CRYPTO_PaillierPublicKey *public_ke
  *
  * @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, 
+ *         or desired_ops, in case that is lower,
+ *         or -1 if less than one homomorphic operation is possible
  */
-void
+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);
+  
+  // 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);
+  }
+  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));
@@ -114,8 +144,7 @@ GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *pu
   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);
@@ -128,13 +157,16 @@ GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *pu
   // c <- r*c mod n^2
   gcry_mpi_mulm (c, r, c, n_square);
 
-  GNUNET_CRYPTO_mpi_print_unsigned (ciphertext->bits, 
-                                    sizeof(*ciphertext) - sizeof(ciphertext->remaining_ops), 
+  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;
 }
 
 
@@ -142,7 +174,7 @@ GNUNET_CRYPTO_paillier_encrypt (const struct GNUNET_CRYPTO_PaillierPublicKey *pu
  * Decrypt a paillier ciphertext with a private key.
  *
  * @param private_key Private key to use for decryption.
- * @param public_key Public key to use for decryption.
+ * @param public_key Public key to use for encryption.
  * @param ciphertext Ciphertext to decrypt.
  * @param[out] m Decryption of @a ciphertext with @private_key.
  */
@@ -150,7 +182,7 @@ void
 GNUNET_CRYPTO_paillier_decrypt (const struct GNUNET_CRYPTO_PaillierPrivateKey *private_key,
                                 const struct GNUNET_CRYPTO_PaillierPublicKey *public_key,
                                 const struct GNUNET_CRYPTO_PaillierCiphertext *ciphertext,
-                                gcry_mpi_t *m)
+                                gcry_mpi_t m)
 {
   gcry_mpi_t mu;
   gcry_mpi_t lambda;
@@ -159,13 +191,11 @@ GNUNET_CRYPTO_paillier_decrypt (const struct GNUNET_CRYPTO_PaillierPrivateKey *p
   gcry_mpi_t c;
 
   GNUNET_assert (0 != (n_square = gcry_mpi_new (0)));
-  if (NULL == *m)
-    GNUNET_assert (0 != (m = gcry_mpi_new (0)));
 
   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
@@ -190,21 +220,62 @@ GNUNET_CRYPTO_paillier_decrypt (const struct GNUNET_CRYPTO_PaillierPrivateKey *p
  * Note that this operation can only be done a finite number of times
  * before an overflow occurs.
  *
- * @param x1 Paillier cipher text.
- * @param x2 Paillier cipher text.
+ * @param public_key Public key to use for encryption.
+ * @param c1 Paillier cipher text.
+ * @param c2 Paillier cipher text.
  * @param[out] result Result of the homomorphic operation.
  * @return #GNUNET_OK if the result could be computed,
  *         #GNUNET_SYSERR if no more homomorphic operations are remaining.
  */
 int
-GNUNET_CRYPTO_paillier_hom_add (const struct GNUNET_CRYPTO_PaillierCiphertext *x1,
-                                const struct GNUNET_CRYPTO_PaillierCiphertext *x2,
-                                const struct GNUNET_CRYPTO_PaillierCiphertext *result)
+GNUNET_CRYPTO_paillier_hom_add (const struct GNUNET_CRYPTO_PaillierPublicKey *public_key,
+                                const struct GNUNET_CRYPTO_PaillierCiphertext *c1,
+                                const struct GNUNET_CRYPTO_PaillierCiphertext *c2,
+                                struct GNUNET_CRYPTO_PaillierCiphertext *result)
 {
-  // not implemented yet
-  GNUNET_assert (0);
-  return GNUNET_SYSERR;
+  gcry_mpi_t a;
+  gcry_mpi_t b;
+  gcry_mpi_t c;
+  gcry_mpi_t n_square;
+  int32_t o1;
+  int32_t o2;
+
+  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,
+                                    c);
+  gcry_mpi_release (a);
+  gcry_mpi_release (b);
+  gcry_mpi_release (c);
+  gcry_mpi_release (n_square);
+  return ntohl (result->remaining_ops);
 }
 
 
+/**
+ * Get the number of remaining supported homomorphic operations. 
+ *
+ * @param c Paillier cipher text.
+ * @return the number of remaining homomorphic operations
+ */
+int
+GNUNET_CRYPTO_paillier_hom_get_remaining (const struct GNUNET_CRYPTO_PaillierCiphertext *c)
+{
+  GNUNET_assert (NULL != c);
+  return ntohl (c->remaining_ops);
+}
+
 /* end of crypto_paillier.c */