libdpf/include/dpf/dpf3_ds.hpp
Ryan Henry 0d22946a0e Checkpoint the party/runtime stack before share-program and malicious-mode work.
Ship the TLS mesh, composer, Beaver/Yao/leaf MPC, prep/online paths, apps, and docs so the tree is pushable before elevating share_expr, security_mode, and prep resume.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 05:59:19 -06:00

125 lines
5.3 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// @file dpf/dpf3_ds.hpp
/// @brief Dual-spine Doerner–Shelat generation of (2,3) point keys.
/// @note Two independent openings, one per spine of Zyskind, Yanai, and Pentland (ePrint 2024/1658, Figure 3). Each opening follows Doerner and shelat, CCS 2017 (ePrint 2017/827).
/// @details Runs two independent two-party DS walks (spines A and B) with
/// Fig-3 `τ` payloads, then assembles the three evaluator keys via
/// `assemble_from_spines`. Matches honest-dealer `make_dpf3` on the
/// opened point `x0 ⊕ x1` (after the signed-MSB flip on share 0).
/// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors)
/// @license Released under a GNU General Public v2.0 (GPLv2) license;
/// see [LICENSE.md](@ref license) for details.
#ifndef LIBDPF_INCLUDE_DPF_DPF3_DS_HPP__
#define LIBDPF_INCLUDE_DPF_DPF3_DS_HPP__
#include <tuple>
#include <type_traits>
#include <utility>
#include "hedley/hedley.h"
#include "dpf/dpf3.hpp"
#include "dpf/fp61.hpp"
#include "dpf/incremental.hpp"
#include "dpf/placement.hpp"
#include "dpf/prg_aes.hpp"
#include "dpf/verifiable.hpp"
#include "dpf/wildcard.hpp"
namespace dpf
{
namespace detail
{
namespace dpf3_impl
{
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
bool Verifiable, bool Updatable, bool Extractable>
auto make_point3_ds(InputT x0, InputT x1, fp61 beta)
{
using X = xor61;
const InputT alpha = open_xor_point(x0, x1);
const tau_quad t = sample_taus(beta);
const X payload_a = t.t0 + t.t1;
const X payload_b = t.t2 + t.t3;
if constexpr (Updatable)
{
// Classic DS rejects wildcards; the incremental path plants beaver
// leaves. Inner verifiable tags match the outer `Verifiable` flag.
auto A = [&] {
if constexpr (Verifiable)
return dpf::make_dpf_doerner_shelat<InteriorPRG, ExteriorPRG>(
x0, x1, dpf::wildcard_value<X>{}, dpf::verifiable{});
else
return dpf::make_dpf_doerner_shelat<InteriorPRG, ExteriorPRG>(
x0, x1, dpf::wildcard_value<X>{});
}();
auto B = [&] {
if constexpr (Verifiable)
return dpf::make_dpf_doerner_shelat<InteriorPRG, ExteriorPRG>(
x0, x1, dpf::wildcard_value<X>{}, dpf::verifiable{});
else
return dpf::make_dpf_doerner_shelat<InteriorPRG, ExteriorPRG>(
x0, x1, dpf::wildcard_value<X>{});
}();
assign_xor_payload(A.first, A.second, payload_a);
assign_xor_payload(B.first, B.second, payload_b);
return assemble_from_spines<Verifiable, Extractable, true>(
std::move(A.first), std::move(A.second), std::move(B.first),
std::move(B.second), t, alpha);
}
else
{
auto A = [&] {
if constexpr (Verifiable)
return dpf::make_dpf_doerner_shelat<InteriorPRG, ExteriorPRG>(
x0, x1, payload_a, dpf::verifiable{});
else
return dpf::make_dpf_doerner_shelat<InteriorPRG, ExteriorPRG>(
x0, x1, payload_a);
}();
auto B = [&] {
if constexpr (Verifiable)
return dpf::make_dpf_doerner_shelat<InteriorPRG, ExteriorPRG>(
x0, x1, payload_b, dpf::verifiable{});
else
return dpf::make_dpf_doerner_shelat<InteriorPRG, ExteriorPRG>(
x0, x1, payload_b);
}();
return assemble_from_spines<Verifiable, Extractable, false>(
std::move(A.first), std::move(A.second), std::move(B.first),
std::move(B.second), t, alpha);
}
}
} // namespace dpf3_impl
} // namespace detail
/// @brief Dual-spine Doerner–Shelat (2,3) keys for XOR shares of `α`.
/// @details `α = x0 ⊕ x1` after the signed-MSB flip on `x0`. Tags match
/// `make_dpf3`: `verifiable`, `extractable`, and `updatable`, any order.
/// \complexity O(n) time. One `ds_advance_level` per level: two PRG expansions and one `prepare_level`. n is `depth`.
/// \rounds No sockets. This is the in-process transcript. A networked walk is `dpf::party::dist::point_party`.
/// \communication none here. `local_cw_protocol` opens the correction word locally.
/// \preprocessing Per level, `prepare_level` draws one `ds_cw_pads` (two parties × a 128-bit rand, a 128-bit gamma, and a bit) and two `ds_and_pads`. Arithmetic inputs also run a carry chain of n-1 bit-AND triples in `encode_walk_shares`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename ...Tags>
HEDLEY_WARN_UNUSED_RESULT
auto make_dpf3_doerner_shelat(InputT x0, InputT x1, fp61 beta, Tags ...tags)
{
using flags = detail::dpf3_impl::tag_flags<Tags...>;
static_assert(flags::known,
"make_dpf3_doerner_shelat tags are verifiable, extractable, updatable");
static_assert(sizeof...(Tags) == flags::counted,
"make_dpf3_doerner_shelat: repeated tag");
(void)std::initializer_list<int>{((void)tags, 0)...};
return detail::dpf3_impl::make_point3_ds<InteriorPRG, ExteriorPRG, InputT,
flags::verifiable, flags::updatable, flags::extractable>(x0, x1, beta);
}
} // namespace dpf
#endif // LIBDPF_INCLUDE_DPF_DPF3_DS_HPP__