Initial import of libdpf.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
commit
e4e666f459
4563 changed files with 1690372 additions and 0 deletions
170
examples/eval_audit_fixes.cpp
Normal file
170
examples/eval_audit_fixes.cpp
Normal 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
367
examples/eval_opt_smoke.cpp
Normal 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;
|
||||
}
|
||||
31
examples/evaluation/eval_full.cpp
Normal file
31
examples/evaluation/eval_full.cpp
Normal 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;
|
||||
}
|
||||
42
examples/evaluation/eval_interval.cpp
Normal file
42
examples/evaluation/eval_interval.cpp
Normal 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;
|
||||
}
|
||||
17
examples/evaluation/eval_point.cpp
Normal file
17
examples/evaluation/eval_point.cpp
Normal 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;
|
||||
}
|
||||
54
examples/evaluation/eval_sequence.cpp
Normal file
54
examples/evaluation/eval_sequence.cpp
Normal 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;
|
||||
}
|
||||
50
examples/evaluation/memoizers.cpp
Normal file
50
examples/evaluation/memoizers.cpp
Normal 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;
|
||||
}
|
||||
6
examples/evaluation/output_buffers.cpp
Normal file
6
examples/evaluation/output_buffers.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "dpf.hpp"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
14
examples/input_types/bitstring.cpp
Normal file
14
examples/input_types/bitstring.cpp
Normal 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";
|
||||
}
|
||||
43
examples/input_types/custom.cpp
Normal file
43
examples/input_types/custom.cpp
Normal 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";
|
||||
}
|
||||
11
examples/input_types/extended_types.cpp
Normal file
11
examples/input_types/extended_types.cpp
Normal 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";
|
||||
}
|
||||
25
examples/input_types/integral_types.cpp
Normal file
25
examples/input_types/integral_types.cpp
Normal 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";
|
||||
}
|
||||
28
examples/input_types/keyword.cpp
Normal file
28
examples/input_types/keyword.cpp
Normal 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";
|
||||
}
|
||||
32
examples/input_types/keyword_int_map.cpp
Normal file
32
examples/input_types/keyword_int_map.cpp
Normal 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";
|
||||
}
|
||||
26
examples/input_types/modint.cpp
Normal file
26
examples/input_types/modint.cpp
Normal 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
|
||||
}
|
||||
13
examples/input_types/xor_wrapper.cpp
Normal file
13
examples/input_types/xor_wrapper.cpp
Normal 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";
|
||||
}
|
||||
23
examples/iterables/advice_bit_iterable.cpp
Normal file
23
examples/iterables/advice_bit_iterable.cpp
Normal 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";
|
||||
}
|
||||
}
|
||||
6
examples/iterables/parallel_bit_iterable.cpp
Normal file
6
examples/iterables/parallel_bit_iterable.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "dpf.hpp"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
6
examples/iterables/setbit_index_iterable.cpp
Normal file
6
examples/iterables/setbit_index_iterable.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "dpf.hpp"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
6
examples/iterables/subinterval_iterable.cpp
Normal file
6
examples/iterables/subinterval_iterable.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "dpf.hpp"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
6
examples/iterables/subsequence_iterable.cpp
Normal file
6
examples/iterables/subsequence_iterable.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "dpf.hpp"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
6
examples/iterables/zip_iterable.cpp
Normal file
6
examples/iterables/zip_iterable.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "dpf.hpp"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
10
examples/output_types/bit.cpp
Normal file
10
examples/output_types/bit.cpp
Normal 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";
|
||||
}
|
||||
12
examples/output_types/bitstring.cpp
Normal file
12
examples/output_types/bitstring.cpp
Normal 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";
|
||||
}
|
||||
26
examples/output_types/custom.cpp
Normal file
26
examples/output_types/custom.cpp
Normal 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";
|
||||
}
|
||||
11
examples/output_types/extended_types.cpp
Normal file
11
examples/output_types/extended_types.cpp
Normal 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";
|
||||
}
|
||||
11
examples/output_types/integral_types.cpp
Normal file
11
examples/output_types/integral_types.cpp
Normal 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";
|
||||
}
|
||||
18
examples/output_types/wildcard.cpp
Normal file
18
examples/output_types/wildcard.cpp
Normal 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));
|
||||
}
|
||||
11
examples/output_types/xor_wrapper.cpp
Normal file
11
examples/output_types/xor_wrapper.cpp
Normal 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";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue