libdpf/examples/protocol/party_node.cpp
Ryan Henry 0d22946a0e Checkpoint the party/runtime stack before share-program and malicious-mode work.
Ship the TLS mesh, composer, Beaver/Yao/leaf MPC, prep/online paths, apps, and docs so the tree is pushable before elevating share_expr, security_mode, and prep resume.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 05:59:19 -06:00

86 lines
3.1 KiB
C++

#include <cstdint>
#include <cstring>
#include <iostream>
#include <vector>
#include "dpf/launch.hpp"
#include "dpf/run_log.hpp"
// One party of a two- or three-party run, one process per party.
//
// c++ -std=c++17 -march=native -pthread -I include -I thirdparty \
// -DLIBDPF_GIT_REV="\"$(git describe --always --dirty)\"" \
// examples/protocol/party_node.cpp -lsctp -lssl -lcrypto -o party_node
// ./party_node --party=0 --peers=127.0.0.1:9100,127.0.0.1:9101 &
// ./party_node --party=1 --peers=127.0.0.1:9100,127.0.0.1:9101
//
// Any run_config key works as a flag (--transport=parallel --lanes=2 ...).
// Start order does not matter: connects retry until --connect_ms.
//
// Links are TLS 1.3. With no keys they are encrypted but unauthenticated (and
// the log says so). To authenticate, give each party a key and the others'
// public keys (dpf_keygen p0.key prints p0's), for example in p0.conf:
// identity = p0.key
// peer.1 = <p1's public key>
// and run ./party_node --config=p0.conf --party=0 --peers=...
// The run log goes to stderr at info; --log=file:/tmp/p0.log --log_level=debug
// or DPF_LOG / DPF_LOG_LEVEL redirect it (see dpf/run_log.hpp).
//
// With three peers the protocol adds a dealer-delivered mask: party 2 is the
// dealer, and parties 0 and 1 each open (input + mask share).
int main(int argc, char ** argv)
{
try
{
const auto args = dpf::app::parse_node_args(argc, argv);
dpf::app::start_logging(args.cfg);
const unsigned me = args.party;
const bool dealer = args.peers.size() == 3;
dpf::protocol::composer c(me);
auto x = c.input(dpf::protocol::domain::a, 8);
dpf::protocol::node opened{};
dpf::protocol::node mask{};
if (dealer)
{
auto pad = c.input(dpf::protocol::domain::a, 8);
mask = c.dealer_deliver(pad);
opened = c.exchange(x);
(void)pad;
}
else
opened = c.exchange(x);
auto plan = c.schedule();
dpf::app::party_values values(plan.nodes().size());
for (auto & v : values)
v.assign(8, 0);
const std::uint64_t mine = me == 0 ? 11 : 31;
std::memcpy(values[x.id].data(), &mine, 8);
if (dealer && me == 2)
{
const std::uint64_t pad = 7;
std::memcpy(values[plan.inputs_of(mask.id)[0]].data(), &pad, 8);
}
const auto wire = dpf::app::run_node(args, plan, values);
std::uint64_t got = 0;
std::memcpy(&got, values[opened.id].data(), 8);
std::cout << "party " << me << " open=" << got;
if (dealer && me < 2)
{
std::uint64_t m = 0;
std::memcpy(&m, values[mask.id].data(), 8);
std::cout << " mask=" << m;
}
std::cout << " wire_out=" << wire.bytes_out << " wire_in=" << wire.bytes_in
<< "\n";
return (me == 2 || got == 42) ? 0 : 1;
}
catch (const std::exception & e)
{
DPF_LOG(error, "node.failed").kv("what", e.what());
std::cerr << "party_node: " << e.what() << "\n";
return 1;
}
}