libdpf/party/flows_coverage.cpp

793 lines
26 KiB
C++
Raw Permalink Normal View History

/// @file party/flows_coverage.cpp
/// @brief Party flows that close protocol / type gaps not hit by other amalgams.
/// @details Amalgamated into run.cpp (do not compile as a second TU). Dealer
/// (p2) distributes keys for paint / incremental / exotic payloads
/// because oblivious DS rejects paint kinds. Geneval full/sequence and
/// arith_output are dealer-run and share-split. CCMP is a 2-party mesh.
#include "cases.hpp"
#include "dist_dpf3.hpp"
#include "flow_util.hpp"
#include "key_io.hpp"
#include "registry.hpp"
#include <array>
#include <cstdint>
#include <cstring>
#include <string>
#include <utility>
#include <vector>
#include "simde/simde/x86/avx2.h"
#include "dpf.hpp"
#include "dpf/bitstring.hpp"
#include "dpf/constrained_cmp.hpp"
#include "dpf/dcf.hpp"
#include "dpf/dpf3_ds.hpp"
#include "dpf/eval_full.hpp"
#include "dpf/eval_inner_product.hpp"
#include "dpf/eval_point.hpp"
#include "dpf/eval_sequence.hpp"
#include "dpf/field128.hpp"
#include "dpf/geneval.hpp"
#include "dpf/json.hpp"
#include "dpf/keyword2.hpp"
#include "dpf/modint.hpp"
#include "dpf/p256.hpp"
#include "grotto/fixedpoint.hpp"
#include "grotto/nmod.hpp"
namespace dpf
{
namespace party
{
namespace coverage
{
using util::open_additive;
using util::open_subtractive;
using util::require;
using util::role;
using util::share_bits;
using util::trio;
using util::u64;
static constexpr char cov_kw_pat[] = "[ab]{8}";
// ---- shared helpers --------------------------------------------------------
std::uint64_t paint_matched_unit(std::size_t matched, std::uint64_t, bool)
{
return static_cast<std::uint64_t>(matched);
}
std::uint64_t lcp_len(std::uint8_t x, std::uint8_t alpha, std::size_t n = 8)
{
for (std::size_t i = 0; i < n; ++i)
{
const std::uint8_t shift = static_cast<std::uint8_t>(n - 1 - i);
if (((x >> shift) & 1) != ((alpha >> shift) & 1))
return static_cast<std::uint64_t>(i);
}
return n;
}
template <typename Spec, typename Fn0, typename Fn1>
void deal_cmp_keys(trio & net, role self, Spec spec, const Fn0 & on0,
const Fn1 & on1)
{
using Input = std::uint8_t;
const Input alpha = 0xB4;
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha, spec);
send_key(net.to(role::p0), k0);
send_key(net.to(role::p1), k1);
return;
}
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(make_dpf(Input{}, spec)))>;
auto key = recv_key<K>(net.to(role::p2));
on0(key, alpha);
return;
}
using K = std::decay_t<decltype(std::get<1>(make_dpf(Input{}, spec)))>;
auto key = recv_key<K>(net.to(role::p2));
on1(key, alpha);
}
template <typename Key>
void check_paint_grid(trio & net, role self, const Key & key, std::uint8_t alpha,
auto expect_fn, const char * tag)
{
const u64 mask = key.cmp().mask;
const std::array<std::uint8_t, 8> pts{
0, 1, alpha, static_cast<std::uint8_t>(alpha ^ 1u), 0x55, 0xAA, 0xFE, 0xFF};
for (std::uint8_t x : pts)
{
const u64 mine = share_bits(eval_point(cmp, key, x)) & mask;
const u64 opened = open_additive(net, self, mine) & mask;
if (self == role::p0)
require(opened == (expect_fn(x, alpha) & mask), tag);
}
}
// ---- paints (F_DCF path paints; dealer distribute) --------------------------
int cov_paint_lcp(role self, trio & net)
{
auto on = [&](const auto & key, std::uint8_t alpha) {
check_paint_grid(net, self, key, alpha,
[](std::uint8_t x, std::uint8_t a) { return lcp_len(x, a); },
"paint lcp");
};
deal_cmp_keys(net, self, lcp(u64{1}), on, on);
return 0;
}
int cov_paint_one_hot(role self, trio & net)
{
auto on = [&](const auto & key, std::uint8_t alpha) {
check_paint_grid(net, self, key, alpha,
[](std::uint8_t x, std::uint8_t a) {
return 1ULL << lcp_len(x, a);
},
"paint one_hot");
};
deal_cmp_keys(net, self, diverge_one_hot(u64{1}), on, on);
return 0;
}
int cov_paint_break_bit(role self, trio & net)
{
auto on = [&](const auto & key, std::uint8_t alpha) {
check_paint_grid(net, self, key, alpha,
[](std::uint8_t x, std::uint8_t a) {
const auto d = lcp_len(x, a);
if (d >= 8)
return 0ULL;
return 3ULL * ((a >> (7 - d)) & 1);
},
"paint break_bit");
};
deal_cmp_keys(net, self, break_bit(u64{3}), on, on);
return 0;
}
int cov_paint_path(role self, trio & net)
{
auto on = [&](const auto & key, std::uint8_t alpha) {
check_paint_grid(net, self, key, alpha,
[](std::uint8_t x, std::uint8_t a) { return lcp_len(x, a); },
"paint path");
};
deal_cmp_keys(net, self, path_paint(paint_matched_unit), on, on);
return 0;
}
int cov_paint_prefix_with_length(role self, trio & net)
{
auto on = [&](const auto & key, std::uint8_t alpha) {
check_paint_grid(net, self, key, alpha,
[](std::uint8_t x, std::uint8_t a) {
const auto d = lcp_len(x, a);
const u64 low = d == 0 ? 0
: (d >= 8 ? a : static_cast<u64>(a) >> (8 - d));
return (low << 4) | d;
},
"paint prefix_with_length");
};
deal_cmp_keys(net, self, prefix_with_length<4>(u64{1}), on, on);
return 0;
}
// ---- F_IDPF / eq_at / idcf -------------------------------------------------
int cov_idpf_at(role self, trio & net)
{
using Input = std::uint16_t;
const Input alpha = 0xa5c3;
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha, at<8>(std::uint8_t{42}),
at<12>(std::uint16_t{7}));
send_key(net.to(role::p0), k0);
send_key(net.to(role::p1), k1);
return 0;
}
auto check = [&](const auto & key) {
const auto y8 = *eval_point(out<0, 8>, key, alpha);
const auto o8 = open_subtractive(net, self, share_bits(y8));
if (self == role::p0)
require(o8 == std::uint8_t{42}, "idpf at8");
const auto y12 = *eval_point(out<1, 12>, key, alpha);
const auto o12 = open_subtractive(net, self, share_bits(y12));
if (self == role::p0)
require(o12 == std::uint16_t{7}, "idpf at12");
};
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(
make_dpf(Input{}, at<8>(std::uint8_t{}), at<12>(std::uint16_t{}))))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
using K = std::decay_t<decltype(std::get<1>(
make_dpf(Input{}, at<8>(std::uint8_t{}), at<12>(std::uint16_t{}))))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
int cov_eq_at(role self, trio & net)
{
using Input = std::uint16_t;
const Input alpha = 0x1234;
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha,
eq_at<8>(std::uint16_t{99}, std::uint16_t{7}));
send_key(net.to(role::p0), k0);
send_key(net.to(role::p1), k1);
return 0;
}
auto check = [&](const auto & key) {
// High 8 bits of alpha match → true branch 99 on that prefix lane.
const auto y_on = *eval_point(out<0, 8>, key, alpha);
const auto o_on = open_subtractive(net, self, share_bits(y_on));
if (self == role::p0)
require(o_on == std::uint16_t{99}, "eq_at on");
const Input miss = static_cast<Input>(alpha ^ 0x0100);
const auto y_off = *eval_point(out<0, 8>, key, miss);
const auto o_off = open_subtractive(net, self, share_bits(y_off));
if (self == role::p0)
require(o_off == std::uint16_t{7}, "eq_at off");
};
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(
make_dpf(Input{}, eq_at<8>(std::uint16_t{}, std::uint16_t{}))))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
using K = std::decay_t<decltype(std::get<1>(
make_dpf(Input{}, eq_at<8>(std::uint16_t{}, std::uint16_t{}))))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
int cov_idcf(role self, trio & net)
{
using Input = std::uint8_t;
const Input alpha = 0x40;
const u64 beta = 5;
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha, idcf(gt(beta)));
send_key(net.to(role::p0), k0);
send_key(net.to(role::p1), k1);
return 0;
}
auto check = [&](const auto & key) {
const u64 mask = key.cmp().mask;
for (Input x : {Input{0x3f}, alpha, Input{0x41}})
{
const u64 mine = share_bits(eval_point(cmp, key, x)) & mask;
const u64 opened = open_additive(net, self, mine) & mask;
if (self == role::p0)
{
const u64 want = x > alpha ? beta : 0u;
require(opened == want, "idcf gt");
}
}
};
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(
make_dpf(Input{}, idcf(gt(u64{})))))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
using K = std::decay_t<decltype(std::get<1>(
make_dpf(Input{}, idcf(gt(u64{})))))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
// ---- F_GenEval full / sequence / arith_output ------------------------------
struct CovPad
{
std::uint64_t n = 1;
simde__m128i block()
{
auto v = simde_mm_set_epi64x(static_cast<long long>(n),
static_cast<long long>(n * 9 + 3));
n += 2;
return v;
}
std::uint8_t bit() { return static_cast<std::uint8_t>(n++ & 1u); }
};
simde__m128i cov_roots[32];
int cov_ri = 0;
simde__m128i cov_take_root() { return cov_roots[cov_ri++]; }
void cov_reset_roots()
{
cov_ri = 0;
for (int i = 0; i < 32; ++i)
cov_roots[i] = simde_mm_set_epi64x(0x2222 * (i + 1), 0xBEEF0000u + i * 13);
}
HEDLEY_PRAGMA(GCC diagnostic push)
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
ds_randomness<simde__m128i (*)(), CovPad> cov_rng()
{
return {cov_take_root, CovPad{}};
}
HEDLEY_PRAGMA(GCC diagnostic pop)
int cov_geneval_full(role self, trio & net)
{
using Input = std::uint8_t;
using Output = std::uint8_t;
const Input alpha = 0x3c;
const Input x0 = 0x10;
const Input x1 = static_cast<Input>(alpha ^ x0);
const Output y = 0x7e;
if (self == role::p2)
{
cov_reset_roots();
auto g = geneval_full(x0, x1, cov_rng(), y);
require(g.party0.size() == 256u, "geneval_full size");
net.to(role::p0).send_vec(g.party0);
net.to(role::p1).send_vec(g.party1);
return 0;
}
auto mine = net.to(role::p2).recv_vec<Output>();
require(mine.size() == 256u, "geneval_full recv");
const Output opened = open_subtractive(net, self, mine[alpha]);
const Output off = open_subtractive(net, self, mine[0]);
if (self == role::p0)
{
require(opened == y, "geneval_full on");
require(off == Output{0}, "geneval_full off");
}
return 0;
}
int cov_geneval_sequence(role self, trio & net)
{
using Input = std::uint8_t;
using Output = std::uint16_t;
const Input alpha = 0x2a;
const Input x0 = 0x07;
const Input x1 = static_cast<Input>(alpha ^ x0);
const Output y = 99;
const std::array<Input, 5> seq{0, 1, alpha, 200, 255};
if (self == role::p2)
{
cov_reset_roots();
auto g = geneval_sequence(x0, x1, seq.begin(), seq.end(), cov_rng(), y);
require(g.party0.size() == seq.size(), "geneval_seq size");
net.to(role::p0).send_vec(g.party0);
net.to(role::p1).send_vec(g.party1);
return 0;
}
auto mine = net.to(role::p2).recv_vec<Output>();
require(mine.size() == seq.size(), "geneval_seq recv");
for (std::size_t i = 0; i < seq.size(); ++i)
{
const Output opened = open_subtractive(net, self, mine[i]);
if (self == role::p0)
require(opened == (seq[i] == alpha ? y : Output{0}), "geneval_seq");
}
return 0;
}
int cov_arith_output(role self, trio & net)
{
using Input = std::uint8_t;
using Output = std::uint32_t;
const Input alpha = 0x2a;
const Input x0 = 0x55;
const Input x1 = static_cast<Input>(alpha ^ x0);
const Output beta = 0x01020304;
const Output y0 = 0x00010002;
const Output y1 = static_cast<Output>(beta - y0);
if (self == role::p2)
{
cov_reset_roots();
auto g = geneval_point(arith_output, x0, x1, alpha, cov_rng(), y0, y1);
require(g.party0.size() == 1u && g.leaf_live, "arith_output live");
net.to(role::p0).send(net::msg::delta, g.party0[0]);
net.to(role::p1).send(net::msg::delta, g.party1[0]);
return 0;
}
const Output mine = net.to(role::p2).recv<Output>(net::msg::delta);
const Output opened = open_subtractive(net, self, mine);
if (self == role::p0)
require(opened == beta, "arith_output");
return 0;
}
// ---- F_CCMP ----------------------------------------------------------------
int cov_ccmp(role self, trio & net)
{
if (self == role::p2)
return 0;
const u64 mine = self == role::p0 ? 4u : 5u;
const role peer = self == role::p0 ? role::p1 : role::p0;
std::uint8_t z0 = 0, z1 = 0, l = 0;
detail::ccmp_party_terms(mine, self == role::p0 ? 0 : 1, z0, z1, l);
const std::uint8_t peer_z0 = net.exchange_with(peer, z0);
const std::uint8_t peer_z1 = net.exchange_with(peer, z1);
const std::uint8_t peer_l = net.exchange_with(peer, l);
const std::uint8_t opened_z0 = static_cast<std::uint8_t>(z0 ^ peer_z0);
const std::uint8_t opened_z1 = static_cast<std::uint8_t>(z1 ^ peer_z1);
const std::uint8_t t = static_cast<std::uint8_t>(opened_z0 & opened_z1);
const std::uint8_t l1 = self == role::p1 ? l : peer_l;
const std::uint8_t got = static_cast<std::uint8_t>(t ^ l1);
require(got == local_ccmp(4u, 5u), "ccmp mesh");
require(got == 1u, "ccmp 4<5");
bool bad = false;
try
{
(void)local_ccmp(4u, 6u);
}
catch (const std::invalid_argument &)
{
bad = true;
}
require(bad, "ccmp rejects");
return 0;
}
// ---- exotic payloads / domains ---------------------------------------------
template <typename Output>
int cov_payload_point(role self, trio & net, Output beta, const char * tag)
{
using Input = std::uint8_t;
const Input alpha = 0x11;
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha, beta);
send_key(net.to(role::p0), k0);
send_key(net.to(role::p1), k1);
return 0;
}
auto check = [&](const auto & key) {
const auto on = *eval_point(key, alpha);
const auto off = *eval_point(key, static_cast<Input>(alpha ^ 1u));
const Output o_on = open_subtractive(net, self, share_bits(on));
const Output o_off = open_subtractive(net, self, share_bits(off));
if (self == role::p0)
{
require(o_on == beta, tag);
require(o_off == Output{}, tag);
}
};
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(make_dpf(Input{}, beta)))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
using K = std::decay_t<decltype(std::get<1>(make_dpf(Input{}, beta)))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
int cov_field128(role self, trio & net)
{
return cov_payload_point(self, net, field128{42}, "field128");
}
int cov_gf2(role self, trio & net)
{
return cov_payload_point(self, net, dpf::gf2{1}, "gf2");
}
int cov_gf22(role self, trio & net)
{
return cov_payload_point(self, net, dpf::gf22{3}, "gf22");
}
int cov_gf24(role self, trio & net)
{
return cov_payload_point(self, net, dpf::gf24{0xa}, "gf24");
}
int cov_gf28(role self, trio & net)
{
return cov_payload_point(self, net, dpf::gf28{0x1b}, "gf28");
}
int cov_gf216(role self, trio & net)
{
return cov_payload_point(self, net, dpf::gf216{0x2d}, "gf216");
}
int cov_gf232(role self, trio & net)
{
return cov_payload_point(self, net, dpf::gf232{0x90200001u}, "gf232");
}
int cov_gf264(role self, trio & net)
{
return cov_payload_point(self, net, dpf::gf264{0x11}, "gf264");
}
int cov_p256(role self, trio & net)
{
return cov_payload_point(self, net, p256{1}, "p256");
}
int cov_bitstring(role self, trio & net)
{
using bs = bitstring<16>;
return cov_payload_point(self, net, bs{0xBEEFu}, "bitstring");
}
int cov_fixedpoint(role self, trio & net)
{
using fp = grotto::fixedpoint<16>;
return cov_payload_point(self, net, fp::from_raw(0x00018000), "fixedpoint");
}
int cov_keyword2(role self, trio & net)
{
using kw = keyword2<cov_kw_pat>;
const kw alpha{"abababab"};
const u64 beta = 3;
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha, beta);
send_key(net.to(role::p0), k0);
send_key(net.to(role::p1), k1);
return 0;
}
auto check = [&](const auto & key) {
const auto on = *eval_point(key, alpha);
const auto off = *eval_point(key, kw{"babababa"});
const auto o_on = open_subtractive(net, self, share_bits(on));
const auto o_off = open_subtractive(net, self, share_bits(off));
if (self == role::p0)
{
require(o_on == beta, "keyword2 on");
require(o_off == 0u, "keyword2 off");
}
};
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(make_dpf(kw{}, u64{})))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
using K = std::decay_t<decltype(std::get<1>(make_dpf(kw{}, u64{})))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
int cov_modint_domain(role self, trio & net)
{
using in_t = modint<10>;
const in_t alpha{3};
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha, at<6>(std::uint8_t{1}), std::uint16_t{2});
send_key(net.to(role::p0), k0);
send_key(net.to(role::p1), k1);
return 0;
}
auto check = [&](const auto & key) {
const auto y0 = *eval_point(out<0, 6>, key, alpha);
const auto o0 = open_subtractive(net, self, share_bits(y0));
if (self == role::p0)
require(o0 == std::uint8_t{1}, "modint at6");
const auto y1 = *eval_point(out<1>, key, alpha);
const auto o1 = open_subtractive(net, self, share_bits(y1));
if (self == role::p0)
require(o1 == std::uint16_t{2}, "modint leaf");
};
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(
make_dpf(in_t{}, at<6>(std::uint8_t{}), std::uint16_t{})))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
using K = std::decay_t<decltype(std::get<1>(
make_dpf(in_t{}, at<6>(std::uint8_t{}), std::uint16_t{})))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
// ---- grotto nmod (public reduction helper over the mesh) -------------------
int cov_nmod(role self, trio & net)
{
// 42 / 10 with 1/10 ≈ 0x199999999999999a / 2^64, keep 8 residue bits.
const std::int64_t x_raw = 42;
const unsigned x_bits = 0;
const unsigned __int128 recip = 0x199999999999999aull;
const unsigned recip_bits = 64;
const unsigned residue_bits = 8;
auto got = grotto::nmod(x_raw, x_bits, recip, recip_bits, residue_bits);
if (self == role::p2)
{
net.to(role::p0).send(net::msg::delta, got.quotient);
net.to(role::p0).send(net::msg::delta, got.residue);
net.to(role::p1).send(net::msg::delta, got.quotient);
net.to(role::p1).send(net::msg::delta, got.residue);
return 0;
}
const auto q = net.to(role::p2).recv<std::int64_t>(net::msg::delta);
const auto r = net.to(role::p2).recv<std::int64_t>(net::msg::delta);
require(q == got.quotient && r == got.residue, "nmod agree");
require(q == 4 && r != 0, "nmod 42/10");
return 0;
}
// ---- JSON key round-trip over the mesh -------------------------------------
int cov_json_roundtrip(role self, trio & net)
{
using Input = std::uint8_t;
const Input alpha = 0x2a;
const u64 beta = 17;
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha, beta);
const std::string s0 = json::to_json(k0);
const std::string s1 = json::to_json(k1);
net.to(role::p0).send_bytes(net::msg::dpf_key,
reinterpret_cast<const std::uint8_t *>(s0.data()), s0.size());
net.to(role::p1).send_bytes(net::msg::dpf_key,
reinterpret_cast<const std::uint8_t *>(s1.data()), s1.size());
return 0;
}
auto body = net.to(role::p2).recv_bytes(net::msg::dpf_key);
const std::string s(reinterpret_cast<const char *>(body.data()), body.size());
using K0 = std::decay_t<decltype(std::get<0>(make_dpf(Input{}, u64{})))>;
using K1 = std::decay_t<decltype(std::get<1>(make_dpf(Input{}, u64{})))>;
if (self == role::p0)
{
auto key = json::from_json<K0>(s);
const auto y = *eval_point(key, alpha);
const auto open = open_subtractive(net, self, share_bits(y));
require(open == beta, "json on");
return 0;
}
auto key = json::from_json<K1>(s);
const auto y = *eval_point(key, alpha);
(void)open_subtractive(net, self, share_bits(y));
return 0;
}
// ---- F_DPF3DS local API (dealer make_dpf3_doerner_shelat) -------------------
int cov_dpf3_ds_local(role self, trio & net)
{
using Input = std::uint8_t;
const Input alpha = 0x2a;
const Input x0 = 0x11;
const Input x1 = static_cast<Input>(alpha ^ x0);
const fp61 beta{9};
if (self == role::p2)
{
auto [k1, k2, k3] = make_dpf3_doerner_shelat(x0, x1, beta);
send_key(net.to(role::p0), k1);
send_key(net.to(role::p1), k2);
const fp61 y = eval_point(k3, alpha);
const fp61 got = recent::open_shamir3(net, self, y);
require(got == beta, "dpf3_ds on");
const fp61 z = eval_point(k3, static_cast<Input>(alpha ^ 1u));
const fp61 off = recent::open_shamir3(net, self, z);
require(off == fp61{}, "dpf3_ds off");
return 0;
}
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(
make_dpf3_doerner_shelat(Input{}, Input{}, fp61{})))>;
auto key = recv_key<K>(net.to(role::p2));
(void)recent::open_shamir3(net, self, eval_point(key, alpha));
(void)recent::open_shamir3(net, self,
eval_point(key, static_cast<Input>(alpha ^ 1u)));
return 0;
}
using K = std::decay_t<decltype(std::get<1>(
make_dpf3_doerner_shelat(Input{}, Input{}, fp61{})))>;
auto key = recv_key<K>(net.to(role::p2));
(void)recent::open_shamir3(net, self, eval_point(key, alpha));
(void)recent::open_shamir3(net, self,
eval_point(key, static_cast<Input>(alpha ^ 1u)));
return 0;
}
// ---- eval_inner_product on a point DPF -------------------------------------
int cov_eval_inner_product(role self, trio & net)
{
using Input = std::uint8_t;
const Input alpha = 42;
const u64 beta = 7;
if (self == role::p2)
{
auto [k0, k1] = make_dpf(alpha, beta);
send_key(net.to(role::p0), k0);
send_key(net.to(role::p1), k1);
return 0;
}
auto check = [&](const auto & key) {
std::vector<u64> w(11, 1);
const u64 mine = share_bits(
eval_inner_product(paired, key, Input{40}, Input{50}, w));
// Point leaves are subtractive; the guided-tour reconstruct is additive
// on the opened difference after both parties contribute.
const u64 opened = open_subtractive(net, self, mine);
if (self == role::p0)
require(opened == beta * w[2], "eval_inner_product");
};
if (self == role::p0)
{
using K = std::decay_t<decltype(std::get<0>(make_dpf(Input{}, u64{})))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
using K = std::decay_t<decltype(std::get<1>(make_dpf(Input{}, u64{})))>;
check(recv_key<K>(net.to(role::p2)));
return 0;
}
#define REG(name, tags, fn) \
register_flow(flow{#name, tags, fn, false})
} // namespace coverage
void register_coverage_flows()
{
using namespace coverage;
REG(cov_paint_lcp, "coverage paint dcf", cov_paint_lcp);
REG(cov_paint_one_hot, "coverage paint dcf", cov_paint_one_hot);
REG(cov_paint_break_bit, "coverage paint dcf", cov_paint_break_bit);
REG(cov_paint_path, "coverage paint dcf", cov_paint_path);
REG(cov_paint_prefix_with_length, "coverage paint dcf",
cov_paint_prefix_with_length);
REG(cov_idpf_at, "coverage idpf", cov_idpf_at);
REG(cov_eq_at, "coverage eq_at", cov_eq_at);
REG(cov_idcf, "coverage idcf", cov_idcf);
REG(cov_geneval_full, "coverage geneval", cov_geneval_full);
REG(cov_geneval_sequence, "coverage geneval", cov_geneval_sequence);
REG(cov_arith_output, "coverage arith_output", cov_arith_output);
REG(cov_ccmp, "coverage ccmp", cov_ccmp);
REG(cov_field128, "coverage payload", cov_field128);
REG(cov_gf2, "coverage payload", cov_gf2);
REG(cov_gf22, "coverage payload", cov_gf22);
REG(cov_gf24, "coverage payload", cov_gf24);
REG(cov_gf28, "coverage payload", cov_gf28);
REG(cov_gf216, "coverage payload", cov_gf216);
REG(cov_gf232, "coverage payload", cov_gf232);
REG(cov_gf264, "coverage payload", cov_gf264);
REG(cov_p256, "coverage payload", cov_p256);
REG(cov_bitstring, "coverage payload", cov_bitstring);
REG(cov_fixedpoint, "coverage payload", cov_fixedpoint);
REG(cov_keyword2, "coverage keyword2", cov_keyword2);
REG(cov_modint_domain, "coverage modint", cov_modint_domain);
REG(cov_nmod, "coverage nmod", cov_nmod);
REG(cov_json_roundtrip, "coverage json", cov_json_roundtrip);
REG(cov_dpf3_ds_local, "coverage dpf3_ds", cov_dpf3_ds_local);
REG(cov_eval_inner_product, "coverage eval_inner_product",
cov_eval_inner_product);
}
#undef REG
} // namespace party
} // namespace dpf