/// @file dpf/pad_graphs.hpp /// @brief Setup / pad protocols as real `schedule_round` lists. #ifndef LIBDPF_INCLUDE_DPF_PAD_GRAPHS_HPP__ #define LIBDPF_INCLUDE_DPF_PAD_GRAPHS_HPP__ #include #include #include #include #include #include #include "dpf/protocol.hpp" namespace dpf { namespace protocol { /// @brief Dealer Beaver / Du-Atallah blinding tape: one delivery round per triple. inline std::vector dealer_tape_graph(std::size_t n_triples, std::size_t slot_bytes, const std::shared_ptr> & tape) { return make_pad_rounds(n_triples, slot_bytes, tape, edge_channel::dealer); } /// @brief Du-Atallah 3PC multiply: P2 blinds (offline) + one P0↔P1 exchange. /// @details Round 0 on dealer edge carries (X0,Y0,…) tokens; round 1 on peer /// exchanges blinded shares. Bodies are schedule-shaped stubs that /// XOR into `tape` so PIRsona / hushmap can splice them before online. inline std::vector du_atallah_mul_graph( const std::shared_ptr> & tape, std::size_t slot_bytes = 24) { auto dealer = make_pad_rounds(1, slot_bytes, tape, edge_channel::dealer); auto peer = make_pad_rounds(1, slot_bytes, tape, edge_channel::peer); peer[0].sink_round = 0; return splice_rounds(std::move(dealer), std::move(peer)); } /// @brief Key-ship: one round delivering `key_bytes` on `edge` (PIR upload seed). inline std::vector key_ship_graph(std::size_t key_bytes, edge_id edge = edge_peer) { std::vector rounds(1); rounds[0].slot_bytes = key_bytes; rounds[0].edge = edge; rounds[0].channel = edge <= edge_dealer ? static_cast(edge) : edge_channel::peer; rounds[0].recv = receive_rule::copy_peer; rounds[0].sink_round = 0; rounds[0].produce = [key_bytes](std::size_t, const std::uint8_t *, std::size_t, std::uint8_t * out) { if (out != nullptr && key_bytes != 0) std::memset(out, 0x5a, key_bytes); }; return rounds; } /// @brief Server end of one star spoke: absorb upload, produce answer. inline std::vector star_server_reply_rounds( std::size_t query_bytes, std::size_t answer_bytes, std::vector answer) { std::vector sr(2); sr[0].slot_bytes = query_bytes; sr[0].edge = edge_peer; sr[0].sink_round = 0; sr[0].produce = [query_bytes](std::size_t, const std::uint8_t *, std::size_t, std::uint8_t * out) { if (out != nullptr && query_bytes != 0) std::memset(out, 0, query_bytes); }; sr[1].slot_bytes = answer_bytes; sr[1].edge = edge_peer; sr[1].sink_round = 1; sr[1].produce = [answer = std::move(answer), answer_bytes](std::size_t, const std::uint8_t *, std::size_t, std::uint8_t * out) { if (out == nullptr) return; if (answer.size() >= answer_bytes) std::memcpy(out, answer.data(), answer_bytes); else std::memset(out, 0, answer_bytes); }; return sr; } /// @brief Client star: upload then answer on each of `n_servers` edges. /// @details Rounds `[0, n)` upload on edge i; rounds `[n, 2n)` answer on edge i. inline std::vector star_upload_answer_graph( std::size_t n_servers, std::size_t query_bytes, std::size_t answer_bytes, const std::shared_ptr>> & queries, const std::shared_ptr>> & answers) { if (n_servers < 2) throw std::invalid_argument("star_upload_answer_graph servers"); std::vector rounds(2 * n_servers); for (std::size_t i = 0; i < n_servers; ++i) { auto & up = rounds[i]; up.slot_bytes = query_bytes; up.edge = static_cast(i); up.recv = receive_rule::copy_peer; up.sink_round = 0; up.produce = [i, query_bytes, queries](std::size_t, const std::uint8_t *, std::size_t, std::uint8_t * out) { if (out == nullptr) return; if (queries && i < queries->size() && (*queries)[i].size() >= query_bytes) std::memcpy(out, (*queries)[i].data(), query_bytes); else std::memset(out, static_cast(i + 1), query_bytes); }; auto & ans = rounds[n_servers + i]; ans.slot_bytes = answer_bytes; ans.edge = static_cast(i); ans.recv = receive_rule::copy_peer; ans.sink_round = 1; ans.produce = [i, answer_bytes, answers](std::size_t, const std::uint8_t * peer, std::size_t peer_n, std::uint8_t * out) { if (out == nullptr) return; if (answers && i < answers->size() && (*answers)[i].size() >= answer_bytes) std::memcpy(out, (*answers)[i].data(), answer_bytes); else if (peer != nullptr && peer_n >= answer_bytes) std::memcpy(out, peer, answer_bytes); else std::memset(out, 0, answer_bytes); }; } return rounds; } } // namespace protocol } // namespace dpf #endif // LIBDPF_INCLUDE_DPF_PAD_GRAPHS_HPP__