/// @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 #include #include #include #include #include #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(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(n - 1 - i); if (((x >> shift) & 1) != ((alpha >> shift) & 1)) return static_cast(i); } return n; } template 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(make_dpf(Input{}, spec)))>; auto key = recv_key(net.to(role::p2)); on0(key, alpha); return; } using K = std::decay_t(make_dpf(Input{}, spec)))>; auto key = recv_key(net.to(role::p2)); on1(key, alpha); } template 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 pts{ 0, 1, alpha, static_cast(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(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( make_dpf(Input{}, at<8>(std::uint8_t{}), at<12>(std::uint16_t{}))))>; check(recv_key(net.to(role::p2))); return 0; } using K = std::decay_t( make_dpf(Input{}, at<8>(std::uint8_t{}), at<12>(std::uint16_t{}))))>; check(recv_key(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(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( make_dpf(Input{}, eq_at<8>(std::uint16_t{}, std::uint16_t{}))))>; check(recv_key(net.to(role::p2))); return 0; } using K = std::decay_t( make_dpf(Input{}, eq_at<8>(std::uint16_t{}, std::uint16_t{}))))>; check(recv_key(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( make_dpf(Input{}, idcf(gt(u64{})))))>; check(recv_key(net.to(role::p2))); return 0; } using K = std::decay_t( make_dpf(Input{}, idcf(gt(u64{})))))>; check(recv_key(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(n), static_cast(n * 9 + 3)); n += 2; return v; } std::uint8_t bit() { return static_cast(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 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(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(); 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(alpha ^ x0); const Output y = 99; const std::array 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(); 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(alpha ^ x0); const Output beta = 0x01020304; const Output y0 = 0x00010002; const Output y1 = static_cast(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(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(z0 ^ peer_z0); const std::uint8_t opened_z1 = static_cast(z1 ^ peer_z1); const std::uint8_t t = static_cast(opened_z0 & opened_z1); const std::uint8_t l1 = self == role::p1 ? l : peer_l; const std::uint8_t got = static_cast(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 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(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(make_dpf(Input{}, beta)))>; check(recv_key(net.to(role::p2))); return 0; } using K = std::decay_t(make_dpf(Input{}, beta)))>; check(recv_key(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; 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(make_dpf(kw{}, u64{})))>; check(recv_key(net.to(role::p2))); return 0; } using K = std::decay_t(make_dpf(kw{}, u64{})))>; check(recv_key(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( make_dpf(in_t{}, at<6>(std::uint8_t{}), std::uint16_t{})))>; check(recv_key(net.to(role::p2))); return 0; } using K = std::decay_t( make_dpf(in_t{}, at<6>(std::uint8_t{}), std::uint16_t{})))>; check(recv_key(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(net::msg::delta); const auto r = net.to(role::p2).recv(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(s0.data()), s0.size()); net.to(role::p1).send_bytes(net::msg::dpf_key, reinterpret_cast(s1.data()), s1.size()); return 0; } auto body = net.to(role::p2).recv_bytes(net::msg::dpf_key); const std::string s(reinterpret_cast(body.data()), body.size()); using K0 = std::decay_t(make_dpf(Input{}, u64{})))>; using K1 = std::decay_t(make_dpf(Input{}, u64{})))>; if (self == role::p0) { auto key = json::from_json(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(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(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(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( make_dpf3_doerner_shelat(Input{}, Input{}, fp61{})))>; auto key = recv_key(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(alpha ^ 1u))); return 0; } using K = std::decay_t( make_dpf3_doerner_shelat(Input{}, Input{}, fp61{})))>; auto key = recv_key(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(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 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(make_dpf(Input{}, u64{})))>; check(recv_key(net.to(role::p2))); return 0; } using K = std::decay_t(make_dpf(Input{}, u64{})))>; check(recv_key(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