* @brief scalarproduct service implementation
* @author Christian M. Fuchs
*/
-#include <limits.h>
#include "platform.h"
+#include <limits.h>
+#include <gcrypt.h>
#include "gnunet_util_lib.h"
#include "gnunet_core_service.h"
-#include "gnunet_mesh_service.h"
+#include "gnunet_cadet_service.h"
#include "gnunet_applications.h"
#include "gnunet_protocols.h"
#include "gnunet_scalarproduct_service.h"
+#include "gnunet_set_service.h"
#include "scalarproduct.h"
#define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct", __VA_ARGS__)
// Service Structure Definitions
///////////////////////////////////////////////////////////////////////////////
+
/**
- * state a session can be in
+ * role a peer in a session can assume
*/
-enum SessionState
+enum PeerRole
{
- WAITING_FOR_BOBS_CONNECT,
- MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED,
- WAITING_FOR_RESPONSE_FROM_SERVICE,
- REQUEST_FROM_SERVICE_RECEIVED,
- FINALIZED
+ ALICE,
+ BOB
};
/**
- * role a peer in a session can assume
+ * DLL for sorting elements
*/
-enum PeerRole
+struct SortedValue
{
- ALICE,
- BOB
+ /**
+ * Sorted Values are kept in a DLL
+ */
+ struct SortedValue * next;
+
+ /**
+ * Sorted Values are kept in a DLL
+ */
+ struct SortedValue * prev;
+
+ /**
+ * The element's id+integer-value
+ */
+ struct GNUNET_SCALARPRODUCT_Element * elem;
+
+ /**
+ * the element's value converted to MPI
+ */
+ gcry_mpi_t val;
};
/**
* A scalarproduct session which tracks:
- *
+ *
* a request form the client to our final response.
* or
* a request from a service to us(service).
*/
struct ServiceSession
{
- /**
- * the role this peer has
- */
- enum PeerRole role;
-
- /**
- * session information is kept in a DLL
- */
- struct ServiceSession *next;
-
- /**
- * session information is kept in a DLL
- */
- struct ServiceSession *prev;
-
- /**
- * (hopefully) unique transaction ID
- */
- struct GNUNET_HashCode key;
-
- /**
- * state of the session
- */
- enum SessionState state;
-
- /**
- * Alice or Bob's peerID
- */
- struct GNUNET_PeerIdentity peer;
-
- /**
- * the client this request is related to
- */
- struct GNUNET_SERVER_Client * client;
-
- /**
- * The message to send
- */
- struct GNUNET_MessageHeader * msg;
-
- /**
- * how many elements we were supplied with from the client
- */
- uint16_t element_count;
-
- /**
- * how many elements actually are used after applying the mask
- */
- uint16_t used_element_count;
-
- /**
- * how many bytes the mask is long.
- * just for convenience so we don't have to re-re-re calculate it each time
- */
- uint16_t mask_length;
-
- /**
- * all the vector elements we received
- */
- int32_t * vector;
-
- /**
- * mask of which elements to check
- */
- unsigned char * mask;
-
- /**
- * Public key of the remote service, only used by bob
- */
- gcry_sexp_t remote_pubkey;
-
- /**
- * E(ai)(Bob) or ai(Alice) after applying the mask
- */
- gcry_mpi_t * a;
-
- /**
- * The computed scalar
- */
- gcry_mpi_t product;
-
- /**
- * My transmit handle for the current message to a alice/bob
- */
- struct GNUNET_MESH_TransmitHandle * service_transmit_handle;
-
- /**
- * My transmit handle for the current message to the client
- */
- struct GNUNET_SERVER_TransmitHandle * client_transmit_handle;
-
- /**
- * tunnel-handle associated with our mesh handle
- */
- struct GNUNET_MESH_Tunnel * tunnel;
-
- GNUNET_SCHEDULER_TaskIdentifier client_notification_task;
-
- GNUNET_SCHEDULER_TaskIdentifier service_request_task;
+ /**
+ * the role this peer has
+ */
+ enum PeerRole role;
+
+ /**
+ * session information is kept in a DLL
+ */
+ struct ServiceSession *next;
+
+ /**
+ * session information is kept in a DLL
+ */
+ struct ServiceSession *prev;
+
+ /**
+ * (hopefully) unique transaction ID
+ */
+ struct GNUNET_HashCode session_id;
+
+ /**
+ * Alice or Bob's peerID
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * the client this request is related to
+ */
+ struct GNUNET_SERVER_Client * client;
+
+ /**
+ * The message to send
+ */
+ struct GNUNET_MessageHeader * msg;
+
+ /**
+ * how many elements we were supplied with from the client
+ */
+ uint32_t total;
+
+ /**
+ * how many elements we used for intersection
+ */
+ uint32_t intersected_elements_count;
+
+ /**
+ * all non-0-value'd elements transmitted to us
+ */
+ struct GNUNET_CONTAINER_MultiHashMap * intersected_elements;
+
+ /**
+ * how many elements actually are used for the scalar product
+ */
+ uint32_t used_elements_count;
+
+ /**
+ * already transferred elements (sent/received) for multipart messages, less or equal than used_element_count for
+ */
+ uint32_t transferred_element_count;
+
+ /**
+ * Set of elements for which will conduction an intersection.
+ * the resulting elements are then used for computing the scalar product.
+ */
+ struct GNUNET_SET_Handle * intersection_set;
+
+ /**
+ * Set of elements for which will conduction an intersection.
+ * the resulting elements are then used for computing the scalar product.
+ */
+ struct GNUNET_SET_OperationHandle * intersection_op;
+
+ /**
+ * Handle to Alice's Intersection operation listening for Bob
+ */
+ struct GNUNET_SET_ListenHandle * intersection_listen;
+
+ /**
+ * Public key of the remote service, only used by bob
+ */
+ struct GNUNET_CRYPTO_PaillierPublicKey * remote_pubkey;
+
+ /**
+ * DLL for sorting elements after intersection
+ */
+ struct SortedValue * a_head;
+
+ /**
+ * a(Alice)
+ */
+ struct SortedValue * a_tail;
+
+ /**
+ * a(Alice)
+ */
+ gcry_mpi_t * sorted_elements;
+
+ /**
+ * E(ai)(Bob) after applying the mask
+ */
+ struct GNUNET_CRYPTO_PaillierCiphertext * e_a;
+
+ /**
+ * Bob's permutation p of R
+ */
+ struct GNUNET_CRYPTO_PaillierCiphertext * r;
+
+ /**
+ * Bob's permutation q of R
+ */
+ struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
+
+ /**
+ * Bob's s
+ */
+ struct GNUNET_CRYPTO_PaillierCiphertext * s;
+
+ /**
+ * Bob's s'
+ */
+ struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
+
+ /**
+ * Bobs matching response session from the client
+ */
+ struct ServiceSession * response;
+
+ /**
+ * The computed scalar
+ */
+ gcry_mpi_t product;
+
+ /**
+ * My transmit handle for the current message to a alice/bob
+ */
+ struct GNUNET_CADET_TransmitHandle * service_transmit_handle;
+
+ /**
+ * My transmit handle for the current message to the client
+ */
+ struct GNUNET_SERVER_TransmitHandle * client_transmit_handle;
+
+ /**
+ * channel-handle associated with our cadet handle
+ */
+ struct GNUNET_CADET_Channel * channel;
+
+ /**
+ * Handle to a task that sends a msg to the our client
+ */
+ GNUNET_SCHEDULER_TaskIdentifier client_notification_task;
};
///////////////////////////////////////////////////////////////////////////////
-// Global Variables
+// Forward Delcarations
///////////////////////////////////////////////////////////////////////////////
-
/**
- * Handle to the core service (NULL until we've connected to it).
+ * Send a multi part chunk of a service request from alice to bob.
+ * This element only contains a part of the elements-vector (session->a[]),
+ * mask and public key set have to be contained within the first message
+ *
+ * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
+ *
+ * @param cls the associated service session
*/
-static struct GNUNET_MESH_Handle *my_mesh;
+static void
+prepare_alices_cyrptodata_message_multipart (void *cls);
/**
- * The identity of this host.
+ * Send a multi part chunk of a service response from bob to alice.
+ * This element only contains the two permutations of R, R'.
+ *
+ * @param cls the associated service session
*/
-static struct GNUNET_PeerIdentity me;
+static void
+prepare_bobs_cryptodata_message_multipart (void *cls);
-/**
- * Service's own public key represented as string
- */
-static unsigned char * my_pubkey_external;
-/**
- * Service's own public key represented as string
- */
-static uint16_t my_pubkey_external_length = 0;
+///////////////////////////////////////////////////////////////////////////////
+// Global Variables
+///////////////////////////////////////////////////////////////////////////////
+
/**
- * Service's own n
+ * Gnunet configuration handle
*/
-static gcry_mpi_t my_n;
+const struct GNUNET_CONFIGURATION_Handle * cfg;
/**
- * Service's own n^2 (kept for performance)
+ * Handle to the core service (NULL until we've connected to it).
*/
-static gcry_mpi_t my_nsquare;
+static struct GNUNET_CADET_Handle *my_cadet;
/**
- * Service's own public exponent
+ * The identity of this host.
*/
-static gcry_mpi_t my_g;
+static struct GNUNET_PeerIdentity me;
/**
- * Service's own private multiplier
+ * Service's own public key
*/
-static gcry_mpi_t my_mu;
+static struct GNUNET_CRYPTO_PaillierPublicKey my_pubkey;
/**
- * Service's own private exponent
+ * Service's own private key
*/
-static gcry_mpi_t my_lambda;
+static struct GNUNET_CRYPTO_PaillierPrivateKey my_privkey;
/**
* Service's offset for values that could possibly be negative but are plaintext for encryption.
static gcry_mpi_t my_offset;
/**
- * Head of our double linked list for client-requests sent to us.
+ * Head of our double linked list for client-requests sent to us.
* for all of these elements we calculate a scalar product with a remote peer
* split between service->service and client->service for simplicity
*/
static struct ServiceSession * from_client_head;
/**
- * Tail of our double linked list for client-requests sent to us.
+ * Tail of our double linked list for client-requests sent to us.
* for all of these elements we calculate a scalar product with a remote peer
* split between service->service and client->service for simplicity
*/
static struct ServiceSession * from_client_tail;
/**
- * Head of our double linked list for service-requests sent to us.
+ * Head of our double linked list for service-requests sent to us.
* for all of these elements we help the requesting service in calculating a scalar product
* split between service->service and client->service for simplicity
*/
static struct ServiceSession * from_service_head;
/**
- * Tail of our double linked list for service-requests sent to us.
+ * Tail of our double linked list for service-requests sent to us.
* for all of these elements we help the requesting service in calculating a scalar product
* split between service->service and client->service for simplicity
*/
static struct ServiceSession * from_service_tail;
/**
- * Certain events (callbacks for server & mesh operations) must not be queued after shutdown.
+ * Certain events (callbacks for server & cadet operations) must not be queued after shutdown.
*/
static int do_shutdown;
// Helper Functions
///////////////////////////////////////////////////////////////////////////////
-/**
- * Generates an Paillier private/public keyset and extracts the values using libgrcypt only
- */
-static void
-generate_keyset ()
-{
- gcry_sexp_t gen_parms;
- gcry_sexp_t key;
- gcry_sexp_t tmp_sexp;
- gcry_mpi_t p;
- gcry_mpi_t q;
- gcry_mpi_t tmp1;
- gcry_mpi_t tmp2;
- gcry_mpi_t gcd;
-
- size_t erroff = 0;
-
- // we can still use the RSA keygen for generating p,q,n, but using e is pointless.
- GNUNET_assert (0 == gcry_sexp_build (&gen_parms, &erroff,
- "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))",
- KEYBITS));
-
- GNUNET_assert (0 == gcry_pk_genkey (&key, gen_parms));
- gcry_sexp_release (gen_parms);
-
- // get n and d of our publickey as MPI
- tmp_sexp = gcry_sexp_find_token (key, "n", 0);
- GNUNET_assert (tmp_sexp);
- my_n = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (tmp_sexp);
- tmp_sexp = gcry_sexp_find_token (key, "p", 0);
- GNUNET_assert (tmp_sexp);
- p = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (tmp_sexp);
- tmp_sexp = gcry_sexp_find_token (key, "q", 0);
- GNUNET_assert (tmp_sexp);
- q = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (key);
-
- tmp1 = gcry_mpi_new (0);
- tmp2 = gcry_mpi_new (0);
- gcd = gcry_mpi_new (0);
- my_g = gcry_mpi_new (0);
- my_mu = gcry_mpi_new (0);
- my_nsquare = gcry_mpi_new (0);
- my_lambda = gcry_mpi_new (0);
-
- // calculate lambda
- // lambda = \frac{(p-1)*(q-1)}{gcd(p-1,q-1)}
- gcry_mpi_sub_ui (tmp1, p, 1);
- gcry_mpi_sub_ui (tmp2, q, 1);
- gcry_mpi_gcd (gcd, tmp1, tmp2);
- gcry_mpi_set (my_lambda, tmp1);
- gcry_mpi_mul (my_lambda, my_lambda, tmp2);
- gcry_mpi_div (my_lambda, NULL, my_lambda, gcd, 0);
-
- // generate a g
- gcry_mpi_mul (my_nsquare, my_n, my_n);
- do
- {
- // find a matching g
- do
- {
- gcry_mpi_randomize (my_g, KEYBITS * 2, GCRY_WEAK_RANDOM);
- // g must be smaller than n^2
- if (0 >= gcry_mpi_cmp (my_g, my_nsquare))
- continue;
-
- // g must have gcd == 1 with n^2
- gcry_mpi_gcd (gcd, my_g, my_nsquare);
- }
- while (gcry_mpi_cmp_ui (gcd, 1));
-
- // is this a valid g?
- // if so, gcd(((g^lambda mod n^2)-1 )/n, n) = 1
- gcry_mpi_powm (tmp1, my_g, my_lambda, my_nsquare);
- gcry_mpi_sub_ui (tmp1, tmp1, 1);
- gcry_mpi_div (tmp1, NULL, tmp1, my_n, 0);
- gcry_mpi_gcd (gcd, tmp1, my_n);
- }
- while (gcry_mpi_cmp_ui (gcd, 1));
-
- // calculate our mu based on g and n.
- // mu = (((g^lambda mod n^2)-1 )/n)^-1 mod n
- gcry_mpi_invm (my_mu, tmp1, my_n);
-
- GNUNET_assert (0 == gcry_sexp_build (&key, &erroff,
- "(public-key (paillier (n %M)(g %M)))",
- my_n, my_g));
-
- // get the length of this sexpression
- my_pubkey_external_length = gcry_sexp_sprint (key,
- GCRYSEXP_FMT_CANON,
- NULL,
- UINT16_MAX);
-
- GNUNET_assert (my_pubkey_external_length > 0);
- my_pubkey_external = GNUNET_malloc (my_pubkey_external_length);
-
- // convert the sexpression to canonical format
- gcry_sexp_sprint (key,
- GCRYSEXP_FMT_CANON,
- my_pubkey_external,
- my_pubkey_external_length);
-
- gcry_sexp_release (key);
-
- // offset has to be sufficiently small to allow computation of:
- // m1+m2 mod n == (S + a) + (S + b) mod n,
- // if we have more complex operations, this factor needs to be lowered
- my_offset = gcry_mpi_new(KEYBITS/3);
- gcry_mpi_set_bit(my_offset, KEYBITS/3);
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Generated key set with key length %d bits.\n"), KEYBITS);
-}
-
-
-/**
- * If target != size, move target bytes to the
- * end of the size-sized buffer and zero out the
- * first target-size bytes.
- *
- * @param buf original buffer
- * @param size number of bytes in the buffer
- * @param target target size of the buffer
- */
-static void
-adjust (unsigned char *buf, size_t size, size_t target)
-{
- if (size < target)
- {
- memmove (&buf[target - size], buf, size);
- memset (buf, 0, target - size);
- }
-}
-
-
-/**
- * encrypts an element using the paillier crypto system
- *
- * @param c ciphertext (output)
- * @param m plaintext
- * @param g the public base
- * @param n the module from which which r is chosen (Z*_n)
- * @param n_square the module for encryption, for performance reasons.
- */
-static void
-encrypt_element (gcry_mpi_t c, gcry_mpi_t m, gcry_mpi_t g, gcry_mpi_t n, gcry_mpi_t n_square)
-{
- gcry_mpi_t tmp;
-
- GNUNET_assert (tmp = gcry_mpi_new (0));
-
- while (0 >= gcry_mpi_cmp_ui (tmp, 1))
- {
- gcry_mpi_randomize (tmp, KEYBITS / 3, GCRY_WEAK_RANDOM);
- // r must be 1 < r < n
- }
-
- gcry_mpi_powm (c, g, m, n_square);
- gcry_mpi_powm (tmp, tmp, n, n_square);
- gcry_mpi_mulm (c, tmp, c, n_square);
-
- gcry_mpi_release (tmp);
-}
-
-/**
- * decrypts an element using the paillier crypto system
- *
- * @param m plaintext (output)
- * @param c the ciphertext
- * @param mu the modifier to correct encryption
- * @param lambda the private exponent
- * @param n the outer module for decryption
- * @param n_square the inner module for decryption
- */
-static void
-decrypt_element (gcry_mpi_t m, gcry_mpi_t c, gcry_mpi_t mu, gcry_mpi_t lambda, gcry_mpi_t n, gcry_mpi_t n_square)
-{
- gcry_mpi_powm (m, c, lambda, n_square);
- gcry_mpi_sub_ui (m, m, 1);
- gcry_mpi_div (m, NULL, m, n, 0);
- gcry_mpi_mulm (m, m, mu, n);
-}
-
/**
* computes the square sum over a vector of a given length.
- *
+ *
* @param vector the vector to encrypt
* @param length the length of the vector
* @return an MPI value containing the calculated sum, never NULL
*/
static gcry_mpi_t
-compute_square_sum (gcry_mpi_t * vector, uint16_t length)
+compute_square_sum (gcry_mpi_t * vector, uint32_t length)
{
gcry_mpi_t elem;
gcry_mpi_t sum;
GNUNET_assert (elem = gcry_mpi_new (0));
// calculare E(sum (ai ^ 2), publickey)
- for (i = 0; i < length; i++)
- {
- gcry_mpi_mul (elem, vector[i], vector[i]);
- gcry_mpi_add (sum, sum, elem);
- }
+ for (i = 0; i < length; i++) {
+ gcry_mpi_mul (elem, vector[i], vector[i]);
+ gcry_mpi_add (sum, sum, elem);
+ }
gcry_mpi_release (elem);
return sum;
* Primitive callback for copying over a message, as they
* usually are too complex to be handled in the callback itself.
* clears a session-callback, if a session was handed over and the transmit handle was stored
- *
- * @param cls the message object
+ *
+ * @param cls the session containing the message object
* @param size the size of the buffer we got
* @param buf the buffer to copy the message to
* @return 0 if we couldn't copy, else the size copied over
static size_t
do_send_message (void *cls, size_t size, void *buf)
{
- struct ServiceSession * session = cls;
- size_t written = 0;
+ struct ServiceSession * s = cls;
+ uint16_t type;
GNUNET_assert (buf);
- if (ntohs (session->msg->size) == size)
- {
- memcpy (buf, session->msg, size);
- written = size;
- }
-
- if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT == ntohs(session->msg->type)){
- session->state = FINALIZED;
- session->client_transmit_handle = NULL;
+ if (ntohs (s->msg->size) != size) {
+ GNUNET_break (0);
+ return 0;
}
- else
- session->service_transmit_handle = NULL;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sent a message of type %hu.\n",
- ntohs (session->msg->type));
- GNUNET_free(session->msg);
- session->msg = NULL;
-
- return written;
-}
-
-
-/**
- * initializes a new vector with fresh MPI values (=0) of a given length
- *
- * @param length of the vector to create
- * @return the initialized vector, never NULL
- */
-static gcry_mpi_t *
-initialize_mpi_vector (uint16_t length)
-{
- uint32_t i;
- gcry_mpi_t * output = GNUNET_malloc (sizeof (gcry_mpi_t) * length);
-
- for (i = 0; i < length; i++)
- GNUNET_assert (NULL != (output[i] = gcry_mpi_new (0)));
- return output;
-}
-
-
-/**
- * permutes an MPI vector according to the given permutation vector
- *
- * @param vector the vector to permuted
- * @param perm the permutation to use
- * @param length the length of the vectors
- * @return the permuted vector (same as input), never NULL
- */
-static gcry_mpi_t *
-permute_vector (gcry_mpi_t * vector,
- unsigned int * perm,
- uint32_t length)
-{
- gcry_mpi_t tmp[length];
- uint32_t i;
- GNUNET_assert (length > 0);
-
- // backup old layout
- memcpy (tmp, vector, length * sizeof (gcry_mpi_t));
-
- // permute vector according to given
- for (i = 0; i < length; i++)
- vector[i] = tmp[perm[i]];
-
- return vector;
-}
-
-
-/**
- * Populate a vector with random integer values and convert them to
- *
- * @param length the length of the vector we must generate
- * @return an array of MPI values with random values
- */
-static gcry_mpi_t *
-generate_random_vector (uint16_t length)
-{
- gcry_mpi_t * random_vector;
- int32_t value;
- uint32_t i;
+ type = ntohs (s->msg->type);
+ memcpy (buf, s->msg, size);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sent a message of type %hu.\n",
+ type);
+ GNUNET_free (s->msg);
+ s->msg = NULL;
- random_vector = initialize_mpi_vector (length);
- for (i = 0; i < length; i++)
- {
- value = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
-
- // long to gcry_mpi_t
- if (value < 0)
- gcry_mpi_sub_ui (random_vector[i],
- random_vector[i],
- -value);
- else
- random_vector[i] = gcry_mpi_set_ui (random_vector[i], value);
- }
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT:
+ s->client_transmit_handle = NULL;
+ break;
+
+ case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA:
+ case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART:
+ s->service_transmit_handle = NULL;
+ if (s->used_elements_count != s->transferred_element_count)
+ prepare_alices_cyrptodata_message_multipart (s);
+ break;
+
+ case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA:
+ case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART:
+ s->service_transmit_handle = NULL;
+ if (s->used_elements_count != s->transferred_element_count)
+ prepare_bobs_cryptodata_message_multipart (s);
+ break;
+
+ default:
+ GNUNET_assert (0);
+ }
- return random_vector;
+ return size;
}
/**
- * Finds a not terminated client/service session in the
+ * Finds a not terminated client/service session in the
* given DLL based on session key, element count and state.
- *
+ *
* @param tail - the tail of the DLL
- * @param my - the session to compare it to
- * @return a pointer to a matching session,
- * else NULL
+ * @param key - the key we want to search for
+ * @param element_count - the total element count of the dataset (session->total)
+ * @param peerid - a pointer to the peer ID of the associated peer, NULL to ignore
+ * @return a pointer to a matching session, or NULL
*/
static struct ServiceSession *
find_matching_session (struct ServiceSession * tail,
const struct GNUNET_HashCode * key,
- uint16_t element_count,
- enum SessionState * state,
+ uint32_t element_count,
const struct GNUNET_PeerIdentity * peerid)
{
struct ServiceSession * curr;
- for (curr = tail; NULL != curr; curr = curr->prev)
- {
- // if the key matches, and the element_count is same
- if ((!memcmp (&curr->key, key, sizeof (struct GNUNET_HashCode)))
- && (curr->element_count == element_count))
- {
- // if incoming state is NULL OR is same as state of the queued request
- if ((NULL == state) || (curr->state == *state))
- {
- // if peerid is NULL OR same as the peer Id in the queued request
- if ((NULL == peerid)
- || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
- // matches and is not an already terminated session
- return curr;
- }
- }
+ for (curr = tail; NULL != curr; curr = curr->prev) {
+ // if the key matches, and the element_count is same
+ if ((!memcmp (&curr->session_id, key, sizeof (struct GNUNET_HashCode)))
+ && (curr->total == element_count)) {
+ // if peerid is NULL OR same as the peer Id in the queued request
+ if ((NULL == peerid)
+ || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
+ // matches and is not an already terminated session
+ return curr;
}
+ }
return NULL;
}
+/**
+ * Safely frees ALL memory areas referenced by a session.
+ *
+ * @param session - the session to free elements from
+ */
static void
-free_session (struct ServiceSession * session)
+free_session_variables (struct ServiceSession * session)
{
- unsigned int i;
-
- if (session->a)
- {
- for (i = 0; i < session->used_element_count; i++)
- gcry_mpi_release (session->a[i]);
-
- GNUNET_free (session->a);
+ while (NULL != session->a_head) {
+ struct SortedValue * e = session->a_head;
+ GNUNET_free (e->elem);
+ gcry_mpi_release (e->val);
+ GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, e);
+ GNUNET_free (e);
+ }
+ if (session->e_a) {
+ GNUNET_free (session->e_a);
+ session->e_a = NULL;
+ }
+ if (session->remote_pubkey){
+ GNUNET_free(session->remote_pubkey);
+ session->remote_pubkey=NULL;
+ }
+ if (session->sorted_elements) {
+ GNUNET_free (session->sorted_elements);
+ session->sorted_elements = NULL;
+ }
+ if (session->intersected_elements) {
+ GNUNET_CONTAINER_multihashmap_destroy (session->intersected_elements);
+ //elements are freed independently in session->a_head/tail
+ session->intersected_elements = NULL;
+ }
+ if (session->intersection_listen) {
+ GNUNET_SET_listen_cancel (session->intersection_listen);
+ session->intersection_listen = NULL;
+ }
+ if (session->intersection_op) {
+ GNUNET_SET_operation_cancel (session->intersection_op);
+ session->intersection_op = NULL;
+ }
+ if (session->intersection_set) {
+ GNUNET_SET_destroy (session->intersection_set);
+ session->intersection_set = NULL;
+ }
+ if (session->channel){
+ GNUNET_CADET_channel_destroy(session->channel);
+ session->channel = NULL;
+ }
+ if (session->msg) {
+ GNUNET_free (session->msg);
+ session->msg = NULL;
+ }
+ if (session->r) {
+ GNUNET_free (session->r);
+ session->r = NULL;
+ }
+ if (session->r_prime) {
+ GNUNET_free (session->r_prime);
+ session->r_prime = NULL;
+ }
+ if (session->s) {
+ GNUNET_free (session->s);
+ session->s = NULL;
+ }
+ if (session->s_prime) {
+ GNUNET_free (session->s_prime);
+ session->s_prime = NULL;
}
- if (session->product)
+ if (session->product) {
gcry_mpi_release (session->product);
-
- if (session->remote_pubkey)
- gcry_sexp_release (session->remote_pubkey);
-
- GNUNET_free_non_null (session->vector);
- GNUNET_free (session);
+ session->product = NULL;
+ }
}
///////////////////////////////////////////////////////////////////////////////
// Event and Message Handlers
///////////////////////////////////////////////////////////////////////////////
+
/**
- * A client disconnected.
- *
- * Remove the associated session(s), release datastructures
+ * A client disconnected.
+ *
+ * Remove the associated session(s), release data structures
* and cancel pending outgoing transmissions to the client.
* if the session has not yet completed, we also cancel Alice's request to Bob.
*
{
struct ServiceSession *session;
+ if (NULL != client)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _ ("Client (%p) disconnected from us.\n"), client);
+ else
+ return;
+
session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
if (NULL == session)
return;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _ ("Client (%p) disconnected from us.\n"), client);
GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
-
- if (!(session->role == BOB && session->state == FINALIZED))
- {
- //we MUST terminate any client message underway
- if (session->service_transmit_handle && session->tunnel)
- GNUNET_MESH_notify_transmit_ready_cancel (session->service_transmit_handle);
- if (session->tunnel && session->state == WAITING_FOR_RESPONSE_FROM_SERVICE)
- GNUNET_MESH_tunnel_destroy (session->tunnel);
- }
- if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task)
- {
- GNUNET_SCHEDULER_cancel (session->client_notification_task);
- session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
- }
- if (GNUNET_SCHEDULER_NO_TASK != session->service_request_task)
- {
- GNUNET_SCHEDULER_cancel (session->service_request_task);
- session->service_request_task = GNUNET_SCHEDULER_NO_TASK;
- }
- if (NULL != session->client_transmit_handle)
- {
- GNUNET_SERVER_notify_transmit_ready_cancel (session->client_transmit_handle);
- session->client_transmit_handle = NULL;
- }
- free_session (session);
+
+ if (!(session->role == BOB && 0/*//TODO: if session concluded*/)) {
+ //we MUST terminate any client message underway
+ if (session->service_transmit_handle && session->channel)
+ GNUNET_CADET_notify_transmit_ready_cancel (session->service_transmit_handle);
+ if (session->channel && 0/* //TODO: waiting for service response */)
+ GNUNET_CADET_channel_destroy (session->channel);
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
+ GNUNET_SCHEDULER_cancel (session->client_notification_task);
+ session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != session->client_transmit_handle) {
+ GNUNET_SERVER_notify_transmit_ready_cancel (session->client_transmit_handle);
+ session->client_transmit_handle = NULL;
+ }
+ free_session_variables (session);
+ GNUNET_free (session);
}
/**
* Notify the client that the session has succeeded or failed completely.
- * This message gets sent to
+ * This message gets sent to
* * alice's client if bob disconnected or to
* * bob's client if the operation completed or alice disconnected
- *
- * @param client_session the associated client session
- * @return GNUNET_NO, if we could not notify the client
- * GNUNET_YES if we notified it.
+ *
+ * @param cls the associated client session
+ * @param tc the task context handed to us by the scheduler, unused
*/
static void
prepare_client_end_notification (void * cls,
{
struct ServiceSession * session = cls;
struct GNUNET_SCALARPRODUCT_client_response * msg;
-
+
session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_client_response);
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT);
- memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
+ memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_client_response));
- // 0 size and the first char in the product is 0, which should never be zero if encoding is used.
+ // signal error if not signalized, positive result-range field but zero length.
msg->product_length = htonl (0);
- msg->range = 1;
+ msg->range = (session /* //TODO: if finalized */) ? 0 : -1;
session->msg = &msg->header;
session);
// if we could not even queue our request, something is wrong
- if ( ! session->client_transmit_handle)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to client (%p)! This is OK if it was disconnected beforehand already.\n"), session->client);
- // usually gets freed by do_send_message
- GNUNET_free (msg_obj);
- GNUNET_free (msg);
- }
+ if (NULL == session->client_transmit_handle) {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to client (%p)!\n"), session->client);
+ // usually gets freed by do_send_message
+ session->msg = NULL;
+ GNUNET_free (msg);
+ }
else
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->key));
-
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->session_id));
+
+ free_session_variables (session);
+}
+
+
+/**
+ * Executed by Alice, fills in a service-request message and sends it to the given peer
+ *
+ * @param cls the session associated with this request
+ */
+static void
+prepare_alices_cyrptodata_message (void *cls)
+{
+ struct ServiceSession * session = cls;
+ struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg;
+ struct GNUNET_CRYPTO_PaillierCiphertext * payload;
+ unsigned int i;
+ uint32_t msg_length;
+ gcry_mpi_t a;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
+
+ msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
+ +session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+
+ if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length) {
+ session->transferred_element_count = session->used_elements_count;
+ }
+ else {
+ //create a multipart msg, first we calculate a new msg size for the head msg
+ session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message))
+ / sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+ msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
+ +session->transferred_element_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+ }
+
+ msg = GNUNET_malloc (msg_length);
+ msg->header.size = htons (msg_length);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
+ msg->contained_element_count = htonl (session->transferred_element_count);
+
+ // fill in the payload
+ payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
+
+ // now copy over the sorted element vector
+ a = gcry_mpi_new (0);
+ for (i = 0; i < session->transferred_element_count; i++) {
+ gcry_mpi_add (a, session->sorted_elements[i], my_offset);
+ GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i]);
+ }
+ gcry_mpi_release (a);
+
+ session->msg = (struct GNUNET_MessageHeader *) msg;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
+
+ //transmit via cadet messaging
+ session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ msg_length,
+ &do_send_message,
+ session);
+ if (NULL == session->service_transmit_handle) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
+ GNUNET_free (msg);
+ session->msg = NULL;
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ return;
+ }
+}
+
+
+/**
+ * Send a multipart chunk of a service response from bob to alice.
+ * This element only contains the two permutations of R, R'.
+ *
+ * @param cls the associated service session
+ */
+static void
+prepare_bobs_cryptodata_message_multipart (void *cls)
+{
+ struct ServiceSession * session = cls;
+ struct GNUNET_CRYPTO_PaillierCiphertext * payload;
+ struct GNUNET_SCALARPRODUCT_multipart_message * msg;
+ unsigned int i;
+ unsigned int j;
+ uint32_t msg_length;
+ uint32_t todo_count;
+
+ msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
+ todo_count = session->used_elements_count - session->transferred_element_count;
+
+ if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2)
+ // send the currently possible maximum chunk, we always transfer both permutations
+ todo_count = MULTIPART_ELEMENT_CAPACITY / 2;
+
+ msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2;
+ msg = GNUNET_malloc (msg_length);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
+ msg->header.size = htons (msg_length);
+ msg->contained_element_count = htonl (todo_count);
+
+ payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
+ for (i = session->transferred_element_count, j = 0; i < session->transferred_element_count + todo_count; i++) {
+ //r[i][p] and r[i][q]
+ memcpy (&payload[j++], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ memcpy (&payload[j++], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ }
+ session->transferred_element_count += todo_count;
+ session->msg = (struct GNUNET_MessageHeader *) msg;
+ session->service_transmit_handle =
+ GNUNET_CADET_notify_transmit_ready (session->channel,
+ GNUNET_YES,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ msg_length,
+ &do_send_message,
+ session);
+ //disconnect our client
+ if (NULL == session->service_transmit_handle) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
+
+ GNUNET_free (msg);
+ session->msg = NULL;
+ GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
+
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session->response);
+ free_session_variables(session);
+ GNUNET_free(session);
+ return;
+ }
+ if (session->transferred_element_count != session->used_elements_count) {
+ // more multiparts
+ }
+ else {
+ // final part
+ GNUNET_free (session->r_prime);
+ GNUNET_free (session->r);
+ session->r_prime = NULL;
+ session->r = NULL;
+ }
}
/**
* Bob executes:
- * generates the response message to be sent to alice after computing
+ * generates the response message to be sent to alice after computing
* the values (1), (2), S and S'
* (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
* (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
* S: $S := E_A(sum (r_i + b_i)^2)$
* S': $S' := E_A(sum r_i^2)$
- *
- * @param r (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
- * @param r_prime (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
- * @param s S: $S := E_A(sum (r_i + b_i)^2)$
- * @param s_prime S': $S' := E_A(sum r_i^2)$
- * @param request the associated requesting session with alice
- * @param response the associated responder session with bob's client
- * @return GNUNET_SYSERR if the function was called with NULL parameters or if there was an error
- * GNUNET_NO if we could not send our message
- * GNUNET_OK if the operation succeeded
+ *
+ * @param session the associated requesting session with alice
*/
-static int
-prepare_service_response (gcry_mpi_t * r,
- gcry_mpi_t * r_prime,
- gcry_mpi_t s,
- gcry_mpi_t s_prime,
- struct ServiceSession * request,
- struct ServiceSession * response)
+static void
+prepare_bobs_cryptodata_message (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext
+ * tc)
{
+ struct ServiceSession * session = (struct ServiceSession *) cls;
struct GNUNET_SCALARPRODUCT_service_response * msg;
- uint16_t msg_length = 0;
- unsigned char * current = NULL;
- unsigned char * element_exported = NULL;
- size_t element_length = 0;
+ uint32_t msg_length = 0;
+ struct GNUNET_CRYPTO_PaillierCiphertext * payload;
int i;
msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
- + 2 * request->used_element_count * PAILLIER_ELEMENT_LENGTH // kp, kq
- + 2 * PAILLIER_ELEMENT_LENGTH; // s, stick
+ + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext); // s, stick
- msg = GNUNET_malloc (msg_length);
+ if (GNUNET_SERVER_MAX_MESSAGE_SIZE >
+ msg_length + 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)) { //r, r'
+ msg_length += 2 * session->used_elements_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+ session->transferred_element_count = session->used_elements_count;
+ }
+ else
+ session->transferred_element_count = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) /
+ (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * 2);
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_TO_ALICE);
+ msg = GNUNET_malloc (msg_length);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA);
msg->header.size = htons (msg_length);
- msg->element_count = htons (request->element_count);
- msg->used_element_count = htons (request->used_element_count);
- memcpy (&msg->key, &request->key, sizeof (struct GNUNET_HashCode));
- current = (unsigned char *) &msg[1];
-
- // 4 times the same logics with slight variations.
- // doesn't really justify having 2 functions for that
- // so i put it into blocks to enhance readability
- // convert s
- {
- element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
- GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
- element_exported, PAILLIER_ELEMENT_LENGTH,
- &element_length,
- s));
- adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
- memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
- GNUNET_free (element_exported);
- current += PAILLIER_ELEMENT_LENGTH;
- }
-
- // convert stick
- {
- element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
- GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
- element_exported, PAILLIER_ELEMENT_LENGTH,
- &element_length,
- s_prime));
- adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
- memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
- GNUNET_free (element_exported);
- current += PAILLIER_ELEMENT_LENGTH;
- }
-
- // convert kp[]
- for (i = 0; i < request->used_element_count; i++)
- {
- element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
- GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
- element_exported, PAILLIER_ELEMENT_LENGTH,
- &element_length,
- r[i]));
- adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
- memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
- GNUNET_free (element_exported);
- current += PAILLIER_ELEMENT_LENGTH;
- }
-
-
- // convert kq[]
- for (i = 0; i < request->used_element_count; i++)
- {
- element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
- GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
- element_exported, PAILLIER_ELEMENT_LENGTH,
- &element_length,
- r_prime[i]));
- adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
- memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
- GNUNET_free (element_exported);
- current += PAILLIER_ELEMENT_LENGTH;
- }
-
- if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= msg_length)
- {
- struct MessageObject * msg_obj;
-
- msg_obj = GNUNET_new (struct MessageObject);
- msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
- msg_obj->transmit_handle = (void *) &request->service_transmit_handle; //and reset the transmit handle
- request->service_transmit_handle =
- GNUNET_MESH_notify_transmit_ready (request->tunnel,
- GNUNET_YES,
- GNUNET_TIME_UNIT_FOREVER_REL,
- msg_length,
- &do_send_message,
- msg_obj);
- // we don't care if it could be send or not. either way, the session is over for us.
- request->state = FINALIZED;
- response->state = FINALIZED;
- }
- else
- {
- // TODO FEATURE: fallback to fragmentation, in case the message is too long
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!)\n"));
- }
+ msg->total_element_count = htonl (session->total);
+ msg->used_element_count = htonl (session->used_elements_count);
+ msg->contained_element_count = htonl (session->transferred_element_count);
+ memcpy (&msg->key, &session->session_id, sizeof (struct GNUNET_HashCode));
+
+ payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
+ memcpy (&payload[0], session->s, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ memcpy (&payload[1], session->s_prime, sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ GNUNET_free (session->s_prime);
+ session->s_prime = NULL;
+ GNUNET_free (session->s);
+ session->s = NULL;
+
+ payload = &payload[2];
+ // convert k[][]
+ for (i = 0; i < session->transferred_element_count; i++) {
+ //k[i][p] and k[i][q]
+ memcpy (&payload[i * 2], &session->r[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ memcpy (&payload[i * 2 + 1], &session->r_prime[i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ }
+ session->msg = (struct GNUNET_MessageHeader *) msg;
+ session->service_transmit_handle =
+ GNUNET_CADET_notify_transmit_ready (session->channel,
+ GNUNET_YES,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ msg_length,
+ &do_send_message,
+ session);
//disconnect our client
- if ( ! request->service_transmit_handle)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via mesh!)\n"));
-
- response->client_notification_task =
- GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
- response);
- return GNUNET_NO;
- }
- return GNUNET_OK;
+ if (NULL == session->service_transmit_handle) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via cadet!)\n"));
+
+ GNUNET_free (msg);
+ session->msg = NULL;
+ GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
+
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session->response);
+ free_session_variables(session);
+ GNUNET_free(session);
+ return;
+ }
+ if (session->transferred_element_count != session->used_elements_count) {
+ // multipart
+ }
+ else {
+ //singlepart
+ GNUNET_free (session->r);
+ session->r = NULL;
+ GNUNET_free (session->r_prime);
+ session->r_prime = NULL;
+ }
}
/**
- * executed by bob:
- * compute the values
- * (1)[]: $E_A(a_{\pi(i)}) \otimes E_A(- r_{\pi(i)} - b_{\pi(i)}) &= E_A(a_{\pi(i)} - r_{\pi(i)} - b_{\pi(i)})$
- * (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$
- * S: $S := E_A(\sum (r_i + b_i)^2)$
- * S': $S' := E_A(\sum r_i^2)$
- *
+ * executed by bob:
+ * compute the values
+ * (1)[]: $E_A(a_{pi(i)}) otimes E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$
+ * (2)[]: $E_A(a_{pi'(i)}) otimes E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$
+ * S: $S := E_A(sum (r_i + b_i)^2)$
+ * S': $S' := E_A(sum r_i^2)$
+ *
* @param request the requesting session + bob's requesting peer
- * @param response the responding session + bob's client handle
- * @return GNUNET_SYSERR if the computation failed
- * GNUNET_OK if everything went well.
*/
-static int
-compute_service_response (struct ServiceSession * request,
- struct ServiceSession * response)
+static void
+compute_service_response (struct ServiceSession * session)
{
int i;
- int j;
- int ret = GNUNET_SYSERR;
unsigned int * p;
unsigned int * q;
- uint16_t count;
+ uint32_t count;
gcry_mpi_t * rand = NULL;
- gcry_mpi_t * r = NULL;
- gcry_mpi_t * r_prime = NULL;
+ gcry_mpi_t tmp;
gcry_mpi_t * b;
- gcry_mpi_t * a_pi;
- gcry_mpi_t * a_pi_prime;
- gcry_mpi_t * b_pi;
- gcry_mpi_t * rand_pi;
- gcry_mpi_t * rand_pi_prime;
- gcry_mpi_t s = NULL;
- gcry_mpi_t s_prime = NULL;
- gcry_mpi_t remote_n = NULL;
- gcry_mpi_t remote_nsquare;
- gcry_mpi_t remote_g = NULL;
- gcry_sexp_t tmp_exp;
- uint32_t value;
-
- count = request->used_element_count;
-
- b = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
- a_pi = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
- b_pi = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
- a_pi_prime = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
- rand_pi = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
- rand_pi_prime = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
-
- // convert responder session to from long to mpi
- for (i = 0, j = 0; i < response->element_count && j < count; i++)
- {
- if (request->mask[i / 8] & (1 << (i % 8)))
- {
- value = response->vector[i] >= 0 ? response->vector[i] : -response->vector[i];
- // long to gcry_mpi_t
- if (0 > response->vector[i])
- {
- b[j] = gcry_mpi_new (0);
- gcry_mpi_sub_ui (b[j], b[j], value);
- }
- else
- {
- b[j] = gcry_mpi_set_ui (NULL, value);
- }
- j++;
- }
- }
- GNUNET_free (response->vector);
- response->vector = NULL;
-
- tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "n", 0);
- if ( ! tmp_exp)
- {
- GNUNET_break_op (0);
- gcry_sexp_release (request->remote_pubkey);
- request->remote_pubkey = NULL;
- goto except;
- }
- remote_n = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG);
- if ( ! remote_n)
- {
- GNUNET_break (0);
- gcry_sexp_release (tmp_exp);
- goto except;
- }
- remote_nsquare = gcry_mpi_new (KEYBITS + 1);
- gcry_mpi_mul (remote_nsquare, remote_n, remote_n);
- gcry_sexp_release (tmp_exp);
- tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "g", 0);
- gcry_sexp_release (request->remote_pubkey);
- request->remote_pubkey = NULL;
- if ( ! tmp_exp)
- {
- GNUNET_break_op (0);
- gcry_mpi_release (remote_n);
- goto except;
- }
- remote_g = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG);
- if ( ! remote_g)
- {
- GNUNET_break (0);
- gcry_mpi_release (remote_n);
- gcry_sexp_release (tmp_exp);
- goto except;
- }
- gcry_sexp_release (tmp_exp);
-
- // generate r, p and q
- rand = generate_random_vector (count);
- p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
+ struct GNUNET_CRYPTO_PaillierCiphertext * a;
+ struct GNUNET_CRYPTO_PaillierCiphertext * r;
+ struct GNUNET_CRYPTO_PaillierCiphertext * r_prime;
+ struct GNUNET_CRYPTO_PaillierCiphertext * s;
+ struct GNUNET_CRYPTO_PaillierCiphertext * s_prime;
+
+ count = session->used_elements_count;
+ a = session->e_a;
+ b = session->sorted_elements;
q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
- //initialize the result vectors
- r = initialize_mpi_vector (count);
- r_prime = initialize_mpi_vector (count);
-
- // copy the REFERNCES of a, b and r into aq and bq. we will not change
- // those values, thus we can work with the references
- memcpy (a_pi, request->a, sizeof (gcry_mpi_t) * count);
- memcpy (a_pi_prime, request->a, sizeof (gcry_mpi_t) * count);
- memcpy (b_pi, b, sizeof (gcry_mpi_t) * count);
- memcpy (rand_pi, rand, sizeof (gcry_mpi_t) * count);
- memcpy (rand_pi_prime, rand, sizeof (gcry_mpi_t) * count);
-
- // generate p and q permutations for a, b and r
- GNUNET_assert (permute_vector (a_pi, p, count));
- GNUNET_assert (permute_vector (b_pi, p, count));
- GNUNET_assert (permute_vector (rand_pi, p, count));
- GNUNET_assert (permute_vector (a_pi_prime, q, count));
- GNUNET_assert (permute_vector (rand_pi_prime, q, count));
+ p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
+
+ for (i = 0; i < count; i++)
+ GNUNET_assert (NULL != (rand[i] = gcry_mpi_new (0)));
+ r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
+ r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * count);
+ s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+
+ for (i = 0; i < count; i++) {
+ int32_t svalue;
+
+ svalue = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
+
+ // long to gcry_mpi_t
+ if (svalue < 0)
+ gcry_mpi_sub_ui (rand[i],
+ rand[i],
+ -svalue);
+ else
+ rand[i] = gcry_mpi_set_ui (rand[i], svalue);
+ }
+ tmp = gcry_mpi_new (0);
// encrypt the element
// for the sake of readability I decided to have dedicated permutation
- // vectors, which get rid of all the lookups in p/q.
+ // vectors, which get rid of all the lookups in p/q.
// however, ap/aq are not absolutely necessary but are just abstraction
// Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi)
- for (i = 0; i < count; i++)
- {
- // E(S - r_pi - b_pi)
- gcry_mpi_sub (r[i], my_offset, rand_pi[i]);
- gcry_mpi_sub (r[i], r[i], b_pi[i]);
- encrypt_element (r[i], r[i], remote_g, remote_n, remote_nsquare);
-
- // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
- gcry_mpi_mulm (r[i], r[i], a_pi[i], remote_nsquare);
- }
- GNUNET_free (a_pi);
- GNUNET_free (b_pi);
- GNUNET_free (rand_pi);
+ for (i = 0; i < count; i++) {
+ // E(S - r_pi - b_pi)
+ gcry_mpi_sub (tmp, my_offset, rand[p[i]]);
+ gcry_mpi_sub (tmp, tmp, b[p[i]]);
+ GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
+ tmp,
+ 2,
+ &r[i]);
+
+ // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b)
+ GNUNET_CRYPTO_paillier_hom_add (session->remote_pubkey,
+ &r[i],
+ &a[p[i]],
+ &r[i]);
+ }
// Calculate Kq = E(S + a_qi) (+) E(S - r_qi)
- for (i = 0; i < count; i++)
- {
- // E(S - r_qi)
- gcry_mpi_sub (r_prime[i], my_offset, rand_pi_prime[i]);
- encrypt_element (r_prime[i], r_prime[i], remote_g, remote_n, remote_nsquare);
-
- // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
- gcry_mpi_mulm (r_prime[i], r_prime[i], a_pi_prime[i], remote_nsquare);
- }
- GNUNET_free (a_pi_prime);
- GNUNET_free (rand_pi_prime);
+ for (i = 0; i < count; i++) {
+ // E(S - r_qi)
+ gcry_mpi_sub (tmp, my_offset, rand[q[i]]);
+ GNUNET_assert (2 == GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
+ tmp,
+ 2,
+ &r_prime[i]));
+
+ // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi)
+ GNUNET_assert (1 == GNUNET_CRYPTO_paillier_hom_add (session->remote_pubkey,
+ &r_prime[i],
+ &a[q[i]],
+ &r_prime[i]));
+ }
// Calculate S' = E(SUM( r_i^2 ))
- s_prime = compute_square_sum (rand, count);
- encrypt_element (s_prime, s_prime, remote_g, remote_n, remote_nsquare);
+ tmp = compute_square_sum (rand, count);
+ GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
+ tmp,
+ 1,
+ s_prime);
// Calculate S = E(SUM( (r_i + b_i)^2 ))
for (i = 0; i < count; i++)
- {
- gcry_mpi_add (rand[i], rand[i], b[i]);
- }
- s = compute_square_sum (rand, count);
- encrypt_element (s, s, remote_g, remote_n, remote_nsquare);
- gcry_mpi_release (remote_n);
- gcry_mpi_release (remote_g);
- gcry_mpi_release (remote_nsquare);
-
- // release r and tmp
- for (i = 0; i < count; i++)
- // rp, rq, aq, ap, bp, bq are released along with a, r, b respectively, (a and b are handled at except:)
+ gcry_mpi_add (rand[i], rand[i], b[i]);
+ tmp = compute_square_sum (rand, count);
+ GNUNET_CRYPTO_paillier_encrypt (session->remote_pubkey,
+ tmp,
+ 1,
+ s);
+
+ session->r = r;
+ session->r_prime = r_prime;
+ session->s = s;
+ session->s_prime = s_prime;
+
+ // release rand, b and a
+ for (i = 0; i < count; i++) {
gcry_mpi_release (rand[i]);
+ gcry_mpi_release (b[i]);
+ }
+ gcry_mpi_release (tmp);
+ GNUNET_free (session->e_a);
+ session->e_a = NULL;
+ GNUNET_free (p);
+ GNUNET_free (q);
+ GNUNET_free (b);
+ GNUNET_free (rand);
+
+ // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these
+ GNUNET_SCHEDULER_add_now (&prepare_bobs_cryptodata_message, session);
+}
- // copy the Kp[], Kq[], S and Stick into a new message
- if (GNUNET_YES != prepare_service_response (r, r_prime, s, s_prime, request, response))
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to communicate with `%s', scalar product calculation aborted.\n"),
- GNUNET_i2s (&request->peer));
+
+/**
+ * Iterator over all hash map entries in session->intersected_elements.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return #GNUNET_YES if we should continue to
+ * iterate,
+ * #GNUNET_NO if not.
+ */
+int
+cb_insert_element_sorted (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct ServiceSession * session = (struct ServiceSession*) cls;
+ struct SortedValue * e = GNUNET_new (struct SortedValue);
+ struct SortedValue * o = session->a_head;
+
+ e->elem = value;
+ e->val = gcry_mpi_new (0);
+ if (0 > e->elem->value)
+ gcry_mpi_sub_ui (e->val, e->val, abs (e->elem->value));
else
- ret = GNUNET_OK;
+ gcry_mpi_add_ui (e->val, e->val, e->elem->value);
- for (i = 0; i < count; i++)
- {
- gcry_mpi_release (r_prime[i]);
- gcry_mpi_release (r[i]);
+ // insert as first element with the lowest key
+ if (NULL == session->a_head
+ || (0 <= GNUNET_CRYPTO_hash_cmp (&session->a_head->elem->key, &e->elem->key))) {
+ GNUNET_CONTAINER_DLL_insert (session->a_head, session->a_tail, e);
+ return GNUNET_YES;
+ }
+ // insert as last element with the highest key
+ if (0 >= GNUNET_CRYPTO_hash_cmp (&session->a_tail->elem->key, &e->elem->key)) {
+ GNUNET_CONTAINER_DLL_insert_tail (session->a_head, session->a_tail, e);
+ return GNUNET_YES;
+ }
+ // insert before the first higher/equal element
+ do {
+ if (0 <= GNUNET_CRYPTO_hash_cmp (&o->elem->key, &e->elem->key)) {
+ GNUNET_CONTAINER_DLL_insert_before (session->a_head, session->a_tail, o, e);
+ return GNUNET_YES;
}
+ o = o->next;
+ }
+ while (NULL != o);
+ // broken DLL
+ GNUNET_assert (0);
+}
- gcry_mpi_release (s);
- gcry_mpi_release (s_prime);
-except:
- for (i = 0; i < count; i++)
- {
- gcry_mpi_release (b[i]);
- gcry_mpi_release (request->a[i]);
+/**
+ * Callback for set operation results. Called for each element
+ * in the result set.
+ *
+ * @param cls closure
+ * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
+ * @param status see `enum GNUNET_SET_Status`
+ */
+static void
+cb_intersection_element_removed (void *cls,
+ const struct GNUNET_SET_Element *element,
+ enum GNUNET_SET_Status status)
+{
+ struct ServiceSession * session = (struct ServiceSession*) cls;
+ struct GNUNET_SCALARPRODUCT_Element * se;
+ int i;
+
+ switch (status)
+ {
+ case GNUNET_SET_STATUS_OK:
+ //this element has been removed from the set
+ se = GNUNET_CONTAINER_multihashmap_get (session->intersected_elements,
+ element->data);
+
+ GNUNET_CONTAINER_multihashmap_remove (session->intersected_elements,
+ element->data,
+ se);
+ session->used_elements_count--;
+ return;
+
+ case GNUNET_SET_STATUS_DONE:
+ if (2 > session->used_elements_count) {
+ // failed! do not leak information about our single remaining element!
+ // continue after the loop
+ break;
}
- GNUNET_free (b);
- GNUNET_free (request->a);
- request->a = NULL;
+ GNUNET_CONTAINER_multihashmap_iterate (session->intersected_elements,
+ &cb_insert_element_sorted,
+ session);
+
+ session->sorted_elements = GNUNET_malloc (session->used_elements_count * sizeof (gcry_mpi_t));
+ for (i = 0; NULL != session->a_head; i++) {
+ struct SortedValue* a = session->a_head;
+ GNUNET_assert (i < session->used_elements_count);
+
+ session->sorted_elements[i] = a->val;
+ GNUNET_CONTAINER_DLL_remove (session->a_head, session->a_tail, a);
+ GNUNET_free (a->elem);
+ }
+ GNUNET_assert (i == session->used_elements_count);
- return ret;
+ if (ALICE == session->role) {
+ prepare_alices_cyrptodata_message (session);
+ return;
+ }
+ else if (session->used_elements_count == session->transferred_element_count) {
+ compute_service_response (session);
+ return;
+ }
+ default:
+ break;
+ }
+
+ //failed if we go here
+ GNUNET_break (0);
+
+ // and notify our client-session that we could not complete the session
+ if (ALICE == session->role) {
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ }
+ else {
+ GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
+ free_session_variables (session);
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session->response);
+ GNUNET_free(session);
+ }
}
/**
- * Executed by Alice, fills in a service-request message and sends it to the given peer
- *
- * @param session the session associated with this request, then also holds the CORE-handle
- * @return #GNUNET_SYSERR if we could not send the message
- * #GNUNET_NO if the message was too large
- * #GNUNET_OK if we sent it
+ * Called when another peer wants to do a set operation with the
+ * local peer. If a listen error occurs, the @a request is NULL.
+ *
+ * @param cls closure
+ * @param other_peer the other peer
+ * @param context_msg message with application specific information from
+ * the other peer
+ * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
+ * to accept it, otherwise the request will be refused
+ * Note that we can't just return value from the listen callback,
+ * as it is also necessary to specify the set we want to do the
+ * operation with, whith sometimes can be derived from the context
+ * message. It's necessary to specify the timeout.
+ */
+static void
+cb_intersection_request_alice (void *cls,
+ const struct GNUNET_PeerIdentity *other_peer,
+ const struct GNUNET_MessageHeader *context_msg,
+ struct GNUNET_SET_Request *request)
+{
+ struct ServiceSession * session = (struct ServiceSession *) cls;
+
+ // check the peer-id, the app-id=session-id is compared by SET
+ if (0 != memcmp (&session->peer, &other_peer, sizeof (struct GNUNET_PeerIdentity)))
+ return;
+
+ session->intersection_op = GNUNET_SET_accept (request,
+ GNUNET_SET_RESULT_REMOVED,
+ cb_intersection_element_removed,
+ session);
+
+ if (NULL == session->intersection_op) {
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ return;
+ }
+ if (GNUNET_OK != GNUNET_SET_commit (session->intersection_op, session->intersection_set)) {
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ return;
+ }
+ session->intersection_set = NULL;
+ session->intersection_listen = NULL;
+}
+
+
+/**
+ * prepare the response we will send to alice or bobs' clients.
+ * in Bobs case the product will be NULL.
+ *
+ * @param cls the session associated with our client.
+ * @param tc the task context handed to us by the scheduler, unused
*/
static void
-prepare_service_request (void *cls,
+prepare_client_response (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct ServiceSession * session = cls;
- unsigned char * current;
+ struct GNUNET_SCALARPRODUCT_client_response * msg;
+ unsigned char * product_exported = NULL;
+ size_t product_length = 0;
+ uint32_t msg_length = 0;
+ int8_t range = -1;
+ gcry_error_t rc;
+ int sign;
+
+ session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (session->product) {
+ gcry_mpi_t value = gcry_mpi_new (0);
+
+ sign = gcry_mpi_cmp_ui (session->product, 0);
+ // libgcrypt can not handle a print of a negative number
+ // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
+ if (0 > sign) {
+ gcry_mpi_sub (value, value, session->product);
+ }
+ else if (0 < sign) {
+ range = 1;
+ gcry_mpi_add (value, value, session->product);
+ }
+ else
+ range = 0;
+
+ gcry_mpi_release (session->product);
+ session->product = NULL;
+
+ // get representation as string
+ if (range
+ && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD,
+ &product_exported,
+ &product_length,
+ value)))) {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ product_length = 0;
+ range = -1; // signal error with product-length = 0 and range = -1
+ }
+ gcry_mpi_release (value);
+ }
+
+ msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) +product_length;
+ msg = GNUNET_malloc (msg_length);
+ msg->key = session->session_id;
+ msg->peer = session->peer;
+ if (product_exported != NULL) {
+ memcpy (&msg[1], product_exported, product_length);
+ GNUNET_free (product_exported);
+ }
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
+ msg->header.size = htons (msg_length);
+ msg->range = range;
+ msg->product_length = htonl (product_length);
+
+ session->msg = (struct GNUNET_MessageHeader *) msg;
+ //transmit this message to our client
+ session->client_transmit_handle =
+ GNUNET_SERVER_notify_transmit_ready (session->client,
+ msg_length,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_send_message,
+ session);
+ if (NULL == session->client_transmit_handle) {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _ ("Could not send message to client (%p)!\n"),
+ session->client);
+ session->client = NULL;
+ // callback was not called!
+ GNUNET_free (msg);
+ session->msg = NULL;
+ }
+ else
+ // gracefully sent message, just terminate session structure
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _ ("Sent result to client (%p), this session (%s) has ended!\n"),
+ session->client,
+ GNUNET_h2s (&session->session_id));
+ free_session_variables (session);
+}
+
+
+/**
+ * Executed by Alice, fills in a service-request message and sends it to the given peer
+ *
+ * @param session the session associated with this request
+ */
+static void
+prepare_alices_computation_request (struct ServiceSession * session)
+{
struct GNUNET_SCALARPRODUCT_service_request * msg;
- struct MessageObject * msg_obj;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new channel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
+
+ msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_service_request);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA);
+ msg->total_element_count = htonl (session->used_elements_count);
+ memcpy (&msg->session_id, &session->session_id, sizeof (struct GNUNET_HashCode));
+ msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_service_request));
+
+ session->msg = (struct GNUNET_MessageHeader *) msg;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
+
+ //transmit via cadet messaging
+ session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ sizeof (struct GNUNET_SCALARPRODUCT_service_request),
+ &do_send_message,
+ session);
+ if (!session->service_transmit_handle) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to channel!\n"));
+ GNUNET_free (msg);
+ session->msg = NULL;
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ return;
+ }
+}
+
+
+/**
+ * Send a multi part chunk of a service request from alice to bob.
+ * This element only contains a part of the elements-vector (session->a[]),
+ * mask and public key set have to be contained within the first message
+ *
+ * This allows a ~32kbit key length while using 32000 elements or 62000 elements per request.
+ *
+ * @param cls the associated service session
+ */
+static void
+prepare_alices_cyrptodata_message_multipart (void *cls)
+{
+ struct ServiceSession * session = cls;
+ struct GNUNET_SCALARPRODUCT_multipart_message * msg;
+ struct GNUNET_CRYPTO_PaillierCiphertext * payload;
unsigned int i;
- unsigned int j;
- uint16_t msg_length;
- size_t element_length = 0; //gets initialized by gcry_mpi_print, but the compiler doesn't know that
+ uint32_t msg_length;
+ uint32_t todo_count;
gcry_mpi_t a;
- uint32_t value;
-
- session->service_request_task = GNUNET_SCHEDULER_NO_TASK;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new tunnel to peer (%s)!\n"), GNUNET_i2s (&session->peer));
-
- msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_request)
- + session->used_element_count * PAILLIER_ELEMENT_LENGTH
- + session->mask_length
- + my_pubkey_external_length;
-
- if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (struct GNUNET_SCALARPRODUCT_service_request)
- + session->used_element_count * PAILLIER_ELEMENT_LENGTH
- + session->mask_length
- + my_pubkey_external_length)
- {
- // TODO FEATURE: fallback to fragmentation, in case the message is too long
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!\n"));
- session->client_notification_task =
- GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
- session);
- return;
- }
+
+ msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message);
+ todo_count = session->used_elements_count - session->transferred_element_count;
+
+ if (todo_count > MULTIPART_ELEMENT_CAPACITY)
+ // send the currently possible maximum chunk
+ todo_count = MULTIPART_ELEMENT_CAPACITY;
+
+ msg_length += todo_count * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
msg = GNUNET_malloc (msg_length);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART);
+ msg->header.size = htons (msg_length);
+ msg->contained_element_count = htonl (todo_count);
+
+ payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
+
+ // now copy over the sorted element vector
+ a = gcry_mpi_new (0);
+ for (i = session->transferred_element_count; i < todo_count; i++) {
+ gcry_mpi_add (a, session->sorted_elements[i], my_offset);
+ GNUNET_CRYPTO_paillier_encrypt (&my_pubkey, a, 3, &payload[i - session->transferred_element_count]);
+ }
+ gcry_mpi_release (a);
+ session->transferred_element_count += todo_count;
+
+ session->msg = (struct GNUNET_MessageHeader *) msg;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n"));
+
+ //transmit via cadet messaging
+ session->service_transmit_handle = GNUNET_CADET_notify_transmit_ready (session->channel, GNUNET_YES,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ msg_length,
+ &do_send_message,
+ session);
+ if (!session->service_transmit_handle) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-request multipart message to channel!\n"));
+ GNUNET_free (msg);
+ session->msg = NULL;
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ return;
+ }
+}
+
+
+/**
+ * Our client has finished sending us its multipart message.
+ *
+ * @param session the service session context
+ */
+static void
+client_request_complete_bob (struct ServiceSession * client_session)
+{
+ struct ServiceSession * session;
+
+ //check if service queue contains a matching request
+ session = find_matching_session (from_service_tail,
+ &client_session->session_id,
+ client_session->total, NULL);
+ if (NULL != session) {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"),
+ GNUNET_h2s (&client_session->session_id));
+
+ session->response = client_session;
+ session->intersected_elements = client_session->intersected_elements;
+ client_session->intersected_elements = NULL;
+ session->intersection_set = client_session->intersection_set;
+ client_session->intersection_set = NULL;
+
+ session->intersection_op = GNUNET_SET_prepare (&session->peer,
+ &session->session_id,
+ NULL,
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
+ GNUNET_SET_RESULT_REMOVED,
+ cb_intersection_element_removed,
+ session);
+
+ GNUNET_SET_commit (session->intersection_op, session->intersection_set);
+ }
+ else {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"),
+ GNUNET_h2s (&client_session->session_id));
+ // no matching session exists yet, store the response
+ // for later processing by handle_service_request()
+ }
+}
+
+
+/**
+ * Our client has finished sending us its multipart message.
+ *
+ * @param session the service session context
+ */
+static void
+client_request_complete_alice (struct ServiceSession * session)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _ ("Creating new channel for session with key %s.\n"),
+ GNUNET_h2s (&session->session_id));
+ session->channel = GNUNET_CADET_channel_create (my_cadet, session,
+ &session->peer,
+ GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
+ GNUNET_CADET_OPTION_RELIABLE);
+ if (NULL == session->channel) {
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ return;
+ }
+ session->intersection_listen = GNUNET_SET_listen (cfg,
+ GNUNET_SET_OPERATION_INTERSECTION,
+ &session->session_id,
+ cb_intersection_request_alice,
+ session);
+ if (NULL == session->intersection_listen) {
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ return;
+ }
+ prepare_alices_computation_request (session);
+}
+
+
+static void
+handle_client_message_multipart (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_SCALARPRODUCT_computation_message_multipart * msg = (const struct GNUNET_SCALARPRODUCT_computation_message_multipart *) message;
+ struct ServiceSession * session;
+ uint32_t contained_count;
+ struct GNUNET_SCALARPRODUCT_Element * elements;
+ uint32_t i;
+
+ // only one concurrent session per client connection allowed, simplifies logics a lot...
+ session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
+ if (NULL == session) {
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ contained_count = ntohl (msg->element_count_contained);
+
+ //sanity check: is the message as long as the message_count fields suggests?
+ if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message_multipart) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
+ || (0 == contained_count) || (session->total < session->transferred_element_count + contained_count)) {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ session->transferred_element_count += contained_count;
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB);
- memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
- msg->mask_length = htons (session->mask_length);
- msg->pk_length = htons (my_pubkey_external_length);
- msg->used_element_count = htons (session->used_element_count);
- msg->element_count = htons (session->element_count);
- msg->header.size = htons (msg_length);
+ elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
+ for (i = 0; i < contained_count; i++) {
+ struct GNUNET_SET_Element set_elem;
+ struct GNUNET_SCALARPRODUCT_Element * elem;
- // fill in the payload
- current = (unsigned char *) &msg[1];
- // copy over the mask
- memcpy (current, session->mask, session->mask_length);
- // copy over our public key
- current += session->mask_length;
- memcpy (current, my_pubkey_external, my_pubkey_external_length);
- current += my_pubkey_external_length;
-
- // now copy over the element vector
- session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * session->used_element_count);
- a = gcry_mpi_new (KEYBITS * 2);
- // encrypt our vector and generate string representations
- for (i = 0, j = 0; i < session->element_count; i++)
- {
- // if this is a used element...
- if (session->mask[i / 8] & 1 << (i % 8))
- {
- unsigned char * element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
- value = session->vector[i] >= 0 ? session->vector[i] : -session->vector[i];
-
- a = gcry_mpi_set_ui (a, 0);
- // long to gcry_mpi_t
- if (session->vector[i] < 0)
- gcry_mpi_sub_ui (a, a, value);
- else
- gcry_mpi_add_ui (a, a, value);
-
- session->a[j++] = gcry_mpi_set (NULL, a);
- gcry_mpi_add (a, a, my_offset);
- encrypt_element (a, a, my_g, my_n, my_nsquare);
-
- // get representation as string
- // we always supply some value, so gcry_mpi_print fails only if it can't reserve memory
- GNUNET_assert ( ! gcry_mpi_print (GCRYMPI_FMT_USG,
- element_exported, PAILLIER_ELEMENT_LENGTH,
- &element_length,
- a));
-
- // move buffer content to the end of the buffer so it can easily be read by libgcrypt. also this now has fixed size
- adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
-
- // copy over to the message
- memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
- current += PAILLIER_ELEMENT_LENGTH;
- }
- }
- gcry_mpi_release (a);
+ if (0 == ntohl (elements[i].value))
+ continue;
- msg_obj = GNUNET_new (struct MessageObject);
- msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
- msg_obj->transmit_handle = (void *) &session->service_transmit_handle; //and reset the transmit handle
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting service request.\n"));
+ elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
+ memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
- //transmit via mesh messaging
- session->state = WAITING_FOR_RESPONSE_FROM_SERVICE;
- session->service_transmit_handle = GNUNET_MESH_notify_transmit_ready (session->tunnel, GNUNET_YES,
- GNUNET_TIME_UNIT_FOREVER_REL,
- msg_length,
- &do_send_message,
- msg_obj);
- if ( ! session->service_transmit_handle)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not send mutlicast message to tunnel!\n"));
- GNUNET_free (msg_obj);
- GNUNET_free (msg);
- session->client_notification_task =
- GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
- session);
+ if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
+ &elem->key,
+ elem,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
+ GNUNET_free (elem);
+ continue;
}
+ set_elem.data = &elements[i].key;
+ set_elem.size = htons (sizeof (elements[i].key));
+ set_elem.type = htons (0); /* do we REALLY need this? */
+ GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
+ session->used_elements_count++;
+ }
+
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+
+ if (session->total != session->transferred_element_count)
+ // multipart msg
+ return;
+
+ if (ALICE == session->role)
+ client_request_complete_alice (session);
+ else
+ client_request_complete_bob (session);
}
+
/**
- * Handler for a client request message.
+ * Handler for a client request message.
* Can either be type A or B
* A: request-initiation to compute a scalar product with a peer
- * B: response role, keep the values + session and wait for a matching session or process a waiting request
+ * B: response role, keep the values + session and wait for a matching session or process a waiting request
*
* @param cls closure
* @param client identification of the client
* @param message the actual message
*/
static void
-handle_client_request (void *cls,
+handle_client_message (void *cls,
struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
- const struct GNUNET_SCALARPRODUCT_client_request * msg = (const struct GNUNET_SCALARPRODUCT_client_request *) message;
+ const struct GNUNET_SCALARPRODUCT_computation_message * msg = (const struct GNUNET_SCALARPRODUCT_computation_message *) message;
struct ServiceSession * session;
- uint16_t element_count;
- uint16_t mask_length;
- uint16_t msg_type;
- int32_t * vector;
+ uint32_t contained_count;
+ uint32_t total_count;
+ uint32_t msg_type;
+ struct GNUNET_SCALARPRODUCT_Element * elements;
uint32_t i;
- GNUNET_SERVER_client_get_user_context (client, session);
- if ((NULL != session) && (session->state != FINALIZED)){
- // only one concurrent session per client connection allowed
+ // only one concurrent session per client connection allowed, simplifies logics a lot...
+ session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession);
+ if (NULL != session) {
GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
- else if(NULL != session){
- // old session is already completed, clean it up
- GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
- free_session(session);
- }
-
- //we need at least a peer and one message id to compare
- if (sizeof (struct GNUNET_SCALARPRODUCT_client_request) > ntohs (msg->header.size))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _ ("Too short message received from client!\n"));
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
msg_type = ntohs (msg->header.type);
- element_count = ntohs (msg->element_count);
- mask_length = ntohs (msg->mask_length);
+ total_count = ntohl (msg->element_count_total);
+ contained_count = ntohl (msg->element_count_contained);
+
+ if ((GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
+ && (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))) {
+ //session with ourself makes no sense!
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
//sanity check: is the message as long as the message_count fields suggests?
- if (( ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_client_request) + element_count * sizeof (int32_t) + mask_length))
- || (0 == element_count))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _ ("Invalid message received from client, session information incorrect!\n"));
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
+ if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_computation_message) +contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element)))
+ || (0 == total_count)) {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
// do we have a duplicate session here already?
if (NULL != find_matching_session (from_client_tail,
- &msg->key,
- element_count,
- NULL, NULL))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _ ("Duplicate session information received, cannot create new session with key `%s'\n"),
- GNUNET_h2s (&msg->key));
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
+ &msg->session_key,
+ total_count, NULL)) {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _ ("Duplicate session information received, can not create new session with key `%s'\n"),
+ GNUNET_h2s (&msg->session_key));
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
session = GNUNET_new (struct ServiceSession);
- //FIXME: this actually should not happen here!
- GNUNET_SERVER_client_set_user_context (client, session);
- session->service_request_task = GNUNET_SCHEDULER_NO_TASK;
session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
session->client = client;
- session->element_count = element_count;
- session->mask_length = mask_length;
+ session->total = total_count;
+ session->transferred_element_count = contained_count;
// get our transaction key
- memcpy (&session->key, &msg->key, sizeof (struct GNUNET_HashCode));
- //allocate memory for vector and encrypted vector
- session->vector = GNUNET_malloc (sizeof (int32_t) * element_count);
- vector = (int32_t *) & msg[1];
-
- if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _ ("Got client-request-session with key %s, preparing tunnel to remote service.\n"),
- GNUNET_h2s (&session->key));
-
- session->role = ALICE;
- // fill in the mask
- session->mask = GNUNET_malloc (mask_length);
- memcpy (session->mask, &vector[element_count], mask_length);
-
- // copy over the elements
- session->used_element_count = 0;
- for (i = 0; i < element_count; i++)
- {
- session->vector[i] = ntohl (vector[i]);
- if (session->vector[i] == 0)
- session->mask[i / 8] &= ~(1 << (i % 8));
- if (session->mask[i / 8] & (1 << (i % 8)))
- session->used_element_count++;
- }
-
- if ( ! session->used_element_count)
- {
- GNUNET_break_op (0);
- GNUNET_free (session->vector);
- GNUNET_free (session->a);
- GNUNET_free (session);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- //session with ourself makes no sense!
- if ( ! memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_break (0);
- GNUNET_free (session->vector);
- GNUNET_free (session->a);
- GNUNET_free (session);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- // get our peer ID
- memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _ ("Creating new tunnel to for session with key %s.\n"),
- GNUNET_h2s (&session->key));
- GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
- session->tunnel = GNUNET_MESH_tunnel_create (my_mesh, session,
- &session->peer,
- GNUNET_APPLICATION_TYPE_SCALARPRODUCT,
- GNUNET_NO,
- GNUNET_YES);
- //prepare_service_request, tunnel_peer_disconnect_handler,
- if ( ! session->tunnel)
- {
- GNUNET_break (0);
- GNUNET_free (session->vector);
- GNUNET_free (session->a);
- GNUNET_free (session);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- session->state = WAITING_FOR_BOBS_CONNECT;
-
- session->service_request_task =
- GNUNET_SCHEDULER_add_now (&prepare_service_request,
- session);
-
- }
- else
- {
- struct ServiceSession * requesting_session;
- enum SessionState needed_state = REQUEST_FROM_SERVICE_RECEIVED;
-
- session->role = BOB;
- session->mask = NULL;
- // copy over the elements
- session->used_element_count = element_count;
- for (i = 0; i < element_count; i++)
- session->vector[i] = ntohl (vector[i]);
- session->state = MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED;
-
- GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
- //check if service queue contains a matching request
- requesting_session = find_matching_session (from_service_tail,
- &session->key,
- session->element_count,
- &needed_state, NULL);
- if (NULL != requesting_session)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"), GNUNET_h2s (&session->key));
- if (GNUNET_OK != compute_service_response (requesting_session, session))
- session->client_notification_task =
- GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
- session);
-
- }
- else{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"), GNUNET_h2s (&session->key));
- // no matching session exists yet, store the response
- // for later processing by handle_service_request()
- }
+ memcpy (&session->session_id, &msg->session_key, sizeof (struct GNUNET_HashCode));
+
+ elements = (struct GNUNET_SCALARPRODUCT_Element *) & msg[1];
+ session->intersected_elements = GNUNET_CONTAINER_multihashmap_create (session->total, GNUNET_NO);
+ session->intersection_set = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_INTERSECTION);
+ for (i = 0; i < contained_count; i++) {
+ struct GNUNET_SET_Element set_elem;
+ struct GNUNET_SCALARPRODUCT_Element * elem;
+
+ if (0 == ntohl (elements[i].value))
+ continue;
+
+ elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
+ memcpy (elem, &elements[i], sizeof (struct GNUNET_SCALARPRODUCT_Element));
+
+ if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (session->intersected_elements,
+ &elem->key,
+ elem,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) {
+ GNUNET_free (elem);
+ continue;
}
+ set_elem.data = &elements[i].key;
+ set_elem.size = htons (sizeof (elements[i].key));
+ set_elem.type = htons (0); /* do we REALLY need this? */
+ GNUNET_SET_add_element (session->intersection_set, &set_elem, NULL, NULL);
+ session->used_elements_count++;
+ }
+
+ if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) {
+ session->role = ALICE;
+ memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
+ }
+ else {
+ session->role = BOB;
+ }
+
+ GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
+ GNUNET_SERVER_client_set_user_context (client, session);
GNUNET_SERVER_receive_done (client, GNUNET_YES);
+
+ if (session->total != session->transferred_element_count)
+ // multipart msg
+ return;
+
+ if (ALICE == session->role)
+ client_request_complete_alice (session);
+ else
+ client_request_complete_bob (session);
}
/**
- * Function called for inbound tunnels.
+ * Function called for inbound channels.
*
* @param cls closure
- * @param tunnel new handle to the tunnel
- * @param initiator peer that started the tunnel
- * @param atsi performance information for the tunnel
- * @return initial tunnel context for the tunnel
- * (can be NULL -- that's not an error)
+ * @param channel new handle to the channel
+ * @param initiator peer that started the channel
+ * @param port unused
+ * @param options unused
+ *
+ * @return session associated with the channel
*/
static void *
-tunnel_incoming_handler (void *cls,
- struct GNUNET_MESH_Tunnel *tunnel,
- const struct GNUNET_PeerIdentity *initiator,
- uint32_t port)
+cb_channel_incoming (void *cls,
+ struct GNUNET_CADET_Channel *channel,
+ const struct GNUNET_PeerIdentity *initiator,
+ uint32_t port, enum GNUNET_CADET_ChannelOption options)
{
struct ServiceSession * c = GNUNET_new (struct ServiceSession);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _ ("New incoming channel from peer %s.\n"),
+ GNUNET_i2s (initiator));
+
c->peer = *initiator;
- c->tunnel = tunnel;
+ c->channel = channel;
c->role = BOB;
return c;
}
/**
- * Function called whenever a tunnel is destroyed. Should clean up
- * any associated state.
- *
- * It must NOT call GNUNET_MESH_tunnel_destroy on the tunnel.
+ * Function called whenever a channel is destroyed. Should clean up
+ * any associated state.
+ *
+ * It must NOT call GNUNET_CADET_channel_destroy on the channel.
*
- * @param cls closure (set from GNUNET_MESH_connect)
- * @param tunnel connection to the other end (henceforth invalid)
- * @param tunnel_ctx place where local state associated
- * with the tunnel is stored
+ * @param cls closure (set from GNUNET_CADET_connect)
+ * @param channel connection to the other end (henceforth invalid)
+ * @param channel_ctx place where local state associated
+ * with the channel is stored
*/
static void
-tunnel_destruction_handler (void *cls,
- const struct GNUNET_MESH_Tunnel *tunnel,
- void *tunnel_ctx)
+cb_channel_destruction (void *cls,
+ const struct GNUNET_CADET_Channel *channel,
+ void *channel_ctx)
{
- struct ServiceSession * session = tunnel_ctx;
+ struct ServiceSession * session = channel_ctx;
struct ServiceSession * client_session;
struct ServiceSession * curr;
-
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Peer disconnected, terminating session %s with peer (%s)\n"),
- GNUNET_h2s (&session->key),
- GNUNET_i2s (&session->peer));
+ _ ("Peer disconnected, terminating session %s with peer (%s)\n"),
+ GNUNET_h2s (&session->session_id),
+ GNUNET_i2s (&session->peer));
if (ALICE == session->role) {
// as we have only one peer connected in each session, just remove the session
- if ((FINALIZED != session->state) && (!do_shutdown))
- {
- session->tunnel = NULL;
+ if ((0/*//TODO: only for complete session*/) && (!do_shutdown)) {
+ session->channel = NULL;
// if this happened before we received the answer, we must terminate the session
- session->client_notification_task =
+ session->client_notification_task =
GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
session);
}
}
else { //(BOB == session->role) service session
-
// remove the session, unless it has already been dequeued, but somehow still active
// this could bug without the IF in case the queue is empty and the service session was the only one know to the service
// scenario: disconnect before alice can send her message to bob.
for (curr = from_service_head; NULL != curr; curr = curr->next)
- if (curr == session)
- {
+ if (curr == session) {
GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, curr);
break;
}
// there is a client waiting for this service session, terminate it, too!
// i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
client_session = find_matching_session (from_client_tail,
- &session->key,
- session->element_count,
- NULL, NULL);
- free_session (session);
+ &session->session_id,
+ session->total, NULL);
+ free_session_variables (session);
+ GNUNET_free (session);
- // the client has to check if it was waiting for a result
+ // the client has to check if it was waiting for a result
// or if it was a responder, no point in adding more statefulness
- if (client_session && (!do_shutdown))
- {
- client_session->client_notification_task =
+ if (client_session && (!do_shutdown)) {
+ client_session->client_notification_task =
GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
client_session);
}
/**
* Compute our scalar product, done by Alice
- *
+ *
* @param session - the session associated with this computation
- * @param kp - (1) from the protocol definition:
- * $E_A(a_{\pi(i)}) \otimes E_A(- r_{\pi(i)} - b_{\pi(i)}) &= E_A(a_{\pi(i)} - r_{\pi(i)} - b_{\pi(i)})$
- * @param kq - (2) from the protocol definition:
- * $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$
- * @param s - S from the protocol definition:
- * $S := E_A(\sum (r_i + b_i)^2)$
- * @param stick - S' from the protocol definition:
- * $S' := E_A(\sum r_i^2)$
* @return product as MPI, never NULL
*/
static gcry_mpi_t
-compute_scalar_product (struct ServiceSession * session,
- gcry_mpi_t * r, gcry_mpi_t * r_prime, gcry_mpi_t s, gcry_mpi_t s_prime)
+compute_scalar_product (struct ServiceSession * session)
{
- uint16_t count;
+ uint32_t count;
gcry_mpi_t t;
gcry_mpi_t u;
- gcry_mpi_t utick;
+ gcry_mpi_t u_prime;
gcry_mpi_t p;
- gcry_mpi_t ptick;
+ gcry_mpi_t p_prime;
gcry_mpi_t tmp;
+ gcry_mpi_t r[session->used_elements_count];
+ gcry_mpi_t r_prime[session->used_elements_count];
+ gcry_mpi_t s;
+ gcry_mpi_t s_prime;
unsigned int i;
- count = session->used_element_count;
- tmp = gcry_mpi_new (KEYBITS);
+ count = session->used_elements_count;
// due to the introduced static offset S, we now also have to remove this
// from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each,
// the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi)
- for (i = 0; i < count; i++)
- {
- decrypt_element (r[i], r[i], my_mu, my_lambda, my_n, my_nsquare);
- gcry_mpi_sub(r[i],r[i],my_offset);
- gcry_mpi_sub(r[i],r[i],my_offset);
- decrypt_element (r_prime[i], r_prime[i], my_mu, my_lambda, my_n, my_nsquare);
- gcry_mpi_sub(r_prime[i],r_prime[i],my_offset);
- gcry_mpi_sub(r_prime[i],r_prime[i],my_offset);
- }
+ for (i = 0; i < count; i++) {
+ GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
+ &session->r[i], r[i]);
+ gcry_mpi_sub (r[i], r[i], my_offset);
+ gcry_mpi_sub (r[i], r[i], my_offset);
+ GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
+ &session->r_prime[i], r_prime[i]);
+ gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
+ gcry_mpi_sub (r_prime[i], r_prime[i], my_offset);
+ }
// calculate t = sum(ai)
- t = compute_square_sum (session->a, count);
+ t = compute_square_sum (session->sorted_elements, count);
// calculate U
u = gcry_mpi_new (0);
gcry_mpi_release (tmp);
//calculate U'
- utick = gcry_mpi_new (0);
+ u_prime = gcry_mpi_new (0);
tmp = compute_square_sum (r_prime, count);
- gcry_mpi_sub (utick, utick, tmp);
+ gcry_mpi_sub (u_prime, u_prime, tmp);
GNUNET_assert (p = gcry_mpi_new (0));
- GNUNET_assert (ptick = gcry_mpi_new (0));
+ GNUNET_assert (p_prime = gcry_mpi_new (0));
+ GNUNET_assert (s = gcry_mpi_new (0));
+ GNUNET_assert (s_prime = gcry_mpi_new (0));
// compute P
- decrypt_element (s, s, my_mu, my_lambda, my_n, my_nsquare);
- decrypt_element (s_prime, s_prime, my_mu, my_lambda, my_n, my_nsquare);
-
+ GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
+ session->s, s);
+ GNUNET_CRYPTO_paillier_decrypt (&my_privkey, &my_pubkey,
+ session->s_prime, s_prime);
+
// compute P
gcry_mpi_add (p, s, t);
gcry_mpi_add (p, p, u);
// compute P'
- gcry_mpi_add (ptick, s_prime, t);
- gcry_mpi_add (ptick, ptick, utick);
+ gcry_mpi_add (p_prime, s_prime, t);
+ gcry_mpi_add (p_prime, p_prime, u_prime);
gcry_mpi_release (t);
gcry_mpi_release (u);
- gcry_mpi_release (utick);
+ gcry_mpi_release (u_prime);
+ gcry_mpi_release (s);
+ gcry_mpi_release (s_prime);
// compute product
- gcry_mpi_sub (p, p, ptick);
- gcry_mpi_release (ptick);
+ gcry_mpi_sub (p, p, p_prime);
+ gcry_mpi_release (p_prime);
tmp = gcry_mpi_set_ui (tmp, 2);
gcry_mpi_div (p, NULL, p, tmp, 0);
gcry_mpi_release (tmp);
- for (i = 0; i < count; i++)
- gcry_mpi_release (session->a[i]);
- GNUNET_free (session->a);
- session->a = NULL;
-
+ for (i = 0; i < count; i++) {
+ gcry_mpi_release (session->sorted_elements[i]);
+ gcry_mpi_release (r[i]);
+ gcry_mpi_release (r_prime[i]);
+ }
+ GNUNET_free (session->a_head);
+ session->a_head = NULL;
+ GNUNET_free (session->s);
+ session->s = NULL;
+ GNUNET_free (session->s_prime);
+ session->s_prime = NULL;
+ GNUNET_free (session->r);
+ session->r = NULL;
+ GNUNET_free (session->r_prime);
+ session->r_prime = NULL;
+
return p;
}
/**
- * prepare the response we will send to alice or bobs' clients.
- * in Bobs case the product will be NULL.
- *
- * @param session the session associated with our client.
+ * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us.
+ *
+ * @param cls closure (set from #GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
+ * @param message the actual message
+ * @return #GNUNET_OK to keep the connection open,
+ * #GNUNET_SYSERR to close it (signal serious error)
*/
-static void
-prepare_client_response (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+static int
+handle_alices_cyrptodata_message_multipart (void *cls,
+ struct GNUNET_CADET_Channel * channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader * message)
{
- struct ServiceSession * session = cls;
- struct GNUNET_SCALARPRODUCT_client_response * msg;
- unsigned char * product_exported = NULL;
- size_t product_length = 0;
- uint16_t msg_length = 0;
- struct MessageObject * msg_obj;
- int8_t range = -1;
- gcry_error_t rc;
- int sign;
-
- session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
+ struct ServiceSession * session;
+ const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
+ struct GNUNET_CRYPTO_PaillierCiphertext *payload;
+ uint32_t contained_elements;
+ uint32_t msg_length;
+
+ // are we in the correct state?
+ session = (struct ServiceSession *) * channel_ctx;
+ //we are not bob
+ if ((NULL == session->e_a) || //or we did not expect this message yet
+ (session->used_elements_count == session->transferred_element_count)) { //we are not expecting multipart messages
+ goto except;
+ }
+ // shorter than minimum?
+ if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
+ goto except;
+ }
+ contained_elements = ntohl (msg->contained_element_count);
+ msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
+ +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+ //sanity check
+ if ((ntohs (msg->header.size) != msg_length)
+ || (session->used_elements_count < contained_elements + session->transferred_element_count)
+ || (0 == contained_elements)) {
+ goto except;
+ }
+ payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
+ // Convert each vector element to MPI_value
+ memcpy (&session->e_a[session->transferred_element_count], payload,
+ sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * contained_elements);
+
+ session->transferred_element_count += contained_elements;
+
+ if (contained_elements == session->used_elements_count) {
+ // single part finished
+ if (NULL == session->intersection_op)
+ // intersection has already finished, so we can proceed
+ compute_service_response (session);
+ }
- if (session->product)
- {
- gcry_mpi_t value = gcry_mpi_new(0);
-
- sign = gcry_mpi_cmp_ui(session->product, 0);
- // libgcrypt can not handle a print of a negative number
- if (0 > sign){
- gcry_mpi_sub(value, value, session->product);
- }
- else if(0 < sign){
- range = 1;
- gcry_mpi_add(value, value, session->product);
- }
- else
- range = 0;
-
- // get representation as string
- // unfortunately libgcrypt is too stupid to implement print-support in
- // signed GCRYMPI_FMT_STD format, and simply asserts in that case.
- // here is the associated sourcecode:
- // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */
- if (range
- && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_USG,
- &product_exported,
- &product_length,
- session->product)))){
- LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
- product_length = 0;
- range = -1; // signal error with product-length = 0 and range = -1
- }
-
- gcry_mpi_release (session->product);
- session->product = NULL;
- }
+ return GNUNET_OK;
+except:
+ session->channel = NULL;
+ // and notify our client-session that we could not complete the session
+ free_session_variables (session);
+ if (NULL != session->client){
+ //Alice
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ }
+ else {
+ //Bob
+ if (NULL != session->response)
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session->response);
+ GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
+ GNUNET_free(session);
+ }
+ return GNUNET_SYSERR;
+}
- msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) + product_length;
- msg = GNUNET_malloc (msg_length);
- memcpy (&msg[1], product_exported, product_length);
- GNUNET_free_non_null (product_exported);
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT);
- msg->header.size = htons (msg_length);
- msg->range = range;
- memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
- memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
- msg->product_length = htonl (product_length);
-
- msg_obj = GNUNET_new (struct MessageObject);
- msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
- msg_obj->transmit_handle = NULL; // don't reset the transmit handle
- //transmit this message to our client
- session->client_transmit_handle =
- GNUNET_SERVER_notify_transmit_ready (session->client,
- msg_length,
- GNUNET_TIME_UNIT_FOREVER_REL,
- &do_send_message,
- msg_obj);
- if ( ! session->client_transmit_handle)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _ ("Could not send message to client (%p)! This probably is OK if the client disconnected before us.\n"),
- session->client);
- session->client = NULL;
- // callback was not called!
- GNUNET_free (msg_obj);
- GNUNET_free (msg);
- }
- else
- // gracefully sent message, just terminate session structure
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _ ("Sent result to client (%p), this session (%s) has ended!\n"),
- session->client,
- GNUNET_h2s (&session->key));
+/**
+ * Handle a request from another service to calculate a scalarproduct with us.
+ *
+ * @param cls closure (set from #GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
+ * @param message the actual message
+ * @return #GNUNET_OK to keep the connection open,
+ * #GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_alices_cyrptodata_message (void *cls,
+ struct GNUNET_CADET_Channel * channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader * message)
+{
+ struct ServiceSession * session;
+ const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message * msg = (const struct GNUNET_SCALARPRODUCT_alices_cryptodata_message *) message;
+ struct GNUNET_CRYPTO_PaillierCiphertext *payload;
+ uint32_t contained_elements = 0;
+ uint32_t msg_length;
+
+ session = (struct ServiceSession *) * channel_ctx;
+ //we are not bob
+ if ((BOB != session->role)
+ //we are expecting multipart messages instead
+ || (NULL != session->e_a)
+ //or we did not expect this message yet
+ || //intersection OP has not yet finished
+ !((NULL != session->intersection_op)
+ //intersection OP done
+ || (session->response->sorted_elements)
+ )) {
+ goto invalid_msg;
+ }
+
+ // shorter than minimum?
+ if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) {
+ goto invalid_msg;
+ }
+
+ contained_elements = ntohl (msg->contained_element_count);
+ msg_length = sizeof (struct GNUNET_SCALARPRODUCT_alices_cryptodata_message)
+ +contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+
+ //sanity check: is the message as long as the message_count fields suggests?
+ if ((ntohs (msg->header.size) != msg_length) ||
+ (session->used_elements_count < session->transferred_element_count + contained_elements) ||
+ (0 == contained_elements)) {
+ goto invalid_msg;
+ }
+
+ session->transferred_element_count = contained_elements;
+ payload = (struct GNUNET_CRYPTO_PaillierCiphertext*) &msg[1];
+
+ session->e_a = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
+ memcpy (&session->e_a[0], payload, contained_elements * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ if (contained_elements == session->used_elements_count) {
+ // single part finished
+ if (NULL == session->intersection_op)
+ // intersection has already finished, so we can proceed
+ compute_service_response (session);
+ }
+ return GNUNET_OK;
+invalid_msg:
+ GNUNET_break_op (0);
+ session->channel = NULL;
+ // and notify our client-session that we could not complete the session
+ free_session_variables (session);
+ if (NULL != session->client){
+ //Alice
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ }
+ else {
+ //Bob
+ if (NULL != session->response)
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session->response);
+ GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
+ GNUNET_free(session);
+ }
+ return GNUNET_SYSERR;
}
/**
* Handle a request from another service to calculate a scalarproduct with us.
*
- * @param cls closure (set from #GNUNET_MESH_connect)
- * @param tunnel connection to the other end
- * @param tunnel_ctx place to store local state associated with the tunnel
- * @param sender who sent the message
+ * @param cls closure (set from #GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
* @param message the actual message
- * @param atsi performance data for the connection
* @return #GNUNET_OK to keep the connection open,
* #GNUNET_SYSERR to close it (signal serious error)
*/
static int
-handle_service_request (void *cls,
- struct GNUNET_MESH_Tunnel * tunnel,
- void **tunnel_ctx,
+handle_alices_computation_request (void *cls,
+ struct GNUNET_CADET_Channel * channel,
+ void **channel_ctx,
const struct GNUNET_MessageHeader * message)
{
struct ServiceSession * session;
+ struct ServiceSession * client_session;
const struct GNUNET_SCALARPRODUCT_service_request * msg = (const struct GNUNET_SCALARPRODUCT_service_request *) message;
- uint16_t mask_length;
- uint16_t pk_length;
- uint16_t used_elements;
- uint16_t element_count;
- uint16_t msg_length;
- unsigned char * current;
- struct ServiceSession * responder_session;
- int32_t i = -1;
- enum SessionState needed_state;
-
- session = (struct ServiceSession *) * tunnel_ctx;
- if (BOB != session->role){
- GNUNET_break_op(0);
- return GNUNET_SYSERR;
+ uint32_t total_elements;
+
+ session = (struct ServiceSession *) * channel_ctx;
+ if (session->total != 0) {
+ // must be a fresh session
+ goto invalid_msg;
}
- // is this tunnel already in use?
- if ( (session->next) || (from_service_head == session))
- {
- GNUNET_break_op(0);
- return GNUNET_SYSERR;
- }
// Check if message was sent by me, which would be bad!
- if ( ! memcmp (&session->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_break (0);
- GNUNET_free (session);
- return GNUNET_SYSERR;
- }
-
- //we need at least a peer and one message id to compare
- if (ntohs (msg->header.size) < sizeof (struct GNUNET_SCALARPRODUCT_service_request))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Too short message received from peer!\n"));
- GNUNET_free (session);
- return GNUNET_SYSERR;
- }
- mask_length = ntohs (msg->mask_length);
- pk_length = ntohs (msg->pk_length);
- used_elements = ntohs (msg->used_element_count);
- element_count = ntohs (msg->element_count);
- msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_request)
- + mask_length + pk_length + used_elements * PAILLIER_ELEMENT_LENGTH;
+ if (!memcmp (&session->peer, &me, sizeof (struct GNUNET_PeerIdentity))) {
+ GNUNET_free (session);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ // shorter than expected?
+ if (ntohs (msg->header.size) != sizeof (struct GNUNET_SCALARPRODUCT_service_request)) {
+ GNUNET_free (session);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ total_elements = ntohl (msg->total_element_count);
//sanity check: is the message as long as the message_count fields suggests?
- if ((ntohs (msg->header.size) != msg_length) || (element_count < used_elements)
- || (used_elements == 0) || (mask_length != (element_count / 8 + (element_count % 8 ? 1 : 0)))
- )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid message received from peer, message count does not match message length!\n"));
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Used elements: %hu\nElement Count: %hu\nExpected Mask Length: %hu\nCalculated Masklength: %d\n"), used_elements, element_count, mask_length, (element_count / 8 + (element_count % 8 ? 1 : 0)));
- GNUNET_free (session);
- return GNUNET_SYSERR;
- }
+ if (1 > total_elements) {
+ GNUNET_free (session);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
if (find_matching_session (from_service_tail,
- &msg->key,
- element_count,
- NULL,
- NULL))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"), (const char *) &(msg->key));
- GNUNET_free (session);
- return GNUNET_SYSERR;
- }
-
- memcpy (&session->peer, &session->peer, sizeof (struct GNUNET_PeerIdentity));
- session->state = REQUEST_FROM_SERVICE_RECEIVED;
- session->element_count = ntohs (msg->element_count);
- session->used_element_count = used_elements;
- session->tunnel = tunnel;
+ &msg->session_id,
+ total_elements,
+ NULL)) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"),
+ (const char *) &(msg->session_id));
+ GNUNET_free (session);
+ return GNUNET_SYSERR;
+ }
+
+ session->total = total_elements;
+ session->channel = channel;
// session key
- memcpy (&session->key, &msg->key, sizeof (struct GNUNET_HashCode));
- current = (unsigned char *) &msg[1];
- //preserve the mask, we will need that later on
- session->mask = GNUNET_malloc (mask_length);
- memcpy (session->mask, current, mask_length);
- //the public key
- current += mask_length;
-
- //convert the publickey to sexp
- if (gcry_sexp_new (&session->remote_pubkey, current, pk_length, 1))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate remote public key to sexpression!\n"));
- GNUNET_free (session->mask);
- GNUNET_free (session);
- return GNUNET_SYSERR;
- }
+ memcpy (&session->session_id, &msg->session_id, sizeof (struct GNUNET_HashCode));
- current += pk_length;
-
- //check if service queue contains a matching request
- needed_state = MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED;
- responder_session = find_matching_session (from_client_tail,
- &session->key,
- session->element_count,
- &needed_state, NULL);
-
- session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * used_elements);
-
- if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct GNUNET_SCALARPRODUCT_service_request)
- +pk_length
- + mask_length
- + used_elements * PAILLIER_ELEMENT_LENGTH)
- {
- gcry_error_t ret = 0;
- session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * used_elements);
- // Convert each vector element to MPI_value
- for (i = 0; i < used_elements; i++)
- {
- size_t read = 0;
-
- ret = gcry_mpi_scan (&session->a[i],
- GCRYMPI_FMT_USG,
- ¤t[i * PAILLIER_ELEMENT_LENGTH],
- PAILLIER_ELEMENT_LENGTH,
- &read);
- if (ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate E[a%d] to MPI!\n%s/%s\n"),
- i, gcry_strsource (ret), gcry_strerror (ret));
- goto except;
- }
- }
- GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session);
- if (responder_session)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->key));
- if (GNUNET_OK != compute_service_response (session, responder_session))
- {
- //something went wrong, remove it again...
- GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
- goto except;
- }
- }
- else
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->key));
- return GNUNET_OK;
- }
- else
- {
- // TODO FEATURE: fallback to fragmentation, in case the message is too long
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!\n"));
- goto except;
- }
-except:
- for (i = 0; i < used_elements; i++)
- if (session->a[i])
- gcry_mpi_release (session->a[i]);
- gcry_sexp_release (session->remote_pubkey);
- session->remote_pubkey = NULL;
- GNUNET_free_non_null (session->a);
- session->a = NULL;
- free_session (session);
+ // public key
+ session->remote_pubkey = GNUNET_new (struct GNUNET_CRYPTO_PaillierPublicKey);
+ memcpy (session->remote_pubkey, &msg->public_key, sizeof (struct GNUNET_CRYPTO_PaillierPublicKey));
+
+ //check if service queue contains a matching request
+ client_session = find_matching_session (from_client_tail,
+ &session->session_id,
+ session->total, NULL);
+
+ GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session);
+
+ if ((NULL != client_session)
+ && (client_session->transferred_element_count == client_session->total)) {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->session_id));
+
+ session->response = client_session;
+ session->intersected_elements = client_session->intersected_elements;
+ client_session->intersected_elements = NULL;
+ session->intersection_set = client_session->intersection_set;
+ client_session->intersection_set = NULL;
+
+ session->intersection_op = GNUNET_SET_prepare (&session->peer,
+ &session->session_id,
+ NULL,
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT16_MAX),
+ GNUNET_SET_RESULT_REMOVED,
+ cb_intersection_element_removed,
+ session);
+
+ GNUNET_SET_commit (session->intersection_op, session->intersection_set);
+ }
+ else {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->session_id));
+ }
+
+ return GNUNET_OK;
+invalid_msg:
+ GNUNET_break_op (0);
+ session->channel = NULL;
// and notify our client-session that we could not complete the session
- if (responder_session)
- {
- // we just found the responder session in this queue
- GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, responder_session);
- responder_session->client_notification_task =
- GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
- responder_session);
- }
+ free_session_variables (session);
+ if (NULL != session->client){
+ //Alice
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session);
+ }
+ else {
+ //Bob
+ if (NULL != session->response)
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session->response);
+ GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
+ GNUNET_free(session);
+ }
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with.
+ *
+ * @param cls closure (set from #GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
+ * @param message the actual message
+ * @return #GNUNET_OK to keep the connection open,
+ * #GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_bobs_cryptodata_multipart (void *cls,
+ struct GNUNET_CADET_Channel * channel,
+ void **channel_ctx,
+ const struct GNUNET_MessageHeader * message)
+{
+ struct ServiceSession * session;
+ const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message;
+ struct GNUNET_CRYPTO_PaillierCiphertext * payload;
+ size_t i;
+ uint32_t contained = 0;
+ size_t msg_size;
+ size_t required_size;
+
+ GNUNET_assert (NULL != message);
+ // are we in the correct state?
+ session = (struct ServiceSession *) * channel_ctx;
+ if ((ALICE != session->role) || (NULL == session->sorted_elements)) {
+ goto invalid_msg;
+ }
+ msg_size = ntohs (msg->header.size);
+ required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
+ + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+ // shorter than minimum?
+ if (required_size > msg_size) {
+ goto invalid_msg;
+ }
+ contained = ntohl (msg->contained_element_count);
+ required_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)
+ + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+ //sanity check: is the message as long as the message_count fields suggests?
+ if ((required_size != msg_size) || (session->used_elements_count < session->transferred_element_count + contained)) {
+ goto invalid_msg;
+ }
+ payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
+ // Convert each k[][perm] to its MPI_value
+ for (i = 0; i < contained; i++) {
+ memcpy (&session->r[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ memcpy (&session->r_prime[session->transferred_element_count + i], &payload[2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ }
+ session->transferred_element_count += contained;
+ if (session->transferred_element_count != session->used_elements_count)
+ return GNUNET_OK;
+ session->product = compute_scalar_product (session); //never NULL
+
+invalid_msg:
+ GNUNET_break_op (NULL != session->product);
+ session->channel = NULL;
+ // send message with product to client
+ if (NULL != session->client){
+ //Alice
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_response,
+ session);
+ }
+ else {
+ //Bob
+ if (NULL != session->response)
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session->response);
+ GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
+ free_session_variables (session);
+ GNUNET_free(session);
+ }
+ // the channel has done its job, terminate our connection and the channel
+ // the peer will be notified that the channel was destroyed via channel_destruction_handler
+ // just close the connection, as recommended by Christian
return GNUNET_SYSERR;
}
/**
* Handle a response we got from another service we wanted to calculate a scalarproduct with.
*
- * @param cls closure (set from #GNUNET_MESH_connect)
- * @param tunnel connection to the other end
- * @param tunnel_ctx place to store local state associated with the tunnel
- * @param sender who sent the message
+ * @param cls closure (set from #GNUNET_CADET_connect)
+ * @param channel connection to the other end
+ * @param channel_ctx place to store local state associated with the channel
* @param message the actual message
- * @param atsi performance data for the connection
* @return #GNUNET_OK to keep the connection open,
* #GNUNET_SYSERR to close it (we are done)
*/
static int
-handle_service_response (void *cls,
- struct GNUNET_MESH_Tunnel * tunnel,
- void **tunnel_ctx,
+handle_bobs_cryptodata_message (void *cls,
+ struct GNUNET_CADET_Channel * channel,
+ void **channel_ctx,
const struct GNUNET_MessageHeader * message)
{
struct ServiceSession * session;
const struct GNUNET_SCALARPRODUCT_service_response * msg = (const struct GNUNET_SCALARPRODUCT_service_response *) message;
- unsigned char * current;
- uint16_t count;
- gcry_mpi_t s = NULL;
- gcry_mpi_t s_prime = NULL;
- size_t read;
+ struct GNUNET_CRYPTO_PaillierCiphertext * payload;
size_t i;
- uint16_t used_element_count;
+ uint32_t contained = 0;
size_t msg_size;
- gcry_mpi_t * r = NULL;
- gcry_mpi_t * r_prime = NULL;
- int rc;
+ size_t required_size;
GNUNET_assert (NULL != message);
- session = (struct ServiceSession *) * tunnel_ctx;
- if (ALICE != session->role){
- GNUNET_break_op(0);
- return GNUNET_SYSERR;
+ session = (struct ServiceSession *) * channel_ctx;
+ // are we in the correct state?
+ if (0 /*//TODO: correct state*/) {
+ goto invalid_msg;
}
-
- count = session->used_element_count;
- session->product = NULL;
-
- //we need at least a peer and one message id to compare
- if (sizeof (struct GNUNET_SCALARPRODUCT_service_response) > ntohs (msg->header.size))
- {
- GNUNET_break_op (0);
- goto invalid_msg;
- }
- used_element_count = ntohs (msg->used_element_count);
- msg_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
- + 2 * used_element_count * PAILLIER_ELEMENT_LENGTH
- + 2 * PAILLIER_ELEMENT_LENGTH;
- //sanity check: is the message as long as the message_count fields suggests?
- if ((ntohs (msg->header.size) != msg_size) || (count != used_element_count))
- {
- GNUNET_break_op (0);
- goto invalid_msg;
- }
+ //we need at least a full message without elements attached
+ msg_size = ntohs (msg->header.size);
+ required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response) + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+ if (required_size > msg_size) {
+ goto invalid_msg;
+ }
+ contained = ntohl (msg->contained_element_count);
+ required_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response)
+ + 2 * contained * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext)
+ + 2 * sizeof (struct GNUNET_CRYPTO_PaillierCiphertext);
+ //sanity check: is the message as long as the message_count fields suggests?
+ if ((msg_size != required_size) || (session->used_elements_count < contained)) {
+ goto invalid_msg;
+ }
+ session->transferred_element_count = contained;
//convert s
- current = (unsigned char *) &msg[1];
- if (0 != (rc = gcry_mpi_scan (&s, GCRYMPI_FMT_USG, current,
- PAILLIER_ELEMENT_LENGTH, &read)))
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc);
- GNUNET_break_op (0);
- goto invalid_msg;
- }
- current += PAILLIER_ELEMENT_LENGTH;
- //convert stick
- if (0 != (rc = gcry_mpi_scan (&s_prime, GCRYMPI_FMT_USG, current,
- PAILLIER_ELEMENT_LENGTH, &read)))
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc);
- GNUNET_break_op (0);
- goto invalid_msg;
- }
- current += PAILLIER_ELEMENT_LENGTH;
+ payload = (struct GNUNET_CRYPTO_PaillierCiphertext *) &msg[1];
- r = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
- // Convert each kp[] to its MPI_value
- for (i = 0; i < count; i++)
- {
- if (0 != (rc = gcry_mpi_scan (&r[i], GCRYMPI_FMT_USG, current,
- PAILLIER_ELEMENT_LENGTH, &read)))
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc);
- GNUNET_break_op (0);
- goto invalid_msg;
- }
- current += PAILLIER_ELEMENT_LENGTH;
- }
+ session->s = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ session->s_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ memcpy (session->s, &payload[0], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ memcpy (session->s_prime, &payload[1], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ session->r = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
+ session->r_prime = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * session->used_elements_count);
+
+ // Convert each k[][perm] to its MPI_value
+ for (i = 0; i < contained; i++) {
+ memcpy (&session->r[i], &payload[2 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ memcpy (&session->r_prime[i], &payload[3 + 2 * i], sizeof (struct GNUNET_CRYPTO_PaillierCiphertext));
+ }
+ if (session->transferred_element_count != session->used_elements_count)
+ return GNUNET_OK; //wait for the other multipart chunks
+ session->product = compute_scalar_product (session); //never NULL
- r_prime = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
- // Convert each kq[] to its MPI_value
- for (i = 0; i < count; i++)
- {
- if (0 != (rc = gcry_mpi_scan (&r_prime[i], GCRYMPI_FMT_USG, current,
- PAILLIER_ELEMENT_LENGTH, &read)))
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc);
- GNUNET_break_op (0);
- goto invalid_msg;
- }
- current += PAILLIER_ELEMENT_LENGTH;
- }
-
- session->product = compute_scalar_product (session, r, r_prime, s, s_prime);
-
invalid_msg:
- if (s)
- gcry_mpi_release (s);
- if (s_prime)
- gcry_mpi_release (s_prime);
- for (i = 0; r && i < count; i++)
- if (r[i]) gcry_mpi_release (r[i]);
- for (i = 0; r_prime && i < count; i++)
- if (r_prime[i]) gcry_mpi_release (r_prime[i]);
- GNUNET_free_non_null (r);
- GNUNET_free_non_null (r_prime);
-
- session->state = FINALIZED;
- // the tunnel has done its job, terminate our connection and the tunnel
- // the peer will be notified that the tunnel was destroyed via tunnel_destruction_handler
- GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
+ GNUNET_break_op (NULL != session->product);
+ session->channel = NULL;
// send message with product to client
-
- session->client_notification_task =
- GNUNET_SCHEDULER_add_now (&prepare_client_response,
- session);
- // just close the connection.
+ if (NULL != session->client){
+ //Alice
+ session->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_response,
+ session);
+ }
+ else {
+ //Bob
+ if (NULL != session->response)
+ session->response->client_notification_task =
+ GNUNET_SCHEDULER_add_now (&prepare_client_end_notification,
+ session->response);
+ GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
+ free_session_variables (session);
+ GNUNET_free(session);
+ }
+ // the channel has done its job, terminate our connection and the channel
+ // the peer will be notified that the channel was destroyed via channel_destruction_handler
+ // just close the connection, as recommended by Christian
return GNUNET_SYSERR;
}
+
/**
* Task run during shutdown.
*
do_shutdown = GNUNET_YES;
- // terminate all owned open tunnels.
- for (session = from_client_head; NULL != session; session = session->next)
- {
- if (FINALIZED != session->state)
- GNUNET_MESH_tunnel_destroy (session->tunnel);
- if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task)
- {
+ // terminate all owned open channels.
+ for (session = from_client_head; NULL != session; session = session->next) {
+ if ((0/*//TODO: not finalized*/) && (NULL != session->channel)) {
+ GNUNET_CADET_channel_destroy (session->channel);
+ session->channel = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) {
GNUNET_SCHEDULER_cancel (session->client_notification_task);
session->client_notification_task = GNUNET_SCHEDULER_NO_TASK;
}
- if (GNUNET_SCHEDULER_NO_TASK != session->service_request_task)
- {
- GNUNET_SCHEDULER_cancel (session->service_request_task);
- session->service_request_task = GNUNET_SCHEDULER_NO_TASK;
+ if (NULL != session->client) {
+ GNUNET_SERVER_client_disconnect (session->client);
+ session->client = NULL;
}
}
for (session = from_service_head; NULL != session; session = session->next)
-
- if (my_mesh)
- {
- GNUNET_MESH_disconnect (my_mesh);
- my_mesh = NULL;
+ if (NULL != session->channel) {
+ GNUNET_CADET_channel_destroy (session->channel);
+ session->channel = NULL;
}
+
+ if (my_cadet) {
+ GNUNET_CADET_disconnect (my_cadet);
+ my_cadet = NULL;
+ }
}
const struct GNUNET_CONFIGURATION_Handle *c)
{
static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
- {&handle_client_request, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, 0},
- {&handle_client_request, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 0},
+ {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE, 0},
+ {&handle_client_message, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB, 0},
+ {&handle_client_message_multipart, NULL, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART, 0},
{NULL, NULL, 0, 0}
};
- static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
- { &handle_service_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB, 0},
- { &handle_service_response, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_TO_ALICE, 0},
+ static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
+ { &handle_alices_computation_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
+ { &handle_alices_cyrptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA, 0},
+ { &handle_alices_cyrptodata_message_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_CRYPTODATA_MULTIPART, 0},
+ { &handle_bobs_cryptodata_message, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA, 0},
+ { &handle_bobs_cryptodata_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_CRYPTODATA_MULTIPART, 0},
{NULL, 0, 0}
};
static const uint32_t ports[] = {
0
};
//generate private/public key set
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Generating Paillier-Keyset.\n"));
- generate_keyset ();
+ GNUNET_CRYPTO_paillier_create (&my_pubkey, &my_privkey);
+
+ // offset has to be sufficiently small to allow computation of:
+ // m1+m2 mod n == (S + a) + (S + b) mod n,
+ // if we have more complex operations, this factor needs to be lowered
+ my_offset = gcry_mpi_new (GNUNET_CRYPTO_PAILLIER_BITS / 3);
+ gcry_mpi_set_bit (my_offset, GNUNET_CRYPTO_PAILLIER_BITS / 3);
+
// register server callbacks and disconnect handler
GNUNET_SERVER_add_handlers (server, server_handlers);
GNUNET_SERVER_disconnect_notify (server,
&handle_client_disconnect,
NULL);
GNUNET_break (GNUNET_OK ==
- GNUNET_CRYPTO_get_host_identity (c,
- &me));
- my_mesh = GNUNET_MESH_connect (c, NULL,
- &tunnel_incoming_handler,
- &tunnel_destruction_handler,
- mesh_handlers, ports);
- if (!my_mesh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to MESH failed\n"));
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Mesh initialized\n"));
+ GNUNET_CRYPTO_get_peer_identity (c,
+ &me));
+ my_cadet = GNUNET_CADET_connect (c, NULL,
+ &cb_channel_incoming,
+ &cb_channel_destruction,
+ cadet_handlers, ports);
+ if (!my_cadet) {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CADET failed\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("CADET initialized\n"));
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
&shutdown_task,
NULL);
&run, NULL)) ? 0 : 1;
}
-/* end of gnunet-service-ext.c */
+/* end of gnunet-service-scalarproduct.c */