libdpf/party/flows_gadget.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

642 lines
24 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// @file party/flows_gadget.cpp
/// @brief Bench flows for word garbling, stacked Yao, FLUTE, and hidden shuffle.
/// @details Amalgamated into run.cpp. Every cross-party byte goes through
/// `net::trio` (the same local mesh `party_bench` already dials).
/// Two-party gadgets use the p0–p1 link. FLUTE's dealer is p2.
/// The hidden shuffle is the three ring passes, and the receiver
/// feeds the arrived array into the next party step.
#include "cases.hpp"
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <vector>
#include "dpf/arith_garble.hpp"
#include "dpf/flute.hpp"
#include "dpf/shuffle.hpp"
#include "dpf/yao.hpp"
#include "dpf/yao_stack.hpp"
namespace dpf
{
namespace party
{
namespace gadget
{
using net::role;
using net::trio;
void require(bool cond, const char * msg)
{
if (!cond)
throw std::runtime_error(msg);
}
void put_lab(std::vector<std::uint16_t> & blob, const arith_garble::lab & lab)
{
blob.insert(blob.end(), lab.d.begin(), lab.d.end());
}
arith_garble::lab take_lab(const std::uint16_t *& p, const std::uint16_t * end,
std::uint16_t mod)
{
if (static_cast<std::size_t>(end - p) < arith_garble::k_digits)
throw std::runtime_error("arith garble: short label");
arith_garble::lab lab;
lab.mod = mod;
for (std::size_t i = 0; i < arith_garble::k_digits; ++i)
lab.d[i] = *p++;
return lab;
}
std::uint16_t take_u16(const std::uint16_t *& p, const std::uint16_t * end)
{
if (p == end)
throw std::runtime_error("arith garble: short frame");
return *p++;
}
/// @brief p0 garbles and ships the evaluator view. p1 evaluates that view.
void arith_exchange(trio & net, role self, const arith_garble::circuit & c,
const std::uint16_t * semantic)
{
const auto plain = arith_garble::eval_plain(c, semantic);
if (self == role::p0)
{
auto st = arith_garble::detail::garble(c);
auto active = arith_garble::detail::evaluate(c, st, semantic);
std::size_t out_i = 0;
for (std::uint32_t id : c.outputs())
{
const std::uint16_t mod = c.nodes()[id].mod;
const std::uint16_t got = arith_garble::open_shares(
mod, st.zero[id].d[0], active[id].d[0]);
require(got == plain[id], "arith garble: garbler open");
++out_i;
}
require(out_i == c.outputs().size(), "arith garble: outputs");
std::vector<std::uint16_t> blob;
const auto & nodes = c.nodes();
for (std::uint32_t i = 0; i < nodes.size(); ++i)
{
const auto & nd = nodes[i];
if (nd.code == arith_garble::circuit::op::in)
put_lab(blob, active[i]);
else if (nd.code == arith_garble::circuit::op::proj)
{
for (const auto & row : st.proj[i].row)
put_lab(blob, row);
}
else if (nd.code == arith_garble::circuit::op::pass)
{
put_lab(blob, st.pass[i].payload[0]);
put_lab(blob, st.pass[i].payload[1]);
blob.push_back(st.pass[i].flag_ct[0]);
blob.push_back(st.pass[i].flag_ct[1]);
}
}
for (std::uint32_t id : c.outputs())
blob.push_back(st.zero[id].d[0]);
net.send_vec_to(role::p1, net::msg::bytes, blob);
return;
}
require(self == role::p1, "arith garble: party");
auto blob = net.recv_vec_from<std::uint16_t>(role::p0, net::msg::bytes);
const std::uint16_t * p = blob.data();
const std::uint16_t * end = p + blob.size();
arith_garble::detail::garble_state st;
const auto & nodes = c.nodes();
st.zero.resize(nodes.size());
st.delta.assign(static_cast<std::size_t>(arith_garble::k_max_mod) + 1,
arith_garble::lab{});
for (std::uint16_t m = 1; m <= arith_garble::k_max_mod; ++m)
st.delta[m].mod = m;
st.proj.resize(nodes.size());
st.pass.resize(nodes.size());
std::size_t n_in = 0;
for (const auto & nd : nodes)
if (nd.code == arith_garble::circuit::op::in)
++n_in;
for (std::uint32_t i = 0; i < nodes.size(); ++i)
{
const auto & nd = nodes[i];
if (nd.code == arith_garble::circuit::op::in)
st.zero[i] = take_lab(p, end, nd.mod);
else if (nd.code == arith_garble::circuit::op::proj)
{
const std::uint16_t m = nodes[nd.a].mod;
require(m > 0, "arith garble: projection modulus");
st.proj[i].row.resize(static_cast<std::size_t>(m - 1));
for (std::uint16_t color = 1; color < m; ++color)
st.proj[i].row[static_cast<std::size_t>(color - 1)] =
take_lab(p, end, nd.mod);
}
else if (nd.code == arith_garble::circuit::op::pass)
{
st.pass[i].payload[0] = take_lab(p, end, nd.mod);
st.pass[i].payload[1] = take_lab(p, end, nd.mod);
st.pass[i].flag_ct[0] = take_u16(p, end);
st.pass[i].flag_ct[1] = take_u16(p, end);
}
}
std::vector<std::uint16_t> masks;
masks.reserve(c.outputs().size());
for (std::size_t i = 0; i < c.outputs().size(); ++i)
masks.push_back(take_u16(p, end));
require(p == end, "arith garble: trailing bytes");
std::vector<std::uint16_t> zeros(n_in, 0);
auto active = arith_garble::detail::evaluate(c, st, zeros.data());
std::size_t out_i = 0;
for (std::uint32_t id : c.outputs())
{
const std::uint16_t mod = nodes[id].mod;
const std::uint16_t got = arith_garble::open_shares(
mod, masks[out_i], active[id].d[0]);
require(got == plain[id], "arith garble: evaluator open");
++out_i;
}
}
int run_proj(role self, trio & net, std::uint16_t mod)
{
if (self == role::p2)
return 0;
arith_garble::circuit c;
auto x = c.input(mod);
std::vector<std::uint16_t> phi(mod);
for (std::uint16_t i = 0; i < mod; ++i)
phi[i] = static_cast<std::uint16_t>((i * 3) % mod);
c.out(c.project(x, mod, std::move(phi)));
const std::uint16_t in = static_cast<std::uint16_t>(mod / 2);
arith_exchange(net, self, c, &in);
return 0;
}
int run_mul(role self, trio & net, std::uint16_t p)
{
if (self == role::p2)
return 0;
arith_garble::circuit c;
auto x = c.input(p);
auto y = c.input(p);
c.out(c.mul(x, y));
const std::uint16_t in[2] = {static_cast<std::uint16_t>(p - 1), 2};
arith_exchange(net, self, c, in);
return 0;
}
int run_thresh(role self, trio & net, unsigned b)
{
if (self == role::p2)
return 0;
arith_garble::circuit c;
const auto mod = static_cast<std::uint16_t>(b + 1);
std::vector<arith_garble::wire> bits;
bits.reserve(b);
for (unsigned i = 0; i < b; ++i)
bits.push_back(c.input(mod));
c.out(c.threshold(bits, static_cast<std::uint16_t>(b / 2)));
std::vector<std::uint16_t> in(b, 0);
for (unsigned i = 0; i < b; i += 2)
in[i] = 1;
arith_exchange(net, self, c, in.data());
return 0;
}
int run_chain(role self, trio & net)
{
if (self == role::p2)
return 0;
arith_garble::circuit c;
auto x = c.input(7);
auto y = c.input(7);
auto z = c.mul(x, y);
for (int i = 0; i < 3; ++i)
z = c.mul(z, x);
c.out(z);
const std::uint16_t in[2] = {2, 3};
arith_exchange(net, self, c, in);
return 0;
}
yao::netlist and_n(unsigned n)
{
yao::netlist nl;
std::vector<yao::bit> in;
in.reserve(n);
for (unsigned i = 0; i < n; ++i)
in.push_back(nl.shared_in());
auto acc = in[0];
for (unsigned i = 1; i < n; ++i)
acc = nl.and_(acc, in[i]);
nl.out(acc);
return nl;
}
yao::netlist xor2()
{
yao::netlist nl;
auto a = nl.shared_in();
auto b = nl.shared_in();
nl.out(nl.xor_(a, b));
return nl;
}
/// @brief Garbled tables and the evaluator's labels on the p0–p1 channel.
/// @details Party 1 runs `eval_party1` on the bytes that arrived. The choice
/// labels are the OT output for party 1's bits; base OT is its own
/// bench (`iknp`), not this garble row.
void yao_ship(trio & net, role self, const yao::netlist & nl,
const std::uint8_t * p0_bits, const std::uint8_t * p1_bits)
{
const role peer = self == role::p0 ? role::p1 : role::p0;
auto & link = net.to(peer);
std::size_t nchoice = 0;
std::size_t ndirect = 0;
for (std::uint32_t i = 0; i < nl.n_in(); ++i)
{
const auto kind = nl.kind_at(i);
if (kind == yao::input::shared || kind == yao::input::priv1)
++nchoice;
if (kind == yao::input::shared || kind == yao::input::priv0)
++ndirect;
}
const std::size_t ntable = static_cast<std::size_t>(nl.n_and()) * 2u;
std::vector<std::uint8_t> share;
if (self == role::p0)
{
auto g = yao::detail::garble_party0(nl, p0_bits);
require(g.tables.size() == ntable, "yao: table size");
require(g.direct.size() == ndirect, "yao: direct labels");
require(g.ot0.size() == nchoice && g.ot1.size() == nchoice, "yao: ot labels");
std::vector<yao::block> chosen(nchoice);
std::size_t oi = 0;
for (std::uint32_t i = 0; i < nl.n_in(); ++i)
{
const auto kind = nl.kind_at(i);
if (kind != yao::input::shared && kind != yao::input::priv1)
continue;
chosen[oi] = (p1_bits[i] & 1u) ? g.ot1[oi] : g.ot0[oi];
++oi;
}
std::vector<yao::block> blob;
blob.reserve(ntable + ndirect + nchoice);
blob.insert(blob.end(), g.tables.begin(), g.tables.end());
blob.insert(blob.end(), g.direct.begin(), g.direct.end());
blob.insert(blob.end(), chosen.begin(), chosen.end());
link.send_vec(blob, net::msg::bytes);
share = std::move(g.share);
}
else
{
const auto blob = link.recv_vec<yao::block>(net::msg::bytes);
require(blob.size() == ntable + ndirect + nchoice, "yao: payload size");
std::vector<yao::block> tables(ntable);
std::vector<yao::block> direct(ndirect);
std::vector<yao::block> chosen(nchoice);
if (ntable != 0)
std::memcpy(tables.data(), blob.data(), ntable * sizeof(yao::block));
if (ndirect != 0)
std::memcpy(direct.data(), blob.data() + ntable,
ndirect * sizeof(yao::block));
if (nchoice != 0)
std::memcpy(chosen.data(), blob.data() + ntable + ndirect,
nchoice * sizeof(yao::block));
share = yao::detail::eval_party1(nl, tables, direct, chosen);
}
auto other = net.exchange_vec_with(peer, share, net::msg::delta);
require(other.size() == share.size(), "yao: share length");
std::vector<std::uint8_t> semantic(nl.n_in());
for (std::uint32_t i = 0; i < nl.n_in(); ++i)
semantic[i] = static_cast<std::uint8_t>(p0_bits[i] ^ p1_bits[i]);
auto plain = yao::eval_plain(nl, semantic.data());
require(plain.size() == share.size(), "yao: output length");
for (std::size_t i = 0; i < plain.size(); ++i)
{
const auto opened = static_cast<std::uint8_t>(share[i] ^ other[i]);
require(opened == plain[i], "yao: open");
}
}
int run_if(role self, trio & net, unsigned heavy, unsigned light)
{
if (self == role::p2)
return 0;
auto then_nl = and_n(heavy);
std::vector<std::uint8_t> h0(heavy, 1);
std::vector<std::uint8_t> h1(heavy, 0);
if (self == role::p0)
{
auto else_nl = and_n(light);
std::vector<std::uint8_t> l0(light, 1);
std::vector<std::uint8_t> l1(light, 1);
auto stacked = yao::eval_if(then_nl, else_nl, 0, 0, h0.data(), h1.data(),
l0.data(), l1.data());
std::vector<std::uint8_t> semantic(heavy, 1);
auto plain = yao::eval_plain(then_nl, semantic.data());
require(stacked.share0.size() == plain.size(), "yao stack: outputs");
for (std::size_t i = 0; i < plain.size(); ++i)
{
const auto opened = static_cast<std::uint8_t>(
stacked.share0[i] ^ stacked.share1[i]);
require(opened == plain[i], "yao stack: if");
}
require(stacked.stack_blocks > 0, "yao stack: empty");
}
yao_ship(net, self, then_nl, h0.data(), h1.data());
return 0;
}
int run_hot(role self, trio & net, unsigned k)
{
if (self == role::p2)
return 0;
auto active = and_n(2);
const std::uint8_t bits0[2] = {1, 0};
const std::uint8_t bits1[2] = {0, 1};
if (self == role::p0)
{
std::vector<yao::netlist> branches;
std::vector<std::vector<std::uint8_t>> p0;
std::vector<std::vector<std::uint8_t>> p1;
branches.reserve(k);
for (unsigned i = 0; i < k; ++i)
{
branches.push_back(i % 2 == 0 ? and_n(2) : xor2());
p0.push_back({1, static_cast<std::uint8_t>(i & 1u)});
p1.push_back({0, 1});
}
auto stacked = yao::eval_one_hot(branches, 0, 0, p0, p1);
const std::uint8_t semantic[2] = {1, 1};
auto plain = yao::eval_plain(active, semantic);
require(stacked.share0.size() == plain.size(), "yao stack: one-hot outputs");
for (std::size_t i = 0; i < plain.size(); ++i)
{
const auto opened = static_cast<std::uint8_t>(
stacked.share0[i] ^ stacked.share1[i]);
require(opened == plain[i], "yao stack: one-hot");
}
require(stacked.stack_blocks > 0, "yao stack: one-hot empty");
}
yao_ship(net, self, active, bits0, bits1);
return 0;
}
std::vector<std::uint8_t> flute_columns(unsigned delta, unsigned n_out)
{
const unsigned rows = 1u << delta;
std::vector<std::uint8_t> columns(static_cast<std::size_t>(n_out) * rows);
for (unsigned w = 0; w < n_out; ++w)
for (unsigned j = 0; j < rows; ++j)
columns[static_cast<std::size_t>(w) * rows + j] =
static_cast<std::uint8_t>(((j >> (w % delta)) ^ w) & 1u);
return columns;
}
std::vector<std::uint8_t> flute_bits(unsigned delta)
{
std::vector<std::uint8_t> bits(delta, 0);
bits[0] = 1;
if (delta > 2)
bits[2] = 1;
return bits;
}
std::vector<std::uint8_t> flute_pack(const flute::detail::setup & s, unsigned party)
{
std::vector<std::uint8_t> out;
out.insert(out.end(), s.m.begin(), s.m.end());
out.insert(out.end(), s.share[party].begin(), s.share[party].end());
out.insert(out.end(), s.lamz[party].begin(), s.lamz[party].end());
return out;
}
int run_flute(role self, trio & net, unsigned delta, unsigned n_out)
{
const auto columns = flute_columns(delta, n_out);
const auto x = flute_bits(delta);
const unsigned rows = 1u << delta;
const std::uint32_t full = rows - 1u;
if (self == role::p2)
{
auto setup = flute::detail::make_setup(delta, n_out, 2, x.data());
auto to0 = flute_pack(setup, 0);
auto to1 = flute_pack(setup, 1);
net.send_bytes_to(role::p0, net::msg::bytes, to0.data(), to0.size());
net.send_bytes_to(role::p1, net::msg::bytes, to1.data(), to1.size());
return 0;
}
const unsigned party = self == role::p0 ? 0u : 1u;
auto bytes = net.recv_bytes_from(role::p2, net::msg::bytes);
const std::size_t need = static_cast<std::size_t>(delta) + rows + n_out;
require(bytes.size() == need, "flute: deal size");
flute::detail::setup setup;
setup.m.assign(bytes.begin(), bytes.begin() + delta);
setup.share.assign(2, {});
setup.share[party].assign(bytes.begin() + delta, bytes.begin() + delta + rows);
setup.lamz.assign(2, {});
setup.lamz[party].assign(bytes.end() - static_cast<std::ptrdiff_t>(n_out),
bytes.end());
std::vector<std::uint8_t> mine(static_cast<std::size_t>(n_out) * 2u);
for (unsigned w = 0; w < n_out; ++w)
{
const std::uint8_t * column =
columns.data() + static_cast<std::size_t>(w) * rows;
mine[w] = flute::detail::party_v(setup, party, delta, full, column,
setup.lamz[party][w]);
mine[n_out + w] = setup.lamz[party][w];
}
const role peer = self == role::p0 ? role::p1 : role::p0;
auto theirs = net.exchange_vec_with(peer, mine, net::msg::bytes);
auto expect = flute::eval_plain(delta, n_out, columns.data(), x.data());
for (unsigned w = 0; w < n_out; ++w)
{
const std::uint8_t * column =
columns.data() + static_cast<std::size_t>(w) * rows;
const std::uint8_t t = flute::detail::dot_column(
full, delta, setup.m.data(), column);
const auto opened = static_cast<std::uint8_t>(
mine[w] ^ theirs[w] ^ t ^ mine[n_out + w] ^ theirs[n_out + w]);
require(opened == expect[w], "flute: open");
}
return 0;
}
rss::seed_bundle shuffle_bundle()
{
rss::seed_bundle bundle{};
auto fill = [](rss::seed_block & seed, std::uint8_t tag) {
auto * p = reinterpret_cast<std::uint8_t *>(&seed);
for (std::size_t i = 0; i < sizeof(seed); ++i)
p[i] = static_cast<std::uint8_t>(tag + i * 17u);
};
fill(bundle.k01, 1);
fill(bundle.k12, 2);
fill(bundle.k20, 3);
return bundle;
}
shuffle::shuffle_party_view<std::uint64_t> shuffle_view(unsigned me, std::size_t n)
{
std::uint64_t rng = 0xA5A5A5A5A5A5A5A5ull;
auto draw = [&] {
rng = rng * 6364136223846793005ull + 1u;
return rng;
};
shuffle::shuffle_party_view<std::uint64_t> view;
view.own.resize(n);
view.next.resize(n);
for (std::size_t i = 0; i < n; ++i)
{
const auto a = draw();
const auto b = draw();
const auto c = static_cast<std::uint64_t>(i) - a - b;
if (me == 0)
{
view.own[i] = a;
view.next[i] = b;
}
else if (me == 1)
{
view.own[i] = b;
view.next[i] = c;
}
else
{
view.own[i] = c;
view.next[i] = a;
}
}
return view;
}
int run_shuffle(role self, trio & net, std::size_t n)
{
const unsigned me = static_cast<unsigned>(self);
const auto bundle = shuffle_bundle();
const std::uint64_t index = 1;
auto seeds = rss::party_seeds::from_bundle(bundle, me);
auto view = shuffle_view(me, n);
const unsigned order[3] = {2u, 0u, 1u};
for (unsigned left : order)
{
const unsigned u = shuffle::hidden_u_party(left);
const unsigned side = shuffle::hidden_side_party(left);
if (me == u)
{
auto step = shuffle::shuffle_hidden_pass<std::uint64_t>(
me, seeds, view, index, left, nullptr);
require(step.out.sends, "shuffle: u sends");
require(step.out.to == side, "shuffle: u recipient");
net.send_vec_to(static_cast<role>(step.out.to), net::msg::ring_vector,
step.out.data);
view = std::move(step.view);
}
else if (me == side)
{
auto inbound = net.recv_vec_from<std::uint64_t>(
static_cast<role>(u), net::msg::ring_vector);
auto step = shuffle::shuffle_hidden_pass<std::uint64_t>(
me, seeds, view, index, left, &inbound);
require(step.out.sends, "shuffle: side sends");
require(step.out.to == left, "shuffle: side recipient");
net.send_vec_to(static_cast<role>(step.out.to), net::msg::ring_vector,
step.out.data);
view = std::move(step.view);
}
else
{
auto inbound = net.recv_vec_from<std::uint64_t>(
static_cast<role>(side), net::msg::ring_vector);
auto step = shuffle::shuffle_hidden_pass<std::uint64_t>(
me, seeds, view, index, left, &inbound);
require(!step.out.sends, "shuffle: left-out is silent");
view = std::move(step.view);
}
}
if (self == role::p0)
{
auto from1 = net.recv_vec_from<std::uint64_t>(role::p1, net::msg::ring_vector);
auto from2 = net.recv_vec_from<std::uint64_t>(role::p2, net::msg::ring_vector);
require(from1.size() == n && from2.size() == n, "shuffle: open size");
std::vector<std::uint64_t> clear(n);
for (std::size_t i = 0; i < n; ++i)
clear[i] = i;
auto expect = shuffle::permute(clear,
shuffle::permutation_from_seed(bundle.k01, n, index));
expect = shuffle::permute(expect,
shuffle::permutation_from_seed(bundle.k12, n, index));
expect = shuffle::permute(expect,
shuffle::permutation_from_seed(bundle.k20, n, index));
for (std::size_t i = 0; i < n; ++i)
{
const auto got = view.own[i] + from1[i] + from2[i];
require(got == expect[i], "shuffle: open");
}
}
else
{
net.send_vec_to(role::p0, net::msg::ring_vector, view.own);
}
return 0;
}
int arith_proj_m5(role self, trio & net) { return run_proj(self, net, 5); }
int arith_proj_m17(role self, trio & net) { return run_proj(self, net, 17); }
int arith_proj_m64(role self, trio & net) { return run_proj(self, net, 64); }
int arith_mul_p5(role self, trio & net) { return run_mul(self, net, 5); }
int arith_mul_p7(role self, trio & net) { return run_mul(self, net, 7); }
int arith_mul_p11(role self, trio & net) { return run_mul(self, net, 11); }
int arith_thresh_b8(role self, trio & net) { return run_thresh(self, net, 8); }
int arith_thresh_b16(role self, trio & net) { return run_thresh(self, net, 16); }
int arith_chain_mul4(role self, trio & net) { return run_chain(self, net); }
int yao_if_4_2(role self, trio & net) { return run_if(self, net, 4, 2); }
int yao_if_16_8(role self, trio & net) { return run_if(self, net, 16, 8); }
int yao_onehot_k4(role self, trio & net) { return run_hot(self, net, 4); }
int yao_onehot_k8(role self, trio & net) { return run_hot(self, net, 8); }
int flute_d2(role self, trio & net) { return run_flute(self, net, 2, 1); }
int flute_d4(role self, trio & net) { return run_flute(self, net, 4, 1); }
int flute_d8(role self, trio & net) { return run_flute(self, net, 8, 1); }
int flute_d4_o8(role self, trio & net) { return run_flute(self, net, 4, 8); }
int shuffle_n16(role self, trio & net) { return run_shuffle(self, net, 16); }
int shuffle_n64(role self, trio & net) { return run_shuffle(self, net, 64); }
int shuffle_n256(role self, trio & net) { return run_shuffle(self, net, 256); }
#define REG(name, tags, fn) \
register_flow(flow{#name, tags, fn, true})
} // namespace gadget
void register_gadget_flows()
{
using namespace gadget;
REG(arith_proj_m5, "bench arith garble", arith_proj_m5);
REG(arith_proj_m17, "bench arith garble", arith_proj_m17);
REG(arith_proj_m64, "bench arith garble", arith_proj_m64);
REG(arith_mul_p5, "bench arith garble", arith_mul_p5);
REG(arith_mul_p7, "bench arith garble", arith_mul_p7);
REG(arith_mul_p11, "bench arith garble", arith_mul_p11);
REG(arith_thresh_b8, "bench arith garble", arith_thresh_b8);
REG(arith_thresh_b16, "bench arith garble", arith_thresh_b16);
REG(arith_chain_mul4, "bench arith garble", arith_chain_mul4);
REG(yao_if_4_2, "bench yao stack", yao_if_4_2);
REG(yao_if_16_8, "bench yao stack", yao_if_16_8);
REG(yao_onehot_k4, "bench yao stack", yao_onehot_k4);
REG(yao_onehot_k8, "bench yao stack", yao_onehot_k8);
REG(flute_d2, "bench flute", flute_d2);
REG(flute_d4, "bench flute", flute_d4);
REG(flute_d8, "bench flute", flute_d8);
REG(flute_d4_o8, "bench flute", flute_d4_o8);
REG(shuffle_n16, "bench shuffle rss", shuffle_n16);
REG(shuffle_n64, "bench shuffle rss", shuffle_n64);
REG(shuffle_n256, "bench shuffle rss", shuffle_n256);
}
} // namespace party
} // namespace dpf