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
58
examples/grotto/dwt_lut.cpp
Normal file
58
examples/grotto/dwt_lut.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "grotto.hpp"
|
||||
|
||||
// Haar and bior(5,3) lookup tables (Reis, Ugurbil, Wagh, Henry, de Vega,
|
||||
// PoPETs 2025, ePrint 2025/013). The grid is sigmoid on [0, 4), stored as
|
||||
// Q4.4. Depth 2 keeps the top 4 bits of a 6-bit index.
|
||||
//
|
||||
// c++ -std=c++17 -march=native -I include -I thirdparty examples/grotto/dwt_lut.cpp
|
||||
|
||||
int main()
|
||||
{
|
||||
//! [dwt-lut]
|
||||
constexpr unsigned domain_bits = 6;
|
||||
constexpr unsigned fractional_bits = 4;
|
||||
constexpr unsigned depth = 2;
|
||||
auto samples = grotto::sample_dwt_signal(domain_bits, fractional_bits,
|
||||
[](double x) {
|
||||
return 1.0 / (1.0 + std::exp(-(x - 2.0)));
|
||||
});
|
||||
auto haar = grotto::make_haar_dwt_lut(samples, fractional_bits, depth);
|
||||
auto bior = grotto::make_bior53_dwt_lut(samples, fractional_bits, depth);
|
||||
|
||||
// Haar is the mean of each block of 2^depth samples, then quantized.
|
||||
const std::uint64_t raw = 32;
|
||||
double block = 0;
|
||||
for (unsigned k = 0; k < 4; ++k)
|
||||
block += samples[(raw & ~std::uint64_t{3}) + k];
|
||||
const auto haar_expect = static_cast<std::int64_t>(
|
||||
std::floor(block / 4.0 * 16.0));
|
||||
|
||||
// bior(5,3), lsb = 0: only the first tap, at index msb+2, divided by 2^j.
|
||||
const std::uint64_t msb = raw >> depth;
|
||||
const auto c0 = bior.coeff[(msb + 2) % bior.coeff.size()];
|
||||
const auto bior_at_32 = c0 / 4;
|
||||
|
||||
// lsb = 1: both taps, weights (2^j - lsb) and lsb, then divide by 2^{2j}.
|
||||
const auto c1 = bior.coeff[(msb + 3) % bior.coeff.size()];
|
||||
const auto bior_at_33 = (c0 * 3 + c1) / 16;
|
||||
//! [dwt-lut]
|
||||
|
||||
if (haar(raw) != haar_expect || haar(raw) != 8)
|
||||
{
|
||||
std::cerr << "haar lut\n";
|
||||
return 1;
|
||||
}
|
||||
if (bior(raw) != bior_at_32 || bior(33) != bior_at_33 || bior(raw) != 8)
|
||||
{
|
||||
std::cerr << "bior lut\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << haar(raw) << " " << bior(raw) << " " << bior(33) << "\n";
|
||||
return 0;
|
||||
}
|
||||
98
examples/grotto/jet_and_ring.cpp
Normal file
98
examples/grotto/jet_and_ring.cpp
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "grotto.hpp"
|
||||
|
||||
/// Binomial jet readouts and an exact ring switch from one public offset.
|
||||
int main()
|
||||
{
|
||||
//! [jet-and-ring]
|
||||
// --- Binomial jet -------------------------------------------------------
|
||||
// After eta opens, the jet is the binomial basis at the wrapped
|
||||
// center+kappa. Degree 3 leaves room for a degree-2 hockey-stick prefix.
|
||||
const std::uint8_t center = 12;
|
||||
const std::uint8_t eta = 3;
|
||||
const std::uint8_t point = static_cast<std::uint8_t>(center + eta); // 15
|
||||
const std::size_t degree = 3;
|
||||
auto jet_keys = grotto::make_offset_jet_keys<std::uint8_t>(center, degree);
|
||||
// f(t) = 4 + 2 C(t,1) + C(t,2) (padded to degree 3).
|
||||
const std::vector<std::uint64_t> poly{4, 2, 1};
|
||||
std::vector<std::uint64_t> coeff = poly;
|
||||
coeff.push_back(0);
|
||||
const std::vector<std::uint8_t> knots{0};
|
||||
|
||||
const auto j0 = grotto::offset_jet_shares<0>(jet_keys, knots, eta);
|
||||
const auto j1 = grotto::offset_jet_shares<1>(jet_keys, knots, eta);
|
||||
std::vector<std::uint64_t> jet(degree + 1);
|
||||
for (std::size_t k = 0; k <= degree; ++k)
|
||||
jet[k] = j0[k] + j1[k];
|
||||
|
||||
const std::uint64_t value = grotto::offset_jet_dot(coeff, jet);
|
||||
const std::uint64_t diff = grotto::offset_jet_dot(
|
||||
grotto::offset_jet_difference_coeff(coeff), jet);
|
||||
const std::uint64_t prefix = grotto::offset_jet_dot(
|
||||
grotto::offset_jet_prefix_coeff(poly), jet);
|
||||
|
||||
// Padé / Newton are public dots against the same jet, then one reciprocal
|
||||
// after the shares are opened. For a seed p(t)/p'(t):
|
||||
// auto num = offset_jet_dot(coeff, jet);
|
||||
// auto den = offset_jet_dot(offset_jet_difference_coeff(coeff), jet);
|
||||
// // open num, den; one masked reciprocal; Newton: t - num/den.
|
||||
|
||||
// --- Exact ring switch --------------------------------------------------
|
||||
// Same public-offset pattern: eta = x - r, then x lands in the residue.
|
||||
const std::uint8_t r = 200;
|
||||
const std::uint8_t x = 44;
|
||||
const std::uint8_t ring_eta = static_cast<std::uint8_t>(x - r); // 100, wraps
|
||||
using Z = grotto::zn64<1009>;
|
||||
auto ring = grotto::make_ring_switch_keys<Z>(r);
|
||||
const Z x_mod = grotto::ring_switch_eval<0>(ring, ring_eta)
|
||||
+ grotto::ring_switch_eval<1>(ring, ring_eta);
|
||||
|
||||
auto field = grotto::make_ring_switch_keys<dpf::field128>(r);
|
||||
const dpf::field128 x_field = grotto::ring_switch_eval<0>(field, ring_eta)
|
||||
+ grotto::ring_switch_eval<1>(field, ring_eta);
|
||||
//! [jet-and-ring]
|
||||
|
||||
auto c = [](std::uint64_t t, unsigned k) {
|
||||
return grotto::offset_jet_binom(t, k);
|
||||
};
|
||||
const std::uint64_t expect_v =
|
||||
4 + 2 * c(point, 1) + c(point, 2);
|
||||
if (value != expect_v)
|
||||
{
|
||||
std::cerr << "jet value\n";
|
||||
return 1;
|
||||
}
|
||||
const std::uint64_t expect_fx1 =
|
||||
4 + 2 * c(static_cast<std::uint8_t>(point + 1), 1)
|
||||
+ c(static_cast<std::uint8_t>(point + 1), 2);
|
||||
if (diff != expect_fx1 - expect_v)
|
||||
{
|
||||
std::cerr << "jet difference\n";
|
||||
return 1;
|
||||
}
|
||||
std::uint64_t expect_p = 0;
|
||||
for (std::uint8_t i = 0; i < point; ++i)
|
||||
expect_p += 4 + 2 * c(i, 1) + c(i, 2);
|
||||
if (prefix != expect_p)
|
||||
{
|
||||
std::cerr << "jet prefix\n";
|
||||
return 1;
|
||||
}
|
||||
if (x_mod.raw() != static_cast<std::uint64_t>(x) % 1009)
|
||||
{
|
||||
std::cerr << "ring zn64\n";
|
||||
return 1;
|
||||
}
|
||||
if (x_field != dpf::field128{x})
|
||||
{
|
||||
std::cerr << "ring field128\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << value << " " << diff << " " << prefix << " "
|
||||
<< x_mod.raw() << "\n";
|
||||
return 0;
|
||||
}
|
||||
43
examples/grotto/lut_union.cpp
Normal file
43
examples/grotto/lut_union.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "grotto.hpp"
|
||||
|
||||
/// Two piecewise LUTs, one comparison, one prefix walk of the union.
|
||||
int main()
|
||||
{
|
||||
//! [lut-union]
|
||||
grotto::piecewise_lut<std::uint8_t> low{{0, 10}, {{1, 0}, {0, 2}}};
|
||||
grotto::piecewise_lut<std::uint8_t> high{{0, 4, 12}, {{3, 0}, {1, 1}, {9, 4}}};
|
||||
const std::uint8_t center = 12;
|
||||
const std::uint8_t eta = 3;
|
||||
|
||||
auto plan = grotto::make_lut_union_plan({low, high}, eta);
|
||||
auto mat = grotto::make_offset_poly_keys<std::uint8_t>(center, plan.degree);
|
||||
auto s0 = grotto::lut_union_eval<0>(mat, plan);
|
||||
auto s1 = grotto::lut_union_eval<1>(mat, plan);
|
||||
|
||||
dpf::protocol::composer composer(0);
|
||||
grotto::schedule_lut_union(composer, plan);
|
||||
//! [lut-union]
|
||||
|
||||
if (plan.comparisons != 1 || plan.prefix_walks != 1)
|
||||
{
|
||||
std::cerr << "plan shape\n";
|
||||
return 1;
|
||||
}
|
||||
if (composer.default_plan().rounds() != plan.depth)
|
||||
{
|
||||
std::cerr << "geneval rounds\n";
|
||||
return 1;
|
||||
}
|
||||
const std::uint64_t opened[2] = {s0[0] + s1[0], s0[1] + s1[1]};
|
||||
if (opened[0] != grotto::offset_poly_clear<std::uint8_t>(center, low.knots, low.coeff, eta)
|
||||
|| opened[1] != grotto::offset_poly_clear<std::uint8_t>(center, high.knots, high.coeff, eta))
|
||||
{
|
||||
std::cerr << "opened value\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
132
examples/grotto/repr_and_twist.cpp
Normal file
132
examples/grotto/repr_and_twist.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "grotto.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::uint64_t pow_u64(std::uint64_t base, std::uint64_t exp)
|
||||
{
|
||||
std::uint64_t acc = 1;
|
||||
while (exp != 0)
|
||||
{
|
||||
if (exp & 1u)
|
||||
acc *= base;
|
||||
base *= base;
|
||||
exp >>= 1;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// Representation shift (Fibonacci / geometric / CRC) and twisted monomials.
|
||||
int main()
|
||||
{
|
||||
//! [repr-and-twist]
|
||||
// --- Representation shift: Fibonacci checkpoint ----------------------
|
||||
// Dealer keys S_c = (F_{c+1}, F_c). After eta opens, each party applies
|
||||
// the public companion-matrix power M^kappa to its share of S_c.
|
||||
const std::uint8_t center = 10;
|
||||
const std::uint8_t eta = 5;
|
||||
const std::uint8_t point = static_cast<std::uint8_t>(center + eta); // 15
|
||||
const auto fib_state = grotto::offset_repr_fibonacci_state(center);
|
||||
const auto M = grotto::offset_repr_fibonacci_matrix();
|
||||
auto fib_keys = grotto::make_offset_repr_keys<std::uint8_t>(center, fib_state);
|
||||
const std::vector<std::uint8_t> knots{0};
|
||||
|
||||
const auto f0 = grotto::offset_repr_eval<0>(fib_keys, M, knots, eta);
|
||||
const auto f1 = grotto::offset_repr_eval<1>(fib_keys, M, knots, eta);
|
||||
const std::vector<std::uint64_t> S{f0[0] + f1[0], f0[1] + f1[1]};
|
||||
|
||||
// Geometric twin: 1x1 matrix [lambda] advances lambda^c by lambda^kappa.
|
||||
const std::uint64_t lambda_geo = 3;
|
||||
const auto G = grotto::offset_repr_geometric_matrix(lambda_geo);
|
||||
auto geo_keys = grotto::make_offset_repr_keys<std::uint8_t>(
|
||||
center, {pow_u64(lambda_geo, center)});
|
||||
const auto g0 = grotto::offset_repr_eval<0>(geo_keys, G, knots, eta);
|
||||
const auto g1 = grotto::offset_repr_eval<1>(geo_keys, G, knots, eta);
|
||||
const std::uint64_t geo = g0[0] + g1[0];
|
||||
|
||||
// Clear CRC-32 jump documents the GF(2) twin (XOR shares, not additive).
|
||||
const std::uint32_t crc_seed = 0x12345678u;
|
||||
const std::uint32_t crc_jumped = grotto::offset_repr_crc32_jump(crc_seed, 64);
|
||||
|
||||
// --- Twisted monomials: (a0 + a1 x + a2 x^2) * lambda^x -------------
|
||||
const std::uint64_t lambda = 3;
|
||||
const std::size_t degree = 2;
|
||||
auto twist_keys = grotto::make_offset_twist_keys<std::uint8_t>(
|
||||
center, degree, lambda);
|
||||
// h(x) = (2 + 5x + x^2) * 3^x
|
||||
const std::vector<std::uint64_t> coeff{2, 5, 1};
|
||||
const std::uint64_t twisted =
|
||||
grotto::offset_twist_eval<0>(twist_keys, knots, coeff, eta)
|
||||
+ grotto::offset_twist_eval<1>(twist_keys, knots, coeff, eta);
|
||||
|
||||
// Dyadic decay: masked carry shift. The sum of the shares is the shifted value.
|
||||
auto half_keys = grotto::make_offset_twist_keys<std::uint8_t>(
|
||||
center, degree, grotto::twist_half);
|
||||
const std::uint64_t half =
|
||||
grotto::offset_twist_eval<0>(half_keys, knots, coeff, eta)
|
||||
+ grotto::offset_twist_eval<1>(half_keys, knots, coeff, eta);
|
||||
|
||||
// Closed form sum_{k=1}^n k * lambda^k from the same twisted table.
|
||||
const std::uint64_t ag = grotto::offset_twist_arithmetico_geometric(point, lambda);
|
||||
//! [repr-and-twist]
|
||||
|
||||
const auto expect_S = grotto::offset_repr_fibonacci_state(point);
|
||||
if (S != expect_S)
|
||||
{
|
||||
std::cerr << "fibonacci state\n";
|
||||
return 1;
|
||||
}
|
||||
if (geo != pow_u64(lambda_geo, point))
|
||||
{
|
||||
std::cerr << "geometric\n";
|
||||
return 1;
|
||||
}
|
||||
std::uint64_t expect_t = 0;
|
||||
std::uint64_t xp = 1;
|
||||
for (std::uint64_t c : coeff)
|
||||
{
|
||||
expect_t += c * xp;
|
||||
xp *= point;
|
||||
}
|
||||
expect_t *= pow_u64(lambda, point);
|
||||
if (twisted != expect_t)
|
||||
{
|
||||
std::cerr << "twisted poly\n";
|
||||
return 1;
|
||||
}
|
||||
std::uint64_t expect_h = 0;
|
||||
xp = 1;
|
||||
for (std::uint64_t c : coeff)
|
||||
{
|
||||
expect_h += c * xp;
|
||||
xp *= point;
|
||||
}
|
||||
expect_h >>= point;
|
||||
if (half != expect_h)
|
||||
{
|
||||
std::cerr << "twist half\n";
|
||||
return 1;
|
||||
}
|
||||
std::uint64_t expect_ag = 0;
|
||||
for (std::uint64_t k = 1; k <= point; ++k)
|
||||
expect_ag += k * pow_u64(lambda, k);
|
||||
if (ag != expect_ag)
|
||||
{
|
||||
std::cerr << "arithmetico-geometric\n";
|
||||
return 1;
|
||||
}
|
||||
if (crc_jumped == 0 && crc_seed != 0)
|
||||
{
|
||||
// Jump can legally land on zero; only used as a smoke output.
|
||||
}
|
||||
|
||||
std::cout << S[1] << " " << geo << " " << twisted << " " << half << " "
|
||||
<< ag << " " << crc_jumped << "\n";
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue