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>
1707 lines
55 KiB
C++
1707 lines
55 KiB
C++
/// @file dpf/secret_share.hpp
|
||
/// @brief Thin secret-share wrappers.
|
||
/// @details (2,2)-additive and (2,2)-subtractive shares, and (3,3)-additive
|
||
/// shares, are layout-identical to `T`. A (2,3)-replicated share
|
||
/// holds two components of a (3,3)-additive sharing: party `i`
|
||
/// stores `(x_i, x_{i+1 mod 3})`.
|
||
/// Reconstruction: (2,2)-additive opens by sum, (2,2)-subtractive by
|
||
/// `share0 - share1`, (3,3)-additive by the sum of all three shares,
|
||
/// and (2,3)-replicated from any two parties.
|
||
/// Linear combinations of same-party, same-scheme shares are local.
|
||
/// Mixing (2,2)-additive with (2,2)-subtractive applies the party
|
||
/// coefficient. A public plaintext absorbs on party 0 for a one-word
|
||
/// share, and into component `x_0` for a replicated share.
|
||
/// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors)
|
||
/// @license Released under a GNU General Public v2.0 (GPLv2) license;
|
||
/// see [LICENSE.md](@ref license) for details.
|
||
|
||
#ifndef LIBDPF_INCLUDE_DPF_SECRET_SHARE_HPP__
|
||
#define LIBDPF_INCLUDE_DPF_SECRET_SHARE_HPP__
|
||
|
||
#include <array>
|
||
#include <cassert>
|
||
#include <cstddef>
|
||
#include <cstdint>
|
||
#include <cstring>
|
||
#include <ostream>
|
||
#include <stdexcept>
|
||
#include <tuple>
|
||
#include <type_traits>
|
||
#include <utility>
|
||
|
||
#include "hedley/hedley.h"
|
||
|
||
#include "dpf/shamir.hpp"
|
||
#include "dpf/twiddle.hpp"
|
||
|
||
namespace dpf
|
||
{
|
||
|
||
/// @brief Sharing scheme tag.
|
||
enum class sharing : unsigned char
|
||
{
|
||
/// (2,2) additive: `s = s0 + s1`.
|
||
additive = 0,
|
||
/// (2,2) subtractive: `s = s0 - s1`.
|
||
subtractive = 1,
|
||
/// (3,3) additive: `s = s0 + s1 + s2`. Every share is required.
|
||
additive3 = 2,
|
||
/// (2,3) replicated: party `i` holds `(x_i, x_{i+1 mod 3})` with
|
||
/// `s = x0 + x1 + x2`. Any two parties reconstruct.
|
||
replicated = 3,
|
||
/// (2,2) FSS leaf share. Opens like subtractive (`s0 - s1`). The distinct
|
||
/// tag is the evaluator's leaf output, not a generic subtractive word.
|
||
fss = 4,
|
||
/// (2,3) Shamir, `shamir::two_of_three`. Party `i` holds `s + slope·(i+1)`
|
||
/// in a field. Any two parties reconstruct by Lagrange. Points are `1`,
|
||
/// `2`, and `3`. This is `shamir::share<T, Party, 2, 3>`. Other thresholds
|
||
/// use `shamir::share<T, Party, K, N>`.
|
||
shamir = 5
|
||
};
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
struct secret_share;
|
||
|
||
template <typename T, std::size_t Party>
|
||
using additive_share = secret_share<T, Party, sharing::additive>;
|
||
|
||
template <typename T, std::size_t Party>
|
||
using subtractive_share = secret_share<T, Party, sharing::subtractive>;
|
||
|
||
template <typename T, std::size_t Party>
|
||
using additive3_share = secret_share<T, Party, sharing::additive3>;
|
||
|
||
template <typename T, std::size_t Party>
|
||
using replicated_share = secret_share<T, Party, sharing::replicated>;
|
||
|
||
template <typename T, std::size_t Party>
|
||
using fss_share = secret_share<T, Party, sharing::fss>;
|
||
|
||
template <typename T, std::size_t Party>
|
||
using shamir_share = secret_share<T, Party, sharing::shamir>;
|
||
|
||
/// @brief `true` for (2,2) additive, subtractive, and FSS leaf shares.
|
||
template <sharing Scheme>
|
||
inline constexpr bool is_two_party_sharing_v =
|
||
Scheme == sharing::additive || Scheme == sharing::subtractive
|
||
|| Scheme == sharing::fss;
|
||
|
||
/// @brief Parties who hold a share of `Scheme`.
|
||
template <sharing Scheme>
|
||
inline constexpr std::size_t sharing_parties_v =
|
||
is_two_party_sharing_v<Scheme> ? 2 : 3;
|
||
|
||
/// @brief Shares required to open `Scheme`.
|
||
template <sharing Scheme>
|
||
inline constexpr std::size_t sharing_threshold_v =
|
||
(Scheme == sharing::replicated || Scheme == sharing::shamir)
|
||
? 2
|
||
: sharing_parties_v<Scheme>;
|
||
|
||
template <typename T>
|
||
struct is_secret_share : std::false_type
|
||
{
|
||
};
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
struct is_secret_share<secret_share<T, Party, Scheme>> : std::true_type
|
||
{
|
||
};
|
||
|
||
template <typename T>
|
||
inline constexpr bool is_secret_share_v = is_secret_share<std::decay_t<T>>::value;
|
||
|
||
template <typename T>
|
||
struct share_party;
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
struct share_party<secret_share<T, Party, Scheme>>
|
||
: std::integral_constant<std::size_t, Party>
|
||
{
|
||
};
|
||
|
||
template <typename T>
|
||
inline constexpr std::size_t share_party_v = share_party<std::decay_t<T>>::value;
|
||
|
||
template <typename T>
|
||
struct share_scheme;
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
struct share_scheme<secret_share<T, Party, Scheme>>
|
||
: std::integral_constant<sharing, Scheme>
|
||
{
|
||
};
|
||
|
||
template <typename T>
|
||
inline constexpr sharing share_scheme_v = share_scheme<std::decay_t<T>>::value;
|
||
|
||
template <typename T>
|
||
struct share_value_type;
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
struct share_value_type<secret_share<T, Party, Scheme>>
|
||
{
|
||
using type = T;
|
||
};
|
||
|
||
template <typename T>
|
||
using share_value_type_t = typename share_value_type<std::decay_t<T>>::type;
|
||
|
||
namespace detail
|
||
{
|
||
|
||
/// @brief Two's-complement negation. Signed minimum stays defined.
|
||
/// @tparam T value type
|
||
/// @param v the `v`
|
||
/// @return the group negation used by a (2,2) sign flip
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T negate_word(const T & v) noexcept
|
||
{
|
||
if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
|
||
{
|
||
using unsigned_type = std::make_unsigned_t<T>;
|
||
return static_cast<T>(static_cast<unsigned_type>(0)
|
||
- static_cast<unsigned_type>(v));
|
||
}
|
||
else
|
||
return static_cast<T>(-v);
|
||
}
|
||
|
||
/// @brief Group sum. IEEE `float` / `double` add by XOR of the bits, matching
|
||
/// the leaf group. Signed integers add in the unsigned width.
|
||
/// @tparam T value type
|
||
/// @param a left addend
|
||
/// @param b right addend
|
||
/// @return `a` plus `b` in the share group
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T group_add(const T & a, const T & b) noexcept
|
||
{
|
||
if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>)
|
||
{
|
||
using bits_t = std::conditional_t<sizeof(T) == 4, std::uint32_t, std::uint64_t>;
|
||
bits_t xa{}, xb{};
|
||
std::memcpy(&xa, std::addressof(a), sizeof(T));
|
||
std::memcpy(&xb, std::addressof(b), sizeof(T));
|
||
bits_t xc = static_cast<bits_t>(xa ^ xb);
|
||
T out{};
|
||
std::memcpy(&out, &xc, sizeof(T));
|
||
return out;
|
||
}
|
||
else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
|
||
{
|
||
using unsigned_type = std::make_unsigned_t<T>;
|
||
return static_cast<T>(static_cast<unsigned_type>(a)
|
||
+ static_cast<unsigned_type>(b));
|
||
}
|
||
else
|
||
return static_cast<T>(a + b);
|
||
}
|
||
|
||
/// @brief Group difference. IEEE bits subtract by XOR. Signed integers
|
||
/// subtract in the unsigned width.
|
||
/// @tparam T value type
|
||
/// @param a minuend
|
||
/// @param b subtrahend
|
||
/// @return `a` minus `b` in the share group
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T group_sub(const T & a, const T & b) noexcept
|
||
{
|
||
if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>)
|
||
return group_add(a, b);
|
||
else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
|
||
{
|
||
using unsigned_type = std::make_unsigned_t<T>;
|
||
return static_cast<T>(static_cast<unsigned_type>(a)
|
||
- static_cast<unsigned_type>(b));
|
||
}
|
||
else
|
||
return static_cast<T>(a - b);
|
||
}
|
||
|
||
/// @brief Ring product. IEEE bits use AND, matching `leaf_group_mul`. Signed
|
||
/// integers multiply in the unsigned width.
|
||
/// @tparam T value type
|
||
/// @param a left factor
|
||
/// @param b right factor
|
||
/// @return `a` times `b` in the share ring
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T group_mul(const T & a, const T & b) noexcept
|
||
{
|
||
if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>)
|
||
{
|
||
using bits_t = std::conditional_t<sizeof(T) == 4, std::uint32_t, std::uint64_t>;
|
||
bits_t xa{}, xb{};
|
||
std::memcpy(&xa, std::addressof(a), sizeof(T));
|
||
std::memcpy(&xb, std::addressof(b), sizeof(T));
|
||
bits_t xc = static_cast<bits_t>(xa & xb);
|
||
T out{};
|
||
std::memcpy(&out, &xc, sizeof(T));
|
||
return out;
|
||
}
|
||
else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
|
||
{
|
||
using unsigned_type = std::make_unsigned_t<T>;
|
||
return static_cast<T>(static_cast<unsigned_type>(a)
|
||
* static_cast<unsigned_type>(b));
|
||
}
|
||
else
|
||
return static_cast<T>(a * b);
|
||
}
|
||
|
||
/// @brief Sign of a (2,2) party's word. Additive is always +1. Subtractive
|
||
/// and FSS are +1 on party 0 and −1 on party 1.
|
||
/// @tparam Scheme scheme
|
||
/// @tparam Party party index
|
||
template <sharing Scheme, std::size_t Party>
|
||
inline constexpr int two_party_sign_v =
|
||
(Party == 0 || Scheme == sharing::additive) ? 1 : -1;
|
||
|
||
/// @brief Rewrite a (2,2) word from `From` into `To`. Negate iff the signs differ.
|
||
/// @tparam From source scheme
|
||
/// @tparam To destination scheme
|
||
/// @tparam Party party index
|
||
/// @tparam T value type
|
||
/// @param v the stored word
|
||
/// @return the word in `To`
|
||
template <sharing From, sharing To, std::size_t Party, typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T retarget_word(const T & v) noexcept
|
||
{
|
||
if constexpr (two_party_sign_v<From, Party> == two_party_sign_v<To, Party>)
|
||
return v;
|
||
else
|
||
return negate_word(v);
|
||
}
|
||
|
||
// `detail::shamir_field` is the field inverse for Shamir reconstruction.
|
||
// The primary template lives in `shamir.hpp`. `fp61` and `gf2n` specialize it.
|
||
|
||
} // namespace detail
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
struct secret_share
|
||
{
|
||
static_assert(
|
||
(is_two_party_sharing_v<Scheme> && (Party == 0 || Party == 1))
|
||
|| (Scheme == sharing::additive3 && Party < 3),
|
||
"secret_share: (2,2) parties are 0 or 1; "
|
||
"(3,3)-additive parties are 0, 1, or 2");
|
||
|
||
using value_type = T;
|
||
static constexpr std::size_t party = Party;
|
||
static constexpr sharing scheme = Scheme;
|
||
|
||
T value{};
|
||
|
||
secret_share() = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share(const secret_share &) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share(secret_share &&) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share & operator=(const secret_share &) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share & operator=(secret_share &&) noexcept = default;
|
||
~secret_share() = default;
|
||
|
||
/// @brief Bit-preserving construction. Does not apply a party coefficient.
|
||
/// @param v the `v`
|
||
/// @return Bit-preserving construction
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
static constexpr secret_share from_raw(T v) noexcept
|
||
{
|
||
secret_share s;
|
||
s.value = v;
|
||
return s;
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
constexpr const T & raw() const noexcept { return value; }
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
constexpr T & raw() noexcept { return value; }
|
||
|
||
/// @brief Secret-preserving conversion to an additive share of the same party.
|
||
/// @return Secret-preserving conversion to an additive share of the same party
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
constexpr additive_share<T, Party> as_additive() const noexcept
|
||
{
|
||
static_assert(is_two_party_sharing_v<Scheme>,
|
||
"as_additive converts a (2,2) share; "
|
||
"a (3,3) component is already additive, and a replicated share "
|
||
"uses as_additive3()");
|
||
if constexpr (Scheme == sharing::additive)
|
||
return additive_share<T, Party>::from_raw(value);
|
||
// Subtractive and FSS: party 0 keeps bits; party 1 negates.
|
||
return additive_share<T, Party>::from_raw(
|
||
detail::retarget_word<Scheme, sharing::additive, Party>(value));
|
||
}
|
||
|
||
/// @brief Secret-preserving conversion to a subtractive share of the same party.
|
||
/// @return Secret-preserving conversion to a subtractive share of the same party
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
constexpr subtractive_share<T, Party> as_subtractive() const noexcept
|
||
{
|
||
static_assert(is_two_party_sharing_v<Scheme>,
|
||
"as_subtractive converts a (2,2) share");
|
||
if constexpr (Scheme == sharing::subtractive)
|
||
return subtractive_share<T, Party>::from_raw(value);
|
||
// Additive party 1 negates. FSS already opens like subtractive.
|
||
return subtractive_share<T, Party>::from_raw(
|
||
detail::retarget_word<Scheme, sharing::subtractive, Party>(value));
|
||
}
|
||
|
||
/// @brief Secret-preserving conversion to an FSS leaf share of the same party.
|
||
/// @details FSS leaves open like subtractive shares. Additive party 1 negates.
|
||
/// @return the FSS share
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
constexpr fss_share<T, Party> as_fss() const noexcept
|
||
{
|
||
static_assert(is_two_party_sharing_v<Scheme>,
|
||
"as_fss converts a (2,2) share");
|
||
if constexpr (Scheme == sharing::fss)
|
||
return fss_share<T, Party>::from_raw(value);
|
||
return fss_share<T, Party>::from_raw(
|
||
detail::retarget_word<Scheme, sharing::fss, Party>(value));
|
||
}
|
||
|
||
/// @brief Bit-preserving retag (no secret-preserving sign fix).
|
||
/// @tparam NewScheme new scheme
|
||
/// @tparam NewParty new party
|
||
/// @return Bit-preserving retag (no secret-preserving sign fix)
|
||
template <sharing NewScheme, std::size_t NewParty = Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, NewParty, NewScheme> retag() const noexcept
|
||
{
|
||
return secret_share<T, NewParty, NewScheme>::from_raw(value);
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
constexpr secret_share operator-() const noexcept
|
||
{
|
||
return from_raw(detail::negate_word(value));
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share & operator+=(const secret_share & rhs) noexcept
|
||
{
|
||
value = static_cast<T>(value + rhs.value);
|
||
return *this;
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share & operator-=(const secret_share & rhs) noexcept
|
||
{
|
||
value = static_cast<T>(value - rhs.value);
|
||
return *this;
|
||
}
|
||
|
||
template <typename Scalar,
|
||
std::enable_if_t<!is_secret_share_v<Scalar>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator*=(const Scalar & c) noexcept
|
||
{
|
||
value = static_cast<T>(value * static_cast<T>(c));
|
||
return *this;
|
||
}
|
||
|
||
/// @brief Absorb a public plaintext on party 0 only.
|
||
/// @tparam Plain plain
|
||
/// @tparam T value type
|
||
/// @param c the `c`
|
||
/// @return `*this`
|
||
template <typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator+=(const Plain & c) noexcept
|
||
{
|
||
if constexpr (Party == 0)
|
||
value = static_cast<T>(value + static_cast<T>(c));
|
||
return *this;
|
||
}
|
||
|
||
template <typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator-=(const Plain & c) noexcept
|
||
{
|
||
if constexpr (Party == 0)
|
||
value = static_cast<T>(value - static_cast<T>(c));
|
||
return *this;
|
||
}
|
||
};
|
||
|
||
/// @brief (2,3) replicated share. Party `Party` holds `(x_Party, x_{Party+1})`.
|
||
/// @details `own` is this party's (3,3) component. `next` is the following
|
||
/// party's component, stored here so any two parties hold every
|
||
/// component. Local `+`, `-`, and scalar `*` touch both words.
|
||
/// A public plaintext is added only to `x_0`: party 0 updates `own`,
|
||
/// party 2 updates `next`, party 1 is unchanged.
|
||
/// @tparam T value type
|
||
/// @tparam Party party index, `0`, `1`, or `2`
|
||
template <typename T, std::size_t Party>
|
||
struct secret_share<T, Party, sharing::replicated>
|
||
{
|
||
static_assert(Party < 3,
|
||
"replicated_share party must be 0, 1, or 2");
|
||
|
||
using value_type = T;
|
||
static constexpr std::size_t party = Party;
|
||
static constexpr sharing scheme = sharing::replicated;
|
||
static constexpr std::size_t next_party = (Party + 1) % 3;
|
||
|
||
/// Component `x_Party`.
|
||
T own{};
|
||
/// Component `x_{Party+1 mod 3}`.
|
||
T next{};
|
||
|
||
secret_share() = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share(const secret_share &) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share(secret_share &&) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share & operator=(const secret_share &) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share & operator=(secret_share &&) noexcept = default;
|
||
~secret_share() = default;
|
||
|
||
/// @brief Bit-preserving construction.
|
||
/// @param own_v component `x_Party`
|
||
/// @param next_v component `x_{Party+1 mod 3}`
|
||
/// @return the share
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
static constexpr secret_share from_raw(T own_v, T next_v) noexcept
|
||
{
|
||
secret_share s;
|
||
s.own = own_v;
|
||
s.next = next_v;
|
||
return s;
|
||
}
|
||
|
||
/// @brief Build from this party's (3,3) component and the next party's.
|
||
/// @param mine `x_Party`
|
||
/// @param nxt `x_{Party+1 mod 3}`
|
||
/// @return the replicated share
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
static constexpr secret_share from_additive3(
|
||
const additive3_share<T, Party> & mine,
|
||
const additive3_share<T, next_party> & nxt) noexcept
|
||
{
|
||
return from_raw(mine.raw(), nxt.raw());
|
||
}
|
||
|
||
/// @brief This party's underlying (3,3) component (`own`).
|
||
/// @return an `additive3_share` of the same party
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
constexpr additive3_share<T, Party> as_additive3() const noexcept
|
||
{
|
||
return additive3_share<T, Party>::from_raw(own);
|
||
}
|
||
|
||
/// @brief The next party's (3,3) component, as stored in `next`.
|
||
/// @return an `additive3_share` of party `Party + 1 mod 3`
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
constexpr additive3_share<T, next_party> next_additive3() const noexcept
|
||
{
|
||
return additive3_share<T, next_party>::from_raw(next);
|
||
}
|
||
|
||
/// @brief Add `v` into `x_Party`.
|
||
/// @details The previous party stores the same component as `next` and
|
||
/// must apply the same addend, or the two replicas diverge.
|
||
/// `add_replicated` updates both holders.
|
||
/// @param v addend in the share group
|
||
/// @return `*this`
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share & add_own(const T & v) noexcept
|
||
{
|
||
own = detail::group_add(own, v);
|
||
return *this;
|
||
}
|
||
|
||
/// @brief Add `v` into `x_{Party+1}`.
|
||
/// @details Party `Party+1` stores that component as `own` and must apply
|
||
/// the same addend.
|
||
/// @param v addend in the share group
|
||
/// @return `*this`
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share & add_next(const T & v) noexcept
|
||
{
|
||
next = detail::group_add(next, v);
|
||
return *this;
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share operator-() const noexcept
|
||
{
|
||
return from_raw(detail::negate_word(own), detail::negate_word(next));
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share & operator+=(const secret_share & rhs) noexcept
|
||
{
|
||
own = detail::group_add(own, rhs.own);
|
||
next = detail::group_add(next, rhs.next);
|
||
return *this;
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share & operator-=(const secret_share & rhs) noexcept
|
||
{
|
||
own = detail::group_sub(own, rhs.own);
|
||
next = detail::group_sub(next, rhs.next);
|
||
return *this;
|
||
}
|
||
|
||
template <typename Scalar,
|
||
std::enable_if_t<!is_secret_share_v<Scalar>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator*=(const Scalar & c) noexcept
|
||
{
|
||
own = static_cast<T>(own * static_cast<T>(c));
|
||
next = static_cast<T>(next * static_cast<T>(c));
|
||
return *this;
|
||
}
|
||
|
||
/// @brief Absorb a public plaintext into `x_0` only.
|
||
/// @tparam Plain plain
|
||
/// @param c the `c`
|
||
/// @return `*this`
|
||
template <typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator+=(const Plain & c) noexcept
|
||
{
|
||
const T addend = static_cast<T>(c);
|
||
if constexpr (Party == 0)
|
||
own = detail::group_add(own, addend);
|
||
else if constexpr (Party == 2)
|
||
next = detail::group_add(next, addend);
|
||
return *this;
|
||
}
|
||
|
||
template <typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator-=(const Plain & c) noexcept
|
||
{
|
||
const T subtrahend = static_cast<T>(c);
|
||
if constexpr (Party == 0)
|
||
own = detail::group_sub(own, subtrahend);
|
||
else if constexpr (Party == 2)
|
||
next = detail::group_sub(next, subtrahend);
|
||
return *this;
|
||
}
|
||
};
|
||
|
||
/// @brief (2,3) Shamir share. Party `Party` holds `s + slope·(Party+1)`.
|
||
/// @details This is `shamir::share<T, Party, 2, 3>`, the `shamir::two_of_three`
|
||
/// case of `(K,N)` Shamir. The evaluation points are `1`, `2`, and
|
||
/// `3`, matching `shamir3::share`. A public plaintext is added on
|
||
/// every party, because every evaluation of `s + c` grows by `c`.
|
||
/// Scalar multiplication scales the share. Two shares multiply to a
|
||
/// degree-2 polynomial, which is not a Shamir share; use `rss_mul`
|
||
/// for a (2,3) product.
|
||
/// @tparam T field element
|
||
/// @tparam Party party index, `0`, `1`, or `2`
|
||
template <typename T, std::size_t Party>
|
||
struct secret_share<T, Party, sharing::shamir>
|
||
{
|
||
static_assert(Party < 3, "shamir_share party must be 0, 1, or 2");
|
||
|
||
using value_type = T;
|
||
using access_type = shamir::two_of_three;
|
||
static constexpr std::size_t party = Party;
|
||
static constexpr sharing scheme = sharing::shamir;
|
||
static constexpr std::size_t threshold = access_type::threshold;
|
||
static constexpr std::size_t parties = access_type::parties;
|
||
static constexpr std::size_t degree = access_type::degree;
|
||
/// Lagrange point. Party 0 is point 1.
|
||
static constexpr std::uint64_t point = Party + 1;
|
||
|
||
T value{};
|
||
|
||
secret_share() = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share(const secret_share &) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share(secret_share &&) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share & operator=(const secret_share &) noexcept = default;
|
||
HEDLEY_NO_THROW
|
||
secret_share & operator=(secret_share &&) noexcept = default;
|
||
~secret_share() = default;
|
||
|
||
/// @brief Bit-preserving construction. Does not apply a Lagrange weight.
|
||
/// @param v the field element
|
||
/// @return the share
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
static constexpr secret_share from_raw(T v) noexcept
|
||
{
|
||
secret_share s;
|
||
s.value = v;
|
||
return s;
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
constexpr const T & raw() const noexcept { return value; }
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
constexpr T & raw() noexcept { return value; }
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share operator-() const noexcept
|
||
{
|
||
return from_raw(static_cast<T>(-value));
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share & operator+=(const secret_share & rhs) noexcept
|
||
{
|
||
value = static_cast<T>(value + rhs.value);
|
||
return *this;
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr secret_share & operator-=(const secret_share & rhs) noexcept
|
||
{
|
||
value = static_cast<T>(value - rhs.value);
|
||
return *this;
|
||
}
|
||
|
||
template <typename Scalar,
|
||
std::enable_if_t<!is_secret_share_v<Scalar>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator*=(const Scalar & c) noexcept
|
||
{
|
||
value = static_cast<T>(value * static_cast<T>(c));
|
||
return *this;
|
||
}
|
||
|
||
/// @brief Absorb a public plaintext on every party.
|
||
/// @tparam Plain plain
|
||
/// @param c the `c`
|
||
/// @return `*this`
|
||
template <typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator+=(const Plain & c) noexcept
|
||
{
|
||
value = static_cast<T>(value + static_cast<T>(c));
|
||
return *this;
|
||
}
|
||
|
||
template <typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share & operator-=(const Plain & c) noexcept
|
||
{
|
||
value = static_cast<T>(value - static_cast<T>(c));
|
||
return *this;
|
||
}
|
||
};
|
||
|
||
namespace shamir
|
||
{
|
||
|
||
/// @brief `(2,3)` is the `sharing::shamir` share, not `basic_share`.
|
||
template <typename T, std::size_t Party>
|
||
struct share_of<T, Party, 2, 3>
|
||
{
|
||
using type = secret_share<T, Party, sharing::shamir>;
|
||
};
|
||
|
||
template <typename T, std::size_t Party>
|
||
struct params<secret_share<T, Party, sharing::shamir>> : std::true_type
|
||
{
|
||
using value_type = T;
|
||
static constexpr std::size_t party = Party;
|
||
static constexpr std::size_t threshold = 2;
|
||
static constexpr std::size_t parties = 3;
|
||
static constexpr std::uint64_t point =
|
||
secret_share<T, Party, sharing::shamir>::point;
|
||
};
|
||
|
||
} // namespace shamir
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Same-scheme, same-party arithmetic
|
||
// ---------------------------------------------------------------------------
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, Scheme> operator+(
|
||
secret_share<T, Party, Scheme> lhs,
|
||
const secret_share<T, Party, Scheme> & rhs) noexcept
|
||
{
|
||
lhs += rhs;
|
||
return lhs;
|
||
}
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, Scheme> operator-(
|
||
secret_share<T, Party, Scheme> lhs,
|
||
const secret_share<T, Party, Scheme> & rhs) noexcept
|
||
{
|
||
lhs -= rhs;
|
||
return lhs;
|
||
}
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme, typename Scalar,
|
||
std::enable_if_t<!is_secret_share_v<Scalar>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, Scheme> operator*(
|
||
secret_share<T, Party, Scheme> lhs, const Scalar & c) noexcept
|
||
{
|
||
lhs *= c;
|
||
return lhs;
|
||
}
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme, typename Scalar,
|
||
std::enable_if_t<!is_secret_share_v<Scalar>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, Scheme> operator*(
|
||
const Scalar & c, secret_share<T, Party, Scheme> rhs) noexcept
|
||
{
|
||
rhs *= c;
|
||
return rhs;
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Cross-scheme, same-party (2,2) only. Keep the left-hand scheme. Party 1
|
||
// flips the right-hand word when the two schemes disagree on its sign.
|
||
// Subtractive and FSS share a sign, so mixing those does not flip.
|
||
// ---------------------------------------------------------------------------
|
||
|
||
template <typename T, std::size_t Party, sharing LhsScheme, sharing RhsScheme,
|
||
std::enable_if_t<LhsScheme != RhsScheme
|
||
&& is_two_party_sharing_v<LhsScheme>
|
||
&& is_two_party_sharing_v<RhsScheme>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, LhsScheme> operator+(
|
||
const secret_share<T, Party, LhsScheme> & lhs,
|
||
const secret_share<T, Party, RhsScheme> & rhs) noexcept
|
||
{
|
||
if constexpr (detail::two_party_sign_v<LhsScheme, Party>
|
||
== detail::two_party_sign_v<RhsScheme, Party>)
|
||
return secret_share<T, Party, LhsScheme>::from_raw(
|
||
static_cast<T>(lhs.raw() + rhs.raw()));
|
||
else
|
||
return secret_share<T, Party, LhsScheme>::from_raw(
|
||
static_cast<T>(lhs.raw() - rhs.raw()));
|
||
}
|
||
|
||
template <typename T, std::size_t Party, sharing LhsScheme, sharing RhsScheme,
|
||
std::enable_if_t<LhsScheme != RhsScheme
|
||
&& is_two_party_sharing_v<LhsScheme>
|
||
&& is_two_party_sharing_v<RhsScheme>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, LhsScheme> operator-(
|
||
const secret_share<T, Party, LhsScheme> & lhs,
|
||
const secret_share<T, Party, RhsScheme> & rhs) noexcept
|
||
{
|
||
if constexpr (detail::two_party_sign_v<LhsScheme, Party>
|
||
== detail::two_party_sign_v<RhsScheme, Party>)
|
||
return secret_share<T, Party, LhsScheme>::from_raw(
|
||
static_cast<T>(lhs.raw() - rhs.raw()));
|
||
else
|
||
return secret_share<T, Party, LhsScheme>::from_raw(
|
||
static_cast<T>(lhs.raw() + rhs.raw()));
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Plaintext absorb (party 0 only)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme, typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, Scheme> operator+(
|
||
secret_share<T, Party, Scheme> lhs, const Plain & c) noexcept
|
||
{
|
||
lhs += c;
|
||
return lhs;
|
||
}
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme, typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, Scheme> operator+(
|
||
const Plain & c, secret_share<T, Party, Scheme> rhs) noexcept
|
||
{
|
||
rhs += c;
|
||
return rhs;
|
||
}
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme, typename Plain,
|
||
std::enable_if_t<!is_secret_share_v<Plain>
|
||
&& std::is_convertible_v<Plain, T>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr secret_share<T, Party, Scheme> operator-(
|
||
secret_share<T, Party, Scheme> lhs, const Plain & c) noexcept
|
||
{
|
||
lhs -= c;
|
||
return lhs;
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Equality (same party, same scheme) — compare raw bits
|
||
// ---------------------------------------------------------------------------
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme,
|
||
std::enable_if_t<Scheme != sharing::replicated, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr bool operator==(const secret_share<T, Party, Scheme> & lhs,
|
||
const secret_share<T, Party, Scheme> & rhs) noexcept
|
||
{
|
||
return lhs.raw() == rhs.raw();
|
||
}
|
||
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr bool operator==(const replicated_share<T, Party> & lhs,
|
||
const replicated_share<T, Party> & rhs) noexcept
|
||
{
|
||
return lhs.own == rhs.own && lhs.next == rhs.next;
|
||
}
|
||
|
||
template <typename T, std::size_t Party, sharing Scheme>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr bool operator!=(const secret_share<T, Party, Scheme> & lhs,
|
||
const secret_share<T, Party, Scheme> & rhs) noexcept
|
||
{
|
||
return !(lhs == rhs);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Reconstruction
|
||
// ---------------------------------------------------------------------------
|
||
|
||
template <typename T, sharing Scheme,
|
||
std::enable_if_t<is_two_party_sharing_v<Scheme>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T reconstruct(const secret_share<T, 0, Scheme> & s0,
|
||
const secret_share<T, 1, Scheme> & s1) noexcept
|
||
{
|
||
if constexpr (Scheme == sharing::additive)
|
||
return detail::group_add(s0.raw(), s1.raw());
|
||
else
|
||
return detail::group_sub(s0.raw(), s1.raw());
|
||
}
|
||
|
||
template <typename T, sharing Scheme,
|
||
std::enable_if_t<is_two_party_sharing_v<Scheme>, int> = 0>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T reconstruct(const secret_share<T, 1, Scheme> & s1,
|
||
const secret_share<T, 0, Scheme> & s0) noexcept
|
||
{
|
||
return reconstruct(s0, s1);
|
||
}
|
||
|
||
namespace detail
|
||
{
|
||
|
||
template <std::size_t Party, typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr void store_additive3(T & c0, T & c1, T & c2,
|
||
const additive3_share<T, Party> & share) noexcept
|
||
{
|
||
if constexpr (Party == 0)
|
||
c0 = share.raw();
|
||
else if constexpr (Party == 1)
|
||
c1 = share.raw();
|
||
else
|
||
c2 = share.raw();
|
||
}
|
||
|
||
template <std::size_t Party, typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_NO_THROW
|
||
constexpr void store_replicated_own(T & c0, T & c1, T & c2,
|
||
const replicated_share<T, Party> & share) noexcept
|
||
{
|
||
if constexpr (Party == 0)
|
||
c0 = share.own;
|
||
else if constexpr (Party == 1)
|
||
c1 = share.own;
|
||
else
|
||
c2 = share.own;
|
||
}
|
||
|
||
} // namespace detail
|
||
|
||
/// @brief Open a (3,3)-additive sharing. Parties may be passed in any order.
|
||
/// @tparam T value type
|
||
/// @tparam P party of the first share
|
||
/// @tparam Q party of the second share
|
||
/// @tparam R party of the third share
|
||
/// @param a first share
|
||
/// @param b second share
|
||
/// @param c third share
|
||
/// @return `x0 + x1 + x2`
|
||
template <typename T, std::size_t P, std::size_t Q, std::size_t R>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T reconstruct(const additive3_share<T, P> & a,
|
||
const additive3_share<T, Q> & b,
|
||
const additive3_share<T, R> & c) noexcept
|
||
{
|
||
static_assert(P != Q && Q != R && P != R,
|
||
"additive3 reconstruct: need three distinct parties");
|
||
T c0{}, c1{}, c2{};
|
||
detail::store_additive3(c0, c1, c2, a);
|
||
detail::store_additive3(c0, c1, c2, b);
|
||
detail::store_additive3(c0, c1, c2, c);
|
||
return detail::group_add(detail::group_add(c0, c1), c2);
|
||
}
|
||
|
||
/// @brief Open a (2,3)-replicated sharing from any two parties.
|
||
/// @details Party `P` contributes `(x_P, x_{P+1})`. The missing component is
|
||
/// taken from party `Q`.
|
||
/// @tparam T value type
|
||
/// @tparam P first party
|
||
/// @tparam Q second party
|
||
/// @param a first share
|
||
/// @param b second share
|
||
/// @return `x0 + x1 + x2`
|
||
template <typename T, std::size_t P, std::size_t Q>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T reconstruct(const replicated_share<T, P> & a,
|
||
const replicated_share<T, Q> & b) noexcept
|
||
{
|
||
static_assert(P < 3 && Q < 3 && P != Q,
|
||
"replicated reconstruct: need two distinct parties in 0..2");
|
||
constexpr std::size_t missing = (P + 2) % 3;
|
||
T third{};
|
||
if constexpr (Q == missing)
|
||
third = b.own;
|
||
else
|
||
third = b.next;
|
||
return detail::group_add(detail::group_add(a.own, a.next), third);
|
||
}
|
||
|
||
/// @brief Open a (2,3)-replicated sharing from all three `own` components.
|
||
/// @details This is the underlying (3,3) sum. `next` is not read.
|
||
/// @tparam T value type
|
||
/// @tparam P first party
|
||
/// @tparam Q second party
|
||
/// @tparam R third party
|
||
/// @param a first share
|
||
/// @param b second share
|
||
/// @param c third share
|
||
/// @return `x0 + x1 + x2`
|
||
template <typename T, std::size_t P, std::size_t Q, std::size_t R>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr T reconstruct(const replicated_share<T, P> & a,
|
||
const replicated_share<T, Q> & b,
|
||
const replicated_share<T, R> & c) noexcept
|
||
{
|
||
static_assert(P != Q && Q != R && P != R,
|
||
"replicated reconstruct: need three distinct parties");
|
||
T c0{}, c1{}, c2{};
|
||
detail::store_replicated_own(c0, c1, c2, a);
|
||
detail::store_replicated_own(c0, c1, c2, b);
|
||
detail::store_replicated_own(c0, c1, c2, c);
|
||
return detail::group_add(detail::group_add(c0, c1), c2);
|
||
}
|
||
|
||
/// @brief Open a (2,3) Shamir sharing from any two parties.
|
||
/// @details `shamir::reconstruct` for `shamir::two_of_three`.
|
||
/// @tparam T field type. Requires `detail::shamir_field<T>`
|
||
/// @tparam P first party
|
||
/// @tparam Q second party
|
||
/// @param a first share
|
||
/// @param b second share
|
||
/// @return the secret
|
||
/// @throws std::invalid_argument if a Lagrange denominator is zero
|
||
template <typename T, std::size_t P, std::size_t Q>
|
||
HEDLEY_WARN_UNUSED_RESULT
|
||
T reconstruct(const shamir_share<T, P> & a, const shamir_share<T, Q> & b)
|
||
{
|
||
return shamir::reconstruct(a, b);
|
||
}
|
||
|
||
/// @brief Open a (2,3) Shamir sharing from all three parties.
|
||
/// @details The third share is checked against the polynomial of the first two.
|
||
/// @throws std::invalid_argument if a party index is repeated
|
||
/// @throws std::runtime_error if the three shares are inconsistent
|
||
template <typename T, std::size_t P, std::size_t Q, std::size_t R>
|
||
HEDLEY_WARN_UNUSED_RESULT
|
||
T reconstruct(const shamir_share<T, P> & a, const shamir_share<T, Q> & b,
|
||
const shamir_share<T, R> & c)
|
||
{
|
||
return shamir::reconstruct(a, b, c);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Plaintext splits (share1 = 0)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
HEDLEY_NO_THROW
|
||
constexpr auto make_additive_shares(T secret) noexcept
|
||
{
|
||
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
|
||
return std::make_pair(
|
||
additive_share<T_, 0>::from_raw(static_cast<T_>(secret)),
|
||
additive_share<T_, 1>::from_raw(T_{}));
|
||
}
|
||
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
HEDLEY_NO_THROW
|
||
constexpr auto make_subtractive_shares(T secret) noexcept
|
||
{
|
||
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
|
||
return std::make_pair(
|
||
subtractive_share<T_, 0>::from_raw(static_cast<T_>(secret)),
|
||
subtractive_share<T_, 1>::from_raw(T_{}));
|
||
}
|
||
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
HEDLEY_NO_THROW
|
||
constexpr auto make_additive3_shares(T secret) noexcept
|
||
{
|
||
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
|
||
return std::make_tuple(
|
||
additive3_share<T_, 0>::from_raw(static_cast<T_>(secret)),
|
||
additive3_share<T_, 1>::from_raw(T_{}),
|
||
additive3_share<T_, 2>::from_raw(T_{}));
|
||
}
|
||
|
||
/// @brief Shamir shares of `secret` for access structure `(K,N)`.
|
||
/// @details Party `i` stores `p(i+1)` where
|
||
/// `p(x) = secret + coeff[0] x + ... + coeff[K-2] x^{K-1}`.
|
||
/// This is `shamir::deal<T, K, N>`.
|
||
/// @tparam K reconstruction threshold
|
||
/// @tparam N shareholder count
|
||
/// @tparam T field type
|
||
/// @param secret the constant term
|
||
/// @param coeff higher coefficients, low degree first
|
||
/// @return shares for parties `0 .. N-1`
|
||
template <std::size_t K, std::size_t N, typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
HEDLEY_NO_THROW
|
||
constexpr auto make_shamir_shares(T secret,
|
||
const std::array<std::remove_cv_t<std::remove_reference_t<T>>,
|
||
shamir::access<K, N>::degree> & coeff) noexcept
|
||
{
|
||
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
|
||
return shamir::deal<T_, K, N>(static_cast<T_>(secret), coeff);
|
||
}
|
||
|
||
/// @brief Degree-1 Shamir shares of `secret` with the given slope.
|
||
/// @details `(K,N) = (2,3)`. Party `i` stores `secret + slope·(i+1)`.
|
||
/// This is `make_shamir_shares<2, 3>` with that one coefficient.
|
||
/// @tparam T field type
|
||
/// @param secret the cleartext secret
|
||
/// @param slope the uniform slope. Zero puts `secret` on every party
|
||
/// @return shares for parties 0, 1, and 2
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
HEDLEY_NO_THROW
|
||
constexpr auto make_shamir_shares(T secret, T slope) noexcept
|
||
{
|
||
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
|
||
return make_shamir_shares<2, 3>(static_cast<T_>(secret),
|
||
std::array<T_, 1>{{static_cast<T_>(slope)}});
|
||
}
|
||
|
||
/// @brief Deterministic (2,3) replicated split. The secret sits in `x_0`.
|
||
/// @details Party 0 stores `(secret, 0)`, party 1 stores `(0, 0)`, party 2
|
||
/// stores `(0, secret)`.
|
||
/// @tparam T value type
|
||
/// @param secret the cleartext secret
|
||
/// @return shares for parties 0, 1, and 2
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
HEDLEY_NO_THROW
|
||
constexpr auto make_replicated_shares(T secret) noexcept
|
||
{
|
||
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
|
||
const T_ s = static_cast<T_>(secret);
|
||
const T_ z{};
|
||
return std::make_tuple(
|
||
replicated_share<T_, 0>::from_raw(s, z),
|
||
replicated_share<T_, 1>::from_raw(z, z),
|
||
replicated_share<T_, 2>::from_raw(z, s));
|
||
}
|
||
|
||
/// @brief Replicated shares of the (3,3) components `x0`, `x1`, and `x2`.
|
||
/// @tparam T value type
|
||
/// @param x0 component held by parties 0 and 2
|
||
/// @param x1 component held by parties 0 and 1
|
||
/// @param x2 component held by parties 1 and 2
|
||
/// @return shares for parties 0, 1, and 2
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
HEDLEY_NO_THROW
|
||
constexpr auto make_replicated_shares(T x0, T x1, T x2) noexcept
|
||
{
|
||
using T_ = std::remove_cv_t<std::remove_reference_t<T>>;
|
||
const T_ a = static_cast<T_>(x0);
|
||
const T_ b = static_cast<T_>(x1);
|
||
const T_ c = static_cast<T_>(x2);
|
||
return std::make_tuple(
|
||
replicated_share<T_, 0>::from_raw(a, b),
|
||
replicated_share<T_, 1>::from_raw(b, c),
|
||
replicated_share<T_, 2>::from_raw(c, a));
|
||
}
|
||
|
||
/// @brief Replicated shares of an existing (3,3)-additive sharing.
|
||
/// @tparam T value type
|
||
/// @param s0 party 0's component
|
||
/// @param s1 party 1's component
|
||
/// @param s2 party 2's component
|
||
/// @return shares for parties 0, 1, and 2
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_CONST
|
||
HEDLEY_NO_THROW
|
||
constexpr auto make_replicated_shares(const additive3_share<T, 0> & s0,
|
||
const additive3_share<T, 1> & s1,
|
||
const additive3_share<T, 2> & s2) noexcept
|
||
{
|
||
return make_replicated_shares(s0.raw(), s1.raw(), s2.raw());
|
||
}
|
||
|
||
/// @brief Fold a (3,3)-additive sharing into a replicated sharing.
|
||
/// @details Each component is added at both parties that store it, so the
|
||
/// replicas stay equal.
|
||
/// @tparam T value type
|
||
/// @param r0 party 0
|
||
/// @param r1 party 1
|
||
/// @param r2 party 2
|
||
/// @param a0 addend component 0
|
||
/// @param a1 addend component 1
|
||
/// @param a2 addend component 2
|
||
/// @return the updated replicated shares
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr auto add_replicated(
|
||
replicated_share<T, 0> r0,
|
||
replicated_share<T, 1> r1,
|
||
replicated_share<T, 2> r2,
|
||
const additive3_share<T, 0> & a0,
|
||
const additive3_share<T, 1> & a1,
|
||
const additive3_share<T, 2> & a2) noexcept
|
||
{
|
||
r0.add_own(a0.raw());
|
||
r0.add_next(a1.raw());
|
||
r1.add_own(a1.raw());
|
||
r1.add_next(a2.raw());
|
||
r2.add_own(a2.raw());
|
||
r2.add_next(a0.raw());
|
||
return std::make_tuple(r0, r1, r2);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Share conversions
|
||
//
|
||
// Letters: a (2,2) additive, b (2,2) subtractive, fss (2,2) leaf share,
|
||
// y (3,3) additive, rss (2,3) replicated, s (2,3) Shamir.
|
||
//
|
||
// Local, one party, secret-preserving:
|
||
// a2b b2a a2fss fss2a b2fss fss2b
|
||
// rss2y (this party's component)
|
||
// y2rss(own, next) (one replicated share)
|
||
// Local, a reconstructing set in one place (the secret is opened, then split):
|
||
// y2rss(y0,y1,y2) rss2y(r0,r1,r2)
|
||
// s2y y2s s2rss rss2s
|
||
// Not local, and not defined here: a2y y2a b2y y2b a2rss rss2a b2rss rss2b
|
||
// fss2y y2fss fss2rss rss2fss, and Shamir with a single (2,2) share.
|
||
// Those change the party count. The garbled-bit conversions with the same
|
||
// names (a2y through y2rss) are dpf::yao in dpf/yao_share.hpp. They are not
|
||
// these casts. Top-level rss2y / y2rss stay the local (3,3) operations.
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/// @brief (2,2) additive to subtractive. Party 1 negates.
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr subtractive_share<T, Party> a2b(const additive_share<T, Party> & s) noexcept
|
||
{
|
||
return s.as_subtractive();
|
||
}
|
||
|
||
/// @brief (2,2) subtractive to additive. Party 1 negates.
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr additive_share<T, Party> b2a(const subtractive_share<T, Party> & s) noexcept
|
||
{
|
||
return s.as_additive();
|
||
}
|
||
|
||
/// @brief (2,2) additive to an FSS leaf share. Party 1 negates.
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr fss_share<T, Party> a2fss(const additive_share<T, Party> & s) noexcept
|
||
{
|
||
return s.as_fss();
|
||
}
|
||
|
||
/// @brief FSS leaf share to (2,2) additive. Party 1 negates.
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr additive_share<T, Party> fss2a(const fss_share<T, Party> & s) noexcept
|
||
{
|
||
return s.as_additive();
|
||
}
|
||
|
||
/// @brief (2,2) subtractive to an FSS leaf share. Same opening, bits unchanged.
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr fss_share<T, Party> b2fss(const subtractive_share<T, Party> & s) noexcept
|
||
{
|
||
return s.as_fss();
|
||
}
|
||
|
||
/// @brief FSS leaf share to (2,2) subtractive. Same opening, bits unchanged.
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr subtractive_share<T, Party> fss2b(const fss_share<T, Party> & s) noexcept
|
||
{
|
||
return s.as_subtractive();
|
||
}
|
||
|
||
/// @brief This party's (3,3) component of a replicated share (`y` = additive3).
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr additive3_share<T, Party> rss2y(const replicated_share<T, Party> & s) noexcept
|
||
{
|
||
return s.as_additive3();
|
||
}
|
||
|
||
/// @brief One replicated share from this party's component and the next party's.
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr replicated_share<T, Party> y2rss(
|
||
const additive3_share<T, Party> & mine,
|
||
const additive3_share<T, replicated_share<T, Party>::next_party> & nxt) noexcept
|
||
{
|
||
return replicated_share<T, Party>::from_additive3(mine, nxt);
|
||
}
|
||
|
||
/// @brief Replicated shares of a (3,3)-additive sharing.
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr auto y2rss(const additive3_share<T, 0> & y0,
|
||
const additive3_share<T, 1> & y1,
|
||
const additive3_share<T, 2> & y2) noexcept
|
||
{
|
||
return make_replicated_shares(y0, y1, y2);
|
||
}
|
||
|
||
/// @brief The three (3,3) components of a replicated sharing.
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr auto rss2y(const replicated_share<T, 0> & r0,
|
||
const replicated_share<T, 1> & r1,
|
||
const replicated_share<T, 2> & r2) noexcept
|
||
{
|
||
return std::make_tuple(r0.as_additive3(), r1.as_additive3(), r2.as_additive3());
|
||
}
|
||
|
||
/// @brief Open two Shamir shares and split the secret as (3,3) additive.
|
||
/// @details The secret sits on party 0. The other two components are zero.
|
||
template <typename T, std::size_t P, std::size_t Q>
|
||
HEDLEY_WARN_UNUSED_RESULT
|
||
auto s2y(const shamir_share<T, P> & a, const shamir_share<T, Q> & b)
|
||
{
|
||
return make_additive3_shares(reconstruct(a, b));
|
||
}
|
||
|
||
/// @brief Shamir-share a (3,3) additive secret with `slope`.
|
||
template <typename T>
|
||
HEDLEY_WARN_UNUSED_RESULT
|
||
auto y2s(const additive3_share<T, 0> & y0, const additive3_share<T, 1> & y1,
|
||
const additive3_share<T, 2> & y2, T slope)
|
||
{
|
||
return make_shamir_shares(reconstruct(y0, y1, y2), slope);
|
||
}
|
||
|
||
/// @brief Open two Shamir shares and split the secret as replicated shares.
|
||
/// @details Component `x_0` holds the secret. The other components are zero.
|
||
template <typename T, std::size_t P, std::size_t Q>
|
||
HEDLEY_WARN_UNUSED_RESULT
|
||
auto s2rss(const shamir_share<T, P> & a, const shamir_share<T, Q> & b)
|
||
{
|
||
return make_replicated_shares(reconstruct(a, b));
|
||
}
|
||
|
||
/// @brief Shamir-share a replicated secret with `slope`.
|
||
template <typename T, std::size_t P, std::size_t Q>
|
||
HEDLEY_WARN_UNUSED_RESULT
|
||
auto rss2s(const replicated_share<T, P> & a, const replicated_share<T, Q> & b,
|
||
T slope)
|
||
{
|
||
return make_shamir_shares(reconstruct(a, b), slope);
|
||
}
|
||
|
||
/// @brief Local factor of an RSS product: `x_i y_i + x_i y_{i+1} + x_{i+1} y_i`.
|
||
/// @details The three parties' terms sum to the product. Party `i+1`'s term is
|
||
/// not known here; `rss_mul` on all three shares replicates it.
|
||
template <typename T, std::size_t Party>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr additive3_share<T, Party> rss_mul(
|
||
const replicated_share<T, Party> & x,
|
||
const replicated_share<T, Party> & y) noexcept
|
||
{
|
||
const T term = detail::group_add(
|
||
detail::group_add(detail::group_mul(x.own, y.own),
|
||
detail::group_mul(x.own, y.next)),
|
||
detail::group_mul(x.next, y.own));
|
||
return additive3_share<T, Party>::from_raw(term);
|
||
}
|
||
|
||
/// @brief RSS product once every party's local factor is in hand.
|
||
/// @details Correct, and not randomized: each factor is a function of that
|
||
/// party's input shares. Pass a zero (3,3) sharing to mask it.
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr auto rss_mul(
|
||
const replicated_share<T, 0> & x0, const replicated_share<T, 1> & x1,
|
||
const replicated_share<T, 2> & x2, const replicated_share<T, 0> & y0,
|
||
const replicated_share<T, 1> & y1, const replicated_share<T, 2> & y2) noexcept
|
||
{
|
||
return make_replicated_shares(rss_mul(x0, y0), rss_mul(x1, y1), rss_mul(x2, y2));
|
||
}
|
||
|
||
/// @brief Masked RSS product. `m0 + m1 + m2` must be 0.
|
||
template <typename T>
|
||
HEDLEY_ALWAYS_INLINE
|
||
HEDLEY_PURE
|
||
HEDLEY_NO_THROW
|
||
constexpr auto rss_mul(
|
||
const replicated_share<T, 0> & x0, const replicated_share<T, 1> & x1,
|
||
const replicated_share<T, 2> & x2, const replicated_share<T, 0> & y0,
|
||
const replicated_share<T, 1> & y1, const replicated_share<T, 2> & y2,
|
||
const additive3_share<T, 0> & m0, const additive3_share<T, 1> & m1,
|
||
const additive3_share<T, 2> & m2) noexcept
|
||
{
|
||
return make_replicated_shares(
|
||
additive3_share<T, 0>::from_raw(
|
||
detail::group_add(rss_mul(x0, y0).raw(), m0.raw())),
|
||
additive3_share<T, 1>::from_raw(
|
||
detail::group_add(rss_mul(x1, y1).raw(), m1.raw())),
|
||
additive3_share<T, 2>::from_raw(
|
||
detail::group_add(rss_mul(x2, y2).raw(), m2.raw())));
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Party-tagged DPF key wrapper
|
||
// ---------------------------------------------------------------------------
|
||
|
||
template <typename T>
|
||
struct is_party_key : std::false_type
|
||
{
|
||
};
|
||
|
||
template <std::size_t Party, typename Key>
|
||
struct party_key : Key
|
||
{
|
||
static_assert(Party == 0 || Party == 1, "party_key party must be 0 or 1");
|
||
|
||
static constexpr std::size_t party = Party;
|
||
using key_type = Key;
|
||
|
||
party_key() = default;
|
||
|
||
HEDLEY_ALWAYS_INLINE
|
||
explicit party_key(Key k)
|
||
: Key(std::move(k))
|
||
{
|
||
#ifndef NDEBUG
|
||
assert(static_cast<std::size_t>(
|
||
static_cast<bool>(dpf::get_lo_bit(this->root()))) == Party);
|
||
#endif
|
||
}
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
Key & key() noexcept { return static_cast<Key &>(*this); }
|
||
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
const Key & key() const noexcept { return static_cast<const Key &>(*this); }
|
||
|
||
/// @brief Party-tagged additive share of the comparison absorb addend.
|
||
/// @return Party-tagged additive share of the comparison absorb addend
|
||
HEDLEY_NO_THROW
|
||
HEDLEY_ALWAYS_INLINE
|
||
auto cmp_addend() const noexcept
|
||
{
|
||
return additive_share<std::uint64_t, Party>::from_raw(
|
||
Key::cmp_addend());
|
||
}
|
||
};
|
||
|
||
template <std::size_t Party, typename Key>
|
||
struct is_party_key<party_key<Party, Key>> : std::true_type
|
||
{
|
||
};
|
||
|
||
template <typename T>
|
||
inline constexpr bool is_party_key_v = is_party_key<std::decay_t<T>>::value;
|
||
|
||
template <typename T>
|
||
struct party_of; // incomplete for non-`party_key` (fail loudly on misuse)
|
||
|
||
template <std::size_t Party, typename Key>
|
||
struct party_of<party_key<Party, Key>>
|
||
: std::integral_constant<std::size_t, Party>
|
||
{
|
||
};
|
||
|
||
template <typename T>
|
||
inline constexpr std::size_t party_of_v = party_of<std::decay_t<T>>::value;
|
||
|
||
/// @brief Strip a `party_key` wrapper; bare keys are unchanged. Memoizers and other
|
||
/// tree-layout helpers key on the underlying DPF key type so a memoizer built
|
||
/// for party 0 also accepts party 1.
|
||
/// @tparam T value type
|
||
template <typename T>
|
||
struct unwrap_party_key
|
||
{
|
||
using type = std::decay_t<T>;
|
||
};
|
||
template <std::size_t Party, typename Key>
|
||
struct unwrap_party_key<party_key<Party, Key>>
|
||
{
|
||
using type = Key;
|
||
};
|
||
template <typename T>
|
||
using unwrap_party_key_t = typename unwrap_party_key<std::decay_t<T>>::type;
|
||
|
||
template <std::size_t Party, typename Key>
|
||
HEDLEY_ALWAYS_INLINE
|
||
auto make_party_key(Key && k)
|
||
{
|
||
return party_key<Party, std::decay_t<Key>>(std::forward<Key>(k));
|
||
}
|
||
|
||
template <typename Key0, typename Key1>
|
||
HEDLEY_ALWAYS_INLINE
|
||
auto make_party_key_pair(Key0 && k0, Key1 && k1)
|
||
{
|
||
using K = std::decay_t<Key0>;
|
||
static_assert(std::is_same_v<K, std::decay_t<Key1>>,
|
||
"make_party_key_pair: both keys must have the same type");
|
||
return std::make_pair(
|
||
party_key<0, K>(std::forward<Key0>(k0)),
|
||
party_key<1, K>(std::forward<Key1>(k1)));
|
||
}
|
||
|
||
template <typename CharT, typename Traits, typename T, std::size_t Party,
|
||
sharing Scheme,
|
||
std::enable_if_t<Scheme != sharing::replicated, int> = 0>
|
||
std::basic_ostream<CharT, Traits> & operator<<(
|
||
std::basic_ostream<CharT, Traits> & os,
|
||
const secret_share<T, Party, Scheme> & s)
|
||
{
|
||
return os << s.raw();
|
||
}
|
||
|
||
template <typename CharT, typename Traits, typename T, std::size_t Party>
|
||
std::basic_ostream<CharT, Traits> & operator<<(
|
||
std::basic_ostream<CharT, Traits> & os,
|
||
const replicated_share<T, Party> & s)
|
||
{
|
||
return os << '(' << s.own << ", " << s.next << ')';
|
||
}
|
||
|
||
/// @brief Copy `val` into `slot`.
|
||
/// @details One-word shares copy `raw()`. Replicated shares copy both
|
||
/// components. A plaintext overwrites a one-word share and is not a
|
||
/// replicated share.
|
||
/// @tparam Slot destination slot
|
||
/// @tparam Val source value
|
||
/// @param slot the `slot`
|
||
/// @param val the `val`
|
||
template <typename Slot, typename Val>
|
||
HEDLEY_ALWAYS_INLINE
|
||
constexpr void assign_share_slot(Slot && slot, Val && val)
|
||
{
|
||
using slot_t = std::decay_t<Slot>;
|
||
using val_t = std::decay_t<Val>;
|
||
if constexpr (is_secret_share_v<slot_t>)
|
||
{
|
||
if constexpr (is_secret_share_v<val_t>)
|
||
{
|
||
if constexpr (share_scheme_v<slot_t> == sharing::replicated)
|
||
{
|
||
static_assert(share_scheme_v<val_t> == sharing::replicated,
|
||
"assign_share_slot: replicated slot needs a replicated share");
|
||
static_assert(share_party_v<slot_t> == share_party_v<val_t>,
|
||
"assign_share_slot: replicated parties differ");
|
||
slot = slot_t::from_raw(val.own, val.next);
|
||
}
|
||
else
|
||
{
|
||
static_assert(share_scheme_v<val_t> != sharing::replicated,
|
||
"assign_share_slot: a replicated share has two components");
|
||
slot = slot_t::from_raw(val.raw());
|
||
}
|
||
}
|
||
else
|
||
{
|
||
static_assert(share_scheme_v<slot_t> != sharing::replicated,
|
||
"assign_share_slot: a plaintext is not a replicated share");
|
||
slot = slot_t::from_raw(
|
||
static_cast<typename slot_t::value_type>(val));
|
||
}
|
||
}
|
||
else if constexpr (is_secret_share_v<val_t>)
|
||
{
|
||
static_assert(share_scheme_v<val_t> != sharing::replicated,
|
||
"assign_share_slot: open a replicated share, or copy own and next");
|
||
slot = val.raw();
|
||
}
|
||
else
|
||
slot = std::forward<Val>(val);
|
||
}
|
||
|
||
} // namespace dpf
|
||
|
||
#endif // LIBDPF_INCLUDE_DPF_SECRET_SHARE_HPP__
|