73 lines
2.4 KiB
C++
73 lines
2.4 KiB
C++
|
|
#include <cstdint>
|
||
|
|
#include <iostream>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "dpf.hpp"
|
||
|
|
#include "dpf/app_flow.hpp"
|
||
|
|
#include "dpf/app_plans.hpp"
|
||
|
|
|
||
|
|
// Pika, the lookup (Wagh, PoPETs 2022, Fig. 1). Party P2 is the dealer.
|
||
|
|
// P2 keys a unit DPF at a fresh index r and shares r. P0 and P1 open
|
||
|
|
// x = r - a, and take the inner product of the DPF with the table rotated
|
||
|
|
// by x. A word payload of 1 reconstructs to +1. A 1-bit payload lifts to
|
||
|
|
// +1 or -1; the dealer reads that sign off Gen's final control bit.
|
||
|
|
//
|
||
|
|
// The rotation is folded into the walk with `dpf::rotate{s}` (no rotated
|
||
|
|
// copy of the table), and the sign is recorded at keygen with
|
||
|
|
// `dpf::unit_sign` (no evaluator-side eval_point).
|
||
|
|
//
|
||
|
|
// c++ -std=c++17 -march=native -I include -I thirdparty \
|
||
|
|
// examples/applications/pika.cpp
|
||
|
|
|
||
|
|
int main()
|
||
|
|
{
|
||
|
|
constexpr std::size_t n = 256;
|
||
|
|
constexpr std::uint8_t r = 50;
|
||
|
|
constexpr std::uint8_t a0 = 10;
|
||
|
|
constexpr std::uint8_t a1 = 7;
|
||
|
|
constexpr std::uint8_t a = static_cast<std::uint8_t>(a0 + a1);
|
||
|
|
constexpr std::uint8_t x = static_cast<std::uint8_t>(r - a);
|
||
|
|
|
||
|
|
std::vector<std::uint64_t> table(n);
|
||
|
|
for (std::size_t i = 0; i < n; ++i)
|
||
|
|
table[i] = static_cast<std::uint64_t>(i) * i;
|
||
|
|
|
||
|
|
// Lookup: DPF at r dotted with the table read at (i - x) mod n, i.e.
|
||
|
|
// rotated by s = (n - x) mod n. The walk applies the offset; no copy.
|
||
|
|
auto [k0, k1] = dpf::make_dpf(r, std::uint64_t{1});
|
||
|
|
const std::size_t s = (n - static_cast<std::size_t>(x)) % n;
|
||
|
|
const auto value = dpf::reconstruct(
|
||
|
|
dpf::eval_full_inner_product(dpf::paired, k0, table, dpf::rotate{s}),
|
||
|
|
dpf::eval_full_inner_product(dpf::paired, k1, table, dpf::rotate{s}));
|
||
|
|
if (value != table[a])
|
||
|
|
{
|
||
|
|
std::cerr << "pika lookup\n";
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// The early-stop bit leaf. The dealer, who sees both keys, records a
|
||
|
|
// sign of +1 or -1 at r via `unit_sign`; the evaluators never open r.
|
||
|
|
int w0 = 0, w1 = 0;
|
||
|
|
auto [b0, b1] = dpf::make_dpf(r, dpf::bit::one, dpf::unit_sign{w0, w1});
|
||
|
|
const int sign = w0 - w1;
|
||
|
|
if (sign != 1 && sign != -1)
|
||
|
|
{
|
||
|
|
std::cerr << "pika sign\n";
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
if (dpf::reconstruct(*dpf::eval_point(k0, r), *dpf::eval_point(k1, r)) != 1)
|
||
|
|
{
|
||
|
|
std::cerr << "pika unit\n";
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
if (int rc = dpf::app::run_measured("pika",
|
||
|
|
dpf::protocol::pika_lookup_plan(0, 8, 3), 5))
|
||
|
|
return rc;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::cout << value << "\n";
|
||
|
|
return 0;
|
||
|
|
}
|