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>
This commit is contained in:
parent
695f8e84f7
commit
0d22946a0e
1835 changed files with 170291 additions and 2849 deletions
503
party/dist_dpf3.hpp
Normal file
503
party/dist_dpf3.hpp
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
/// @file party/dist_dpf3.hpp
|
||||
/// @brief Networked (2,3) Shamir DPF keygen (three key holders).
|
||||
/// @details A pure two-party variant is not meaningful: after keygen each of
|
||||
/// three parties must hold a Shamir share of the evaluation. Use
|
||||
/// `dist_with_*_iknp` in `iknp_deal.hpp` for two-party VDPF keygen
|
||||
/// without a pad dealer.
|
||||
/// @brief Distributed dual-spine Doerner–Shelat keygen for (2,3) point keys.
|
||||
/// @details Two `deal_point` / `point_party` runs (spines A and B) with Fig-3
|
||||
/// `τ` payloads. p0 samples `τ` and `π`; overlapping halves are shipped
|
||||
/// so p0 holds party-1, p2 holds party-2, p1 holds party-3.
|
||||
/// Produced keys are always verifiable. Default spines keep `α` as XOR
|
||||
/// shares (F_DPF3DS): `π` is peeled from the leaf seed of the shared
|
||||
/// path, not from an opened point. p0 sends p1 only its `τ` halves.
|
||||
/// Pass `RevealPoint=true` only when the caller wants the tree prefix
|
||||
/// (and packed lane on updatable keys). Pass `dpf::updatable` for
|
||||
/// beaver leaves and a later networked Fig-10 update via
|
||||
/// `dist_update_payload`.
|
||||
|
||||
#ifndef LIBDPF_PARTY_DIST_DPF3_HPP__
|
||||
#define LIBDPF_PARTY_DIST_DPF3_HPP__
|
||||
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "hedley/hedley.h"
|
||||
|
||||
#include "dist_ds.hpp"
|
||||
#include "key_io.hpp"
|
||||
|
||||
#include "dpf/dpf3.hpp"
|
||||
#include "dpf/dpf3_ds.hpp"
|
||||
#include "dpf/fp61.hpp"
|
||||
#include "dpf/shamir3.hpp"
|
||||
#include "dpf/wildcard.hpp"
|
||||
|
||||
namespace dpf
|
||||
{
|
||||
namespace party
|
||||
{
|
||||
|
||||
/// @brief How trio roles map onto Shamir party indices `{1,2,3}`.
|
||||
/// @details **dealer**: p0→1, p1→2, p2→3 (trusted keygen on p2, then ship).
|
||||
/// **dist**: p0→1, p2→2, p1→3 (`dist_with_dpf3_key` assembly).
|
||||
enum class dpf3_role_map : unsigned
|
||||
{
|
||||
dealer = 0,
|
||||
dist = 1,
|
||||
};
|
||||
|
||||
/// @brief Shamir party index for a trio role under `map`.
|
||||
HEDLEY_CONST
|
||||
HEDLEY_NO_THROW
|
||||
constexpr int dpf3_party_of(role r, dpf3_role_map map) noexcept
|
||||
{
|
||||
if (map == dpf3_role_map::dist)
|
||||
{
|
||||
if (r == role::p0)
|
||||
return 1;
|
||||
if (r == role::p2)
|
||||
return 2;
|
||||
return 3; // p1
|
||||
}
|
||||
// dealer
|
||||
if (r == role::p0)
|
||||
return 1;
|
||||
if (r == role::p1)
|
||||
return 2;
|
||||
return 3; // p2
|
||||
}
|
||||
|
||||
/// @brief Public VDPF+ offsets for one (2,3) keygen.
|
||||
struct dpf3_pi_msg
|
||||
{
|
||||
shamir3::xor61 pi_a{};
|
||||
shamir3::xor61 pi_b{};
|
||||
};
|
||||
|
||||
/// @brief Fig-10 patch broadcast (leaf patches so p2 need not learn `α`).
|
||||
template <typename Leaf>
|
||||
struct dpf3_fig10_msg
|
||||
{
|
||||
Leaf patch_a{};
|
||||
Leaf patch_b{};
|
||||
shamir3::xor61 pi_a{};
|
||||
shamir3::xor61 pi_b{};
|
||||
};
|
||||
|
||||
/// @brief p1's τ halves for spines A and B (party-3 strings). Does not reveal β.
|
||||
struct dpf3_tau_share
|
||||
{
|
||||
shamir3::xor61 t1{};
|
||||
shamir3::xor61 t3{};
|
||||
};
|
||||
|
||||
namespace detail_dist_dpf3
|
||||
{
|
||||
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename OutputT>
|
||||
using spine_out0 = decltype(dist::point_party<InteriorPRG, ExteriorPRG, InputT,
|
||||
OutputT, role::p0>(std::declval<trio &>(), std::declval<InputT>(),
|
||||
std::declval<OutputT>()));
|
||||
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename OutputT>
|
||||
using spine_key0 = spine_out0<InteriorPRG, ExteriorPRG, InputT, OutputT>;
|
||||
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename OutputT>
|
||||
using spine_out1 = decltype(dist::point_party<InteriorPRG, ExteriorPRG, InputT,
|
||||
OutputT, role::p1>(std::declval<trio &>(), std::declval<InputT>(),
|
||||
std::declval<OutputT>()));
|
||||
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename OutputT>
|
||||
using spine_key1 = spine_out1<InteriorPRG, ExteriorPRG, InputT, OutputT>;
|
||||
|
||||
template <typename Key, typename Share>
|
||||
void assign_wildcard_over_link(Key & key, Share my_share, trio & net, role self)
|
||||
{
|
||||
const role peer = self == role::p0 ? role::p1 : role::p0;
|
||||
auto & wrap = std::get<0>(key.leaf_nodes);
|
||||
auto blinded = wrap.compute_and_get_blinded_output_share(my_share);
|
||||
auto peer_blinded = net.exchange_with(peer, blinded);
|
||||
auto leaf = wrap.compute_and_get_leaf_share(peer_blinded);
|
||||
auto peer_leaf = net.exchange_with(peer, leaf);
|
||||
wrap.reconstruct_correction_word(peer_leaf);
|
||||
}
|
||||
|
||||
/// @brief Assign XOR payload from each party's τ half (payload never opened).
|
||||
template <typename Key>
|
||||
void assign_spine_tau_halves(trio & net, role self, Key & key,
|
||||
shamir3::xor61 my_half)
|
||||
{
|
||||
assign_wildcard_over_link(key, my_half, net, self);
|
||||
}
|
||||
|
||||
template <typename Key, typename Leaf>
|
||||
void apply_fig10_leaves(Key & key, const dpf3_fig10_msg<Leaf> & msg)
|
||||
{
|
||||
detail::dpf3_impl::apply_leaf_patch(key.a.dpf_key, msg.patch_a);
|
||||
detail::dpf3_impl::apply_leaf_patch(key.b.dpf_key, msg.patch_b);
|
||||
}
|
||||
|
||||
template <typename Key, typename Leaf>
|
||||
void apply_fig10(Key & key, const dpf3_fig10_msg<Leaf> & msg)
|
||||
{
|
||||
apply_fig10_leaves(key, msg);
|
||||
key.a.offset = msg.pi_a;
|
||||
key.b.offset = msg.pi_b;
|
||||
}
|
||||
|
||||
template <typename Key, typename Node>
|
||||
HEDLEY_WARN_UNUSED_RESULT
|
||||
shamir3::xor61 peel_from_seed(const Key & key, const Node & seed)
|
||||
{
|
||||
const auto y = key.template traverse_exterior<0>(seed);
|
||||
using Y = std::decay_t<decltype(y)>;
|
||||
if constexpr (is_secret_share_v<Y>)
|
||||
return shamir3::xor61{y.raw()};
|
||||
else if constexpr (std::is_integral_v<Y>
|
||||
|| std::is_convertible_v<Y, std::uint64_t>)
|
||||
return shamir3::xor61{static_cast<std::uint64_t>(y)};
|
||||
else
|
||||
{
|
||||
std::uint64_t w = 0;
|
||||
static_assert(sizeof(Y) >= sizeof(w),
|
||||
"peel_from_seed: leaf narrower than xor61");
|
||||
std::memcpy(&w, &y, sizeof(w));
|
||||
return shamir3::xor61{w};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputT>
|
||||
struct dpf3_opened
|
||||
{
|
||||
InputT opened_prefix{};
|
||||
/// Meaningful when the spine payload is a packed wildcard.
|
||||
unsigned opened_lane = 0;
|
||||
bool lane_opened = false;
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct has_nested_key : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_nested_key<T, std::void_t<decltype(std::declval<T &>().key)>>
|
||||
: std::true_type {};
|
||||
template <typename T>
|
||||
inline constexpr bool has_nested_key_v = has_nested_key<T>::value;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct has_opened_prefix : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_opened_prefix<T,
|
||||
std::void_t<decltype(std::declval<const T &>().opened_prefix)>>
|
||||
: std::true_type {};
|
||||
template <typename T>
|
||||
inline constexpr bool has_opened_prefix_v = has_opened_prefix<T>::value;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct has_opened_lane : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_opened_lane<T,
|
||||
std::void_t<decltype(std::declval<const T &>().opened_lane)>>
|
||||
: std::true_type {};
|
||||
template <typename T>
|
||||
inline constexpr bool has_opened_lane_v = has_opened_lane<T>::value;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct has_member_dpf_key : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_member_dpf_key<T, std::void_t<decltype(std::declval<T &>().dpf_key)>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename Held>
|
||||
auto spine_key_of(Held && held)
|
||||
{
|
||||
using H = std::decay_t<Held>;
|
||||
if constexpr (has_member_dpf_key<H>::value)
|
||||
return std::move(held.dpf_key);
|
||||
else if constexpr (has_nested_key_v<H>)
|
||||
return std::move(held.key);
|
||||
else
|
||||
return std::move(held);
|
||||
}
|
||||
|
||||
template <typename Held, typename InputT>
|
||||
void note_opened(dpf3_opened<InputT> & learned, const Held & held)
|
||||
{
|
||||
if constexpr (has_opened_prefix_v<std::decay_t<Held>>)
|
||||
{
|
||||
learned.opened_prefix = held.opened_prefix;
|
||||
if constexpr (has_opened_lane_v<std::decay_t<Held>>)
|
||||
{
|
||||
learned.opened_lane = held.opened_lane;
|
||||
learned.lane_opened = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InteriorPRG, typename ExteriorPRG, typename InputT,
|
||||
typename OutputT, bool Updatable, bool RevealPoint, typename Fn1,
|
||||
typename Fn2, typename Fn3>
|
||||
std::optional<dpf3_opened<InputT>> dist_with_dpf3_key_impl(trio & net, role self,
|
||||
InputT x0, InputT x1,
|
||||
const fp61 beta, Fn1 && on1, Fn2 && on2, Fn3 && on3)
|
||||
{
|
||||
using X = shamir3::xor61;
|
||||
using tau_quad = detail::dpf3_impl::tau_quad;
|
||||
using Key0 = spine_key0<InteriorPRG, ExteriorPRG, InputT, OutputT>;
|
||||
using Key1 = spine_key1<InteriorPRG, ExteriorPRG, InputT, OutputT>;
|
||||
using node = typename dpf::tree_traits<InteriorPRG>::node;
|
||||
constexpr bool V = true; // dist point_party always opens correction seeds
|
||||
|
||||
if (self == role::p2)
|
||||
{
|
||||
dist::deal_point<InteriorPRG, InputT, OutputT, !RevealPoint>(net);
|
||||
dist::deal_point<InteriorPRG, InputT, OutputT, !RevealPoint>(net);
|
||||
const auto pi = net.recv_from<dpf3_pi_msg>(role::p0, net::msg::delta);
|
||||
auto key_b0 = recv_key<Key0>(net, role::p0);
|
||||
auto key_a1 = recv_key<Key1>(net, role::p1);
|
||||
detail::dpf3_impl::vdpf_plus_key<Key1> plus_a1{std::move(key_a1),
|
||||
pi.pi_a};
|
||||
detail::dpf3_impl::vdpf_plus_key<Key0> plus_b0{std::move(key_b0),
|
||||
pi.pi_b};
|
||||
dpf3_key<2, decltype(plus_a1), decltype(plus_b0)> k2{
|
||||
std::move(plus_a1), std::move(plus_b0), V, false, Updatable};
|
||||
std::forward<Fn2>(on2)(std::move(k2));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// p0 samples τ from a Shamir split of β; p1 receives only (t1, t3).
|
||||
tau_quad t{};
|
||||
X my_a{};
|
||||
X my_b{};
|
||||
if (self == role::p0)
|
||||
{
|
||||
t = detail::dpf3_impl::sample_taus(beta);
|
||||
my_a = t.t0;
|
||||
my_b = t.t2;
|
||||
net.send_to(role::p1, net::msg::delta, dpf3_tau_share{t.t1, t.t3});
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto sh = net.recv_from<dpf3_tau_share>(role::p0, net::msg::delta);
|
||||
my_a = sh.t1;
|
||||
my_b = sh.t3;
|
||||
t.t1 = sh.t1;
|
||||
t.t3 = sh.t3;
|
||||
}
|
||||
|
||||
dpf3_opened<InputT> learned{};
|
||||
node seed_a{};
|
||||
node seed_b{};
|
||||
|
||||
// Non-updatable and updatable both plant beaver leaves; τ halves are
|
||||
// assigned without opening the spine payload. The outer Updatable flag
|
||||
// only gates Fig-10.
|
||||
// Spines still use per-message `exchange_with`. Wiring RoundSink here
|
||||
// needs a round budget that covers wild+hash leaf mux; undersizing hangs
|
||||
// the peer on `msg::round_batch`.
|
||||
OutputT wild{};
|
||||
if (self == role::p0)
|
||||
{
|
||||
auto out_a0 = dist::point_party<InteriorPRG, ExteriorPRG, InputT,
|
||||
OutputT, role::p0, false, RevealPoint>(net, x0, wild, false,
|
||||
&seed_a);
|
||||
note_opened(learned, out_a0);
|
||||
auto key_a0 = spine_key_of(std::move(out_a0));
|
||||
auto out_b0 = dist::point_party<InteriorPRG, ExteriorPRG, InputT,
|
||||
OutputT, role::p0, false, RevealPoint>(net, x0, wild, false,
|
||||
&seed_b);
|
||||
auto key_b0 = spine_key_of(std::move(out_b0));
|
||||
assign_spine_tau_halves(net, self, key_a0, my_a);
|
||||
assign_spine_tau_halves(net, self, key_b0, my_b);
|
||||
dpf3_pi_msg pi{};
|
||||
pi.pi_a = t.t0 + peel_from_seed(key_a0, seed_a);
|
||||
pi.pi_b = t.t2 + peel_from_seed(key_b0, seed_b);
|
||||
net.send_to(role::p1, net::msg::delta, pi);
|
||||
net.send_to(role::p2, net::msg::delta, pi);
|
||||
send_key(net, role::p2, key_b0);
|
||||
detail::dpf3_impl::vdpf_plus_key<Key0> plus_a0{std::move(key_a0),
|
||||
pi.pi_a};
|
||||
detail::dpf3_impl::vdpf_plus_key<Key0> plus_b0{std::move(key_b0),
|
||||
pi.pi_b};
|
||||
dpf3_key<1, decltype(plus_a0), decltype(plus_b0)> k1{
|
||||
std::move(plus_a0), std::move(plus_b0), V, false, Updatable};
|
||||
std::forward<Fn1>(on1)(std::move(k1));
|
||||
if constexpr (RevealPoint)
|
||||
return learned;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto out_a1 = dist::point_party<InteriorPRG, ExteriorPRG, InputT,
|
||||
OutputT, role::p1, false, RevealPoint>(net, x1, wild, false,
|
||||
&seed_a);
|
||||
note_opened(learned, out_a1);
|
||||
auto key_a1 = spine_key_of(std::move(out_a1));
|
||||
auto out_b1 = dist::point_party<InteriorPRG, ExteriorPRG, InputT,
|
||||
OutputT, role::p1, false, RevealPoint>(net, x1, wild, false,
|
||||
&seed_b);
|
||||
auto key_b1 = spine_key_of(std::move(out_b1));
|
||||
assign_spine_tau_halves(net, self, key_a1, my_a);
|
||||
assign_spine_tau_halves(net, self, key_b1, my_b);
|
||||
const auto pi = net.recv_from<dpf3_pi_msg>(role::p0, net::msg::delta);
|
||||
send_key(net, role::p2, key_a1);
|
||||
detail::dpf3_impl::vdpf_plus_key<Key1> plus_a1{std::move(key_a1),
|
||||
pi.pi_a};
|
||||
detail::dpf3_impl::vdpf_plus_key<Key1> plus_b1{std::move(key_b1),
|
||||
pi.pi_b};
|
||||
dpf3_key<3, decltype(plus_a1), decltype(plus_b1)> k3{
|
||||
std::move(plus_a1), std::move(plus_b1), V, false, Updatable};
|
||||
std::forward<Fn3>(on3)(std::move(k3));
|
||||
if constexpr (RevealPoint)
|
||||
return learned;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace detail_dist_dpf3
|
||||
|
||||
/// @brief Distributed dual-spine (2,3) keygen over the trio.
|
||||
/// @details Role map after assembly: **p0 → party 1**, **p2 → party 2**,
|
||||
/// **p1 → party 3**. Keys are always verifiable. Each computing
|
||||
/// party's view of `α` is only its XOR share; p1's view of `β` is
|
||||
/// only its τ halves (not a clear payload). Default return is empty.
|
||||
/// @tparam RevealPoint when true, p0/p1 also reconstruct the tree prefix
|
||||
/// @return Opened prefix when `RevealPoint`, else empty. Empty on p2.
|
||||
/// @throws std::runtime_error if a frame is truncated or tagged wrong
|
||||
/// \complexity Two `point_party` spines, so the local work is two O(n) walks, plus O(1) τ arithmetic.
|
||||
/// \rounds The rounds of two `point_party` calls, then one τ-share send (p0 to p1), one `dpf3_pi_msg` to p1 and p2, and one key send to p2. p2 runs two `deal_point` calls first. Counted in `dist_with_dpf3_key_impl`. Fig-10 update is `dist_update_payload`, not this function.
|
||||
/// \communication Two dealer tapes (see `deal_point` / `point_party`), one `dpf3_tau_share`, one `dpf3_pi_msg` (two `xor61` values), and one key blob (`send_key`, `sizeof` of the spine key).
|
||||
/// \preprocessing p2's `deal_point` pads for both spines. p0 samples the four τ strings locally from a Shamir split of β.
|
||||
template <typename InteriorPRG = dpf::prg::aes128,
|
||||
typename ExteriorPRG = InteriorPRG,
|
||||
bool RevealPoint = false,
|
||||
typename InputT,
|
||||
typename Fn1,
|
||||
typename Fn2,
|
||||
typename Fn3>
|
||||
[[nodiscard]] std::optional<InputT> dist_with_dpf3_key(trio & net, role self,
|
||||
InputT x0, InputT x1, const fp61 beta, Fn1 && on1, Fn2 && on2, Fn3 && on3)
|
||||
{
|
||||
auto opened = detail_dist_dpf3::dist_with_dpf3_key_impl<InteriorPRG,
|
||||
ExteriorPRG, InputT, dpf::wildcard_value<shamir3::xor61>, false,
|
||||
RevealPoint>(net, self, x0, x1, beta, std::forward<Fn1>(on1),
|
||||
std::forward<Fn2>(on2), std::forward<Fn3>(on3));
|
||||
if (!opened)
|
||||
return std::nullopt;
|
||||
return opened->opened_prefix;
|
||||
}
|
||||
|
||||
/// @brief What an updatable (2,3) keygen reconstructs when `RevealPoint`.
|
||||
template <typename InputT>
|
||||
struct dpf3_updatable_opened
|
||||
{
|
||||
InputT opened_prefix{};
|
||||
unsigned opened_lane = 0;
|
||||
};
|
||||
|
||||
/// @brief Distributed dual-spine (2,3) keygen with beaver leaves (Fig-10-ready).
|
||||
/// @tparam RevealPoint when true, return prefix and packed lane on p0/p1
|
||||
/// @return Opened values when `RevealPoint`, else empty. Empty on p2.
|
||||
/// \complexity Two `point_party` spines, so the local work is two O(n) walks, plus O(1) τ arithmetic.
|
||||
/// \rounds The rounds of two `point_party` calls, then one τ-share send (p0 to p1), one `dpf3_pi_msg` to p1 and p2, and one key send to p2. p2 runs two `deal_point` calls first. Counted in `dist_with_dpf3_key_impl`. Fig-10 update is `dist_update_payload`, not this function.
|
||||
/// \communication Two dealer tapes (see `deal_point` / `point_party`), one `dpf3_tau_share`, one `dpf3_pi_msg` (two `xor61` values), and one key blob (`send_key`, `sizeof` of the spine key).
|
||||
/// \preprocessing p2's `deal_point` pads for both spines. p0 samples the four τ strings locally from a Shamir split of β.
|
||||
template <typename InteriorPRG = dpf::prg::aes128,
|
||||
typename ExteriorPRG = InteriorPRG,
|
||||
bool RevealPoint = false,
|
||||
typename InputT,
|
||||
typename Fn1,
|
||||
typename Fn2,
|
||||
typename Fn3>
|
||||
[[nodiscard]] std::optional<dpf3_updatable_opened<InputT>> dist_with_dpf3_key(
|
||||
trio & net, role self, InputT x0, InputT x1, const fp61 beta, updatable,
|
||||
Fn1 && on1, Fn2 && on2, Fn3 && on3)
|
||||
{
|
||||
auto opened = detail_dist_dpf3::dist_with_dpf3_key_impl<InteriorPRG,
|
||||
ExteriorPRG, InputT, dpf::wildcard_value<shamir3::xor61>, true,
|
||||
RevealPoint>(net, self, x0, x1, beta, std::forward<Fn1>(on1),
|
||||
std::forward<Fn2>(on2), std::forward<Fn3>(on3));
|
||||
if (!opened)
|
||||
return std::nullopt;
|
||||
return dpf3_updatable_opened<InputT>{opened->opened_prefix,
|
||||
opened->opened_lane};
|
||||
}
|
||||
|
||||
/// @brief Networked Fig-10 payload update for keys from `dist_with_dpf3_key`.
|
||||
/// @details p0 and p1 (who are given `α`) exchange peels, p0 samples fresh `τ`
|
||||
/// and broadcasts leaf patches + new public `π`. p2 applies patches
|
||||
/// without learning `α`. Requires `key.updatable`.
|
||||
/// @throws std::invalid_argument if the key is not updatable
|
||||
template <typename Key, typename InputT>
|
||||
void dist_update_payload(trio & net, role self, Key & key, InputT alpha,
|
||||
fp61 beta_new)
|
||||
{
|
||||
static_assert(Key::is_dpf3, "dist_update_payload: dpf3 key");
|
||||
if (!key.updatable)
|
||||
throw std::invalid_argument(
|
||||
"dist_update_payload: key was not generated with dpf::updatable");
|
||||
|
||||
using X = shamir3::xor61;
|
||||
using InnerA = typename Key::plus_a_type::inner_type;
|
||||
using Leaf = decltype(detail::dpf3_impl::make_leaf_patch<InnerA>(alpha,
|
||||
X{}));
|
||||
using Msg = dpf3_fig10_msg<Leaf>;
|
||||
|
||||
struct peel_pair
|
||||
{
|
||||
X peel_a{};
|
||||
X peel_b{};
|
||||
};
|
||||
|
||||
Msg msg{};
|
||||
if (self == role::p0 || self == role::p1)
|
||||
{
|
||||
peel_pair mine{detail::dpf3_impl::peel(key.a.dpf_key, alpha),
|
||||
detail::dpf3_impl::peel(key.b.dpf_key, alpha)};
|
||||
const role peer = self == role::p0 ? role::p1 : role::p0;
|
||||
const peel_pair theirs = net.exchange_with(peer, mine);
|
||||
|
||||
if (self == role::p0)
|
||||
{
|
||||
// p0 = party 1 (A0,B0); p1 = party 3 (A1,B1).
|
||||
// Leaf CW patches only move the half whose path control bit is set;
|
||||
// compute π from a post-patch peel (same as dealer refresh_offset).
|
||||
detail::dpf3_impl::tau_quad told{};
|
||||
told.t0 = mine.peel_a + key.a.offset;
|
||||
told.t1 = theirs.peel_a + key.a.offset;
|
||||
told.t2 = mine.peel_b + key.b.offset;
|
||||
told.t3 = theirs.peel_b + key.b.offset;
|
||||
const auto tnew = detail::dpf3_impl::sample_taus(beta_new);
|
||||
const X dA = (tnew.t0 + tnew.t1) + (told.t0 + told.t1);
|
||||
const X dB = (tnew.t2 + tnew.t3) + (told.t2 + told.t3);
|
||||
msg.patch_a =
|
||||
detail::dpf3_impl::make_leaf_patch<InnerA>(alpha, dA);
|
||||
msg.patch_b =
|
||||
detail::dpf3_impl::make_leaf_patch<InnerA>(alpha, dB);
|
||||
detail_dist_dpf3::apply_fig10_leaves(key, msg);
|
||||
msg.pi_a = tnew.t0 + detail::dpf3_impl::peel(key.a.dpf_key, alpha);
|
||||
msg.pi_b = tnew.t2 + detail::dpf3_impl::peel(key.b.dpf_key, alpha);
|
||||
key.a.offset = msg.pi_a;
|
||||
key.b.offset = msg.pi_b;
|
||||
net.send_to(role::p1, net::msg::delta, msg);
|
||||
net.send_to(role::p2, net::msg::delta, msg);
|
||||
return;
|
||||
}
|
||||
msg = net.recv_from<Msg>(role::p0, net::msg::delta);
|
||||
detail_dist_dpf3::apply_fig10(key, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
msg = net.recv_from<Msg>(role::p0, net::msg::delta);
|
||||
detail_dist_dpf3::apply_fig10(key, msg);
|
||||
}
|
||||
|
||||
} // namespace party
|
||||
} // namespace dpf
|
||||
|
||||
#endif // LIBDPF_PARTY_DIST_DPF3_HPP__
|
||||
Loading…
Add table
Add a link
Reference in a new issue