diff options
author | Christian Fuchs <christian.fuchs@cfuchs.net> | 2013-08-22 13:41:49 +0000 |
---|---|---|
committer | Christian Fuchs <christian.fuchs@cfuchs.net> | 2013-08-22 13:41:49 +0000 |
commit | 3003feb0b391420b403654d840d3c67404fab048 (patch) | |
tree | 4da537dcded885418f9b7d357a7a8c73176ab4b2 | |
parent | f14d78e3c6555f5721705c587e01e8e10503de19 (diff) |
added vectorproduct protocol definitions
added to be localized files to POTFILES
added (inactive) changes to the src/Makefile.am
added manpage for vectorproduct
added apptype for vectorproduct
added vectorproduct service, client, API and related sources to SVN
-rw-r--r-- | doc/man/Makefile.am | 1 | ||||
-rw-r--r-- | doc/man/gnunet-vectorproduct.1 | 65 | ||||
-rw-r--r-- | po/POTFILES.in | 3 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/include/gnunet_applications.h | 5 | ||||
-rw-r--r-- | src/include/gnunet_protocols.h | 33 | ||||
-rw-r--r-- | src/include/gnunet_vectorproduct_service.h | 265 | ||||
-rw-r--r-- | src/vectorproduct/Makefile.am | 97 | ||||
-rw-r--r-- | src/vectorproduct/gnunet-service-vectorproduct.c | 2067 | ||||
-rw-r--r-- | src/vectorproduct/gnunet-vectorproduct.c | 410 | ||||
-rw-r--r-- | src/vectorproduct/gnunet_vectorproduct.h | 274 | ||||
-rw-r--r-- | src/vectorproduct/test_vectorproduct_api.c | 865 | ||||
-rw-r--r-- | src/vectorproduct/test_vectorproduct_api_4peers.c | 1084 | ||||
-rw-r--r-- | src/vectorproduct/test_vectorproduct_api_data.conf | 96 | ||||
-rw-r--r-- | src/vectorproduct/test_vectorproduct_api_regression.c | 852 | ||||
-rw-r--r-- | src/vectorproduct/test_vectorproduct_api_regression2.c | 931 | ||||
-rw-r--r-- | src/vectorproduct/vectorproduct.conf.in | 7 | ||||
-rw-r--r-- | src/vectorproduct/vectorproduct_api.c | 715 | ||||
-rw-r--r-- | src/vectorproduct/vectorproduct_testing.h | 129 |
19 files changed, 7899 insertions, 2 deletions
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 9e63bb243e..8657c23658 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -27,6 +27,7 @@ man_MANS = \ gnunet-transport.1 \ gnunet-unindex.1 \ gnunet-uri.1 \ + gnunet-vectorproduct.1 \ gnunet-vpn.1 EXTRA_DIST = ${man_MANS} diff --git a/doc/man/gnunet-vectorproduct.1 b/doc/man/gnunet-vectorproduct.1 new file mode 100644 index 0000000000..6852694b66 --- /dev/null +++ b/doc/man/gnunet-vectorproduct.1 @@ -0,0 +1,65 @@ +.TH GNUNET\-VECTORPRODUCT 1 "8 Aug 2013" "GNUnet" + +.SH NAME +gnunet\-vectorproduct \- compute a vectorproduct + +.SH SYNOPSIS +.B gnunet\-vectorproduct +.RI [ options ] +.br + +.SH DESCRIPTION +\fBgnunet-vectorproduct\fP enables you to compute a vectorproduct across two peers \fBAlice\fP and \fBBob\fP. + +A client can issue one of two messages to its service: +.TS +tab (@); +l lx. +1@T{ +A request to compute a vectorproduct with another peer (\fBAlice\fP) +T} +2@T{ +Elements to support a peer in computing a vectorproduct (\fBBob\fP) +T} +.TE + +Both requests must share the same SID, which can be an arbitrary string identifying the session. SIDs should be unique, however it is sufficient to guarantee the uniqueness of the tupel element count and session ID. + +\fBAlice\fP\'s client must supply the ASCII encoded peer ID of bob\'s service, it will internally be checked by the client for validity. Invalid values here result in the client or the service failing the session. + +Elements are handed over as signed decimal integers, the element count supplied by \fBAlice\fP and \fBBob\fP must match. \fBAlice\fP can also supply a mask for these values to her service, which allows partial vector products to be computed across the vector. Elements can be masked by setting their the corresponding mask element to zero, any other value means the element will not be masked. \fBAlice\fP\'s client will also mask all 0-values to avoid information leakage to \fBBob\fP. + +The protocol by definition relies on \fBAlice\fP and \fBBob\fP being benign, thus \fBBob\fP can arbitrarily falsify his information. Both peers collaborate to achieve a correct result. + +.SH OPTIONS +.B +.IP "\-e ELEMENTS, \-\-elements=ELEMENTS" +The element-vector the vectorproduct should be computed over in signed decimal form, eg: \"42,1,-3,3,7\". Zero value elements will be automatically masked. +.B +.IP "\-m MASK, \-\-mask=MASK" +Elements in the vector can be masked. There must be at least two elements left in the vector to compute a vectorproduct. Non-Zero values indicate an element is not maskes. +.B +.IP "\-k KEY, \-\-key=KEY" +The session key, a shared string of arbitrary length from which the SID will be generated +.B +.IP "\-c FILENAME, \-\-config=FILENAME" +Use the configuration file FILENAME. +.B +.IP "\-p PEERID, \-\-peer=PEERID" +The remote peer\'s ASCII-armored gnunet-peer ID as output by gnunet-peerinfo. If this option is not given, the peer will take the \fBBob\fP\'s role. +.B +.IP "\-h, \-\-help" +Print short help on options. +.B +.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL" +Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR. +.B +.IP "\-v, \-\-version" +Print GNUnet version number. + + +.SH BUGS +Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <gnunet\-developers@gnu.org> + +.SH SEE ALSO +gnunet\-peerinfo(1) diff --git a/po/POTFILES.in b/po/POTFILES.in index 18fd7ab067..cd4e05faeb 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -343,3 +343,6 @@ src/mesh/mesh_protocol.h src/mesh/mesh_protocol_enc.h src/testbed/testbed_api.h src/testbed/testbed_api_operations.h +src/vectorproduct/vectorproduct_api.c +src/vectorproduct/gnunet-service-vectorproduct.c +src/vectorproduct/gnunet-vectorproduct.c diff --git a/src/Makefile.am b/src/Makefile.am index b77025a3e6..5240989927 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,10 +7,12 @@ if HAVE_TESTING TESTBED = testbed CONSENSUS = consensus EXPERIMENTATION = experimentation + VECTORPRODUCT = vectorproduct endif if HAVE_EXPERIMENTAL EXP_DIR = dv $(CONSENSUS) $(EXPERIMENTATION) +#note: vectorproduct is not being listed here yet as the crypto is being reworked at the moment endif if HAVE_MYSQL diff --git a/src/include/gnunet_applications.h b/src/include/gnunet_applications.h index 4e86e332e8..866ea01402 100644 --- a/src/include/gnunet_applications.h +++ b/src/include/gnunet_applications.h @@ -76,12 +76,15 @@ extern "C" */ #define GNUNET_APPLICATION_TYPE_CONSENSUS 18 - /** * Set. Used for two-peer set operations implemented using stream. */ #define GNUNET_APPLICATION_TYPE_SET 19 +/** + * Vectorproduct. Used for two-peer vectorproduct operations + */ +#define GNUNET_APPLICATION_TYPE_VECTORPRODUCT 20 #if 0 /* keep Emacsens' auto-indent happy */ { diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index a62b286af1..dfd7c55065 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -1905,8 +1905,39 @@ extern "C" #define GNUNET_MESSAGE_TYPE_IDENTITY_DELETE 631 +/******************************************************************************* + * VECTORPRODUCT message types + ******************************************************************************/ + +/** + * Client -> Vector-Product Service request message + */ +#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE 640 + +/** + * Client -> Vector-Product Service request message + */ +#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_BOB 641 + +/** + * Vector-Product Service request -> remote VP Service + */ +#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_ALICE_TO_BOB 642 + +/** + * remote Vector-Product Service response -> requesting VP Service + */ +#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_BOB_TO_ALICE 643 + +/** + * Vector-Product Service response -> Client + */ +#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT 644 + + + /** - * Next available: 640 + * Next available: 650 */ diff --git a/src/include/gnunet_vectorproduct_service.h b/src/include/gnunet_vectorproduct_service.h new file mode 100644 index 0000000000..743a7365d1 --- /dev/null +++ b/src/include/gnunet_vectorproduct_service.h @@ -0,0 +1,265 @@ +/* + This file is part of GNUnet. + (C) 2013 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file include/gnunet_vectorproduct_service.h + * @brief API to the vectorproduct service + * @author Christian M. Fuchs + * @author Gaurav Kukreja + */ +#ifndef GNUNET_VECTORPRODUCT_SERVICE_H +#define GNUNET_VECTORPRODUCT_SERVICE_H +#define GCRYPT_NO_DEPRECATED +// including gcrypt crashes netbeans after the next restart... +#include <gcrypt.h> + +#ifdef __cplusplus +extern "C" { +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Version of the vectorproduct API. + */ +#define GNUNET_VECTORPRODUCT_VERSION 0x00000042 + +/** + * Message type passed from client to service + * to initiate a request or responder role + */ +struct GNUNET_VECTORPRODUCT_client_request { + /** + * GNUNET message header + */ + struct GNUNET_MessageHeader header; + + /** + * how many elements the vector in payload contains + */ + uint16_t element_count GNUNET_PACKED; + + /** + * how many bytes the mask has + */ + uint16_t mask_length GNUNET_PACKED; + + /** + * the transaction/session key used to identify a session + */ + struct GNUNET_HashCode key; + + /** + * the identity of a remote peer we want to communicate with + */ + struct GNUNET_PeerIdentity peer; + + /** + * followed by long vector[element_count] | [unsigned char mask[mask_bytes]] + */ +}; + +/** + * Message type passed from service client + * to finalize a session as requester or responder + */ +struct GNUNET_VECTORPRODUCT_client_response { + /** + * GNUNET message header + */ + struct GNUNET_MessageHeader header; + + /** + * 0 if no product attached + */ + uint32_t product_length GNUNET_PACKED; + + /** + * the transaction/session key used to identify a session + */ + struct GNUNET_HashCode key; + + /** + * the identity of a remote peer we want to communicate with + */ + struct GNUNET_PeerIdentity peer; + + /** + * followed by product of length product_length (or nothing) + */ +}; + +enum GNUNET_VECTORPRODUCT_ResponseStatus { + GNUNET_VECTORPRODUCT_Status_Success = 0, + GNUNET_VECTORPRODUCT_Status_Failure, + GNUNET_VECTORPRODUCT_Status_Timeout, + GNUNET_VECTORPRODUCT_Status_InvalidResponse, + GNUNET_VECTORPRODUCT_Status_ServiceDisconnected +}; + +struct GNUNET_VECTORPRODUCT_Handle { + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Current connection to the vectorproduct service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Handle for statistics. + */ + struct GNUNET_STATISTICS_Handle *stats; + + /** + * Current head of priority queue. + */ + struct GNUNET_VECTORPRODUCT_QueueEntry *queue_head; + + /** + * Current tail of priority queue. + */ + struct GNUNET_VECTORPRODUCT_QueueEntry *queue_tail; + + /** + * Are we currently trying to receive from the service? + */ + int in_receive; + + /** + * Current transmit handle. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * TODO: What else should/could go here? + */ +}; + +typedef void (*GNUNET_VECTORPRODUCT_ResponseMessageHandler) (void *cls, + const struct GNUNET_MessageHeader *msg, + enum GNUNET_VECTORPRODUCT_ResponseStatus status); + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure + * @param success GNUNET_SYSERR on failure (including timeout/queue drop) + * GNUNET_NO if content was already there + * GNUNET_YES (or other positive value) on success + * @param msg NULL on success, otherwise an error message + */ +typedef void (*GNUNET_VECTORPRODUCT_ContinuationWithStatus) (void *cls, + const struct GNUNET_HashCode * key, + enum GNUNET_VECTORPRODUCT_ResponseStatus status); +/** + * Process a datum that was stored in the vectorproduct. + * + * @param cls closure + * @param key Sessioon key + * @param peer PeerID of the peer with whom the scalar product was calculated. + * @param status Status of the request + * @param size Size of the received message + * @param data Pointer to the data + * @param type Type of data + */ +typedef void (*GNUNET_VECTORPRODUCT_DatumProcessor) (void *cls, + const struct GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity * peer, + enum GNUNET_VECTORPRODUCT_ResponseStatus status, + const struct GNUNET_VECTORPRODUCT_client_response *msg); + +/** + * Request the Scalar Product Evaluation + * + * @param h handle to the master context + * @param key Session key - unique to the requesting client + * @param peer PeerID of the other peer + * @param element_count Number of elements in the vector + * @param mask_bytes number of bytes in the mask + * @param elements Array of elements of the vector + * @param mask Array of the mask + * @param timeout Relative timeout for the operation + * @param cont Callback function + * @param cont_cls Closure for the callback function + */ +struct GNUNET_VECTORPRODUCT_QueueEntry * +GNUNET_VECTORPRODUCT_request(struct GNUNET_VECTORPRODUCT_Handle *h, + const struct GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *peer, + uint16_t element_count, + uint16_t mask_bytes, + int32_t * elements, const unsigned char * mask, + struct GNUNET_TIME_Relative timeout, + GNUNET_VECTORPRODUCT_DatumProcessor cont, + void *cont_cls); + +/** + * Called by the responder client to prepare response + * + * @param h handle to the master context + * @param key Session key - unique to the requesting client + * @param element_count Number of elements in the vector + * @param mask_bytes number of bytes in the mask + * @param elements Array of elements of the vector + * @param mask Array of the mask + * @param timeout Relative timeout for the operation + * @param cont Callback function + * @param cont_cls Closure for the callback function + */ +struct GNUNET_VECTORPRODUCT_QueueEntry * +GNUNET_VECTORPRODUCT_prepare_response(struct GNUNET_VECTORPRODUCT_Handle *h, + const struct GNUNET_HashCode * key, + uint16_t element_count, + int32_t* elements, + struct GNUNET_TIME_Relative timeout, + GNUNET_VECTORPRODUCT_ContinuationWithStatus cont, + void *cont_cls); + +/** + * Connect to the vectorproduct service. + * + * @param cfg configuration to use + * @return handle to use to access the service + */ +struct GNUNET_VECTORPRODUCT_Handle * +GNUNET_VECTORPRODUCT_connect(const struct GNUNET_CONFIGURATION_Handle * cfg); + +/** + * Disconnect from the vectorproduct service. + * + * @param h handle to the vectorproduct + */ +void +GNUNET_VECTORPRODUCT_disconnect(struct GNUNET_VECTORPRODUCT_Handle * h); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/vectorproduct/Makefile.am b/src/vectorproduct/Makefile.am new file mode 100644 index 0000000000..e9cbbc644d --- /dev/null +++ b/src/vectorproduct/Makefile.am @@ -0,0 +1,97 @@ +SUBDIRS = . + +INCLUDES = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir) + +AM_CPPFLAGS = \ + $(GNUNET_CPPFLAGS) + +# Set this variable if you are using GNUNET libraries for all programs and +# libraries. You don't then need to target-specific _LDFLAGS with GNUNET_LDFLAGS +# AM_LDFLAGS = \ +# $(GNUNET_LDFLAGS) \ +# $(WINFLAGS) \ +# -export-dynamic + +lib_LTLIBRARIES = libgnunetvectorproduct.la + +pkgcfgdir= $(prefix)/share/gnunet/config.d/ + +libexecdir= $(prefix)/lib/gnunet/libexec/ + +libgnunetvectorproduct_la_SOURCES = \ + vectorproduct_api.c +libgnunetvectorproduct_la_LIBADD = \ + -lgnunetutil -lgcrypt -lgnunetstatistics +libgnunetvectorproduct_la_LDFLAGS = \ + $(GNUNET_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +bin_PROGRAMS = gnunet-vectorproduct + +libexec_PROGRAMS = gnunet-service-vectorproduct + +check_PROGRAMS = \ + test_vectorproduct_api_regression \ + test_vectorproduct_api \ + test_vectorproduct_api_4peers +#FIXME unfinished +#test_vectorproduct_api_regression2 + +TESTS = $(check_PROGRAMS) + +gnunet_service_vectorproduct_SOURCES = \ + gnunet-service-vectorproduct.c +gnunet_service_vectorproduct_LDADD = \ + -lgnunetutil -lgnunettransport -lgnunetcore -lgnunetmesh -lgnunetdht -lgcrypt \ + $(INTLLIBS) +gnunet_service_vectorproduct_LDFLAGS = \ + $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic + +gnunet_vectorproduct_SOURCES = \ + gnunet-vectorproduct.c +gnunet_vectorproduct_LDADD = \ + $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ + -lgnunetutil -lgcrypt \ + $(INTLLIBS) +gnunet_vectorproduct_LDFLAGS = \ + $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic + + +test_vectorproduct_api_SOURCES = \ + test_vectorproduct_api.c +test_vectorproduct_api_LDADD = \ + $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ + -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed +test_vectorproduct_api_LDFLAGS = \ + $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic + +#FIXME unfinished +#test_vectorproduct_api_regression2_SOURCES = \ +# test_vectorproduct_api_regression2.c +#test_vectorproduct_api_regression2_LDADD = \ +# $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ +# -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed +#test_vectorproduct_api_regression2_LDFLAGS = \ +# $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic + +test_vectorproduct_api_regression_SOURCES = \ + test_vectorproduct_api_regression.c +test_vectorproduct_api_regression_LDADD = \ + $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ + -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed +test_vectorproduct_api_regression_LDFLAGS = \ + $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic + +test_vectorproduct_api_4peers_SOURCES = \ + test_vectorproduct_api_4peers.c +test_vectorproduct_api_4peers_LDADD = \ + $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ + -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed +test_vectorproduct_api_4peers_LDFLAGS = \ + $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic + + pkgcfg_DATA = vectorproduct.conf + diff --git a/src/vectorproduct/gnunet-service-vectorproduct.c b/src/vectorproduct/gnunet-service-vectorproduct.c new file mode 100644 index 0000000000..1c459a3357 --- /dev/null +++ b/src/vectorproduct/gnunet-service-vectorproduct.c @@ -0,0 +1,2067 @@ +/* + This file is part of GNUnet. + (C) 2013 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file vectorproduct/gnunet-service-vectorproduct.c + * @brief vectorproduct service implementation + * @author Christian M. Fuchs + */ +#include <limits.h> +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_mesh_service.h" +#include "gnunet_applications.h" +#include "gnunet_protocols.h" +#include "gnunet_vectorproduct_service.h" +#include "gnunet_vectorproduct.h" + +/////////////////////////////////////////////////////////////////////////////// +// Global Variables +/////////////////////////////////////////////////////////////////////////////// + +/** + * Handle to the core service (NULL until we've connected to it). + */ +static struct GNUNET_CORE_Handle *my_core; + +/** + * Handle to the core service (NULL until we've connected to it). + */ +static struct GNUNET_MESH_Handle *my_mesh; + +/** + * The identity of this host. + */ +static struct GNUNET_PeerIdentity me; + +/** + * 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; + +/** + * Service's own n + */ +static gcry_mpi_t my_n; + +/** + * Service's own n^2 (kept for performance) + */ +static gcry_mpi_t my_nsquare; + +/** + * Service's own public exponent + */ +static gcry_mpi_t my_g; + +/** + * Service's own private multiplier + */ +static gcry_mpi_t my_mu; + +/** + * Service's own private exponent + */ +static gcry_mpi_t my_lambda; + +/** + * Head of our double linked list for client-requests sent to us. + * for all of these elements we calculate a vector 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. + * for all of these elements we calculate a vector 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. + * for all of these elements we help the requesting service in calculating a vector 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. + * for all of these elements we help the requesting service in calculating a vector 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. + */ +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); + + 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 r random base (optional) gets generated and if not NULL but uninitialized + * @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 r, gcry_mpi_t n, gcry_mpi_t n_square) +{ +#ifndef DISABLE_CRYPTO + gcry_mpi_t tmp; + int release_r = GNUNET_NO; + + GNUNET_assert (tmp = gcry_mpi_new (0)); + if (NULL == r) + { + GNUNET_assert (r = gcry_mpi_new (0)); + release_r = GNUNET_YES; + + while (0 <= gcry_mpi_cmp (r, n) || 0 >= gcry_mpi_cmp_ui (r, 1)) + { + gcry_mpi_randomize (r, KEYBITS, GCRY_WEAK_RANDOM); + // r must be 1 < r < n + } + } + + + gcry_mpi_powm (c, g, m, n_square); + gcry_mpi_powm (tmp, r, n, n_square); + gcry_mpi_mulm (c, tmp, c, n_square); + + gcry_mpi_release (tmp); + if (GNUNET_YES == release_r) + gcry_mpi_release (r); +#else + gcry_mpi_set (c, m); +#endif +} + + +/** + * 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) +{ +#ifndef DISABLE_CRYPTO + 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); +#else + gcry_mpi_set (m, c); +#endif +} + + +/** + * 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) +{ + gcry_mpi_t elem; + gcry_mpi_t sum; + int32_t i; + + GNUNET_assert (sum = gcry_mpi_new (0)); + 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); + } + 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 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 MessageObject * info = cls; + struct GNUNET_MessageHeader * msg; + size_t written = 0; + + GNUNET_assert (info); + msg = info->msg; + GNUNET_assert (msg); + GNUNET_assert (buf); + + if (ntohs (msg->size) == size) + { + memcpy (buf, msg, size); + written = size; + } + + // reset the transmit handle, if necessary + if (info->transmit_handle) + *info->transmit_handle = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Sent a message of type %hu.\n"), ntohs (msg->type)); + GNUNET_free(msg); + GNUNET_free(info); + 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 + * + * @para |