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

@ -34,6 +34,12 @@ namespace grotto
/// zero-extend. Sign-extending a narrower signed operand, and replicating the
/// product sign when `modulus_bits > multiply_bits`, are plaintext steps the
/// MPC protocol has to reproduce (they are not local on additive shares).
/// @tparam IntegerBits number of integer bits, including the sign
/// @tparam FractionalBits number of fractional bits
/// @tparam LhsFractionalBits lhs fractional bits
/// @tparam LhsIntegral lhs integral
/// @tparam RhsFractionalBits rhs fractional bits
/// @tparam RhsIntegral rhs integral
template <unsigned IntegerBits,
unsigned FractionalBits,
unsigned LhsFractionalBits,
@ -51,12 +57,12 @@ struct fixed_mul_plan
static constexpr bool rhs_signed = std::is_signed_v<RhsIntegral>;
static constexpr bool operands_signed = lhs_signed || rhs_signed;
/// Right shift applied to the raw product. Negative means a left shift.
/// @brief Right shift applied to the raw product. Negative means a left shift.
static constexpr int align_shift = static_cast<int>(LhsFractionalBits)
+ static_cast<int>(RhsFractionalBits)
- static_cast<int>(FractionalBits);
/// Bits of the product that the shift reads. Zero when a left shift
/// @brief Bits of the product that the shift reads. Zero when a left shift
/// moves every product bit out of the output.
static constexpr int modulus_bits_signed = align_shift >= 0
? align_shift + static_cast<int>(out_bits)
@ -64,14 +70,14 @@ struct fixed_mul_plan
static constexpr unsigned modulus_bits = modulus_bits_signed > 0
? static_cast<unsigned>(modulus_bits_signed) : 0u;
/// Full two's-complement product fits in this many bits.
/// @brief Full two's-complement product fits in this many bits.
static constexpr unsigned product_bits = lhs_width + rhs_width;
static constexpr unsigned multiply_bits = modulus_bits < product_bits
? modulus_bits : product_bits;
static constexpr unsigned limbs = multiply_bits == 0u
? 0u : (multiply_bits + 63u) / 64u;
/// Signed storage exists through 128 bits. A wider window is the same
/// @brief Signed storage exists through 128 bits. A wider window is the same
/// residue held in an unsigned fixed-point.
static constexpr bool result_is_signed = operands_signed && out_bits <= 128u;
@ -197,7 +203,14 @@ constexpr void store_raw_limbs(const T & value, std::uint64_t out[4]) noexcept
}
}
/// Low `dest_bits` of `value`, sign-extended when `value` is a narrower signed integer.
/// @brief Low `dest_bits` of `value`, sign-extended when `value` is a narrower signed integer.
/// @tparam T value type
/// @param value the value to convert or store
/// @param src_bits the `src_bits`
/// @param is_signed the `is_signed`
/// @param dest_bits the `dest_bits`
/// @param dest the destination
/// @param nlimbs the `nlimbs`
template <typename T>
HEDLEY_NO_THROW
constexpr void reduce_operand(const T & value, unsigned src_bits, bool is_signed,
@ -222,7 +235,11 @@ constexpr void reduce_operand(const T & value, unsigned src_bits, bool is_signed
mask_to_bits(dest, nlimbs, dest_bits);
}
/// Product modulo `2^(64*nlimbs)`, using exactly `nlimbs` limbs of each operand.
/// @brief Product modulo `2^(64*nlimbs)`, using exactly `nlimbs` limbs of each operand.
/// @param out the output buffer
/// @param lhs the left-hand operand
/// @param rhs the right-hand operand
/// @param nlimbs the `nlimbs`
HEDLEY_NO_THROW
constexpr void mul_low_limbs(std::uint64_t * out, const std::uint64_t * lhs,
const std::uint64_t * rhs, unsigned nlimbs) noexcept
@ -328,15 +345,21 @@ constexpr T limbs_to_integral(const std::uint64_t * limbs) noexcept
} // namespace detail
/// @brief Multiply two fixed-point values into a chosen integer and fraction width.
/// @tparam IntegerBits Integer bits kept in the result, including the sign bit
/// when the result is signed. Bits above this wrap.
/// @details The result is held in the smallest fixed-point word that can store
/// `IntegerBits + FractionalBits`. A signed word is used when either operand
/// is signed and the window is at most 128 bits; otherwise the window is the
/// unsigned residue.
/// @tparam IntegerBits Integer bits kept in the result, including the sign bit
/// when the result is signed. Bits above this wrap.
/// @tparam FractionalBits Fraction bits kept in the result. Lower fraction bits
/// of the exact product are discarded (floored).
///
/// The result is held in the smallest fixed-point word that can store
/// `IntegerBits + FractionalBits`. A signed word is used when either operand
/// is signed and the window is at most 128 bits; otherwise the window is the
/// unsigned residue.
/// of the exact product are discarded (floored).
/// @tparam LhsFractionalBits fractional bits of the left operand
/// @tparam LhsIntegral integral type of the left operand
/// @tparam RhsFractionalBits fractional bits of the right operand
/// @tparam RhsIntegral integral type of the right operand
/// @param lhs the left-hand operand
/// @param rhs the right-hand operand
/// @return the product at the requested width
template <unsigned IntegerBits,
unsigned FractionalBits,
unsigned LhsFractionalBits,