133 lines
5.6 KiB
C++
133 lines
5.6 KiB
C++
|
|
/// @file dpf/grow_ds.hpp
|
|||
|
|
/// @brief Doerner–Shelat interactive / joint grow: `extend_ds` and
|
|||
|
|
/// `add_output_ds` on path-memoizer frontiers.
|
|||
|
|
/// @details Joint (2+1 / local) view holds both keys and both memoizers. One
|
|||
|
|
/// correction-word round uses `ds_advance_level`; leaf planting reuses
|
|||
|
|
/// dealer `grow_impl` with the opened CW. A socket backend swaps in a
|
|||
|
|
/// `CwProtocol` that exchanges blinds without revealing the peer seed.
|
|||
|
|
/// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors)
|
|||
|
|
/// @license Released under a GNU General Public v2.0 (GPLv2) license.
|
|||
|
|
|
|||
|
|
#ifndef LIBDPF_INCLUDE_DPF_GROW_DS_HPP__
|
|||
|
|
#define LIBDPF_INCLUDE_DPF_GROW_DS_HPP__
|
|||
|
|
|
|||
|
|
#include <array>
|
|||
|
|
#include <cstddef>
|
|||
|
|
#include <cstdint>
|
|||
|
|
#include <type_traits>
|
|||
|
|
#include <utility>
|
|||
|
|
|
|||
|
|
#include "hedley/hedley.h"
|
|||
|
|
|
|||
|
|
#include "dpf/doerner_shelat.hpp"
|
|||
|
|
#include "dpf/grow.hpp"
|
|||
|
|
#include "dpf/path_memoizer.hpp"
|
|||
|
|
#include "dpf/utils.hpp"
|
|||
|
|
|
|||
|
|
namespace dpf
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
/// @brief One interactive interior level from memoizer frontiers, then plant
|
|||
|
|
/// `specs` via the same assembly as dealer `extend`.
|
|||
|
|
/// @details `x0` / `x1` are XOR shares of the programmed point (use `(x, 0)` in
|
|||
|
|
/// a local joint test). Memoizers must already be filled for the clear
|
|||
|
|
/// point `x0 ⊕ x1` through the old depth.
|
|||
|
|
/// \complexity One `ds_advance_level` (two PRG expands + `prepare_level` /
|
|||
|
|
/// `open_cw` / AND opens) plus the same leaf plants as dealer
|
|||
|
|
/// `extend`. No O(d) rewalk when memoizers are warm.
|
|||
|
|
/// \rounds One interactive CW round for the new level (local_cw_protocol opens
|
|||
|
|
/// in-process; a socket `CwProtocol` is one peer exchange round).
|
|||
|
|
/// \communication Local: none on the wire. Networked: one level's blinds, CW
|
|||
|
|
/// shares, and advice (same shape as one `point_party` level),
|
|||
|
|
/// plus leaf pads when planting.
|
|||
|
|
template <typename K0, typename K1, typename Memo0, typename Memo1,
|
|||
|
|
typename InputT, typename CwProtocol, typename... Specs>
|
|||
|
|
HEDLEY_WARN_UNUSED_RESULT
|
|||
|
|
auto extend_ds(const K0 & k0, const K1 & k1, Memo0 & m0, Memo1 & m1, InputT x0,
|
|||
|
|
InputT x1, CwProtocol & proto, Specs &&... specs)
|
|||
|
|
{
|
|||
|
|
using old_key = detail::grow_impl::bare_key_t<K0>;
|
|||
|
|
static_assert(std::is_same_v<old_key, detail::grow_impl::bare_key_t<K1>>,
|
|||
|
|
"extend_ds: both keys must have the same type");
|
|||
|
|
using input_type = typename old_key::input_type;
|
|||
|
|
using node = typename old_key::interior_node;
|
|||
|
|
using interior = typename old_key::interior_prg;
|
|||
|
|
|
|||
|
|
input_type xx0 = static_cast<input_type>(x0);
|
|||
|
|
input_type xx1 = static_cast<input_type>(x1);
|
|||
|
|
utils::flip_msb_if_signed_integral(xx0);
|
|||
|
|
// Party 1 share is not MSB-flipped in DS (same as make_dpf_doerner_shelat).
|
|||
|
|
const input_type x = utils::xor_input_shares(xx0, xx1);
|
|||
|
|
|
|||
|
|
const old_key & bk0 = static_cast<const old_key &>(k0);
|
|||
|
|
const old_key & bk1 = static_cast<const old_key &>(k1);
|
|||
|
|
|
|||
|
|
const bool bit = detail::grow_impl::bit_at(x, old_key::depth);
|
|||
|
|
|
|||
|
|
node s0{};
|
|||
|
|
node s1{};
|
|||
|
|
std::array<bool, old_key::depth == 0 ? 1 : old_key::depth> path{};
|
|||
|
|
detail::grow_impl::frontier_from_memos(bk0, bk1, m0, m1, x, old_key::depth, s0,
|
|||
|
|
s1, old_key::depth == 0 ? nullptr : path.data());
|
|||
|
|
|
|||
|
|
detail::ds_gen_state<node> st;
|
|||
|
|
st.init(s0, s1);
|
|||
|
|
|
|||
|
|
const std::size_t level = old_key::depth;
|
|||
|
|
const std::size_t new_depth = old_key::depth + 1;
|
|||
|
|
auto mask = old_key::msb_mask;
|
|||
|
|
for (std::size_t i = 0; i < level; ++i)
|
|||
|
|
mask >>= 1;
|
|||
|
|
|
|||
|
|
node cw{};
|
|||
|
|
psnip_uint8_t advice = 0;
|
|||
|
|
detail::ds_advance_level<interior>(st, xx0, xx1, mask, level, new_depth,
|
|||
|
|
proto, cw, advice);
|
|||
|
|
|
|||
|
|
node ns0 = st.seed0();
|
|||
|
|
node ns1 = st.seed1();
|
|||
|
|
|
|||
|
|
return detail::grow_impl::grow_impl<true, true>(bk0, bk1, &m0, &m1, bit, x,
|
|||
|
|
true, &cw, &advice, &ns0, &ns1, std::forward<Specs>(specs)...);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// @brief Plant outputs on existing levels using memoizer seeds. Joint leaf
|
|||
|
|
/// construction matches dealer `add_output`; `proto.open_leaf_group` is
|
|||
|
|
/// invoked so a non-local protocol can hide the clear point.
|
|||
|
|
/// \complexity O(1) frontier reads plus leaf plants. No new interior CW.
|
|||
|
|
/// \rounds Leaf-open only (local: one `open_leaf_group` callback; networked:
|
|||
|
|
/// the leaf pad / mux pattern of `point_party`).
|
|||
|
|
/// \communication none for `local_cw_protocol`; otherwise leaf pads and the
|
|||
|
|
/// leaf CW open.
|
|||
|
|
template <typename K0, typename K1, typename Memo0, typename Memo1,
|
|||
|
|
typename InputT, typename CwProtocol, typename... Specs>
|
|||
|
|
HEDLEY_WARN_UNUSED_RESULT
|
|||
|
|
auto add_output_ds(const K0 & k0, const K1 & k1, Memo0 & m0, Memo1 & m1,
|
|||
|
|
InputT x0, InputT x1, CwProtocol & proto, Specs &&... specs)
|
|||
|
|
{
|
|||
|
|
using old_key = detail::grow_impl::bare_key_t<K0>;
|
|||
|
|
using input_type = typename old_key::input_type;
|
|||
|
|
const old_key & bk0 = static_cast<const old_key &>(k0);
|
|||
|
|
const old_key & bk1 = static_cast<const old_key &>(k1);
|
|||
|
|
|
|||
|
|
input_type xx0 = static_cast<input_type>(x0);
|
|||
|
|
input_type xx1 = static_cast<input_type>(x1);
|
|||
|
|
utils::flip_msb_if_signed_integral(xx0);
|
|||
|
|
input_type x{};
|
|||
|
|
proto.open_leaf_group(xx0, xx1, [&](input_type sx0, input_type sx1) {
|
|||
|
|
x = utils::xor_input_shares(sx0, sx1);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return detail::grow_impl::grow_impl<false, true>(bk0, bk1, &m0, &m1,
|
|||
|
|
/*bit=*/false, x, false,
|
|||
|
|
static_cast<typename old_key::interior_node *>(nullptr),
|
|||
|
|
static_cast<psnip_uint8_t *>(nullptr),
|
|||
|
|
static_cast<typename old_key::interior_node *>(nullptr),
|
|||
|
|
static_cast<typename old_key::interior_node *>(nullptr),
|
|||
|
|
std::forward<Specs>(specs)...);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} // namespace dpf
|
|||
|
|
|
|||
|
|
#endif // LIBDPF_INCLUDE_DPF_GROW_DS_HPP__
|