Initial import of libdpf.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-24 14:08:32 -06:00
commit e4e666f459
4563 changed files with 1690372 additions and 0 deletions

View file

@ -0,0 +1,170 @@
// Regression checks for the eval / memoizer / output-buffer audit fixes.
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <limits>
#include <vector>
#include "dpf.hpp"
static int fails = 0;
static void expect(bool ok, const char *what)
{
if (!ok)
{
std::fprintf(stderr, "FAIL: %s\n", what);
++fails;
}
}
static void test_wrap_interval()
{
using input_t = uint8_t;
using output_t = uint64_t;
const input_t alpha = 252;
const output_t beta = 0x1234567890abcdefULL;
auto [k0, k1] = dpf::make_dpf(input_t{alpha}, output_t{beta});
const input_t from = 250;
const input_t to = 5;
auto [buf0, it0] = dpf::eval_interval(k0, from, to);
auto [buf1, it1] = dpf::eval_interval(k1, from, to);
auto z0 = std::begin(it0);
auto z1 = std::begin(it1);
int seen = 0;
for (int step = 0; step < 16; ++step, ++z0, ++z1)
{
const input_t x = static_cast<input_t>(from + step);
if (z0 == std::end(it0))
break;
const auto p0 = dpf::eval_point(k0, x);
const auto p1 = dpf::eval_point(k1, x);
const output_t interval = static_cast<output_t>(*z1) - static_cast<output_t>(*z0);
const output_t point = static_cast<output_t>(*p1) - static_cast<output_t>(*p0);
const output_t want = (x == alpha) ? beta : output_t{0};
expect(interval == point && interval == want, "wrap interval matches point");
++seen;
}
expect(z0 == std::end(it0), "wrap iterable consumed");
expect(seen == 12, "wrap covers 250..255,0..5");
}
static void test_uint64_suffix()
{
using input_t = uint64_t;
using output_t = uint64_t;
using key_t = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128,
input_t, output_t>;
const input_t alpha = std::numeric_limits<input_t>::max() - 1;
const output_t beta = 77;
auto [k0, k1] = dpf::make_dpf(input_t{alpha}, output_t{beta});
input_t flipped_to = std::numeric_limits<input_t>::max();
dpf::utils::flip_msb_if_signed_integral(flipped_to);
const auto to_node = dpf::utils::get_to_node<key_t>(flipped_to);
expect(to_node == (input_t{1} << 63), "uint64 max exclusive leaf is 2^63");
const input_t from = std::numeric_limits<input_t>::max() - 3;
const input_t to = std::numeric_limits<input_t>::max();
auto [buf0, it0] = dpf::eval_interval(k0, from, to);
auto [buf1, it1] = dpf::eval_interval(k1, from, to);
auto z0 = std::begin(it0);
auto z1 = std::begin(it1);
int seen = 0;
for (input_t x = from;; ++x, ++z0, ++z1)
{
expect(z0 != std::end(it0), "uint64 suffix still has outputs");
const auto p0 = dpf::eval_point(k0, x);
const auto p1 = dpf::eval_point(k1, x);
const output_t interval = static_cast<output_t>(*z1) - static_cast<output_t>(*z0);
const output_t point = static_cast<output_t>(*p1) - static_cast<output_t>(*p0);
const output_t want = (x == alpha) ? beta : output_t{0};
expect(interval == point && interval == want, "uint64 suffix matches point");
++seen;
if (x == to)
break;
}
++z0;
expect(z0 == std::end(it0), "uint64 suffix iterable consumed");
expect(seen == 4, "uint64 suffix length");
}
static void test_narrow_inner_product()
{
using input_t = uint8_t;
using output_t = uint8_t;
const input_t alpha = 30;
const output_t beta = 7;
auto [k0, k1] = dpf::make_dpf(input_t{alpha}, output_t{beta});
uint64_t w[256];
for (int i = 0; i < 256; ++i)
w[i] = static_cast<uint64_t>(i * 3 + 1);
const input_t from = 0;
const input_t to = 255;
auto memo0 = dpf::make_basic_full_memoizer(k0);
auto memo1 = dpf::make_basic_full_memoizer(k1);
auto ip0 = dpf::eval_inner_product(k0, from, to, w, memo0);
auto ip1 = dpf::eval_inner_product(k1, from, to, w, memo1);
// Shares live in the output group, so a uint8 dot product is mod 256.
// alpha sits in lane 14 of its leaf, past the old 8-lane read.
const uint64_t got = static_cast<uint64_t>(ip1) - static_cast<uint64_t>(ip0);
const uint64_t want = (static_cast<uint64_t>(beta) * w[alpha]) & 0xffu;
expect(got == want, "uint8 inner product (16 lanes per leaf)");
}
static void test_empty_sequence()
{
using input_t = uint8_t;
using output_t = uint64_t;
auto [k0, k1] = dpf::make_dpf(input_t{3}, output_t{1});
std::vector<input_t> pts;
auto [buf, it] = dpf::eval_sequence(k0, pts.begin(), pts.end(),
dpf::return_output_only_tag_{});
expect(std::begin(it) == std::end(it), "empty output-only sequence");
auto [bbuf, bit] = dpf::eval_sequence_breadth_first(k0, pts.begin(), pts.end());
expect(std::begin(bit) == std::end(bit), "empty breadth-first sequence");
auto recipe = dpf::make_sequence_recipe<decltype(k0)>(pts.begin(), pts.end());
expect(recipe.num_leaf_nodes() == 0, "empty recipe has no leaves");
auto [rbuf, rit] = dpf::eval_sequence(k1, recipe, dpf::return_output_only_tag_{});
expect(std::begin(rit) == std::end(rit), "empty recipe eval");
(void)buf;
(void)bbuf;
(void)rbuf;
}
static void test_path_high_water()
{
using input_t = uint16_t;
using output_t = uint64_t;
const input_t alpha = 1000;
const output_t beta = 42;
auto [k0, k1] = dpf::make_dpf(input_t{alpha}, output_t{beta});
auto path = dpf::make_basic_path_memoizer(k0);
input_t tx = alpha;
dpf::utils::flip_msb_if_signed_integral(tx);
dpf::detail::ensure_level(k0, tx, path, 2);
const auto partial = dpf::eval_point(k0, alpha, path);
const auto fresh = dpf::eval_point(k0, alpha);
const auto other = dpf::eval_point(k1, alpha);
const output_t got = static_cast<output_t>(*other) - static_cast<output_t>(*partial);
const output_t want = static_cast<output_t>(*other) - static_cast<output_t>(*fresh);
expect(got == beta && want == beta, "point eval resumes a partial path");
}
int main()
{
test_wrap_interval();
test_uint64_suffix();
test_narrow_inner_product();
test_empty_sequence();
test_path_high_water();
if (fails != 0)
{
std::fprintf(stderr, "%d check(s) failed\n", fails);
return EXIT_FAILURE;
}
std::printf("eval audit fixes ok\n");
return EXIT_SUCCESS;
}

367
examples/eval_opt_smoke.cpp Normal file
View file

@ -0,0 +1,367 @@
// Smoke test for the interval-eval optimizations: pipelined interior
// eval01 / eval01_x4, round-major and x4/x8 exterior AES, fused dual-output
// leaf pass, uninitialized output buffers.
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
#include "dpf.hpp"
static int fails = 0;
static void expect(bool ok, const char *what)
{
if (!ok)
{
std::fprintf(stderr, "FAIL: %s\n", what);
++fails;
}
}
static bool m128_eq(simde__m128i a, simde__m128i b)
{
return std::memcmp(&a, &b, sizeof(a)) == 0;
}
static void test_aes_batch()
{
using prg = dpf::prg::aes128;
simde__m128i seed = simde_mm_set_epi64x(
static_cast<int64_t>(0xfedcba9876543210ULL),
static_cast<int64_t>(0x0123456789abcdefULL));
auto a0 = prg::eval(seed, 0);
auto a1 = prg::eval(seed, 1);
auto a2 = prg::eval(seed, 2);
auto a3 = prg::eval(seed, 3);
auto kids = prg::eval01(seed);
expect(m128_eq(kids[0], a0), "eval01[0] == eval(seed, 0)");
expect(m128_eq(kids[1], a1), "eval01[1] == eval(seed, 1)");
simde__m128i buf2[2];
prg::eval(seed, buf2, 2, 0);
expect(m128_eq(buf2[0], a0), "batch count=2 pos=0 [0]");
expect(m128_eq(buf2[1], a1), "batch count=2 pos=0 [1]");
simde__m128i buf1[1];
prg::eval(seed, buf1, 1, 3);
expect(m128_eq(buf1[0], a3), "batch count=1 pos=3");
simde__m128i buf4[4];
prg::eval(seed, buf4, 4, 0);
expect(m128_eq(buf4[0], a0) && m128_eq(buf4[1], a1)
&& m128_eq(buf4[2], a2) && m128_eq(buf4[3], a3),
"round-major batch count=4");
simde__m128i buf2p[2];
prg::eval(seed, buf2p, 2, 2);
expect(m128_eq(buf2p[0], a2) && m128_eq(buf2p[1], a3),
"batch count=2 pos=2");
simde__m128i seeds[4];
simde__m128i left[4], right[4];
for (int i = 0; i < 4; ++i)
{
seeds[i] = simde_mm_xor_si128(seed, simde_mm_set_epi64x(0, i + 1));
}
prg::eval01_x4(seeds, left, right);
for (int i = 0; i < 4; ++i)
{
auto kids = prg::eval01(seeds[i]);
expect(m128_eq(left[i], kids[0]) && m128_eq(right[i], kids[1]),
"eval01_x4 matches eval01");
}
simde__m128i x4[4];
prg::eval_x4(seeds, x4, 3);
for (int i = 0; i < 4; ++i)
{
expect(m128_eq(x4[i], prg::eval(seeds[i], 3)),
"eval_x4 matches eval");
}
simde__m128i seeds8[8];
simde__m128i x8[8];
for (int i = 0; i < 8; ++i)
{
seeds8[i] = simde_mm_xor_si128(seed, simde_mm_set_epi64x(i + 9, i + 1));
}
prg::eval_x8(seeds8, x8, 0);
for (int i = 0; i < 8; ++i)
{
expect(m128_eq(x8[i], prg::eval(seeds8[i], 0)),
"eval_x8 matches eval");
}
}
static void test_dual_interval()
{
using input_t = dpf::modint<8>;
using add_t = psnip_uint64_t;
using xor_t = dpf::xor_wrapper<psnip_uint64_t>;
using dpf_t = dpf::utils::dpf_type_t<
dpf::prg::aes128, dpf::prg::aes128, input_t, add_t, xor_t>;
const uint64_t alpha = 37;
const uint64_t beta_add = 0x1111111111111111ULL;
const uint64_t beta_xor = 0xaaaaaaaaaaaaaaaaULL;
auto args = dpf::make_dpfargs(
input_t{static_cast<typename input_t::integral_type>(alpha)},
static_cast<add_t>(beta_add),
xor_t{static_cast<psnip_uint64_t>(beta_xor)});
auto [k0, k1] = dpf::make_dpf(std::move(args));
auto from = std::numeric_limits<input_t>::min();
auto to = std::numeric_limits<input_t>::max();
auto add0 = dpf::make_output_buffer_for_full<0>(k0);
auto xor0 = dpf::make_output_buffer_for_full<1>(k0);
auto add1 = dpf::make_output_buffer_for_full<0>(k1);
auto xor1 = dpf::make_output_buffer_for_full<1>(k1);
auto memo0 = dpf::make_basic_full_memoizer(k0);
auto memo1 = dpf::make_basic_full_memoizer(k1);
auto bufs0 = std::forward_as_tuple(add0, xor0);
auto bufs1 = std::forward_as_tuple(add1, xor1);
dpf::eval_interval<0, 1>(k0, from, to, bufs0, memo0);
dpf::eval_interval<0, 1>(k1, from, to, bufs1, memo1);
const int n = 1 << 8;
int add_hits = 0, xor_hits = 0, add_miss = 0, xor_miss = 0;
for (int x = 0; x < n; ++x)
{
auto in = input_t{static_cast<typename input_t::integral_type>(x)};
uint64_t s_add = static_cast<uint64_t>(add1[x])
- static_cast<uint64_t>(add0[x]);
uint64_t s_xor = static_cast<uint64_t>(static_cast<psnip_uint64_t>(xor_t(xor0[x])))
^ static_cast<uint64_t>(static_cast<psnip_uint64_t>(xor_t(xor1[x])));
auto p0 = dpf::eval_point<0>(k0, in);
auto p1 = dpf::eval_point<0>(k1, in);
uint64_t point_add = static_cast<uint64_t>(*p1) - static_cast<uint64_t>(*p0);
if (x == static_cast<int>(alpha))
{
if (s_add == beta_add) ++add_hits; else ++add_miss;
if (s_xor == beta_xor) ++xor_hits; else ++xor_miss;
expect(point_add == beta_add, "eval_point add at alpha");
}
else
{
if (s_add == 0) ++add_hits; else ++add_miss;
if (s_xor == 0) ++xor_hits; else ++xor_miss;
expect(point_add == 0, "eval_point add off alpha");
}
expect(s_add == point_add, "interval add matches eval_point");
}
expect(add_miss == 0 && add_hits == n, "dual-output additive reconstruct");
expect(xor_miss == 0 && xor_hits == n, "dual-output xor reconstruct");
}
static void test_four_outputs_and_wrap()
{
using input_t = dpf::modint<8>;
using out_t = psnip_uint64_t;
auto args = dpf::make_dpfargs(
input_t{static_cast<typename input_t::integral_type>(5)},
static_cast<out_t>(1), static_cast<out_t>(2),
static_cast<out_t>(3), static_cast<out_t>(4));
auto [k0, k1] = dpf::make_dpf(std::move(args));
auto from = std::numeric_limits<input_t>::min();
auto to = std::numeric_limits<input_t>::max();
auto [bufs0, it0] = dpf::eval_interval<0, 1, 2, 3>(k0, from, to);
auto [bufs1, it1] = dpf::eval_interval<0, 1, 2, 3>(k1, from, to);
const uint64_t want[4] = {1, 2, 3, 4};
for (int i = 0; i < 4; ++i)
{
const auto & a = (i == 0) ? std::get<0>(bufs0)
: (i == 1) ? std::get<1>(bufs0)
: (i == 2) ? std::get<2>(bufs0) : std::get<3>(bufs0);
const auto & b = (i == 0) ? std::get<0>(bufs1)
: (i == 1) ? std::get<1>(bufs1)
: (i == 2) ? std::get<2>(bufs1) : std::get<3>(bufs1);
for (int x = 0; x < 256; ++x)
{
uint64_t s = static_cast<uint64_t>(b[x]) - static_cast<uint64_t>(a[x]);
uint64_t exp = (x == 5) ? want[i] : 0ULL;
if (s != exp)
{
expect(false, "4-output fused reconstruct");
return;
}
}
}
}
static void test_single_and_reuse()
{
using input_t = dpf::modint<8>;
using out_t = psnip_uint64_t;
auto args = dpf::make_dpfargs(
input_t{static_cast<typename input_t::integral_type>(11)},
static_cast<out_t>(7));
auto [k0, k1] = dpf::make_dpf(std::move(args));
auto from = std::numeric_limits<input_t>::min();
auto to = std::numeric_limits<input_t>::max();
auto buf0 = dpf::make_output_buffer_for_full<0>(k0);
auto buf1 = dpf::make_output_buffer_for_full<0>(k1);
auto memo0 = dpf::make_basic_full_memoizer(k0);
auto memo1 = dpf::make_basic_full_memoizer(k1);
dpf::eval_interval<0>(k0, from, to, buf0, memo0);
dpf::eval_interval<0>(k1, from, to, buf1, memo1);
// Reuse the same buffers / memoizer with a second key pair.
auto args2 = dpf::make_dpfargs(
input_t{static_cast<typename input_t::integral_type>(200)},
static_cast<out_t>(99));
auto [k2, k3] = dpf::make_dpf(std::move(args2));
dpf::eval_interval<0>(k2, from, to, buf0, memo0);
dpf::eval_interval<0>(k3, from, to, buf1, memo1);
for (int x = 0; x < 256; ++x)
{
uint64_t s = static_cast<uint64_t>(buf1[x]) - static_cast<uint64_t>(buf0[x]);
uint64_t want = (x == 200) ? 99ULL : 0ULL;
if (s != want)
{
expect(false, "reused buffer/memoizer reconstruct");
return;
}
}
}
static void test_partial_interval()
{
using input_t = dpf::modint<8>;
using out_t = psnip_uint64_t;
auto args = dpf::make_dpfargs(
input_t{static_cast<typename input_t::integral_type>(17)},
static_cast<out_t>(42));
auto [k0, k1] = dpf::make_dpf(std::move(args));
// 12 leaf nodes (24 outputs): hits eval_x8 then eval_x4. Size is a
// multiple of the 64-byte output_buffer alignment (ASan aligned_alloc).
auto from = input_t{static_cast<typename input_t::integral_type>(0)};
auto to = input_t{static_cast<typename input_t::integral_type>(23)};
auto [bufs0, it0] = dpf::eval_interval<0>(k0, from, to);
auto [bufs1, it1] = dpf::eval_interval<0>(k1, from, to);
(void)bufs0;
(void)bufs1;
auto z0 = std::begin(it0);
auto z1 = std::begin(it1);
auto e0 = std::end(it0);
for (int x = 0; z0 != e0; ++x, ++z0, ++z1)
{
uint64_t s = static_cast<uint64_t>(*z1) - static_cast<uint64_t>(*z0);
uint64_t want = (x == 17) ? 42ULL : 0ULL;
if (s != want)
{
expect(false, "partial interval reconstruct");
return;
}
auto in = input_t{static_cast<typename input_t::integral_type>(x)};
auto p0 = dpf::eval_point<0>(k0, in);
auto p1 = dpf::eval_point<0>(k1, in);
uint64_t point = static_cast<uint64_t>(*p1) - static_cast<uint64_t>(*p0);
expect(s == point, "partial interval matches eval_point");
}
}
static void test_inner_product()
{
using input_t = dpf::modint<8>;
using add_t = psnip_uint64_t;
using xor_t = dpf::xor_wrapper<psnip_uint64_t>;
const uint64_t alpha = 19;
const uint64_t beta_add = 7;
const uint64_t beta_xor = 0x5a5a5a5a5a5a5a5aULL;
auto args = dpf::make_dpfargs(
input_t{static_cast<typename input_t::integral_type>(alpha)},
static_cast<add_t>(beta_add),
xor_t{static_cast<psnip_uint64_t>(beta_xor)});
auto [k0, k1] = dpf::make_dpf(std::move(args));
auto from = std::numeric_limits<input_t>::min();
auto to = std::numeric_limits<input_t>::max();
const int n = 1 << 8;
uint64_t w_add[256];
uint64_t w_xor[256];
for (int i = 0; i < n; ++i)
{
w_add[i] = static_cast<uint64_t>(i * 3 + 1);
w_xor[i] = static_cast<uint64_t>(0x1111111111111111ULL * (i + 1));
}
auto add0 = dpf::make_output_buffer_for_full<0>(k0);
auto xor0 = dpf::make_output_buffer_for_full<1>(k0);
auto add1 = dpf::make_output_buffer_for_full<0>(k1);
auto xor1 = dpf::make_output_buffer_for_full<1>(k1);
auto memo0 = dpf::make_basic_full_memoizer(k0);
auto memo1 = dpf::make_basic_full_memoizer(k1);
auto bufs0 = std::forward_as_tuple(add0, xor0);
auto bufs1 = std::forward_as_tuple(add1, xor1);
dpf::eval_interval<0, 1>(k0, from, to, bufs0, memo0);
dpf::eval_interval<0, 1>(k1, from, to, bufs1, memo1);
uint64_t dot_add0 = 0, dot_add1 = 0, dot_xor0 = 0, dot_xor1 = 0;
for (int i = 0; i < n; ++i)
{
dot_add0 += static_cast<uint64_t>(add0[i]) * w_add[i];
dot_add1 += static_cast<uint64_t>(add1[i]) * w_add[i];
dot_xor0 ^= static_cast<uint64_t>(static_cast<psnip_uint64_t>(xor_t(xor0[i])))
& w_xor[i];
dot_xor1 ^= static_cast<uint64_t>(static_cast<psnip_uint64_t>(xor_t(xor1[i])))
& w_xor[i];
}
auto memo0b = dpf::make_basic_full_memoizer(k0);
auto memo1b = dpf::make_basic_full_memoizer(k1);
dpf::eval_prepare_interval(k0, from, to, memo0b);
dpf::eval_prepare_interval(k1, from, to, memo1b);
auto [ip_add0, ip_xor0] = dpf::eval_inner_product<0, 1>(
k0, from, to, std::forward_as_tuple(w_add, w_xor), memo0b);
auto [ip_add1, ip_xor1] = dpf::eval_inner_product<0, 1>(
k1, from, to, std::forward_as_tuple(w_add, w_xor), memo1b);
expect(static_cast<uint64_t>(ip_add0) == dot_add0, "inner product add p0");
expect(static_cast<uint64_t>(ip_add1) == dot_add1, "inner product add p1");
expect(static_cast<uint64_t>(static_cast<psnip_uint64_t>(xor_t(ip_xor0)))
== dot_xor0, "inner product xor p0");
expect(static_cast<uint64_t>(static_cast<psnip_uint64_t>(xor_t(ip_xor1)))
== dot_xor1, "inner product xor p1");
uint64_t recon_add = static_cast<uint64_t>(ip_add1)
- static_cast<uint64_t>(ip_add0);
uint64_t recon_xor = static_cast<uint64_t>(static_cast<psnip_uint64_t>(xor_t(ip_xor0)))
^ static_cast<uint64_t>(static_cast<psnip_uint64_t>(xor_t(ip_xor1)));
expect(recon_add == beta_add * w_add[static_cast<int>(alpha)],
"inner product reconstruct add");
expect(recon_xor == (beta_xor & w_xor[static_cast<int>(alpha)]),
"inner product reconstruct xor");
auto [ip_add0b, ip_add0c] = dpf::eval_full_inner_product<0, 0>(
k0, std::forward_as_tuple(w_add, w_add), memo0b);
expect(static_cast<uint64_t>(ip_add0b) == static_cast<uint64_t>(ip_add0),
"duplicate-output inner product");
expect(static_cast<uint64_t>(ip_add0c) == static_cast<uint64_t>(ip_add0),
"duplicate-output inner product match");
}
int main()
{
test_aes_batch();
test_dual_interval();
test_four_outputs_and_wrap();
test_single_and_reuse();
test_partial_interval();
test_inner_product();
if (fails)
{
std::fprintf(stderr, "%d check(s) failed\n", fails);
return 1;
}
std::puts("eval_opt_smoke: ok");
return 0;
}

View file

@ -0,0 +1,31 @@
#include <iostream>
#include "dpf.hpp"
int main(int arc, char * argv[])
{
uint16_t x = 42; // Input value
using prg = dpf::prg::counter_wrapper<dpf::prg::dummy>; // This is just to count the number of PRG invocations
auto before = prg::count(); // In order to show how much this program cost
auto [dpf0, dpf1] = dpf::make_dpf<prg>(x);
auto after = prg::count();
std::cout << "dpf::make_dpf used " << (after-before) << "\n";
before = prg::count();
auto [buf0, iter0] = dpf::eval_full(dpf0);
after = prg::count();
std::cout << "dpf::eval_full(dpf0) used " << (after-before) << "\n";
before = prg::count();
auto [buf1, iter1] = dpf::eval_full(dpf1);
after = prg::count();
std::cout << "dpf::eval_full(dpf1) used " << (after-before) << "\n";
// Retrieve the original input by iterating over the two buffers
for (size_t i = 0; i < buf0.size(); ++i) {
bool item1 = buf0[i];
bool item2 = buf1[i];
if (item1 ^ item2) std::cout << "The original input is: " << i << std::endl;
}
std::cout << "Total PRG invocation: " << prg::count() << "\n";
return 0;
}

View file

@ -0,0 +1,42 @@
#include <iostream>
#include "dpf.hpp"
int main(int arc, char * argv[])
{
uint16_t x = 42, y;
using prg = dpf::prg::counter_wrapper<dpf::prg::dummy>;
// Make the DPF
auto before = prg::count();
auto [dpf0, dpf1] = dpf::make_dpf<prg>(x);
auto after = prg::count();
std::cout << "dpf::make_dpf prg invocation: " << (after-before) << "\n";
// Evaluate the DPF by interval
before = prg::count();
int from = 0, to = 49;
auto [buf0, iter0] = dpf::eval_interval(dpf0, from, to);
auto [buf1, iter1] = dpf::eval_interval(dpf1, from, to);
after = prg::count();
std::cout << "dpf::eval_interval prg invocation: " << (after-before) << "\n";
// Retrieve the original input by iterating over the two buffers
std::vector<bool> result;
for (size_t i = from; i < to+1; ++i) {
bool item1 = buf0[i];
bool item2 = buf1[i];
result.push_back(item1 ^ item2);
if (item1 ^ item2) y=i;
}
// Print out the XOR interval
for (const auto& item : result) {
std::cout << static_cast<bool>(item);
}
std::cout << std::endl;
if (y == x) std::cout << "The orginal value is: " << x << std::endl;
else std::cout << "The evaluated inputs did not match the original value." << std::endl;
std::cout << "Total PRG invocation: " << prg::count() << std::endl;
return 0;
}

View file

@ -0,0 +1,17 @@
#include <iostream>
#include "dpf.hpp"
int main(int arc, char * argv[])
{
uint16_t x = 42;
auto [dpf0, dpf1] = dpf::make_dpf(x);
auto res = dpf::eval_point(dpf0, x);
std::cout << *dpf::eval_point(dpf0, 41) << " ^ " << *dpf::eval_point(dpf1, 41) << " = " << (*dpf::eval_point(dpf0, 41) ^ *dpf::eval_point(dpf1, 41)) << "\n"; // = 0
std::cout << *dpf::eval_point(dpf0, x) << " ^ " << *dpf::eval_point(dpf1, x) << " = " << (*dpf::eval_point(dpf0, x) ^ *dpf::eval_point(dpf1, x)) << "\n"; // = 1
std::cout << *dpf::eval_point(dpf0, 43) << " ^ " << *dpf::eval_point(dpf1, 43) << " = " << (*dpf::eval_point(dpf0, 43) ^ *dpf::eval_point(dpf1, 43)) << "\n"; // = 0
return 0;
}

View file

@ -0,0 +1,54 @@
#include <chrono>
#include <iostream>
#include "dpf.hpp"
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
int main(int argc, char * argv[])
{
using input_type = uint8_t;
using prg = dpf::prg::counter_wrapper<dpf::prg::dummy>;
constexpr int N = 50;
std::array<input_type, N> keys{};
for(int i=0; i<N; i++) keys[i] = i; // Create an array of keys
// eval_sequence with recipe
input_type x = 42;
auto [dpf0, dpf1] = dpf::make_dpf<prg>(x); // First DPF to be able to create the recipe
auto t1 = high_resolution_clock::now(); // To measure the time of execution
auto before = prg::count(); // To count the number of PRG invocations
auto recipe0 = dpf::make_sequence_recipe(dpf0, std::begin(keys), std::end(keys)); // Create a recipe
auto recipe1 = dpf::make_sequence_recipe(dpf1, std::begin(keys), std::end(keys)); // Create a recipe
for (int i=0; i<N; i++)
{
auto [dpf00, dpf11] = dpf::make_dpf<prg>(i); // Make 50 DPFs
dpf::eval_sequence(dpf0, recipe0); // Evaluate the DPFs with the recipe
dpf::eval_sequence(dpf1, recipe0); // Evaluate the DPFs with the recipe
}
auto after = prg::count(); // Count the number of PRG invocations
std::cout << "dpf::eval_sequence with recipe " << (after-before) << "\n";
// eval_sequence without the recipe
auto t2 = high_resolution_clock::now();
duration<double, std::milli> ms_double = t2 - t1;
std::cout << "Time of execution: " << ms_double.count() << "ms\n";
auto t3 = high_resolution_clock::now();
before = prg::count();
for (int i=0; i<N; i++)
{
auto [dpf00, dpf11] = dpf::make_dpf<prg>(i);
dpf::eval_sequence(dpf00, std::begin(keys), std::end(keys));
dpf::eval_sequence(dpf11, std::begin(keys), std::end(keys));
}
after = prg::count();
std::cout << "dpf::eval_sequence used " << (after-before) << "\n";
auto t4 = high_resolution_clock::now();
duration<double, std::milli> ms_double2 = t4 - t3;
std::cout << "Time of execution with the memoizers: " << ms_double2.count() << "ms\n";
return 0;
}

View file

@ -0,0 +1,50 @@
#include <iostream>
#include <chrono>
#include "dpf.hpp"
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
int main(int arc, char * argv[])
{
// Making the DPF with an integer value
uint16_t x = 42;
using prg = dpf::prg::counter_wrapper<dpf::prg::dummy>;
auto [dpf0, dpf1] = dpf::make_dpf<prg>(x);
// Evaluating the DPF and counting how much it cost without memoizers
auto t1 = high_resolution_clock::now();
auto before = prg::count();
for (int i = 0; i<1024*1024; i++)
{
dpf::eval_point(dpf0, i);
}
// Printing out the results
auto after = prg::count();
std::cout << "Without memoizers: " << "\n";
std::cout << "PRG invocation: " << after-before << "\n";
auto t2 = high_resolution_clock::now();
duration<double, std::milli> ms_double = t2 - t1;
std::cout << "Time of execution: " << ms_double.count() << "ms\n";
// Evaluating the DPF and counting how much it cost with memoizers
auto t3 = high_resolution_clock::now();
before = prg::count();
auto path = dpf::make_basic_path_memoizer(dpf0);
for (int i = 0; i<1024*1024; i++)
{
dpf::eval_point(dpf0, i, path);
}
// Printing out the results
after = prg::count();
std::cout << "With memoizers: " << "\n";
std::cout << "PRG invocation: " << after-before << "\n";
auto t4 = high_resolution_clock::now();
duration<double, std::milli> ms_double2 = t4 - t3;
std::cout << "Time of execution with the memoizers: " << ms_double2.count() << "ms\n";
return 0;
}

View file

@ -0,0 +1,6 @@
#include "dpf.hpp"
int main(int argc, char * argv[])
{
return 0;
}

View file

@ -0,0 +1,14 @@
#include <iostream>
#include "dpf.hpp"
int main()
{
using namespace dpf::literals;
using bits = dpf::bitstring<8>;
bits x = 10101001_bitstring;
std::cout << (x == bits(0b10101001)) << " " << x.to_string() << "\n";
auto [k0, k1] = dpf::make_dpf(x, dpf::bit::one);
auto y0 = dpf::eval_point(k0, x);
auto y1 = dpf::eval_point(k1, x);
std::cout << (static_cast<dpf::bit>(y0) + static_cast<dpf::bit>(y1)) << "\n";
}

View file

@ -0,0 +1,43 @@
#include <cstdint>
#include <iostream>
#include "dpf.hpp"
// Minimal 16-bit input. See test/tests/helpers/custom_input_type.hpp for a
// type that also supports interval evaluation.
struct input_type
{
std::uint16_t i{};
input_type() = default;
explicit constexpr input_type(std::uint16_t v) : i{v} {}
input_type operator&(input_type rhs) const { return input_type{static_cast<std::uint16_t>(i & rhs.i)}; }
input_type operator&(std::uint64_t rhs) const { return input_type{static_cast<std::uint16_t>(i & rhs)}; }
input_type operator>>(std::size_t n) const { return input_type{static_cast<std::uint16_t>(i >> n)}; }
input_type & operator>>=(int) { i = static_cast<std::uint16_t>(i >> 1); return *this; }
explicit operator bool() const { return i != 0; }
};
namespace dpf::utils
{
template <> struct bitlength_of<input_type> : std::integral_constant<std::size_t, 16> {};
template <> struct msb_of<input_type>
{
static constexpr input_type value{std::uint16_t{0x8000}};
};
template <> struct mod_pow_2<input_type>
{
std::size_t operator()(input_type val, std::size_t n) const noexcept
{
if (n == 0) return 0;
const auto mask = n >= 16 ? 0xffffu : (1u << n) - 1u;
return val.i & mask;
}
};
}
int main()
{
auto [k0, k1] = dpf::make_dpf(input_type{7}, dpf::bit::one);
auto y0 = dpf::eval_point(k0, input_type{7});
auto y1 = dpf::eval_point(k1, input_type{7});
std::cout << (static_cast<dpf::bit>(y0) + static_cast<dpf::bit>(y1)) << "\n";
}

View file

@ -0,0 +1,11 @@
#include <iostream>
#include "dpf.hpp"
int main()
{
simde_uint128 x = 42;
auto [k0, k1] = dpf::make_dpf(x, dpf::bit::one);
auto y0 = dpf::eval_point(k0, x);
auto y1 = dpf::eval_point(k1, x);
std::cout << (static_cast<dpf::bit>(y0) + static_cast<dpf::bit>(y1)) << "\n";
}

View file

@ -0,0 +1,25 @@
#include <iostream>
#include <cassert>
#include "dpf.hpp"
int main(int argc, char * argv[])
{
using value_type = int;
std::vector<value_type> values = {12, 34, 56, 78};
auto [dpf0, dpf1] = dpf::make_dpf(value_type{56});
int i=0;
value_type res0{};
auto [buf0, iter0] = dpf::eval_sequence(dpf0, std::begin(values), std::end(values));
for (auto b : iter0) { if (b) res0 ^= values[i]; i++; }
i=0;
value_type res1{};
auto [buf1, iter1] = dpf::eval_sequence(dpf1, std::begin(values), std::end(values));
for (auto b : iter1) { if (b) res1 ^= values[i]; i++; }
std::cout << (res0 ^ res1) << "\n";
std::cout << values[2] << "\n";
}

View file

@ -0,0 +1,28 @@
#include <iostream>
#include <cassert>
#include "dpf.hpp"
int main(int argc, char * argv[])
{
using keyword_type = dpf::keyword<3, dpf::alphabets::lowercase_alpha>;
using value_type = int;
std::vector<keyword_type> keys = {"cat", "dog", "bat", "pig"};
std::vector<value_type> values = {12, 34, 56, 78};
auto [dpf0, dpf1] = dpf::make_dpf(keyword_type{"bat"});
// auto [dpf0, dpf1] = dpf::make_dpf(keyword_type{"rat"}); // key does not exist; result will be 0
int i=0;
value_type res0{};
auto [buf0, iter0] = dpf::eval_sequence(dpf0, std::begin(keys), std::end(keys));
for (auto b : iter0) { if (b) res0 ^= values[i]; i++; }
i=0;
value_type res1{};
auto [buf1, iter1] = dpf::eval_sequence(dpf1, std::begin(keys), std::end(keys));
for (auto b : iter1) { if (b) res1 ^= values[i]; i++; }
std::cout << (res0 ^ res1) << "\n";
std::cout << values[2] << "\n";
}

View file

@ -0,0 +1,32 @@
#include <iostream>
#include <cassert>
#include <map>
#include "dpf.hpp"
int main(int argc, char * argv[])
{
static constexpr char lc[] = "abcdefghijklmnopqrstuvwxyz";
using keyword_type = dpf::keyword<3, lc>;
using value_type = int;
std::map<keyword_type, value_type> database{{"cat", 12},
{"bat", 34},
{"dog", 56},
{"pig", 78}};
keyword_type x = "bat";
std::cout << x << std::endl;
auto [dpf0, dpf1] = dpf::make_dpf(x);
value_type share0{}, share1{};
auto path0 = dpf::make_basic_path_memoizer(dpf0);
auto path1 = dpf::make_basic_path_memoizer(dpf1);
for (auto & [key, value] : database)
{
if (dpf::eval_point(dpf0, key, path0)) {share0 ^= value; std::cout << value << std::endl;}
if (dpf::eval_point(dpf1, key, path1)) share1 ^= value;
}
std::cout << share0 << share1 << "\n";
std::cout << std::string(x) << "(" << x << ")->" << (share0 ^ share1) << "\n";
}

View file

@ -0,0 +1,26 @@
#include <iostream>
#include <cassert>
#include "dpf.hpp"
int main(int argc, char * argv[])
{
dpf::modint<10> a(2048); // 2048 % 2^10 = 0
dpf::modint<10> b(1026); // 1026 % 2^10 = 2
std::cout << a + b << std::endl; // = 2
dpf::modint<10> c(2051); // 2051 % 2^10 = 3
dpf::modint<10> d(1026); // 1026 % 2^10 = 2
std::cout << c - d << std::endl; // = 1
dpf::modint<10> e(2050); // 2050 % 2^10 = 2
dpf::modint<10> f(1026); // 1026 % 2^10 = 2
std::cout << e * f << std::endl; // = 4
dpf::modint<10> g(2052); // 2052 % 2^10 = 4
dpf::modint<10> h(1026); // 1026 % 2^10 = 2
std::cout << g / h << std::endl; // = 2
dpf::modint<10> i(2048); // 2048 % 2^10 = 0
dpf::modint<10> j(1024); // 1024 % 2^10 = 0
std::cout << (i == j) << std::endl; // = 1
}

View file

@ -0,0 +1,13 @@
#include <iostream>
#include "dpf.hpp"
int main()
{
using x8 = dpf::xor_wrapper<std::uint8_t>;
x8 x{0x3c};
auto [k0, k1] = dpf::make_dpf(x, dpf::bit::one);
auto y0 = dpf::eval_point(k0, x);
auto y1 = dpf::eval_point(k1, x);
std::cout << (static_cast<dpf::bit>(y0) + static_cast<dpf::bit>(y1)) << "\n";
std::cout << ((++x8{1}) == x8{0}) << "\n";
}

View file

@ -0,0 +1,23 @@
#include <iostream>
#include "dpf.hpp"
int main(int argc, char * argv[])
{
using input_type = uint16_t;
using output_type = dpf::bit;
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
auto memo0 = dpf::make_basic_full_memoizer<dpf_type>();
auto memo1 = dpf::make_basic_full_memoizer<dpf_type>();
input_type x = 42;
output_type y = dpf::bit::one;
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
auto advice0 = dpf::advice_bits_of(memo0);
auto advice1 = dpf::advice_bits_of(memo1);
auto it0 = std::begin(advice0), it1 = std::begin(advice1);
for (std::size_t i = 0; i < std::size_t(1)<<dpf_type::depth; ++i, ++it0, ++it1)
{
std::cout << "Advice bit " << i << " of dpf0: " << *it0 << "\n";
}
}

View file

@ -0,0 +1,6 @@
#include "dpf.hpp"
int main(int argc, char * argv[])
{
return 0;
}

View file

@ -0,0 +1,6 @@
#include "dpf.hpp"
int main(int argc, char * argv[])
{
return 0;
}

View file

@ -0,0 +1,6 @@
#include "dpf.hpp"
int main(int argc, char * argv[])
{
return 0;
}

View file

@ -0,0 +1,6 @@
#include "dpf.hpp"
int main(int argc, char * argv[])
{
return 0;
}

View file

@ -0,0 +1,6 @@
#include "dpf.hpp"
int main(int argc, char * argv[])
{
return 0;
}

View file

@ -0,0 +1,10 @@
#include <iostream>
#include "dpf.hpp"
int main()
{
auto [k0, k1] = dpf::make_dpf(std::uint8_t{3}, dpf::bit::one);
auto y0 = dpf::eval_point(k0, std::uint8_t{3});
auto y1 = dpf::eval_point(k1, std::uint8_t{3});
std::cout << (static_cast<dpf::bit>(y0) + static_cast<dpf::bit>(y1)) << "\n";
}

View file

@ -0,0 +1,12 @@
#include <iostream>
#include "dpf.hpp"
int main()
{
using bits = dpf::bitstring<8>;
auto programmed = bits(0b10101001);
auto [k0, k1] = dpf::make_dpf(std::uint8_t{2}, programmed);
auto y0 = dpf::eval_point(k0, std::uint8_t{2});
auto y1 = dpf::eval_point(k1, std::uint8_t{2});
std::cout << (static_cast<bits>(y0) + static_cast<bits>(y1)) << "\n";
}

View file

@ -0,0 +1,26 @@
#include <cstdint>
#include <iostream>
#include "dpf.hpp"
struct point
{
std::uint32_t v{};
point operator+(point rhs) const { return point{v + rhs.v}; }
point operator-(point rhs) const { return point{v - rhs.v}; }
bool operator==(point rhs) const { return v == rhs.v; }
};
namespace dpf::leaf_arithmetic
{
template <> struct add_t<point, simde__m128i> final : detail::add4x32_t {};
template <> struct subtract_t<point, simde__m128i> final : detail::sub4x32_t {};
template <> struct multiply_t<point, simde__m128i> final : detail::mul4x32_t {};
}
int main()
{
auto [k0, k1] = dpf::make_dpf(std::uint8_t{9}, point{5});
auto y0 = dpf::eval_point(k0, std::uint8_t{9});
auto y1 = dpf::eval_point(k1, std::uint8_t{9});
std::cout << (static_cast<point>(y0) + static_cast<point>(y1)).v << "\n";
}

View file

@ -0,0 +1,11 @@
#include <iostream>
#include "dpf.hpp"
int main()
{
auto [k0, k1] = dpf::make_dpf(std::uint8_t{1}, simde_uint128{7});
auto y0 = dpf::eval_point(k0, std::uint8_t{1});
auto y1 = dpf::eval_point(k1, std::uint8_t{1});
auto sum = static_cast<simde_uint128>(y0) + static_cast<simde_uint128>(y1);
std::cout << (sum == simde_uint128{7}) << "\n";
}

View file

@ -0,0 +1,11 @@
#include <cstdint>
#include <iostream>
#include "dpf.hpp"
int main()
{
auto [k0, k1] = dpf::make_dpf(std::uint16_t{42}, std::uint32_t{7});
auto y0 = dpf::eval_point(k0, std::uint16_t{42});
auto y1 = dpf::eval_point(k1, std::uint16_t{42});
std::cout << (static_cast<std::uint32_t>(y0) + static_cast<std::uint32_t>(y1)) << "\n";
}

View file

@ -0,0 +1,18 @@
#include <iostream>
#include "dpf.hpp"
int main(int argc, char * argv[])
{
using input_type = uint8_t;
using output_type = dpf::wildcard_value<uint32_t>;
using dpf_type = dpf::utils::dpf_type_t<dpf::prg::aes128, dpf::prg::aes128, input_type, output_type>;
input_type x = 12;
output_type y;
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
std::array<input_type, 5> points{12, 34, 56, 78, 90};
auto recipe0 = dpf::make_sequence_recipe(dpf0, std::begin(points), std::end(points));
auto recipe1 = dpf::make_sequence_recipe(dpf1, std::begin(points), std::end(points));
}

View file

@ -0,0 +1,11 @@
#include <iostream>
#include "dpf.hpp"
int main()
{
using x32 = dpf::xor_wrapper<std::uint32_t>;
auto [k0, k1] = dpf::make_dpf(std::uint8_t{4}, x32{0x11});
auto y0 = dpf::eval_point(k0, std::uint8_t{4});
auto y1 = dpf::eval_point(k1, std::uint8_t{4});
std::cout << (static_cast<x32>(y0) + static_cast<x32>(y1)) << "\n";
}