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:
parent
0d8a5a8131
commit
0dff6df8ed
250 changed files with 12199 additions and 1981 deletions
|
|
@ -22,6 +22,7 @@
|
|||
#include "dpf/bit.hpp"
|
||||
#include "dpf/xor_wrapper.hpp"
|
||||
#include "dpf/twiddle.hpp"
|
||||
#include "dpf/cmp_group.hpp"
|
||||
|
||||
namespace dpf
|
||||
{
|
||||
|
|
@ -39,8 +40,8 @@ template <typename ...Ts>
|
|||
inline constexpr bool no_ic_pack_v =
|
||||
(!is_ic_pack<std::decay_t<Ts>>::value && ...);
|
||||
|
||||
/// Comparison kind for the optional DCF channel on a key.
|
||||
/// `lt`/`leq`/`gt`/`geq` are the comparison predicates. The later kinds are
|
||||
/// @brief Comparison kind for the optional DCF channel on a key.
|
||||
/// @details `lt`/`leq`/`gt`/`geq` are the comparison predicates. The later kinds are
|
||||
/// path paints: one constant on each sibling subtree of the secret point,
|
||||
/// evaluated by the same value-correction walk.
|
||||
enum class cmp_kind : uint8_t
|
||||
|
|
@ -58,7 +59,9 @@ enum class cmp_kind : uint8_t
|
|||
paint = 10 // caller-supplied unit plant
|
||||
};
|
||||
|
||||
/// True for the path-paint kinds. Comparisons stay `lt`/`leq`/`gt`/`geq`.
|
||||
/// @brief True for the path-paint kinds. Comparisons stay `lt`/`leq`/`gt`/`geq`.
|
||||
/// @param kind the comparison or paint kind
|
||||
/// @return True for the path-paint kinds
|
||||
HEDLEY_NO_THROW
|
||||
inline constexpr bool is_paint_kind(cmp_kind kind) noexcept
|
||||
{
|
||||
|
|
@ -77,7 +80,7 @@ inline constexpr bool is_paint_kind(cmp_kind kind) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
/// Unit plant for `path_paint`. `prefix` is the in-lane matched prefix.
|
||||
/// @brief Unit plant for `path_paint`. `prefix` is the in-lane matched prefix.
|
||||
using paint_callback = uint64_t (*)(std::size_t matched, uint64_t prefix,
|
||||
bool leaf, const void * ctx);
|
||||
|
||||
|
|
@ -119,6 +122,16 @@ uint64_t beta_delta_u64(const Beta & if_true, const Beta & if_false,
|
|||
return (static_cast<uint64_t>(if_true) ^ static_cast<uint64_t>(if_false))
|
||||
& mask;
|
||||
}
|
||||
else if constexpr (detail::has_integral_representation<Beta>::value)
|
||||
{
|
||||
using raw_type = typename Beta::integral_type;
|
||||
using unsigned_type = utils::make_unsigned_t<raw_type>;
|
||||
const auto t = static_cast<uint64_t>(
|
||||
static_cast<unsigned_type>(if_true.integral_representation()));
|
||||
const auto f = static_cast<uint64_t>(
|
||||
static_cast<unsigned_type>(if_false.integral_representation()));
|
||||
return (t - f) & mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (static_cast<uint64_t>(if_true)
|
||||
|
|
@ -132,6 +145,13 @@ uint64_t beta_to_u64_simple(const Beta & beta, uint64_t mask) noexcept
|
|||
{
|
||||
if constexpr (std::is_same_v<Beta, dpf::bit>)
|
||||
return (static_cast<bool>(beta) ? 1ULL : 0ULL) & mask;
|
||||
else if constexpr (detail::has_integral_representation<Beta>::value)
|
||||
{
|
||||
using raw_type = typename Beta::integral_type;
|
||||
using unsigned_type = utils::make_unsigned_t<raw_type>;
|
||||
return static_cast<uint64_t>(static_cast<unsigned_type>(
|
||||
beta.integral_representation())) & mask;
|
||||
}
|
||||
else
|
||||
return static_cast<uint64_t>(beta) & mask;
|
||||
}
|
||||
|
|
@ -154,6 +174,8 @@ Beta u64_to_beta(uint64_t v) noexcept
|
|||
{
|
||||
if constexpr (std::is_same_v<Beta, dpf::bit>)
|
||||
return dpf::bit{static_cast<bool>(v & 1u)};
|
||||
else if constexpr (detail::has_integral_representation<Beta>::value)
|
||||
return Beta::from_raw(static_cast<typename Beta::integral_type>(v));
|
||||
else
|
||||
return static_cast<Beta>(v);
|
||||
}
|
||||
|
|
@ -186,7 +208,10 @@ constexpr uint64_t sgn_m(uint8_t t1, uint64_t x, uint64_t mask) noexcept
|
|||
return t1 ? neg_m(x, mask) : x;
|
||||
}
|
||||
|
||||
/// Convert a GGM node to a group element (low 64 bits, control bits cleared).
|
||||
/// @brief Convert a GGM node to a group element (low 64 bits, control bits cleared).
|
||||
/// @param n the `n`
|
||||
/// @param mask the bit mask
|
||||
/// @return the returned `uint64_t`
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
uint64_t convert_node(simde__m128i n, uint64_t mask) noexcept
|
||||
{
|
||||
|
|
@ -194,11 +219,15 @@ uint64_t convert_node(simde__m128i n, uint64_t mask) noexcept
|
|||
simde_mm_cvtsi128_si64(dpf::unset_lo_2bits(n))) & mask;
|
||||
}
|
||||
|
||||
/// Draw the group-width blind `r` used to split the `cmp_addend` share.
|
||||
/// `sample` yields one interior block; only `popcount(mask)` live bits are
|
||||
/// @brief Draw the group-width blind `r` used to split the `cmp_addend` share.
|
||||
/// @details `sample` yields one interior block; only `popcount(mask)` live bits are
|
||||
/// kept, so the blind (and thus the addend share) never needs a full padded
|
||||
/// `uint64_t` on the wire. Dealer and Doerner–Shelat gen call this with the
|
||||
/// same block source so their keys stay byte-identical (matched tapes).
|
||||
/// @tparam BlockSampler block sampler
|
||||
/// @param mask the bit mask
|
||||
/// @param sample the `sample`
|
||||
/// @return the returned `uint64_t`
|
||||
template <typename BlockSampler>
|
||||
HEDLEY_ALWAYS_INLINE
|
||||
HEDLEY_NO_THROW
|
||||
|
|
@ -207,8 +236,19 @@ uint64_t sample_addend_blind(uint64_t mask, BlockSampler && sample) noexcept
|
|||
return convert_node(dpf::unset_lo_2bits(sample()), mask);
|
||||
}
|
||||
|
||||
/// One level of value CW on GGM children. Updates running `Va`.
|
||||
/// `ai` is the keep-path bit of the (effective) threshold.
|
||||
/// @brief One level of value CW on GGM children. Updates running `Va`.
|
||||
/// @details `ai` is the keep-path bit of the (effective) threshold.
|
||||
/// @param c0L the `c0L`
|
||||
/// @param c0R the `c0R`
|
||||
/// @param c1L the `c1L`
|
||||
/// @param c1R the `c1R`
|
||||
/// @param t0 the `t0`
|
||||
/// @param t1 the `t1`
|
||||
/// @param ai the `ai`
|
||||
/// @param Va the `Va`
|
||||
/// @param beta the payload
|
||||
/// @param mask the bit mask
|
||||
/// @return One level of value CW on GGM children
|
||||
HEDLEY_NO_THROW
|
||||
inline uint64_t make_value_cw(simde__m128i c0L, simde__m128i c0R,
|
||||
simde__m128i c1L, simde__m128i c1R, uint8_t t0, uint8_t t1, int ai,
|
||||
|
|
@ -239,8 +279,20 @@ inline uint64_t make_value_cw(simde__m128i c0L, simde__m128i c0R,
|
|||
return vcw;
|
||||
}
|
||||
|
||||
/// Same recurrence as `make_value_cw`, planting `plant` on the lose child
|
||||
/// @brief Same recurrence as `make_value_cw`, planting `plant` on the lose child
|
||||
/// in both directions. `plant == 0` leaves the correction unchanged.
|
||||
/// @param c0L the `c0L`
|
||||
/// @param c0R the `c0R`
|
||||
/// @param c1L the `c1L`
|
||||
/// @param c1R the `c1R`
|
||||
/// @param t0 the `t0`
|
||||
/// @param t1 the `t1`
|
||||
/// @param ai the `ai`
|
||||
/// @param Va the `Va`
|
||||
/// @param plant the unit plant
|
||||
/// @param mask the bit mask
|
||||
/// @return Same recurrence as `make_value_cw`, planting `plant` on the lose child in both
|
||||
/// directions
|
||||
HEDLEY_NO_THROW
|
||||
inline uint64_t make_value_cw_planted(simde__m128i c0L, simde__m128i c0R,
|
||||
simde__m128i c1L, simde__m128i c1R, uint8_t t0, uint8_t t1, int ai,
|
||||
|
|
@ -280,7 +332,11 @@ inline unsigned __int128 paint_lane_mask(std::size_t nbits) noexcept
|
|||
return (u128{1} << nbits) - 1;
|
||||
}
|
||||
|
||||
/// High `d` bits of an `nbits`-wide lane, in that lane's own positions.
|
||||
/// @brief High `d` bits of an `nbits`-wide lane, in that lane's own positions.
|
||||
/// @param alpha the secret input point
|
||||
/// @param nbits the width in bits
|
||||
/// @param d the `d`
|
||||
/// @return High `d` bits of an `nbits`-wide lane, in that lane's own positions
|
||||
HEDLEY_NO_THROW
|
||||
inline unsigned __int128 paint_high_bits(unsigned __int128 alpha,
|
||||
std::size_t nbits, std::size_t d) noexcept
|
||||
|
|
@ -306,9 +362,18 @@ inline unsigned __int128 paint_low_aligned(unsigned __int128 alpha,
|
|||
return alpha >> (nbits - d);
|
||||
}
|
||||
|
||||
/// Unit (β = 1) lose-subtree or leaf plant. The caller scales by δ.
|
||||
/// `matched` is the number of leading bits already shared with α. A lose
|
||||
/// @brief Unit (β = 1) lose-subtree or leaf plant. The caller scales by δ.
|
||||
/// @details `matched` is the number of leading bits already shared with α. A lose
|
||||
/// subtree at that depth reconstructs to this value; `leaf` is the full match.
|
||||
/// @param kind the comparison or paint kind
|
||||
/// @param matched the number of leading bits shared with the secret point
|
||||
/// @param alpha the secret input point
|
||||
/// @param nbits the width in bits
|
||||
/// @param length_bits the bits used to store the prefix length
|
||||
/// @param leaf the leaf value
|
||||
/// @param fn the `fn`
|
||||
/// @param ctx the `ctx`
|
||||
/// @return Unit (β = 1) lose-subtree or leaf plant
|
||||
inline uint64_t paint_unit(cmp_kind kind, std::size_t matched,
|
||||
unsigned __int128 alpha, std::size_t nbits, std::size_t length_bits,
|
||||
bool leaf, paint_callback fn, const void * ctx)
|
||||
|
|
@ -357,8 +422,15 @@ inline uint64_t scale_plant(uint64_t unit, uint64_t scale, uint64_t mask) noexce
|
|||
return (unit * scale) & mask;
|
||||
}
|
||||
|
||||
/// Final leaf value CW. `on_path` is the payload reconstructed when the query
|
||||
/// @brief Final leaf value CW. `on_path` is the payload reconstructed when the query
|
||||
/// stays on α's path through all levels (0 for strict lt/geq; β for leq/gt).
|
||||
/// @param s0 the `s0`
|
||||
/// @param s1 the `s1`
|
||||
/// @param t1 the `t1`
|
||||
/// @param Va the `Va`
|
||||
/// @param mask the bit mask
|
||||
/// @param on_path the value reconstructed on the secret path
|
||||
/// @return Final leaf value CW
|
||||
HEDLEY_NO_THROW
|
||||
inline uint64_t make_final_cw(simde__m128i s0, simde__m128i s1, uint8_t t1,
|
||||
uint64_t Va, uint64_t mask, uint64_t on_path = 0) noexcept
|
||||
|
|
@ -371,8 +443,8 @@ inline uint64_t make_final_cw(simde__m128i s0, simde__m128i s1, uint8_t t1,
|
|||
|
||||
} // namespace dcf_impl
|
||||
|
||||
/// Comparison metadata on an incremental key (value CWs live on the key).
|
||||
/// Payload δ = if_true − if_false is dealer-known and baked into `value_cw` /
|
||||
/// @brief Comparison metadata on an incremental key (value CWs live on the key).
|
||||
/// @details Payload δ = if_true − if_false is dealer-known and baked into `value_cw` /
|
||||
/// `cw_last` only — never stored clear on the key (traditional DPF hiding).
|
||||
/// The second output value (`if_false`) is held as a per-party additive share
|
||||
/// on the key (`cmp_addend`), not as a public constant.
|
||||
|
|
@ -393,7 +465,7 @@ struct cmp_meta
|
|||
bool empty() const noexcept { return !active; }
|
||||
};
|
||||
|
||||
/// Backward-compatible alias while call sites migrate.
|
||||
/// @brief Backward-compatible alias while call sites migrate.
|
||||
using cmp_channel = cmp_meta;
|
||||
|
||||
} // namespace detail
|
||||
|
|
@ -591,8 +663,13 @@ inline auto break_bit_at(Beta t = Beta{1},
|
|||
return paint_at_pack<N, cmp_kind::break_bit, Beta>(std::move(t), std::move(f));
|
||||
}
|
||||
|
||||
/// Low `LengthBits` hold the common-prefix length. Above them sits the
|
||||
/// @brief Low `LengthBits` hold the common-prefix length. Above them sits the
|
||||
/// matched prefix packed into the low bits of the lane (`α >> (N − d)`).
|
||||
/// @tparam LengthBits length bits
|
||||
/// @tparam Beta payload type
|
||||
/// @param t the `t`
|
||||
/// @param f the `f`
|
||||
/// @return Low `LengthBits` hold the common-prefix length
|
||||
template <std::size_t LengthBits = 8, typename Beta = uint64_t>
|
||||
inline auto prefix_with_length(Beta t = Beta{1},
|
||||
Beta f = detail::dcf_impl::default_false<Beta>())
|
||||
|
|
@ -608,9 +685,11 @@ inline auto prefix_with_length_at(Beta t = Beta{1},
|
|||
std::move(t), std::move(f));
|
||||
}
|
||||
|
||||
/// Arbitrary unit plant. `fn(matched, in_lane_prefix, leaf)` returns the β = 1
|
||||
/// @brief Arbitrary unit plant. `fn(matched, in_lane_prefix, leaf)` returns the β = 1
|
||||
/// value of that sibling subtree (`leaf` is the full match, `matched == N`).
|
||||
/// The result is scaled by `if_true − if_false` like the canned recipes.
|
||||
/// @details The result is scaled by `if_true − if_false` like the canned recipes.
|
||||
/// @tparam Beta payload type
|
||||
/// @tparam Fn fn
|
||||
template <typename Beta, typename Fn>
|
||||
struct paint_fn_pack
|
||||
{
|
||||
|
|
@ -667,8 +746,9 @@ inline auto path_paint_at(Fn fn, Beta t,
|
|||
std::move(t), std::move(f), std::move(fn));
|
||||
}
|
||||
|
||||
/// Incremental comparison: the same predicate, correct at every prefix length.
|
||||
/// Evaluate the full point with `cmp`, and a prefix with `cmp_prefix<L>`.
|
||||
/// @brief Incremental comparison: the same predicate, correct at every prefix length.
|
||||
/// @details Evaluate the full point with `cmp`, and a prefix with `cmp_prefix<L>`.
|
||||
/// @tparam Spec comparison or interval specification
|
||||
template <typename Spec>
|
||||
struct idcf_pack
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue