/// @file examples/protocol/stream_dpf3_smoke.cpp /// @brief Local DPF3 eval plus trio-shaped stream edges (peer / rss_next / dealer). #include #include #include #include #include #include #include "dpf.hpp" #include "dpf/net/stream_array.hpp" #include "dpf/net/stream_mesh.hpp" #include "dpf/protocol_factory.hpp" namespace { struct trio_edge_ping { std::uint32_t from = 0; std::uint32_t to = 0; std::uint64_t nonce = 0; }; struct trio_party_streams { dpf::net::memory_stream_array & peer; dpf::net::memory_stream_array & rss_next; dpf::net::memory_stream_array & dealer; }; template void exchange_pod(dpf::net::memory_stream_array & link, std::size_t stream, const T & mine, T & theirs) { static_assert(std::is_trivially_copyable_v, "pod"); link.write(stream, &mine, sizeof(T)); link.flush(stream); link.read(stream, &theirs, sizeof(T)); } void ping_edge(trio_party_streams s, unsigned me, unsigned peer_id, std::uint64_t nonce, std::size_t stream_idx) { trio_edge_ping mine{me, peer_id, nonce}; trio_edge_ping theirs{}; exchange_pod(s.peer, stream_idx, mine, theirs); if (theirs.from != peer_id || theirs.to != me) throw std::runtime_error("stream_dpf3_smoke: peer edge"); } } // namespace int main() { using Input = std::uint8_t; const Input alpha = 42; const dpf::fp61 beta{7}; auto [k1, k2, k3] = dpf::make_dpf3(alpha, beta); const dpf::fp61 y1 = dpf::eval_point(k1, alpha); const dpf::fp61 y2 = dpf::eval_point(k2, alpha); const dpf::fp61 y3 = dpf::eval_point(k3, alpha); const dpf::fp61 opened = dpf::reconstruct( dpf::as_share(k1, y1), dpf::as_share(k2, y2), dpf::as_share(k3, y3)); if (opened != beta) { std::cerr << "dpf3 local eval\n"; return 1; } // Dealer delivers a keyed marker on stream 0 to each evaluator. auto dealer0 = dpf::net::make_memory_stream_pair(1); auto dealer1 = dpf::net::make_memory_stream_pair(1); struct key_delivery { std::uint32_t party = 0; std::uint64_t beta_raw = 0; }; key_delivery m0{0, beta.raw()}, m1{1, beta.raw()}; dealer0.first.write(0, &m0, sizeof(m0)); dealer0.first.flush(0); dealer1.first.write(0, &m1, sizeof(m1)); dealer1.first.flush(0); key_delivery got0{}, got1{}; dealer0.second.read(0, &got0, sizeof(got0)); dealer1.second.read(0, &got1, sizeof(got1)); if (got0.beta_raw != beta.raw() || got1.beta_raw != beta.raw()) { std::cerr << "dealer stream delivery\n"; return 1; } // Trio-shaped edges on a 3-party clique (p2 = dealer): peer + rss_next + dealer. constexpr std::size_t k_peer = 0; constexpr std::size_t k_rss = 1; auto clique = dpf::net::make_memory_stream_clique(3, 2); std::exception_ptr err; std::thread t0([&] { try { trio_party_streams s{clique.end(0, 1), clique.end(0, 1), clique.end(0, 2)}; ping_edge(s, 0, 1, 11, k_peer); const trio_edge_ping rss_out{0, 1, 99}; s.rss_next.write(k_rss, &rss_out, sizeof(rss_out)); s.rss_next.flush(k_rss); } catch (...) { err = std::current_exception(); } }); std::thread t1([&] { try { trio_party_streams s{clique.end(1, 0), clique.end(1, 0), clique.end(1, 2)}; ping_edge(s, 1, 0, 22, k_peer); trio_edge_ping rss_in{}; s.rss_next.read(k_rss, &rss_in, sizeof(rss_in)); if (rss_in.from != 0u) throw std::runtime_error("stream_dpf3_smoke: rss_next"); const trio_edge_ping dealer_out{1, 2, 88}; s.dealer.write(k_rss, &dealer_out, sizeof(dealer_out)); s.dealer.flush(k_rss); } catch (...) { err = std::current_exception(); } }); t0.join(); t1.join(); if (err) std::rethrow_exception(err); trio_edge_ping dealer_in{}; clique.end(2, 1).read(k_rss, &dealer_in, sizeof(dealer_in)); if (dealer_in.from != 1u || dealer_in.to != 2u) { std::cerr << "dealer edge\n"; return 1; } std::cout << "stream_trio_ok\n"; return 0; }