libdpf/examples/protocol/stream_dpf3_smoke.cpp

146 lines
4.2 KiB
C++
Raw Normal View History

/// @file examples/protocol/stream_dpf3_smoke.cpp
/// @brief Local DPF3 eval plus trio-shaped stream edges (peer / rss_next / dealer).
#include <cstdint>
#include <cstring>
#include <iostream>
#include <thread>
#include <type_traits>
#include <vector>
#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 <typename T>
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<T>, "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;
}