Checkpoint the party/runtime stack before share-program and malicious-mode work.
Ship the TLS mesh, composer, Beaver/Yao/leaf MPC, prep/online paths, apps, and docs so the tree is pushable before elevating share_expr, security_mode, and prep resume. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
695f8e84f7
commit
0d22946a0e
1835 changed files with 170291 additions and 2849 deletions
|
|
@ -1,4 +1,8 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <tuple>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
#include "asio.hpp"
|
||||
#define LIBDPF_HAS_ASIO
|
||||
|
|
@ -591,7 +595,7 @@ TEST(WildcardTest, PackedSmallWildcardsAtNonTerminalAssignAll)
|
|||
dpf::at<10>(w, w, w, w),
|
||||
uint16_t{99});
|
||||
|
||||
ASSERT_THROW((void)dpf::eval_point(dpf::out<0, 10>, dpf0, x), std::runtime_error);
|
||||
ASSERT_THROW(dpf::eval_point(dpf::out<0, 10>, dpf0, x), std::runtime_error);
|
||||
ASSERT_EQ(static_cast<uint16_t>(
|
||||
dpf::reconstruct(*dpf::eval_point(dpf::out<4>, dpf0, x), *dpf::eval_point(dpf::out<4>, dpf1, x))),
|
||||
uint16_t{99});
|
||||
|
|
@ -617,3 +621,189 @@ TEST(WildcardTest, PackedSmallWildcardsAtNonTerminalAssignAll)
|
|||
static_cast<uint16_t>(x ^ (1u << 6))))),
|
||||
concrete_t{0});
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename Bits, typename T>
|
||||
T bits_as(Bits bits)
|
||||
{
|
||||
T out{};
|
||||
std::memcpy(&out, &bits, sizeof(T));
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto bits_of(T v)
|
||||
{
|
||||
using bits_t = std::conditional_t<sizeof(T) == 4, std::uint32_t, std::uint64_t>;
|
||||
bits_t bits{};
|
||||
std::memcpy(&bits, &v, sizeof(T));
|
||||
return bits;
|
||||
}
|
||||
|
||||
/// In-process assign for a wildcard leaf (same messages as asio, no socket).
|
||||
template <std::size_t I = 0, typename DpfKey0, typename DpfKey1, typename ShareT>
|
||||
void assign_leaf_local(DpfKey0 & dpf0, DpfKey1 & dpf1, const ShareT & shr0,
|
||||
const ShareT & shr1)
|
||||
{
|
||||
auto & w0 = std::get<I>(dpf0.leaf_nodes);
|
||||
auto & w1 = std::get<I>(dpf1.leaf_nodes);
|
||||
if (w0.is_ready())
|
||||
w0.begin_update();
|
||||
if (w1.is_ready())
|
||||
w1.begin_update();
|
||||
const auto b0 = w0.compute_and_get_blinded_output_share(shr0);
|
||||
const auto b1 = w1.compute_and_get_blinded_output_share(shr1);
|
||||
const auto l0 = w0.compute_and_get_leaf_share(b1);
|
||||
const auto l1 = w1.compute_and_get_leaf_share(b0);
|
||||
w0.reconstruct_correction_word(l1);
|
||||
w1.reconstruct_correction_word(l0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(WildcardTest, FullWidthXorDoesNotRevealBeta)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using concrete_type = dpf::xints::xint128_t;
|
||||
using output_type = dpf::wildcard_value<concrete_type>;
|
||||
input_type x = 0x42;
|
||||
output_type y;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
|
||||
auto & w0 = std::get<0>(dpf0.leaf_nodes);
|
||||
auto & w1 = std::get<0>(dpf1.leaf_nodes);
|
||||
// Scale Beaver must be planted even for a single full-width XOR lane.
|
||||
EXPECT_EQ((dpf::outputs_per_leaf_v<concrete_type,
|
||||
typename std::decay_t<decltype(dpf0)>::exterior_node>), 1u);
|
||||
EXPECT_TRUE(dpf::utils::has_characteristic_two_v<concrete_type>);
|
||||
|
||||
concrete_type y_exp = concrete_type{0x0123456789ABCDEFull};
|
||||
concrete_type y_shr0 = concrete_type{0x1111111111111111ull};
|
||||
concrete_type y_shr1 = y_exp + y_shr0; // XOR group
|
||||
|
||||
const auto blinded0 = w0.compute_and_get_blinded_output_share(y_shr0);
|
||||
const auto blinded1 = w1.compute_and_get_blinded_output_share(y_shr1);
|
||||
// With a non-trivial output blind, the exchanged value is not the share.
|
||||
EXPECT_NE(blinded0, y_shr0);
|
||||
EXPECT_NE(blinded1, y_shr1);
|
||||
// Finish the assign after the privacy check above (state is already blinded).
|
||||
const auto l0 = w0.compute_and_get_leaf_share(blinded1);
|
||||
const auto l1 = w1.compute_and_get_leaf_share(blinded0);
|
||||
w0.reconstruct_correction_word(l1);
|
||||
w1.reconstruct_correction_word(l0);
|
||||
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(dpf0, x), *dpf::eval_point(dpf1, x)),
|
||||
y_exp);
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(dpf0, static_cast<input_type>(x ^ 1)),
|
||||
*dpf::eval_point(dpf1, static_cast<input_type>(x ^ 1))),
|
||||
concrete_type{});
|
||||
}
|
||||
|
||||
TEST(WildcardTest, FloatWildcardRoundTrip)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using concrete_type = float;
|
||||
using output_type = dpf::wildcard_value<concrete_type>;
|
||||
input_type x = 0x55;
|
||||
output_type y;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, y);
|
||||
|
||||
const concrete_type y_exp = 3.14159265f;
|
||||
const auto y_bits = bits_of(y_exp);
|
||||
const std::uint32_t shr0_bits = 0xA5A5A5A5u;
|
||||
const concrete_type y_shr0 = bits_as<std::uint32_t, concrete_type>(shr0_bits);
|
||||
const concrete_type y_shr1 =
|
||||
bits_as<std::uint32_t, concrete_type>(y_bits ^ shr0_bits);
|
||||
|
||||
assign_leaf_local(dpf0, dpf1, y_shr0, y_shr1);
|
||||
|
||||
const auto got = dpf::reconstruct(*dpf::eval_point(dpf0, x), *dpf::eval_point(dpf1, x));
|
||||
EXPECT_EQ(bits_of(got), y_bits);
|
||||
EXPECT_EQ(bits_of(dpf::reconstruct(
|
||||
*dpf::eval_point(dpf0, static_cast<input_type>(x ^ 1)),
|
||||
*dpf::eval_point(dpf1, static_cast<input_type>(x ^ 1)))),
|
||||
0u);
|
||||
}
|
||||
|
||||
TEST(WildcardTest, SecondAssignUpdatesPayload)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using concrete_type = uint32_t;
|
||||
using output_type = dpf::wildcard_value<concrete_type>;
|
||||
input_type x = 0x11;
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(x, output_type{});
|
||||
|
||||
const concrete_type beta = 0xAAAAAAAAu;
|
||||
const concrete_type beta2 = 0xBBBBBBBBu;
|
||||
const concrete_type s0 = 0x12345678u;
|
||||
assign_leaf_local(dpf0, dpf1, s0, static_cast<concrete_type>(beta - s0));
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(dpf0, x), *dpf::eval_point(dpf1, x)), beta);
|
||||
|
||||
// Second assign installs (beta2 - beta) on top of the ready leaf.
|
||||
const concrete_type delta = static_cast<concrete_type>(beta2 - beta);
|
||||
const concrete_type d0 = 0x01010101u;
|
||||
assign_leaf_local(dpf0, dpf1, d0, static_cast<concrete_type>(delta - d0));
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(dpf0, x), *dpf::eval_point(dpf1, x)),
|
||||
beta2);
|
||||
}
|
||||
|
||||
TEST(WildcardTest, AssignWildcardInputOpensPublicShiftNotAlpha)
|
||||
{
|
||||
using input_type = uint8_t;
|
||||
using output_type = uint32_t;
|
||||
// Wildcard domain: dealer plants a random mask; parties later open (mask - alpha).
|
||||
auto [dpf0, dpf1] = dpf::make_dpf(dpf::wildcard_value<input_type>{}, output_type{7});
|
||||
|
||||
const input_type mask = static_cast<input_type>(
|
||||
dpf0.offset_x.raw() + dpf1.offset_x.raw());
|
||||
const input_type alpha = 0xAAu;
|
||||
const input_type a0 = 0x12u;
|
||||
const input_type a1 = static_cast<input_type>(alpha - a0);
|
||||
|
||||
const auto sh0 = dpf0.offset_x.compute_and_get_share(a0);
|
||||
const auto sh1 = dpf1.offset_x.compute_and_get_share(a1);
|
||||
const auto open0 = dpf0.offset_x.reconstruct(sh1);
|
||||
const auto open1 = dpf1.offset_x.reconstruct(sh0);
|
||||
|
||||
EXPECT_EQ(open0, open1);
|
||||
const input_type want_shift = static_cast<input_type>(mask - alpha);
|
||||
EXPECT_EQ(open0, want_shift);
|
||||
EXPECT_NE(open0, alpha); // public value is the shift, not alpha
|
||||
EXPECT_EQ(static_cast<input_type>(open0 + alpha), mask);
|
||||
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(dpf0, alpha), *dpf::eval_point(dpf1, alpha)),
|
||||
output_type{7});
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(dpf0, static_cast<input_type>(alpha ^ 1)),
|
||||
*dpf::eval_point(dpf1, static_cast<input_type>(alpha ^ 1))),
|
||||
output_type{0});
|
||||
}
|
||||
|
||||
TEST(WildcardTest, UpdatableTagAssignsThenRewrites)
|
||||
{
|
||||
const std::uint8_t alpha = 0x2a;
|
||||
auto [k0, k1] = dpf::make_dpf(alpha, std::uint64_t{7}, dpf::updatable{});
|
||||
EXPECT_TRUE(k0.is_wildcard(0));
|
||||
EXPECT_TRUE(k1.is_wildcard(0));
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(k0, alpha), *dpf::eval_point(k1, alpha)),
|
||||
std::uint64_t{7});
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(k0, std::uint8_t{0}),
|
||||
*dpf::eval_point(k1, std::uint8_t{0})),
|
||||
std::uint64_t{0});
|
||||
|
||||
auto & w0 = std::get<0>(k0.leaf_nodes);
|
||||
auto & w1 = std::get<0>(k1.leaf_nodes);
|
||||
w0.begin_update();
|
||||
w1.begin_update();
|
||||
// A second assign installs the difference β' − β, not the new absolute payload.
|
||||
const auto shares = dpf::additively_share(std::uint64_t{9} - std::uint64_t{7});
|
||||
const auto b0 = w0.compute_and_get_blinded_output_share(shares.first.raw());
|
||||
const auto b1 = w1.compute_and_get_blinded_output_share(shares.second.raw());
|
||||
const auto l0 = w0.compute_and_get_leaf_share(b1);
|
||||
const auto l1 = w1.compute_and_get_leaf_share(b0);
|
||||
w0.reconstruct_correction_word(l1);
|
||||
w1.reconstruct_correction_word(l0);
|
||||
EXPECT_EQ(dpf::reconstruct(*dpf::eval_point(k0, alpha), *dpf::eval_point(k1, alpha)),
|
||||
std::uint64_t{9});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue