133 lines
4.3 KiB
C++
133 lines
4.3 KiB
C++
|
|
#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;
|
||
|
|
}
|