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:
parent
875f09fec1
commit
0d8a5a8131
97 changed files with 9212 additions and 1159 deletions
|
|
@ -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__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue