Document the new DPF surfaces in one command set, and test the field, half-tree, and multipoint edges.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-24 23:18:10 -06:00
parent 0d8a5a8131
commit 0dff6df8ed
250 changed files with 12199 additions and 1981 deletions

View file

@ -60,7 +60,8 @@ T offset_horner_group_sub(T a, T b) noexcept
return static_cast<T>(static_cast<u>(static_cast<u>(a) - static_cast<u>(b)));
}
/// `eta = x - r` and `center = 2r`, both in the input group.
/// @brief `eta = x - r` and `center = 2r`, both in the input group.
/// @tparam T value type
template <typename T>
struct offset_horner_x_plus_r
{
@ -218,8 +219,11 @@ T domain_min() noexcept
return T{0};
}
/// Public center-space cut where `center + eta` crosses the domain end.
/// Empty when that cut is outside the domain, including `eta == 0`.
/// @brief Public center-space cut where `center + eta` crosses the domain end.
/// @details Empty when that cut is outside the domain, including `eta == 0`.
/// @tparam T value type
/// @param eta the `eta`
/// @return Public center-space cut where `center + eta` crosses the domain end
template <typename T>
HEDLEY_NO_THROW
std::optional<T> carry_threshold(T eta) noexcept
@ -246,7 +250,11 @@ std::optional<T> carry_threshold(T eta) noexcept
}
}
/// `center + kappa` is the wrapped representative, as a mathematical integer.
/// @brief `center + kappa` is the wrapped representative, as a mathematical integer.
/// @tparam T value type
/// @param left the `left`
/// @param eta the `eta`
/// @return `center + kappa` is the wrapped representative, as a mathematical integer
template <typename T>
HEDLEY_NO_THROW
int64_t kappa_for(T left, T eta) noexcept
@ -363,9 +371,14 @@ std::vector<prepared_piece<Degree, InputT>> prepare_pieces(
return out;
}
/// `out[k]` sums to the polynomial at the wrapped input. It is
/// @brief `out[k]` sums to the polynomial at the wrapped input. It is
/// `center^k` times the public binomial coefficient of `kappa`, not a
/// coefficient you Horner-evaluate at `eta`.
/// @tparam Degree degree
/// @param seg the `seg`
/// @param coeff the public coefficient
/// @param kappa the `kappa`
/// @return `out[k]` sums to the polynomial at the wrapped input
template <std::size_t Degree>
std::array<uint64_t, Degree + 1> contributions(
const std::array<std::vector<uint64_t>, Degree + 1> & seg,
@ -386,7 +399,9 @@ std::array<uint64_t, Degree + 1> contributions(
} // namespace offset_horner_detail
/// Both parties' comparison keys and wrap-piece shares for one center.
/// @brief Both parties' comparison keys and wrap-piece shares for one center.
/// @tparam InputT input domain type
/// @tparam Degree degree
template <typename InputT, std::size_t Degree = offset_horner_max_degree>
struct offset_horner_keys
{
@ -398,9 +413,9 @@ struct offset_horner_keys
using key_pair = decltype(dpf::make_dpf(std::declval<InputT>(), dpf::gt(uint64_t{0})));
InputT center{};
/// `keys[m]` is `gt(center^m)` keyed at `center`. `.first` is party 0.
/// @brief `keys[m]` is `gt(center^m)` keyed at `center`. `.first` is party 0.
std::array<key_pair, Degree + 1> keys;
/// Random additive split of `center^m`, indexed `[power][party]`.
/// @brief Random additive split of `center^m`, indexed `[power][party]`.
std::array<std::array<uint64_t, 2>, Degree + 1> wrap_share{};
};
@ -424,9 +439,17 @@ offset_horner_keys<InputT, Degree> make_offset_horner_keys(InputT center)
return mat;
}
/// Cleartext binomial coefficients of the selected refined piece in the
/// @brief Cleartext binomial coefficients of the selected refined piece in the
/// variable `center`: Horner at `lift(center)` is the polynomial at the
/// wrapped input.
/// @tparam Degree degree
/// @tparam InputT input domain type
/// @param center the `center`
/// @param knots the `knots`
/// @param coeff the public coefficient
/// @param eta the `eta`
/// @return Cleartext binomial coefficients of the selected refined piece in the variable `center`:
/// Horner at `lift(center)` is the polynomial at the wrapped input
template <std::size_t Degree, typename InputT>
std::array<uint64_t, Degree + 1> offset_horner_clear_coefficients(
InputT center,
@ -447,7 +470,14 @@ std::array<uint64_t, Degree + 1> offset_horner_clear_coefficients(
piece.coeff, static_cast<uint64_t>(piece.kappa));
}
/// Cleartext value of the selected piece at the wrapped `center + eta`.
/// @brief Cleartext value of the selected piece at the wrapped `center + eta`.
/// @tparam Degree degree
/// @tparam InputT input domain type
/// @param center the `center`
/// @param knots the `knots`
/// @param coeff the public coefficient
/// @param eta the `eta`
/// @return Cleartext value of the selected piece at the wrapped `center + eta`
template <std::size_t Degree, typename InputT>
uint64_t offset_horner_clear(
InputT center,
@ -459,7 +489,18 @@ uint64_t offset_horner_clear(
return offset_horner_detail::horner_at<Degree>(c, offset_horner_detail::lift(center));
}
/// `Party` selects `.first` or `.second` of each key pair.
/// @brief `Party` selects `.first` or `.second` of each key pair.
/// @tparam Party party index, `0` or `1`
/// @tparam Degree degree
/// @tparam InputT input domain type
/// @tparam KeyPair key pair
/// @param keys the party keys
/// @param wrap_share the `wrap_share`
/// @param knots the `knots`
/// @param coeff the public coefficient
/// @param eta the `eta`
/// @return `Party` selects `.first` or `.second` of each key pair
/// @throws std::invalid_argument if `one comparison key per power`
template <std::size_t Party, std::size_t Degree, typename InputT, typename KeyPair>
std::array<uint64_t, Degree + 1> offset_horner_coefficient_share(
const std::vector<KeyPair> & keys,
@ -492,7 +533,15 @@ std::array<uint64_t, Degree + 1> offset_horner_coefficient_share(
return contributions<Degree>(seg, ordered, kappa);
}
/// One party's coefficient shares. `Party` is 0 or 1.
/// @brief One party's coefficient shares. `Party` is 0 or 1.
/// @tparam Party party index, `0` or `1`
/// @tparam Degree degree
/// @tparam InputT input domain type
/// @param mat the `mat`
/// @param knots the `knots`
/// @param coeff the public coefficient
/// @param eta the `eta`
/// @return One party's coefficient shares
template <std::size_t Party, std::size_t Degree, typename InputT>
std::array<uint64_t, Degree + 1> offset_horner_coefficient_share(
const offset_horner_keys<InputT, Degree> & mat,
@ -506,10 +555,12 @@ std::array<uint64_t, Degree + 1> offset_horner_coefficient_share(
keys, mat.wrap_share, knots, coeff, eta);
}
/// Both parties' Horner shares from one joint Doerner–Shelat generation.
/// `center0 XOR center1` is the comparison point, in geneval's share
/// @brief Both parties' Horner shares from one joint Doerner–Shelat generation.
/// @details `center0 XOR center1` is the comparison point, in geneval's share
/// convention (the signed MSB of `center0` is flipped before the XOR, and
/// flipped back here). `eta` is already public.
/// @tparam Degree degree
/// @tparam InputT input domain type
template <std::size_t Degree, typename InputT>
struct geneval_offset_horner_result
{
@ -523,8 +574,12 @@ struct geneval_offset_horner_result
uint64_t value1 = 0;
};
/// Logical comparison point for geneval's XOR shares. Matches `make_dpf(P)`
/// @brief Logical comparison point for geneval's XOR shares. Matches `make_dpf(P)`
/// when `center1 = P XOR center0` or when `center0 = P` and `center1 = 0`.
/// @tparam InputT input domain type
/// @param center0 the `center0`
/// @param center1 the `center1`
/// @return Logical comparison point for geneval's XOR shares
template <typename InputT>
InputT geneval_offset_horner_center(InputT center0, InputT center1)
{
@ -602,12 +657,22 @@ geneval_offset_horner_result<Degree, InputT> geneval_at(
} // namespace offset_horner_detail
/// Geneval-style offset Horner. The center is XOR-shared as in `geneval_point`.
/// Comparison keys are opened with the same local Doerner–Shelat protocol
/// @brief Geneval-style offset Horner. The center is XOR-shared as in `geneval_point`.
/// @details Comparison keys are opened with the same local Doerner–Shelat protocol
/// geneval uses for its correction words. The value dot uses the per-piece
/// carry shift and is local.
/// A value-correction word is required on every level of the secret path, so
/// this does not stop early the way a leaf trie does.
/// @tparam Degree degree
/// @tparam InputT input domain type
/// @tparam Rng rng
/// @param center0 the `center0`
/// @param center1 the `center1`
/// @param eta the `eta`
/// @param knots the `knots`
/// @param coeff the public coefficient
/// @param rng the Doerner–Shelat randomness tapes
/// @return Geneval-style offset Horner
template <std::size_t Degree = offset_horner_max_degree,
typename InputT,
typename Rng>
@ -629,13 +694,27 @@ geneval_offset_horner_result<Degree, InputT> geneval_offset_horner(
const std::vector<std::array<uint64_t, Degree + 1>> & coeff)
{
using block = typename dpf::prg::aes128::block_type;
HEDLEY_PRAGMA(GCC diagnostic push)
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
dpf::ds_randomness<block (*)(), dpf::detail::urandom_pad_rng> rng{
dpf::uniform_sample<block>, {}};
HEDLEY_PRAGMA(GCC diagnostic pop)
return geneval_offset_horner<Degree>(
center0, center1, eta, knots, coeff, std::move(rng));
}
/// Additive shares of the center: `center0 + center1` is the comparison point.
/// @brief Additive shares of the center: `center0 + center1` is the comparison point.
/// @tparam Degree degree
/// @tparam InputT input domain type
/// @tparam Rng rng
/// @param arith_input_t the `arith_input_t`
/// @param center0 the `center0`
/// @param center1 the `center1`
/// @param eta the `eta`
/// @param knots the `knots`
/// @param coeff the public coefficient
/// @param rng the Doerner–Shelat randomness tapes
/// @return Additive shares of the center: `center0 + center1` is the comparison point
template <std::size_t Degree = offset_horner_max_degree,
typename InputT,
typename Rng>
@ -650,10 +729,21 @@ geneval_offset_horner_result<Degree, InputT> geneval_offset_horner(
true, center0, center1, center, eta, knots, coeff, std::move(rng));
}
/// Additive shares of the input `x` and the mask `r`. Reconstructs
/// @brief Additive shares of the input `x` and the mask `r`. Reconstructs
/// `eta = x - r` and passes additive shares of `center = 2r` (`2·r0`, `2·r1`)
/// to arithmetic `geneval_cmp`. Returns both parties' Horner shares of the
/// cubic at `x + r` (the group element `x + r`).
/// @tparam Degree degree
/// @tparam InputT input domain type
/// @tparam Rng rng
/// @param x0 the `x0`
/// @param x1 the `x1`
/// @param r0 the party 0's share of the mask
/// @param r1 the party 1's share of the mask
/// @param knots the `knots`
/// @param coeff the public coefficient
/// @param rng the Doerner–Shelat randomness tapes
/// @return Additive shares of the input `x` and the mask `r`
template <std::size_t Degree = offset_horner_max_degree,
typename InputT,
typename Rng>
@ -680,14 +770,25 @@ geneval_offset_horner_result<Degree, InputT> geneval_offset_horner(
const std::vector<std::array<uint64_t, Degree + 1>> & coeff)
{
using block = typename dpf::prg::aes128::block_type;
HEDLEY_PRAGMA(GCC diagnostic push)
HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes")
dpf::ds_randomness<block (*)(), dpf::detail::urandom_pad_rng> rng{
dpf::uniform_sample<block>, {}};
HEDLEY_PRAGMA(GCC diagnostic pop)
return geneval_offset_horner<Degree>(
x0, x1, r0, r1, knots, coeff, std::move(rng));
}
/// One party's share of the cubic at the wrapped `center + eta`.
/// Sum the coefficient shares; they are already scaled by `center^k`.
/// @brief One party's share of the cubic at the wrapped `center + eta`.
/// @details Sum the coefficient shares; they are already scaled by `center^k`.
/// @tparam Party party index, `0` or `1`
/// @tparam Degree degree
/// @tparam InputT input domain type
/// @param mat the `mat`
/// @param knots the `knots`
/// @param coeff the public coefficient
/// @param eta the `eta`
/// @return One party's share of the cubic at the wrapped `center + eta`
template <std::size_t Party, std::size_t Degree, typename InputT>
uint64_t offset_horner_eval(
const offset_horner_keys<InputT, Degree> & mat,