/// @file dpf/factory_tapes.hpp /// @brief Dealer stream layouts for `factory_gadgets` online tapes (A2B, trunc, GT). #ifndef LIBDPF_INCLUDE_DPF_FACTORY_TAPES_HPP__ #define LIBDPF_INCLUDE_DPF_FACTORY_TAPES_HPP__ #include #include #include #include #include #include "dpf/protocol_factory.hpp" namespace dpf { namespace factory { namespace detail { inline std::pair deal_gmw_and_blind_pair() { auto t = deal_bit_triple(); gmw_and_blind v0{t.first.a, t.first.b, t.first.c}; gmw_and_blind v1{t.second.a, t.second.b, t.second.c}; return {v0, v1}; } template inline void deal_tape_pod(net::stream_array & party0, net::stream_array & party1, std::size_t stream, std::size_t count, F && f) { if (stream >= party0.size() || stream >= party1.size()) throw std::invalid_argument("deal_tape_pod: stream index"); for (std::size_t j = 0; j < count; ++j) { auto views = f(); using V0 = std::decay_t; using V1 = std::decay_t; static_assert(std::is_trivially_copyable_v && std::is_trivially_copyable_v, "deal_tape_pod views must be trivially copyable"); if (sizeof(V0) != sizeof(V1)) throw std::logic_error("deal_tape_pod: unequal view sizes"); detail::write_pod(party0, stream, views.first); detail::write_pod(party1, stream, views.second); } party0.flush(stream); party1.flush(stream); } } // namespace detail /// @brief Sequential dabits then AND blinds for one `a2b_online` pass. inline void deal_a2b_tape(unsigned width, std::uint16_t limb, net::stream_array & party0, net::stream_array & party1, std::size_t dabit_stream = 0, std::size_t and_blind_stream = 1) { if (width == 0 || width > 64) throw std::invalid_argument("deal_a2b_tape width"); const std::size_t need = 1 + (dabit_stream > and_blind_stream ? dabit_stream : and_blind_stream); if (party0.size() < need || party1.size() < need) throw std::invalid_argument("deal_a2b_tape: not enough streams"); detail::deal_tape_pod(party0, party1, dabit_stream, width, [limb] { return deal_dabit(limb); }); detail::deal_tape_pod(party0, party1, and_blind_stream, width, [] { return detail::deal_gmw_and_blind_pair(); }); } /// @brief `s + 1` dabits (low mask + B2A wrap) and `s` AND blinds for trunc. inline void deal_trunc_tape(unsigned n, unsigned s, std::uint16_t limb, net::stream_array & party0, net::stream_array & party1, std::size_t dabit_stream = 0, std::size_t and_blind_stream = 1) { if (s >= n || n > 64) throw std::invalid_argument("deal_trunc_tape"); const std::size_t need = 1 + (dabit_stream > and_blind_stream ? dabit_stream : and_blind_stream); if (party0.size() < need || party1.size() < need) throw std::invalid_argument("deal_trunc_tape: not enough streams"); detail::deal_tape_pod(party0, party1, dabit_stream, s + 1u, [limb] { return deal_dabit(limb); }); detail::deal_tape_pod(party0, party1, and_blind_stream, s, [] { return detail::deal_gmw_and_blind_pair(); }); } /// @brief Dealer layout for `gt_online`: streams 0–1 (x A2B), 2–3 (y), 4 compare. inline void deal_gt_tape(unsigned width, std::uint16_t limb, net::stream_array & party0, net::stream_array & party1) { if (width == 0 || width > 64) throw std::invalid_argument("deal_gt_tape width"); constexpr std::size_t k_gt_streams = 5; if (party0.size() < k_gt_streams || party1.size() < k_gt_streams) throw std::invalid_argument("deal_gt_tape: need 5 dealer streams"); deal_a2b_tape(width, limb, party0, party1, 0, 1); deal_a2b_tape(width, limb, party0, party1, 2, 3); detail::deal_tape_pod(party0, party1, 4, 3u * width, [] { return detail::deal_gmw_and_blind_pair(); }); } } // namespace factory } // namespace dpf #endif