Document the new DPF surfaces in one command set, and test the field, half-tree, and multipoint edges.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-24 23:18:10 -06:00
parent 0d8a5a8131
commit 0dff6df8ed
250 changed files with 12199 additions and 1981 deletions

View file

@ -58,26 +58,31 @@ template <std::size_t N, typename O, typename ...Os>
struct is_at<at_pack<N, O, Os...>> : std::true_type {};
template <typename T> inline constexpr bool is_at_v = is_at<T>::value;
/// Phantom pack element for a key's comparison (DCF) channel. Not a leaf: it
/// @brief Phantom pack element for a key's comparison (DCF) channel. Not a leaf: it
/// only records the cmp prefix depth in the key's type. `Depth` is the number
/// of tree levels the comparison walks (0 is reserved for "no cmp").
/// `OutBits` is the comparison output group width (bits of the β payload),
/// @details `OutBits` is the comparison output group width (bits of the β payload),
/// so the value CWs / addend can be stored at group width instead of a full
/// padded `uint64_t` per level.
/// @tparam Depth depth
/// @tparam OutBits out bits
/// @tparam Wild whether the payload is a wildcard
/// @tparam BlockWidth checkpoint spacing, in levels
/// @tparam Incremental whether a final correction is stored at every depth
template <std::size_t Depth, std::size_t OutBits = 0, bool Wild = false,
std::size_t BlockWidth = 0, bool Incremental = false>
struct cmp_channel_tag
{
static constexpr std::size_t depth = Depth;
static constexpr std::size_t out_bits = OutBits;
/// True when the comparison payload (β) is a wildcard to be assigned
/// @brief True when the comparison payload (β) is a wildcard to be assigned
/// after keygen. Concrete (non-wildcard) cmp keys keep `Wild == false`
/// so their layout / type name is unchanged.
static constexpr bool wild = Wild;
/// 0 keeps the per-level path-sum. `B >= 1` selects blocked checkpoints
/// @brief 0 keeps the per-level path-sum. `B >= 1` selects blocked checkpoints
/// of target width `B`.
static constexpr std::size_t block_width = BlockWidth;
/// Save a final correction at every depth (`idcf`).
/// @brief Save a final correction at every depth (`idcf`).
static constexpr bool incremental = Incremental;
};
@ -90,6 +95,38 @@ template <typename T>
inline constexpr bool is_cmp_channel_tag_v =
is_cmp_channel_tag<std::decay_t<T>>::value;
/// Phantom pack element: key carries per-level VDPF correction seeds.
struct verifiable
{
static constexpr bool is_verifiable_tag = true;
};
/// Phantom pack element: ROM leaf stretch + extractability checks.
struct extractable
{
static constexpr bool is_extractable_tag = true;
};
template <typename T>
struct is_verifiable_tag : std::false_type
{ };
template <>
struct is_verifiable_tag<verifiable> : std::true_type
{ };
template <typename T>
inline constexpr bool is_verifiable_tag_v =
is_verifiable_tag<std::decay_t<T>>::value;
template <typename T>
struct is_extractable_tag : std::false_type
{ };
template <>
struct is_extractable_tag<extractable> : std::true_type
{ };
template <typename T>
inline constexpr bool is_extractable_tag_v =
is_extractable_tag<std::decay_t<T>>::value;
namespace detail
{
namespace incr
@ -99,13 +136,25 @@ namespace incr
// A concrete placed output: an output type `OutputT` planted at prefix `N`.
// ---------------------------------------------------------------------------
/// @brief Default: placed payload type is the stored type. Specialized for
/// `arith_beta<T>` in `doerner_shelat.hpp` so the key leaf type is `T`.
/// @tparam T value type
template <typename T>
struct unwrap_placed_output
{
using type = T;
};
template <std::size_t N, typename OutputT>
struct placed
{
static constexpr std::size_t prefix = N;
using output_type = OutputT;
/// @brief Stored argument type (may be `arith_beta<T>`).
using stored_type = OutputT;
/// @brief Key / leaf payload type (`T` when stored is `arith_beta<T>`).
using output_type = typename unwrap_placed_output<OutputT>::type;
OutputT value;
OutputT addend{}; // public if_false for eq(...); party 0 absorbs at eval
output_type addend{}; // public if_false for eq(...); party 0 absorbs at eval
};
template <typename T> struct is_placed : std::false_type {};
@ -114,8 +163,10 @@ struct is_placed<placed<N, O>> : std::true_type {};
template <typename T>
inline constexpr bool is_placed_v = is_placed<std::decay_t<T>>::value;
/// Heavy-hitters incremental point function: one payload per prefix length.
/// `levels[i]` is the bit length of slot `i`.
/// @brief Heavy-hitters incremental point function: one payload per prefix length.
/// @details `levels[i]` is the bit length of slot `i`.
/// @tparam LevelSeq level seq
/// @tparam Betas betas
template <typename LevelSeq, typename ...Betas>
struct idpf_pack;
@ -416,6 +467,8 @@ struct normalize_one
static constexpr bool cmp_wild = false;
static constexpr std::size_t cmp_block = 0;
static constexpr bool cmp_idcf = false;
static constexpr bool is_verifiable = false;
static constexpr bool is_extractable = false;
};
template <std::size_t BitLen, std::size_t N, typename T>
struct normalize_one<BitLen, placed<N, T>>
@ -426,6 +479,8 @@ struct normalize_one<BitLen, placed<N, T>>
static constexpr bool cmp_wild = false;
static constexpr std::size_t cmp_block = 0;
static constexpr bool cmp_idcf = false;
static constexpr bool is_verifiable = false;
static constexpr bool is_extractable = false;
};
template <std::size_t BitLen, std::size_t Depth, std::size_t OutBits, bool Wild,
std::size_t Block, bool Incremental>
@ -438,6 +493,32 @@ struct normalize_one<BitLen,
static constexpr bool cmp_wild = Wild;
static constexpr std::size_t cmp_block = Block;
static constexpr bool cmp_idcf = Incremental;
static constexpr bool is_verifiable = false;
static constexpr bool is_extractable = false;
};
template <std::size_t BitLen>
struct normalize_one<BitLen, verifiable>
{
using placed_tuple = std::tuple<>;
static constexpr std::size_t cmp_depth = 0;
static constexpr std::size_t cmp_out_bits = 0;
static constexpr bool cmp_wild = false;
static constexpr std::size_t cmp_block = 0;
static constexpr bool cmp_idcf = false;
static constexpr bool is_verifiable = true;
static constexpr bool is_extractable = false;
};
template <std::size_t BitLen>
struct normalize_one<BitLen, extractable>
{
using placed_tuple = std::tuple<>;
static constexpr std::size_t cmp_depth = 0;
static constexpr std::size_t cmp_out_bits = 0;
static constexpr bool cmp_wild = false;
static constexpr std::size_t cmp_block = 0;
static constexpr bool cmp_idcf = false;
static constexpr bool is_verifiable = false;
static constexpr bool is_extractable = true;
};
template <std::size_t BitLen, typename ...Elems>
@ -448,18 +529,18 @@ struct normalize_pack
std::declval<typename normalize_one<BitLen, Elems>::placed_tuple>()...));
static constexpr std::size_t cmp_depth =
(std::size_t{0} + ... + normalize_one<BitLen, Elems>::cmp_depth);
// At most one comparison channel per key, so the sum is that channel's
// output width (0 when there is no cmp channel).
static constexpr std::size_t cmp_out_bits =
(std::size_t{0} + ... + normalize_one<BitLen, Elems>::cmp_out_bits);
// At most one comparison channel per key, so the OR is that channel's
// wildcard flag (false when there is no cmp channel).
static constexpr bool cmp_wild =
(false || ... || normalize_one<BitLen, Elems>::cmp_wild);
static constexpr std::size_t cmp_block =
(std::size_t{0} + ... + normalize_one<BitLen, Elems>::cmp_block);
static constexpr bool cmp_idcf =
(false || ... || normalize_one<BitLen, Elems>::cmp_idcf);
static constexpr bool is_verifiable =
(false || ... || normalize_one<BitLen, Elems>::is_verifiable);
static constexpr bool is_extractable =
(false || ... || normalize_one<BitLen, Elems>::is_extractable);
};
template <std::size_t BitLen>
@ -471,19 +552,26 @@ struct normalize_pack<BitLen>
static constexpr bool cmp_wild = false;
static constexpr std::size_t cmp_block = 0;
static constexpr bool cmp_idcf = false;
static constexpr bool is_verifiable = false;
static constexpr bool is_extractable = false;
};
/// True iff the pack is "classic-shaped": every element is a bare output (no
/// `placed<>` from `at<>` and no `cmp_channel_tag<>`).
/// @brief True iff the pack is "classic-shaped": every element is a bare output (no
/// `placed<>` from `at<>`, no `cmp_channel_tag<>`, and no verifiable/extractable).
template <typename ...Elems>
inline constexpr bool is_classic_pack_v =
!((is_placed_v<Elems> || is_cmp_channel_tag_v<Elems>) || ...);
!((is_placed_v<Elems> || is_cmp_channel_tag_v<Elems>
|| is_verifiable_tag_v<Elems> || is_extractable_tag_v<Elems>) || ...);
} // namespace incr
} // namespace detail
/// Sparse heavy-hitters IDPF. Slot `i` is the point function on prefix
/// @brief Sparse heavy-hitters IDPF. Slot `i` is the point function on prefix
/// `Levels[i]`, evaluated with `out<i>`.
/// @tparam Levels levels
/// @tparam Betas betas
/// @param betas the `betas`
/// @return Sparse heavy-hitters IDPF
template <std::size_t ...Levels, typename ...Betas>
auto idpf_at(Betas ...betas)
{
@ -500,7 +588,10 @@ auto idpf_from_seq(std::index_sequence<I...>, Betas ...betas)
return idpf_at<(I + 1)...>(std::move(betas)...);
}
/// Consecutive prefixes of length 1, 2, …, `sizeof...(Betas)`.
/// @brief Consecutive prefixes of length 1, 2, …, `sizeof...(Betas)`.
/// @tparam Betas betas
/// @param betas the `betas`
/// @return Consecutive prefixes of length 1, 2, …, `sizeof...(Betas)`
template <typename ...Betas>
auto idpf(Betas ...betas)
{