86 lines
2.7 KiB
C++
86 lines
2.7 KiB
C++
|
|
#include <array>
|
||
|
|
#include <cstddef>
|
||
|
|
#include <cstdint>
|
||
|
|
#include <iostream>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "dpf.hpp"
|
||
|
|
#include "dpf/app_flow.hpp"
|
||
|
|
#include "dpf/app_plans.hpp"
|
||
|
|
|
||
|
|
// A (2,3) ledger, the DPF step. Three servers replicate a ledger as
|
||
|
|
// Shamir-style (2-of-3) shares (this group's dpf3 / VDPF+ construction). Each
|
||
|
|
// append writes one point (slot -> amount) into all three shares; any two
|
||
|
|
// servers reconstruct a slot. A verifiable proof (verify_dpf3) rejects an
|
||
|
|
// append that is not a single well-formed point before it is applied.
|
||
|
|
//
|
||
|
|
// c++ -std=c++17 -march=native -I include -I thirdparty \
|
||
|
|
// examples/applications/ledger23.cpp
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
|
||
|
|
using dpf::fp61;
|
||
|
|
constexpr std::size_t nslots = 256; // uint8 slot domain
|
||
|
|
|
||
|
|
fp61 open2(fp61 a, fp61 b) // any two of three shares reconstruct
|
||
|
|
{
|
||
|
|
return dpf::shamir3::reconstruct(dpf::shamir3::share{1, a},
|
||
|
|
dpf::shamir3::share{2, b});
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
int main()
|
||
|
|
{
|
||
|
|
std::vector<fp61> l1(nslots), l2(nslots), l3(nslots);
|
||
|
|
|
||
|
|
// Each append is a verified (2,3) point key.
|
||
|
|
const std::pair<std::uint8_t, std::uint64_t> entries[] = {
|
||
|
|
{5, 100}, {40, 25}, {5, 7}};
|
||
|
|
for (auto [slot, amount] : entries)
|
||
|
|
{
|
||
|
|
auto [k1, k2, k3] = dpf::make_dpf3(slot, fp61{amount}, dpf::verifiable{});
|
||
|
|
if (!dpf::verify_dpf3(dpf::prove_dpf3(k1, slot),
|
||
|
|
dpf::prove_dpf3(k2, slot), dpf::prove_dpf3(k3, slot)))
|
||
|
|
{
|
||
|
|
std::cerr << "ledger append audit\n";
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
// Fold the (2,3) expansion into each party's ledger shares.
|
||
|
|
dpf::eval_full_add_into(l1, k1);
|
||
|
|
dpf::eval_full_add_into(l2, k2);
|
||
|
|
dpf::eval_full_add_into(l3, k3);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Slot 5 got two credits (100 + 7); slot 40 got 25; the rest are 0.
|
||
|
|
if (open2(l1[5], l2[5]) != fp61{107}
|
||
|
|
|| open2(l1[40], l2[40]) != fp61{25}
|
||
|
|
|| open2(l1[0], l2[0]).raw() != 0)
|
||
|
|
{
|
||
|
|
std::cerr << "ledger balance\n";
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// A proof that does not come from the same append is rejected: mixing one
|
||
|
|
// party's token from an independent key triple fails verification.
|
||
|
|
auto [b1, b2, b3] = dpf::make_dpf3(std::uint8_t{9}, fp61{1}, dpf::verifiable{});
|
||
|
|
auto [c1, c2, c3] = dpf::make_dpf3(std::uint8_t{9}, fp61{1}, dpf::verifiable{});
|
||
|
|
if (dpf::verify_dpf3(dpf::prove_dpf3(b1, std::uint8_t{9}),
|
||
|
|
dpf::prove_dpf3(b2, std::uint8_t{9}),
|
||
|
|
dpf::prove_dpf3(c3, std::uint8_t{9})))
|
||
|
|
{
|
||
|
|
std::cerr << "ledger accepted a bad append\n";
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
if (int rc = dpf::app::run_measured("ledger23",
|
||
|
|
dpf::protocol::ledger23_append_plan(0), 2))
|
||
|
|
return rc;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::cout << open2(l1[5], l2[5]).raw() << "\n";
|
||
|
|
return 0;
|
||
|
|
}
|