Annotate noexcept and constexpr with HEDLEY, and add interval containment, ChaCha, and the dyadic range tables.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-24 20:44:07 -06:00
parent 875f09fec1
commit 0d8a5a8131
97 changed files with 9212 additions and 1159 deletions

View file

@ -10,10 +10,10 @@
/// nodes are identical across the two parties, so a dummy word
/// cancels.
///
/// A wildcard-input call takes additive shares of the real point and
/// a public query. It samples a random target, runs geneval there,
/// and shifts the query by `target - x`, which is what
/// `offset_x` does after a wildcard key is bound to `x`.
/// Default calls take XOR shares of the point. Tagged with
/// `arith_input`, the point is the ring sum of the two shares; path
/// bits are opened by a carry chain inside the local CW protocol so
/// the words match `make_dpf(x0 + x1)` at the caller's query.
///
/// `geneval_cmp` is the comparison-channel form. The value-correction
/// word is a function of the secret path at every level, so the walk
@ -50,13 +50,6 @@
namespace dpf
{
/// Tag for a geneval whose point is known only as additive shares.
struct wildcard_input_t
{
};
inline constexpr wildcard_input_t wildcard_input{};
/// Shares and the correction words opened along the query trie.
/// `correction_words[i]` / `correction_advice[i]` match a reusable key at
/// the same target for every `i < live_levels`. `leaf_live` means the
@ -78,6 +71,7 @@ namespace detail
template <typename T>
HEDLEY_ALWAYS_INLINE
HEDLEY_NO_THROW
T geneval_mod_add(T a, T b) noexcept
{
using U = std::make_unsigned_t<T>;
@ -87,17 +81,6 @@ T geneval_mod_add(T a, T b) noexcept
return out;
}
template <typename T>
HEDLEY_ALWAYS_INLINE
T geneval_mod_sub(T a, T b) noexcept
{
using U = std::make_unsigned_t<T>;
U diff = static_cast<U>(static_cast<U>(a) - static_cast<U>(b));
T out;
std::memcpy(&out, &diff, sizeof(out));
return out;
}
template <typename T>
T geneval_flipped(T x)
{
@ -151,8 +134,9 @@ template <typename InteriorPRG,
typename OutputT,
typename RootSampler,
typename PadRng>
auto geneval_run(InputT x0, InputT x1, const std::vector<InputT> & queries,
RootSampler & root_sampler, PadRng & pads, OutputT y)
auto geneval_run(bool arith, InputT x0, InputT x1,
const std::vector<InputT> & queries, RootSampler & root_sampler,
PadRng & pads, OutputT y)
{
static_assert(std::is_integral_v<InputT>,
"geneval input shares are an integral domain");
@ -172,9 +156,10 @@ auto geneval_run(InputT x0, InputT x1, const std::vector<InputT> & queries,
if (queries.size() > (std::size_t{1} << 22))
throw std::length_error("geneval query is too large");
local_cw_protocol<PadRng> proto{pads};
InputT x0c = x0;
InputT x1c = x1;
utils::flip_msb_if_signed_integral(x0c);
proto.encode_walk_shares(x0c, x1c, arith);
const InputT alpha = utils::xor_input_shares(x0c, x1c);
std::vector<InputT> flipped;
@ -196,7 +181,6 @@ auto geneval_run(InputT x0, InputT x1, const std::vector<InputT> & queries,
const uint64_t secret_leaf = geneval_leaf_id<dpf_type>(alpha);
local_cw_protocol<PadRng> proto{pads};
constexpr auto to_int = utils::to_integral_type<InputT>{};
const node root0 = dpf::unset_lo_bit(static_cast<node>(root_sampler()));
@ -342,6 +326,19 @@ auto geneval_run(InputT x0, InputT x1, const std::vector<InputT> & queries,
return result;
}
template <typename InteriorPRG,
typename ExteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng>
auto geneval_run(InputT x0, InputT x1, const std::vector<InputT> & queries,
RootSampler & root_sampler, PadRng & pads, OutputT y)
{
return geneval_run<InteriorPRG, ExteriorPRG>(false, x0, x1, queries,
root_sampler, pads, y);
}
template <typename InputT>
InputT geneval_from_bits(uint64_t bits)
{
@ -401,22 +398,6 @@ std::vector<InputT> geneval_inclusive(InputT from, InputT to)
return qs;
}
template <typename InputT, typename TargetSampler>
InputT geneval_sample_target(TargetSampler & sample)
{
return static_cast<InputT>(sample());
}
template <typename InputT>
std::vector<InputT> geneval_shift_all(const std::vector<InputT> & qs, InputT delta)
{
std::vector<InputT> out;
out.reserve(qs.size());
for (const InputT & q : qs)
out.push_back(geneval_mod_add(q, delta));
return out;
}
} // namespace detail
/// Geneval at one public point. The secret point is `x0 XOR x1`.
@ -430,7 +411,22 @@ HEDLEY_WARN_UNUSED_RESULT
auto geneval_point(InputT x0, InputT x1, InputT query,
ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return detail::geneval_run<InteriorPRG, ExteriorPRG>(x0, x1,
return detail::geneval_run<InteriorPRG, ExteriorPRG>(false, x0, x1,
std::vector<InputT>{query}, rng.root, rng.pad, y);
}
/// Geneval at one public point. The secret point is `x0 + x1`.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_point(arith_input_t, InputT x0, InputT x1, InputT query,
ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return detail::geneval_run<InteriorPRG, ExteriorPRG>(true, x0, x1,
std::vector<InputT>{query}, rng.root, rng.pad, y);
}
@ -445,7 +441,21 @@ HEDLEY_WARN_UNUSED_RESULT
auto geneval_interval(InputT x0, InputT x1, InputT from, InputT to,
ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return detail::geneval_run<InteriorPRG, ExteriorPRG>(x0, x1,
return detail::geneval_run<InteriorPRG, ExteriorPRG>(false, x0, x1,
detail::geneval_inclusive(from, to), rng.root, rng.pad, y);
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_interval(arith_input_t, InputT x0, InputT x1, InputT from,
InputT to, ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return detail::geneval_run<InteriorPRG, ExteriorPRG>(true, x0, x1,
detail::geneval_inclusive(from, to), rng.root, rng.pad, y);
}
@ -460,7 +470,21 @@ HEDLEY_WARN_UNUSED_RESULT
auto geneval_full(InputT x0, InputT x1,
ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return detail::geneval_run<InteriorPRG, ExteriorPRG>(x0, x1,
return detail::geneval_run<InteriorPRG, ExteriorPRG>(false, x0, x1,
detail::geneval_full_domain<InputT>(), rng.root, rng.pad, y);
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_full(arith_input_t, InputT x0, InputT x1,
ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return detail::geneval_run<InteriorPRG, ExteriorPRG>(true, x0, x1,
detail::geneval_full_domain<InputT>(), rng.root, rng.pad, y);
}
@ -477,154 +501,10 @@ auto geneval_sequence(InputT x0, InputT x1, ForwardIterator begin,
ForwardIterator end, ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
std::vector<InputT> qs(begin, end);
return detail::geneval_run<InteriorPRG, ExteriorPRG>(x0, x1,
return detail::geneval_run<InteriorPRG, ExteriorPRG>(false, x0, x1,
std::move(qs), rng.root, rng.pad, y);
}
/// Wildcard-input geneval. `x0 + x1` is the real point (additive shares).
/// `sample_target()` is the random DPF target; the public query is shifted
/// by `target - (x0 + x1)` before the walk.
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng,
typename TargetSampler>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_point(wildcard_input_t, InputT x0, InputT x1, InputT query,
ds_randomness<RootSampler, PadRng> rng, TargetSampler sample_target,
OutputT y)
{
const InputT alpha = detail::geneval_sample_target<InputT>(sample_target);
const InputT delta = detail::geneval_mod_sub(alpha,
detail::geneval_mod_add(x0, x1));
const InputT shifted = detail::geneval_mod_add(query, delta);
InputT zero{};
return detail::geneval_run<InteriorPRG, ExteriorPRG>(zero, alpha,
std::vector<InputT>{shifted}, rng.root, rng.pad, y);
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_point(wildcard_input_t, InputT x0, InputT x1, InputT query,
ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return geneval_point<InteriorPRG, ExteriorPRG>(wildcard_input, x0, x1, query,
std::move(rng), [] { return dpf::uniform_sample<InputT>(); }, y);
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng,
typename TargetSampler>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_interval(wildcard_input_t, InputT x0, InputT x1, InputT from,
InputT to, ds_randomness<RootSampler, PadRng> rng, TargetSampler sample_target,
OutputT y)
{
const InputT alpha = detail::geneval_sample_target<InputT>(sample_target);
const InputT delta = detail::geneval_mod_sub(alpha,
detail::geneval_mod_add(x0, x1));
auto shifted = detail::geneval_shift_all(
detail::geneval_inclusive(from, to), delta);
InputT zero{};
return detail::geneval_run<InteriorPRG, ExteriorPRG>(zero, alpha,
std::move(shifted), rng.root, rng.pad, y);
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_interval(wildcard_input_t, InputT x0, InputT x1, InputT from,
InputT to, ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return geneval_interval<InteriorPRG, ExteriorPRG>(wildcard_input, x0, x1,
from, to, std::move(rng), [] { return dpf::uniform_sample<InputT>(); }, y);
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng,
typename TargetSampler>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_full(wildcard_input_t, InputT x0, InputT x1,
ds_randomness<RootSampler, PadRng> rng, TargetSampler sample_target, OutputT y)
{
const InputT alpha = detail::geneval_sample_target<InputT>(sample_target);
const InputT delta = detail::geneval_mod_sub(alpha,
detail::geneval_mod_add(x0, x1));
InputT zero{};
auto full = detail::geneval_run<InteriorPRG, ExteriorPRG>(zero, alpha,
detail::geneval_full_domain<InputT>(), rng.root, rng.pad, y);
constexpr auto to_int = utils::to_integral_type<InputT>{};
const std::size_t n = full.party0.size();
std::vector<OutputT> p0(n), p1(n);
for (std::size_t i = 0; i < n; ++i)
{
InputT q = detail::geneval_from_bits<InputT>(i);
InputT s = detail::geneval_mod_add(q, delta);
const std::size_t si = static_cast<std::size_t>(to_int(s));
p0[i] = full.party0[si];
p1[i] = full.party1[si];
}
full.party0 = std::move(p0);
full.party1 = std::move(p1);
return full;
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_full(wildcard_input_t, InputT x0, InputT x1,
ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return geneval_full<InteriorPRG, ExteriorPRG>(wildcard_input, x0, x1,
std::move(rng), [] { return dpf::uniform_sample<InputT>(); }, y);
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
typename OutputT,
typename RootSampler,
typename PadRng,
typename ForwardIterator,
typename TargetSampler>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_sequence(wildcard_input_t, InputT x0, InputT x1,
ForwardIterator begin, ForwardIterator end,
ds_randomness<RootSampler, PadRng> rng, TargetSampler sample_target, OutputT y)
{
const InputT alpha = detail::geneval_sample_target<InputT>(sample_target);
const InputT delta = detail::geneval_mod_sub(alpha,
detail::geneval_mod_add(x0, x1));
std::vector<InputT> qs(begin, end);
auto shifted = detail::geneval_shift_all(qs, delta);
InputT zero{};
return detail::geneval_run<InteriorPRG, ExteriorPRG>(zero, alpha,
std::move(shifted), rng.root, rng.pad, y);
}
template <typename InteriorPRG = dpf::prg::aes128,
typename ExteriorPRG = InteriorPRG,
typename InputT,
@ -633,12 +513,13 @@ template <typename InteriorPRG = dpf::prg::aes128,
typename PadRng,
typename ForwardIterator>
HEDLEY_WARN_UNUSED_RESULT
auto geneval_sequence(wildcard_input_t, InputT x0, InputT x1,
auto geneval_sequence(arith_input_t, InputT x0, InputT x1,
ForwardIterator begin, ForwardIterator end,
ds_randomness<RootSampler, PadRng> rng, OutputT y)
{
return geneval_sequence<InteriorPRG, ExteriorPRG>(wildcard_input, x0, x1,
begin, end, std::move(rng), [] { return dpf::uniform_sample<InputT>(); }, y);
std::vector<InputT> qs(begin, end);
return detail::geneval_run<InteriorPRG, ExteriorPRG>(true, x0, x1,
std::move(qs), rng.root, rng.pad, y);
}
/// Opened comparison key material and one prefix share per endpoint.
@ -651,6 +532,7 @@ struct geneval_cmp_result
std::vector<simde__m128i, aligned_allocator<simde__m128i>> correction_words;
std::vector<uint8_t> correction_advice;
std::vector<uint64_t> value_cw;
std::vector<uint64_t> tail_cw;
uint64_t cw_last = 0;
uint64_t addend0 = 0;
uint64_t addend1 = 0;
@ -689,12 +571,77 @@ geneval_cmp_result geneval_cmp(InputT x0, InputT x1,
out.addend1 = k1.cmp_addend().raw();
out.correction_words.resize(depth);
out.correction_advice.resize(depth);
out.value_cw.resize(depth);
if constexpr (key_type::cmp_block > 0)
{
out.value_cw.resize(key_type::cmp_checkpoints);
for (std::size_t i = 0; i < key_type::cmp_checkpoints; ++i)
out.value_cw[i] = k0.value_cw(i);
out.tail_cw.resize(key_type::cmp_tail);
for (std::size_t z = 0; z < key_type::cmp_tail; ++z)
out.tail_cw[z] = k0.tail_cw(z);
}
else
out.value_cw.resize(depth);
for (std::size_t level = 0; level < depth; ++level)
{
out.correction_words[level] = k0.correction_word(level);
out.correction_advice[level] = static_cast<uint8_t>(k0.correction_advice(level));
out.value_cw[level] = k0.value_cw(level);
if constexpr (key_type::cmp_block == 0)
out.value_cw[level] = k0.value_cw(level);
}
for (auto it = begin; it != end; ++it)
{
out.party0.push_back(eval_point(dpf::cmp, k0, *it).raw());
out.party1.push_back(eval_point(dpf::cmp, k1, *it).raw());
}
return out;
}
/// Comparison geneval with additive shares of the point (`x0 + x1`).
template <typename InputT,
typename ForwardIterator,
typename RootSampler,
typename PadRng,
typename Spec>
HEDLEY_WARN_UNUSED_RESULT
geneval_cmp_result geneval_cmp(arith_input_t, InputT x0, InputT x1,
ForwardIterator begin, ForwardIterator end,
ds_randomness<RootSampler, PadRng> rng, Spec spec)
{
geneval_cmp_result out;
if (begin == end)
return out;
auto keys = make_dpf_doerner_shelat(arith_input, std::move(x0), std::move(x1),
std::move(rng), std::move(spec));
const auto & k0 = keys.first;
const auto & k1 = keys.second;
using key_type = std::decay_t<decltype(k0)>;
constexpr std::size_t depth = key_type::depth;
out.live_levels = depth;
out.mask = k0.cmp().mask;
out.cw_last = k0.cw_last();
out.addend0 = k0.cmp_addend().raw();
out.addend1 = k1.cmp_addend().raw();
out.correction_words.resize(depth);
out.correction_advice.resize(depth);
if constexpr (key_type::cmp_block > 0)
{
out.value_cw.resize(key_type::cmp_checkpoints);
for (std::size_t i = 0; i < key_type::cmp_checkpoints; ++i)
out.value_cw[i] = k0.value_cw(i);
out.tail_cw.resize(key_type::cmp_tail);
for (std::size_t z = 0; z < key_type::cmp_tail; ++z)
out.tail_cw[z] = k0.tail_cw(z);
}
else
out.value_cw.resize(depth);
for (std::size_t level = 0; level < depth; ++level)
{
out.correction_words[level] = k0.correction_word(level);
out.correction_advice[level] = static_cast<uint8_t>(k0.correction_advice(level));
if constexpr (key_type::cmp_block == 0)
out.value_cw[level] = k0.value_cw(level);
}
for (auto it = begin; it != end; ++it)
{
@ -718,6 +665,19 @@ geneval_cmp_result geneval_cmp(InputT x0, InputT x1,
std::move(rng), dpf::gt(beta));
}
template <typename InputT,
typename ForwardIterator,
typename RootSampler,
typename PadRng>
HEDLEY_WARN_UNUSED_RESULT
geneval_cmp_result geneval_cmp(arith_input_t, InputT x0, InputT x1,
ForwardIterator begin, ForwardIterator end,
ds_randomness<RootSampler, PadRng> rng, uint64_t beta)
{
return geneval_cmp(arith_input, std::move(x0), std::move(x1), begin, end,
std::move(rng), dpf::gt(beta));
}
} // namespace dpf
#endif // LIBDPF_INCLUDE_DPF_GENEVAL_HPP__