libdpf/include/dpf/rss_seed.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

217 lines
6.5 KiB
C++
Raw 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/rss_seed.hpp
/// @brief Pairwise PRG seeds for honest-majority 3PC RSS preprocessing.
/// @details Parties 0,1,2 hold keys `k01`, `k12`, `k20`. Party `i` derives
/// both components of a replicated random value, a zero-sharing, and
/// the local cross term of an RSS multiply with no message.
#ifndef LIBDPF_INCLUDE_DPF_RSS_SEED_HPP__
#define LIBDPF_INCLUDE_DPF_RSS_SEED_HPP__
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <utility>
#include "hedley/hedley.h"
#include "dpf/buffered_prg.hpp"
#include "dpf/prg_aes.hpp"
#include "dpf/random.hpp"
#include "dpf/secret_share.hpp"
namespace dpf
{
namespace rss
{
using seed_block = typename prg::aes128::block_type;
/// @brief Three pairwise master seeds. Role `i` holds seeds with `i±1 mod 3`.
struct seed_bundle
{
seed_block k01{};
seed_block k12{};
seed_block k20{};
};
/// @brief Sample three independent pairwise seeds (dealer / setup).
HEDLEY_WARN_UNUSED_RESULT
inline seed_bundle sample_seed_bundle()
{
seed_bundle b;
b.k01 = randomness::sample_master_seed<prg::aes128>();
b.k12 = randomness::sample_master_seed<prg::aes128>();
b.k20 = randomness::sample_master_seed<prg::aes128>();
return b;
}
/// @brief Party `me`'s view: the two seeds it shares with its neighbors.
struct party_seeds
{
unsigned me = 0;
seed_block with_prev{}; ///< shared with (me+2)%3
seed_block with_next{}; ///< shared with (me+1)%3
static party_seeds from_bundle(const seed_bundle & b, unsigned me)
{
if (me > 2)
throw std::invalid_argument("rss party_seeds: me must be 0..2");
party_seeds s;
s.me = me;
if (me == 0)
{
s.with_prev = b.k20;
s.with_next = b.k01;
}
else if (me == 1)
{
s.with_prev = b.k01;
s.with_next = b.k12;
}
else
{
s.with_prev = b.k12;
s.with_next = b.k20;
}
return s;
}
};
namespace detail
{
template <typename T>
T derive(seed_block master, std::uint32_t role, std::uint64_t index)
{
randomness::lane_table<T, prg::aes128> table(master);
return table.value_at(role, index);
}
inline seed_block pair_seed(unsigned a, unsigned b, const seed_bundle & bundle)
{
const unsigned lo = a < b ? a : b;
const unsigned hi = a < b ? b : a;
if (lo == 0 && hi == 1)
return bundle.k01;
if (lo == 1 && hi == 2)
return bundle.k12;
if (lo == 0 && hi == 2)
return bundle.k20;
throw std::invalid_argument("rss pair_seed: bad pair");
}
} // namespace detail
/// @brief Replicated random `r` at `index`. Party `me` holds `(r_me, r_{me+1})`.
template <typename T>
HEDLEY_WARN_UNUSED_RESULT
replicated_share<T, 0> random_replicated0(const party_seeds & s, std::uint64_t index)
{
if (s.me != 0)
throw std::invalid_argument("random_replicated0: wrong party");
// r0 from k20 (parties 2,0), r1 from k01 (parties 0,1)
const T r0 = detail::derive<T>(s.with_prev, 0, index);
const T r1 = detail::derive<T>(s.with_next, 1, index);
return replicated_share<T, 0>::from_raw(r0, r1);
}
template <typename T>
HEDLEY_WARN_UNUSED_RESULT
replicated_share<T, 1> random_replicated1(const party_seeds & s, std::uint64_t index)
{
if (s.me != 1)
throw std::invalid_argument("random_replicated1: wrong party");
const T r1 = detail::derive<T>(s.with_prev, 1, index);
const T r2 = detail::derive<T>(s.with_next, 2, index);
return replicated_share<T, 1>::from_raw(r1, r2);
}
template <typename T>
HEDLEY_WARN_UNUSED_RESULT
replicated_share<T, 2> random_replicated2(const party_seeds & s, std::uint64_t index)
{
if (s.me != 2)
throw std::invalid_argument("random_replicated2: wrong party");
const T r2 = detail::derive<T>(s.with_prev, 2, index);
const T r0 = detail::derive<T>(s.with_next, 0, index);
return replicated_share<T, 2>::from_raw(r2, r0);
}
/// @brief Party-erased random replicated share.
template <typename T>
HEDLEY_WARN_UNUSED_RESULT
std::pair<T, T> random_replicated_components(const party_seeds & s,
std::uint64_t index)
{
if (s.me == 0)
{
auto sh = random_replicated0<T>(s, index);
return {sh.own, sh.next};
}
if (s.me == 1)
{
auto sh = random_replicated1<T>(s, index);
return {sh.own, sh.next};
}
auto sh = random_replicated2<T>(s, index);
return {sh.own, sh.next};
}
/// @brief Zero-sharing for reshare: party `i` holds `z_i` with sum zero.
/// @details `z_i = r_i - r_{i-1}` where `r` is a common pairwise stream on
/// each edge; the three differences cancel.
template <typename T>
HEDLEY_WARN_UNUSED_RESULT
T zero_share(const party_seeds & s, std::uint64_t index)
{
// On edge with_next: parties me and next share stream role 0 → value α
// On edge with_prev: parties me and prev share stream role 0 → value β
// z_me = α - β so sum over the ring is zero.
const T alpha = detail::derive<T>(s.with_next, 10u + s.me, index);
const T beta = detail::derive<T>(s.with_prev, 10u + ((s.me + 2) % 3), index);
return static_cast<T>(alpha - beta);
}
/// @brief Local y-component of an RSS multiply before neighbor refresh.
/// @details Party `i` holds `(x_i, x_{i+1})` and `(y_i, y_{i+1})`. The local
/// product factor is `x_i*y_i + x_i*y_{i+1} + x_{i+1}*y_i` plus a
/// zero-mask so the three factors sum to `xy` after refresh.
template <typename T>
HEDLEY_WARN_UNUSED_RESULT
T rss_mul_local(const party_seeds & s, T x_own, T x_next, T y_own, T y_next,
std::uint64_t index)
{
const T cross = static_cast<T>(
x_own * y_own + x_own * y_next + x_next * y_own);
const T mask = zero_share<T>(s, index);
return static_cast<T>(cross + mask);
}
/// @brief Full dealer view: derive every party's components for tests.
template <typename T>
struct replicated_triple
{
replicated_share<T, 0> p0;
replicated_share<T, 1> p1;
replicated_share<T, 2> p2;
};
template <typename T>
HEDLEY_WARN_UNUSED_RESULT
replicated_triple<T> random_replicated_all(const seed_bundle & b,
std::uint64_t index)
{
auto s0 = party_seeds::from_bundle(b, 0);
auto s1 = party_seeds::from_bundle(b, 1);
auto s2 = party_seeds::from_bundle(b, 2);
return replicated_triple<T>{
random_replicated0<T>(s0, index),
random_replicated1<T>(s1, index),
random_replicated2<T>(s2, index)};
}
} // namespace rss
} // namespace dpf
#endif // LIBDPF_INCLUDE_DPF_RSS_SEED_HPP__