#include "node.hpp" #include "logging.hpp" #include "gmpxx.h" #include using namespace boost::asio::ip; Node::Node(ListenSettings const& listen_settings, NodeNetworkSettings network_settings) : io_service() , server(io_service, listen_settings, [this](boost::asio::ip::tcp::socket&& socket){accept_handler(std::move(socket));}) , clients() , network_settings(network_settings) , next_node(tcp::socket(io_service)) , api(get_curve25519_implementation()) , keypair(api.create_key_pair()) , network_pub_key() { GOOGLE_PROTOBUF_VERIFY_VERSION; auto on_connect = [this, network_settings](){ if(network_settings.is_first) { start_initialisation(); } }; next_node.async_connect(network_settings.next_host, network_settings.next_port, on_connect); } Node::~Node() { api.free_key_pair(keypair); } void Node::run() { io_service.run(); } void Node::accept_handler(boost::asio::ip::tcp::socket&& socket) { clients.emplace_back(std::move(socket)); auto it = --clients.end(); clients.back().on_done( [this, it]() { clients.erase(it); } ); } void Node::start_initialisation() { cmix_proto::Initialization init; init.set_public_share(keypair.pub, keypair.pub_len); cmix_proto::CMixMessage message; *message.mutable_initialization() = init; std::string message_str; message.SerializeToString(&message_str); next_node.send(message_str); for(auto&& client : clients) { client.receive(std::bind(&Node::handle_message, this, std::placeholders::_1)); } } void Node::handle_message(const std::vector& message_buffer) { cmix_proto::CMixMessage message; if(!message.ParseFromArray(message_buffer.data(), message_buffer.size())) { BOOST_LOG_TRIVIAL(error) << "Received something which was not a CMixMessage"; } switch(message.contents_case()) { case cmix_proto::CMixMessage::ContentsCase::kInitialization: { handle_initialization(message.initialization()); break; } default: { BOOST_LOG_TRIVIAL(error) << "CMixMessage contains unknown contents."; } } } void Node::handle_initialization(const cmix_proto::Initialization& init) { if(network_settings.is_first) { std::string share = init.public_share(); network_pub_key = std::vector(share.begin(), share.end()); start_precomputation(); } else { mpz_t shared; mpz_init(shared); mpz_import(shared, init.public_share().size(), -1, 1, 0, 0, init.public_share().data()); mpz_t my_share; mpz_init(my_share); mpz_import(my_share, keypair.pub_len, -1, 1, 0, 0, keypair.pub); mpz_mul(shared, shared, my_share); mpz_t mod; mpz_init(mod); mpz_set_ui(mod, 2); mpz_pow_ui(mod, mod, 255); mpz_sub_ui(mod, mod, 19); mpz_mod(shared, shared, mod); std::vector new_shared(keypair.pub_len, '\0'); size_t size; mpz_export(new_shared.data(), &size, -1, 1, 0, 0, shared); cmix_proto::Initialization init; init.set_public_share(new_shared.data(), new_shared.size()); cmix_proto::CMixMessage message; *message.mutable_initialization() = init; std::string message_str; message.SerializeToString(&message_str); next_node.send(message_str); mpz_clear(shared); mpz_clear(my_share); mpz_clear(mod); } } void Node::start_precomputation() { io_service.stop(); }