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
|
|
@ -5,8 +5,11 @@
|
|||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "dpf/beaver.hpp"
|
||||
#include "dpf/buffered_prg.hpp"
|
||||
#include "dpf/doerner_shelat.hpp"
|
||||
#include "dpf/modint.hpp"
|
||||
|
||||
namespace
|
||||
|
|
@ -303,6 +306,37 @@ TEST(Beaver, InnerProductMatchesTheSumAndIsOneCross)
|
|||
EXPECT_EQ(fused.open(again), expect);
|
||||
}
|
||||
|
||||
TEST(Beaver, ScheduleObjectiveRoundsKeepsOneRound)
|
||||
{
|
||||
session64 latency;
|
||||
latency.set_schedule_objective(dpf::beavers::schedule_objective::rounds);
|
||||
auto sgn = latency.input();
|
||||
auto x = latency.input();
|
||||
auto a0 = latency.input();
|
||||
auto a1 = latency.input();
|
||||
auto lin = latency(sgn * (a1 * x + a0));
|
||||
EXPECT_EQ(latency.round_of(lin), 1);
|
||||
|
||||
session64 prep;
|
||||
prep.set_schedule_objective(dpf::beavers::schedule_objective::prep);
|
||||
auto ps = prep.input();
|
||||
auto px = prep.input();
|
||||
auto pa0 = prep.input();
|
||||
auto pa1 = prep.input();
|
||||
auto plin = prep(ps * (pa1 * px + pa0));
|
||||
EXPECT_EQ(prep.round_of(plin), 2);
|
||||
EXPECT_LT(prep.preprocessing_count(), latency.preprocessing_count());
|
||||
|
||||
Counter rng;
|
||||
latency.sample(rng);
|
||||
latency.bind(sgn, u64{3}, rng);
|
||||
latency.bind(x, u64{2}, rng);
|
||||
latency.bind(a0, u64{4}, rng);
|
||||
latency.bind(a1, u64{5}, rng);
|
||||
latency.evaluate();
|
||||
EXPECT_EQ(latency.open(lin), 3u * (5u * 2u + 4u));
|
||||
}
|
||||
|
||||
TEST(Beaver, InnerProductPeelsASharedFactor)
|
||||
{
|
||||
session64 s;
|
||||
|
|
@ -632,16 +666,16 @@ TEST(Beaver, InnerProductRejectsABadShape)
|
|||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto z = s.input();
|
||||
EXPECT_THROW((void)[&] {
|
||||
EXPECT_THROW([&] {
|
||||
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);
|
||||
EXPECT_THROW([&] { 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);
|
||||
EXPECT_THROW([&] { 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);
|
||||
EXPECT_THROW([&] { return s.dot_cross(dotted); }(), std::logic_error);
|
||||
EXPECT_THROW([&] { return s.dot_cross(x); }(), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(Beaver, ScaleSharesScalarBlind)
|
||||
|
|
@ -1531,7 +1565,7 @@ TEST(Beaver, FactoredProductIsVisibleAndTheSexticTermIsNot)
|
|||
EXPECT_EQ(s.preprocessing_count(), prep);
|
||||
EXPECT_EQ(s.monomial({{x, 1u}, {z, 1u}}).open(),
|
||||
s.lambda(x).open() * s.lambda(z).open());
|
||||
EXPECT_THROW((void)[&] { return s.monomial({{x, 2u}, {z, 2u}}); }(),
|
||||
EXPECT_THROW([&] { return s.monomial({{x, 2u}, {z, 2u}}); }(),
|
||||
std::logic_error);
|
||||
s.bind(x, u64{6}, rng);
|
||||
s.bind(z, u64{7}, rng);
|
||||
|
|
@ -1909,8 +1943,8 @@ TEST(Beaver, HighPowersAndTheExpansionLimit)
|
|||
|
||||
session64 s;
|
||||
auto x = s.input();
|
||||
EXPECT_THROW((void)[&] { return pow(x, 17u); }(), std::invalid_argument);
|
||||
EXPECT_THROW((void)[&] { return pow(x, 10) * pow(x, 7); }(), std::invalid_argument);
|
||||
EXPECT_THROW([&] { return pow(x, 17u); }(), std::invalid_argument);
|
||||
EXPECT_THROW([&] { return pow(x, 10) * pow(x, 7); }(), std::invalid_argument);
|
||||
|
||||
std::vector<wire64> wide;
|
||||
wide.reserve(12);
|
||||
|
|
@ -1929,7 +1963,7 @@ TEST(Beaver, HighPowersAndTheExpansionLimit)
|
|||
EXPECT_EQ(s.open(all), 1u);
|
||||
|
||||
auto thirteenth = s.input();
|
||||
EXPECT_THROW((void)[&] { return s(expr12 * thirteenth); }(), std::invalid_argument);
|
||||
EXPECT_THROW([&] { return s(expr12 * thirteenth); }(), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(Beaver, ScheduledPolynomialRejectsEarlyUse)
|
||||
|
|
@ -1938,8 +1972,8 @@ TEST(Beaver, ScheduledPolynomialRejectsEarlyUse)
|
|||
session64 b;
|
||||
auto x = a.input();
|
||||
auto y = b.input();
|
||||
EXPECT_THROW((void)[&] { return x + y; }(), std::invalid_argument);
|
||||
EXPECT_THROW((void)[&] { return x * y; }(), std::invalid_argument);
|
||||
EXPECT_THROW([&] { return x + y; }(), std::invalid_argument);
|
||||
EXPECT_THROW([&] { return x * y; }(), std::invalid_argument);
|
||||
auto z = a(x + pow(x, 2));
|
||||
EXPECT_THROW(a.open(z), std::logic_error);
|
||||
EXPECT_THROW(a.evaluate(), std::logic_error);
|
||||
|
|
@ -1959,15 +1993,15 @@ TEST(Beaver, RejectsBadUse)
|
|||
dpf::beavers::session<u64> b;
|
||||
auto x = a.input();
|
||||
auto y = b.input();
|
||||
EXPECT_THROW((void)[&] { return a.product(x, y); }(), std::invalid_argument);
|
||||
EXPECT_THROW((void)[&] { return x * y; }(), std::invalid_argument);
|
||||
EXPECT_THROW([&] { return a.product(x, y); }(), std::invalid_argument);
|
||||
EXPECT_THROW([&] { return x * y; }(), std::invalid_argument);
|
||||
auto bit = a.bit();
|
||||
EXPECT_THROW(a.bind(bit, u64{2}), std::invalid_argument);
|
||||
auto z = a.product(x, x);
|
||||
EXPECT_THROW(a.evaluate(), std::logic_error);
|
||||
a.sample();
|
||||
EXPECT_THROW(a.evaluate(), std::logic_error);
|
||||
EXPECT_THROW((void)[&] { return a.bit_mul(x, x); }(), std::invalid_argument);
|
||||
EXPECT_THROW([&] { return a.bit_mul(x, x); }(), std::invalid_argument);
|
||||
(void)z;
|
||||
}
|
||||
|
||||
|
|
@ -1993,3 +2027,178 @@ TEST(Beaver, ProductExtremes)
|
|||
EXPECT_EQ(s.open(z), want) << a << " * " << b;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BeaverAuth, AuthBeaver2HonestAndTamper)
|
||||
{
|
||||
auto key = dpf::sample_mac_key<u64>();
|
||||
auto t = dpf::beavers::sample_auth_beaver2<u64>(key);
|
||||
EXPECT_TRUE(t.verify(key));
|
||||
EXPECT_EQ(t.ab.open(), t.a.open() * t.b.open());
|
||||
|
||||
auto bad = t;
|
||||
bad.ab.tag.p0 ^= 1ull;
|
||||
EXPECT_FALSE(bad.verify(key));
|
||||
}
|
||||
|
||||
TEST(BeaverAuth, AuthBeaverMulMatchesProduct)
|
||||
{
|
||||
auto key = dpf::sample_mac_key<u64>();
|
||||
auto bev = dpf::beavers::sample_auth_beaver2<u64>(key);
|
||||
const u64 x = 7, y = 11;
|
||||
auto xs = dpf::beavers::auth_share(x, key);
|
||||
auto ys = dpf::beavers::auth_share(y, key);
|
||||
auto [z0, z1] = dpf::beavers::auth_beaver_mul(
|
||||
xs.party(0), xs.party(1), ys.party(0), ys.party(1), bev, key);
|
||||
EXPECT_EQ(z0.value + z1.value, x * y);
|
||||
EXPECT_TRUE(dpf::mac_verify(z0, z1, key));
|
||||
|
||||
z0.tag ^= 1ull;
|
||||
EXPECT_FALSE(dpf::mac_verify(z0, z1, key));
|
||||
}
|
||||
|
||||
TEST(BeaverAuth, SessionAby2ValuesVerify)
|
||||
{
|
||||
auto key = dpf::sample_mac_key<u64>();
|
||||
session64 s;
|
||||
s.set_mac_key(key);
|
||||
auto x = s.input();
|
||||
auto y = s.input();
|
||||
auto z = s(x * y);
|
||||
Counter rng;
|
||||
s.sample(rng);
|
||||
s.bind(x, u64{6}, rng);
|
||||
s.bind(y, u64{7}, rng);
|
||||
s.evaluate();
|
||||
EXPECT_EQ(s.open(z), 42u);
|
||||
EXPECT_TRUE(s.lambda_auth(x).verify(key));
|
||||
EXPECT_TRUE(s.value_auth(x).verify(key));
|
||||
EXPECT_TRUE(s.value_auth(z).verify(key));
|
||||
EXPECT_TRUE(s.verify_delta(x));
|
||||
EXPECT_TRUE(s.verify_delta(y));
|
||||
EXPECT_TRUE(s.verify_all());
|
||||
|
||||
auto tampered = s.value_auth(z);
|
||||
tampered.tag.p0 ^= 1ull;
|
||||
EXPECT_FALSE(tampered.verify(key));
|
||||
}
|
||||
|
||||
TEST(BeaverAuth, PartyTapeCarriesTagsAndOpeningsCheck)
|
||||
{
|
||||
auto key = dpf::sample_mac_key<u64>();
|
||||
session64 dealer;
|
||||
dealer.set_mac_key(key);
|
||||
auto x = dealer.input();
|
||||
auto y = dealer.input();
|
||||
auto z = dealer(x * y);
|
||||
Counter rng;
|
||||
dealer.sample(rng);
|
||||
auto tape0 = dealer.export_party(0);
|
||||
auto tape1 = dealer.export_party(1);
|
||||
EXPECT_TRUE(tape0.has_mac);
|
||||
EXPECT_TRUE(tape1.has_mac);
|
||||
EXPECT_EQ(tape0.lambda_tag.size(), tape0.lambda.size());
|
||||
EXPECT_EQ(tape0.lambda[0] + tape1.lambda[0], dealer.lambda(x).open());
|
||||
EXPECT_EQ(tape0.lambda_tag[0] + tape1.lambda_tag[0],
|
||||
dealer.lambda_auth(x).tag.open());
|
||||
|
||||
dealer.bind(x, u64{3}, rng);
|
||||
dealer.bind(y, u64{5}, rng);
|
||||
dealer.evaluate();
|
||||
EXPECT_EQ(dealer.open(z), 15u);
|
||||
EXPECT_TRUE(dealer.verify_all());
|
||||
|
||||
auto honest = dealer.delta_auth(x);
|
||||
dpf::beavers::auth_opening<u64> a{honest.value.p0, honest.tag.p0};
|
||||
dpf::beavers::auth_opening<u64> b{honest.value.p1, honest.tag.p1};
|
||||
EXPECT_TRUE(dpf::beavers::verify_auth_opening(a, b, key));
|
||||
b.value ^= 1ull;
|
||||
EXPECT_FALSE(dpf::beavers::verify_auth_opening(a, b, key));
|
||||
|
||||
// Party views: authenticated input shares + λ tags reconstruct δ.
|
||||
auto xv = dealer.value_auth(x);
|
||||
dpf::beavers::auth_opening<u64> ox0{
|
||||
xv.party(0).value + tape0.lambda[0],
|
||||
xv.party(0).tag + tape0.lambda_tag[0]};
|
||||
dpf::beavers::auth_opening<u64> ox1{
|
||||
xv.party(1).value + tape1.lambda[0],
|
||||
xv.party(1).tag + tape1.lambda_tag[0]};
|
||||
EXPECT_TRUE(dpf::beavers::verify_auth_opening(ox0, ox1, key));
|
||||
EXPECT_EQ(ox0.value + ox1.value, dealer.delta(x));
|
||||
}
|
||||
|
||||
TEST(Beaver, OracleAuthTagsReplayFromTheSeed)
|
||||
{
|
||||
using block = dpf::prg::aes128::block_type;
|
||||
const block seed = simde_mm_set_epi64x(0x51, 0x52);
|
||||
auto key = dpf::sample_mac_key<u64>();
|
||||
dpf::beavers::oracle<u64> left(seed, 4);
|
||||
dpf::beavers::oracle<u64> right(seed, 4);
|
||||
auto a = dpf::beavers::sample_auth_beaver2(key, left, 3);
|
||||
auto b = dpf::beavers::sample_auth_beaver2(key, right, 3);
|
||||
EXPECT_EQ(a.a, b.a);
|
||||
EXPECT_EQ(a.b, b.b);
|
||||
EXPECT_EQ(a.ab, b.ab);
|
||||
EXPECT_EQ(a.out, b.out);
|
||||
EXPECT_TRUE(a.verify(key));
|
||||
EXPECT_EQ(a.ab.open(), a.a.open() * a.b.open());
|
||||
|
||||
dpf::beavers::session<u64> session;
|
||||
session.set_mac_key(key);
|
||||
auto x = session.input();
|
||||
auto y = session.input();
|
||||
auto z = session(x * y);
|
||||
session.pin(z);
|
||||
session.sample_from(left, 3);
|
||||
EXPECT_TRUE(session.lambda_auth(x).verify(key));
|
||||
EXPECT_TRUE(session.monomial_auth({{x, 1u}, {y, 1u}}).verify(key));
|
||||
EXPECT_EQ(session.lambda(x), a.a.value);
|
||||
}
|
||||
|
||||
TEST(Beaver, OracleShapesOpen)
|
||||
{
|
||||
using block = dpf::prg::aes128::block_type;
|
||||
const block seed = simde_mm_set_epi64x(0x71, 0x72);
|
||||
dpf::beavers::oracle<u64> src(seed, 8);
|
||||
auto p3 = dpf::beavers::sample_beaver3(src, 1);
|
||||
EXPECT_EQ(p3.abc.open(), p3.a.open() * p3.b.open() * p3.c.open());
|
||||
auto sq = dpf::beavers::sample_square(src, 2);
|
||||
EXPECT_EQ(sq.x2.open(), sq.x.open() * sq.x.open());
|
||||
auto sc = dpf::beavers::sample_scale(2, src, 4);
|
||||
EXPECT_EQ(sc.cross[1].open(), sc.scalar.open() * sc.lanes[1].open());
|
||||
auto fresh = dpf::beavers::sample_fresh<3, u64>(src, 5);
|
||||
EXPECT_EQ(fresh.subset[(1u << 3) - 2].open(),
|
||||
fresh.in[0].open() * fresh.in[1].open() * fresh.in[2].open());
|
||||
}
|
||||
|
||||
TEST(Beaver, PrgPadReplaysDsGadgets)
|
||||
{
|
||||
using block = dpf::prg::aes128::block_type;
|
||||
const block seed = simde_mm_set_epi64x(0x81, 0x82);
|
||||
dpf::prg_pad_rng<> left(seed);
|
||||
dpf::prg_pad_rng<> right(seed);
|
||||
const auto a = dpf::detail::ds_sample_bit_and(left);
|
||||
const auto b = dpf::detail::ds_sample_bit_and(right);
|
||||
EXPECT_EQ(a.a0, b.a0);
|
||||
EXPECT_EQ(a.c1, b.c1);
|
||||
const auto abit = static_cast<std::uint8_t>(a.a0 ^ a.a1);
|
||||
const auto bbit = static_cast<std::uint8_t>(a.b0 ^ a.b1);
|
||||
const auto cbit = static_cast<std::uint8_t>(a.c0 ^ a.c1);
|
||||
EXPECT_EQ(cbit, static_cast<std::uint8_t>(abit & bbit));
|
||||
|
||||
dpf::prg_pad_rng<> cleft(seed);
|
||||
dpf::prg_pad_rng<> cright(seed);
|
||||
const auto cw0 = dpf::detail::ds_sample_cw(cleft);
|
||||
const auto cw1 = dpf::detail::ds_sample_cw(cright);
|
||||
EXPECT_EQ(std::memcmp(&cw0.p0.rand, &cw1.p0.rand, sizeof(cw0.p0.rand)), 0);
|
||||
EXPECT_EQ(std::memcmp(&cw0.p1.gamma, &cw1.p1.gamma, sizeof(cw0.p1.gamma)), 0);
|
||||
const auto prod = dpf::detail::ds_xor(
|
||||
(cw0.p1.bit & 1u) ? cw0.p0.rand : simde_mm_setzero_si128(),
|
||||
(cw0.p0.bit & 1u) ? cw0.p1.rand : simde_mm_setzero_si128());
|
||||
const auto got = dpf::detail::ds_xor(cw0.p0.gamma, cw0.p1.gamma);
|
||||
EXPECT_EQ(std::memcmp(&got, &prod, sizeof(got)), 0);
|
||||
|
||||
dpf::detail::urandom_pad_rng pad;
|
||||
const auto shares = dpf::beavers::sample_bit_arith(pad);
|
||||
EXPECT_EQ(shares.add0 + shares.add1,
|
||||
static_cast<std::uint64_t>(shares.xor0 ^ shares.xor1));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue