#include #include #include #include #include #include "dpf.hpp" namespace { TEST(SecretShare, LayoutMatchesValueType) { using T = std::uint64_t; EXPECT_EQ(sizeof(dpf::additive_share), sizeof(T)); EXPECT_EQ(sizeof(dpf::subtractive_share), sizeof(T)); EXPECT_TRUE((std::is_trivially_copyable_v>)); EXPECT_TRUE((std::is_standard_layout_v>)); } TEST(SecretShare, PlaintextSplitOpens) { const std::uint32_t secret = 0xdeadbeefu; auto [a0, a1] = dpf::make_additive_shares(secret); EXPECT_EQ(dpf::reconstruct(a0, a1), secret); EXPECT_EQ(a1.raw(), 0u); auto [s0, s1] = dpf::make_subtractive_shares(secret); EXPECT_EQ(dpf::reconstruct(s0, s1), secret); EXPECT_EQ(s1.raw(), 0u); } TEST(SecretShare, SameSchemeLinearCombo) { auto [a0, a1] = dpf::make_additive_shares(std::uint32_t{10}); auto [b0, b1] = dpf::make_additive_shares(std::uint32_t{3}); auto c0 = a0 * 2 + b0; auto c1 = a1 * 2 + b1; EXPECT_EQ(dpf::reconstruct(c0, c1), 23u); auto [s0, s1] = dpf::make_subtractive_shares(std::uint32_t{10}); auto [t0, t1] = dpf::make_subtractive_shares(std::uint32_t{3}); auto u0 = s0 * 2 - t0; auto u1 = s1 * 2 - t1; EXPECT_EQ(dpf::reconstruct(u0, u1), 17u); } TEST(SecretShare, CrossSchemeSigns) { auto [a0, a1] = dpf::make_additive_shares(std::int32_t{20}); auto [s0, s1] = dpf::make_subtractive_shares(std::int32_t{7}); // party 0: raw add; party 1: flip the differing-scheme operand auto r0 = a0 + s0; auto r1 = a1 + s1; EXPECT_EQ(dpf::reconstruct(r0, r1), 27); auto q0 = s0 + a0; auto q1 = s1 + a1; EXPECT_EQ(dpf::reconstruct(q0, q1), 27); } TEST(SecretShare, PlaintextAbsorbOnParty0) { auto [s0, s1] = dpf::make_subtractive_shares(std::uint32_t{5}); s0 += std::uint32_t{10}; s1 += std::uint32_t{10}; // no-op for party 1 EXPECT_EQ(dpf::reconstruct(s0, s1), 15u); } TEST(SecretShare, AsAdditivePreservesSecret) { auto [s0, s1] = dpf::make_subtractive_shares(std::int32_t{42}); auto a0 = s0.as_additive(); auto a1 = s1.as_additive(); EXPECT_EQ(dpf::reconstruct(a0, a1), 42); } TEST(SecretShare, DpfLeafRoundTrip) { const std::uint8_t alpha = 0x2a; const std::uint32_t beta = 0x01020304; auto [k0, k1] = dpf::make_dpf(alpha, beta); EXPECT_TRUE(dpf::is_party_key_v); EXPECT_EQ(decltype(k0)::party, 0u); EXPECT_EQ(decltype(k1)::party, 1u); auto y0 = *dpf::eval_point(k0, alpha); auto y1 = *dpf::eval_point(k1, alpha); EXPECT_TRUE((std::is_same_v>)); EXPECT_EQ(dpf::reconstruct(y0, y1), beta); auto z0 = *dpf::eval_point(k0, static_cast(alpha ^ 1)); auto z1 = *dpf::eval_point(k1, static_cast(alpha ^ 1)); EXPECT_EQ(dpf::reconstruct(z0, z1), 0u); } TEST(SecretShare, DpfXorLeafRoundTrip) { using X = dpf::xor_wrapper; const std::uint8_t alpha = 7; const X beta{0xA5A5A5A5u}; auto [k0, k1] = dpf::make_dpf(alpha, beta); auto y0 = *dpf::eval_point(k0, alpha); auto y1 = *dpf::eval_point(k1, alpha); EXPECT_EQ(dpf::reconstruct(y0, y1), beta); } TEST(SecretShare, CmpAdditiveRoundTrip) { const std::uint32_t alpha = 100u; const std::uint64_t yt = 5u, yf = 9u; auto [k0, k1] = dpf::make_dpf(alpha, dpf::lt(yt, yf)); const std::uint64_t mask = k0.cmp().mask; auto below = dpf::reconstruct( dpf::eval_point(dpf::cmp, k0, 50u), dpf::eval_point(dpf::cmp, k1, 50u)) & mask; auto at = dpf::reconstruct( dpf::eval_point(dpf::cmp, k0, alpha), dpf::eval_point(dpf::cmp, k1, alpha)) & mask; EXPECT_EQ(below, yt); EXPECT_EQ(at, yf); } TEST(SecretShare, PrgExpandSubtractive) { using prg = dpf::prg::aes128; const auto seed0 = dpf::uniform_sample(); const auto seed1 = dpf::uniform_sample(); auto s0 = prg::expand(seed0, 0); auto s1 = prg::expand(seed1, 0); // Same pos, different seeds: reconstruct is raw0 - raw1 (bit pattern). EXPECT_EQ(dpf::reconstruct(s0, s1), static_cast(s0.raw() - s1.raw())); // Same seed → same bits → reconstruct 0 auto t0 = prg::expand(seed0, 3); auto t1 = prg::expand(seed0, 3); EXPECT_EQ(dpf::reconstruct(t0, t1), 0u); } } // namespace