Document the new DPF surfaces in one command set, and test the field, half-tree, and multipoint edges.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
0d8a5a8131
commit
0dff6df8ed
250 changed files with 12199 additions and 1981 deletions
370
test/tests/arith_payload_test.cpp
Normal file
370
test/tests/arith_payload_test.cpp
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
simde__m128i g_roots[16];
|
||||
int g_ri = 0;
|
||||
simde__m128i take_root() { return g_roots[g_ri++]; }
|
||||
|
||||
struct Pad
|
||||
{
|
||||
uint64_t n = 1;
|
||||
simde__m128i block()
|
||||
{
|
||||
auto v = simde_mm_set_epi64x(static_cast<long long>(n),
|
||||
static_cast<long long>(n * 9 + 3));
|
||||
n += 2;
|
||||
return v;
|
||||
}
|
||||
uint8_t bit() { return static_cast<uint8_t>(n++ & 1u); }
|
||||
};
|
||||
|
||||
void reset_roots()
|
||||
{
|
||||
g_ri = 0;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
g_roots[i] = simde_mm_set_epi64x(0x2222 * (i + 1), 0xBEEF0000u + i * 13);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T bare(const T & v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t Party, dpf::sharing Scheme>
|
||||
T bare(const dpf::secret_share<T, Party, Scheme> & s)
|
||||
{
|
||||
return s.raw();
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
auto recon(const A & a, const B & b)
|
||||
{
|
||||
using T = decltype(bare(a));
|
||||
return static_cast<T>(bare(a) - bare(b));
|
||||
}
|
||||
|
||||
template <typename Key, typename In>
|
||||
auto ev(const Key & key, In x)
|
||||
{
|
||||
return bare(*dpf::eval_point(key, x));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ArithPayload, DsXorIndexMatchesDealer)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint32_t;
|
||||
const in_t alpha = 0x2a;
|
||||
const in_t x0 = 0x55;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const out_t beta = 0x01020304;
|
||||
const out_t y0 = 0x00010002;
|
||||
const out_t y1 = static_cast<out_t>(beta - y0);
|
||||
|
||||
reset_roots();
|
||||
auto dealer = dpf::make_dpf(alpha, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
beta);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(dpf::arith_output, x0, x1, rng, y0, y1);
|
||||
|
||||
using key_t = std::decay_t<decltype(dealer.first)>;
|
||||
EXPECT_EQ(std::memcmp(&dealer.first.root(), &ds.first.root(),
|
||||
sizeof(simde__m128i)), 0);
|
||||
EXPECT_EQ(std::memcmp(&dealer.second.root(), &ds.second.root(),
|
||||
sizeof(simde__m128i)), 0);
|
||||
for (std::size_t i = 0; i < key_t::depth; ++i)
|
||||
{
|
||||
EXPECT_EQ(std::memcmp(&dealer.first.correction_word(i),
|
||||
&ds.first.correction_word(i), sizeof(simde__m128i)), 0)
|
||||
<< "cw " << i;
|
||||
EXPECT_EQ(dealer.first.correction_advice(i),
|
||||
ds.first.correction_advice(i))
|
||||
<< "advice " << i;
|
||||
}
|
||||
EXPECT_EQ(std::memcmp(&dealer.first.leaf(), &ds.first.leaf(),
|
||||
sizeof(dealer.first.leaf())), 0);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
EXPECT_EQ(recon(ev(ds.first, q), ev(ds.second, q)),
|
||||
q == alpha ? beta : out_t{})
|
||||
<< i;
|
||||
EXPECT_EQ(ev(ds.first, q), ev(dealer.first, q)) << "p0 " << i;
|
||||
EXPECT_EQ(ev(ds.second, q), ev(dealer.second, q)) << "p1 " << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ArithPayload, DsArithIndexMatchesDealer)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint16_t;
|
||||
const in_t alpha = 0xc0;
|
||||
const in_t x0 = 0x40;
|
||||
const in_t x1 = static_cast<in_t>(alpha - x0);
|
||||
const out_t beta = 9;
|
||||
const out_t y0 = 3;
|
||||
const out_t y1 = 6;
|
||||
|
||||
reset_roots();
|
||||
auto dealer = dpf::make_dpf(alpha, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
beta);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(dpf::arith_input, dpf::arith_output,
|
||||
x0, x1, rng, y0, y1);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
EXPECT_EQ(recon(ev(ds.first, q), ev(ds.second, q)),
|
||||
q == alpha ? beta : out_t{})
|
||||
<< i;
|
||||
EXPECT_EQ(ev(ds.first, q), ev(dealer.first, q)) << "p0 " << i;
|
||||
EXPECT_EQ(ev(ds.second, q), ev(dealer.second, q)) << "p1 " << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ArithPayload, GenevalXorSharedBeta)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint16_t;
|
||||
const in_t alpha = 0x33;
|
||||
const in_t x0 = 0x0f;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const out_t beta = 0x77;
|
||||
const out_t y0 = 0x10;
|
||||
const out_t y1 = static_cast<out_t>(beta - y0);
|
||||
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf(alpha, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
beta);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> g_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto g = dpf::geneval_point(dpf::arith_output, x0, x1, alpha, g_rng, y0, y1);
|
||||
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
ASSERT_EQ(g.party0.size(), 1u);
|
||||
EXPECT_EQ(recon(g.party0[0], g.party1[0]), beta);
|
||||
EXPECT_EQ(g.party0[0], ev(keys.first, alpha));
|
||||
EXPECT_EQ(g.party1[0], ev(keys.second, alpha));
|
||||
}
|
||||
|
||||
TEST(ArithPayload, GenevalArithSharedBeta)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint16_t;
|
||||
const in_t alpha = 0x90;
|
||||
const in_t x0 = 0x20;
|
||||
const in_t x1 = static_cast<in_t>(alpha - x0);
|
||||
const out_t beta = 3;
|
||||
const out_t y0 = 1;
|
||||
const out_t y1 = 2;
|
||||
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf(alpha, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
beta);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> g_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto g = dpf::geneval_point(dpf::arith_input, dpf::arith_output, x0, x1,
|
||||
alpha, g_rng, y0, y1);
|
||||
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
ASSERT_EQ(g.party0.size(), 1u);
|
||||
EXPECT_EQ(recon(g.party0[0], g.party1[0]), beta);
|
||||
EXPECT_EQ(g.party0[0], ev(keys.first, alpha));
|
||||
EXPECT_EQ(g.party1[0], ev(keys.second, alpha));
|
||||
}
|
||||
|
||||
TEST(ArithPayload, XorWrapperSharesMatchDealer)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = dpf::xor_wrapper<std::uint32_t>;
|
||||
const in_t alpha = 0x11;
|
||||
const in_t x0 = 0x55;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const out_t beta{0x0a0b0c0du};
|
||||
const out_t y0{0x01020304u};
|
||||
const out_t y1 = beta ^ y0;
|
||||
|
||||
reset_roots();
|
||||
auto dealer = dpf::make_dpf(alpha, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
beta);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(dpf::arith_output, x0, x1, rng, y0, y1);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
const auto got = dpf::reconstruct(*dpf::eval_point(ds.first, q),
|
||||
*dpf::eval_point(ds.second, q));
|
||||
const auto expect = dpf::reconstruct(*dpf::eval_point(dealer.first, q),
|
||||
*dpf::eval_point(dealer.second, q));
|
||||
EXPECT_EQ(got, expect) << i;
|
||||
EXPECT_EQ(got, q == alpha ? beta : out_t{}) << i;
|
||||
}
|
||||
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> g_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto g = dpf::geneval_point(dpf::arith_output, x0, x1, alpha, g_rng, y0, y1);
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
ASSERT_EQ(g.party0.size(), 1u);
|
||||
EXPECT_EQ(g.party0[0] ^ g.party1[0], beta);
|
||||
}
|
||||
|
||||
TEST(ArithPayload, MultiBlockUint256MatchesDealer)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = uint256_t;
|
||||
const in_t alpha = 0x2a;
|
||||
const in_t x0 = 0x0f;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const out_t beta = (out_t{1} << 200) + out_t{0xabcdefu};
|
||||
const out_t y0 = (out_t{1} << 180) + out_t{0x1111u};
|
||||
const out_t y1 = beta - y0;
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_GT((dpf::block_length_of_leaf_v<out_t, simde__m128i>), 1u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
|
||||
reset_roots();
|
||||
auto dealer = dpf::make_dpf(alpha, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
beta);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(dpf::arith_output, x0, x1, rng, y0, y1);
|
||||
|
||||
EXPECT_EQ(std::memcmp(&dealer.first.leaf(), &ds.first.leaf(),
|
||||
sizeof(dealer.first.leaf())), 0);
|
||||
|
||||
for (int i = 0; i < 256; i += 17)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
EXPECT_EQ(recon(ev(ds.first, q), ev(ds.second, q)),
|
||||
q == alpha ? beta : out_t{})
|
||||
<< i;
|
||||
EXPECT_EQ(ev(ds.first, q), ev(dealer.first, q)) << "p0 " << i;
|
||||
EXPECT_EQ(ev(ds.second, q), ev(dealer.second, q)) << "p1 " << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ArithPayload, IncrementalMultiSlotArithBeta)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
const in_t alpha = 0x44;
|
||||
const in_t x0 = 0x12;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const std::uint16_t b0 = 0x1111;
|
||||
const std::uint16_t b1 = 0x2222;
|
||||
const std::uint16_t y00 = 0x0100;
|
||||
const std::uint16_t y01 = static_cast<std::uint16_t>(b0 - y00);
|
||||
const std::uint16_t y10 = 0x0003;
|
||||
const std::uint16_t y11 = static_cast<std::uint16_t>(b1 - y10);
|
||||
|
||||
reset_roots();
|
||||
auto dealer = dpf::make_dpf(alpha, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
dpf::at<8>(b0, b1));
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(dpf::arith_output, x0, x1, rng,
|
||||
dpf::at<8>(dpf::arith_beta<std::uint16_t>{y00, y01},
|
||||
dpf::arith_beta<std::uint16_t>{y10, y11}));
|
||||
|
||||
auto r0 = [&](auto & k0, auto & k1, in_t q) {
|
||||
return recon(*dpf::eval_point(dpf::out<0, 8>, k0, q),
|
||||
*dpf::eval_point(dpf::out<0, 8>, k1, q));
|
||||
};
|
||||
auto r1 = [&](auto & k0, auto & k1, in_t q) {
|
||||
return recon(*dpf::eval_point(dpf::out<1, 8>, k0, q),
|
||||
*dpf::eval_point(dpf::out<1, 8>, k1, q));
|
||||
};
|
||||
|
||||
for (int i = 0; i < 256; i += 13)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
EXPECT_EQ(r0(ds.first, ds.second, q), r0(dealer.first, dealer.second, q))
|
||||
<< "s0 " << i;
|
||||
EXPECT_EQ(r1(ds.first, ds.second, q), r1(dealer.first, dealer.second, q))
|
||||
<< "s1 " << i;
|
||||
EXPECT_EQ(r0(ds.first, ds.second, q),
|
||||
q == alpha ? b0 : std::uint16_t{0})
|
||||
<< i;
|
||||
EXPECT_EQ(r1(ds.first, ds.second, q),
|
||||
q == alpha ? b1 : std::uint16_t{0})
|
||||
<< i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ArithPayload, MixedArithBetaAndWildcard)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
const in_t alpha = 0x70;
|
||||
const in_t x0 = 0x01;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const std::uint8_t beta = 9;
|
||||
const std::uint8_t y0 = 2;
|
||||
const std::uint8_t y1 = 7;
|
||||
|
||||
reset_roots();
|
||||
auto dealer = dpf::make_dpf(alpha, dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
dpf::at<8>(beta, dpf::wildcard_value<std::uint8_t>{}));
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(dpf::arith_output, x0, x1, rng,
|
||||
dpf::at<8>(dpf::arith_beta<std::uint8_t>{y0, y1},
|
||||
dpf::wildcard_value<std::uint8_t>{}));
|
||||
|
||||
using key_t = std::decay_t<decltype(ds.first)>;
|
||||
static_assert(dpf::is_wildcard_v<typename key_t::template output_type_t<1>>);
|
||||
|
||||
for (int i = 0; i < 256; i += 19)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
const auto got = recon(*dpf::eval_point(dpf::out<0, 8>, ds.first, q),
|
||||
*dpf::eval_point(dpf::out<0, 8>, ds.second, q));
|
||||
const auto expect =
|
||||
recon(*dpf::eval_point(dpf::out<0, 8>, dealer.first, q),
|
||||
*dpf::eval_point(dpf::out<0, 8>, dealer.second, q));
|
||||
EXPECT_EQ(got, expect) << i;
|
||||
EXPECT_EQ(got, q == alpha ? beta : std::uint8_t{0}) << i;
|
||||
}
|
||||
}
|
||||
|
|
@ -103,6 +103,7 @@ TEST(Beaver, ProductTwo)
|
|||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(rng.draws, 5); // two input blinds * 2 draws + one product share
|
||||
EXPECT_EQ(s.preprocessing_count(), 3u);
|
||||
EXPECT_EQ(s.monomial_count(), 1u);
|
||||
EXPECT_EQ(s.round_of(z), 1);
|
||||
EXPECT_EQ(s.monomial({{x, 1u}, {y, 1u}}).open(),
|
||||
|
|
@ -150,7 +151,8 @@ TEST(Beaver, MulSquareIsOneRound)
|
|||
s.sample(rng);
|
||||
EXPECT_EQ(s.round_of(z), 1);
|
||||
EXPECT_EQ(s.wire_count(), 3u);
|
||||
// λx², λa λx, λa λx². One blind for both x factors.
|
||||
// λx², λa λx, λa λx². One blind for both x factors. The output is unpinned.
|
||||
EXPECT_EQ(s.preprocessing_count(), 5u);
|
||||
EXPECT_EQ(s.monomial_count(), 3u);
|
||||
EXPECT_EQ(rng.draws, 7); // two input blinds * 2 + three product shares
|
||||
EXPECT_EQ(s.monomial({{x, 2u}}).open(),
|
||||
|
|
@ -194,9 +196,10 @@ TEST(Beaver, DotAggregatesCrossTerm)
|
|||
auto z = s.dot({x0, x1, x2}, {y0, y1, y2});
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(s.monomial_count(), 0u);
|
||||
EXPECT_EQ(s.monomial_count(), 1u);
|
||||
EXPECT_EQ(s.round_of(z), 1);
|
||||
// 6 input blinds, two draws each, plus one aggregated cross draw
|
||||
// Six input blinds and one fused cross. Three separate products would be three crosses.
|
||||
EXPECT_EQ(s.preprocessing_count(), 7u);
|
||||
EXPECT_EQ(rng.draws, 13);
|
||||
auto cross = s.lambda(x0).open() * s.lambda(y0).open()
|
||||
+ s.lambda(x1).open() * s.lambda(y1).open()
|
||||
|
|
@ -220,13 +223,427 @@ TEST(Beaver, DotReusesAPair)
|
|||
auto z = s.dot({a, a}, {b, b});
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(s.monomial_count(), 0u);
|
||||
EXPECT_EQ(s.monomial_count(), 1u);
|
||||
EXPECT_EQ(s.preprocessing_count(), 3u);
|
||||
EXPECT_EQ(rng.draws, 5);
|
||||
EXPECT_EQ(s.dot_cross(z).open(),
|
||||
u64{2} * s.lambda(a).open() * s.lambda(b).open());
|
||||
s.bind(a, u64{3}, rng);
|
||||
s.bind(b, u64{4}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z), 24u);
|
||||
}
|
||||
|
||||
TEST(Beaver, InnerProductMatchesTheSumAndIsOneCross)
|
||||
{
|
||||
const u64 x[] = {0, 2, 5};
|
||||
const u64 y[] = {4, 0, 7};
|
||||
u64 expect = 0;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
expect += x[i] * y[i];
|
||||
|
||||
session64 fused;
|
||||
std::vector<wire64> fx;
|
||||
std::vector<wire64> fy;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
fx.push_back(fused.input());
|
||||
fy.push_back(fused.input());
|
||||
}
|
||||
auto dot = fused.dot(fx, fy);
|
||||
auto as_sum = fused(fx[0] * fy[0] + fx[1] * fy[1] + fx[2] * fy[2]);
|
||||
EXPECT_EQ(fused.round_of(dot), 1);
|
||||
EXPECT_EQ(fused.round_of(as_sum), 1);
|
||||
EXPECT_EQ(fused.preprocessing_count(), 7u);
|
||||
EXPECT_EQ(fused.monomial_count(), 1u);
|
||||
|
||||
session64 separate;
|
||||
std::vector<wire64> sx;
|
||||
std::vector<wire64> sy;
|
||||
std::vector<wire64> prods;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
sx.push_back(separate.input());
|
||||
sy.push_back(separate.input());
|
||||
}
|
||||
for (int i = 0; i < 3; ++i)
|
||||
prods.push_back(separate(sx[i] * sy[i]));
|
||||
auto summed = separate(prods[0] + prods[1] + prods[2]);
|
||||
EXPECT_EQ(separate.preprocessing_count(), 9u);
|
||||
EXPECT_LT(fused.preprocessing_count(), separate.preprocessing_count());
|
||||
|
||||
Counter rf;
|
||||
Counter rs;
|
||||
fused.sample(rf);
|
||||
separate.sample(rs);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
fused.bind(fx[i], x[i], rf);
|
||||
fused.bind(fy[i], y[i], rf);
|
||||
separate.bind(sx[i], x[i], rs);
|
||||
separate.bind(sy[i], y[i], rs);
|
||||
}
|
||||
fused.evaluate();
|
||||
separate.evaluate();
|
||||
EXPECT_EQ(fused.open(dot), expect);
|
||||
EXPECT_EQ(fused.open(as_sum), expect);
|
||||
EXPECT_EQ(separate.open(summed), expect);
|
||||
u64 cross = 0;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
cross += fused.lambda(fx[i]).open() * fused.lambda(fy[i]).open();
|
||||
EXPECT_EQ(fused.dot_cross(dot).open(), cross);
|
||||
|
||||
const auto monos = fused.monomial_count();
|
||||
const auto prep = fused.preprocessing_count();
|
||||
auto again = fused.dot(fx, fy);
|
||||
EXPECT_EQ(fused.monomial_count(), monos);
|
||||
EXPECT_EQ(fused.preprocessing_count(), prep);
|
||||
fused.sample(rf);
|
||||
fused.evaluate();
|
||||
EXPECT_EQ(fused.open(again), expect);
|
||||
}
|
||||
|
||||
TEST(Beaver, InnerProductPeelsASharedFactor)
|
||||
{
|
||||
session64 s;
|
||||
auto a = s.input();
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto z = s.input();
|
||||
auto dotted = s.dot({a, a, a}, {x, y, z});
|
||||
EXPECT_EQ(s.round_of(dotted), 2);
|
||||
EXPECT_EQ(s.preprocessing_count(), 3u);
|
||||
|
||||
session64 hand;
|
||||
auto ha = hand.input();
|
||||
auto hx = hand.input();
|
||||
auto hy = hand.input();
|
||||
auto hz = hand.input();
|
||||
auto written = hand(ha * (hx + hy + hz));
|
||||
EXPECT_EQ(hand.round_of(written), 2);
|
||||
EXPECT_EQ(hand.preprocessing_count(), s.preprocessing_count());
|
||||
EXPECT_LT(s.preprocessing_count(), 7u);
|
||||
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(a, u64{3}, rng);
|
||||
s.bind(x, u64{4}, rng);
|
||||
s.bind(y, u64{5}, rng);
|
||||
s.bind(z, u64{6}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(dotted), 3u * (4u + 5u + 6u));
|
||||
}
|
||||
|
||||
TEST(Beaver, InnerProductOfSquaresIsOneShare)
|
||||
{
|
||||
auto got = run_poly(2, [](session64 & s, const std::vector<wire64> & in) {
|
||||
return s.dot({in[0], in[1]}, {in[0], in[1]});
|
||||
}, {6, 7});
|
||||
EXPECT_EQ(got.value, 36u + 49u);
|
||||
EXPECT_EQ(got.rounds, 1);
|
||||
EXPECT_EQ(got.prep, 3u);
|
||||
EXPECT_EQ(got.monos, 1u);
|
||||
}
|
||||
|
||||
TEST(Beaver, ScaledInnerProductUsesThePolynomialSchedule)
|
||||
{
|
||||
session64 automatic;
|
||||
auto sgn = automatic.input();
|
||||
auto x0 = automatic.input();
|
||||
auto x1 = automatic.input();
|
||||
auto y0 = automatic.input();
|
||||
auto y1 = automatic.input();
|
||||
auto y = automatic(sgn * dpf::beavers::dot({x0, x1}, {y0, y1}));
|
||||
|
||||
session64 hand;
|
||||
auto hs = hand.input();
|
||||
auto hx0 = hand.input();
|
||||
auto hx1 = hand.input();
|
||||
auto hy0 = hand.input();
|
||||
auto hy1 = hand.input();
|
||||
auto inner = hand.dot({hx0, hx1}, {hy0, hy1});
|
||||
auto outer = hand(hs * inner);
|
||||
EXPECT_EQ(automatic.preprocessing_count(), hand.preprocessing_count());
|
||||
EXPECT_EQ(automatic.round_of(y), hand.round_of(outer));
|
||||
EXPECT_LT(automatic.preprocessing_count(), 9u);
|
||||
|
||||
const u64 sv = 3, a = 2, b = 5, c = 4, d = 6;
|
||||
Counter ra;
|
||||
Counter rh;
|
||||
automatic.sample(ra);
|
||||
hand.sample(rh);
|
||||
automatic.bind(sgn, sv, ra);
|
||||
automatic.bind(x0, a, ra);
|
||||
automatic.bind(x1, b, ra);
|
||||
automatic.bind(y0, c, ra);
|
||||
automatic.bind(y1, d, ra);
|
||||
hand.bind(hs, sv, rh);
|
||||
hand.bind(hx0, a, rh);
|
||||
hand.bind(hx1, b, rh);
|
||||
hand.bind(hy0, c, rh);
|
||||
hand.bind(hy1, d, rh);
|
||||
automatic.evaluate();
|
||||
hand.evaluate();
|
||||
const u64 expect = sv * (a * c + b * d);
|
||||
EXPECT_EQ(automatic.open(y), expect);
|
||||
EXPECT_EQ(hand.open(outer), expect);
|
||||
|
||||
session64 scaled;
|
||||
auto sx0 = scaled.input();
|
||||
auto sx1 = scaled.input();
|
||||
auto sy0 = scaled.input();
|
||||
auto sy1 = scaled.input();
|
||||
auto plain = scaled.dot({sx0, sx1}, {sy0, sy1});
|
||||
auto triple = scaled(u64{3} * dpf::beavers::dot({sx0, sx1}, {sy0, sy1}));
|
||||
EXPECT_EQ(scaled.preprocessing_count(), 5u);
|
||||
EXPECT_EQ(scaled.monomial_count(), 1u);
|
||||
(void)plain;
|
||||
Counter rs;
|
||||
scaled.sample(rs);
|
||||
scaled.bind(sx0, a, rs);
|
||||
scaled.bind(sx1, b, rs);
|
||||
scaled.bind(sy0, c, rs);
|
||||
scaled.bind(sy1, d, rs);
|
||||
scaled.evaluate();
|
||||
EXPECT_EQ(scaled.open(triple), 3u * (a * c + b * d));
|
||||
EXPECT_EQ(scaled.open(plain), a * c + b * d);
|
||||
}
|
||||
|
||||
TEST(Beaver, InnerProductsOnModintAndXor)
|
||||
{
|
||||
using M = dpf::modint<17>;
|
||||
dpf::beavers::session<M> ms;
|
||||
auto mx0 = ms.input();
|
||||
auto mx1 = ms.input();
|
||||
auto my0 = ms.input();
|
||||
auto my1 = ms.input();
|
||||
auto my = ms.dot({mx0, mx1}, {my0, my1});
|
||||
EXPECT_EQ(ms.preprocessing_count(), 5u);
|
||||
EXPECT_EQ(ms.monomial_count(), 1u);
|
||||
Seq<M> mr;
|
||||
ms.sample(mr);
|
||||
ms.bind(mx0, M{10}, mr);
|
||||
ms.bind(mx1, M{9}, mr);
|
||||
ms.bind(my0, M{8}, mr);
|
||||
ms.bind(my1, M{7}, mr);
|
||||
ms.evaluate();
|
||||
EXPECT_EQ(ms.open(my), M{10} * M{8} + M{9} * M{7});
|
||||
|
||||
using W = dpf::xor_wrapper<std::uint32_t>;
|
||||
dpf::beavers::session<W> xs;
|
||||
auto xx = xs.input();
|
||||
auto xy = xs.input();
|
||||
auto yx = xs.input();
|
||||
auto yy = xs.input();
|
||||
auto dot = xs.dot({xx, xy}, {yx, yy});
|
||||
EXPECT_EQ(xs.preprocessing_count(), 5u);
|
||||
XorSeq<W> xr;
|
||||
xs.sample(xr);
|
||||
const W a{0b11110000u};
|
||||
const W b{0b11001100u};
|
||||
const W c{0b10101010u};
|
||||
const W d{0b11111111u};
|
||||
xs.bind(xx, a, xr);
|
||||
xs.bind(xy, b, xr);
|
||||
xs.bind(yx, c, xr);
|
||||
xs.bind(yy, d, xr);
|
||||
xs.evaluate();
|
||||
EXPECT_EQ(xs.open(dot), a * c + b * d);
|
||||
}
|
||||
|
||||
TEST(Beaver, InnerProductOfEarlierProductsIsALaterRound)
|
||||
{
|
||||
session64 s;
|
||||
auto a = s.input();
|
||||
auto b = s.input();
|
||||
auto c = s.input();
|
||||
auto d = s.input();
|
||||
auto ab = s(a * b);
|
||||
auto cd = s(c * d);
|
||||
s.pin(ab);
|
||||
s.pin(cd);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
auto lab = s.lambda(ab);
|
||||
s.bind(a, u64{2}, rng);
|
||||
s.bind(b, u64{3}, rng);
|
||||
s.bind(c, u64{4}, rng);
|
||||
s.bind(d, u64{5}, rng);
|
||||
auto both = s.dot({ab, cd}, {ab, cd});
|
||||
EXPECT_EQ(s.round_of(both), 2);
|
||||
const auto draws = rng.draws;
|
||||
s.sample(rng);
|
||||
EXPECT_EQ(s.lambda(ab), lab);
|
||||
EXPECT_EQ(rng.draws, draws + 1);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(ab), 6u);
|
||||
EXPECT_EQ(s.open(cd), 20u);
|
||||
EXPECT_EQ(s.open(both), 6u * 6u + 20u * 20u);
|
||||
}
|
||||
|
||||
TEST(Beaver, TriplesUseNoExtraShares)
|
||||
{
|
||||
{
|
||||
session64 s;
|
||||
auto a = s.input();
|
||||
auto b = s.input();
|
||||
auto ab = s(a * b);
|
||||
s.pin(ab);
|
||||
EXPECT_EQ(s.preprocessing_count(), 4u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(a, u64{6}, rng);
|
||||
s.bind(b, u64{7}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(ab), 42u);
|
||||
EXPECT_EQ(s.monomial({{a, 1u}, {b, 1u}}).open(),
|
||||
s.lambda(a).open() * s.lambda(b).open());
|
||||
}
|
||||
{
|
||||
session64 s;
|
||||
auto a = s.input();
|
||||
auto b = s.input();
|
||||
auto c = s.input();
|
||||
auto abc = s(a * b * c);
|
||||
s.pin(abc);
|
||||
EXPECT_EQ(s.preprocessing_count(), 8u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(a, u64{2}, rng);
|
||||
s.bind(b, u64{3}, rng);
|
||||
s.bind(c, u64{5}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(abc), 30u);
|
||||
EXPECT_EQ(s.monomial({{a, 1u}, {b, 1u}}).open(),
|
||||
s.lambda(a).open() * s.lambda(b).open());
|
||||
EXPECT_EQ(s.monomial({{a, 1u}, {b, 1u}, {c, 1u}}).open(),
|
||||
s.lambda(a).open() * s.lambda(b).open() * s.lambda(c).open());
|
||||
}
|
||||
{
|
||||
session64 s;
|
||||
auto x = s.input();
|
||||
auto x2 = s(x * x);
|
||||
s.pin(x2);
|
||||
EXPECT_EQ(s.preprocessing_count(), 3u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(x, u64{9}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(x2), 81u);
|
||||
}
|
||||
{
|
||||
session64 s;
|
||||
auto a = s.input();
|
||||
auto x = s.input();
|
||||
auto ax2 = s(a * x * x);
|
||||
s.pin(ax2);
|
||||
EXPECT_EQ(s.preprocessing_count(), 6u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(a, u64{4}, rng);
|
||||
s.bind(x, u64{3}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(ax2), 36u);
|
||||
EXPECT_EQ(s.monomial({{a, 1u}, {x, 2u}}).open(),
|
||||
s.lambda(a).open() * s.lambda(x).open() * s.lambda(x).open());
|
||||
}
|
||||
{
|
||||
session64 s;
|
||||
std::vector<wire64> x;
|
||||
std::vector<wire64> y;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
x.push_back(s.input());
|
||||
y.push_back(s.input());
|
||||
}
|
||||
auto unpinned = s.dot(x, y);
|
||||
EXPECT_EQ(s.preprocessing_count(), 7u);
|
||||
s.pin(unpinned);
|
||||
EXPECT_EQ(s.preprocessing_count(), 8u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
const u64 xv[] = {1, 2, 3};
|
||||
const u64 yv[] = {4, 5, 6};
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
s.bind(x[i], xv[i], rng);
|
||||
s.bind(y[i], yv[i], rng);
|
||||
}
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(unpinned), 32u);
|
||||
}
|
||||
{
|
||||
session64 s;
|
||||
auto scalar = s.input();
|
||||
auto v0 = s.input();
|
||||
auto v1 = s.input();
|
||||
auto v2 = s.input();
|
||||
auto z = s.scale(scalar, {v0, v1, v2});
|
||||
EXPECT_EQ(s.preprocessing_count(), 7u);
|
||||
for (auto out : z)
|
||||
s.pin(out);
|
||||
EXPECT_EQ(s.preprocessing_count(), 10u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(scalar, u64{3}, rng);
|
||||
s.bind(v0, u64{4}, rng);
|
||||
s.bind(v1, u64{5}, rng);
|
||||
s.bind(v2, u64{0}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z[0]), 12u);
|
||||
EXPECT_EQ(s.open(z[1]), 15u);
|
||||
EXPECT_EQ(s.open(z[2]), 0u);
|
||||
}
|
||||
{
|
||||
session64 s;
|
||||
auto bit = s.bit();
|
||||
auto scalar = s.input();
|
||||
auto out = s.bit_mul(bit, scalar);
|
||||
s.pin(out);
|
||||
EXPECT_EQ(s.preprocessing_count(), 4u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(bit, u64{1}, rng);
|
||||
s.bind(scalar, u64{19}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(out), 19u);
|
||||
}
|
||||
{
|
||||
session64 s;
|
||||
auto bit = s.bit();
|
||||
auto when1 = s.input();
|
||||
auto when0 = s.input();
|
||||
auto out = s.mux(bit, when1, when0);
|
||||
s.pin(out);
|
||||
EXPECT_EQ(s.preprocessing_count(), 6u);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(bit, u64{0}, rng);
|
||||
s.bind(when1, u64{8}, rng);
|
||||
s.bind(when0, u64{9}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(out), 9u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Beaver, InnerProductRejectsABadShape)
|
||||
{
|
||||
session64 s;
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto z = s.input();
|
||||
EXPECT_THROW((void)[&] {
|
||||
return s.dot(std::initializer_list<wire64>{}, std::initializer_list<wire64>{});
|
||||
}(), std::invalid_argument);
|
||||
EXPECT_THROW((void)[&] { return s.dot({x}, {y, z}); }(), std::invalid_argument);
|
||||
session64 other;
|
||||
auto w = other.input();
|
||||
EXPECT_THROW((void)[&] { return s.dot({x}, {w}); }(), std::invalid_argument);
|
||||
auto dotted = s.dot({x}, {y});
|
||||
EXPECT_THROW((void)[&] { return s.dot_cross(dotted); }(), std::logic_error);
|
||||
EXPECT_THROW((void)[&] { return s.dot_cross(x); }(), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(Beaver, ScaleSharesScalarBlind)
|
||||
{
|
||||
dpf::beavers::session<u64> s;
|
||||
|
|
@ -240,6 +657,7 @@ TEST(Beaver, ScaleSharesScalarBlind)
|
|||
s.sample(rng);
|
||||
EXPECT_EQ(z.size(), 4u);
|
||||
EXPECT_EQ(s.monomial_count(), 4u);
|
||||
EXPECT_EQ(s.preprocessing_count(), 9u);
|
||||
EXPECT_EQ(s.round_of(z[0]), 1);
|
||||
// 1 scalar + 4 lanes + 4 outputs = 9 wires * 2, plus 4 cross terms
|
||||
EXPECT_EQ(rng.draws, 14);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "dpf/blocked_dcf.hpp"
|
||||
#include "dpf/json.hpp"
|
||||
#include "grotto/offset_horner.hpp"
|
||||
#include "grotto/prefix_parity.hpp"
|
||||
|
|
@ -238,7 +239,10 @@ TEST(BlockedDcf, DealerMatchesDoernerShelat)
|
|||
dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
dpf::block_width<4>(dpf::lt(uint64_t{15}, uint64_t{2})));
|
||||
reset_tape();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::block_width<4>(dpf::lt(uint64_t{15}, uint64_t{2})));
|
||||
|
||||
|
|
@ -336,7 +340,10 @@ TEST(BlockedDcf, GenevalOpensCheckpointWords)
|
|||
const uint8_t x0 = 1;
|
||||
const uint8_t x1 = static_cast<uint8_t>(alpha ^ x0);
|
||||
reset_tape();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
std::array<uint8_t, 3> ends{{0, 20, 21}};
|
||||
auto g = dpf::geneval_cmp(x0, x1, ends.begin(), ends.end(), rng,
|
||||
dpf::block_width<4>(dpf::lt(uint64_t{5})));
|
||||
|
|
@ -350,6 +357,85 @@ TEST(BlockedDcf, GenevalOpensCheckpointWords)
|
|||
EXPECT_EQ((g.party0[2] + g.party1[2]) & g.mask, 0u);
|
||||
}
|
||||
|
||||
TEST(BlockedDcf, UnevenScheduleMatchesDenseComparison)
|
||||
{
|
||||
const uint16_t alpha = 0x0B4C;
|
||||
auto dense = dpf::make_dpf(alpha, dpf::lt(uint64_t{9}, uint64_t{2}));
|
||||
auto blocked = dpf::make_dpf(alpha,
|
||||
dpf::block_width<4>(dpf::lt(uint64_t{9}, uint64_t{2})));
|
||||
using KT = std::decay_t<decltype(blocked.first)>;
|
||||
EXPECT_EQ(KT::cmp_h, 14u);
|
||||
EXPECT_EQ(KT::cmp_block, 4u);
|
||||
EXPECT_NE(KT::cmp_h % KT::cmp_block, 0u);
|
||||
EXPECT_EQ(blocked.first.value_cw().size(), KT::cmp_checkpoints);
|
||||
using sched = dpf::detail::blocked::schedule<KT::cmp_h, KT::cmp_block>;
|
||||
ASSERT_GE(sched::count, 2u);
|
||||
bool uneven = false;
|
||||
const auto first_step = sched::depths[1] - sched::depths[0];
|
||||
for (std::size_t i = 1; i < sched::count; ++i)
|
||||
{
|
||||
if (sched::depths[i] - sched::depths[i - 1] != first_step)
|
||||
uneven = true;
|
||||
}
|
||||
EXPECT_TRUE(uneven);
|
||||
for (uint32_t x = 0; x < 65536u; ++x)
|
||||
{
|
||||
const auto q = static_cast<uint16_t>(x);
|
||||
ASSERT_EQ(recon_cmp(blocked.first, blocked.second, q),
|
||||
recon_cmp(dense.first, dense.second, q))
|
||||
<< x;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BlockedDcf, WideCheckpointFrontierMatchesDense)
|
||||
{
|
||||
const uint32_t alpha = 0x01020304u;
|
||||
// `cmp_q` is 2, so `lt_at<19>` checkpoints at height 17. One block of 17
|
||||
// parks a root sibling 16 levels above that checkpoint.
|
||||
auto dense = dpf::make_dpf(alpha, dpf::lt_at<19>(uint64_t{5}, uint64_t{1}));
|
||||
auto blocked = dpf::make_dpf(alpha,
|
||||
dpf::block_width<17>(dpf::lt_at<19>(uint64_t{5}, uint64_t{1})));
|
||||
using KT = std::decay_t<decltype(blocked.first)>;
|
||||
EXPECT_GE(KT::cmp_h, 17u);
|
||||
EXPECT_EQ(KT::cmp_checkpoints, 1u);
|
||||
const uint32_t pts[] = {
|
||||
0u, 1u, alpha - 1u, alpha, alpha + 1u, 0x80000000u, 0xffffffffu
|
||||
};
|
||||
for (uint32_t x : pts)
|
||||
{
|
||||
EXPECT_EQ(recon_cmp(blocked.first, blocked.second, x),
|
||||
recon_cmp(dense.first, dense.second, x))
|
||||
<< std::hex << x;
|
||||
}
|
||||
|
||||
const uint32_t from = 100, to = 101;
|
||||
auto buf0 = dpf::make_output_buffer(dpf::cmp, blocked.first, from, to);
|
||||
auto buf1 = dpf::make_output_buffer(dpf::cmp, blocked.second, from, to);
|
||||
dpf::eval_interval(dpf::cmp, blocked.first, from, to, buf0);
|
||||
dpf::eval_interval(dpf::cmp, blocked.second, from, to, buf1);
|
||||
EXPECT_EQ(recon(buf0[0], buf1[0]) & blocked.first.cmp().mask,
|
||||
recon_cmp(blocked.first, blocked.second, from));
|
||||
EXPECT_EQ(recon(buf0[1], buf1[1]) & blocked.first.cmp().mask,
|
||||
recon_cmp(blocked.first, blocked.second, to));
|
||||
}
|
||||
|
||||
TEST(BlockedDcf, PathRecipesStayOnThePerLevelChannel)
|
||||
{
|
||||
const uint8_t alpha = 0x3C;
|
||||
EXPECT_THROW(dpf::make_dpf(alpha, dpf::block_width<4>(dpf::lcp(uint64_t{1}))),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(dpf::make_dpf(alpha, dpf::block_width<4>(dpf::break_bit(uint64_t{3}))),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(dpf::make_dpf(alpha,
|
||||
dpf::block_width<4>(dpf::prefix_with_length<4>(uint64_t{1}))),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(dpf::make_dpf(alpha, dpf::block_width<2>(dpf::path_paint(
|
||||
[](std::size_t matched, uint64_t, bool) {
|
||||
return static_cast<uint64_t>(matched);
|
||||
}))),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(BlockedDcf, GrottoPrefixSegmentAndHorner)
|
||||
{
|
||||
const uint16_t alpha = 1000;
|
||||
|
|
|
|||
64
test/tests/constrained_cmp_test.cpp
Normal file
64
test/tests/constrained_cmp_test.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
|
||||
TEST(ConstrainedCmp, LemmaAdjacentPairs)
|
||||
{
|
||||
// |x0 − x1| = 1 ⇒ local_ccmp = 1{x0 < x1}.
|
||||
EXPECT_EQ(dpf::local_ccmp(0, 1), 1u);
|
||||
EXPECT_EQ(dpf::local_ccmp(1, 0), 0u);
|
||||
EXPECT_EQ(dpf::local_ccmp(2, 3), 1u);
|
||||
EXPECT_EQ(dpf::local_ccmp(3, 2), 0u);
|
||||
EXPECT_EQ(dpf::local_ccmp(100, 101), 1u);
|
||||
EXPECT_EQ(dpf::local_ccmp(101, 100), 0u);
|
||||
// Control-bit pairs used by arith leaf open (t0 ⊕ t1 = 1).
|
||||
EXPECT_EQ(dpf::local_ccmp(0, 1), 1u); // g = t1
|
||||
EXPECT_EQ(dpf::local_ccmp(1, 0), 0u); // g = t1
|
||||
}
|
||||
|
||||
TEST(ConstrainedCmp, RandomAdjacentBatch)
|
||||
{
|
||||
std::mt19937_64 rng{0xC0FFEEULL};
|
||||
std::uniform_int_distribution<std::uint64_t> dist(0, (1ull << 40) - 2);
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const std::uint64_t a = dist(rng);
|
||||
const std::uint64_t b = a + 1;
|
||||
EXPECT_EQ(dpf::local_ccmp(a, b), 1u) << a << " < " << b;
|
||||
EXPECT_EQ(dpf::local_ccmp(b, a), 0u) << b << " > " << a;
|
||||
EXPECT_EQ(dpf::local_ccmp_int(a, b), 1u);
|
||||
EXPECT_EQ(dpf::local_ccmp_int(b, a), 0u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstrainedCmp, PartyTermsMatchTheAndInputs)
|
||||
{
|
||||
uint8_t z0 = 9, z1 = 9, l = 9;
|
||||
dpf::detail::ccmp_party_terms(0b10, 0, z0, z1, l);
|
||||
EXPECT_EQ(l, 0u);
|
||||
EXPECT_EQ(z0, 1u);
|
||||
EXPECT_EQ(z1, 1u);
|
||||
dpf::detail::ccmp_party_terms(0b11, 1, z0, z1, l);
|
||||
EXPECT_EQ(l, 1u);
|
||||
EXPECT_EQ(z0, 1u);
|
||||
EXPECT_EQ(z1, static_cast<uint8_t>(1u ^ 1u ^ 1u));
|
||||
}
|
||||
|
||||
TEST(ConstrainedCmp, AdjacentAtTheTopOfUint64)
|
||||
{
|
||||
const std::uint64_t top = std::numeric_limits<std::uint64_t>::max();
|
||||
EXPECT_EQ(dpf::local_ccmp(top - 1, top), 1u);
|
||||
EXPECT_EQ(dpf::local_ccmp(top, top - 1), 0u);
|
||||
}
|
||||
|
||||
TEST(ConstrainedCmp, ProtocolHook)
|
||||
{
|
||||
dpf::detail::urandom_pad_rng pads{};
|
||||
dpf::local_cw_protocol<dpf::detail::urandom_pad_rng> proto{pads};
|
||||
EXPECT_EQ(proto.open_ccmp(0, 1), 1u);
|
||||
EXPECT_EQ(proto.open_ccmp(1, 0), 0u);
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ TEST(ContextBlast, ModintEdgesAndFullDomain)
|
|||
every_point(m7{64}, dpf::xor_wrapper<uint32_t>{0x00ff}, 128);
|
||||
|
||||
for (unsigned a : {0u, 1u, 511u, 512u, 1023u})
|
||||
every_point(m10{a}, uint32_t{0xabcdu}, 1024);
|
||||
every_point(m10{static_cast<m10::integral_type>(a)}, uint32_t{0xabcdu}, 1024);
|
||||
|
||||
every_point(m9{0}, uint16_t{2}, 512);
|
||||
every_point(m9{511}, uint16_t{2}, 512);
|
||||
|
|
@ -140,11 +140,11 @@ TEST(ContextBlast, BitstringPointIntervalSequence)
|
|||
const uint32_t y = 0x11111111u;
|
||||
for (unsigned a : {0u, 1u, 31u, 32u, 63u})
|
||||
{
|
||||
bs alpha{a};
|
||||
bs alpha{static_cast<bs::word_type>(a)};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
for (unsigned i = 0; i < 64; ++i)
|
||||
{
|
||||
bs q{i};
|
||||
bs q{static_cast<bs::word_type>(i)};
|
||||
EXPECT_EQ(opened(ev(k0, q), ev(k1, q)), q == alpha ? y : 0u) << i;
|
||||
}
|
||||
bs from{0};
|
||||
|
|
@ -280,8 +280,11 @@ TEST(ContextBlast, XorWrapperAndGenevalIntegers)
|
|||
const int32_t secret = -2;
|
||||
const int32_t x1 = secret ^ x0;
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto g = dpf::geneval_point(x0, x1, secret,
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, X{7});
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
EXPECT_EQ(g.live_levels, std::decay_t<decltype(keys.first)>::depth);
|
||||
EXPECT_EQ(opened(g.party0[0], g.party1[0]), X{7});
|
||||
|
|
@ -289,8 +292,11 @@ TEST(ContextBlast, XorWrapperAndGenevalIntegers)
|
|||
|
||||
const int32_t far = 100;
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto off = dpf::geneval_point(x0, x1, far,
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, X{7});
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_FALSE(off.leaf_live);
|
||||
EXPECT_GT(off.live_levels, 0u);
|
||||
EXPECT_LT(off.live_levels, off.correction_words.size());
|
||||
|
|
@ -307,8 +313,11 @@ TEST(ContextBlast, XorWrapperAndGenevalIntegers)
|
|||
uint64_t{99});
|
||||
reset_roots();
|
||||
const uint32_t qs[] = {0u, 1u, u, u ^ 1u, 0xffffffffu};
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto sq = dpf::geneval_sequence(u0, u1, std::begin(qs), std::end(qs),
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, uint64_t{99});
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_TRUE(sq.leaf_live);
|
||||
for (std::size_t i = 0; i < sq.live_levels; ++i)
|
||||
EXPECT_EQ(std::memcmp(&sq.correction_words[i], &uk.first.correction_word(i),
|
||||
|
|
|
|||
|
|
@ -384,7 +384,10 @@ TEST(CornerGaps, PrgRejectsUint32Seam)
|
|||
EXPECT_EQ(std::memcmp(&out[i], &one, sizeof(one)), 0) << i;
|
||||
}
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_THROW((dpf::randomness::detail::lane_codec<dpf::prg::aes128, simde__m128i>::fill(
|
||||
seed, static_cast<std::uint64_t>(UINT32_MAX) - 1u, out, 4)),
|
||||
std::invalid_argument);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,3 +213,17 @@ TEST(DyadicLut, Int64Edges)
|
|||
EXPECT_EQ(bit(std::int64_t{-5}), 1);
|
||||
EXPECT_EQ(bit(std::int64_t{5}), 0);
|
||||
}
|
||||
|
||||
TEST(DyadicLut, RejectsAFractionalWidthThatDoesNotFit)
|
||||
{
|
||||
EXPECT_THROW(grotto::make_signum_lut<std::int16_t>(63), std::invalid_argument);
|
||||
EXPECT_THROW(grotto::make_positive_lut<std::int64_t>(63), std::invalid_argument);
|
||||
EXPECT_THROW(grotto::make_ilogb_lut<std::int16_t>(64), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(DyadicLut, RejectsAnEncodedValueThatDoesNotFit)
|
||||
{
|
||||
// clz(0) is 64. 64 << 57 does not fit in int64; 64 << 56 does.
|
||||
EXPECT_THROW(grotto::make_clz_lut<std::int64_t>(57), std::overflow_error);
|
||||
EXPECT_NO_THROW(grotto::make_clz_lut<std::int64_t>(56));
|
||||
}
|
||||
|
|
|
|||
57
test/tests/fp61_test.cpp
Normal file
57
test/tests/fp61_test.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include "dpf/fp61.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using dpf::fp61;
|
||||
using dpf::fp61_mod;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Fp61, ReduceCanonicalizesTheModulus)
|
||||
{
|
||||
EXPECT_EQ(fp61::reduce(0), 0u);
|
||||
EXPECT_EQ(fp61::reduce(1), 1u);
|
||||
EXPECT_EQ(fp61::reduce(fp61_mod), 0u);
|
||||
EXPECT_EQ(fp61::reduce(fp61_mod + 1), 1u);
|
||||
EXPECT_EQ(fp61::reduce(std::uint64_t{1} << 61), 1u);
|
||||
EXPECT_EQ(fp61::reduce(std::numeric_limits<std::uint64_t>::max()), 7u);
|
||||
EXPECT_EQ(fp61::reduce(fp61::reduce(fp61_mod + 9)), fp61::reduce(9));
|
||||
}
|
||||
|
||||
TEST(Fp61, ArithmeticWrapsInTheField)
|
||||
{
|
||||
const fp61 a{fp61_mod - 1};
|
||||
const fp61 b{3};
|
||||
EXPECT_EQ((a + b).raw(), 2u);
|
||||
EXPECT_EQ((b - a).raw(), 4u);
|
||||
EXPECT_EQ((-a).raw(), 1u);
|
||||
EXPECT_EQ((-fp61{0}).raw(), 0u);
|
||||
EXPECT_EQ((a - a).raw(), 0u);
|
||||
EXPECT_EQ((-(-a)).raw(), a.raw());
|
||||
EXPECT_EQ((a * fp61{1}).raw(), a.raw());
|
||||
EXPECT_EQ((a * fp61{0}).raw(), 0u);
|
||||
EXPECT_EQ((fp61{2} * fp61{3}).raw(), 6u);
|
||||
}
|
||||
|
||||
TEST(Fp61, MultiplicationDistributes)
|
||||
{
|
||||
const fp61 a{1000};
|
||||
const fp61 b{fp61_mod - 5};
|
||||
const fp61 c{17};
|
||||
EXPECT_EQ(((a + b) * c).raw(), (a * c + b * c).raw());
|
||||
EXPECT_EQ((a * b).raw(), (b * a).raw());
|
||||
}
|
||||
|
||||
TEST(Fp61, StreamPrintsTheReducedValue)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << fp61{fp61_mod + 4};
|
||||
EXPECT_EQ(os.str(), "4");
|
||||
}
|
||||
|
|
@ -86,6 +86,8 @@ std::size_t live_through_lcp(std::size_t lcp, std::size_t depth)
|
|||
return std::min(depth, lcp + 1);
|
||||
}
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
template <typename Key>
|
||||
void expect_prefix_words(const Key & key, const std::vector<simde__m128i,
|
||||
dpf::aligned_allocator<simde__m128i>> & cws,
|
||||
|
|
@ -112,6 +114,7 @@ dpf::ds_randomness<simde__m128i (*)(), Pad> rng()
|
|||
{
|
||||
return {take_root, Pad{}};
|
||||
}
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
@ -508,7 +511,10 @@ TEST(Geneval, DoernerShelatKeyAgreesOnLivePrefix)
|
|||
out_t y = 1;
|
||||
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> ds_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, ds_rng, y);
|
||||
reset_roots();
|
||||
auto g = dpf::geneval_point(x0, x1, query, rng<in_t>(), y);
|
||||
|
|
@ -631,7 +637,10 @@ TEST(Geneval, XorSplitAndPadStreamDoNotChangeLiveWords)
|
|||
auto check = [&](in_t x0, auto pad, const char * name) {
|
||||
in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), decltype(pad)> r{take_root, pad};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto g = dpf::geneval_point(x0, x1, query, r, y);
|
||||
EXPECT_EQ(g.live_levels, live) << name;
|
||||
expect_prefix_words(keys.first, g.correction_words, g.correction_advice,
|
||||
|
|
@ -1190,7 +1199,10 @@ TEST(Geneval, DoernerShelatOnTargetSharesMatch)
|
|||
const out_t y = 0x9f3c;
|
||||
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> ds_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, ds_rng, y);
|
||||
reset_roots();
|
||||
auto g = dpf::geneval_point(x0, x1, alpha, rng<in_t>(), y);
|
||||
|
|
@ -1251,7 +1263,10 @@ TEST(Geneval, CmpLeqGeqNonzeroElseAndDomainMin)
|
|||
auto spec_ds = spec;
|
||||
auto spec_g = spec;
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> ds_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, ds_rng, spec_ds);
|
||||
reset_roots();
|
||||
auto g = dpf::geneval_cmp(x0, x1, ends.begin(), ends.end(), rng<in_t>(), spec_g);
|
||||
|
|
|
|||
322
test/tests/half_tree_test.cpp
Normal file
322
test/tests/half_tree_test.cpp
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using ht_prg = dpf::prg::aes128_ccr;
|
||||
using leaf_prg = dpf::prg::aes128;
|
||||
|
||||
simde__m128i g_roots[8];
|
||||
int g_ri = 0;
|
||||
simde__m128i take_root() { return g_roots[g_ri++]; }
|
||||
|
||||
struct Pad
|
||||
{
|
||||
uint64_t n = 1;
|
||||
simde__m128i block()
|
||||
{
|
||||
auto v = simde_mm_set_epi64x(static_cast<long long>(n),
|
||||
static_cast<long long>(n * 9 + 3));
|
||||
n += 2;
|
||||
return v;
|
||||
}
|
||||
uint8_t bit() { return static_cast<uint8_t>(n++ & 1u); }
|
||||
};
|
||||
|
||||
void reset_roots()
|
||||
{
|
||||
g_ri = 0;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
g_roots[i] = simde_mm_set_epi64x(0x1111 * (i + 1), 0xA5A50000u + i * 17);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T bare(const T & v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t Party, dpf::sharing Scheme>
|
||||
T bare(const dpf::secret_share<T, Party, Scheme> & s)
|
||||
{
|
||||
return s.raw();
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
auto recon(const A & a, const B & b)
|
||||
{
|
||||
using T = decltype(bare(a));
|
||||
return static_cast<T>(bare(a) - bare(b));
|
||||
}
|
||||
|
||||
template <typename Key, typename In>
|
||||
auto ev(const Key & key, In x)
|
||||
{
|
||||
return bare(*dpf::eval_point(key, x));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(HalfTree, TraitsSelectedByCcrPrg)
|
||||
{
|
||||
static_assert(dpf::tree_traits<ht_prg>::is_half_tree);
|
||||
static_assert(!dpf::tree_traits<leaf_prg>::is_half_tree);
|
||||
static_assert(dpf::tree_traits<ht_prg>::last_level_differs);
|
||||
static_assert(!dpf::tree_traits<ht_prg>::stores_mid_advice);
|
||||
}
|
||||
|
||||
TEST(HalfTree, DealerPointAndFullDomain)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint32_t;
|
||||
const in_t alpha = 0x2a;
|
||||
const out_t beta = 0x01020304;
|
||||
|
||||
auto [k0, k1] = dpf::make_dpf<ht_prg, leaf_prg>(alpha, beta);
|
||||
using key_t = std::decay_t<decltype(k0)>;
|
||||
static_assert(key_t::tree::is_half_tree);
|
||||
|
||||
// Mid-level advice unused; last level may pack BGI-style advice.
|
||||
for (std::size_t i = 0; i + 1 < key_t::depth; ++i)
|
||||
EXPECT_EQ(k0.correction_advice(i), 0) << "mid advice " << i;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
const out_t got = recon(ev(k0, q), ev(k1, q));
|
||||
EXPECT_EQ(got, q == alpha ? beta : out_t{}) << i;
|
||||
}
|
||||
|
||||
auto [buf0, it0] = dpf::eval_full(k0);
|
||||
auto [buf1, it1] = dpf::eval_full(k1);
|
||||
(void)it0;
|
||||
(void)it1;
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const out_t got = recon(buf0[i], buf1[i]);
|
||||
EXPECT_EQ(got, static_cast<in_t>(i) == alpha ? beta : out_t{}) << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HalfTree, OutputParityVsBgi)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint16_t;
|
||||
const in_t alpha = 0x7e;
|
||||
const out_t beta = 0xabcd;
|
||||
|
||||
auto [h0, h1] = dpf::make_dpf<ht_prg, leaf_prg>(alpha, beta);
|
||||
auto [b0, b1] = dpf::make_dpf<leaf_prg, leaf_prg>(alpha, beta);
|
||||
|
||||
// Keys differ (different tree), but reconstructed outputs match.
|
||||
EXPECT_NE(std::memcmp(&h0.root(), &b0.root(), sizeof(simde__m128i)), 0);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
const out_t ht = recon(ev(h0, q), ev(h1, q));
|
||||
const out_t bgi = recon(ev(b0, q), ev(b1, q));
|
||||
EXPECT_EQ(ht, bgi) << i;
|
||||
EXPECT_EQ(ht, q == alpha ? beta : out_t{}) << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HalfTree, DoernerShelatXorMatchesDealer)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint16_t;
|
||||
const in_t alpha = 0x11;
|
||||
const in_t x0 = 0x55;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const out_t y = 0x42;
|
||||
|
||||
reset_roots();
|
||||
auto dealer = dpf::make_dpf<ht_prg, leaf_prg>(alpha,
|
||||
dpf::root_sampler_t<ht_prg>{take_root}, y);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> ds_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat<ht_prg, leaf_prg>(x0, x1, ds_rng, y);
|
||||
|
||||
using key_t = std::decay_t<decltype(dealer.first)>;
|
||||
EXPECT_EQ(std::memcmp(&dealer.first.root(), &ds.first.root(),
|
||||
sizeof(simde__m128i)), 0);
|
||||
EXPECT_EQ(std::memcmp(&dealer.second.root(), &ds.second.root(),
|
||||
sizeof(simde__m128i)), 0);
|
||||
for (std::size_t i = 0; i < key_t::depth; ++i)
|
||||
{
|
||||
EXPECT_EQ(std::memcmp(&dealer.first.correction_word(i),
|
||||
&ds.first.correction_word(i), sizeof(simde__m128i)), 0)
|
||||
<< "cw " << i;
|
||||
EXPECT_EQ(dealer.first.correction_advice(i),
|
||||
ds.first.correction_advice(i))
|
||||
<< "advice " << i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
EXPECT_EQ(recon(ev(ds.first, q), ev(ds.second, q)),
|
||||
q == alpha ? y : out_t{})
|
||||
<< i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HalfTree, DoernerShelatArithMatchesDealer)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint16_t;
|
||||
const in_t alpha = 0xc0;
|
||||
const in_t x0 = 0x40;
|
||||
const in_t x1 = static_cast<in_t>(alpha - x0);
|
||||
const out_t y = 9;
|
||||
|
||||
reset_roots();
|
||||
auto dealer = dpf::make_dpf<ht_prg, leaf_prg>(alpha,
|
||||
dpf::root_sampler_t<ht_prg>{take_root}, y);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> ds_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat<ht_prg, leaf_prg>(dpf::arith_input,
|
||||
x0, x1, ds_rng, y);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
EXPECT_EQ(recon(ev(ds.first, q), ev(ds.second, q)),
|
||||
q == alpha ? y : out_t{})
|
||||
<< i;
|
||||
EXPECT_EQ(ev(ds.first, q), ev(dealer.first, q)) << "p0 " << i;
|
||||
EXPECT_EQ(ev(ds.second, q), ev(dealer.second, q)) << "p1 " << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HalfTree, GenevalPointMatchesDealer)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint16_t;
|
||||
const in_t alpha = 0x33;
|
||||
const in_t x0 = 0x0f;
|
||||
const in_t x1 = static_cast<in_t>(alpha ^ x0);
|
||||
const out_t y = 0x77;
|
||||
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf<ht_prg, leaf_prg>(alpha,
|
||||
dpf::root_sampler_t<ht_prg>{take_root}, y);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> g_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto g = dpf::geneval_point<ht_prg, leaf_prg>(x0, x1, alpha, g_rng, y);
|
||||
|
||||
using key_t = std::decay_t<decltype(keys.first)>;
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
EXPECT_EQ(g.live_levels, key_t::depth);
|
||||
for (std::size_t i = 0; i < g.live_levels; ++i)
|
||||
{
|
||||
EXPECT_EQ(std::memcmp(&g.correction_words[i],
|
||||
&keys.first.correction_word(i), sizeof(simde__m128i)), 0)
|
||||
<< "cw " << i;
|
||||
EXPECT_EQ(g.correction_advice[i], keys.first.correction_advice(i))
|
||||
<< "advice " << i;
|
||||
}
|
||||
ASSERT_EQ(g.party0.size(), 1u);
|
||||
EXPECT_EQ(g.party0[0], ev(keys.first, alpha));
|
||||
EXPECT_EQ(g.party1[0], ev(keys.second, alpha));
|
||||
EXPECT_EQ(recon(g.party0[0], g.party1[0]), y);
|
||||
}
|
||||
|
||||
TEST(HalfTree, GenevalArithPointMatchesDealer)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using out_t = std::uint16_t;
|
||||
const in_t alpha = 0x90;
|
||||
const in_t x0 = 0x20;
|
||||
const in_t x1 = static_cast<in_t>(alpha - x0);
|
||||
const out_t y = 3;
|
||||
|
||||
reset_roots();
|
||||
auto keys = dpf::make_dpf<ht_prg, leaf_prg>(alpha,
|
||||
dpf::root_sampler_t<ht_prg>{take_root}, y);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> g_rng{take_root, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto g = dpf::geneval_point<ht_prg, leaf_prg>(dpf::arith_input, x0, x1,
|
||||
alpha, g_rng, y);
|
||||
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
ASSERT_EQ(g.party0.size(), 1u);
|
||||
EXPECT_EQ(recon(g.party0[0], g.party1[0]), y);
|
||||
EXPECT_EQ(g.party0[0], ev(keys.first, alpha));
|
||||
EXPECT_EQ(g.party1[0], ev(keys.second, alpha));
|
||||
}
|
||||
|
||||
TEST(HalfTree, IncrementalCmpSmoke)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
using ht_prg = dpf::prg::aes128_ccr;
|
||||
using leaf_prg = dpf::prg::aes128;
|
||||
const in_t alpha = 0x40;
|
||||
const uint64_t if_true = 4;
|
||||
const uint64_t if_false = 1;
|
||||
|
||||
auto ht = dpf::make_dpf<ht_prg, leaf_prg>(alpha,
|
||||
dpf::lt(if_true, if_false));
|
||||
auto bgi = dpf::make_dpf<leaf_prg, leaf_prg>(alpha,
|
||||
dpf::lt(if_true, if_false));
|
||||
|
||||
using key_t = std::decay_t<decltype(ht.first)>;
|
||||
static_assert(key_t::tree::is_half_tree);
|
||||
for (std::size_t i = 0; i + 1 < key_t::depth; ++i)
|
||||
EXPECT_EQ(ht.first.correction_advice(i), 0) << "mid advice " << i;
|
||||
|
||||
const uint64_t mask = ht.first.cmp().mask;
|
||||
auto recon_cmp = [&](const auto & k0, const auto & k1, in_t q) {
|
||||
return dpf::reconstruct(dpf::eval_point(dpf::cmp, k0, q),
|
||||
dpf::eval_point(dpf::cmp, k1, q))
|
||||
& mask;
|
||||
};
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
const auto ht_got = recon_cmp(ht.first, ht.second, q);
|
||||
const auto bgi_got = recon_cmp(bgi.first, bgi.second, q);
|
||||
const uint64_t expect = (q < alpha) ? if_true : if_false;
|
||||
EXPECT_EQ(ht_got, expect) << i;
|
||||
EXPECT_EQ(ht_got, bgi_got) << "parity " << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HalfTree, IncrementalPlacementSmoke)
|
||||
{
|
||||
using in_t = std::uint8_t;
|
||||
const in_t alpha = 0x40;
|
||||
auto keys = dpf::make_dpf<ht_prg, leaf_prg>(alpha, dpf::at<8>(uint8_t{7}));
|
||||
|
||||
using key_t = std::decay_t<decltype(keys.first)>;
|
||||
static_assert(key_t::tree::is_half_tree);
|
||||
for (std::size_t i = 0; i + 1 < key_t::depth; ++i)
|
||||
EXPECT_EQ(keys.first.correction_advice(i), 0) << "mid advice " << i;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const in_t q = static_cast<in_t>(i);
|
||||
const auto got = recon(*dpf::eval_point(keys.first, q),
|
||||
*dpf::eval_point(keys.second, q));
|
||||
EXPECT_EQ(got, q == alpha ? uint8_t{7} : uint8_t{0}) << i;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
#include "dpf.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -40,6 +41,39 @@ void expect_domain(Input r, Input p, Input q, Beta if_true, Beta if_false,
|
|||
}
|
||||
}
|
||||
|
||||
struct IcPad
|
||||
{
|
||||
simde__m128i block() { return dpf::uniform_sample<simde__m128i>(); }
|
||||
uint8_t bit() { return static_cast<uint8_t>(dpf::uniform_sample<uint8_t>() & 1u); }
|
||||
};
|
||||
|
||||
using IcRng = dpf::ds_randomness<decltype(&dpf::uniform_sample<simde__m128i>), IcPad>;
|
||||
|
||||
IcRng ic_rng()
|
||||
{
|
||||
return {&dpf::uniform_sample<simde__m128i>, {}};
|
||||
}
|
||||
|
||||
template <typename Input>
|
||||
void expect_samples(Input r, Input p, Input q, uint32_t if_true, uint32_t if_false,
|
||||
std::initializer_list<Input> xs)
|
||||
{
|
||||
auto keys = dpf::make_dpf(r, dpf::ic(p, q, if_true, if_false));
|
||||
const uint64_t nmask = keys.first.input_mask;
|
||||
const uint64_t rb = static_cast<uint64_t>(r);
|
||||
const uint64_t pb = static_cast<uint64_t>(p);
|
||||
const uint64_t qb = static_cast<uint64_t>(q);
|
||||
for (Input x : xs)
|
||||
{
|
||||
const uint64_t got = static_cast<uint64_t>(dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, keys.first, x),
|
||||
dpf::eval_point(dpf::ic, keys.second, x))) & 0xffffffffu;
|
||||
const uint64_t want = oracle(static_cast<uint64_t>(x), rb, pb, qb, nmask,
|
||||
if_true, if_false, 0xffffffffu);
|
||||
EXPECT_EQ(got, want) << "r=" << rb << " x=" << static_cast<uint64_t>(x);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Ic, Uint8FullDomainCorners)
|
||||
|
|
@ -222,3 +256,92 @@ TEST(Ic, BitPayload)
|
|||
EXPECT_EQ(static_cast<bool>(y), w >= 1 && w <= 3) << x;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Ic, Uint16FullDomain)
|
||||
{
|
||||
expect_domain<uint16_t>(uint16_t{0x0100}, uint16_t{20}, uint16_t{400},
|
||||
uint32_t{9}, uint32_t{3}, 0xffffffffu);
|
||||
expect_domain<uint16_t>(uint16_t{0xFF00}, uint16_t{0}, uint16_t{1},
|
||||
uint32_t{1}, uint32_t{0}, 0xffffffffu);
|
||||
}
|
||||
|
||||
TEST(Ic, WideMasksSampleTheWrap)
|
||||
{
|
||||
const uint32_t p32 = 10, q32 = 1000;
|
||||
const uint32_t r32 = 0xFFFFFFF0u;
|
||||
expect_samples<uint32_t>(r32, p32, q32, 7u, 2u, {
|
||||
0u, 1u, p32, q32, q32 + 1u, r32, r32 - 1u, r32 + 1u,
|
||||
0x80000000u, 0xffffffffu
|
||||
});
|
||||
|
||||
const uint64_t p64 = 1, q64 = 3;
|
||||
const uint64_t r64 = ~uint64_t{0};
|
||||
expect_samples<uint64_t>(r64, p64, q64, 5u, 4u, {
|
||||
0ull, 1ull, 2ull, 3ull, 4ull, r64, r64 - 1ull,
|
||||
uint64_t{1} << 63
|
||||
});
|
||||
auto keys = dpf::make_dpf(r64, dpf::ic(p64, q64, uint32_t{5}, uint32_t{4}));
|
||||
EXPECT_EQ(keys.first.input_mask, ~uint64_t{0});
|
||||
}
|
||||
|
||||
TEST(Ic, AdditiveDoernerShelatMatchesDealer)
|
||||
{
|
||||
auto check = [](uint8_t r0, uint8_t r1, uint8_t p, uint8_t q,
|
||||
uint32_t beta, uint32_t fals) {
|
||||
const uint8_t r = static_cast<uint8_t>(r0 + r1);
|
||||
auto dealer = dpf::make_dpf(r, dpf::ic(p, q, beta, fals));
|
||||
auto ds = dpf::make_dpf_doerner_shelat(dpf::arith_input, r0, r1, ic_rng(),
|
||||
dpf::ic(p, q, beta, fals));
|
||||
for (int x = 0; x < 256; ++x)
|
||||
{
|
||||
const auto dealer_y = dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, dealer.first, static_cast<uint8_t>(x)),
|
||||
dpf::eval_point(dpf::ic, dealer.second, static_cast<uint8_t>(x)));
|
||||
const auto ds_y = dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, ds.first, static_cast<uint8_t>(x)),
|
||||
dpf::eval_point(dpf::ic, ds.second, static_cast<uint8_t>(x)));
|
||||
EXPECT_EQ(dealer_y, ds_y) << "r0=" << int(r0) << " r1=" << int(r1)
|
||||
<< " x=" << x;
|
||||
}
|
||||
};
|
||||
check(9, 100, 3, 50, 4, 0);
|
||||
check(200, 100, 0, 255, 8, 1);
|
||||
check(200, 200, 10, 20, 6, 2);
|
||||
check(0, 0, 1, 1, 1, 0);
|
||||
check(1, 0, 0, 0, 3, 9);
|
||||
}
|
||||
|
||||
TEST(Ic, AdditiveGeneval)
|
||||
{
|
||||
const uint8_t r0 = 250, r1 = 20, p = 4, q = 8;
|
||||
const uint32_t beta = 11, fals = 2;
|
||||
const uint8_t r = static_cast<uint8_t>(r0 + r1);
|
||||
const uint8_t queries[] = {0, 1, 4, 8, 9, 255};
|
||||
auto opened = dpf::geneval_ic(dpf::arith_input, r0, r1,
|
||||
std::begin(queries), std::end(queries), ic_rng(),
|
||||
dpf::ic(p, q, beta, fals));
|
||||
ASSERT_EQ(opened.party0.size(), 6u);
|
||||
for (std::size_t i = 0; i < 6; ++i)
|
||||
{
|
||||
const uint64_t got = (opened.party0[i] + opened.party1[i]) & 0xffffffffu;
|
||||
const uint64_t w = static_cast<uint64_t>(static_cast<uint8_t>(queries[i] - r));
|
||||
const uint64_t want = (w >= p && w <= q) ? beta : fals;
|
||||
EXPECT_EQ(got, want) << i;
|
||||
}
|
||||
|
||||
const uint8_t none[] = {0};
|
||||
auto empty = dpf::geneval_ic(dpf::arith_input, r0, r1,
|
||||
std::begin(none), std::begin(none), ic_rng(), dpf::ic(p, q, beta));
|
||||
EXPECT_TRUE(empty.party0.empty());
|
||||
EXPECT_EQ(empty.live_levels, 0u);
|
||||
}
|
||||
|
||||
TEST(Ic, IntervalRejectsDescendingEndpoints)
|
||||
{
|
||||
auto keys = dpf::make_dpf(uint8_t{4}, dpf::ic(uint8_t{1}, uint8_t{6}, uint32_t{1}));
|
||||
auto buf = dpf::make_output_buffer(dpf::ic, keys.first, 1);
|
||||
EXPECT_THROW(dpf::eval_interval(dpf::ic, keys.first, uint8_t{9}, uint8_t{2}, buf),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(dpf::make_output_buffer(dpf::ic, keys.first, uint8_t{9}, uint8_t{2}),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@
|
|||
#include "dpf.hpp"
|
||||
#include "dpf/json.hpp"
|
||||
|
||||
static_assert(NLOHMANN_JSON_VERSION_MAJOR == 3
|
||||
&& NLOHMANN_JSON_VERSION_MINOR == 12
|
||||
&& NLOHMANN_JSON_VERSION_PATCH == 0,
|
||||
"JSON tests build against nlohmann 3.12.0");
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
|
@ -17,15 +22,16 @@ TEST(IncrementalJsonTest, CmpKeyRoundTrips)
|
|||
const uint32_t alpha = 0x00abcdefu;
|
||||
const uint64_t yt = 42u;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::lt(yt));
|
||||
using KT = std::decay_t<decltype(k0)>;
|
||||
static_assert(KT::is_multilevel, "cmp key must be multi-level");
|
||||
ASSERT_EQ(KT::num_outputs, 0u);
|
||||
using KT0 = std::decay_t<decltype(k0)>;
|
||||
using KT1 = std::decay_t<decltype(k1)>;
|
||||
static_assert(KT0::is_multilevel, "cmp key must be multi-level");
|
||||
ASSERT_EQ(KT0::num_outputs, 0u);
|
||||
|
||||
const std::string s0 = dpf::json::to_json(k0);
|
||||
const std::string s1 = dpf::json::to_json(k1);
|
||||
|
||||
auto r0 = dpf::json::from_json<KT>(s0);
|
||||
auto r1 = dpf::json::from_json<KT>(s1);
|
||||
auto r0 = dpf::json::from_json<KT0>(s0);
|
||||
auto r1 = dpf::json::from_json<KT1>(s1);
|
||||
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
EXPECT_EQ(r0.cmp().nbits, k0.cmp().nbits);
|
||||
|
|
@ -48,10 +54,11 @@ TEST(IncrementalJsonTest, CmpGeqRoundTrips)
|
|||
const uint32_t alpha = 100u;
|
||||
const uint64_t yt = 5u, yf = 9u;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::geq(yt, yf));
|
||||
using KT = std::decay_t<decltype(k0)>;
|
||||
using KT0 = std::decay_t<decltype(k0)>;
|
||||
using KT1 = std::decay_t<decltype(k1)>;
|
||||
|
||||
auto r0 = dpf::json::from_json<KT>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<KT>(dpf::json::to_json(k1));
|
||||
auto r0 = dpf::json::from_json<KT0>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<KT1>(dpf::json::to_json(k1));
|
||||
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
auto r = [&](uint32_t q) {
|
||||
|
|
@ -62,4 +69,184 @@ TEST(IncrementalJsonTest, CmpGeqRoundTrips)
|
|||
EXPECT_EQ(r(101u), yt);
|
||||
}
|
||||
|
||||
// A single-output classic key, including its leaf share.
|
||||
TEST(IncrementalJsonTest, ClassicPointRoundTrips)
|
||||
{
|
||||
const uint32_t alpha = 0x00abcdefu;
|
||||
const uint32_t y = 99u;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
using P0 = std::decay_t<decltype(k0)>;
|
||||
using P1 = std::decay_t<decltype(k1)>;
|
||||
|
||||
auto r0 = dpf::json::from_json<P0>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<P1>(dpf::json::to_json(k1));
|
||||
|
||||
EXPECT_EQ(static_cast<uint32_t>(dpf::reconstruct(
|
||||
*dpf::eval_point(r0, alpha), *dpf::eval_point(r1, alpha))), y);
|
||||
EXPECT_EQ(static_cast<uint32_t>(dpf::reconstruct(
|
||||
*dpf::eval_point(r0, alpha ^ 1u), *dpf::eval_point(r1, alpha ^ 1u))), 0u);
|
||||
}
|
||||
|
||||
// Multi-lane outputs are stored as leaf blocks, not truncated integers.
|
||||
TEST(IncrementalJsonTest, VecOutputRoundTrips)
|
||||
{
|
||||
using out_t = dpf::vec<std::uint32_t, 4>;
|
||||
const std::uint16_t alpha = 0x1234;
|
||||
out_t y;
|
||||
y[0] = 1;
|
||||
y[1] = 0xffffffffu;
|
||||
y[2] = 7;
|
||||
y[3] = 100;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
using P0 = std::decay_t<decltype(k0)>;
|
||||
using P1 = std::decay_t<decltype(k1)>;
|
||||
auto r0 = dpf::json::from_json<P0>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<P1>(dpf::json::to_json(k1));
|
||||
auto at = [&](std::uint16_t x) {
|
||||
return dpf::reconstruct(*dpf::eval_point(r0, x), *dpf::eval_point(r1, x));
|
||||
};
|
||||
EXPECT_EQ(at(alpha), y);
|
||||
EXPECT_EQ(at(0), out_t{});
|
||||
EXPECT_EQ(at(static_cast<std::uint16_t>(alpha + 1)), out_t{});
|
||||
}
|
||||
|
||||
// `at<>` keys carry leaf outputs the comparison-only path used to drop.
|
||||
TEST(IncrementalJsonTest, AtOutputRoundTrips)
|
||||
{
|
||||
const uint32_t x = 0x00abcdefu;
|
||||
auto [k0, k1] = dpf::make_dpf(x, dpf::at<10>(dpf::bit::one));
|
||||
using P0 = std::decay_t<decltype(k0)>;
|
||||
using P1 = std::decay_t<decltype(k1)>;
|
||||
static_assert(P0::is_multilevel, "at<> key must be multi-level");
|
||||
ASSERT_GT(P0::num_outputs, 0u);
|
||||
|
||||
auto r0 = dpf::json::from_json<P0>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<P1>(dpf::json::to_json(k1));
|
||||
EXPECT_TRUE(static_cast<bool>(dpf::reconstruct(
|
||||
*dpf::eval_point(dpf::out<0, 10>, r0, x),
|
||||
*dpf::eval_point(dpf::out<0, 10>, r1, x))));
|
||||
const uint32_t neighbor = x ^ (1u << (32 - 10));
|
||||
EXPECT_FALSE(static_cast<bool>(dpf::reconstruct(
|
||||
*dpf::eval_point(dpf::out<0, 10>, r0, neighbor),
|
||||
*dpf::eval_point(dpf::out<0, 10>, r1, neighbor))));
|
||||
}
|
||||
|
||||
// Point output and comparison channel on one key.
|
||||
TEST(IncrementalJsonTest, OutputAndCmpRoundTrips)
|
||||
{
|
||||
const uint32_t alpha = 0x00abcdefu;
|
||||
const uint64_t yt = 42u;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, uint32_t{7}, dpf::lt(yt));
|
||||
using P0 = std::decay_t<decltype(k0)>;
|
||||
using P1 = std::decay_t<decltype(k1)>;
|
||||
auto r0 = dpf::json::from_json<P0>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<P1>(dpf::json::to_json(k1));
|
||||
|
||||
EXPECT_EQ(static_cast<uint32_t>(dpf::reconstruct(
|
||||
*dpf::eval_point(r0, alpha), *dpf::eval_point(r1, alpha))), 7u);
|
||||
EXPECT_EQ(static_cast<uint32_t>(dpf::reconstruct(
|
||||
*dpf::eval_point(r0, alpha ^ 1u), *dpf::eval_point(r1, alpha ^ 1u))), 0u);
|
||||
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
auto recon_cmp = [&](uint32_t q) {
|
||||
return dpf::reconstruct(dpf::eval_point(dpf::cmp, r0, q),
|
||||
dpf::eval_point(dpf::cmp, r1, q)) & mask;
|
||||
};
|
||||
EXPECT_EQ(recon_cmp(alpha - 1u), yt);
|
||||
EXPECT_EQ(recon_cmp(alpha), 0u);
|
||||
EXPECT_EQ(recon_cmp(alpha + 1u), 0u);
|
||||
}
|
||||
|
||||
// Comparison payloads wider than 64 bits stay in the correction words.
|
||||
TEST(IncrementalJsonTest, Uint128CmpRoundTrips)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t alpha = 0x20;
|
||||
const beta hi = (beta{1} << 80) + 9;
|
||||
const beta lo = beta{3};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(hi, lo));
|
||||
using P0 = std::decay_t<decltype(k0)>;
|
||||
using P1 = std::decay_t<decltype(k1)>;
|
||||
const std::string s0 = dpf::json::to_json(k0);
|
||||
EXPECT_NE(s0.find("\"cw_last\":["), std::string::npos);
|
||||
|
||||
auto r0 = dpf::json::from_json<P0>(s0);
|
||||
auto r1 = dpf::json::from_json<P1>(dpf::json::to_json(k1));
|
||||
EXPECT_EQ(r0.cw_last_word(), k0.cw_last_word());
|
||||
EXPECT_EQ(r0.cmp_addend_word(), k0.cmp_addend_word());
|
||||
EXPECT_EQ(r0.value_cw(), k0.value_cw());
|
||||
for (int x = 0; x < 256; ++x)
|
||||
{
|
||||
const auto q = static_cast<std::uint8_t>(x);
|
||||
const beta got = dpf::reconstruct(
|
||||
dpf::eval_point<beta>(dpf::cmp, r0, q),
|
||||
dpf::eval_point<beta>(dpf::cmp, r1, q));
|
||||
const beta want = q > alpha ? hi : lo;
|
||||
EXPECT_EQ(got, want) << int(q);
|
||||
}
|
||||
}
|
||||
|
||||
// iDCF prefix corrections are part of the same wide word.
|
||||
TEST(IncrementalJsonTest, Uint128IdcfRoundTrips)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t alpha = 0x6e;
|
||||
const beta y = (beta{1} << 100) + 13;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::idcf(dpf::gt(y)));
|
||||
using P0 = std::decay_t<decltype(k0)>;
|
||||
using P1 = std::decay_t<decltype(k1)>;
|
||||
auto r0 = dpf::json::from_json<P0>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<P1>(dpf::json::to_json(k1));
|
||||
EXPECT_EQ(r0.prefix_cws(), k0.prefix_cws());
|
||||
for (std::uint8_t q : {std::uint8_t{0}, std::uint8_t{0x60}, alpha, std::uint8_t{0x70}})
|
||||
{
|
||||
const beta got = dpf::reconstruct(
|
||||
dpf::eval_point<beta>(dpf::cmp, r0, q),
|
||||
dpf::eval_point<beta>(dpf::cmp, r1, q));
|
||||
const beta want = dpf::reconstruct(
|
||||
dpf::eval_point<beta>(dpf::cmp, k0, q),
|
||||
dpf::eval_point<beta>(dpf::cmp, k1, q));
|
||||
EXPECT_EQ(got, want) << int(q);
|
||||
}
|
||||
}
|
||||
|
||||
// Wildcard coefficients survive, so assign_cmp still works after a round-trip.
|
||||
TEST(IncrementalJsonTest, WildcardCmpAssignAfterRoundTrip)
|
||||
{
|
||||
const uint32_t alpha = 0x00abcdefu;
|
||||
const uint64_t yt = 42u;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::lt(dpf::wildcard_value<uint64_t>{}));
|
||||
using P0 = std::decay_t<decltype(k0)>;
|
||||
using P1 = std::decay_t<decltype(k1)>;
|
||||
static_assert(P0::cmp_is_wildcard, "expected a wildcard comparison key");
|
||||
|
||||
auto r0 = dpf::json::from_json<P0>(dpf::json::to_json(k0));
|
||||
auto r1 = dpf::json::from_json<P1>(dpf::json::to_json(k1));
|
||||
EXPECT_FALSE(r0.cmp_assigned());
|
||||
EXPECT_EQ(r0.value_cw_coeff(), k0.value_cw_coeff());
|
||||
EXPECT_EQ(r0.cw_last_coeff_word(), k0.cw_last_coeff_word());
|
||||
|
||||
dpf::assign_cmp(r0, r1, yt);
|
||||
EXPECT_TRUE(r0.cmp_assigned());
|
||||
const uint64_t mask = k0.cmp().mask;
|
||||
auto r = [&](uint32_t q) {
|
||||
return dpf::reconstruct(dpf::eval_point(dpf::cmp, r0, q),
|
||||
dpf::eval_point(dpf::cmp, r1, q)) & mask;
|
||||
};
|
||||
EXPECT_EQ(r(alpha - 1u), yt);
|
||||
EXPECT_EQ(r(0u), yt);
|
||||
EXPECT_EQ(r(alpha), 0u);
|
||||
EXPECT_EQ(r(alpha + 1u), 0u);
|
||||
|
||||
auto a0 = dpf::json::from_json<P0>(dpf::json::to_json(r0));
|
||||
auto a1 = dpf::json::from_json<P1>(dpf::json::to_json(r1));
|
||||
EXPECT_TRUE(a0.cmp_assigned());
|
||||
auto again = [&](uint32_t q) {
|
||||
return dpf::reconstruct(dpf::eval_point(dpf::cmp, a0, q),
|
||||
dpf::eval_point(dpf::cmp, a1, q)) & mask;
|
||||
};
|
||||
EXPECT_EQ(again(alpha - 1u), yt);
|
||||
EXPECT_EQ(again(alpha), 0u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -447,7 +447,10 @@ TEST_F(IncrementalDpfTest, DealerMatchesDoernerShelat)
|
|||
dpf::xor_wrapper<uint16_t>{0xcafe});
|
||||
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<10>(dpf::bit::one),
|
||||
dpf::at<14>(uint8_t{3}, uint8_t{5}),
|
||||
|
|
@ -458,7 +461,10 @@ TEST_F(IncrementalDpfTest, DealerMatchesDoernerShelat)
|
|||
EXPECT_TRUE(same_incr_key(dealer.second, ds.second));
|
||||
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadB> rngb{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds2 = dpf::make_dpf_doerner_shelat(x0, x1, rngb,
|
||||
dpf::at<10>(dpf::bit::one),
|
||||
dpf::at<14>(uint8_t{3}, uint8_t{5}),
|
||||
|
|
@ -483,7 +489,10 @@ TEST_F(IncrementalDpfTest, IntermediateWildcardSameKey)
|
|||
uint64_t{42});
|
||||
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<10>(dpf::bit::one), dpf::at<16>(wc), uint64_t{42});
|
||||
|
||||
|
|
@ -615,7 +624,10 @@ TEST_F(IncrementalDpfTest, DsEvalAgreesWithDealer)
|
|||
dpf::at<10>(dpf::bit::one), uint32_t{99});
|
||||
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<10>(dpf::bit::one), uint32_t{99});
|
||||
|
||||
|
|
@ -796,7 +808,10 @@ TEST_F(IncrementalDpfTest, FixedpointDealerMatchesDoernerShelat)
|
|||
fp16::from_raw(0x00030000));
|
||||
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<12>(y, z), dpf::at<16>(wc), fp16::from_raw(0x00030000));
|
||||
|
||||
|
|
@ -1010,7 +1025,10 @@ TEST_F(IncrementalDpfTest, LocalCwProtocolMatchesDsRandomness)
|
|||
uint32_t x1 = x ^ x0;
|
||||
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto via_rng = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<10>(dpf::bit::one), uint32_t{5});
|
||||
|
||||
|
|
@ -1156,7 +1174,10 @@ TEST_F(IncrementalDpfTest, CmpDealerMatchesDoernerShelat)
|
|||
dpf::lt(uint64_t{42}));
|
||||
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<10>(dpf::bit::one),
|
||||
dpf::lt(uint64_t{42}));
|
||||
|
|
@ -1335,7 +1356,10 @@ TEST_F(IncrementalDpfTest, CmpValueCwGroupWidthDsParity)
|
|||
dpf::lt(uint16_t{42}));
|
||||
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng, dpf::lt(uint16_t{42}));
|
||||
|
||||
using KT = std::decay_t<decltype(dealer.first)>;
|
||||
|
|
@ -1627,7 +1651,10 @@ TEST_F(IncrementalDpfTest, DsWildcardCmpMatchesDealerThenAssign)
|
|||
dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
dpf::lt(dpf::wildcard_value<uint64_t>{}));
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(a0, a1, rng,
|
||||
dpf::lt(dpf::wildcard_value<uint64_t>{}));
|
||||
|
||||
|
|
@ -1686,7 +1713,10 @@ TEST_F(IncrementalDpfTest, DsWildcardCmpWithAtAndNarrowPayload)
|
|||
dpf::at<16>(uint16_t{9}),
|
||||
dpf::lt(dpf::wildcard_value<uint16_t>{}));
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(a0, a1, rng,
|
||||
dpf::at<16>(uint16_t{9}),
|
||||
dpf::lt(dpf::wildcard_value<uint16_t>{}));
|
||||
|
|
|
|||
|
|
@ -392,7 +392,10 @@ TEST(LaneBlast, GenevalMatchesKeyOnPackedLanes)
|
|||
dpf::root_sampler_t<dpf::prg::aes128>{take_root}, y);
|
||||
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto on = dpf::geneval_point(x0, x1, alpha, dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
expect_live_words(keys.first, on);
|
||||
EXPECT_TRUE(on.leaf_live);
|
||||
EXPECT_EQ(opened(on.party0[0], on.party1[0]), y);
|
||||
|
|
@ -401,8 +404,11 @@ TEST(LaneBlast, GenevalMatchesKeyOnPackedLanes)
|
|||
|
||||
const in_t neighbor = static_cast<in_t>(alpha ^ 1u);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto lane = dpf::geneval_point(x0, x1, neighbor,
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_TRUE(lane.leaf_live);
|
||||
expect_live_words(keys.first, lane);
|
||||
EXPECT_EQ(opened(lane.party0[0], lane.party1[0]), out_t{});
|
||||
|
|
@ -410,7 +416,10 @@ TEST(LaneBlast, GenevalMatchesKeyOnPackedLanes)
|
|||
|
||||
const in_t far = 200;
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto off = dpf::geneval_point(x0, x1, far, dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_FALSE(off.leaf_live);
|
||||
EXPECT_LT(off.live_levels, off.correction_words.size());
|
||||
expect_live_words(keys.first, off);
|
||||
|
|
@ -418,8 +427,11 @@ TEST(LaneBlast, GenevalMatchesKeyOnPackedLanes)
|
|||
EXPECT_NE(off.party0[0], ev(keys.first, far));
|
||||
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto iv = dpf::geneval_interval(x0, x1, in_t{41}, in_t{50},
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_TRUE(iv.leaf_live);
|
||||
expect_live_words(keys.first, iv);
|
||||
ASSERT_EQ(iv.party0.size(), 10u);
|
||||
|
|
@ -427,7 +439,10 @@ TEST(LaneBlast, GenevalMatchesKeyOnPackedLanes)
|
|||
EXPECT_EQ(opened(iv.party0[i], iv.party1[i]), out_t{});
|
||||
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto full = dpf::geneval_full(x0, x1, dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_EQ(full.party0.size(), 256u);
|
||||
EXPECT_TRUE(full.leaf_live);
|
||||
expect_live_words(keys.first, full);
|
||||
|
|
@ -440,8 +455,11 @@ TEST(LaneBlast, GenevalMatchesKeyOnPackedLanes)
|
|||
|
||||
const in_t seq[] = {0, 255, alpha, neighbor, alpha};
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto sq = dpf::geneval_sequence(x0, x1, std::begin(seq), std::end(seq),
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_TRUE(sq.leaf_live);
|
||||
expect_live_words(keys.first, sq);
|
||||
for (std::size_t i = 0; i < 5; ++i)
|
||||
|
|
@ -463,15 +481,21 @@ TEST(LaneBlast, GenevalNybleArithAndSigned)
|
|||
auto keys = dpf::make_dpf(secret,
|
||||
dpf::root_sampler_t<dpf::prg::aes128>{take_root}, y);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto g = dpf::geneval_point(dpf::arith_input, a0, a1, secret,
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_TRUE(g.leaf_live);
|
||||
expect_live_words(keys.first, g);
|
||||
EXPECT_EQ(opened(g.party0[0], g.party1[0]), y);
|
||||
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto miss = dpf::geneval_point(dpf::arith_input, a0, a1, in_t{250},
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_EQ(opened(miss.party0[0], miss.party1[0]), out_t{});
|
||||
expect_live_words(keys.first, miss);
|
||||
}
|
||||
|
|
@ -484,7 +508,10 @@ TEST(LaneBlast, GenevalNybleArithAndSigned)
|
|||
auto keys = dpf::make_dpf(alpha,
|
||||
dpf::root_sampler_t<dpf::prg::aes128>{take_root}, y);
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto full = dpf::geneval_full(x0, x1, dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_EQ(full.party0.size(), 256u);
|
||||
EXPECT_TRUE(full.leaf_live);
|
||||
expect_live_words(keys.first, full);
|
||||
|
|
@ -497,8 +524,11 @@ TEST(LaneBlast, GenevalNybleArithAndSigned)
|
|||
EXPECT_EQ(full.party0[i], ev(keys.first, v));
|
||||
}
|
||||
reset_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto iv = dpf::geneval_interval(x0, x1, in_t{-2}, in_t{2},
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad>{take_root, Pad{}}, y);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
ASSERT_EQ(iv.party0.size(), 5u);
|
||||
for (int q = -2; q <= 2; ++q)
|
||||
{
|
||||
|
|
|
|||
180
test/tests/multipoint_test.cpp
Normal file
180
test/tests/multipoint_test.cpp
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
using Interior = dpf::prg::aes128;
|
||||
using Exterior = dpf::prg::aes128;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename Input, typename Output, typename Key0, typename Key1>
|
||||
void expect_points(const Key0 & k0, const Key1 & k1,
|
||||
const std::vector<Input> & alphas, const std::vector<Output> & betas)
|
||||
{
|
||||
for (std::size_t i = 0; i < alphas.size(); ++i)
|
||||
{
|
||||
EXPECT_EQ(dpf::reconstruct(dpf::eval_multipoint(k0, alphas[i]),
|
||||
dpf::eval_multipoint(k1, alphas[i])),
|
||||
betas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Multipoint, PlainPointsAndZeros)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
const std::vector<Input> alphas{1, 2, 9, 40};
|
||||
const std::vector<std::uint64_t> betas{7, 11, 1000, 3};
|
||||
auto [k0, k1] = dpf::make_multipoint(alphas, betas);
|
||||
EXPECT_FALSE(decltype(k0)::is_verifiable);
|
||||
EXPECT_TRUE(decltype(k0)::is_multipoint);
|
||||
EXPECT_EQ(k0.bucket_count, k1.bucket_count);
|
||||
EXPECT_EQ(k0.bucket_domain, k1.bucket_domain);
|
||||
EXPECT_GT(k0.bucket_count, alphas.size());
|
||||
|
||||
expect_points(k0, k1, alphas, betas);
|
||||
for (Input x = 0; x < 255; ++x)
|
||||
{
|
||||
const bool hot = x == 1 || x == 2 || x == 9 || x == 40;
|
||||
const auto y = dpf::reconstruct(dpf::eval_multipoint(k0, x),
|
||||
dpf::eval_multipoint(k1, x));
|
||||
if (!hot)
|
||||
EXPECT_EQ(y, 0u);
|
||||
}
|
||||
EXPECT_EQ(dpf::reconstruct(dpf::eval_multipoint(k0, Input{255}),
|
||||
dpf::eval_multipoint(k1, Input{255})),
|
||||
0u);
|
||||
}
|
||||
|
||||
TEST(Multipoint, VerifiableFullDomain)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
const std::vector<Input> alphas{4, 8, 15, 16};
|
||||
const std::vector<std::uint64_t> betas{1, 2, 3, 4};
|
||||
auto [k0, k1] = dpf::make_multipoint(alphas, betas, dpf::verifiable{});
|
||||
EXPECT_TRUE(decltype(k0)::is_verifiable);
|
||||
|
||||
dpf::proof_token batch0{}, batch1{};
|
||||
std::array<Input, 256> xs{};
|
||||
for (int i = 0; i < 256; ++i)
|
||||
xs[static_cast<std::size_t>(i)] = static_cast<Input>(i);
|
||||
std::vector<decltype(k0)::share_type> y0(xs.size());
|
||||
std::vector<decltype(k1)::share_type> y1(xs.size());
|
||||
dpf::eval_multipoint(k0, xs, y0.begin(), dpf::prove(batch0));
|
||||
dpf::eval_multipoint(k1, xs, y1.begin(), dpf::prove(batch1));
|
||||
EXPECT_TRUE(dpf::verify(batch0, batch1));
|
||||
|
||||
for (std::size_t i = 0; i < xs.size(); ++i)
|
||||
{
|
||||
std::uint64_t expect = 0;
|
||||
for (std::size_t p = 0; p < alphas.size(); ++p)
|
||||
if (alphas[p] == xs[i])
|
||||
expect = betas[p];
|
||||
EXPECT_EQ(dpf::reconstruct(y0[i], y1[i]), expect);
|
||||
}
|
||||
|
||||
dpf::proof_token a0{}, a1{};
|
||||
dpf::audit_multipoint(k0, dpf::prove(a0));
|
||||
dpf::audit_multipoint(k1, dpf::prove(a1));
|
||||
EXPECT_TRUE(dpf::verify(a0, a1));
|
||||
}
|
||||
|
||||
TEST(Multipoint, TamperedBucketRejects)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
const std::vector<Input> alphas{3, 5, 7, 9};
|
||||
const std::vector<std::uint64_t> betas{1, 1, 1, 1};
|
||||
auto [k0, k1] = dpf::make_multipoint(alphas, betas, dpf::verifiable{});
|
||||
|
||||
auto & cs = const_cast<dpf::cs_block &>(k0.buckets[0].correction_seeds()[0]);
|
||||
cs[0] = simde_mm_xor_si128(cs[0], simde_mm_set1_epi8(1));
|
||||
|
||||
dpf::proof_token a0{}, a1{};
|
||||
dpf::audit_multipoint(k0, dpf::prove(a0));
|
||||
dpf::audit_multipoint(k1, dpf::prove(a1));
|
||||
EXPECT_FALSE(dpf::verify(a0, a1));
|
||||
}
|
||||
|
||||
TEST(Multipoint, XorAndHalfTree)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
using Ht = dpf::prg::aes128_ccr;
|
||||
const std::array<Input, 4> alphas{10, 20, 30, 40};
|
||||
const std::array<dpf::xor_wrapper<std::uint32_t>, 4> betas{
|
||||
dpf::xor_wrapper<std::uint32_t>{0x11u},
|
||||
dpf::xor_wrapper<std::uint32_t>{0x22u},
|
||||
dpf::xor_wrapper<std::uint32_t>{0x33u},
|
||||
dpf::xor_wrapper<std::uint32_t>{0x44u}};
|
||||
auto [k0, k1] = dpf::make_multipoint<Ht, Ht>(alphas, betas, dpf::verifiable{});
|
||||
EXPECT_TRUE(std::decay_t<decltype(k0.buckets[0])>::tree::is_half_tree);
|
||||
|
||||
for (std::size_t i = 0; i < alphas.size(); ++i)
|
||||
{
|
||||
dpf::proof_token p0{}, p1{};
|
||||
const auto y0 = dpf::eval_multipoint(k0, alphas[i], dpf::prove(p0));
|
||||
const auto y1 = dpf::eval_multipoint(k1, alphas[i], dpf::prove(p1));
|
||||
EXPECT_EQ(dpf::reconstruct(y0, y1), betas[i]);
|
||||
EXPECT_TRUE(dpf::verify(p0, p1));
|
||||
}
|
||||
EXPECT_EQ(dpf::reconstruct(dpf::eval_multipoint(k0, Input{0}),
|
||||
dpf::eval_multipoint(k1, Input{0})),
|
||||
dpf::xor_wrapper<std::uint32_t>{0});
|
||||
}
|
||||
|
||||
TEST(Multipoint, Remark1Packing)
|
||||
{
|
||||
using Input = std::uint16_t;
|
||||
std::vector<Input> alphas;
|
||||
std::vector<std::uint64_t> betas;
|
||||
alphas.reserve(32);
|
||||
betas.reserve(32);
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
alphas.push_back(static_cast<Input>(100 + i * 17));
|
||||
betas.push_back(static_cast<std::uint64_t>(i + 1));
|
||||
}
|
||||
auto [k0, k1] = dpf::make_multipoint(alphas, betas);
|
||||
EXPECT_LE(k0.bucket_count, alphas.size() * 2);
|
||||
expect_points(k0, k1, alphas, betas);
|
||||
EXPECT_EQ(dpf::reconstruct(dpf::eval_multipoint(k0, Input{1}),
|
||||
dpf::eval_multipoint(k1, Input{1})),
|
||||
0u);
|
||||
}
|
||||
|
||||
TEST(Multipoint, RejectsAnEmptyListAndALengthMismatch)
|
||||
{
|
||||
const std::vector<std::uint8_t> alphas{1, 2};
|
||||
const std::vector<std::uint64_t> betas{1};
|
||||
EXPECT_THROW(
|
||||
{
|
||||
auto keys = dpf::make_multipoint(alphas, betas);
|
||||
(void)keys;
|
||||
},
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(
|
||||
{
|
||||
auto keys = dpf::make_multipoint(
|
||||
std::vector<std::uint8_t>{}, std::vector<std::uint64_t>{});
|
||||
(void)keys;
|
||||
},
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(Multipoint, RejectsDuplicates)
|
||||
{
|
||||
const std::vector<std::uint8_t> alphas{1, 2, 1, 4};
|
||||
const std::vector<std::uint64_t> betas{1, 2, 3, 4};
|
||||
EXPECT_THROW(
|
||||
{
|
||||
auto keys = dpf::make_multipoint(alphas, betas);
|
||||
(void)keys;
|
||||
},
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
|
@ -168,6 +168,19 @@ TEST(Nmod, RejectsAZeroReciprocalAndAHugeQuotient)
|
|||
std::overflow_error);
|
||||
}
|
||||
|
||||
TEST(Nmod, ScalePastTheProductWindow)
|
||||
{
|
||||
const auto pos = grotto::nmod(1, 200, 1, 60, 4);
|
||||
EXPECT_EQ(pos.quotient, 0);
|
||||
EXPECT_EQ(pos.residue, 0);
|
||||
|
||||
const auto neg = grotto::nmod(-1, 200, 1, 60, 4);
|
||||
EXPECT_EQ(neg.quotient, -1);
|
||||
EXPECT_EQ(neg.residue, 15);
|
||||
|
||||
EXPECT_THROW(grotto::nmod(1, 100001u, 1, 0, 4), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(Nmod, MostNegativeInputModuloOne)
|
||||
{
|
||||
const auto split = grotto::nmod(INT64_MIN, 0, 1, 0, 4);
|
||||
|
|
|
|||
|
|
@ -172,6 +172,8 @@ TEST(PackedLane, ScalarRing)
|
|||
EXPECT_EQ(10_nyble, dpf::nyble{10});
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<dpf::twobit>, 2u);
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<dpf::nyble>, 4u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::twobit, simde__m256i>), 2u);
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::nyble, simde__m128i>), 4u);
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<dpf::twobit, simde__m128i>), 64u);
|
||||
|
|
@ -179,6 +181,7 @@ TEST(PackedLane, ScalarRing)
|
|||
EXPECT_EQ((dpf::outputs_per_leaf_v<dpf::nyble, simde__m128i>), 32u);
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<dpf::nyble, simde__m256i>), 64u);
|
||||
EXPECT_EQ((dpf::lg_outputs_per_leaf_v<dpf::twobit, simde__m256i>), 7u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
}
|
||||
|
||||
TEST(PackedLane, SimdMatchesScalar)
|
||||
|
|
@ -229,8 +232,11 @@ TEST(PackedLane, LeafFunctorsMatchSimd)
|
|||
auto via4 = dpf::lane_arith::mul_epi4(a256, dpf::nyble{7});
|
||||
EXPECT_EQ(std::memcmp(&scaled, &via4, sizeof(via4)), 0);
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
std::array<simde__m128i, 2> aa{a128, b128};
|
||||
std::array<simde__m128i, 2> bb{b128, a128};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto both = dpf::add_leaf<dpf::nyble>(aa, bb);
|
||||
auto e0 = dpf::lane_arith::add_epi4(a128, b128);
|
||||
auto e1 = dpf::lane_arith::add_epi4(b128, a128);
|
||||
|
|
|
|||
|
|
@ -209,8 +209,11 @@ TEST(PathRecipe, DoernerShelatAndGenevalMatchLength)
|
|||
lcp_len(static_cast<uint8_t>(x), alpha));
|
||||
}
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), dpf::detail::urandom_pad_rng> rng{
|
||||
dpf::uniform_sample<simde__m128i>, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
const uint8_t ends[] = {0x00, 0x91, 0xFF};
|
||||
auto g = dpf::geneval_cmp(x0, x1, std::begin(ends), std::end(ends), rng,
|
||||
dpf::lcp(uint64_t{1}));
|
||||
|
|
|
|||
135
test/tests/prg_aes_ccr_test.cpp
Normal file
135
test/tests/prg_aes_ccr_test.cpp
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "simde/simde/x86/avx2.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool blocks_equal(simde__m128i a, simde__m128i b)
|
||||
{
|
||||
return simde_mm_movemask_epi8(simde_mm_cmpeq_epi8(a, b)) == 0xFFFF;
|
||||
}
|
||||
|
||||
simde__m128i block_from_lanes(std::uint64_t lo, std::uint64_t hi)
|
||||
{
|
||||
return simde_mm_set_epi64x(static_cast<long long>(hi),
|
||||
static_cast<long long>(lo));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(AesCcrPrg, SigmaRoundTrip)
|
||||
{
|
||||
using prg = dpf::prg::aes128_ccr;
|
||||
const simde__m128i samples[] = {
|
||||
block_from_lanes(0, 0),
|
||||
block_from_lanes(1, 0),
|
||||
block_from_lanes(0, 1),
|
||||
block_from_lanes(0x0123456789abcdefull, 0xfedcba9876543210ull),
|
||||
block_from_lanes(~0ull, ~0ull),
|
||||
};
|
||||
for (simde__m128i x : samples)
|
||||
{
|
||||
EXPECT_TRUE(blocks_equal(prg::sigma_inv(prg::sigma(x)), x));
|
||||
EXPECT_TRUE(blocks_equal(prg::sigma(prg::sigma_inv(x)), x));
|
||||
EXPECT_TRUE(blocks_equal(prg::sigma_prime(x),
|
||||
simde_mm_xor_si128(prg::sigma(x), x)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AesCcrPrg, HashIsAesMmoOfSigma)
|
||||
{
|
||||
using prg = dpf::prg::aes128_ccr;
|
||||
simde__m128i x = block_from_lanes(0x1111222233334444ull, 0x5555666677778888ull);
|
||||
EXPECT_TRUE(blocks_equal(prg::hash(x),
|
||||
dpf::prg::aes128::eval(prg::sigma(x), 0)));
|
||||
EXPECT_TRUE(blocks_equal(prg::H(x), prg::hash(x)));
|
||||
EXPECT_TRUE(blocks_equal(prg::eval(x, 0), prg::hash(x)));
|
||||
EXPECT_TRUE(blocks_equal(prg::eval(x, 3),
|
||||
dpf::prg::aes128::eval(prg::sigma(x), 3)));
|
||||
}
|
||||
|
||||
TEST(AesCcrPrg, Eval01IsHalfTreeChildren)
|
||||
{
|
||||
using prg = dpf::prg::aes128_ccr;
|
||||
simde__m128i seed = block_from_lanes(0x0123456789abcdefull, 0xfedcba9876543210ull);
|
||||
auto kids = prg::eval01(seed);
|
||||
const simde__m128i h = prg::hash(seed);
|
||||
EXPECT_TRUE(blocks_equal(kids[0], h));
|
||||
EXPECT_TRUE(blocks_equal(kids[1], simde_mm_xor_si128(h, seed)));
|
||||
EXPECT_TRUE(blocks_equal(simde_mm_xor_si128(kids[0], kids[1]), seed));
|
||||
}
|
||||
|
||||
TEST(AesCcrPrg, TwoTweakDiffersFromHalfExpand)
|
||||
{
|
||||
using prg = dpf::prg::aes128_ccr;
|
||||
simde__m128i seed = block_from_lanes(7, 9);
|
||||
auto half = prg::eval01(seed);
|
||||
auto tw = prg::eval01_twotweak(seed);
|
||||
const simde__m128i base = dpf::unset_lo_bit(seed);
|
||||
EXPECT_TRUE(blocks_equal(tw[0], prg::hash(base)));
|
||||
EXPECT_TRUE(blocks_equal(tw[1], prg::hash(dpf::set_lo_bit(base))));
|
||||
EXPECT_FALSE(blocks_equal(half[0], tw[0])); // half hashes full seed
|
||||
EXPECT_FALSE(blocks_equal(half[1], tw[1]));
|
||||
}
|
||||
|
||||
TEST(AesCcrPrg, HashX4MatchesScalar)
|
||||
{
|
||||
using prg = dpf::prg::aes128_ccr;
|
||||
alignas(16) simde__m128i in[4] = {
|
||||
block_from_lanes(1, 2),
|
||||
block_from_lanes(3, 4),
|
||||
block_from_lanes(5, 6),
|
||||
block_from_lanes(7, 8),
|
||||
};
|
||||
alignas(16) simde__m128i out[4];
|
||||
prg::hash_x4(in, out);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
EXPECT_TRUE(blocks_equal(out[i], prg::hash(in[i]))) << i;
|
||||
}
|
||||
|
||||
TEST(AesCcrPrg, Eval01X4MatchesScalar)
|
||||
{
|
||||
using prg = dpf::prg::aes128_ccr;
|
||||
alignas(16) simde__m128i seeds[4] = {
|
||||
block_from_lanes(10, 20),
|
||||
block_from_lanes(30, 40),
|
||||
block_from_lanes(50, 60),
|
||||
block_from_lanes(70, 80),
|
||||
};
|
||||
alignas(16) simde__m128i left[4], right[4];
|
||||
prg::eval01_x4(seeds, left, right);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
auto kids = prg::eval01(seeds[i]);
|
||||
EXPECT_TRUE(blocks_equal(left[i], kids[0])) << i;
|
||||
EXPECT_TRUE(blocks_equal(right[i], kids[1])) << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AesCcrPrg, BulkEvalMatchesScalarAndRejectsAWrappingSpan)
|
||||
{
|
||||
using prg = dpf::prg::aes128_ccr;
|
||||
simde__m128i seed = block_from_lanes(0xabcdu, 0x1234u);
|
||||
alignas(16) simde__m128i out[3];
|
||||
out[0] = block_from_lanes(1, 1);
|
||||
prg::eval(seed, out, 0);
|
||||
EXPECT_TRUE(blocks_equal(out[0], block_from_lanes(1, 1)));
|
||||
prg::eval(seed, out, 3, 5);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
EXPECT_TRUE(blocks_equal(out[i], prg::eval(seed, static_cast<std::uint32_t>(5 + i))))
|
||||
<< i;
|
||||
EXPECT_THROW(prg::eval(seed, out, 2, 0xffffffffu), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(AesCcrPrg, HalfTreeTagIsPresent)
|
||||
{
|
||||
static_assert(std::is_void_v<dpf::prg::aes128_ccr::half_tree_tag>);
|
||||
SUCCEED();
|
||||
}
|
||||
|
|
@ -243,3 +243,41 @@ TEST(ChachaPrg, ExpandAndBufferedReplay)
|
|||
EXPECT_EQ(replay.get<0>(), s0);
|
||||
EXPECT_NE(s0, streamed.get<0>());
|
||||
}
|
||||
|
||||
template <typename PRG>
|
||||
void expect_chacha_comparison_and_interval()
|
||||
{
|
||||
const std::uint8_t alpha = 0x3C;
|
||||
auto [c0, c1] = dpf::make_dpf<PRG>(alpha, dpf::lt(std::uint32_t{7}, std::uint32_t{1}));
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const auto x = static_cast<std::uint8_t>(i);
|
||||
const auto got = dpf::reconstruct(
|
||||
dpf::eval_point(dpf::cmp, c0, x),
|
||||
dpf::eval_point(dpf::cmp, c1, x));
|
||||
EXPECT_EQ(static_cast<std::uint64_t>(got) & 0xffffffffu,
|
||||
x < alpha ? 7u : 1u)
|
||||
<< "x=" << i;
|
||||
}
|
||||
|
||||
const std::uint8_t r = 9, p = 2, q = 5;
|
||||
auto keys = dpf::make_dpf<PRG>(r, dpf::ic(p, q, std::uint32_t{4}, std::uint32_t{1}));
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
const auto x = static_cast<std::uint8_t>(i);
|
||||
const auto got = dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, keys.first, x),
|
||||
dpf::eval_point(dpf::ic, keys.second, x));
|
||||
const auto w = static_cast<std::uint8_t>(x - r);
|
||||
EXPECT_EQ(static_cast<std::uint64_t>(got) & 0xffffffffu,
|
||||
(w >= p && w <= q) ? 4u : 1u)
|
||||
<< "x=" << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ChachaPrg, ComparisonAndIntervalKeys)
|
||||
{
|
||||
expect_chacha_comparison_and_interval<dpf::prg::chacha20>();
|
||||
expect_chacha_comparison_and_interval<dpf::prg::chacha12>();
|
||||
expect_chacha_comparison_and_interval<dpf::prg::chacha8>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ long double truth_of(grotto::reduced which, long double x)
|
|||
case grotto::reduced::inv: return 1.0L / x;
|
||||
case grotto::reduced::rsqrt: return 1.0L / std::sqrt(x);
|
||||
case grotto::reduced::invsq: return 1.0L / (x * x);
|
||||
case grotto::reduced::expm1: return expm1l(x);
|
||||
case grotto::reduced::log1p: return log1pl(x);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -64,6 +66,8 @@ const char * name_of(grotto::reduced which)
|
|||
case grotto::reduced::inv: return "inv";
|
||||
case grotto::reduced::rsqrt: return "rsqrt";
|
||||
case grotto::reduced::invsq: return "invsq";
|
||||
case grotto::reduced::expm1: return "expm1";
|
||||
case grotto::reduced::log1p: return "log1p";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
|
@ -244,3 +248,99 @@ TEST(RangeLut, RejectsPolesAndNonPositiveLogarithms)
|
|||
EXPECT_THROW(grotto::eval_reduced(grotto::reduced::csch, 16, 0), std::domain_error);
|
||||
EXPECT_THROW(grotto::eval_reduced(grotto::reduced::ln, 7, 32), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(RangeLut, TanAndSecPolesThrow)
|
||||
{
|
||||
const unsigned k = 16;
|
||||
auto pole_of = [&](grotto::reduced which) {
|
||||
const std::int64_t lo = raw_of(-8.0L, k);
|
||||
const std::int64_t hi = raw_of(8.0L, k);
|
||||
for (std::int64_t raw = lo; raw <= hi; ++raw)
|
||||
{
|
||||
try
|
||||
{
|
||||
(void)grotto::eval_reduced(which, k, raw);
|
||||
}
|
||||
catch (const std::domain_error &)
|
||||
{
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
return std::int64_t{0};
|
||||
};
|
||||
for (auto which : {grotto::reduced::tan, grotto::reduced::sec})
|
||||
{
|
||||
const std::int64_t raw = pole_of(which);
|
||||
ASSERT_NE(raw, 0) << name_of(which);
|
||||
EXPECT_THROW(grotto::eval_reduced(which, k, raw), std::domain_error)
|
||||
<< name_of(which) << " raw=" << raw;
|
||||
if (raw > raw_of(-8.0L, k))
|
||||
{
|
||||
EXPECT_NO_THROW(grotto::eval_reduced(which, k, raw - 1))
|
||||
<< name_of(which);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RangeLut, Exp10RejectsAnIntegerPowerPast18)
|
||||
{
|
||||
const unsigned k = 16;
|
||||
int first_overflow = -1;
|
||||
for (int n = 0; n <= 20; ++n)
|
||||
{
|
||||
try
|
||||
{
|
||||
(void)grotto::eval_reduced(grotto::reduced::exp10, k, raw_of(static_cast<long double>(n), k));
|
||||
}
|
||||
catch (const std::overflow_error &)
|
||||
{
|
||||
first_overflow = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_GT(first_overflow, 0);
|
||||
ASSERT_LE(first_overflow, 19);
|
||||
EXPECT_NO_THROW(grotto::eval_reduced(grotto::reduced::exp10, k,
|
||||
raw_of(static_cast<long double>(first_overflow - 1), k)));
|
||||
EXPECT_THROW(grotto::eval_reduced(grotto::reduced::exp10, k, raw_of(19.0L, k)),
|
||||
std::overflow_error);
|
||||
EXPECT_THROW(grotto::eval_reduced(grotto::reduced::exp10, k, raw_of(-19.0L, k)),
|
||||
std::overflow_error);
|
||||
}
|
||||
|
||||
TEST(RangeLut, Expm1AndLog1pTrackLibm)
|
||||
{
|
||||
const long double expm1_samples[] = {
|
||||
-4.0L, -2.0L, -1.0L, -0.7L, -0.5L, -0.25L, -0.125L, -0.015625L,
|
||||
0.0L, 0.015625L, 0.125L, 0.25L, 0.5L, 0.7L, 1.0L, 1.5L, 2.0L,
|
||||
};
|
||||
const long double log1p_samples[] = {
|
||||
-0.75L, -0.5L, -0.25L, -0.125L, -0.015625L, 0.0L, 0.015625L,
|
||||
0.125L, 0.25L, 0.5L, 1.0L, 1.5L, 3.0L, 7.5L, 16.0L, 100.0L,
|
||||
};
|
||||
for (unsigned k : grotto::principal_precisions)
|
||||
{
|
||||
expect_ulps(grotto::reduced::expm1, k, std::ldexp(1.0L, -static_cast<int>(k)), 2.0L);
|
||||
expect_ulps(grotto::reduced::expm1, k, -std::ldexp(1.0L, -static_cast<int>(k)), 2.0L);
|
||||
expect_ulps(grotto::reduced::log1p, k, std::ldexp(1.0L, -static_cast<int>(k)), 2.0L);
|
||||
expect_ulps(grotto::reduced::log1p, k, -std::ldexp(1.0L, -static_cast<int>(k)), 2.0L);
|
||||
for (long double x : expm1_samples)
|
||||
expect_ulps(grotto::reduced::expm1, k, x, 20.0L);
|
||||
for (long double x : log1p_samples)
|
||||
expect_ulps(grotto::reduced::log1p, k, x, 8.0L);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RangeLut, Expm1AndLog1pFixpoints)
|
||||
{
|
||||
for (unsigned k : grotto::principal_precisions)
|
||||
{
|
||||
EXPECT_EQ(grotto::eval_reduced(grotto::reduced::expm1, k, 0), 0);
|
||||
EXPECT_EQ(grotto::eval_reduced(grotto::reduced::log1p, k, 0), 0);
|
||||
const std::int64_t neg_one = -raw_of(1.0L, k);
|
||||
EXPECT_THROW(grotto::eval_reduced(grotto::reduced::log1p, k, neg_one), std::domain_error);
|
||||
EXPECT_THROW(grotto::eval_reduced(grotto::reduced::log1p, k, neg_one - 1), std::domain_error);
|
||||
const std::int64_t far = raw_of(-40.0L, k);
|
||||
EXPECT_EQ(grotto::eval_reduced(grotto::reduced::expm1, k, far), neg_one);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -639,7 +639,10 @@ TEST_F(StressScenariosTest, ClassicMixedDealerMatchesDoernerShelat)
|
|||
dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
uint32_t{7}, dpf::xor_wrapper<uint32_t>{0xdeadbeef}, uint32_t{42});
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
uint32_t{7}, dpf::xor_wrapper<uint32_t>{0xdeadbeef}, uint32_t{42});
|
||||
|
||||
|
|
@ -974,7 +977,10 @@ TEST_F(StressScenariosTest, CmpPackedAtDeepestUnderDoernerShelat)
|
|||
uint32_t{9},
|
||||
dpf::lt(uint64_t{42}));
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<14>(uint8_t{3}, uint8_t{5}),
|
||||
uint32_t{9},
|
||||
|
|
@ -1455,7 +1461,7 @@ TEST_F(StressScenariosTest, ModintMultilevelWithCmp)
|
|||
// Full-domain cmp on the 12-bit input: true-value 4 below threshold, 1 at/above.
|
||||
for (unsigned q = 0; q < 0x1000u; q += 0x11u)
|
||||
{
|
||||
in_t qi{q};
|
||||
in_t qi{static_cast<in_t::integral_type>(q)};
|
||||
const auto got = dpf::reconstruct(dpf::eval_point(dpf::cmp, k0, qi), dpf::eval_point(dpf::cmp, k1, qi)) & mask;
|
||||
const auto want = (q < 0x2abu) ? uint64_t{4} : uint64_t{1};
|
||||
EXPECT_EQ(got, want) << "q=" << q;
|
||||
|
|
@ -1509,7 +1515,10 @@ TEST_F(StressScenariosTest, DsIdentityManyLevelsMixedWidthsXorAdditiveCmpLt)
|
|||
uint32_t{9},
|
||||
dpf::lt(uint64_t{42}));
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<8>(dpf::bit::one),
|
||||
dpf::at<16>(uint8_t{3}, dpf::xor_wrapper<uint8_t>{0xa5}),
|
||||
|
|
@ -1551,7 +1560,10 @@ TEST_F(StressScenariosTest, DsIdentityPacked16xU8DeepestGeq)
|
|||
uint32_t{5},
|
||||
dpf::geq(uint16_t{100}, uint16_t{1}));
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<12>(
|
||||
uint8_t{1}, uint8_t{2}, uint8_t{3}, uint8_t{4},
|
||||
|
|
@ -1580,7 +1592,10 @@ TEST_F(StressScenariosTest, DsIdentityClassicMultiLeafXorAdditiveBytes)
|
|||
dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
uint32_t{7}, dpf::xor_wrapper<uint32_t>{0xdeadbeef});
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
uint32_t{7}, dpf::xor_wrapper<uint32_t>{0xdeadbeef});
|
||||
|
||||
|
|
@ -1605,7 +1620,10 @@ TEST_F(StressScenariosTest, DsIdentityIntermediateWildcardConcreteSiblings)
|
|||
dpf::at<16>(uint16_t{5}, wc), // concrete sibling next to the wildcard
|
||||
uint32_t{9});
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<10>(dpf::bit::one),
|
||||
dpf::at<16>(uint16_t{5}, wc),
|
||||
|
|
@ -1637,7 +1655,10 @@ TEST_F(StressScenariosTest, DsIdentityFixedpointAtWithCmp)
|
|||
fp16::from_raw(0x00030000),
|
||||
dpf::lt(uint64_t{1000}));
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<12>(y),
|
||||
fp16::from_raw(0x00030000),
|
||||
|
|
@ -1684,7 +1705,10 @@ TEST_F(StressScenariosTest, DsIdentityAesInteriorLowmcExteriorMultilevel)
|
|||
dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
dpf::at<12>(uint8_t{9}), uint16_t{4});
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat<dpf::prg::aes128, dpf::prg::lowmc128>(
|
||||
x0, x1, rng, dpf::at<12>(uint8_t{9}), uint16_t{4});
|
||||
|
||||
|
|
@ -1711,7 +1735,10 @@ TEST_F(StressScenariosTest, DsIdentityWildcardCmpThenAssign)
|
|||
uint32_t{7},
|
||||
dpf::geq(dpf::wildcard_value<uint64_t>{}));
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<12>(uint8_t{5}),
|
||||
uint32_t{7},
|
||||
|
|
@ -1787,7 +1814,10 @@ TEST_F(StressScenariosTest, DsIdentityModintMultilevelXorAdditiveCmp)
|
|||
uint16_t{9},
|
||||
dpf::lt(uint16_t{4}, uint16_t{1}));
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<6>(uint8_t{5}, dpf::xor_wrapper<uint8_t>{0x3c}),
|
||||
uint16_t{9},
|
||||
|
|
@ -1817,7 +1847,10 @@ TEST_F(StressScenariosTest, DsIdentityKeywordMultilevel)
|
|||
dpf::root_sampler_t<dpf::prg::aes128>{take_root},
|
||||
dpf::at<6>(uint8_t{1}), uint16_t{2});
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<6>(uint8_t{1}), uint16_t{2});
|
||||
|
||||
|
|
@ -2091,7 +2124,10 @@ TEST_F(StressScenariosTest, DsIdentityPackedSmallWildcardAtNonTerminal)
|
|||
dpf::at<14>(w, w, w, w, uint8_t{9}, w, w, w),
|
||||
uint32_t{5});
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1, rng,
|
||||
dpf::at<14>(w, w, w, w, uint8_t{9}, w, w, w),
|
||||
uint32_t{5});
|
||||
|
|
@ -2174,7 +2210,10 @@ TEST_F(StressScenariosTest, DsIdentityPackedWildcardLowmcExteriorThenAssign)
|
|||
dpf::at<12>(w, w, w, w),
|
||||
uint16_t{77});
|
||||
reset_tape_roots();
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), PadA> rng{take_root, {}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto ds = dpf::make_dpf_doerner_shelat<dpf::prg::aes128, dpf::prg::lowmc128>(
|
||||
x0, x1, rng, dpf::at<12>(w, w, w, w), uint16_t{77});
|
||||
|
||||
|
|
|
|||
|
|
@ -189,8 +189,11 @@ TEST(TypeTraits, IntegralSelectionAndBuiltinWidths)
|
|||
EXPECT_EQ(dpf::utils::bitlength_of_v<simde_uint128>, 128u);
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<uint128_t>, 128u);
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<uint256_t>, 256u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<simde__m128i>, 128u);
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<simde__m256i>, 256u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_v<std::array<uint32_t, 4>>), 128u);
|
||||
|
||||
EXPECT_TRUE(dpf::utils::uses_signed_msb_v<int32_t>);
|
||||
|
|
@ -272,6 +275,8 @@ TEST(TypeTraits, BoundaryWidthsAndOutputPacking)
|
|||
static_assert(boundary_width_traits<255>());
|
||||
static_assert(boundary_width_traits<256>());
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<uint8_t, simde__m128i>), 8u);
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<uint16_t, simde__m128i>), 16u);
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<uint32_t, simde__m128i>), 32u);
|
||||
|
|
@ -281,7 +286,10 @@ TEST(TypeTraits, BoundaryWidthsAndOutputPacking)
|
|||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::bit, simde__m128i>), 1u);
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::modint<10>, simde__m128i>), 16u);
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::wildcard_value<uint32_t>, simde__m128i>), 32u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<uint8_t, simde__m128i>), 16u);
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<uint32_t, simde__m128i>), 4u);
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<dpf::bit, simde__m128i>), 128u);
|
||||
|
|
@ -289,6 +297,7 @@ TEST(TypeTraits, BoundaryWidthsAndOutputPacking)
|
|||
EXPECT_EQ((dpf::block_length_of_leaf_v<uint32_t, simde__m128i>), 1u);
|
||||
EXPECT_EQ((dpf::block_length_of_leaf_v<uint256_t, simde__m128i>), 2u);
|
||||
EXPECT_EQ((dpf::block_length_of_leaf_v<dpf::modint<200>, simde__m128i>), 2u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
|
||||
EXPECT_TRUE(std::is_trivially_copyable_v<uint32_t>);
|
||||
EXPECT_TRUE(std::is_trivially_copyable_v<dpf::bit>);
|
||||
|
|
@ -463,7 +472,10 @@ TEST(Bit, ConversionArithmeticAndStreams)
|
|||
EXPECT_EQ(unchanged, dpf::bit::one);
|
||||
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<dpf::bit>, 1u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::bit, simde__m128i>), 1u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_TRUE(std::numeric_limits<dpf::bit>::is_specialized);
|
||||
EXPECT_EQ(std::numeric_limits<dpf::bit>::digits, 1);
|
||||
EXPECT_EQ(std::numeric_limits<dpf::bit const>::digits, 1);
|
||||
|
|
@ -751,7 +763,10 @@ TEST(Wildcard, TraitsAndDeferredValues)
|
|||
EXPECT_TRUE(dpf::is_wildcard_v<dpf::wildcard_value<uint32_t>>);
|
||||
EXPECT_TRUE((std::is_same_v<dpf::concrete_type_t<dpf::wildcard_value<dpf::wildcard_value<int>>>, int>));
|
||||
EXPECT_EQ(dpf::utils::bitlength_of_v<dpf::wildcard_value<uint32_t>>, 32u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_EQ((dpf::utils::bitlength_of_output_v<dpf::wildcard_value<dpf::bit>, simde__m256i>), 1u);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
EXPECT_FALSE(dpf::concrete_value<dpf::wildcard_value<uint32_t>>{}(dpf::wildcard_value<uint32_t>{}).has_value());
|
||||
EXPECT_EQ(dpf::concrete_value<uint32_t>{}(7u), std::optional<uint32_t>{7u});
|
||||
|
||||
|
|
@ -865,8 +880,11 @@ TEST(LeafArithmetic, GroupsWiderThanOneLane)
|
|||
auto pack_sum = [](auto value)
|
||||
{
|
||||
using value_type = decltype(value);
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
constexpr auto blocks = dpf::block_length_of_leaf_v<value_type, simde__m128i>;
|
||||
std::array<simde__m128i, blocks> node{};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
static_assert(sizeof(node) == sizeof(value_type));
|
||||
std::memcpy(node.data(), &value, sizeof(value));
|
||||
return node;
|
||||
|
|
@ -953,14 +971,20 @@ TEST(LeafArithmetic, XorGroupsAndModintLanes)
|
|||
psnip_uint32_t one_bits = 0;
|
||||
std::memcpy(&one_bits, &one, sizeof(one_bits));
|
||||
expect_lanes128<uint32_t>(dpf::multiply_leaf(ones, one), one_bits);
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_TRUE(same128(dpf::leaf_arithmetic::add_t<float, simde__m128i>{}(ones, ones),
|
||||
simde_mm_setzero_si128()));
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
float two = 2.0f;
|
||||
simde__m128i one_node{};
|
||||
simde__m128i two_node{};
|
||||
std::memcpy(&one_node, &one, sizeof(one));
|
||||
std::memcpy(&two_node, &two, sizeof(two));
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto xored = dpf::leaf_arithmetic::add_t<float, simde__m128i>{}(one_node, two_node);
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
float xored_float = 0;
|
||||
std::memcpy(&xored_float, &xored, sizeof(xored_float));
|
||||
EXPECT_NE(xored_float, one + two);
|
||||
|
|
@ -970,9 +994,12 @@ TEST(LeafArithmetic, XorGroupsAndModintLanes)
|
|||
std::memcpy(&dbl_bits, &dbl, sizeof(dbl_bits));
|
||||
auto dbl_scaled = dpf::multiply_leaf(simde_mm_set1_epi64x(-1), dbl);
|
||||
EXPECT_EQ(lane128<uint64_t>(dbl_scaled, 0), dbl_bits);
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
EXPECT_TRUE(same256(dpf::leaf_arithmetic::add_t<double, simde__m256i>{}(
|
||||
splat256<uint64_t>(dbl_bits), splat256<uint64_t>(dbl_bits)),
|
||||
simde_mm256_setzero_si256()));
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
|
||||
auto wildcard_sum = dpf::add_leaf<dpf::wildcard_value<uint32_t>>(
|
||||
splat128<uint32_t>(40), splat128<uint32_t>(2));
|
||||
|
|
@ -996,8 +1023,11 @@ TEST(CustomTypes, InputWalkAndOutputLeaf)
|
|||
|
||||
auto sum = dpf::add_leaf<custom_output_type_small>(splat128<uint64_t>(9), splat128<uint64_t>(4));
|
||||
auto diff = dpf::subtract_leaf<custom_output_type_small>(splat128<uint64_t>(9), splat128<uint64_t>(4));
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto prod = dpf::leaf_arithmetic::multiply_t<custom_output_type_small, simde__m128i>{}(
|
||||
splat128<uint64_t>(6), static_cast<psnip_uint64_t>(7));
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
expect_lanes128<uint64_t>(sum, 13);
|
||||
expect_lanes128<uint64_t>(diff, 5);
|
||||
expect_lanes128<uint64_t>(prod, 42);
|
||||
|
|
|
|||
211
test/tests/verifiable_test.cpp
Normal file
211
test/tests/verifiable_test.cpp
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "dpf.hpp"
|
||||
|
||||
using Interior = dpf::prg::aes128;
|
||||
using Exterior = dpf::prg::aes128;
|
||||
|
||||
TEST(Verifiable, HonestPointAccepts)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
const Input alpha = 0x2a;
|
||||
const std::uint64_t beta = 7;
|
||||
auto [k0, k1] = dpf::make_dpf<Interior, Exterior>(alpha, beta, dpf::verifiable{});
|
||||
EXPECT_TRUE(decltype(k0)::is_verifiable);
|
||||
EXPECT_FALSE(decltype(k0)::is_multilevel);
|
||||
|
||||
dpf::proof_token pi0{}, pi1{};
|
||||
const auto y0 = *dpf::eval_point(k0, alpha, dpf::prove(pi0));
|
||||
const auto y1 = *dpf::eval_point(k1, alpha, dpf::prove(pi1));
|
||||
EXPECT_EQ(dpf::reconstruct(y0, y1), beta);
|
||||
EXPECT_TRUE(dpf::verify(pi0, pi1));
|
||||
|
||||
dpf::proof_token q0{}, q1{};
|
||||
const Input other = static_cast<Input>(alpha ^ 1);
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(k0, other, dpf::prove(q0)),
|
||||
*dpf::eval_point(k1, other, dpf::prove(q1))),
|
||||
0);
|
||||
EXPECT_TRUE(dpf::verify(q0, q1));
|
||||
}
|
||||
|
||||
TEST(Verifiable, TamperedCwRejects)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
auto [k0, k1] = dpf::make_dpf<Interior, Exterior>(Input{3},
|
||||
std::uint64_t{1}, dpf::verifiable{});
|
||||
|
||||
// Flip one bit of a public correction word on party 0's view of the
|
||||
// shared CW array by rebuilding an otherwise-identical key is hard;
|
||||
// instead flip cs after the fact via const_cast of the seed storage.
|
||||
auto & cs = const_cast<dpf::cs_block &>(k0.correction_seeds()[0]);
|
||||
cs[0] = simde_mm_xor_si128(cs[0], simde_mm_set1_epi8(1));
|
||||
|
||||
dpf::proof_token pi0{}, pi1{};
|
||||
(void)*dpf::eval_point(k0, Input{3}, dpf::prove(pi0));
|
||||
(void)*dpf::eval_point(k1, Input{3}, dpf::prove(pi1));
|
||||
EXPECT_FALSE(dpf::verify(pi0, pi1));
|
||||
}
|
||||
|
||||
TEST(Verifiable, BatchVerify)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
auto [k0, k1] = dpf::make_dpf<Interior, Exterior>(Input{1},
|
||||
std::uint64_t{9}, dpf::verifiable{});
|
||||
|
||||
std::vector<dpf::proof_token> left, right;
|
||||
for (Input x = 0; x < 8; ++x)
|
||||
{
|
||||
dpf::proof_token a{}, b{};
|
||||
(void)*dpf::eval_point(k0, x, dpf::prove(a));
|
||||
(void)*dpf::eval_point(k1, x, dpf::prove(b));
|
||||
left.push_back(a);
|
||||
right.push_back(b);
|
||||
}
|
||||
EXPECT_TRUE(dpf::verify_batch(left, right));
|
||||
left[2][0] = simde_mm_xor_si128(left[2][0], simde_mm_set1_epi8(0xff));
|
||||
EXPECT_FALSE(dpf::verify_batch(left, right));
|
||||
right.pop_back();
|
||||
EXPECT_FALSE(dpf::verify_batch(left, right));
|
||||
}
|
||||
|
||||
TEST(Verifiable, HalfTreeXorPayload)
|
||||
{
|
||||
using Input = std::uint16_t;
|
||||
using Ht = dpf::prg::aes128_ccr;
|
||||
const Input alpha = 0x0101;
|
||||
auto [k0, k1] = dpf::make_dpf<Ht, Ht>(alpha,
|
||||
dpf::xor_wrapper<std::uint64_t>{0xdeadbeefull}, dpf::verifiable{});
|
||||
EXPECT_TRUE(decltype(k0)::tree::is_half_tree);
|
||||
|
||||
dpf::proof_token pi0{}, pi1{};
|
||||
const auto y0 = *dpf::eval_point(k0, alpha, dpf::prove(pi0));
|
||||
const auto y1 = *dpf::eval_point(k1, alpha, dpf::prove(pi1));
|
||||
EXPECT_EQ(dpf::reconstruct(y0, y1), dpf::xor_wrapper<std::uint64_t>{0xdeadbeefull});
|
||||
EXPECT_TRUE(dpf::verify(pi0, pi1));
|
||||
}
|
||||
|
||||
TEST(Verifiable, SamePublicPart)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
auto [k0, k1] = dpf::make_dpf<Interior, Exterior>(Input{5},
|
||||
std::uint64_t{2}, dpf::verifiable{});
|
||||
EXPECT_TRUE(dpf::same_public_part(k0, k1));
|
||||
|
||||
auto & cw = const_cast<typename std::decay_t<decltype(k0)>::interior_node &>(
|
||||
k0.correction_words()[0]);
|
||||
cw = simde_mm_xor_si128(cw, simde_mm_set1_epi8(1));
|
||||
EXPECT_FALSE(dpf::same_public_part(k0, k1));
|
||||
}
|
||||
|
||||
TEST(Verifiable, DefaultKeyUnchangedLayout)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
auto [a0, a1] = dpf::make_dpf<Interior, Exterior>(Input{1}, std::uint64_t{3});
|
||||
auto [b0, b1] = dpf::make_dpf<Interior, Exterior>(Input{1}, std::uint64_t{3},
|
||||
dpf::verifiable{});
|
||||
EXPECT_FALSE(decltype(a0)::is_verifiable);
|
||||
EXPECT_TRUE(decltype(b0)::is_verifiable);
|
||||
EXPECT_EQ(sizeof(a0.correction_words()), sizeof(b0.correction_words()));
|
||||
EXPECT_EQ(std::tuple_size_v<typename decltype(a0)::correction_seeds_array>, 0u);
|
||||
EXPECT_GT(std::tuple_size_v<typename decltype(b0)::correction_seeds_array>, 0u);
|
||||
}
|
||||
|
||||
TEST(Extractable, Fp61ReconstructAndSketch)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
const Input alpha = 0x11;
|
||||
const dpf::fp61 beta{42};
|
||||
auto [k0, k1] = dpf::make_dpf<Interior, Exterior>(alpha, beta,
|
||||
dpf::extractable{}, dpf::verifiable{});
|
||||
EXPECT_TRUE(decltype(k0)::is_extractable);
|
||||
EXPECT_TRUE(decltype(k0)::is_verifiable);
|
||||
EXPECT_TRUE(dpf::same_public_part(k0, k1));
|
||||
|
||||
const auto y0 = *dpf::eval_point(k0, alpha);
|
||||
const auto y1 = *dpf::eval_point(k1, alpha);
|
||||
EXPECT_EQ(dpf::reconstruct(y0, y1), beta);
|
||||
|
||||
std::array<Input, 4> pts{0x10, 0x11, 0x12, 0x13};
|
||||
std::array<dpf::fp61, 4> r{
|
||||
dpf::fp61{3}, dpf::fp61{5}, dpf::fp61{7}, dpf::fp61{11}};
|
||||
std::array<dpf::fp61, 4> s0{}, s1{};
|
||||
for (std::size_t i = 0; i < pts.size(); ++i)
|
||||
{
|
||||
s0[i] = (*dpf::eval_point(k0, pts[i])).raw();
|
||||
s1[i] = (*dpf::eval_point(k1, pts[i])).raw();
|
||||
}
|
||||
auto sk0 = dpf::sketch_fold(s0, r);
|
||||
auto sk1 = dpf::sketch_fold(s1, r);
|
||||
EXPECT_TRUE(dpf::sketch_verify(sk0, sk1));
|
||||
|
||||
// Two hot points: forge by XORing a second beta into another share.
|
||||
s0[0] = s0[0] + beta;
|
||||
sk0 = dpf::sketch_fold(s0, r);
|
||||
sk1 = dpf::sketch_fold(s1, r);
|
||||
EXPECT_FALSE(dpf::sketch_verify(sk0, sk1));
|
||||
}
|
||||
|
||||
TEST(Extractable, IncrementalPrefix)
|
||||
{
|
||||
using Input = std::uint16_t;
|
||||
const Input alpha = 0x00ab;
|
||||
auto [k0, k1] = dpf::make_dpf<Interior, Exterior>(alpha,
|
||||
dpf::at<8>(dpf::fp61{1}), dpf::extractable{});
|
||||
EXPECT_TRUE(decltype(k0)::is_extractable);
|
||||
EXPECT_TRUE(decltype(k0)::is_multilevel);
|
||||
|
||||
const auto p0 = *dpf::eval_point(dpf::out<0>, k0, alpha);
|
||||
const auto p1 = *dpf::eval_point(dpf::out<0>, k1, alpha);
|
||||
EXPECT_EQ(dpf::reconstruct(p0, p1), dpf::fp61{1});
|
||||
}
|
||||
|
||||
TEST(Verifiable, IntervalProve)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
auto [k0, k1] = dpf::make_dpf<Interior, Exterior>(Input{0x20},
|
||||
std::uint64_t{1}, dpf::verifiable{});
|
||||
dpf::proof_token a{}, b{};
|
||||
dpf::prove_interval(k0, Input{0x1c}, Input{0x24}, dpf::prove(a));
|
||||
dpf::prove_interval(k1, Input{0x1c}, Input{0x24}, dpf::prove(b));
|
||||
EXPECT_TRUE(dpf::verify(a, b));
|
||||
}
|
||||
|
||||
TEST(Verifiable, DoernerShelatProve)
|
||||
{
|
||||
using Input = std::uint8_t;
|
||||
const Input alpha = 0x44;
|
||||
const std::uint64_t beta = 5;
|
||||
Input x0 = 0x12;
|
||||
Input x1 = static_cast<Input>(alpha ^ x0);
|
||||
struct Pad
|
||||
{
|
||||
std::uint64_t n = 1;
|
||||
simde__m128i block()
|
||||
{
|
||||
auto v = simde_mm_set_epi64x(static_cast<long long>(n),
|
||||
static_cast<long long>(n * 9 + 3));
|
||||
n += 2;
|
||||
return v;
|
||||
}
|
||||
std::uint8_t bit() { return static_cast<std::uint8_t>(n++ & 1u); }
|
||||
};
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
dpf::ds_randomness<simde__m128i (*)(), Pad> rng{
|
||||
dpf::uniform_sample<simde__m128i>, Pad{}};
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
auto [s0, s1] = dpf::make_dpf_doerner_shelat<Interior, Exterior>(
|
||||
x0, x1, rng, beta, dpf::verifiable{});
|
||||
|
||||
EXPECT_TRUE(decltype(s0)::is_verifiable);
|
||||
dpf::proof_token a{}, b{};
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(s0, alpha, dpf::prove(a)),
|
||||
*dpf::eval_point(s1, alpha, dpf::prove(b))),
|
||||
beta);
|
||||
EXPECT_TRUE(dpf::verify(a, b));
|
||||
}
|
||||
345
test/tests/wide_payload_test.cpp
Normal file
345
test/tests/wide_payload_test.cpp
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dpf.hpp"
|
||||
#include "grotto/fixedpoint.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename Beta, typename A, typename B, typename X>
|
||||
Beta recon_cmp(const A & a, const B & b, X x)
|
||||
{
|
||||
return dpf::reconstruct(
|
||||
dpf::eval_point<Beta>(dpf::cmp, a, x),
|
||||
dpf::eval_point<Beta>(dpf::cmp, b, x));
|
||||
}
|
||||
|
||||
template <typename Beta, typename A, typename B, typename X>
|
||||
Beta recon_prefix4(const A & a, const B & b, X x)
|
||||
{
|
||||
return dpf::reconstruct(
|
||||
dpf::eval_point<4, Beta>(dpf::cmp_prefix<4>, a, x),
|
||||
dpf::eval_point<4, Beta>(dpf::cmp_prefix<4>, b, x));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(WidePayload, VectorPointAddsComponentwise)
|
||||
{
|
||||
using out_t = dpf::vec<std::uint32_t, 4>;
|
||||
const std::uint16_t alpha = 0x1234;
|
||||
out_t y;
|
||||
y[0] = 1;
|
||||
y[1] = 0xffffffffu;
|
||||
y[2] = 7;
|
||||
y[3] = 100;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, y);
|
||||
auto at = [&](std::uint16_t x) {
|
||||
return dpf::reconstruct(*dpf::eval_point(k0, x), *dpf::eval_point(k1, x));
|
||||
};
|
||||
EXPECT_EQ(at(alpha), y);
|
||||
EXPECT_EQ(at(0), out_t{});
|
||||
EXPECT_EQ(at(static_cast<std::uint16_t>(alpha + 1)), out_t{});
|
||||
}
|
||||
|
||||
TEST(WidePayload, Uint128Comparison)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t alpha = 0x20;
|
||||
const beta hi = (beta{1} << 80) + 9;
|
||||
const beta lo = beta{3};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(hi, lo));
|
||||
for (int x = 0; x < 256; ++x)
|
||||
{
|
||||
const auto q = static_cast<std::uint8_t>(x);
|
||||
const beta got = recon_cmp<beta>(k0, k1, q);
|
||||
const beta want = q > alpha ? hi : lo;
|
||||
EXPECT_EQ(got, want) << int(q);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WidePayload, FixedpointComparison)
|
||||
{
|
||||
using beta = grotto::fixedpoint<8, std::uint32_t>;
|
||||
const std::uint8_t alpha = 10;
|
||||
const beta hi = beta::from_raw(0x01020304u);
|
||||
const beta lo = beta::from_raw(0x00000007u);
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::lt(hi, lo));
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{9}), hi);
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, alpha), lo);
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{11}), lo);
|
||||
}
|
||||
|
||||
TEST(WidePayload, WideFixedpointComparison)
|
||||
{
|
||||
using beta = grotto::fixedpoint<4, simde_uint128>;
|
||||
const std::uint8_t alpha = 4;
|
||||
const beta hi = beta::from_raw((simde_uint128{1} << 70) + 11);
|
||||
const beta lo = beta::from_raw(simde_uint128{2});
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::geq(hi, lo));
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{3}), lo);
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, alpha), hi);
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{5}), hi);
|
||||
}
|
||||
|
||||
TEST(WidePayload, VectorComparison)
|
||||
{
|
||||
using beta = dpf::vec<std::uint16_t, 3>;
|
||||
const std::uint8_t alpha = 7;
|
||||
beta hi;
|
||||
hi[0] = 9;
|
||||
hi[1] = 1000;
|
||||
hi[2] = 4;
|
||||
beta lo;
|
||||
lo[1] = 1;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(hi, lo));
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{6}), lo);
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{8}), hi);
|
||||
}
|
||||
|
||||
TEST(WidePayload, IntervalContainmentUint128)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t r = 20;
|
||||
const beta hi = (beta{1} << 96) + 5;
|
||||
auto [k0, k1] = dpf::make_dpf(r, dpf::ic(std::uint8_t{3}, std::uint8_t{5}, hi));
|
||||
auto at = [&](std::uint8_t opened) {
|
||||
return dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, k0, opened),
|
||||
dpf::eval_point(dpf::ic, k1, opened));
|
||||
};
|
||||
EXPECT_EQ(at(23), hi);
|
||||
EXPECT_EQ(at(25), hi);
|
||||
EXPECT_EQ(at(22), beta{});
|
||||
EXPECT_EQ(at(26), beta{});
|
||||
}
|
||||
|
||||
TEST(WidePayload, IdcfUint128MatchesFullComparison)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t alpha = 0x6e;
|
||||
const beta y = (beta{1} << 100) + 13;
|
||||
auto [i0, i1] = dpf::make_dpf(alpha, dpf::idcf(dpf::gt(y)));
|
||||
auto [f0, f1] = dpf::make_dpf(alpha, dpf::gt(y));
|
||||
for (int x = 0; x < 256; ++x)
|
||||
{
|
||||
const auto q = static_cast<std::uint8_t>(x);
|
||||
EXPECT_EQ(recon_cmp<beta>(i0, i1, q), recon_cmp<beta>(f0, f1, q));
|
||||
const bool above = (q >> 4) > (alpha >> 4);
|
||||
const beta prefix = recon_prefix4<beta>(i0, i1, q);
|
||||
const beta want = above ? y : beta{};
|
||||
EXPECT_EQ(prefix, want) << int(q);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WidePayload, DealerMatchesDoernerShelat)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint16_t alpha = 0x0102;
|
||||
const std::uint16_t x0 = 0x00f0;
|
||||
const std::uint16_t x1 = static_cast<std::uint16_t>(alpha ^ x0);
|
||||
const beta y = (beta{1} << 77) + 4;
|
||||
auto dealer = dpf::make_dpf(alpha, dpf::gt(y));
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto ds = dpf::make_dpf_doerner_shelat(x0, x1,
|
||||
dpf::ds_randomness<simde__m128i (*)(), dpf::detail::urandom_pad_rng>{
|
||||
dpf::uniform_sample<simde__m128i>, {}},
|
||||
dpf::gt(y));
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
for (std::uint16_t q : {std::uint16_t{0}, std::uint16_t{0x0101}, alpha,
|
||||
std::uint16_t{0x0103}, std::uint16_t{0xffff}})
|
||||
{
|
||||
const beta from_dealer = recon_cmp<beta>(dealer.first, dealer.second, q);
|
||||
const beta from_ds = recon_cmp<beta>(ds.first, ds.second, q);
|
||||
EXPECT_EQ(from_dealer, from_ds) << q;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WidePayload, XorWrapperComparison)
|
||||
{
|
||||
using beta = dpf::xor_wrapper<std::uint32_t>;
|
||||
const std::uint8_t alpha = 9;
|
||||
const beta hi{0x01020304u};
|
||||
const beta lo{0x0000000fu};
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(hi, lo));
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{8}), lo);
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{10}), hi);
|
||||
}
|
||||
|
||||
TEST(WidePayload, WildcardAssignUint128)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t alpha = 15;
|
||||
const beta hi = (beta{1} << 90) + 8;
|
||||
const beta lo = beta{2};
|
||||
const auto wild = dpf::wildcard<beta>;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, dpf::gt(wild));
|
||||
dpf::assign_cmp(k0, k1, hi, lo);
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{14}), lo);
|
||||
EXPECT_EQ(recon_cmp<beta>(k0, k1, std::uint8_t{16}), hi);
|
||||
}
|
||||
|
||||
TEST(WidePayload, IntervalContainmentUint128FalseAndTopBound)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t r = 10;
|
||||
const beta hi = (beta{1} << 90) + 8;
|
||||
const beta lo = beta{3};
|
||||
auto [k0, k1] = dpf::make_dpf(r,
|
||||
dpf::ic(std::uint8_t{5}, std::uint8_t{255}, hi, lo));
|
||||
for (int x = 0; x < 256; ++x)
|
||||
{
|
||||
const auto q = static_cast<std::uint8_t>(x);
|
||||
const auto w = static_cast<std::uint8_t>(q - r);
|
||||
const beta want = (w >= 5) ? hi : lo;
|
||||
EXPECT_EQ(dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, k0, q),
|
||||
dpf::eval_point(dpf::ic, k1, q)),
|
||||
want) << int(q);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WidePayload, IntervalContainmentXorGroup)
|
||||
{
|
||||
using beta = dpf::xor_wrapper<std::uint32_t>;
|
||||
const std::uint8_t r = 40;
|
||||
const beta hi{0x11111111u};
|
||||
const beta lo{0x01010101u};
|
||||
auto [k0, k1] = dpf::make_dpf(r,
|
||||
dpf::ic(std::uint8_t{1}, std::uint8_t{255}, hi, lo));
|
||||
for (int x = 0; x < 256; ++x)
|
||||
{
|
||||
const auto q = static_cast<std::uint8_t>(x);
|
||||
const auto w = static_cast<std::uint8_t>(q - r);
|
||||
const beta want = (w >= 1) ? hi : lo;
|
||||
EXPECT_EQ(dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, k0, q),
|
||||
dpf::eval_point(dpf::ic, k1, q)),
|
||||
want) << int(q);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WidePayload, IntervalContainmentVector)
|
||||
{
|
||||
using beta = dpf::vec<std::uint32_t, 2>;
|
||||
beta hi;
|
||||
hi[0] = 9;
|
||||
hi[1] = 0xffffffffu;
|
||||
beta lo;
|
||||
lo[0] = 1;
|
||||
lo[1] = 2;
|
||||
const std::uint8_t r = 8;
|
||||
auto [k0, k1] = dpf::make_dpf(r,
|
||||
dpf::ic(std::uint8_t{2}, std::uint8_t{4}, hi, lo));
|
||||
auto at = [&](std::uint8_t opened) {
|
||||
return dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, k0, opened),
|
||||
dpf::eval_point(dpf::ic, k1, opened));
|
||||
};
|
||||
EXPECT_EQ(at(10), hi);
|
||||
EXPECT_EQ(at(12), hi);
|
||||
EXPECT_EQ(at(9), lo);
|
||||
EXPECT_EQ(at(13), lo);
|
||||
}
|
||||
|
||||
TEST(WidePayload, IntervalWildcardAssignUint128)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t r = 15;
|
||||
const beta hi = (beta{1} << 90) + 8;
|
||||
const beta lo = beta{2};
|
||||
auto [k0, k1] = dpf::make_dpf(r,
|
||||
dpf::ic(std::uint8_t{2}, std::uint8_t{8}, dpf::wildcard<beta>));
|
||||
EXPECT_THROW(dpf::eval_point(dpf::ic, k0, std::uint8_t{0}), std::invalid_argument);
|
||||
dpf::assign_cmp(k0, k1, hi, lo);
|
||||
auto at = [&](std::uint8_t opened) {
|
||||
return dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, k0, opened),
|
||||
dpf::eval_point(dpf::ic, k1, opened));
|
||||
};
|
||||
EXPECT_EQ(at(17), hi);
|
||||
EXPECT_EQ(at(23), hi);
|
||||
EXPECT_EQ(at(16), lo);
|
||||
EXPECT_EQ(at(24), lo);
|
||||
}
|
||||
|
||||
TEST(WidePayload, IntervalDoernerShelatUint128)
|
||||
{
|
||||
using beta = simde_uint128;
|
||||
const std::uint8_t r0 = 9;
|
||||
const std::uint8_t r1 = 100;
|
||||
const std::uint8_t r = static_cast<std::uint8_t>(r0 ^ r1);
|
||||
const beta hi = (beta{1} << 70) + 4;
|
||||
const beta lo = beta{1};
|
||||
auto dealer = dpf::make_dpf(r, dpf::ic(std::uint8_t{3}, std::uint8_t{50}, hi, lo));
|
||||
HEDLEY_PRAGMA(GCC diagnostic push)
|
||||
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
|
||||
auto ds = dpf::make_dpf_doerner_shelat(r0, r1,
|
||||
dpf::ds_randomness<simde__m128i (*)(), dpf::detail::urandom_pad_rng>{
|
||||
dpf::uniform_sample<simde__m128i>, {}},
|
||||
dpf::ic(std::uint8_t{3}, std::uint8_t{50}, hi, lo));
|
||||
HEDLEY_PRAGMA(GCC diagnostic pop)
|
||||
for (int x = 0; x < 256; x += 17)
|
||||
{
|
||||
const auto q = static_cast<std::uint8_t>(x);
|
||||
EXPECT_EQ(dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, dealer.first, q),
|
||||
dpf::eval_point(dpf::ic, dealer.second, q)),
|
||||
dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, ds.first, q),
|
||||
dpf::eval_point(dpf::ic, ds.second, q)))
|
||||
<< int(q);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WidePayload, Modint96ComparisonAndInterval)
|
||||
{
|
||||
using beta = dpf::modint<96>;
|
||||
const beta hi{simde_uint128{1} << 80};
|
||||
const beta lo{simde_uint128{6}};
|
||||
const std::uint8_t alpha = 12;
|
||||
auto cmp = dpf::make_dpf(alpha, dpf::lt(hi, lo));
|
||||
for (int x = 0; x < 256; ++x)
|
||||
{
|
||||
const auto q = static_cast<std::uint8_t>(x);
|
||||
const beta want = q < alpha ? hi : lo;
|
||||
EXPECT_EQ(recon_cmp<beta>(cmp.first, cmp.second, q), want) << int(q);
|
||||
}
|
||||
|
||||
const std::uint8_t r = 4;
|
||||
auto ic = dpf::make_dpf(r, dpf::ic(std::uint8_t{1}, std::uint8_t{3}, hi, lo));
|
||||
auto at = [&](std::uint8_t opened) {
|
||||
return dpf::reconstruct(
|
||||
dpf::eval_point(dpf::ic, ic.first, opened),
|
||||
dpf::eval_point(dpf::ic, ic.second, opened));
|
||||
};
|
||||
EXPECT_EQ(at(5), hi);
|
||||
EXPECT_EQ(at(7), hi);
|
||||
EXPECT_EQ(at(4), lo);
|
||||
EXPECT_EQ(at(8), lo);
|
||||
}
|
||||
|
||||
TEST(WidePayload, VectorLaneArithmeticDoesNotCarry)
|
||||
{
|
||||
dpf::vec<std::uint32_t, 2> a;
|
||||
dpf::vec<std::uint32_t, 2> b;
|
||||
a[0] = 0xffffffffu;
|
||||
a[1] = 1u;
|
||||
b[0] = 2u;
|
||||
b[1] = 3u;
|
||||
const auto sum = a + b;
|
||||
EXPECT_EQ(sum[0], 1u);
|
||||
EXPECT_EQ(sum[1], 4u);
|
||||
const auto prod = a * b;
|
||||
EXPECT_EQ(prod[0], 0xfffffffeu);
|
||||
EXPECT_EQ(prod[1], 3u);
|
||||
const auto neg = -a;
|
||||
EXPECT_EQ(neg[0], 1u);
|
||||
EXPECT_EQ(neg[1], 0xffffffffu);
|
||||
EXPECT_EQ(a, a);
|
||||
EXPECT_NE(a, b);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue