Initial import of libdpf.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-24 14:08:32 -06:00
commit e4e666f459
4563 changed files with 1690372 additions and 0 deletions

View file

@ -0,0 +1,143 @@
#include <gtest/gtest.h>
#include "dpf.hpp"
#include "grotto/constant_lut.hpp"
#include "grotto/prefix_parity.hpp"
#include <array>
#include <cstdint>
#include <vector>
namespace
{
uint64_t opened(uint64_t a, uint64_t b, uint64_t mask)
{
return (a + b) & mask;
}
template <typename T, std::size_t N>
int piece_containing(T alpha, const std::array<T, N> & ends)
{
for (std::size_t i = 0; i + 1 < N; ++i)
{
if (alpha >= ends[i] && alpha < ends[i + 1])
return static_cast<int>(i);
}
return static_cast<int>(N - 1);
}
} // namespace
TEST(SignedPrefix, MatchesComparisonEvalOnEveryUint8Point)
{
const uint8_t alpha = 0x3c;
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(uint64_t{1}));
const uint64_t mask = k0.cmp().mask;
std::array<uint8_t, 8> ends{0, 1, 10, alpha, 100, 200, 254, 255};
const auto p0 = grotto::signed_prefix_parities(k0, ends);
const auto p1 = grotto::signed_prefix_parities(k1, ends);
for (std::size_t i = 0; i < ends.size(); ++i)
{
const auto e0 = dpf::eval_point(dpf::cmp, k0, ends[i]);
const auto e1 = dpf::eval_point(dpf::cmp, k1, ends[i]);
EXPECT_EQ(p0[i], e0.raw()) << int(ends[i]);
EXPECT_EQ(p1[i], e1.raw()) << int(ends[i]);
EXPECT_EQ(opened(p0[i], p1[i], mask), ends[i] > alpha ? 1u : 0u);
}
}
TEST(SignedPrefix, SegmentsAreOneHot)
{
const uint8_t alpha = 40;
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(uint64_t{1}));
const uint64_t mask = k0.cmp().mask;
const std::array<uint8_t, 5> ends{0, 1, 10, 40, 200};
const auto s0 = grotto::signed_segment_parities(k0, ends);
const auto s1 = grotto::signed_segment_parities(k1, ends);
const int hot = piece_containing(alpha, ends);
uint64_t sum = 0;
for (std::size_t i = 0; i < ends.size(); ++i)
{
const uint64_t bit = opened(s0[i], s1[i], mask);
sum = (sum + bit) & mask;
EXPECT_EQ(bit, i == static_cast<std::size_t>(hot) ? 1u : 0u) << i;
}
EXPECT_EQ(sum, 1u);
for (uint8_t a : {uint8_t{0}, uint8_t{1}, uint8_t{9}, uint8_t{200}, uint8_t{255}})
{
auto [a0, a1] = dpf::make_dpf(a, dpf::gt(uint64_t{1}));
const auto t0 = grotto::signed_segment_parities(a0, ends);
const auto t1 = grotto::signed_segment_parities(a1, ends);
const int where = piece_containing(a, ends);
for (std::size_t i = 0; i < ends.size(); ++i)
EXPECT_EQ(opened(t0[i], t1[i], mask), i == static_cast<std::size_t>(where) ? 1u : 0u)
<< "alpha=" << int(a) << " piece=" << i;
}
}
TEST(SignedPrefix, WholeDomainIsThePublicOne)
{
auto [k0, k1] = dpf::make_dpf(uint8_t{7}, dpf::gt(uint64_t{1}));
const std::array<uint8_t, 1> ends{0};
const auto s0 = grotto::signed_segment_parities(k0, ends);
const auto s1 = grotto::signed_segment_parities(k1, ends);
EXPECT_EQ(opened(s0[0], s1[0], k0.cmp().mask), 1u);
}
TEST(SignedPrefix, SignumLutIsSignCorrect)
{
for (int alpha = -128; alpha <= 127; ++alpha)
{
const auto a = static_cast<int8_t>(alpha);
auto [k0, k1] = dpf::make_dpf(a, dpf::gt(uint64_t{1}));
const auto lut = grotto::make_exact_constant_lut<int8_t>(
grotto::exact_constant::signum, 0);
ASSERT_EQ(lut.bounds.size(), 3u);
std::array<int8_t, 3> ends{};
for (std::size_t i = 0; i < 3; ++i)
ends[i] = lut.bounds[i];
const auto s0 = grotto::signed_segment_parities(k0, ends);
const auto s1 = grotto::signed_segment_parities(k1, ends);
uint64_t acc0 = 0;
uint64_t acc1 = 0;
for (std::size_t i = 0; i < 3; ++i)
{
const auto coef = static_cast<uint64_t>(lut.values[i]);
acc0 += s0[i] * coef;
acc1 += s1[i] * coef;
}
const auto got = static_cast<int64_t>(acc0 + acc1);
const int64_t want = alpha < 0 ? -1 : (alpha > 0 ? 1 : 0);
EXPECT_EQ(got, want) << alpha;
// The advice-bit lift is ±want. The DCF shares must not come out negated.
if (want != 0)
EXPECT_NE(got, -want) << alpha;
}
}
TEST(SignedPrefix, SharedPrefixAgreesWithAFreshWalk)
{
const uint16_t alpha = 0x0100;
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(uint64_t{1}));
// Consecutive knots share a long prefix; the cached sum must match a
// one-knot walk.
const std::array<uint16_t, 4> ends{0, 1, 0x0100, 0x0101};
const auto many = grotto::signed_prefix_parities(k0, ends);
for (std::size_t i = 0; i < ends.size(); ++i)
{
const std::array<uint16_t, 1> one{ends[i]};
const auto alone = grotto::signed_prefix_parities(k0, one);
EXPECT_EQ(many[i], alone[0]) << i;
}
(void)k1;
}
TEST(SignedPrefix, RejectsAKeyWithoutAComparison)
{
auto [k0, k1] = dpf::make_dpf(uint8_t{1}, dpf::bit::one);
const std::array<uint8_t, 2> ends{0, 1};
EXPECT_THROW(grotto::signed_prefix_parities(k0, ends), std::invalid_argument);
EXPECT_THROW(grotto::signed_segment_parities(k1, ends), std::invalid_argument);
}