libdpf/examples/grotto/jet_and_ring.cpp
Ryan Henry 0d22946a0e 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>
2026-09-28 05:59:19 -06:00

98 lines
3.6 KiB
C++

#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;
}