convert fs publish to MQ
[oweals/gnunet.git] / src / secretsharing / secretsharing_api.c
index 1489a5c457c19486f54c56764eb856ae3a84e2b3..8c60d76ed531e234c92f070787f23402f2bd02a1 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2012 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2012, 2016 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      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.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
  */
 struct GNUNET_SECRETSHARING_Session
 {
-  /**
-   * Client connected to the secretsharing service.
-   */
-  struct GNUNET_CLIENT_Connection *client;
 
   /**
-   * Message queue for 'client'.
+   * Message queue for @e client.
    */
   struct GNUNET_MQ_Handle *mq;
 
@@ -54,21 +50,20 @@ struct GNUNET_SECRETSHARING_Session
   GNUNET_SECRETSHARING_SecretReadyCallback secret_ready_cb;
 
   /**
-   * Closure for 'secret_ready_cb'.
+   * Closure for @e secret_ready_cb.
    */
   void *secret_ready_cls;
 };
 
 
+/**
+ * Handle to cancel a cooperative decryption operation.
+ */
 struct GNUNET_SECRETSHARING_DecryptionHandle
 {
-  /**
-   * Client connected to the secretsharing service.
-   */
-  struct GNUNET_CLIENT_Connection *client;
 
   /**
-   * Message queue for 'client'.
+   * Message queue for @e client.
    */
   struct GNUNET_MQ_Handle *mq;
 
@@ -78,7 +73,7 @@ struct GNUNET_SECRETSHARING_DecryptionHandle
   GNUNET_SECRETSHARING_DecryptCallback decrypt_cb;
 
   /**
-   * Closure for 'decrypt_cb'.
+   * Closure for @e decrypt_cb.
    */
   void *decrypt_cls;
 };
@@ -103,6 +98,9 @@ static gcry_mpi_t elgamal_p;
 static gcry_mpi_t elgamal_g;
 
 
+/**
+ * Function to initialize #elgamal_q, #elgamal_p and #elgamal_g.
+ */
 static void
 ensure_elgamal_initialized (void)
 {
@@ -118,86 +116,165 @@ ensure_elgamal_initialized (void)
 }
 
 
+/**
+ * Callback invoked when there is an error communicating with
+ * the service.  Notifies the application about the error.
+ *
+ * @param cls the `struct GNUNET_SECRETSHARING_Session`
+ * @param error error code
+ */
 static void
-handle_session_client_error (void *cls, enum GNUNET_MQ_Error error)
+handle_session_client_error (void *cls,
+                             enum GNUNET_MQ_Error error)
 {
   struct GNUNET_SECRETSHARING_Session *s = cls;
 
   s->secret_ready_cb (s->secret_ready_cls, NULL, NULL, 0, NULL);
+  GNUNET_SECRETSHARING_session_destroy (s);
 }
 
 
+/**
+ * Callback invoked when there is an error communicating with
+ * the service.  Notifies the application about the error.
+ *
+ * @param cls the `struct GNUNET_SECRETSHARING_DecryptionHandle`
+ * @param error error code
+ */
 static void
-handle_decrypt_client_error (void *cls, enum GNUNET_MQ_Error error)
+handle_decrypt_client_error (void *cls,
+                             enum GNUNET_MQ_Error error)
 {
   struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
-  
+
   dh->decrypt_cb (dh->decrypt_cls, NULL);
+  GNUNET_SECRETSHARING_decrypt_cancel (dh);
 }
 
 
+/**
+ * Handler invoked with the final result message from
+ * secret sharing.  Decodes the message and passes the
+ * result to the application.
+ *
+ * @param cls the `struct GNUNET_SECRETSHARING_Session`
+ * @param m message with the result
+ */
+static int
+check_secret_ready (void *cls,
+                    const struct GNUNET_SECRETSHARING_SecretReadyMessage *m)
+{
+  /* FIXME: actually check m is well-formed here! */
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handler invoked with the final result message from
+ * secret sharing.  Decodes the message and passes the
+ * result to the application.
+ *
+ * @param cls the `struct GNUNET_SECRETSHARING_Session`
+ * @param m message with the result
+ */
 static void
-handle_secret_ready (void *cls, const struct GNUNET_MessageHeader *msg)
+handle_secret_ready (void *cls,
+                     const struct GNUNET_SECRETSHARING_SecretReadyMessage *m)
 {
-  struct GNUNET_SECRETSHARING_Session *session = cls;
+  struct GNUNET_SECRETSHARING_Session *s = cls;
   struct GNUNET_SECRETSHARING_Share *share;
-  const struct GNUNET_SECRETSHARING_SecretReadyMessage *m = (const void *) msg;
   size_t share_size;
 
-  share_size = ntohs (m->header.size) - sizeof *m;
-
-  share = GNUNET_SECRETSHARING_share_read (&m[1], share_size, NULL);
-
-  session->secret_ready_cb (session->secret_ready_cls,
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got secret ready message of size %u\n",
+       ntohs (m->header.size));
+  share_size = ntohs (m->header.size) - sizeof (struct GNUNET_SECRETSHARING_SecretReadyMessage);
+
+  share = GNUNET_SECRETSHARING_share_read (&m[1],
+                                           share_size,
+                                           NULL);
+  GNUNET_assert (NULL != share); // FIXME: this can fail!
+  // should have been checked in #check_secret_ready!
+  // FIXME: below we never check &m[1] is valid!
+  // FIXME: do we leak 'share' here?
+  s->secret_ready_cb (s->secret_ready_cls,
                       share, /* FIXME */
                       &share->public_key,
                       share->num_peers,
-                      (struct GNUNET_PeerIdentity *) &m[1]);
+                      (const struct GNUNET_PeerIdentity *) &m[1]);
 
-  GNUNET_SECRETSHARING_session_destroy (session);
+  GNUNET_SECRETSHARING_session_destroy (s);
 }
 
 
+/**
+ * Destroy a secret sharing session.
+ * The secret ready callback will not be called.
+ *
+ * @param s session to destroy
+ */
 void
-GNUNET_SECRETSHARING_session_destroy (struct GNUNET_SECRETSHARING_Session *session)
+GNUNET_SECRETSHARING_session_destroy (struct GNUNET_SECRETSHARING_Session *s)
 {
-  GNUNET_MQ_destroy (session->mq);
-  session->mq = NULL;
-  GNUNET_CLIENT_disconnect (session->client);
-  session->client = NULL;
-  GNUNET_free (session);
+  GNUNET_MQ_destroy (s->mq);
+  s->mq = NULL;
+  GNUNET_free (s);
 }
 
 
+/**
+ * Create a session that will eventually establish a shared secret
+ * with the other peers.
+ *
+ * @param cfg configuration to use
+ * @param num_peers number of peers in @a peers
+ * @param peers array of peers that we will share secrets with, can optionally contain the local peer
+ * @param session_id unique session id
+ * @param start When should all peers be available for sharing the secret?
+ *              Random number generation can take place before the start time.
+ * @param deadline point in time where the session must be established; taken as hint
+ *                 by underlying consensus sessions
+ * @param threshold minimum number of peers that must cooperate to decrypt a value
+ * @param cb called when the secret has been established
+ * @param cls closure for @a cb
+ */
 struct GNUNET_SECRETSHARING_Session *
 GNUNET_SECRETSHARING_create_session (const struct GNUNET_CONFIGURATION_Handle *cfg,
                                      unsigned int num_peers,
                                      const struct GNUNET_PeerIdentity *peers,
                                      const struct GNUNET_HashCode *session_id,
+                                     struct GNUNET_TIME_Absolute start,
                                      struct GNUNET_TIME_Absolute deadline,
                                      unsigned int threshold,
                                      GNUNET_SECRETSHARING_SecretReadyCallback cb,
                                      void *cls)
 {
-  struct GNUNET_SECRETSHARING_Session *s;
+  GNUNET_MQ_hd_var_size (secret_ready,
+                         GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY,
+                         struct GNUNET_SECRETSHARING_SecretReadyMessage);
+  struct GNUNET_SECRETSHARING_Session *s
+    = GNUNET_new (struct GNUNET_SECRETSHARING_Session);
+  struct GNUNET_MQ_MessageHandler mq_handlers[] = {
+    make_secret_ready_handler (s),
+    GNUNET_MQ_handler_end ()
+  };
   struct GNUNET_MQ_Envelope *ev;
   struct GNUNET_SECRETSHARING_CreateMessage *msg;
-  static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
-    {handle_secret_ready, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY, 0},
-    GNUNET_MQ_HANDLERS_END
-  };
-
 
-  s = GNUNET_new (struct GNUNET_SECRETSHARING_Session);
-  s->client = GNUNET_CLIENT_connect ("secretsharing", cfg);
+  s->mq = GNUNET_CLIENT_connecT (cfg,
+                                 "secretsharing",
+                                 mq_handlers,
+                                 &handle_session_client_error,
+                                 s);
+  if (NULL == s->mq)
+  {
+    /* secretsharing not configured correctly */
+    GNUNET_break (0);
+    GNUNET_free (s);
+    return NULL;
+  }
   s->secret_ready_cb = cb;
   s->secret_ready_cls = cls;
-  GNUNET_assert (NULL != s->client);
-
-  s->mq = GNUNET_MQ_queue_for_connection_client (s->client, mq_handlers,
-                                                   handle_session_client_error, s);
-  GNUNET_assert (NULL != s->mq);
-
   ev = GNUNET_MQ_msg_extra (msg,
                             num_peers * sizeof (struct GNUNET_PeerIdentity),
                             GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE);
@@ -205,33 +282,31 @@ GNUNET_SECRETSHARING_create_session (const struct GNUNET_CONFIGURATION_Handle *c
   msg->threshold = htons (threshold);
   msg->num_peers = htons (num_peers);
   msg->session_id = *session_id;
+  msg->start = GNUNET_TIME_absolute_hton (start);
   msg->deadline = GNUNET_TIME_absolute_hton (deadline);
   memcpy (&msg[1], peers, num_peers * sizeof (struct GNUNET_PeerIdentity));
 
   GNUNET_MQ_send (s->mq, ev);
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "secretsharing session created with %u peers\n",
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Secretsharing session created with %u peers\n",
        num_peers);
   return s;
 }
 
 
 static void
-handle_decrypt_done (void *cls, const struct GNUNET_MessageHeader *msg)
+handle_decrypt_done (void *cls,
+                     const struct GNUNET_SECRETSHARING_DecryptResponseMessage *m)
 {
   struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls;
-  const struct GNUNET_SECRETSHARING_DecryptResponseMessage *m =
-      (const void *) msg;
-
   const struct GNUNET_SECRETSHARING_Plaintext *plaintext;
 
   if (m->success == 0)
     plaintext = NULL;
   else
     plaintext = (void *) &m->plaintext;
-
   dh->decrypt_cb (dh->decrypt_cls, plaintext);
-
   GNUNET_SECRETSHARING_decrypt_cancel (dh);
 }
 
@@ -253,44 +328,58 @@ struct GNUNET_SECRETSHARING_DecryptionHandle *
 GNUNET_SECRETSHARING_decrypt (const struct GNUNET_CONFIGURATION_Handle *cfg,
                               struct GNUNET_SECRETSHARING_Share *share,
                               const struct GNUNET_SECRETSHARING_Ciphertext *ciphertext,
+                              struct GNUNET_TIME_Absolute start,
                               struct GNUNET_TIME_Absolute deadline,
                               GNUNET_SECRETSHARING_DecryptCallback decrypt_cb,
                               void *decrypt_cb_cls)
 {
-  struct GNUNET_SECRETSHARING_DecryptionHandle *s;
+  GNUNET_MQ_hd_fixed_size (decrypt_done,
+                           GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE,
+                           struct GNUNET_SECRETSHARING_DecryptResponseMessage);
+  struct GNUNET_SECRETSHARING_DecryptionHandle *s
+    = GNUNET_new (struct GNUNET_SECRETSHARING_DecryptionHandle);
+  struct GNUNET_MQ_MessageHandler mq_handlers[] = {
+    make_decrypt_done_handler (s),
+    GNUNET_MQ_handler_end ()
+  };
   struct GNUNET_MQ_Envelope *ev;
   struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg;
-  static const struct GNUNET_MQ_MessageHandler mq_handlers[] = {
-    {handle_decrypt_done, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE, 0},
-    GNUNET_MQ_HANDLERS_END
-  };
   size_t share_size;
 
-
-  s = GNUNET_new (struct GNUNET_SECRETSHARING_DecryptionHandle);
-  s->client = GNUNET_CLIENT_connect ("secretsharing", cfg);
   s->decrypt_cb = decrypt_cb;
   s->decrypt_cls = decrypt_cb_cls;
-  GNUNET_assert (NULL != s->client);
-
-  s->mq = GNUNET_MQ_queue_for_connection_client (s->client, mq_handlers,
-                                                 handle_decrypt_client_error, s);
-  GNUNET_assert (NULL != s->mq);
-
-  GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, NULL, 0, &share_size));
+  s->mq = GNUNET_CLIENT_connecT (cfg,
+                                 "secretsharing",
+                                 mq_handlers,
+                                 &handle_decrypt_client_error,
+                                 s);
+  if (NULL == s->mq)
+  {
+    GNUNET_free (s);
+    return NULL;
+  }
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_SECRETSHARING_share_write (share, NULL, 0,
+                                                   &share_size));
 
   ev = GNUNET_MQ_msg_extra (msg,
                             share_size,
                             GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT);
 
-  GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, &msg[1], share_size, NULL));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_SECRETSHARING_share_write (share,
+                                                   &msg[1],
+                                                   share_size,
+                                                   NULL));
 
+  msg->start = GNUNET_TIME_absolute_hton (start);
   msg->deadline = GNUNET_TIME_absolute_hton (deadline);
   msg->ciphertext = *ciphertext;
 
   GNUNET_MQ_send (s->mq, ev);
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "decrypt session created\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "decrypt session created\n");
   return s;
 }
 
@@ -325,7 +414,9 @@ GNUNET_SECRETSHARING_plaintext_generate_i (struct GNUNET_SECRETSHARING_Plaintext
       return GNUNET_SYSERR;
   }
 
-  GNUNET_CRYPTO_mpi_print_unsigned (plaintext, sizeof (struct GNUNET_SECRETSHARING_Plaintext), x);
+  GNUNET_CRYPTO_mpi_print_unsigned (plaintext,
+                                    sizeof (struct GNUNET_SECRETSHARING_Plaintext),
+                                    x);
 
   return GNUNET_OK;
 }
@@ -369,7 +460,7 @@ GNUNET_SECRETSHARING_encrypt (const struct GNUNET_SECRETSHARING_PublicKey *publi
 
   // Randomize y such that 0 < y < elgamal_q.
   // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1.
-  do 
+  do
   {
     gcry_mpi_randomize (y, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, GCRY_WEAK_RANDOM);
   } while ((gcry_mpi_cmp_ui (y, 0) == 0) || (gcry_mpi_cmp (y, elgamal_q) >= 0));
@@ -379,10 +470,10 @@ GNUNET_SECRETSHARING_encrypt (const struct GNUNET_SECRETSHARING_PublicKey *publi
   // write tmp to c1
   GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c1_bits,
                                     GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp);
-  
+
   // tmp <- h^y
   gcry_mpi_powm (tmp, h, y, elgamal_p);
-  // tmp <- tmp * m 
+  // tmp <- tmp * m
   gcry_mpi_mulm (tmp, tmp, m, elgamal_p);
   // write tmp to c2
   GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c2_bits,
@@ -392,15 +483,20 @@ GNUNET_SECRETSHARING_encrypt (const struct GNUNET_SECRETSHARING_PublicKey *publi
 }
 
 
+/**
+ * Cancel a decryption.
+ *
+ * The decrypt_cb is not called anymore, but the calling
+ * peer may already have irrevocably contributed his share for the decryption of the value.
+ *
+ * @param dh to cancel
+ */
 void
-GNUNET_SECRETSHARING_decrypt_cancel (struct GNUNET_SECRETSHARING_DecryptionHandle *h)
+GNUNET_SECRETSHARING_decrypt_cancel (struct GNUNET_SECRETSHARING_DecryptionHandle *dh)
 {
-  GNUNET_MQ_destroy (h->mq);
-  h->mq = NULL;
-  GNUNET_CLIENT_disconnect (h->client);
-  h->client = NULL;
-  GNUNET_free (h);
+  GNUNET_MQ_destroy (dh->mq);
+  dh->mq = NULL;
+  GNUNET_free (dh);
 }
 
-
-
+/* end of secretsharing_api.c */