/// @file dpf/net/party_tape_io.hpp /// @brief Deal / accept a `dpf::beavers::party_tape` over a framed channel. #ifndef LIBDPF_INCLUDE_DPF_NET_PARTY_TAPE_IO_HPP__ #define LIBDPF_INCLUDE_DPF_NET_PARTY_TAPE_IO_HPP__ #include #include #include #include #include "dpf/beaver.hpp" #include "dpf/net/channel.hpp" #include "dpf/net/trio.hpp" namespace dpf { namespace net { namespace detail { template void send_ring_vec(channel & c, const std::vector & v) { static_assert(std::is_trivially_copyable_v, "party_tape ring must be trivially copyable"); std::uint64_t n = v.size(); c.send(msg::ring_vector, n); if (n != 0) c.send_vec(v.data(), v.size(), msg::ring_vector); } template std::vector recv_ring_vec(channel & c) { auto n = c.recv(msg::ring_vector); if (n == 0) return {}; return c.recv_vec(msg::ring_vector); } inline void send_flags(channel & c, const std::vector & v) { std::uint64_t n = v.size(); c.send(msg::bytes, n); if (n != 0) c.send_bytes(msg::bytes, v); } inline std::vector recv_flags(channel & c) { auto n = c.recv(msg::bytes); if (n == 0) return {}; auto body = c.recv_bytes(msg::bytes); if (body.size() != n) throw std::runtime_error("party_tape flag size mismatch"); return body; } } // namespace detail template void send_party_tape(channel & c, const beavers::party_tape & tape) { c.send(msg::beaver_tape, std::uint8_t{2}); c.send(msg::beaver_tape, static_cast(tape.has_mac ? 1 : 0)); detail::send_ring_vec(c, tape.lambda); detail::send_flags(c, tape.lambda_ready); detail::send_ring_vec(c, tape.monomial); detail::send_flags(c, tape.monomial_ready); detail::send_ring_vec(c, tape.bundles); detail::send_flags(c, tape.bundles_ready); detail::send_ring_vec(c, tape.dot_cross); detail::send_flags(c, tape.dot_ready); if (tape.has_mac) { detail::send_ring_vec(c, tape.lambda_tag); detail::send_ring_vec(c, tape.monomial_tag); detail::send_ring_vec(c, tape.bundles_tag); detail::send_ring_vec(c, tape.dot_cross_tag); } } template beavers::party_tape recv_party_tape(channel & c) { const auto ver = c.recv(msg::beaver_tape); beavers::party_tape tape; if (ver >= 2) tape.has_mac = c.recv(msg::beaver_tape) != 0; tape.lambda = detail::recv_ring_vec(c); tape.lambda_ready = detail::recv_flags(c); tape.monomial = detail::recv_ring_vec(c); tape.monomial_ready = detail::recv_flags(c); tape.bundles = detail::recv_ring_vec(c); tape.bundles_ready = detail::recv_flags(c); tape.dot_cross = detail::recv_ring_vec(c); tape.dot_ready = detail::recv_flags(c); if (tape.has_mac) { tape.lambda_tag = detail::recv_ring_vec(c); tape.monomial_tag = detail::recv_ring_vec(c); tape.bundles_tag = detail::recv_ring_vec(c); tape.dot_cross_tag = detail::recv_ring_vec(c); } return tape; } /// @brief Dealer exports and sends each party's tape. /// @tparam Ring Beaver ring /// @param net the connected trio /// @param s the sampled session /// @throws std::logic_error if this process is not p2 template void send_party_tape(trio & net, role peer, const beavers::party_tape & tape) { net.send_to(peer, msg::beaver_tape, std::uint8_t{2}); net.send_to(peer, msg::beaver_tape, static_cast(tape.has_mac ? 1 : 0)); auto send_ring_vec = [&](const std::vector & v) { const std::uint64_t n = v.size(); net.send_to(peer, msg::ring_vector, n); if (n != 0) net.send_vec_to(peer, msg::ring_vector, v); }; auto send_flags = [&](const std::vector & v) { const std::uint64_t n = v.size(); net.send_to(peer, msg::bytes, n); if (n != 0) net.send_bytes_to(peer, msg::bytes, v.data(), v.size()); }; send_ring_vec(tape.lambda); send_flags(tape.lambda_ready); send_ring_vec(tape.monomial); send_flags(tape.monomial_ready); send_ring_vec(tape.bundles); send_flags(tape.bundles_ready); send_ring_vec(tape.dot_cross); send_flags(tape.dot_ready); if (tape.has_mac) { send_ring_vec(tape.lambda_tag); send_ring_vec(tape.monomial_tag); send_ring_vec(tape.bundles_tag); send_ring_vec(tape.dot_cross_tag); } } template beavers::party_tape recv_party_tape(trio & net, role peer) { const auto ver = net.recv_from(peer, msg::beaver_tape); beavers::party_tape tape; if (ver >= 2) tape.has_mac = net.recv_from(peer, msg::beaver_tape) != 0; auto recv_ring_vec = [&]() { const auto n = net.recv_from(peer, msg::ring_vector); if (n == 0) return std::vector{}; return net.recv_vec_from(peer, msg::ring_vector); }; auto recv_flags = [&]() { const auto n = net.recv_from(peer, msg::bytes); if (n == 0) return std::vector{}; auto body = net.recv_bytes_from(peer, msg::bytes); if (body.size() != n) throw std::runtime_error("party_tape flag size mismatch"); return body; }; tape.lambda = recv_ring_vec(); tape.lambda_ready = recv_flags(); tape.monomial = recv_ring_vec(); tape.monomial_ready = recv_flags(); tape.bundles = recv_ring_vec(); tape.bundles_ready = recv_flags(); tape.dot_cross = recv_ring_vec(); tape.dot_ready = recv_flags(); if (tape.has_mac) { tape.lambda_tag = recv_ring_vec(); tape.monomial_tag = recv_ring_vec(); tape.bundles_tag = recv_ring_vec(); tape.dot_cross_tag = recv_ring_vec(); } return tape; } template void deal_session(trio & net, const beavers::session & s) { if (net.self() != role::p2) throw std::logic_error("deal_session is for the dealer"); send_party_tape(net, role::p0, s.export_party(0)); send_party_tape(net, role::p1, s.export_party(1)); } /// @brief Computing party receives its tape from the dealer. /// @tparam Ring Beaver ring /// @param net the connected trio /// @return this party's tape /// @throws std::logic_error if this process is p2 /// @throws std::runtime_error if a flag vector's length disagrees with its header template HEDLEY_WARN_UNUSED_RESULT beavers::party_tape accept_session(trio & net) { if (net.self() == role::p2) throw std::logic_error("dealer does not accept_session"); return recv_party_tape(net, role::p2); } } // namespace net } // namespace dpf #endif // LIBDPF_INCLUDE_DPF_NET_PARTY_TAPE_IO_HPP__