#include #include #include #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(center + eta); // 15 const std::size_t degree = 3; auto jet_keys = grotto::make_offset_jet_keys(center, degree); // f(t) = 4 + 2 C(t,1) + C(t,2) (padded to degree 3). const std::vector poly{4, 2, 1}; std::vector coeff = poly; coeff.push_back(0); const std::vector 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 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(x - r); // 100, wraps using Z = grotto::zn64<1009>; auto ring = grotto::make_ring_switch_keys(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(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(point + 1), 1) + c(static_cast(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(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; }