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
|
|
@ -5,6 +5,7 @@
|
|||
/// up to the next checkpoint; a full-domain memoizer already holds
|
||||
/// those nodes. `q` tail bits, when the comparison sets the key
|
||||
/// depth, are a residual table on the node at height `h`.
|
||||
/// @note Boyle, Chandran, Gilboa, Gupta, Ishai, Kumar, and Rathee (EUROCRYPT 2021, ePrint 2020/1392) publish a value-correction word on every level. This implementation is ahead of that DCF on payload size: one ring word every B levels, about B times fewer value words, with the same one-seed-word spine. Point evaluation expands the siblings between checkpoints.
|
||||
/// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors)
|
||||
/// @license Released under a GNU General Public v2.0 (GPLv2) license.
|
||||
|
||||
|
|
@ -25,6 +26,7 @@
|
|||
#include "dpf/tree_traits.hpp"
|
||||
#include "dpf/twiddle.hpp"
|
||||
#include "dpf/utils.hpp"
|
||||
#include "dpf/verifiable.hpp"
|
||||
|
||||
namespace dpf
|
||||
{
|
||||
|
|
@ -33,6 +35,20 @@ namespace detail
|
|||
namespace blocked
|
||||
{
|
||||
|
||||
/// @brief High bit set on `fold_node` level so blocked proofs diverge from native.
|
||||
/// @details Must match the level passed to `make_cs` at blocked keygen. Parked
|
||||
/// sibling folds reuse this tag with the sibling's tree depth so they
|
||||
/// share `correction_seeds[depth-1]`.
|
||||
inline constexpr std::size_t fold_spine_tag = std::size_t{1} << 15;
|
||||
|
||||
template <typename NodeT>
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
void fold_spine_node(proof_token & pi, std::size_t level,
|
||||
psnip_uint64_t x_bits, NodeT seed, const cs_block & cs) noexcept
|
||||
{
|
||||
detail::vdpf::fold_node(pi, fold_spine_tag | level, x_bits, seed, cs);
|
||||
}
|
||||
|
||||
template <std::size_t H, std::size_t B>
|
||||
struct schedule
|
||||
{
|
||||
|
|
@ -306,7 +322,8 @@ uint64_t finish_share(const KeyT & dpf, uint64_t suffix, uint64_t acc,
|
|||
}
|
||||
|
||||
template <typename KeyT, typename InputT, typename PathMemoizer>
|
||||
uint64_t eval_share(const KeyT & dpf, InputT tx, PathMemoizer & path)
|
||||
uint64_t eval_share(const KeyT & dpf, InputT tx, PathMemoizer & path,
|
||||
proof_token * pi = nullptr)
|
||||
{
|
||||
using node = typename KeyT::interior_node;
|
||||
const auto & ch = dpf.cmp();
|
||||
|
|
@ -326,18 +343,42 @@ uint64_t eval_share(const KeyT & dpf, InputT tx, PathMemoizer & path)
|
|||
const std::size_t nbits = static_cast<std::size_t>(ch.nbits);
|
||||
const int party = dpf::get_lo_bit(dpf.root()) ? 1 : 0;
|
||||
|
||||
// Expand the seed spine without native path folds; blocked proofs use
|
||||
// domain-separated tags on newly filled levels only (path-memo safe).
|
||||
const auto resume = dpf::detail::path_resume_for_level(path, dpf, tx, h);
|
||||
dpf::detail::ensure_level(dpf, tx, path, h);
|
||||
|
||||
if constexpr (KeyT::is_verifiable)
|
||||
{
|
||||
if (pi != nullptr && resume <= h)
|
||||
{
|
||||
constexpr auto input_bits =
|
||||
utils::bitlength_of_v<typename KeyT::input_type>;
|
||||
for (std::size_t level = resume; level <= h; ++level)
|
||||
{
|
||||
const auto x_bits = static_cast<psnip_uint64_t>(
|
||||
utils::to_integral_type<typename KeyT::input_type>{}(tx)
|
||||
>> (input_bits - level));
|
||||
fold_spine_node(*pi, level - 1, x_bits, path[level],
|
||||
dpf.correction_seeds()[level - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct parked
|
||||
{
|
||||
node seed;
|
||||
std::size_t depth;
|
||||
psnip_uint64_t prefix_bits;
|
||||
};
|
||||
parked pend[128];
|
||||
std::size_t npend = 0;
|
||||
|
||||
uint64_t acc = 0;
|
||||
auto bit_mask = KeyT::msb_mask;
|
||||
// Value accumulation always walks from the root. Proof folds for parked
|
||||
// siblings must not repeat depths already authenticated on a warm path:
|
||||
// re-folding XORs the same contribution away (path-memo cancel bug).
|
||||
for (std::size_t level = 0; level < h; ++level, bit_mask >>= 1)
|
||||
{
|
||||
const bool xi = !!(bit_mask & tx);
|
||||
|
|
@ -349,6 +390,13 @@ uint64_t eval_share(const KeyT & dpf, InputT tx, PathMemoizer & path)
|
|||
{
|
||||
pend[npend].seed = right;
|
||||
pend[npend].depth = level + 1;
|
||||
// Sibling is the right child of `parent`: path bits with low bit 1.
|
||||
const auto path_bits = static_cast<psnip_uint64_t>(
|
||||
utils::to_integral_type<typename KeyT::input_type>{}(tx)
|
||||
>> (utils::bitlength_of_v<typename KeyT::input_type>
|
||||
- (level + 1)));
|
||||
pend[npend].prefix_bits = (path_bits & ~static_cast<psnip_uint64_t>(1))
|
||||
| static_cast<psnip_uint64_t>(1);
|
||||
++npend;
|
||||
}
|
||||
const std::size_t c = level + 1;
|
||||
|
|
@ -357,6 +405,15 @@ uint64_t eval_share(const KeyT & dpf, InputT tx, PathMemoizer & path)
|
|||
const uint64_t word = dpf.value_cw(sched::index(c));
|
||||
for (std::size_t p = 0; p < npend; ++p)
|
||||
{
|
||||
if constexpr (KeyT::is_verifiable)
|
||||
{
|
||||
if (pi != nullptr && pend[p].depth >= resume)
|
||||
{
|
||||
// Tree depth (not checkpoint index): must match CS level.
|
||||
fold_spine_node(*pi, pend[p].depth - 1, pend[p].prefix_bits,
|
||||
pend[p].seed, dpf.correction_seeds()[pend[p].depth - 1]);
|
||||
}
|
||||
}
|
||||
acc = add_frontier<KeyT>(acc, pend[p].seed, pend[p].depth, c,
|
||||
dpf, word, mask, party);
|
||||
}
|
||||
|
|
@ -392,9 +449,17 @@ const typename KeyT::interior_node & memo_node(const Memo & memo, Integral prefi
|
|||
return memo[depth][idx];
|
||||
}
|
||||
|
||||
template <typename KeyT, typename Integral, typename Memo>
|
||||
/// @brief Evaluate one lane from an interval memo; optionally fold a VDPF proof.
|
||||
/// @details When `pi == nullptr` or the key is not verifiable, matches the
|
||||
/// historical body (no folds). When set, folds path / covered
|
||||
/// checkpoint / frontier seeds with `fold_spine_node`, skipping depths
|
||||
/// already covered by `path` (same resume rule as `eval_share`).
|
||||
/// Interval BFS prove must keep passing a null `pi` here.
|
||||
template <typename KeyT, typename Integral, typename Memo,
|
||||
typename PathMemoizer = ::dpf::basic_path_memoizer<KeyT>>
|
||||
uint64_t eval_share_memo(const KeyT & dpf, Integral lane,
|
||||
Integral from_lane, Integral to_excl, const Memo & memo)
|
||||
Integral from_lane, Integral to_excl, const Memo & memo,
|
||||
proof_token * pi = nullptr, PathMemoizer * path = nullptr)
|
||||
{
|
||||
using node = typename KeyT::interior_node;
|
||||
const auto & ch = dpf.cmp();
|
||||
|
|
@ -412,6 +477,43 @@ uint64_t eval_share_memo(const KeyT & dpf, Integral lane,
|
|||
constexpr std::size_t h = KeyT::cmp_h;
|
||||
using sched = schedule<h, KeyT::cmp_block>;
|
||||
const int party = dpf::get_lo_bit(dpf.root()) ? 1 : 0;
|
||||
const std::size_t nbits = static_cast<std::size_t>(ch.nbits);
|
||||
|
||||
std::size_t resume = 0;
|
||||
if constexpr (KeyT::is_verifiable)
|
||||
{
|
||||
if (pi != nullptr && path != nullptr)
|
||||
{
|
||||
const auto tx = static_cast<typename KeyT::input_type>(lane);
|
||||
resume = dpf::detail::path_resume_for_level(*path, dpf, tx, h);
|
||||
dpf::detail::path_note_filled_to(*path, h);
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (KeyT::is_verifiable)
|
||||
{
|
||||
if (pi != nullptr && resume <= h)
|
||||
{
|
||||
Integral pfx = 0;
|
||||
for (std::size_t depth = 0; depth <= h; ++depth)
|
||||
{
|
||||
if (depth >= resume && depth >= 1)
|
||||
{
|
||||
fold_spine_node(*pi, depth - 1,
|
||||
static_cast<psnip_uint64_t>(pfx),
|
||||
memo_node<KeyT>(memo, pfx, depth, from_lane),
|
||||
dpf.correction_seeds()[depth - 1]);
|
||||
}
|
||||
if (depth < h)
|
||||
{
|
||||
const bool xi =
|
||||
((lane >> (nbits - 1 - depth)) & Integral{1}) != 0;
|
||||
pfx = static_cast<Integral>(
|
||||
(pfx << 1) | (xi ? Integral{1} : Integral{0}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct parked
|
||||
{
|
||||
|
|
@ -424,7 +526,6 @@ uint64_t eval_share_memo(const KeyT & dpf, Integral lane,
|
|||
|
||||
uint64_t acc = 0;
|
||||
Integral path_pref = 0;
|
||||
const std::size_t nbits = static_cast<std::size_t>(ch.nbits);
|
||||
for (std::size_t level = 0; level < h; ++level)
|
||||
{
|
||||
const bool xi = ((lane >> (nbits - 1 - level)) & Integral{1}) != 0;
|
||||
|
|
@ -440,7 +541,8 @@ uint64_t eval_share_memo(const KeyT & dpf, Integral lane,
|
|||
pend[npend].depth = level + 1;
|
||||
++npend;
|
||||
}
|
||||
path_pref = static_cast<Integral>((path_pref << 1) | Integral{xi ? 1 : 0});
|
||||
path_pref = static_cast<Integral>(
|
||||
(path_pref << 1) | (xi ? Integral{1} : Integral{0}));
|
||||
const std::size_t c = level + 1;
|
||||
if (!sched::contains(c))
|
||||
continue;
|
||||
|
|
@ -461,6 +563,16 @@ uint64_t eval_share_memo(const KeyT & dpf, Integral lane,
|
|||
for (Integral k = 0; k < nleaf; ++k)
|
||||
{
|
||||
const auto pref = static_cast<Integral>(leftmost + k);
|
||||
if constexpr (KeyT::is_verifiable)
|
||||
{
|
||||
if (pi != nullptr && c >= resume && c >= 1)
|
||||
{
|
||||
fold_spine_node(*pi, c - 1,
|
||||
static_cast<psnip_uint64_t>(pref),
|
||||
memo_node<KeyT>(memo, pref, c, from_lane),
|
||||
dpf.correction_seeds()[c - 1]);
|
||||
}
|
||||
}
|
||||
acc = add_membership<KeyT>(acc,
|
||||
memo_node<KeyT>(memo, pref, c, from_lane), word, mask,
|
||||
party);
|
||||
|
|
@ -468,6 +580,17 @@ uint64_t eval_share_memo(const KeyT & dpf, Integral lane,
|
|||
}
|
||||
else
|
||||
{
|
||||
if constexpr (KeyT::is_verifiable)
|
||||
{
|
||||
if (pi != nullptr && pend[p].depth >= resume
|
||||
&& pend[p].depth >= 1)
|
||||
{
|
||||
fold_spine_node(*pi, pend[p].depth - 1,
|
||||
static_cast<psnip_uint64_t>(pend[p].prefix),
|
||||
pend[p].seed,
|
||||
dpf.correction_seeds()[pend[p].depth - 1]);
|
||||
}
|
||||
}
|
||||
acc = add_frontier<KeyT>(acc, pend[p].seed, pend[p].depth, c,
|
||||
dpf, word, mask, party);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue