#include #include #include #include "dpf.hpp" /// A sorted point list. `return_output_only_tag_` stores one share per point. /// A `sequence_recipe` compiled from that list is reusable across keys. int main() { const std::uint8_t alpha = 42; const std::uint64_t beta = 7; auto [k0, k1] = dpf::make_dpf(alpha, beta); using key_t = dpf::unwrap_party_key_t>; //! [eval-sequence] // Nondecreasing. An unsorted range throws std::runtime_error. std::array points{1, 7, 42, 100, 200}; auto [buf0, iter0] = dpf::eval_sequence(k0, points.begin(), points.end(), dpf::return_output_only_tag_{}); auto [buf1, iter1] = dpf::eval_sequence(k1, points.begin(), points.end(), dpf::return_output_only_tag_{}); auto it0 = std::begin(iter0); auto it1 = std::begin(iter1); for (std::uint8_t x : points) { std::uint64_t got = dpf::reconstruct(*it0, *it1); std::uint64_t expect = (x == alpha) ? beta : 0; if (got != expect) { std::cerr << "eval_sequence\n"; return 1; } ++it0; ++it1; } //! [eval-sequence] //! [eval-sequence-recipe] // The recipe is a property of the point list and the key's input type. // Bind the memoizer to this recipe object and pass that same object back. auto recipe = dpf::make_sequence_recipe(points.begin(), points.end()); auto memo0 = dpf::make_double_space_sequence_memoizer(recipe); auto memo1 = dpf::make_double_space_sequence_memoizer(recipe); auto sbuf0 = dpf::make_output_buffer_for_recipe_subsequence(k0, recipe, dpf::return_output_only_tag_{}); auto sbuf1 = dpf::make_output_buffer_for_recipe_subsequence(k1, recipe, dpf::return_output_only_tag_{}); auto seq0 = dpf::eval_sequence(k0, recipe, sbuf0, memo0, dpf::return_output_only_tag_{}); auto seq1 = dpf::eval_sequence(k1, recipe, sbuf1, memo1, dpf::return_output_only_tag_{}); //! [eval-sequence-recipe] // Omitting the memoizer allocates a double-space workspace for that call. seq0 = dpf::eval_sequence(k0, recipe, sbuf0, dpf::return_output_only_tag_{}); seq1 = dpf::eval_sequence(k1, recipe, sbuf1, dpf::return_output_only_tag_{}); it0 = std::begin(seq0); it1 = std::begin(seq1); for (std::uint8_t x : points) { if (dpf::reconstruct(*it0, *it1) != ((x == alpha) ? beta : 0)) { std::cerr << "eval_sequence recipe, default memoizer\n"; return 1; } ++it0; ++it1; } seq0 = dpf::eval_sequence(k0, recipe, sbuf0, memo0, dpf::return_output_only_tag_{}); seq1 = dpf::eval_sequence(k1, recipe, sbuf1, memo1, dpf::return_output_only_tag_{}); it0 = std::begin(seq0); it1 = std::begin(seq1); for (std::uint8_t x : points) { std::uint64_t got = dpf::reconstruct(*it0, *it1); std::uint64_t expect = (x == alpha) ? beta : 0; if (got != expect) { std::cerr << "eval_sequence recipe\n"; return 1; } ++it0; ++it1; } // Same recipe, same memoizers, same buffers: a second key overwrites them. auto [k0b, k1b] = dpf::make_dpf(std::uint8_t{100}, std::uint64_t{9}); seq0 = dpf::eval_sequence(k0b, recipe, sbuf0, memo0, dpf::return_output_only_tag_{}); seq1 = dpf::eval_sequence(k1b, recipe, sbuf1, memo1, dpf::return_output_only_tag_{}); it0 = std::begin(seq0); it1 = std::begin(seq1); for (std::uint8_t x : points) { std::uint64_t got = dpf::reconstruct(*it0, *it1); std::uint64_t expect = (x == 100) ? 9 : 0; if (got != expect) { std::cerr << "eval_sequence recipe reuse\n"; return 1; } ++it0; ++it1; } std::cout << beta << "\n"; (void)buf0; (void)buf1; return 0; }