diff options
| author | Dennis Brentjes <d.brentjes@gmail.com> | 2016-11-12 13:48:30 +0100 |
|---|---|---|
| committer | Dennis Brentjes <d.brentjes@gmail.com> | 2016-11-12 13:48:30 +0100 |
| commit | f93d52bbd0053574fb35d72b85c4b299dc1f3ee5 (patch) | |
| tree | 4a2120a162ce9161d70074fd9ffa3ed21d80a40e | |
| parent | 8ff9babe2da4a2efc8529e800a6093fbd0327286 (diff) | |
| download | cmix-f93d52bbd0053574fb35d72b85c4b299dc1f3ee5.tar.gz cmix-f93d52bbd0053574fb35d72b85c4b299dc1f3ee5.tar.bz2 cmix-f93d52bbd0053574fb35d72b85c4b299dc1f3ee5.zip | |
Fixes decryption share calculation, adds lots of debugging statements.
| -rw-r--r-- | client/cmixclient.cpp | 19 | ||||
| -rw-r--r-- | libcmix-common/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | libcmix-common/cmixprotofunctor.hpp | 14 | ||||
| -rw-r--r-- | libcmix-common/senderreceiver.cpp | 1 | ||||
| -rw-r--r-- | libcmix-crypto/api.h | 6 | ||||
| -rw-r--r-- | libcmix-crypto/elgamal/elgamal.c | 1 | ||||
| -rw-r--r-- | libcmix-crypto/elgamal/elgamal.h | 2 | ||||
| -rw-r--r-- | libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c | 82 | ||||
| -rw-r--r-- | libcmix-protobuf/cmix.proto | 11 | ||||
| -rw-r--r-- | libcmix/cmix.c | 73 | ||||
| -rw-r--r-- | libcmix/cmix.h | 19 | ||||
| -rw-r--r-- | liblog/logging.cpp | 2 | ||||
| -rw-r--r-- | node/main.cpp | 2 | ||||
| -rw-r--r-- | node/node.cpp | 67 | ||||
| -rw-r--r-- | node/node.hpp | 39 | ||||
| -rw-r--r-- | node/node_client.cpp | 15 | ||||
| -rw-r--r-- | node/node_node.cpp | 157 |
17 files changed, 435 insertions, 77 deletions
diff --git a/client/cmixclient.cpp b/client/cmixclient.cpp index f8ecf7d..d7e1387 100644 --- a/client/cmixclient.cpp +++ b/client/cmixclient.cpp @@ -63,21 +63,26 @@ void CMixClient::handle_key_exchange(size_t node_id, cmix_proto::KeyExchange con &secret_values.at(node_id) ); - size_t len = get_group_element_array_size(&cmix_ctx); - std::vector<char> vec(len, '\0'); - std::string s = "abcdefghijklmnopqrstuvwxyz"; - std::copy_n(s.begin(), s.size(), vec.begin() + 1); - if(std::all_of(shared_values.begin(), shared_values.end(), [](auto const& value){return value != nullptr;})) { + size_t len = get_group_element_array_size(&cmix_ctx); + std::vector<char> vec(len, '\0'); + std::string s = "\1"; + std::copy_n(s.begin(), s.size(), vec.begin() + 1); + cmix_proto::UserMessage message; message.mutable_m()->resize(len); blind_message(&cmix_ctx, &(*message.mutable_m())[0], vec.data(), shared_values.data(), shared_values.size()); + BOOST_LOG_TRIVIAL(trace) << "sending UserMessage: " << message.ShortDebugString(); network_connections.at(0).async_send(message); - cmix_proto::Bye bye; - network_connections.at(node_id).async_send(bye); + size_t last_node_id = network_details.node_details.size() - 1; + network_connections.at(last_node_id).async_receive( + [this, last_node_id](cmix_proto::CMixMessage const& message) { + handle_message(last_node_id, message); + } + ); } } diff --git a/libcmix-common/CMakeLists.txt b/libcmix-common/CMakeLists.txt index cc3125c..71aa472 100644 --- a/libcmix-common/CMakeLists.txt +++ b/libcmix-common/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(cmix-common cmixprotofunctor.hpp receiver.hpp sender.hpp - senderreceiver.hpp senderreceiver.cpp + senderreceiver.hpp ) target_include_directories(cmix-common diff --git a/libcmix-common/cmixprotofunctor.hpp b/libcmix-common/cmixprotofunctor.hpp index effa8bd..0055593 100644 --- a/libcmix-common/cmixprotofunctor.hpp +++ b/libcmix-common/cmixprotofunctor.hpp @@ -37,9 +37,19 @@ struct CMixProtoFunctor { return m; \ } \ + /*! + * \def MESSAGE_SETTER_DEF_ITERATION(Z, N, DATA) + * Defines one iteration of the Repeat below, + * \param Z level over repeat we are using it should be 1. + * \param N current iteration + * \param The sequence consisiting of "pairs" of TYPE, NAME + */ #define MESSAGE_SETTER_DEF_ITERATION(Z, N, DATA) \ MESSAGE_SETTER_DEF(BOOST_PP_SEQ_ELEM(BOOST_PP_MUL(N, 2), DATA), BOOST_PP_SEQ_ELEM(BOOST_PP_ADD(BOOST_PP_MUL(N, 2), 1), DATA)) + /*! + * Loops over the length of the variadic macro parameter / 2 + */ #define MESSAGE_SETTER_DEFS(...) \ BOOST_PP_REPEAT(BOOST_PP_DIV(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 2), MESSAGE_SETTER_DEF_ITERATION, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) @@ -54,7 +64,9 @@ struct CMixProtoFunctor { UserMessage, usermessage, PrePre, prepre, PreMix, premix, - PrePost, prepost + PrePost, prepost, + RealPre, realpre, + RealMix, realmix, ) #undef MESSAGE_SETTER_DEFS #undef MESSAGE_SETTER_DEF_ITERATION diff --git a/libcmix-common/senderreceiver.cpp b/libcmix-common/senderreceiver.cpp deleted file mode 100644 index 8b13789..0000000 --- a/libcmix-common/senderreceiver.cpp +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libcmix-crypto/api.h b/libcmix-crypto/api.h index addf9e3..98c81a1 100644 --- a/libcmix-crypto/api.h +++ b/libcmix-crypto/api.h @@ -98,6 +98,11 @@ typedef void (*Encrypter)(GroupElement*, GroupElement*, GroupElement, GroupEleme /*! * */ +typedef GroupElement (*Inverter)(GroupElement); + +/*! + * + */ typedef GroupElement (*DecryptionShareGetter)(GroupElement, GroupElement); /*! @@ -120,6 +125,7 @@ struct Api { SharedKeyDeriver derive_shared_key; ///< Pointer to shared key derivation function SharedKeyDeleter free_shared_key; ///< Pointer to shared key deleter function Encrypter encrypt; ///< encrypt value with key; + Inverter invert; ///< Invert the group element; Deinitializer deinitialize; ///< Function that will deinitialize the crypto library. }; diff --git a/libcmix-crypto/elgamal/elgamal.c b/libcmix-crypto/elgamal/elgamal.c index dbfccb9..1525618 100644 --- a/libcmix-crypto/elgamal/elgamal.c +++ b/libcmix-crypto/elgamal/elgamal.c @@ -20,6 +20,7 @@ struct Api get_elgamal_implementation() .derive_shared_key = elgamal_derive_shared_key, .free_shared_key = elgamal_delete_shared_key, .encrypt = elgamal_encrypt, + .invert = elgamal_invert, .deinitialize = elgamal_deinitialize }; } diff --git a/libcmix-crypto/elgamal/elgamal.h b/libcmix-crypto/elgamal/elgamal.h index 21bf58a..1fcb044 100644 --- a/libcmix-crypto/elgamal/elgamal.h +++ b/libcmix-crypto/elgamal/elgamal.h @@ -42,6 +42,8 @@ extern SharedKeyDeleter elgamal_delete_shared_key; extern Encrypter elgamal_encrypt; +extern Inverter elgamal_invert; + extern Deinitializer elgamal_deinitialize; /*! diff --git a/libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c b/libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c index 1824ccc..8a6fb7e 100644 --- a/libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c +++ b/libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c @@ -9,6 +9,7 @@ static gcry_mpi_t p; static gcry_mpi_t q; static gcry_mpi_t g; +static unsigned int nr_bytes = 2; void check(gcry_error_t error) { if (error) { @@ -44,9 +45,13 @@ void gcrypt_elgamal_initialize(void) { gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); //leading 0 as specified by libgcrypt - char p_hex[] = "087A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597"; - char q_hex[] = "08CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3"; - char g_hex[] = "03FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659"; + //char p_hex[] = "087A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597"; + //char q_hex[] = "08CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3"; + //char g_hex[] = "03FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659"; + + char p_hex[] = "0b"; + char q_hex[] = "00"; + char g_hex[] = "02"; size_t nr_bytes_scanned; gcry_error_t error; @@ -66,11 +71,15 @@ struct KeyPair gcrypt_elgamal_create_keypair() { size_t parse_error_offset; gcry_error_t error; - void* bytes = gcry_random_bytes_secure(2048/8, GCRY_VERY_STRONG_RANDOM); - gcry_mpi_t x; - error = gcry_mpi_scan(&x, GCRYMPI_FMT_USG, bytes, 2048/8, &parse_error_offset); - check(error); - + gcry_mpi_t x = NULL; + do { + gcry_mpi_release(x); + void* bytes = gcry_random_bytes_secure(nr_bytes, GCRY_VERY_STRONG_RANDOM); + error = gcry_mpi_scan(&x, GCRYMPI_FMT_USG, bytes, nr_bytes, &parse_error_offset); + gcry_free(bytes); + check(error); + gcry_mpi_mod(x, x, p); //bias needs to be removed. + } while(gcry_mpi_cmp_ui(x, 0) == 0 || gcry_mpi_cmp(x, p) != -1); gcry_mpi_t y = gcry_mpi_new(0); gcry_mpi_powm(y, g, x, p); @@ -82,7 +91,6 @@ struct KeyPair gcrypt_elgamal_create_keypair() { check(error); gcry_sexp_release(priv_key); - gcry_free(bytes); return (struct KeyPair){ x, @@ -115,7 +123,7 @@ void* gcrypt_elgamal_array_to_element(char const* buffer, size_t len, bool secur gcry_mpi_t mpi; error = gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, buffer, len, &error_pos); - gcry_mpi_set_flag(mpi, GCRYMPI_FLAG_SECURE); + //gcry_mpi_set_flag(mpi, GCRYMPI_FLAG_SECURE); check(error); return mpi; @@ -125,14 +133,18 @@ void* gcrypt_elgamal_get_group_element(bool secure) { size_t parse_error_offset; gcry_error_t error; - void* bytes = gcry_random_bytes_secure(2048/8, GCRY_VERY_STRONG_RANDOM); - gcry_mpi_t a; - error = gcry_mpi_scan(&a, GCRYMPI_FMT_USG, bytes, 2048/8, &parse_error_offset); + gcry_mpi_t a = NULL; + do { + gcry_mpi_release(a); + void* bytes = gcry_random_bytes_secure(nr_bytes, GCRY_VERY_STRONG_RANDOM); + error = gcry_mpi_scan(&a, GCRYMPI_FMT_USG, bytes, nr_bytes, &parse_error_offset); + check(error); + gcry_mpi_mod(a, a, p); //BIAS REMOVE THIS. + gcry_free(bytes); + } while(gcry_mpi_cmp_ui(a, 0) == 0 || gcry_mpi_cmp(a, p) != -1); //random bytes generated with GCRY{,_VERY}_STRONG_RANDOM are generated in "secure memory" //so secure is unused. - check(error); - gcry_free(bytes); return a; } @@ -153,17 +165,21 @@ GroupElement gcrypt_elgamal_multiply(GroupElement lh, GroupElement rh, bool secu } GroupElement gcrypt_elgamal_get_decryption_share(GroupElement r, GroupElement e) { - gcry_mpi_t inve = gcry_mpi_snew(0); - gcry_mpi_invm(inve, (gcry_mpi_t)e, p); + //gcry_mpi_t inve = gcry_mpi_snew(0); + //gcry_mpi_invm(inve, (gcry_mpi_t)e, p); + + gcry_mpi_t inv_d = gcry_mpi_snew(0); + gcry_mpi_powm(inv_d, (gcry_mpi_t)r, (gcry_mpi_t)e, p); gcry_mpi_t d = gcry_mpi_snew(0); - gcry_mpi_powm(d, (gcry_mpi_t)r, inve, p); - gcry_mpi_release(inve); + gcry_mpi_invm(d, inv_d, p); + + gcry_mpi_release(inv_d); return d; } size_t gcrypt_elgamal_get_group_element_array_size() { - return 256u; + return nr_bytes; } void gcrypt_elgamal_delete_group_element(void* el) { @@ -213,7 +229,22 @@ void gcrypt_elgamal_delete_shared_key(struct SharedKey* s) { } void gcrypt_elgamal_encrypt(GroupElement* random_element, GroupElement* message_element, GroupElement value, GroupElement key) { - gcry_error_t error; + + GroupElement random = gcrypt_elgamal_get_group_element(true); + + *random_element = gcry_mpi_new(0); + gcry_mpi_powm((gcry_mpi_t) *random_element, g, (gcry_mpi_t) random, p); + + gcry_mpi_t key_pow_random = gcry_mpi_snew(0); + gcry_mpi_powm(key_pow_random, (gcry_mpi_t) key, (gcry_mpi_t) random, p); + + *message_element = gcry_mpi_snew(0); + gcry_mpi_mulm((gcry_mpi_t)*message_element, (gcry_mpi_t) value, key_pow_random, p); + + gcry_mpi_release((gcry_mpi_t) random); + gcry_mpi_release(key_pow_random); + +/* gcry_error_t error; size_t parse_error_pos; gcry_sexp_t pubkey_expr; @@ -232,7 +263,13 @@ void gcrypt_elgamal_encrypt(GroupElement* random_element, GroupElement* message_ gcry_sexp_release(enc_expr); gcry_sexp_release(value_expr); - gcry_sexp_release(pubkey_expr); + gcry_sexp_release(pubkey_expr); */ +} + +GroupElement gcrypt_elgamal_invert(GroupElement const x) { + gcry_mpi_t inv_x = gcry_mpi_new(0); + gcry_mpi_invm(inv_x, (gcry_mpi_t)x, p); + return inv_x; } void gcrypt_elgamal_deinitialize(void) { @@ -257,4 +294,5 @@ PublicShareAdder elgamal_add_public_share = &gcrypt_elgamal_add_public_share; SharedKeyDeriver elgamal_derive_shared_key = &gcrypt_elgamal_derive_shared_key; SharedKeyDeleter elgamal_delete_shared_key = &gcrypt_elgamal_delete_shared_key; Encrypter elgamal_encrypt = &gcrypt_elgamal_encrypt; +Inverter elgamal_invert = &gcrypt_elgamal_invert; Deinitializer elgamal_deinitialize = &gcrypt_elgamal_deinitialize;
\ No newline at end of file diff --git a/libcmix-protobuf/cmix.proto b/libcmix-protobuf/cmix.proto index ce1f2c2..8bb1d42 100644 --- a/libcmix-protobuf/cmix.proto +++ b/libcmix-protobuf/cmix.proto @@ -48,6 +48,15 @@ message PrePost { repeated bytes m_EPiRS = 2; } +message RealPre { + repeated bytes h = 1; + repeated bytes m = 2; +} + +message RealMix { + repeated bytes m = 2; +} + message CMixMessage { oneof contents { Initialization initialization = 1; @@ -61,5 +70,7 @@ message CMixMessage { PrePre prepre = 9; PreMix premix = 10; PrePost prepost = 11; + RealPre realpre = 12; + RealMix realmix = 13; } } diff --git a/libcmix/cmix.c b/libcmix/cmix.c index a47a9fa..4465011 100644 --- a/libcmix/cmix.c +++ b/libcmix/cmix.c @@ -46,7 +46,6 @@ struct CMixContext initialize_cmix_context(struct Api api) { .s = NULL, .permutation = NULL, .pirs = NULL, - .messages = NULL }; } @@ -55,13 +54,11 @@ void release_mix(struct CMixContext* ctx) { ctx->api.free_group_element(ctx->r[i]); ctx->api.free_group_element(ctx->s[i]); ctx->api.free_group_element(ctx->pirs[i]); - ctx->api.free_group_element(ctx->messages[i]); } free(ctx->r); free(ctx->s); free(ctx->permutation); free(ctx->pirs); - free(ctx->messages); } void deinitialize(struct CMixContext* ctx) @@ -71,7 +68,7 @@ void deinitialize(struct CMixContext* ctx) ctx->api.deinitialize(); } -void element_to_buffer(struct CMixContext const* ctx, char* out_buffer, GroupElement element) { +void element_to_buffer(struct CMixContext const* ctx, char* out_buffer, GroupElement const element) { size_t el_size = get_group_element_array_size(ctx); unsigned char* buffer; @@ -110,8 +107,7 @@ enum cmix_error alloc_mix(struct CMixContext* ctx) { ctx->s = (GroupElement*) calloc(ctx->nr_participants, sizeof(GroupElement)); ctx->permutation = (unsigned int*) calloc(ctx->nr_participants, sizeof(unsigned int)); ctx->pirs = (GroupElement*) calloc(ctx->nr_participants, sizeof(GroupElement)); - ctx->pirs = (GroupElement*) calloc(ctx->nr_participants, sizeof(GroupElement)); - if(!ctx->r || !ctx->s || !ctx->permutation || !ctx->pirs || !ctx->messages) { + if(!ctx->r || !ctx->s || !ctx->permutation || !ctx->pirs) { return out_of_memory; } return no_error; @@ -132,8 +128,11 @@ enum cmix_error initialize_mix_randomness(struct CMixContext* ctx) { return no_error; } -enum cmix_error generate_random_message(struct CMixContext* ctx, size_t index) { - ctx->messages[index] = ctx->api.get_group_element(true); +enum cmix_error generate_random_message(struct CMixContext* ctx, char* buffer) { + GroupElement el = ctx->api.get_group_element(true); + element_to_buffer(ctx, buffer, el); + ctx->api.free_group_element(el); + return no_error; } @@ -185,7 +184,7 @@ enum cmix_error encrypt_r_and_multiply(struct CMixContext const* ctx, char* rand return no_error; } -enum cmix_error multiply_s(struct CMixContext const* ctx, char* r_out_buffer, char* m_out_buffer, char const* r_in_buffer, char const* m_in_buffer, size_t index) { +enum cmix_error multiply_encrypted_s(struct CMixContext const* ctx, char* r_out_buffer, char* m_out_buffer, char const* r_in_buffer, char const* m_in_buffer, size_t index) { size_t el_size = get_group_element_array_size(ctx); GroupElement random_r = ctx->api.array_to_element(r_in_buffer, el_size, true); @@ -210,9 +209,23 @@ enum cmix_error multiply_s(struct CMixContext const* ctx, char* r_out_buffer, ch return no_error; } +enum cmix_error multiply_s(struct CMixContext const* ctx, char* out_buffer, char const* message, size_t index) { + size_t el_size = get_group_element_array_size(ctx); + + GroupElement message_el = ctx->api.array_to_element(message, el_size, false); + GroupElement mult = ctx->api.multiply(message_el, ctx->s[ctx->permutation[index]], false); + + element_to_buffer(ctx, out_buffer, mult); + + ctx->api.free_group_element(message_el); + ctx->api.free_group_element(mult); + + return no_error; +} + enum cmix_error key_exchange_init(struct CMixContext const* ctx, char* pubkey_buffer, char* value_buffer, GroupElement* priv_el) { *priv_el = ctx->api.get_group_element(true); - GroupElement value = ctx->api.get_key_exchange_value(priv_el); + GroupElement value = ctx->api.get_key_exchange_value(*priv_el); get_public_key(ctx, pubkey_buffer); element_to_buffer(ctx, value_buffer, value); @@ -239,7 +252,7 @@ enum cmix_error key_exchange_responder(struct CMixContext const* ctx, GroupEleme enum cmix_error key_exchange_initiator(struct CMixContext const* ctx, GroupElement* shared_key, char const* pubkey, char const* value, GroupElement* priv_el) { size_t el_len = get_group_element_array_size(ctx); - *shared_key = ctx->api.derive_shared_key(ctx->keypair, (unsigned char*)pubkey, el_len, (unsigned char*)value, el_len, priv_el, false); + *shared_key = ctx->api.derive_shared_key(ctx->keypair, (unsigned char*)pubkey, el_len, (unsigned char*)value, el_len, *priv_el, false); ctx->api.free_group_element(*priv_el); *priv_el = NULL; @@ -250,17 +263,20 @@ enum cmix_error key_exchange_initiator(struct CMixContext const* ctx, GroupEleme enum cmix_error post_process(struct CMixContext* ctx, char* r_out, char* m_out, char const* r_epirs, char const* m_epirs, size_t index) { GroupElement x = ctx->api.array_to_element(r_epirs, get_group_element_array_size(ctx), true); GroupElement D = ctx->api.get_decryption_share(x, ctx->keypair.sec); - element_to_buffer(ctx, r_out, D); + //element_to_buffer(ctx, r_out, D); GroupElement msg = ctx->api.array_to_element(m_epirs, get_group_element_array_size(ctx), true); GroupElement pirs = ctx->api.multiply(D, msg, true); element_to_buffer(ctx, m_out, pirs); + GroupElement new_r = ctx->api.multiply(x, D, true); + element_to_buffer(ctx, r_out, new_r); ctx->pirs[index] = pirs; // this is not always usable as only the last node will be able to use this effectively, but we store it anyways. ctx->api.free_group_element(x); ctx->api.free_group_element(D); ctx->api.free_group_element(msg); + ctx->api.free_group_element(new_r); return no_error; } @@ -280,3 +296,36 @@ enum cmix_error blind_message(struct CMixContext const* ctx, char* m_out, char c return no_error; } + +enum cmix_error swap_k_for_r(struct CMixContext const* ctx, char* out_buffer, char const* message, GroupElement const key, size_t index) { + size_t len = get_group_element_array_size(ctx); + + GroupElement mes = ctx->api.array_to_element(message, len, false); + GroupElement inv_key = ctx->api.invert(key); + + GroupElement unblinded = ctx->api.multiply(mes, inv_key, false); + GroupElement blinded = ctx->api.multiply(unblinded, ctx->r[index], false); + + element_to_buffer(ctx, out_buffer, blinded); + ctx->api.free_group_element(mes); + ctx->api.free_group_element(inv_key); + ctx->api.free_group_element(unblinded); + ctx->api.free_group_element(blinded); + + return no_error; +} + +enum cmix_error remove_r_and_s(struct CMixContext const* ctx, char* out_buffer, char const* message, size_t index) { + size_t len = get_group_element_array_size(ctx); + + GroupElement mes = ctx->api.array_to_element(message, len, false); + GroupElement inv_pirs = ctx->api.invert(ctx->pirs[index]); + + GroupElement mult = ctx->api.multiply(mes, inv_pirs, false); + + element_to_buffer(ctx, out_buffer, mult); + + ctx->api.free_group_element(mes); + ctx->api.free_group_element(inv_pirs); + ctx->api.free_group_element(mult); +} diff --git a/libcmix/cmix.h b/libcmix/cmix.h index 33b99d2..ba0b826 100644 --- a/libcmix/cmix.h +++ b/libcmix/cmix.h @@ -78,9 +78,12 @@ struct CMixContext { GroupElement* s; unsigned int* permutation; GroupElement* pirs; - GroupElement* messages; }; +#ifndef NDEBUG +void element_to_buffer(struct CMixContext const* ctx, char* buffer, GroupElement const element); +#endif + struct CMixContext initialize_cmix_context(struct Api api); void deinitialize(struct CMixContext* ctx); @@ -95,7 +98,7 @@ enum cmix_error start_mix(struct CMixContext* ctx, size_t nr_participants); enum cmix_error initialize_mix_randomness(struct CMixContext* ctx); -enum cmix_error generate_random_message(struct CMixContext* ctx, size_t index); +enum cmix_error generate_random_message(struct CMixContext* ctx, char* buffer); size_t get_group_element_array_size(struct CMixContext const* ctx); @@ -105,7 +108,9 @@ enum cmix_error encrypt_r(struct CMixContext const* ctx, char* random_buffer, ch enum cmix_error encrypt_r_and_multiply(struct CMixContext const* ctx, char* random_buffer, char* message_buffer, char const* random_element, char const* message_element, size_t index); -enum cmix_error multiply_s(struct CMixContext const* ctx, char* r_out_buffer, char* m_out_buffer, char const* r_in_buffer, char const* m_in_buffer, size_t index); +enum cmix_error multiply_encrypted_s(struct CMixContext const* ctx, char* r_out_buffer, char* m_out_buffer, char const* r_in_buffer, char const* m_in_buffer, size_t index); + +enum cmix_error multiply_s(struct CMixContext const* ctx, char* out_buffer, char const* message, size_t index); enum cmix_error get_key_exchange_value(struct CMixContext const* ctx, char* buffer, GroupElement priv_element); @@ -119,6 +124,14 @@ enum cmix_error post_process(struct CMixContext* ctx, char* r_out, char* m_out, enum cmix_error blind_message(struct CMixContext const* ctx, char* m_out, char const* message, GroupElement const* keys, size_t const nr_nodes); +enum cmix_error enqueue_message(struct CMixContext* ctx, char const* message, size_t index); + +enum cmix_error enqueue_random_message(struct CMixContext* ctx, size_t index); + +enum cmix_error swap_k_for_r(struct CMixContext const* ctx, char* out_buffer, char const* message, GroupElement const key, size_t index); + +enum cmix_error remove_r_and_s(struct CMixContext const* ctx, char* out_buffer, char const* message, size_t index); + #ifdef __cplusplus } // extern "C" #endif diff --git a/liblog/logging.cpp b/liblog/logging.cpp index 3b0c2c5..d34de9b 100644 --- a/liblog/logging.cpp +++ b/liblog/logging.cpp @@ -18,7 +18,7 @@ void init_logging(boost::log::trivial::severity_level log_level, std::string fil ( boost::log::keywords::file_name = file_name + ".log", boost::log::keywords::rotation_size = 10 * 1024 * 1024, - boost::log::keywords::format = "[%Severity%] (%TimeStamp%): %Message%", + boost::log::keywords::format = "(%TimeStamp%):" + (" " + file_name + " ") + "[%Severity%] %Message%", boost::log::keywords::auto_flush = true ); diff --git a/node/main.cpp b/node/main.cpp index 28ef60c..acfdafe 100644 --- a/node/main.cpp +++ b/node/main.cpp @@ -21,7 +21,7 @@ int main(int argc, char* argv[]) { ("interface6,6", po::value<std::string>()->default_value("::"), "Set the ipv6 address to listen on.") ("next_node,n", po::value<std::string>(), "The address of the next node in the network.") ("first,f", "This is the first node and will be the communication point for the clients.") - ("last,f", "this is the last node and will be able to send the original message out of the network.") + ("last,l", "this is the last node and will be able to send the original message out of the network.") ("cert,c", po::value<std::string>(), "The cert file to use (in pem format).") ("key,k", po::value<std::string>(), "The key file (in pem format).") ("dhparam,d", po::value<std::string>(), "The dhparam file.") diff --git a/node/node.cpp b/node/node.cpp index b5c8506..5bce063 100644 --- a/node/node.cpp +++ b/node/node.cpp @@ -11,19 +11,40 @@ using namespace boost::asio::ip; Node::Node(ListenSettings const& listen_settings, NodeNetworkSettings network_settings) : io_service() +, timer(io_service) , ssl_ctx(std::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23)) , server(io_service, listen_settings, ssl_ctx, [this](std::unique_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>&& socket, std::shared_ptr<boost::asio::ssl::context> ctx){accept_handler(std::move(socket), ctx);}) , clients() , data() +, messages() , network_settings(network_settings) , prev_node(SSLReceiver(std::unique_ptr<boost::asio::ssl::stream<tcp::socket>>(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(io_service, *ssl_ctx)))) , next_node(SSLSender(std::unique_ptr<boost::asio::ssl::stream<tcp::socket>>(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(io_service, *ssl_ctx)))) , cmix_ctx(initialize_cmix_context(get_implementation())) -, precomputation_data() , shutting_down(false) { initialize_keypair(&cmix_ctx); + std::string x = to_string(cmix_ctx.keypair.sec, cmix_ctx); + std::string y = to_string(cmix_ctx.keypair.pub, cmix_ctx); + { + std::stringstream ss; + ss << "sec: "; + for(auto&& c : x) { + ss << "\\" << std::setw(3) << std::setfill('0') << std::oct << (unsigned int) c; + } + BOOST_LOG_TRIVIAL(trace) << ss.str(); + } + + { + std::stringstream ss; + ss << "pub: "; + for(auto&& c : y) { + ss << "\\" << std::setw(3) << std::setfill('0') << std::oct << (unsigned int) c; + } + BOOST_LOG_TRIVIAL(trace) << ss.str(); + } + GOOGLE_PROTOBUF_VERIFY_VERSION; if(network_settings.is_first) { @@ -131,14 +152,15 @@ void Node::handle_message(Purgatory::iterator handle, cmix_proto::CMixMessage me } void Node::start_precomputation() { + BOOST_LOG_TRIVIAL(trace) << "Starting precomputation for " << clients.size() << " clients."; + index_map.clear(); if(start_mix(&cmix_ctx, clients.size()) != no_error) { exit(-1); } - int i = 0; + unsigned int i = 0; for(auto&& pair : clients) { index_map[pair.first] = i++; - generate_random_message(&cmix_ctx, i); } if(initialize_mix_randomness(&cmix_ctx) != no_error) { @@ -148,15 +170,54 @@ void Node::start_precomputation() { cmix_proto::PrePre prepre; for(size_t i = 0; i < cmix_ctx.nr_participants; ++i) { + prepre.add_m_er(); + prepre.add_r_er(); + size_t len = get_group_element_array_size(&cmix_ctx); prepre.mutable_r_er(i)->resize(len); prepre.mutable_m_er(i)->resize(len); + { + std::stringstream ss; + ss << "r: "; + std::string r = to_string(cmix_ctx.r[i], cmix_ctx); + for(auto&& c : r) { + ss << "\\" << std::setw(3) << std::setfill('0') << std::oct << (unsigned int) c; + } + BOOST_LOG_TRIVIAL(trace) << ss.str(); + } + if(encrypt_r(&cmix_ctx, &(*prepre.mutable_r_er(i))[0], &(*prepre.mutable_m_er(i))[0], i) != no_error) { exit(-1); } } + BOOST_LOG_TRIVIAL(trace) << "Sending prepre message: " << prepre.ShortDebugString(); next_node.async_send(prepre); } + +void Node::start_realtime_phase() { + + cmix_proto::RealPre realpre; + + size_t len = get_group_element_array_size(&cmix_ctx); + for(auto&& pair : index_map) { + realpre.add_h(); + realpre.add_m(); + realpre.mutable_m(pair.second)->resize(len); + std::decay<decltype(pair)>::type::first_type const& handle = pair.first; + std::decay<decltype(pair)>::type::second_type const& index = pair.second; + + auto& queue = messages[pair.first]; + if(queue.empty()) { + std::vector<char> v(len); + generate_random_message(&cmix_ctx, v.data()); + swap_k_for_r(&cmix_ctx, &(*realpre.mutable_m(index))[0], v.data(), data[handle].shared_value, index); + } else { + swap_k_for_r(&cmix_ctx, &(*realpre.mutable_m(index))[0], queue.front().data(), data[handle].shared_value, index); + } + *realpre.mutable_h(index) = handle; + } + next_node.async_send(realpre); +} diff --git a/node/node.hpp b/node/node.hpp index a4c7992..b166c71 100644 --- a/node/node.hpp +++ b/node/node.hpp @@ -14,11 +14,23 @@ #include <list> #include <string> +#include <queue> +#include <iomanip> /*! * \file */ +#ifndef NDEBUG +inline std::string to_string(GroupElement el, CMixContext const& ctx) { + std::string ret; + ret.resize(get_group_element_array_size(&ctx)); + + element_to_buffer(&ctx, &ret[0], el); + return ret; +} +#endif + /*! * \brief The NodeNetworkSettings struct */ @@ -30,29 +42,17 @@ struct NodeNetworkSettings { std::string certdir; ///< Directory containing trusted certificate authorities. }; -struct MixData { - GroupElement r; - GroupElement s; - std::string client_handle; - size_t new_location; - - ~MixData(){ - Api api = get_implementation(); - api.free_group_element(r); - api.free_group_element(s); - } -}; - /*! * \brief The Node class */ class Node { struct CMixClientData { - SharedKey shared_value; + GroupElement shared_value; }; boost::asio::io_service io_service; + boost::asio::deadline_timer timer; std::shared_ptr<boost::asio::ssl::context> ssl_ctx; Server server; @@ -63,6 +63,8 @@ class Node ClientConnections clients; typedef std::map<std::string, CMixClientData> ClientData; ClientData data; + typedef std::map<std::string, std::queue<std::string>> ClientMessages; + ClientMessages messages; NodeNetworkSettings network_settings; @@ -71,26 +73,29 @@ class Node CMixContext cmix_ctx; - std::vector<MixData> precomputation_data; - std::map<std::string, int> index_map; + std::map<std::string, unsigned int> index_map; bool shutting_down; void accept_handler(std::unique_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>&& socket, std::shared_ptr<boost::asio::ssl::context> ctx); void connect_to_next_node(); - void start_precomputation(); void start_initialisation(); + void start_precomputation(); + void start_realtime_phase(); void handle_node_initialization(cmix_proto::Initialization const& init); void handle_node_secretkey(cmix_proto::SecretKey const& secret); void handle_node_prepre(cmix_proto::PrePre const& prepre); void handle_node_premix(cmix_proto::PreMix const& premix); void handle_node_prepost(cmix_proto::PrePost const& prepost); + void handle_node_realpre(cmix_proto::RealPre const& realpre); + void handle_node_realmix(cmix_proto::RealMix const& realmix); void handle_node_message(cmix_proto::CMixMessage message); void handle_client_keyexchange(ClientConnections::key_type handle, cmix_proto::KeyExchange const& ke); void handle_client_bye(ClientConnections::key_type handle, cmix_proto::Bye const&); + void handle_client_usermessage(ClientConnections::key_type handle, cmix_proto::UserMessage const& um); void handle_client_message(ClientConnections::key_type handle, cmix_proto::CMixMessage message); void handle_imanode(Purgatory::iterator handle, cmix_proto::ImANode const&); diff --git a/node/node_client.cpp b/node/node_client.cpp index f60c48d..baf4251 100644 --- a/node/node_client.cpp +++ b/node/node_client.cpp @@ -10,7 +10,7 @@ void Node::handle_client_keyexchange(ClientConnections::key_type handle, cmix_pr nke.mutable_public_key()->resize(len); nke.mutable_value()->resize(len); - key_exchange_responder(&cmix_ctx, &d.shared_value.shared, &(*nke.mutable_public_key())[0], &(*nke.mutable_value())[0], ke.public_key().data(), ke.value().data()); + key_exchange_responder(&cmix_ctx, &d.shared_value, &(*nke.mutable_public_key())[0], &(*nke.mutable_value())[0], ke.public_key().data(), ke.value().data()); data[handle] = d; @@ -23,6 +23,14 @@ void Node::handle_client_bye(ClientConnections::key_type handle, cmix_proto::Bye clients.erase(handle); } +void Node::handle_client_usermessage(ClientConnections::key_type handle, cmix_proto::UserMessage const& um) { + if(!network_settings.is_first) { + BOOST_LOG_TRIVIAL(warning) << "Received a user message but I'm not the first node, ignoring."; + return; + } + messages[handle].push(um.m()); +} + void Node::handle_client_message(ClientConnections::key_type handle, cmix_proto::CMixMessage message) { switch(message.contents_case()) { @@ -36,6 +44,11 @@ void Node::handle_client_message(ClientConnections::key_type handle, cmix_proto: handle_client_bye(handle, message.bye()); return; } + case cmix_proto::CMixMessage::ContentsCase::kUsermessage: { + BOOST_LOG_TRIVIAL(trace) << "Handling user message"; + handle_client_usermessage(handle, message.usermessage()); + break; + } default: { BOOST_LOG_TRIVIAL(error) << "handle_client_message: CMixMessage contains unknown contents."; } diff --git a/node/node_node.cpp b/node/node_node.cpp index eea9eb0..f24ff0a 100644 --- a/node/node_node.cpp +++ b/node/node_node.cpp @@ -13,12 +13,25 @@ cmix_proto::PrePre fill_precomputation_pre_message(CMixContext& ctx, T const& rs cmix_proto::PrePre prepre; - for(size_t i = 0; i < ctx.nr_participants; ++i) { + for(size_t i = 0; i < ms.size(); ++i) { + prepre.add_m_er(); + prepre.add_r_er(); + size_t len = get_group_element_array_size(&ctx); prepre.mutable_m_er(i)->resize(len); prepre.mutable_r_er(i)->resize(len); + { + std::stringstream ss; + ss << "r: "; + std::string r = to_string(ctx.r[i], ctx); + for(auto&& c : r) { + ss << "\\" << std::setw(3) << std::setfill('0') << std::oct << (unsigned int) c; + } + BOOST_LOG_TRIVIAL(trace) << ss.str(); + } + if(encrypt_r_and_multiply( &ctx, &(*prepre.mutable_r_er(i))[0], @@ -36,14 +49,29 @@ cmix_proto::PrePre fill_precomputation_pre_message(CMixContext& ctx, T const& rs template <typename T> cmix_proto::PreMix fill_precomputation_mix_message(CMixContext const& ctx, T const& rs, T const& ms) { cmix_proto::PreMix premix; - for(size_t i = 0; i < ctx.nr_participants; ++i) { + + for(size_t i = 0; i < ms.size(); ++i) { + premix.add_r_epirs(); + premix.add_m_epirs(); + } + for(size_t i = 0; i < ms.size(); ++i) { auto new_pos = ctx.permutation[i]; size_t el_len = get_group_element_array_size(&ctx); premix.mutable_r_epirs(new_pos)->resize(el_len); premix.mutable_m_epirs(new_pos)->resize(el_len); - multiply_s( + { + std::stringstream ss; + ss << "s: "; + std::string s = to_string(ctx.s[i], ctx); + for(auto&& c : s) { + ss << "\\" << std::setw(3) << std::setfill('0') << std::oct << (unsigned int) c; + } + BOOST_LOG_TRIVIAL(trace) << ss.str(); + } + + multiply_encrypted_s( &ctx, &(*premix.mutable_r_epirs(new_pos))[0], &(*premix.mutable_m_epirs(new_pos))[0], @@ -59,7 +87,10 @@ template <typename T> cmix_proto::PrePost fill_precomputation_post_message(CMixContext& ctx, T const& rs, T const& ms) { cmix_proto::PrePost prepost; - for(size_t i = 0; i < ctx.nr_participants; ++i) { + for(size_t i = 0; i < ms.size(); ++i) { + prepost.add_r_epirs(); + prepost.add_m_epirs(); + size_t el_len = get_group_element_array_size(&ctx); prepost.mutable_r_epirs(i)->resize(el_len); @@ -74,6 +105,16 @@ cmix_proto::PrePost fill_precomputation_post_message(CMixContext& ctx, T const& i ); + { + std::stringstream ss; + ss << "pirs: "; + std::string pirs = to_string(ctx.pirs[i], ctx); + for(auto&& c : pirs) { + ss << "\\" << std::setw(3) << std::setfill('0') << std::oct << (unsigned int) c; + } + BOOST_LOG_TRIVIAL(trace) << ss.str(); + } + *prepost.mutable_r_epirs(i) = rs.Get(i); *prepost.mutable_m_epirs(i) = ms.Get(i); } @@ -81,6 +122,56 @@ cmix_proto::PrePost fill_precomputation_post_message(CMixContext& ctx, T const& return prepost; } +template <typename T> +cmix_proto::RealPre fill_realtime_pre_message(CMixContext& ctx, T const& hs, T const& ms, Node::ClientData const& data) { + cmix_proto::RealPre realpre; + + size_t len = get_group_element_array_size(&ctx); + for(int i = 0; i < ms.size(); ++i) { + realpre.add_h(); + realpre.add_m(); + realpre.mutable_m(i)->resize(len); + + swap_k_for_r( + &ctx, + &(*realpre.mutable_m(i))[0], + ms.Get(i).data(), + data.at(hs.Get(i)).shared_value, + i + ); + *realpre.mutable_h(i) = hs.Get(i); + } + + return realpre; +} + +template <typename T> +cmix_proto::RealMix fill_realtime_mix_message(CMixContext& ctx, T const& ms) { + cmix_proto::RealMix realmix; + + size_t len = get_group_element_array_size(&ctx); + + for(int i = 0; i < ms.size(); ++i) { + realmix.add_m(); + } + + for(int i = 0; i < ms.size(); ++i) { + auto new_pos = ctx.permutation[i]; + + realmix.mutable_m(i)->resize(len); + + multiply_s( + &ctx, + &(*realmix.mutable_m(new_pos))[0], + ms.Get(i).data(), + i + ); + + } + + return realmix; +} + void Node::handle_node_initialization(const cmix_proto::Initialization& init) { if(network_settings.is_first) { @@ -97,7 +188,7 @@ void Node::handle_node_initialization(const cmix_proto::Initialization& init) n_init.mutable_public_share()->resize(len); add_public_share(&cmix_ctx, &(*n_init.mutable_public_share())[0], init.public_share().data()); - BOOST_LOG_TRIVIAL(trace) << "Sending intialization"; + BOOST_LOG_TRIVIAL(trace) << "sending message: " << n_init.ShortDebugString(); next_node.async_send(n_init); } } @@ -109,7 +200,10 @@ void Node::handle_node_secretkey(cmix_proto::SecretKey const& secret) set_network_key(&cmix_ctx, secret.secret_key().data(), secret.secret_key().size()); if(network_settings.is_first) { - start_precomputation(); + timer.expires_from_now(boost::posix_time::seconds(4)); + timer.async_wait([this](boost::system::error_code const& ec) { + start_precomputation(); + }); } else { next_node.async_send(secret); } @@ -137,15 +231,54 @@ void Node::handle_node_premix(cmix_proto::PreMix const& premix) { void Node::handle_node_prepost(cmix_proto::PrePost const& prepost) { if(network_settings.is_first) { - + start_realtime_phase(); } else { cmix_proto::PrePost n_prepost = fill_precomputation_post_message(cmix_ctx, prepost.r_epirs(), prepost.m_epirs()); next_node.async_send(n_prepost); } } +void Node::handle_node_realpre(cmix_proto::RealPre const& realpre) { + if(network_settings.is_first) { + cmix_proto::RealMix n_realmix = fill_realtime_mix_message(cmix_ctx, realpre.m()); + next_node.async_send(n_realmix); + } else { + cmix_proto::RealPre n_realpre = fill_realtime_pre_message(cmix_ctx, realpre.h(), realpre.m(), data); + next_node.async_send(n_realpre); + } +} + +void Node::handle_node_realmix(cmix_proto::RealMix const& realmix) { + if(network_settings.is_last) { + BOOST_LOG_TRIVIAL(trace) << "Doing the last step:"; + + cmix_proto::RealMix n_realmix = fill_realtime_mix_message(cmix_ctx, realmix.m()); + + size_t len = get_group_element_array_size(&cmix_ctx); + std::string str; + str.resize(len); + + for(int i = 0; i < n_realmix.m_size(); i++) { + remove_r_and_s(&cmix_ctx, &str[0], n_realmix.m(i).data(), i); + + { + std::stringstream ss; + for(auto&& c : str) { + ss << "\\" << std::setw(3) << std::setfill('0') << std::oct << (unsigned int) c; + } + BOOST_LOG_TRIVIAL(trace) << ss.str(); + } + } + + } else { + cmix_proto::RealMix n_realmix = fill_realtime_mix_message(cmix_ctx, realmix.m()); + next_node.async_send(n_realmix); + } +} + void Node::handle_node_message(cmix_proto::CMixMessage message) { + BOOST_LOG_TRIVIAL(trace) << "Message: " << message.ShortDebugString(); switch(message.contents_case()) { case cmix_proto::CMixMessage::ContentsCase::kInitialization: { BOOST_LOG_TRIVIAL(trace) << "Handling initialization"; @@ -177,6 +310,16 @@ void Node::handle_node_message(cmix_proto::CMixMessage message) handle_node_prepost(message.prepost()); break; } + case cmix_proto::CMixMessage::ContentsCase::kRealpre: { + BOOST_LOG_TRIVIAL(trace) << "Handling RealPre"; + handle_node_realpre(message.realpre()); + break; + } + case cmix_proto::CMixMessage::ContentsCase::kRealmix: { + BOOST_LOG_TRIVIAL(trace) << "Handling RealMix"; + handle_node_realmix(message.realmix()); + break; + } default: { BOOST_LOG_TRIVIAL(error) << "handle_node_message: CMixMessage contains unknown contents."; } |
