Checkpoint the party/runtime stack before share-program and malicious-mode work.
Ship the TLS mesh, composer, Beaver/Yao/leaf MPC, prep/online paths, apps, and docs so the tree is pushable before elevating share_expr, security_mode, and prep resume. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
695f8e84f7
commit
0d22946a0e
1835 changed files with 170291 additions and 2849 deletions
399
test/tests/vdpf_regression_test.cpp
Normal file
399
test/tests/vdpf_regression_test.cpp
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
/// @file vdpf_regression_test.cpp
|
||||
/// @brief Holistic VDPF regressions from DCF/Grotto proof bring-up failures.
|
||||
/// @details Patterns covered:
|
||||
/// - path-memo re-fold cancel (blocked parks / native spine)
|
||||
/// - off-path vs on-path blocked proves (CS level vs checkpoint index)
|
||||
/// - domain-tag survival past `hash_node` level masking
|
||||
/// - keygen `make_cs` level must match fold level
|
||||
/// - warm interval memoizer must not skip upper proof folds
|
||||
/// - multi-endpoint signed/unsigned prefix aggregates
|
||||
/// - endpoint-equal-alpha prefix stability across RNG draws
|
||||
#include <gtest/gtest.h>
|
||||
#include <tuple>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "grotto/prefix_parity.hpp"
|
||||
#include "grotto/offset_horner.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using Input = std::uint8_t;
|
||||
|
||||
bool tokens_equal(const dpf::proof_token & a, const dpf::proof_token & b)
|
||||
{
|
||||
return dpf::detail::vdpf::proof_equal(a, b);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// --- Domain separation / CS tagging ---------------------------------------
|
||||
|
||||
TEST(VdpfRegression, HashNodeRetainsHighLevelBits)
|
||||
{
|
||||
// fold_spine_tag is bit 15; masking to 8 bits would drop it and make
|
||||
// blocked CS verify against native folds.
|
||||
constexpr std::size_t tagged =
|
||||
dpf::detail::blocked::fold_spine_tag | std::size_t{3};
|
||||
const simde__m128i seed = simde_mm_set_epi64x(0x1111, 0x2222);
|
||||
const auto h_native = dpf::detail::vdpf::hash_node(3, 0x2a, seed);
|
||||
const auto h_tagged = dpf::detail::vdpf::hash_node(tagged, 0x2a, seed);
|
||||
EXPECT_NE(std::memcmp(&h_native, &h_tagged, sizeof(h_native)), 0);
|
||||
}
|
||||
|
||||
TEST(VdpfRegression, BlockedKeygenCsUsesSpineTag)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x2a},
|
||||
dpf::block_width<4>(dpf::lt(std::uint64_t{1})), dpf::verifiable{});
|
||||
auto [n0, n1] = dpf::make_dpf(Input{0x2a}, dpf::lt(std::uint64_t{1}),
|
||||
dpf::verifiable{});
|
||||
// Public CS arrays must diverge: blocked keygen tags make_cs levels.
|
||||
EXPECT_NE(std::memcmp(k0.correction_seeds().data(),
|
||||
n0.correction_seeds().data(),
|
||||
sizeof(decltype(k0)::correction_seeds_array)),
|
||||
0);
|
||||
(void)k1;
|
||||
(void)n1;
|
||||
}
|
||||
|
||||
// --- Path-memo idempotence (re-fold cancel) --------------------------------
|
||||
|
||||
TEST(VdpfRegression, BlockedEvalShareProveIsIdempotentOnWarmPath)
|
||||
{
|
||||
// Re-folding parked siblings on a warm path XORs them out of the token.
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x2a},
|
||||
dpf::block_width<4>(dpf::lt(std::uint64_t{1})), dpf::verifiable{});
|
||||
const Input x{0x11}; // off-path, parks right children
|
||||
dpf::proof_token a{}, b{};
|
||||
dpf::detail::vdpf::init_proof(a, k0);
|
||||
dpf::detail::vdpf::init_proof(b, k1);
|
||||
auto p0 = dpf::make_basic_path_memoizer(k0);
|
||||
auto p1 = dpf::make_basic_path_memoizer(k1);
|
||||
dpf::detail::blocked::eval_share(k0, x, p0, &a);
|
||||
dpf::detail::blocked::eval_share(k1, x, p1, &b);
|
||||
EXPECT_TRUE(dpf::verify(a, b));
|
||||
const auto once0 = a;
|
||||
const auto once1 = b;
|
||||
dpf::detail::blocked::eval_share(k0, x, p0, &a);
|
||||
dpf::detail::blocked::eval_share(k1, x, p1, &b);
|
||||
EXPECT_TRUE(tokens_equal(a, once0));
|
||||
EXPECT_TRUE(tokens_equal(b, once1));
|
||||
EXPECT_TRUE(dpf::verify(a, b));
|
||||
}
|
||||
|
||||
TEST(VdpfRegression, NativePathProveIsIdempotentOnWarmPath)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x2a}, dpf::lt(std::uint64_t{1}),
|
||||
dpf::verifiable{});
|
||||
const Input x{0x11};
|
||||
dpf::proof_token a{}, b{};
|
||||
dpf::detail::vdpf::init_proof(a, k0);
|
||||
dpf::detail::vdpf::init_proof(b, k1);
|
||||
auto p0 = dpf::make_basic_path_memoizer(k0);
|
||||
auto p1 = dpf::make_basic_path_memoizer(k1);
|
||||
dpf::detail::ensure_level(k0, x, p0, decltype(k0)::depth, &a);
|
||||
dpf::detail::ensure_level(k1, x, p1, decltype(k1)::depth, &b);
|
||||
const auto once0 = a;
|
||||
const auto once1 = b;
|
||||
dpf::detail::ensure_level(k0, x, p0, decltype(k0)::depth, &a);
|
||||
dpf::detail::ensure_level(k1, x, p1, decltype(k1)::depth, &b);
|
||||
EXPECT_TRUE(tokens_equal(a, once0));
|
||||
EXPECT_TRUE(tokens_equal(b, once1));
|
||||
EXPECT_TRUE(dpf::verify(a, b));
|
||||
}
|
||||
|
||||
TEST(VdpfRegression, PublicProveOnWarmPathMatchesColdNonZero)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x2a}, std::uint64_t{9},
|
||||
dpf::verifiable{});
|
||||
const Input x{0x2a};
|
||||
auto path0 = dpf::make_basic_path_memoizer(k0);
|
||||
auto path1 = dpf::make_basic_path_memoizer(k1);
|
||||
dpf::proof_token cold0{}, cold1{};
|
||||
(void)*dpf::eval_point(k0, x, dpf::prove(cold0));
|
||||
(void)*dpf::eval_point(k1, x, dpf::prove(cold1));
|
||||
EXPECT_TRUE(dpf::verify(cold0, cold1));
|
||||
EXPECT_FALSE(tokens_equal(cold0, dpf::detail::vdpf::zero_proof()));
|
||||
|
||||
(void)*dpf::eval_point(k0, x, path0);
|
||||
(void)*dpf::eval_point(k1, x, path1);
|
||||
dpf::proof_token warm0{}, warm1{};
|
||||
(void)*dpf::eval_point(k0, x, dpf::prove(warm0), path0);
|
||||
(void)*dpf::eval_point(k1, x, dpf::prove(warm1), path1);
|
||||
EXPECT_TRUE(dpf::verify(warm0, warm1));
|
||||
EXPECT_TRUE(tokens_equal(warm0, cold0));
|
||||
EXPECT_TRUE(tokens_equal(warm1, cold1));
|
||||
EXPECT_FALSE(dpf::verify(dpf::detail::vdpf::zero_proof(),
|
||||
dpf::detail::vdpf::zero_proof()));
|
||||
}
|
||||
|
||||
TEST(VdpfRegression, BlockedMultiEndpointSignedPrefixKeepsSharedParks)
|
||||
{
|
||||
// Two endpoints that share a left turn: without resume-aware park folds
|
||||
// the second walk cancels the first's parked contribution.
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x40},
|
||||
dpf::block_width<4>(dpf::gt(std::uint64_t{1})), dpf::verifiable{});
|
||||
// Both 0x10 and 0x18 start with MSB bits that park the same early sibling
|
||||
// under a typical block schedule on uint8.
|
||||
const std::array<Input, 2> ends{Input{0x10}, Input{0x18}};
|
||||
|
||||
dpf::proof_token multi0{}, multi1{};
|
||||
auto s0 = grotto::signed_prefix_parities(k0, ends, dpf::prove(multi0));
|
||||
auto s1 = grotto::signed_prefix_parities(k1, ends, dpf::prove(multi1));
|
||||
EXPECT_TRUE(dpf::verify(multi0, multi1));
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
EXPECT_EQ((s0[i] + s1[i]) & k0.cmp().mask,
|
||||
(dpf::eval_point(dpf::cmp, k0, ends[i]).raw()
|
||||
+ dpf::eval_point(dpf::cmp, k1, ends[i]).raw())
|
||||
& k0.cmp().mask);
|
||||
|
||||
// Reference: fold e0 then e1 on one path without re-init (same as API).
|
||||
dpf::proof_token ref0{}, ref1{};
|
||||
dpf::detail::vdpf::init_proof(ref0, k0);
|
||||
dpf::detail::vdpf::init_proof(ref1, k1);
|
||||
auto p0 = dpf::make_basic_path_memoizer(k0);
|
||||
auto p1 = dpf::make_basic_path_memoizer(k1);
|
||||
dpf::detail::blocked::eval_share(k0, ends[0], p0, &ref0);
|
||||
dpf::detail::blocked::eval_share(k0, ends[1], p0, &ref0);
|
||||
dpf::detail::blocked::eval_share(k1, ends[0], p1, &ref1);
|
||||
dpf::detail::blocked::eval_share(k1, ends[1], p1, &ref1);
|
||||
dpf::detail::vdpf::fold_output_binding(ref0, k0);
|
||||
dpf::detail::vdpf::fold_output_binding(ref1, k1);
|
||||
EXPECT_TRUE(tokens_equal(multi0, ref0));
|
||||
EXPECT_TRUE(tokens_equal(multi1, ref1));
|
||||
|
||||
// Replaying only the tip endpoint on the warm path is idempotent.
|
||||
dpf::proof_token path0{}, path1{};
|
||||
dpf::detail::vdpf::init_proof(path0, k0);
|
||||
dpf::detail::vdpf::init_proof(path1, k1);
|
||||
auto q0 = dpf::make_basic_path_memoizer(k0);
|
||||
auto q1 = dpf::make_basic_path_memoizer(k1);
|
||||
dpf::detail::blocked::eval_share(k0, ends[0], q0, &path0);
|
||||
dpf::detail::blocked::eval_share(k0, ends[1], q0, &path0);
|
||||
dpf::detail::blocked::eval_share(k1, ends[0], q1, &path1);
|
||||
dpf::detail::blocked::eval_share(k1, ends[1], q1, &path1);
|
||||
const auto path_once0 = path0;
|
||||
const auto path_once1 = path1;
|
||||
dpf::detail::blocked::eval_share(k0, ends[1], q0, &path0);
|
||||
dpf::detail::blocked::eval_share(k1, ends[1], q1, &path1);
|
||||
EXPECT_TRUE(tokens_equal(path0, path_once0));
|
||||
EXPECT_TRUE(tokens_equal(path1, path_once1));
|
||||
}
|
||||
|
||||
// --- Off-path / on-path / all-ones blocked point ---------------------------
|
||||
|
||||
TEST(VdpfRegression, BlockedPointProveOffPathOnPathAndAllOnes)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x2a},
|
||||
dpf::block_width<4>(dpf::lt(std::uint64_t{1})), dpf::verifiable{});
|
||||
const Input queries[] = {
|
||||
Input{0x2a}, // on-path
|
||||
Input{0x11}, // off-path with parks
|
||||
Input{0xff}, // never parks (all right)
|
||||
Input{0x00}, // parks every level
|
||||
};
|
||||
for (Input x : queries)
|
||||
{
|
||||
dpf::proof_token a{}, b{};
|
||||
dpf::eval_point(dpf::cmp, k0, x, dpf::prove(a));
|
||||
dpf::eval_point(dpf::cmp, k1, x, dpf::prove(b));
|
||||
EXPECT_TRUE(dpf::verify(a, b)) << "query=" << int(x);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VdpfRegression, BlockedTokenDiffersFromNativeForSameAlpha)
|
||||
{
|
||||
const Input alpha{0x2a};
|
||||
const Input x{0x11};
|
||||
auto [b0, b1] = dpf::make_dpf(alpha,
|
||||
dpf::block_width<4>(dpf::lt(std::uint64_t{1})), dpf::verifiable{});
|
||||
auto [n0, n1] = dpf::make_dpf(alpha, dpf::lt(std::uint64_t{1}),
|
||||
dpf::verifiable{});
|
||||
dpf::proof_token bp0{}, bp1{}, np0{}, np1{};
|
||||
dpf::eval_point(dpf::cmp, b0, x, dpf::prove(bp0));
|
||||
dpf::eval_point(dpf::cmp, b1, x, dpf::prove(bp1));
|
||||
dpf::eval_point(dpf::cmp, n0, x, dpf::prove(np0));
|
||||
dpf::eval_point(dpf::cmp, n1, x, dpf::prove(np1));
|
||||
EXPECT_TRUE(dpf::verify(bp0, bp1));
|
||||
EXPECT_TRUE(dpf::verify(np0, np1));
|
||||
EXPECT_FALSE(tokens_equal(bp0, np0));
|
||||
}
|
||||
|
||||
// --- Warm interval memoizer ------------------------------------------------
|
||||
|
||||
TEST(VdpfRegression, CmpIntervalProveIgnoresWarmMemoizer)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x20}, dpf::lt(std::uint64_t{1}),
|
||||
dpf::verifiable{});
|
||||
using Key = std::decay_t<decltype(k0)>;
|
||||
const Input lo{0x10};
|
||||
const Input hi{0x28};
|
||||
|
||||
dpf::proof_token cold0{}, cold1{};
|
||||
dpf::prove_cmp_interval(k0, lo, hi, dpf::prove(cold0));
|
||||
dpf::prove_cmp_interval(k1, lo, hi, dpf::prove(cold1));
|
||||
EXPECT_TRUE(dpf::verify(cold0, cold1));
|
||||
|
||||
// Warm a full-tree memo on a wider interval, then prove on [lo,hi]
|
||||
// through the same memo. Proving must clear/revisit upper levels.
|
||||
constexpr std::size_t stop =
|
||||
Key::cmp_depth == 0 ? Key::depth : Key::cmp_depth;
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::detail::incr::cmp_full_interval_memo<Key, stop> memo0{256};
|
||||
dpf::detail::incr::cmp_full_interval_memo<Key, stop> memo1{256};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto warm_buf0 =
|
||||
dpf::make_output_buffer(dpf::cmp, k0, Input{0x00}, Input{0x3f});
|
||||
auto warm_buf1 =
|
||||
dpf::make_output_buffer(dpf::cmp, k1, Input{0x00}, Input{0x3f});
|
||||
dpf::eval_interval(dpf::cmp, k0, Input{0x00}, Input{0x3f}, warm_buf0,
|
||||
memo0);
|
||||
dpf::eval_interval(dpf::cmp, k1, Input{0x00}, Input{0x3f}, warm_buf1,
|
||||
memo1);
|
||||
|
||||
auto buf0 = dpf::make_output_buffer(dpf::cmp, k0, lo, hi);
|
||||
auto buf1 = dpf::make_output_buffer(dpf::cmp, k1, lo, hi);
|
||||
dpf::proof_token warm0{}, warm1{};
|
||||
dpf::eval_interval(dpf::cmp, k0, lo, hi, buf0, memo0, dpf::prove(warm0));
|
||||
dpf::eval_interval(dpf::cmp, k1, lo, hi, buf1, memo1, dpf::prove(warm1));
|
||||
EXPECT_TRUE(dpf::verify(warm0, warm1));
|
||||
EXPECT_TRUE(tokens_equal(cold0, warm0));
|
||||
EXPECT_TRUE(tokens_equal(cold1, warm1));
|
||||
}
|
||||
|
||||
// --- Sequence / path-memo aggregate without re-init ------------------------
|
||||
|
||||
TEST(VdpfRegression, CmpSequenceProveMatchesIntervalRunCovers)
|
||||
{
|
||||
// prove_cmp_sequence folds contiguous runs as intervals, not point walks.
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x55}, dpf::gt(std::uint64_t{1}),
|
||||
dpf::verifiable{});
|
||||
const Input xs[] = {0x10, 0x11, 0x40, 0x41};
|
||||
|
||||
dpf::proof_token seq0{}, seq1{};
|
||||
dpf::prove_cmp_sequence(k0, std::begin(xs), std::end(xs), dpf::prove(seq0));
|
||||
dpf::prove_cmp_sequence(k1, std::begin(xs), std::end(xs), dpf::prove(seq1));
|
||||
EXPECT_TRUE(dpf::verify(seq0, seq1));
|
||||
|
||||
dpf::proof_token runs0{}, runs1{};
|
||||
dpf::detail::vdpf::init_proof(runs0, k0);
|
||||
dpf::detail::vdpf::init_proof(runs1, k1);
|
||||
dpf::detail::incr::prove_fold_cmp_interval(k0, Input{0x10}, Input{0x11},
|
||||
runs0);
|
||||
dpf::detail::incr::prove_fold_cmp_interval(k0, Input{0x40}, Input{0x41},
|
||||
runs0);
|
||||
dpf::detail::incr::prove_fold_cmp_interval(k1, Input{0x10}, Input{0x11},
|
||||
runs1);
|
||||
dpf::detail::incr::prove_fold_cmp_interval(k1, Input{0x40}, Input{0x41},
|
||||
runs1);
|
||||
dpf::detail::vdpf::fold_output_binding(runs0, k0);
|
||||
dpf::detail::vdpf::fold_output_binding(runs1, k1);
|
||||
EXPECT_TRUE(tokens_equal(seq0, runs0));
|
||||
EXPECT_TRUE(tokens_equal(seq1, runs1));
|
||||
|
||||
// eval_sequence(cmp, ..., prove) uses path-memo point folds — a different
|
||||
// transcript from interval-run covers. Both must verify; they need not match.
|
||||
auto buf0 = dpf::make_output_buffer(dpf::cmp, k0, 4);
|
||||
auto buf1 = dpf::make_output_buffer(dpf::cmp, k1, 4);
|
||||
dpf::proof_token e0{}, e1{};
|
||||
dpf::eval_sequence(dpf::cmp, k0, std::begin(xs), std::end(xs), buf0,
|
||||
dpf::prove(e0));
|
||||
dpf::eval_sequence(dpf::cmp, k1, std::begin(xs), std::end(xs), buf1,
|
||||
dpf::prove(e1));
|
||||
EXPECT_TRUE(dpf::verify(e0, e1));
|
||||
EXPECT_FALSE(tokens_equal(seq0, e0));
|
||||
}
|
||||
|
||||
// --- Unsigned prefix vs resumed point folds --------------------------------
|
||||
|
||||
TEST(VdpfRegression, UnsignedPrefixTokenMatchesResumedPointFolds)
|
||||
{
|
||||
// Bit payload: unsigned prefix parity is a bit-DPF / XOR gadget.
|
||||
auto [k0, k1] = dpf::make_dpf(Input{0x2a}, dpf::bit{1}, dpf::verifiable{});
|
||||
const std::array<Input, 3> ends{Input{0x10}, Input{0x2b}, Input{0x40}};
|
||||
|
||||
dpf::proof_token pref0{}, pref1{};
|
||||
auto [p0, n0] = grotto::prefix_parities(k0, ends, dpf::prove(pref0));
|
||||
auto [p1, n1] = grotto::prefix_parities(k1, ends, dpf::prove(pref1));
|
||||
(void)n0;
|
||||
(void)n1;
|
||||
EXPECT_TRUE(dpf::verify(pref0, pref1));
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
EXPECT_EQ(p0[i] ^ p1[i], ends[i] > Input{0x2a});
|
||||
|
||||
const auto again0 = pref0;
|
||||
const auto again1 = pref1;
|
||||
grotto::prefix_parities(k0, ends, dpf::prove(pref0));
|
||||
grotto::prefix_parities(k1, ends, dpf::prove(pref1));
|
||||
EXPECT_TRUE(tokens_equal(pref0, again0));
|
||||
EXPECT_TRUE(tokens_equal(pref1, again1));
|
||||
}
|
||||
|
||||
TEST(VdpfRegression, PrefixParityAtAlphaIsExclusiveAndStable)
|
||||
{
|
||||
// Exclusive of alpha: endpoint == alpha must reconstruct to 0 for every
|
||||
// key. A uint64 payload is the wrong gadget type and used to look "flaky".
|
||||
const Input alpha{0x2a};
|
||||
const std::array<Input, 1> ends{alpha};
|
||||
for (int t = 0; t < 32; ++t)
|
||||
{
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::bit{1});
|
||||
auto [p0, n0] = grotto::prefix_parities(k0, ends);
|
||||
auto [p1, n1] = grotto::prefix_parities(k1, ends);
|
||||
(void)n0;
|
||||
(void)n1;
|
||||
EXPECT_FALSE(p0[0] ^ p1[0]) << "trial " << t;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Offset Horner / poly multi-power batch --------------------------------
|
||||
|
||||
TEST(VdpfRegression, OffsetHornerPerPowerTokensIndependent)
|
||||
{
|
||||
constexpr std::size_t D = 2;
|
||||
const Input center = 12;
|
||||
auto mat = grotto::make_offset_horner_keys<Input, D>(center, dpf::verifiable{});
|
||||
const std::vector<Input> knots{0, 10, 50};
|
||||
const std::vector<std::array<std::uint64_t, D + 1>> coeff{
|
||||
{1, 0, 0}, {0, 2, 0}, {7, 1, 3}};
|
||||
const Input eta = 3;
|
||||
dpf::proof_token t0[D + 1]{}, t1[D + 1]{};
|
||||
const auto v0 = grotto::offset_horner_eval<0, D, Input, true>(
|
||||
mat, knots, coeff, eta, t0);
|
||||
const auto v1 = grotto::offset_horner_eval<1, D, Input, true>(
|
||||
mat, knots, coeff, eta, t1);
|
||||
EXPECT_EQ(v0 + v1, grotto::offset_horner_clear<D>(center, knots, coeff, eta));
|
||||
for (std::size_t m = 0; m <= D; ++m)
|
||||
EXPECT_TRUE(dpf::verify(t0[m], t1[m]));
|
||||
// Tamper power 1 only; other powers still verify.
|
||||
t0[1][0] = simde_mm_xor_si128(t0[1][0], simde_mm_set1_epi8(0x7e));
|
||||
EXPECT_FALSE(dpf::verify(t0[1], t1[1]));
|
||||
EXPECT_TRUE(dpf::verify(t0[0], t1[0]));
|
||||
EXPECT_TRUE(dpf::verify(t0[2], t1[2]));
|
||||
}
|
||||
|
||||
TEST(VdpfRegression, SignedPrefixBlockedProveValuesMatchDense)
|
||||
{
|
||||
auto [b0, b1] = dpf::make_dpf(Input{0x30},
|
||||
dpf::block_width<4>(dpf::gt(std::uint64_t{1})), dpf::verifiable{});
|
||||
auto [d0, d1] = dpf::make_dpf(Input{0x30}, dpf::gt(std::uint64_t{1}),
|
||||
dpf::verifiable{});
|
||||
const std::array<Input, 3> ends{Input{0x10}, Input{0x20}, Input{0x50}};
|
||||
dpf::proof_token bp0{}, bp1{};
|
||||
auto bs0 = grotto::signed_prefix_parities(b0, ends, dpf::prove(bp0));
|
||||
auto bs1 = grotto::signed_prefix_parities(b1, ends, dpf::prove(bp1));
|
||||
EXPECT_TRUE(dpf::verify(bp0, bp1));
|
||||
auto ds0 = grotto::signed_prefix_parities(d0, ends);
|
||||
auto ds1 = grotto::signed_prefix_parities(d1, ends);
|
||||
for (std::size_t i = 0; i < ends.size(); ++i)
|
||||
{
|
||||
EXPECT_EQ((bs0[i] + bs1[i]) & b0.cmp().mask,
|
||||
(ds0[i] + ds1[i]) & d0.cmp().mask);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue