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:
Ryan Henry 2026-09-28 05:59:19 -06:00
parent 695f8e84f7
commit 0d22946a0e
1835 changed files with 170291 additions and 2849 deletions

View file

@ -10,10 +10,11 @@
#include <bsd/stdlib.h>
#include <array>
#include <cerrno>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <exception>
#include <fcntl.h>
#include <mutex>
@ -31,11 +32,19 @@ namespace dpf
namespace detail
{
/// @brief Thread-local count of bytes delivered by `uniform_fill`.
inline thread_local std::uint64_t random_bytes_tls = 0;
/// @brief When set, `uniform_fill` copies from this hook and does not read the
/// system RNG. Used to feed the same beaver coins to dealer `make_dpf` and
/// Doerner–Shelat gen. Null in normal use.
inline thread_local void (*uniform_bytes_hook)(void *, std::size_t) = nullptr;
/// @brief State for `uniform_bytes_hook`, set and read by the hook's owner
/// (`experiment` keeps itself here). Travels with the hook when another thread
/// adopts this one's draws (`dpf/thread_work.hpp`).
inline thread_local void * uniform_bytes_ctx = nullptr;
template <typename T>
HEDLEY_ALWAYS_INLINE
HEDLEY_NO_THROW
@ -170,6 +179,20 @@ inline entropy_source & entropy()
} // namespace detail
/// @brief Zero the thread-local random-byte counter.
HEDLEY_ALWAYS_INLINE
void reset_random_bytes_count() noexcept
{
detail::random_bytes_tls = 0;
}
/// @brief Bytes filled by `uniform_fill` since the last reset on this thread.
HEDLEY_ALWAYS_INLINE
std::uint64_t random_bytes_count() noexcept
{
return detail::random_bytes_tls;
}
template <typename T>
HEDLEY_NO_THROW
auto & uniform_fill(T & buf) noexcept // NOLINT(runtime/references)
@ -186,12 +209,17 @@ auto & uniform_fill(T & buf) noexcept // NOLINT(runtime/references)
}
else
{
if (detail::fill_from_hook(buf)) return buf;
if (detail::fill_from_hook(buf))
{
detail::random_bytes_tls += sizeof(buf);
return buf;
}
#if defined(LIBDPF_USE_ARC4RANDOM)
arc4random_buf(&buf, sizeof(buf));
#else
detail::entropy().read(&buf, sizeof(buf));
#endif
detail::random_bytes_tls += sizeof(buf);
return buf;
}
}
@ -214,24 +242,82 @@ auto additively_share(T secret) noexcept
{
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
T_ tmp = uniform_sample<T_>();
// Signed subtraction overflows for extreme shares. Subtract in the
// unsigned width and copy the bits back so the group is mod 2^n.
T_ other;
if constexpr (std::is_integral_v<T_> && std::is_signed_v<T_>)
{
using U = std::make_unsigned_t<T_>;
U diff = static_cast<U>(static_cast<T_>(secret)) - static_cast<U>(tmp);
std::memcpy(&other, &diff, sizeof(other));
}
else
{
other = static_cast<T_>(static_cast<T_>(secret) - tmp);
}
T_ other = detail::group_sub(static_cast<T_>(secret), tmp);
return std::make_pair(
additive_share<T_, 0>::from_raw(tmp),
additive_share<T_, 1>::from_raw(other));
}
/// @brief Uniform (3,3)-additive sharing of `secret`.
/// @details Two components are uniform. The third is `secret` minus those
/// two in the share group, so the three shares sum to `secret`.
/// @tparam T value type
/// @param secret the cleartext secret
/// @return shares for parties 0, 1, and 2
template <typename T>
HEDLEY_ALWAYS_INLINE
HEDLEY_NO_THROW
auto additively_share3(T secret) noexcept
{
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
const T_ a = uniform_sample<T_>();
const T_ b = uniform_sample<T_>();
const T_ c = detail::group_sub(
detail::group_sub(static_cast<T_>(secret), a), b);
return std::make_tuple(
additive3_share<T_, 0>::from_raw(a),
additive3_share<T_, 1>::from_raw(b),
additive3_share<T_, 2>::from_raw(c));
}
/// @brief Uniform (2,3)-replicated sharing of `secret`.
/// @details The underlying (3,3) components are a uniform additive split.
/// Each party receives its component and the next party's.
/// @tparam T value type
/// @param secret the cleartext secret
/// @return shares for parties 0, 1, and 2
template <typename T>
HEDLEY_ALWAYS_INLINE
HEDLEY_NO_THROW
auto share_replicated(T secret) noexcept
{
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
const T_ x0 = uniform_sample<T_>();
const T_ x1 = uniform_sample<T_>();
const T_ x2 = detail::group_sub(
detail::group_sub(static_cast<T_>(secret), x0), x1);
return make_replicated_shares(x0, x1, x2);
}
namespace shamir
{
/// @brief Uniform `(K,N)` Shamir sharing of `secret`.
/// @details Coefficients of `x, ..., x^{K-1}` are `uniform_sample<T>`. The
/// shares are `deal<T, K, N>`. Threshold 1 draws nothing: every share
/// equals `secret`. `shamir3::share_secret` is the `(2,3)` case on
/// `fp61`, reindexed to points `1`, `2`, and `3`.
/// @tparam K shares required to reconstruct
/// @tparam N shareholders
/// @tparam T field type. Opening needs `detail::shamir_field<T>`
/// @param secret the cleartext secret
/// @return one share per party `0 .. N-1`
/// \complexity O(NK) field operations, plus `K-1` field samples. No messages.
template <typename T, std::size_t K, std::size_t N>
HEDLEY_WARN_UNUSED_RESULT
HEDLEY_NO_THROW
auto share_secret(T secret) noexcept
{
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
constexpr std::size_t degree = access<K, N>::degree;
std::array<T_, degree> coeff{};
for (std::size_t i = 0; i < degree; ++i)
coeff[i] = uniform_sample<T_>();
return deal<T_, K, N>(static_cast<T_>(secret), coeff);
}
} // namespace shamir
} // namespace dpf
#endif // LIBDPF_INCLUDE_DPF_RANDOM_HPP__