libdpf/examples/protocol/share_runtime.cpp

100 lines
3.9 KiB
C++
Raw Permalink Normal View History

/// @file examples/protocol/share_runtime.cpp
/// @brief Smoke demo: stream_array dealer/peer gadgets and clear sanity checks.
/// @details Also drives a composed open on the stream framework
/// (`drive_both_on_streams`). The same protocol runs unchanged over the
/// truly asynchronous backends (`dpf::net::async_stream_array` +
/// `dpf::async::overlapped_byte_protocol`, or `async_round_sink`), and
/// on Linux over real SCTP (`async_sctp_stream_array`, index i -> SCTP
/// stream i). The performance harness (experiment_bench) selects any of
/// these with `DPF_TRANSPORT=memory|stream|async|mux|parallel|sctp`.
#include <cstdint>
#include <cstring>
#include <iostream>
#include <thread>
#include <vector>
#include "dpf/compose.hpp"
#include "dpf/factory_gadgets.hpp"
#include "dpf/net/stream_array.hpp"
#include "dpf/protocol_factory.hpp"
#include "dpf/rss_seed.hpp"
int main()
{
auto bundle = dpf::rss::sample_seed_bundle();
auto z0 = dpf::rss::zero_share<std::uint64_t>(
dpf::rss::party_seeds::from_bundle(bundle, 0), 0);
auto z1 = dpf::rss::zero_share<std::uint64_t>(
dpf::rss::party_seeds::from_bundle(bundle, 1), 0);
auto z2 = dpf::rss::zero_share<std::uint64_t>(
dpf::rss::party_seeds::from_bundle(bundle, 2), 0);
std::cout << "rss_zero_sum=" << (z0 + z1 + z2) << "\n";
// Dealer: one ring triple per party; peer: d and e opens.
auto peer = dpf::net::make_memory_stream_pair(2);
auto d0 = dpf::net::make_memory_stream_pair(1);
auto d1 = dpf::net::make_memory_stream_pair(1);
constexpr std::uint16_t limb = 8;
dpf::factory::make_dealer(d0.first, d1.first, 1, [limb] {
return dpf::factory::deal_ring_triple(limb);
});
std::uint64_t prod0 = 0, prod1 = 0;
std::thread t0([&] {
prod0 = dpf::factory::beaver_mul_online(0, 6, 7, peer.first, d0.second,
0, 0, 1, limb);
});
std::thread t1([&] {
prod1 = dpf::factory::beaver_mul_online(1, 0, 0, peer.second, d1.second,
0, 0, 1, limb);
});
t0.join();
t1.join();
std::cout << "beaver_mul_open=" << (prod0 + prod1) << "\n";
// GMW AND 1∧1 via make_protocol_factory.
auto and_peer = dpf::net::make_memory_stream_pair(1);
auto ad0 = dpf::net::make_memory_stream_pair(1);
auto ad1 = dpf::net::make_memory_stream_pair(1);
dpf::factory::make_dealer(ad0.first, ad1.first, 1,
dpf::factory::make_gmw_and_dealer_functor());
std::uint8_t z0b = 0, z1b = 0;
std::thread a0([&] {
z0b = dpf::factory::gmw_and_online(0, 1, 1, and_peer.first, ad0.second);
});
std::thread a1([&] {
z1b = dpf::factory::gmw_and_online(1, 0, 0, and_peer.second, ad1.second);
});
a0.join();
a1.join();
std::cout << "gmw_and_xor=" << static_cast<unsigned>(z0b ^ z1b) << "\n";
// Compose an open and drive both parties on the stream framework. This is
// the same schedule the async backends run; here it uses in-process memory
// stream arrays via drive_both_on_streams.
{
using dpf::protocol::domain;
dpf::protocol::composer comp0(0), comp1(1);
auto a = comp0.input(domain::a, 8);
auto b = comp1.input(domain::a, 8);
auto oa = comp0.exchange(a);
auto ob = comp1.exchange(b);
auto p0 = comp0.schedule();
auto p1 = comp1.schedule();
std::vector<std::vector<std::uint8_t>> va(p0.nodes().size()),
vb(p1.nodes().size());
const std::uint64_t xa = 17, xb = 25;
va[a.id].assign(8, 0);
vb[b.id].assign(8, 0);
std::memcpy(va[a.id].data(), &xa, 8);
std::memcpy(vb[b.id].data(), &xb, 8);
dpf::protocol::drive_both_on_streams(p0, p1, va, vb);
std::uint64_t open0 = 0;
std::memcpy(&open0, va[oa.id].data(), 8);
(void)ob;
std::cout << "compose_open_on_streams=" << open0 << "\n";
}
return 0;
}