#include #include #include #include #include "dpf.hpp" #include "dpf/app_flow.hpp" #include "dpf/app_plans.hpp" // Express, the mailbox write (Eskandarian, Corrigan-Gibbs, Zaharia, Boneh, // USENIX Security 2021 ยง3.1). Two servers hold XOR shares of every mailbox // row. The client sends one `blob` DPF key each. Each server adds its // expansion into its share and folds the one-hot audit in the same walk. // // c++ -std=c++17 -march=native -I include -I thirdparty \ // examples/applications/express.cpp namespace { constexpr std::size_t nboxes = 256; constexpr std::size_t row_bytes = 100; using row_t = dpf::blob; } // namespace int main() { constexpr std::uint8_t address = 9; row_t message{}; for (std::size_t i = 0; i < row_bytes; ++i) message.bytes[i] = static_cast(i + 1); auto [k0, k1] = dpf::make_dpf(address, message); std::vector box0(nboxes), box1(nboxes); // One-pass caller fold: count how many non-zero shares each server sees. std::size_t hot0 = 0, hot1 = 0; dpf::eval_full_add_into(box0, k0, [&](std::size_t, const row_t & s) { if (s != row_t{}) ++hot0; }); dpf::eval_full_add_into(box1, k1, [&](std::size_t, const row_t & s) { if (s != row_t{}) ++hot1; }); (void)hot0; (void)hot1; if ((box0[address] ^ box1[address]) != message) { std::cerr << "express mailbox\n"; return 1; } if ((box0[0] ^ box1[0]) != row_t{}) { std::cerr << "express neighbor\n"; return 1; } // fp61 one-hot audit on a parallel extractable key (same walk shape). auto [a0, a1] = dpf::make_dpf(address, dpf::fp61{1}, dpf::extractable{}); std::vector challenge(nboxes); for (std::size_t i = 0; i < nboxes; ++i) challenge[i] = dpf::fp61{static_cast(i + 1)}; std::vector audit0(nboxes), audit1(nboxes); dpf::sketch_share s0{}, s1{}; dpf::eval_full_add_into(audit0, a0, dpf::sketch(s0, challenge)); dpf::eval_full_add_into(audit1, a1, dpf::sketch(s1, challenge)); if (!dpf::sketch_verify(s0, s1)) { std::cerr << "express audit\n"; return 1; } { if (int rc = dpf::app::run_measured("express", dpf::protocol::mailbox_write_fused_plan(0, 8), 8)) return rc; } std::cout << static_cast(message.bytes[0]) << "\n"; return 0; }