use std::{
iter::Sum,
marker::PhantomData,
mem::MaybeUninit,
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use itertools::{enumerate, izip, Itertools};
use rayon::prelude::IntoParallelIterator;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use subtle::{Choice, ConstantTimeEq};
use typenum::{PartialDiv, Prod, U1, U2, U3};
use wincode::{
io::{Reader, Writer},
ReadResult,
SchemaRead,
SchemaWrite,
WriteResult,
};
use crate::{
algebra::{
elliptic_curve::{BaseField, Curve, Point, ScalarAsExtension, ScalarField},
field::{binary::Gf2_128, mersenne::Mersenne107, FieldElement, SubfieldElement},
ops::transpose::transpose,
},
errors::PrimitiveError,
izip_eq,
random::{CryptoRngCore, Random, RandomWith},
sharing::{
authenticated::{GlobalKey, PairwiseAuthKey, PairwiseAuthOpenShare},
unauthenticated::AdditiveShares,
PlaintextOps,
Reconstructible,
VerifiableWith,
},
types::{
heap_array::{CurvePoints, FieldElements, SubfieldElements},
CollectAll,
ConditionallySelectable,
HeapArray,
PeerIndex,
Positive,
TryFoldAll,
},
utils::IntoExactSizeIterator,
};
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(
bound = "V: Serialize + DeserializeOwned, A: Serialize + DeserializeOwned, B: Serialize + DeserializeOwned"
)]
#[repr(C)]
pub struct PairwiseAuthShare<V, A, B> {
pub(crate) value: V,
pub(crate) macs: Box<[B]>,
pub(crate) keys: Box<[PairwiseAuthKey<A, B>]>,
}
impl<V, A, B> SchemaWrite for PairwiseAuthShare<V, A, B>
where
V: SchemaWrite<Src = V>,
B: SchemaWrite<Src = B>,
PairwiseAuthKey<A, B>: SchemaWrite<Src = PairwiseAuthKey<A, B>>,
{
type Src = Self;
fn size_of(src: &Self) -> WriteResult<usize> {
Ok(V::size_of(&src.value)?
+ <Box<[B]> as SchemaWrite>::size_of(&src.macs)?
+ <Box<[PairwiseAuthKey<A, B>]> as SchemaWrite>::size_of(&src.keys)?)
}
fn write(writer: &mut impl Writer, src: &Self) -> WriteResult<()> {
V::write(writer, &src.value)?;
<Box<[B]> as SchemaWrite>::write(writer, &src.macs)?;
<Box<[PairwiseAuthKey<A, B>]> as SchemaWrite>::write(writer, &src.keys)
}
}
impl<'de, V, A, B> SchemaRead<'de> for PairwiseAuthShare<V, A, B>
where
V: SchemaRead<'de, Dst = V>,
B: SchemaRead<'de, Dst = B>,
PairwiseAuthKey<A, B>: SchemaRead<'de, Dst = PairwiseAuthKey<A, B>>,
{
type Dst = Self;
fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self>) -> ReadResult<()> {
let mut value = MaybeUninit::<V>::uninit();
let mut macs = MaybeUninit::<Box<[B]>>::uninit();
let mut keys = MaybeUninit::<Box<[PairwiseAuthKey<A, B>]>>::uninit();
V::read(reader, &mut value)?;
<Box<[B]> as SchemaRead>::read(reader, &mut macs)?;
<Box<[PairwiseAuthKey<A, B>]> as SchemaRead>::read(reader, &mut keys)?;
let value = unsafe { value.assume_init() };
let macs = unsafe { macs.assume_init() };
let keys = unsafe { keys.assume_init() };
dst.write(PairwiseAuthShare { value, macs, keys });
Ok(())
}
}
impl<V, A, B> PairwiseAuthShare<V, A, B> {
pub fn try_new(
value: V,
macs: Box<[B]>,
keys: Box<[PairwiseAuthKey<A, B>]>,
) -> Result<Self, PrimitiveError> {
if macs.is_empty() {
return Err(PrimitiveError::MinimumLength(2, 0));
}
if macs.len() != keys.len() {
return Err(PrimitiveError::InvalidSize(keys.len(), macs.len()));
}
Ok(Self { value, macs, keys })
}
#[inline]
pub fn get_value(&self) -> &V {
&self.value
}
#[inline]
pub fn get_value_mut(&mut self) -> &mut V {
&mut self.value
}
#[inline]
pub fn get_macs(&self) -> &[B] {
&self.macs
}
#[inline]
pub fn get_mac(&self, peer_index: PeerIndex) -> Option<&B> {
self.macs.get(peer_index)
}
#[inline]
pub fn get_keys(&self) -> &[PairwiseAuthKey<A, B>] {
&self.keys
}
#[inline]
pub fn get_keys_mut(&mut self) -> &mut [PairwiseAuthKey<A, B>] {
&mut self.keys
}
#[inline]
pub fn get_key(&self, peer_index: PeerIndex) -> Option<&PairwiseAuthKey<A, B>> {
self.keys.get(peer_index)
}
#[inline]
pub fn into_value(self) -> V {
self.value
}
#[allow(clippy::type_complexity)]
#[inline]
pub fn into_inner(self) -> (V, Box<[B]>, Box<[PairwiseAuthKey<A, B>]>) {
(self.value, self.macs, self.keys)
}
#[inline]
pub fn n_parties(&self) -> usize {
self.macs.len() + 1
}
#[inline]
pub fn n_distant_parties(&self) -> usize {
self.macs.len()
}
#[inline]
pub fn get_alphas(&self) -> impl ExactSizeIterator<Item = GlobalKey<A>> + '_ {
self.keys.iter().map(|key| key.alpha())
}
#[inline]
pub fn get_betas(&self) -> impl ExactSizeIterator<Item = &B> + '_ {
self.keys.iter().map(|key| key.get_beta())
}
}
pub type BatchedShare<V, A, B, M> = PairwiseAuthShare<HeapArray<V, M>, A, HeapArray<B, M>>;
pub type FieldShare<F> = PairwiseAuthShare<SubfieldElement<F>, FieldElement<F>, FieldElement<F>>;
pub type Mersenne107Share = FieldShare<Mersenne107>;
pub type FieldExtShare<F> = PairwiseAuthShare<FieldElement<F>, FieldElement<F>, FieldElement<F>>;
pub type PointShare<C> = PairwiseAuthShare<Point<C>, ScalarAsExtension<C>, Point<C>>;
pub type FieldShares<F, M> =
PairwiseAuthShare<SubfieldElements<F, M>, FieldElement<F>, FieldElements<F, M>>;
pub type PointShares<C, M> =
PairwiseAuthShare<CurvePoints<C, M>, ScalarAsExtension<C>, CurvePoints<C, M>>;
pub type ScalarShare<C> = FieldShare<ScalarField<C>>;
pub type BaseFieldShare<C> = FieldShare<BaseField<C>>;
pub type BitShare = FieldShare<Gf2_128>;
pub type ScalarShares<C, M> = FieldShares<ScalarField<C>, M>;
pub type BaseFieldShares<C, M> = FieldShares<BaseField<C>, M>;
impl<V, A, B> PairwiseAuthShare<V, A, B> {
pub fn compute_mac(value: V, key: &PairwiseAuthKey<A, B>) -> B
where
A: Clone,
B: for<'b> Add<&'b B, Output = B>,
for<'a> V: Mul<&'a A, Output = B>,
{
value * key.get_alpha() + key.get_beta()
}
pub fn verify_mac(key: &PairwiseAuthKey<A, B>, opening: PairwiseAuthOpenShare<V, B>) -> Choice
where
A: Clone,
B: ConstantTimeEq + SubAssign + for<'b> Add<&'b B, Output = B>,
for<'a> V: Mul<&'a A, Output = B>,
{
let PairwiseAuthOpenShare { value, mac } = opening;
let expected_mac = Self::compute_mac(value, key);
expected_mac.ct_eq(&mac)
}
pub(crate) fn compute_all_pairwise_macs(
all_unauth_shares: &[V],
all_keys: &[Box<[PairwiseAuthKey<A, B>]>],
) -> Vec<Box<[B]>>
where
A: Clone,
V: Clone,
B: for<'b> Add<&'b B, Output = B>,
for<'a> V: Mul<&'a A, Output = B>,
{
let mut all_key_iters = all_keys.iter().map(|k| k.iter()).collect::<Vec<_>>();
enumerate(all_unauth_shares.iter())
.map(|(i, my_unauth_share)| {
enumerate(all_key_iters.iter_mut())
.filter(|(j, _)| *j != i)
.map(|(_, keys_iter)| {
let next_key = keys_iter.next().unwrap();
Self::compute_mac(my_unauth_share.clone(), next_key)
})
.collect()
})
.collect()
}
}
impl<V, A, B> VerifiableWith for PairwiseAuthShare<V, A, B>
where
V: Clone
+ PartialEq
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
+ SchemaWrite<Src = V>
+ for<'de> SchemaRead<'de, Dst = V>,
A: Clone,
B: Clone
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
+ SchemaWrite<Src = B>
+ for<'de> SchemaRead<'de, Dst = B>
+ ConstantTimeEq
+ SubAssign
+ for<'b> Add<&'b B, Output = B>,
for<'a> V: Add<&'a V, Output = V>,
for<'a> V: Mul<&'a A, Output = B>,
{
type VerificationData = ();
#[inline]
fn verify_from_peer_with(
&self,
open_share: PairwiseAuthOpenShare<V, B>,
peer: PeerIndex,
_verification_data: (),
) -> Result<(), PrimitiveError> {
let key = self
.get_key(peer)
.ok_or(PrimitiveError::InvalidPeerIndex(peer, self.keys.len()))?;
if bool::from(PairwiseAuthShare::<V, A, B>::verify_mac(key, open_share)) {
Ok(())
} else {
Err(PrimitiveError::WrongMAC(format!("peer {peer}")).blame(peer))
}
}
#[inline]
fn verify_with(
&self,
open_shares: Vec<PairwiseAuthOpenShare<V, B>>,
_verification_data: (),
) -> Result<(), PrimitiveError> {
enumerate(izip_eq!(open_shares, &self.keys))
.map(|(from_peer, (open_share, key))| {
if bool::from(PairwiseAuthShare::<V, A, B>::verify_mac(key, open_share)) {
Ok(())
} else {
Err(PrimitiveError::WrongMAC(format!("peer {from_peer}")).blame(from_peer))
}
})
.collect_errors()?;
Ok(())
}
}
impl<V, A, B> Reconstructible for PairwiseAuthShare<V, A, B>
where
V: Clone
+ PartialEq
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
+ SchemaWrite<Src = V>
+ for<'de> SchemaRead<'de, Dst = V>,
A: Clone,
B: Clone
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
+ SchemaWrite<Src = B>
+ for<'de> SchemaRead<'de, Dst = B>
+ ConstantTimeEq
+ SubAssign
+ for<'b> Add<&'b B, Output = B>,
for<'a> V: Add<&'a V, Output = V>,
for<'a> V: Mul<&'a A, Output = B>,
{
type Opening = PairwiseAuthOpenShare<V, B>;
type Value = V;
fn open_to(&self, peer: PeerIndex) -> Result<PairwiseAuthOpenShare<V, B>, PrimitiveError> {
let mac = self
.get_mac(peer)
.ok_or(PrimitiveError::InvalidPeerIndex(peer, self.macs.len()))?
.to_owned();
Ok(PairwiseAuthOpenShare::new(self.get_value().to_owned(), mac))
}
fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = PairwiseAuthOpenShare<V, B>> {
self.get_macs()
.iter()
.map(|mac| PairwiseAuthOpenShare::new(self.get_value().to_owned(), mac.to_owned()))
}
fn reconstruct(&self, openings: Vec<PairwiseAuthOpenShare<V, B>>) -> Result<V, PrimitiveError> {
if openings.len() != self.get_keys().len() {
return Err(PrimitiveError::InvalidSize(
self.get_keys().len(),
openings.len(),
));
}
let reconstruct = enumerate(izip_eq!(openings, &self.keys)).try_fold_all(
self.get_value().to_owned(),
|mut reconstructed, (from_peer, (open_share, key))| {
reconstructed = reconstructed + open_share.get_value();
let mac_error = match bool::from(PairwiseAuthShare::<V, A, B>::verify_mac(
key,
open_share.clone(),
)) {
true => None,
false => {
Some(PrimitiveError::WrongMAC(format!("peer {from_peer}")).blame(from_peer))
}
};
(reconstructed, mac_error)
},
)?;
Ok(reconstruct)
}
}
type NParties = usize;
impl<V, A, B> Random for PairwiseAuthShare<V, A, B>
where
V: Random + Clone,
A: Random + Clone,
B: Random + Clone + ConstantTimeEq + SubAssign + for<'b> Add<&'b B, Output = B>,
for<'a> V: Mul<&'a A, Output = B>,
{
fn random(_rng: impl CryptoRngCore) -> Self {
unimplemented!(
"Type {} does not support `random` since it needs to know `n_parties`. Use `random_with(..., n_parties)` instead.",
std::any::type_name::<Self>()
)
}
fn random_n<Container: FromIterator<Self>>(
mut rng: impl CryptoRngCore,
n_parties: usize,
) -> Container {
let all_unauth_shares: Vec<_> = V::random_n(&mut rng, n_parties);
let all_keys = (0..n_parties)
.map(|_| PairwiseAuthKey::<A, B>::random_n(&mut rng, n_parties - 1))
.collect::<Vec<_>>();
let all_macs = Self::compute_all_pairwise_macs(&all_unauth_shares, &all_keys);
izip_eq!(all_unauth_shares, all_macs, all_keys)
.map(|(value, macs, keys)| PairwiseAuthShare { value, macs, keys })
.collect()
}
}
impl<V, A, B> RandomWith<V> for PairwiseAuthShare<V, A, B>
where
V: AdditiveShares,
A: Random + Clone,
B: Random + Clone + ConstantTimeEq + SubAssign + for<'b> Add<&'b B, Output = B>,
for<'a> V: Mul<&'a A, Output = B>,
{
fn random_with(_rng: impl CryptoRngCore, _data: V) -> Self {
unimplemented!(
"Type {} does not support `random_with` since it needs to know `n_parties`. Use `random_n_with` instead.",
std::any::type_name::<Self>()
)
}
fn random_n_with<Container: FromIterator<Self>>(
mut rng: impl CryptoRngCore,
n_parties: usize,
value: V,
) -> Container {
let all_unauth_shares = value.to_additive_shares(n_parties, &mut rng);
let all_keys = (0..n_parties)
.map(|_| PairwiseAuthKey::<A, B>::random_n(&mut rng, n_parties - 1))
.collect::<Vec<_>>();
let all_macs = Self::compute_all_pairwise_macs(&all_unauth_shares, &all_keys);
izip_eq!(all_unauth_shares, all_macs, all_keys)
.map(|(value, macs, keys)| PairwiseAuthShare { value, macs, keys })
.collect()
}
fn random_n_with_each<Container: FromIterator<Self>>(
mut rng: impl CryptoRngCore,
unauth_shares: impl IntoExactSizeIterator<Item = V>,
) -> Container {
let all_unauth_shares = unauth_shares.into_iter().collect::<Vec<_>>();
let n_parties = all_unauth_shares.len();
let all_keys = (0..n_parties)
.map(|_| PairwiseAuthKey::<A, B>::random_n(&mut rng, n_parties - 1))
.collect::<Vec<_>>();
let all_macs = Self::compute_all_pairwise_macs(&all_unauth_shares, &all_keys);
izip_eq!(all_unauth_shares, all_macs, all_keys)
.map(|(value, macs, keys)| PairwiseAuthShare { value, macs, keys })
.collect()
}
}
impl<V, A, B> RandomWith<NParties> for PairwiseAuthShare<V, A, B>
where
V: Random,
A: Random + Clone,
B: Random,
{
fn random_with(mut rng: impl CryptoRngCore, n_parties: NParties) -> Self {
PairwiseAuthShare {
value: V::random(&mut rng),
macs: B::random_n(&mut rng, n_parties - 1),
keys: PairwiseAuthKey::<A, B>::random_n(&mut rng, n_parties - 1),
}
}
}
impl<V, A, B> RandomWith<(NParties, V)> for PairwiseAuthShare<V, A, B>
where
V: Clone,
A: Random + Clone,
B: Random,
{
fn random_with(mut rng: impl CryptoRngCore, (n_parties, value): (NParties, V)) -> Self {
PairwiseAuthShare {
value,
macs: B::random_n(&mut rng, n_parties - 1),
keys: PairwiseAuthKey::<A, B>::random_n(&mut rng, n_parties - 1),
}
}
}
impl<V, A, B> RandomWith<Vec<GlobalKey<A>>> for PairwiseAuthShare<V, A, B>
where
V: Random + Clone,
A: Random + Clone,
B: Random + Clone + ConstantTimeEq + SubAssign + for<'b> Add<&'b B, Output = B>,
for<'a> V: Mul<&'a A, Output = B>,
{
fn random_with(mut rng: impl CryptoRngCore, alphas: Vec<GlobalKey<A>>) -> Self {
let value = V::random(&mut rng);
let keys: Box<[_]> = PairwiseAuthKey::<A, B>::random_n_with_each(&mut rng, alphas);
let macs: Box<[B]> = keys
.iter()
.map(|key| Self::compute_mac(value.clone(), key))
.collect();
PairwiseAuthShare { value, macs, keys }
}
fn random_n_with_each<Container: FromIterator<Self>>(
mut rng: impl CryptoRngCore,
all_alphas: impl IntoExactSizeIterator<Item = Vec<GlobalKey<A>>>,
) -> Container {
let all_alphas = all_alphas.into_iter();
let all_unauth_shares: Vec<_> = V::random_n(&mut rng, all_alphas.len());
let all_keys = all_alphas
.into_iter()
.map(|my_alphas| PairwiseAuthKey::<A, B>::random_n_with_each(&mut rng, my_alphas))
.collect::<Vec<_>>();
let all_macs = Self::compute_all_pairwise_macs(&all_unauth_shares, &all_keys);
izip_eq!(all_unauth_shares, all_macs, all_keys)
.map(|(value, macs, keys)| PairwiseAuthShare { value, macs, keys })
.collect()
}
}
impl<V, A, B> RandomWith<(V, Vec<GlobalKey<A>>)> for PairwiseAuthShare<V, A, B>
where
V: Clone,
A: Random + Clone,
B: Random + Clone + ConstantTimeEq + SubAssign + for<'b> Add<&'b B, Output = B>,
for<'a> V: Mul<&'a A, Output = B>,
{
fn random_with(mut rng: impl CryptoRngCore, (value, alphas): (V, Vec<GlobalKey<A>>)) -> Self {
let keys: Box<[_]> = PairwiseAuthKey::<A, B>::random_n_with_each(&mut rng, alphas);
let macs: Box<[B]> = keys
.iter()
.map(|key| Self::compute_mac(value.clone(), key))
.collect();
PairwiseAuthShare { value, macs, keys }
}
fn random_n_with_each<Container: FromIterator<Self>>(
mut rng: impl CryptoRngCore,
unauth_shares_and_alphas: impl IntoExactSizeIterator<Item = (V, Vec<GlobalKey<A>>)>,
) -> Container {
let (all_unauth_shares, all_keys): (Vec<_>, Vec<_>) = unauth_shares_and_alphas
.into_iter()
.map(|(value, my_alphas)| {
(
value,
PairwiseAuthKey::<A, B>::random_n_with_each(&mut rng, my_alphas),
)
})
.unzip();
let all_macs = Self::compute_all_pairwise_macs(&all_unauth_shares, &all_keys);
izip_eq!(all_unauth_shares, all_macs, all_keys)
.map(|(value, macs, keys)| PairwiseAuthShare { value, macs, keys })
.collect()
}
}
impl<V, A, B> RandomWith<(V, Vec<Vec<GlobalKey<A>>>)> for PairwiseAuthShare<V, A, B>
where
V: AdditiveShares,
A: Random + Clone,
B: Random + Clone + ConstantTimeEq + SubAssign + for<'b> Add<&'b B, Output = B>,
for<'a> V: Mul<&'a A, Output = B>,
{
fn random_with(_rng: impl CryptoRngCore, _: (V, Vec<Vec<GlobalKey<A>>>)) -> Self {
unimplemented!(
"Cannot discern what alpha/global key to use for this peer. Use `random_n_with` instead."
)
}
fn random_n_with<Container: FromIterator<Self>>(
mut rng: impl CryptoRngCore,
n_parties: usize,
(secret_value, all_alphas): (V, Vec<Vec<GlobalKey<A>>>),
) -> Container {
assert_eq!(
all_alphas.len(),
n_parties,
"Number of alphas must match the number of parties"
);
let all_unauth_shares = secret_value.to_additive_shares(all_alphas.len(), &mut rng);
let all_keys = all_alphas
.into_iter()
.map(|my_alphas| PairwiseAuthKey::<A, B>::random_n_with_each(&mut rng, my_alphas))
.collect::<Vec<_>>();
let all_macs = Self::compute_all_pairwise_macs(&all_unauth_shares, &all_keys);
izip_eq!(all_unauth_shares, all_macs, all_keys)
.map(|(value, macs, keys)| PairwiseAuthShare { value, macs, keys })
.collect()
}
}
#[macros::op_variants(owned, borrowed, flipped_commutative)]
impl<'a, V, A, B> Add<&'a PairwiseAuthShare<V, A, B>> for PairwiseAuthShare<V, A, B>
where
for<'v> V: Add<&'v V, Output = V>,
for<'b> B: Add<&'b B, Output = B>,
for<'k> PairwiseAuthKey<A, B>: Add<&'k PairwiseAuthKey<A, B>, Output = PairwiseAuthKey<A, B>>,
{
type Output = PairwiseAuthShare<V, A, B>;
#[inline]
fn add(self, other: &'a PairwiseAuthShare<V, A, B>) -> Self::Output {
PairwiseAuthShare {
value: self.value + &other.value,
macs: izip_eq!(self.macs, &other.macs)
.map(|(mac_i, mac_j)| mac_i + mac_j)
.collect(),
keys: izip_eq!(self.keys, &other.keys)
.map(|(key_i, key_j)| key_i + key_j)
.collect(),
}
}
}
#[macros::op_variants(owned)]
impl<'a, V, A, B> AddAssign<&'a PairwiseAuthShare<V, A, B>> for PairwiseAuthShare<V, A, B>
where
for<'v> V: AddAssign<&'v V>,
for<'b> B: AddAssign<&'b B>,
for<'k> PairwiseAuthKey<A, B>: AddAssign<&'k PairwiseAuthKey<A, B>>,
{
#[inline]
fn add_assign(&mut self, other: &'a PairwiseAuthShare<V, A, B>) {
self.value += &other.value;
izip_eq!(&mut self.macs, &other.macs).for_each(|(mac_i, mac_j)| *mac_i += mac_j);
izip_eq!(&mut self.keys, &other.keys).for_each(|(key_i, key_j)| *key_i += key_j);
}
}
impl<'a, V, A, B> Sum<&'a PairwiseAuthShare<V, A, B>> for PairwiseAuthShare<V, A, B>
where
PairwiseAuthShare<V, A, B>: Clone + Default + AddAssign<&'a PairwiseAuthShare<V, A, B>>,
{
#[inline]
fn sum<I: Iterator<Item = &'a PairwiseAuthShare<V, A, B>>>(mut iter: I) -> Self {
let first = iter.next().cloned().unwrap_or_default();
iter.fold(first, |mut acc, item| {
acc += item;
acc
})
}
}
impl<V, A, B> Sum for PairwiseAuthShare<V, A, B>
where
for<'v> V: AddAssign<&'v V>,
for<'b> B: AddAssign<&'b B>,
for<'k> PairwiseAuthKey<A, B>: AddAssign<&'k PairwiseAuthKey<A, B>>,
PairwiseAuthShare<V, A, B>: Default,
{
#[inline]
fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
let first = iter.next().unwrap_or_default();
iter.fold(first, |mut acc, item| {
acc += &item;
acc
})
}
}
#[macros::op_variants(owned, borrowed, flipped)]
impl<'a, V, A, B> Sub<&'a PairwiseAuthShare<V, A, B>> for PairwiseAuthShare<V, A, B>
where
for<'v> V: Sub<&'v V, Output = V>,
for<'b> B: Sub<&'b B, Output = B>,
for<'k> PairwiseAuthKey<A, B>: Sub<&'k PairwiseAuthKey<A, B>, Output = PairwiseAuthKey<A, B>>,
{
type Output = PairwiseAuthShare<V, A, B>;
#[inline]
fn sub(self, other: &'a PairwiseAuthShare<V, A, B>) -> Self::Output {
PairwiseAuthShare {
value: self.value - &other.value,
macs: izip_eq!(self.macs, &other.macs)
.map(|(mac_i, mac_j)| mac_i - mac_j)
.collect(),
keys: izip_eq!(self.keys, &other.keys)
.map(|(key_i, key_j)| key_i - key_j)
.collect(),
}
}
}
#[macros::op_variants(owned)]
impl<'a, V, A, B> SubAssign<&'a PairwiseAuthShare<V, A, B>> for PairwiseAuthShare<V, A, B>
where
for<'v> V: SubAssign<&'v V>,
for<'b> B: SubAssign<&'b B>,
for<'k> PairwiseAuthKey<A, B>: SubAssign<&'k PairwiseAuthKey<A, B>>,
{
#[inline]
fn sub_assign(&mut self, other: &'a PairwiseAuthShare<V, A, B>) {
self.value -= &other.value;
izip_eq!(&mut self.macs, &other.macs).for_each(|(mac_i, mac_j)| *mac_i -= mac_j);
izip_eq!(&mut self.keys, &other.keys).for_each(|(key_i, key_j)| *key_i -= key_j);
}
}
#[macros::op_variants(borrowed)]
impl<'a, V, V2, A, B, B2, Const> Mul<&'a Const> for PairwiseAuthShare<V, A, B>
where
for<'v> V: Mul<&'v Const, Output = V2>,
for<'b> B: Mul<&'b Const, Output = B2>,
{
type Output = PairwiseAuthShare<V2, A, B2>;
#[inline]
fn mul(self, other: &'a Const) -> Self::Output {
PairwiseAuthShare {
value: self.value * other,
macs: self
.macs
.into_vec()
.into_iter()
.map(|mac| mac * other)
.collect(),
keys: self
.keys
.into_vec()
.into_iter()
.map(|key| key * other)
.collect(),
}
}
}
impl<'a, V, A, B, Const> MulAssign<&'a Const> for PairwiseAuthShare<V, A, B>
where
for<'v> V: MulAssign<&'v Const>,
for<'b> B: MulAssign<&'b Const>,
{
#[inline]
fn mul_assign(&mut self, other: &'a Const) {
self.value *= other;
izip_eq!(&mut self.keys).for_each(|key| *key *= other);
izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
}
}
#[macros::op_variants(borrowed)]
impl<V, A, B> Neg for PairwiseAuthShare<V, A, B>
where
V: Neg<Output = V>,
B: Neg<Output = B>,
PairwiseAuthKey<A, B>: Neg<Output = PairwiseAuthKey<A, B>>,
{
type Output = PairwiseAuthShare<V, A, B>;
#[inline]
fn neg(self) -> Self::Output {
let PairwiseAuthShare { value, macs, keys } = self;
PairwiseAuthShare {
value: -value,
keys: keys.into_vec().into_iter().map(|key| -key).collect(),
macs: macs.into_vec().into_iter().map(|mac| -mac).collect(),
}
}
}
impl<V, A, B> PlaintextOps for PairwiseAuthShare<V, A, B>
where
PairwiseAuthShare<V, A, B>: Reconstructible<Value = V>,
V: Clone + for<'a> AddAssign<&'a V> + for<'a> SubAssign<&'a V>,
A: Clone,
B: Clone + for<'b> AddAssign<&'b B> + for<'b> SubAssign<&'b B> + ConstantTimeEq,
for<'a> V: Mul<&'a A, Output = B>,
{
#[inline]
fn add_plaintext(mut self, ptx: &V, is_first_peer: bool) -> Self {
if is_first_peer {
self.value += ptx;
} else {
let key0 = self.keys.get_mut(0).expect("Missing key 0");
key0.beta -= &(ptx.to_owned() * &key0.alpha);
}
self
}
#[inline]
fn sub_plaintext(mut self, ptx: &V, is_first_peer: bool) -> Self {
if is_first_peer {
self.value -= ptx;
} else {
let key0 = self.keys.get_mut(0).expect("Missing key 0");
key0.beta += &(ptx.to_owned() * &key0.alpha);
}
self
}
}
impl<V, A, B> ConstantTimeEq for PairwiseAuthShare<V, A, B>
where
V: ConstantTimeEq,
B: ConstantTimeEq,
PairwiseAuthKey<A, B>: ConstantTimeEq,
{
#[inline]
fn ct_eq(&self, other: &Self) -> Choice {
self.value.ct_eq(&other.value) & self.macs.ct_eq(&other.macs) & self.keys.ct_eq(&other.keys)
}
}
impl<V, A, B> ConditionallySelectable for PairwiseAuthShare<V, A, B>
where
V: ConditionallySelectable,
B: ConditionallySelectable,
PairwiseAuthKey<A, B>: ConditionallySelectable,
{
#[inline]
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
PairwiseAuthShare {
value: V::conditional_select(&a.value, &b.value, choice),
macs: izip_eq!(&a.macs, &b.macs)
.map(|(a_mac, b_mac)| B::conditional_select(a_mac, b_mac, choice))
.collect(),
keys: izip_eq!(&a.keys, &b.keys)
.map(|(a_key, b_key)| {
PairwiseAuthKey::<A, B>::conditional_select(a_key, b_key, choice)
})
.collect(),
}
}
}
#[derive(Clone, Debug)]
pub struct BatchedSharesIterator<VIter: Iterator, MacIter: Iterator, A, BIter: Iterator> {
remaining: usize,
value: VIter,
macs: Vec<MacIter>,
betas: Vec<BIter>,
alphas: Vec<GlobalKey<A>>,
}
impl<VIter: Iterator, MacIter: Iterator, A: Clone, BIter: Iterator<Item = MacIter::Item>> Iterator
for BatchedSharesIterator<VIter, MacIter, A, BIter>
{
type Item = PairwiseAuthShare<VIter::Item, A, MacIter::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let value = self.value.next()?;
let macs: Box<[_]> = self
.macs
.iter_mut()
.map(|it| it.next())
.collect::<Option<_>>()?;
let keys: Box<[_]> = izip!(&mut self.betas, &self.alphas)
.map(|(beta_iter, alpha)| {
beta_iter
.next()
.map(|beta| PairwiseAuthKey::new(alpha.clone(), beta))
})
.collect::<Option<_>>()?;
self.remaining -= 1;
Some(PairwiseAuthShare { value, macs, keys })
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<VIter: Iterator, MacIter: Iterator, A: Clone, BIter: Iterator<Item = MacIter::Item>>
ExactSizeIterator for BatchedSharesIterator<VIter, MacIter, A, BIter>
{
fn len(&self) -> usize {
self.remaining
}
}
impl<V, A, B> IntoIterator for PairwiseAuthShare<V, A, B>
where
V: IntoIterator,
V::IntoIter: ExactSizeIterator,
B: IntoIterator,
A: Clone,
{
type Item = PairwiseAuthShare<V::Item, A, B::Item>;
type IntoIter = BatchedSharesIterator<V::IntoIter, B::IntoIter, A, B::IntoIter>;
fn into_iter(self) -> Self::IntoIter {
let PairwiseAuthShare { value, macs, keys } = self;
let value_iter = value.into_iter();
let remaining = value_iter.len();
let macs = macs.into_vec().into_iter().map(|m| m.into_iter()).collect();
let (betas, alphas): (Vec<_>, Vec<_>) = keys
.into_vec()
.into_iter()
.map(|k| (k.beta.into_iter(), k.alpha))
.unzip();
BatchedSharesIterator {
remaining,
value: value_iter,
macs,
betas,
alphas,
}
}
}
impl<V, A, B> IntoIterator for &PairwiseAuthShare<V, A, B>
where
V: Clone + IntoIterator,
V::IntoIter: ExactSizeIterator,
B: Clone + IntoIterator,
A: Clone,
{
type Item = PairwiseAuthShare<V::Item, A, B::Item>;
type IntoIter = BatchedSharesIterator<V::IntoIter, B::IntoIter, A, B::IntoIter>;
fn into_iter(self) -> Self::IntoIter {
let value_iter = self.value.clone().into_iter();
let remaining = value_iter.len();
let macs = self.macs.iter().map(|m| m.clone().into_iter()).collect();
let (betas, alphas): (Vec<_>, Vec<_>) = self
.keys
.iter()
.map(|k| (k.beta.clone().into_iter(), k.alpha.clone()))
.unzip();
BatchedSharesIterator {
remaining,
value: value_iter,
macs,
betas,
alphas,
}
}
}
impl<ItemV, A: Clone, ItemB, V, B> FromIterator<PairwiseAuthShare<ItemV, A, ItemB>>
for PairwiseAuthShare<V, A, B>
where
V: FromIterator<ItemV>,
B: FromIterator<ItemB>,
{
fn from_iter<T: IntoIterator<Item = PairwiseAuthShare<ItemV, A, ItemB>>>(iter: T) -> Self {
let (values, macs, keys): (Vec<_>, Vec<Vec<_>>, Vec<Vec<_>>) = iter
.into_iter()
.map(|s| (s.value, s.macs.into_vec(), s.keys.into_vec()))
.multiunzip();
let macs: Box<[B]> = transpose(macs)
.into_iter()
.map(|pm| pm.into_iter().collect::<B>())
.collect::<Vec<_>>()
.into();
let keys: Box<[PairwiseAuthKey<A, B>]> = transpose(keys)
.into_iter()
.map(|peer_keys: Vec<PairwiseAuthKey<A, ItemB>>| {
let alpha = peer_keys[0].get_alpha().to_owned();
let betas: B = peer_keys.into_iter().map(|k| k.beta).collect();
PairwiseAuthKey::new(alpha.into(), betas)
})
.collect::<Vec<_>>()
.into();
PairwiseAuthShare {
value: values.into_iter().collect::<V>(),
macs,
keys,
}
}
}
impl<ItemV, A, ItemB> From<PairwiseAuthShare<ItemV, A, ItemB>>
for BatchedShare<ItemV, A, ItemB, U1>
{
fn from(share: PairwiseAuthShare<ItemV, A, ItemB>) -> Self {
PairwiseAuthShare {
value: HeapArray::from(share.value),
macs: share
.macs
.into_vec()
.into_iter()
.map(HeapArray::from)
.collect(),
keys: share
.keys
.into_vec()
.into_iter()
.map(PairwiseAuthKey::from)
.collect(),
}
}
}
impl<ItemV, A: Clone, ItemB, V, B, N: Positive>
From<HeapArray<PairwiseAuthShare<ItemV, A, ItemB>, N>> for PairwiseAuthShare<V, A, B>
where
V: FromIterator<ItemV>,
B: FromIterator<ItemB>,
{
fn from(shares: HeapArray<PairwiseAuthShare<ItemV, A, ItemB>, N>) -> Self {
shares.into_iter().collect()
}
}
impl<ItemV: Send, A: Clone + Send, ItemB: Send, M: Positive> IntoParallelIterator
for BatchedShare<ItemV, A, ItemB, M>
where
PairwiseAuthShare<ItemV, A, ItemB>: Send,
{
type Item = PairwiseAuthShare<ItemV, A, ItemB>;
type Iter = rayon::vec::IntoIter<Self::Item>;
fn into_par_iter(self) -> Self::Iter {
let PairwiseAuthShare { value, macs, keys } = self;
let value_iter = Vec::from(value).into_iter();
let remaining = value_iter.len();
let mac_iters: Vec<_> = macs
.into_vec()
.into_iter()
.map(|m| Vec::from(m).into_iter())
.collect();
let (betas, alphas): (Vec<_>, Vec<_>) = keys
.into_vec()
.into_iter()
.map(|k| (Vec::from(k.beta).into_iter(), k.alpha))
.unzip();
BatchedSharesIterator {
remaining,
value: value_iter,
macs: mac_iters,
betas,
alphas,
}
.collect::<Vec<_>>()
.into_par_iter()
}
}
impl<V: Copy, A: Clone, B: Copy, M: Positive> BatchedShare<V, A, B, M> {
#[allow(clippy::type_complexity)]
pub fn split<M1, M2>(self) -> (BatchedShare<V, A, B, M1>, BatchedShare<V, A, B, M2>)
where
M1: Positive,
M2: Positive + Add<M1, Output = M>,
{
let PairwiseAuthShare { value, macs, keys } = self;
let (v1, v2) = value.split::<M1, M2>();
let (macs1, macs2): (Vec<_>, Vec<_>) = macs
.into_vec()
.into_iter()
.map(|m| m.split::<M1, M2>())
.unzip();
let (keys1, keys2): (Vec<_>, Vec<_>) = keys
.into_vec()
.into_iter()
.map(|k| k.split::<M1, M2>())
.unzip();
(
PairwiseAuthShare::try_new(v1, macs1.into(), keys1.into()).unwrap(),
PairwiseAuthShare::try_new(v2, macs2.into(), keys2.into()).unwrap(),
)
}
#[allow(clippy::type_complexity)]
pub fn split_halves<MDiv2>(self) -> (BatchedShare<V, A, B, MDiv2>, BatchedShare<V, A, B, MDiv2>)
where
MDiv2: Positive + Mul<U2, Output = M>,
{
let PairwiseAuthShare { value, macs, keys } = self;
let (v1, v2) = value.split_halves::<MDiv2>();
let (macs1, macs2): (Vec<_>, Vec<_>) = macs
.into_vec()
.into_iter()
.map(|m| m.split_halves::<MDiv2>())
.unzip();
let (keys1, keys2): (Vec<_>, Vec<_>) = keys
.into_vec()
.into_iter()
.map(|k| k.split_halves::<MDiv2>())
.unzip();
(
PairwiseAuthShare::try_new(v1, macs1.into(), keys1.into()).unwrap(),
PairwiseAuthShare::try_new(v2, macs2.into(), keys2.into()).unwrap(),
)
}
#[allow(clippy::type_complexity)]
pub fn merge_halves(this: Self, other: Self) -> BatchedShare<V, A, B, Prod<M, U2>>
where
M: Mul<U2, Output: Positive>,
A: PartialEq,
{
let PairwiseAuthShare {
value: v1,
macs: m1,
keys: k1,
} = this;
let PairwiseAuthShare {
value: v2,
macs: m2,
keys: k2,
} = other;
let value = HeapArray::merge_halves(v1, v2);
let macs: Box<[_]> = izip_eq!(m1, m2)
.map(|(a, b)| HeapArray::merge_halves(a, b))
.collect();
let keys: Box<[_]> = izip_eq!(k1, k2)
.map(|(a, b)| PairwiseAuthKey::merge_halves(a, b))
.collect();
PairwiseAuthShare::try_new(value, macs, keys).unwrap()
}
#[allow(clippy::type_complexity)]
pub fn split_thirds<MDiv3>(
self,
) -> (
BatchedShare<V, A, B, MDiv3>,
BatchedShare<V, A, B, MDiv3>,
BatchedShare<V, A, B, MDiv3>,
)
where
MDiv3: Positive + Mul<U3, Output = M>,
{
let PairwiseAuthShare { value, macs, keys } = self;
let (v1, v2, v3) = value.split_thirds::<MDiv3>();
let (macs1, macs2, macs3): (Vec<_>, Vec<_>, Vec<_>) = macs
.into_vec()
.into_iter()
.map(|m| m.split_thirds::<MDiv3>())
.multiunzip();
let (keys1, keys2, keys3): (Vec<_>, Vec<_>, Vec<_>) = keys
.into_vec()
.into_iter()
.map(|k| k.split_thirds::<MDiv3>())
.multiunzip();
(
PairwiseAuthShare::try_new(v1, macs1.into(), keys1.into()).unwrap(),
PairwiseAuthShare::try_new(v2, macs2.into(), keys2.into()).unwrap(),
PairwiseAuthShare::try_new(v3, macs3.into(), keys3.into()).unwrap(),
)
}
#[allow(clippy::type_complexity)]
pub fn merge_thirds(
first: Self,
second: Self,
third: Self,
) -> BatchedShare<V, A, B, Prod<M, U3>>
where
M: Mul<U3, Output: Positive>,
A: PartialEq,
{
let PairwiseAuthShare {
value: v1,
macs: m1,
keys: k1,
} = first;
let PairwiseAuthShare {
value: v2,
macs: m2,
keys: k2,
} = second;
let PairwiseAuthShare {
value: v3,
macs: m3,
keys: k3,
} = third;
let value = HeapArray::merge_thirds(v1, v2, v3);
let macs: Box<[_]> = izip_eq!(m1, m2, m3)
.map(|(a, b, c)| HeapArray::merge_thirds(a, b, c))
.collect();
let keys: Box<[_]> = izip_eq!(k1, k2, k3)
.map(|(a, b, c)| PairwiseAuthKey::merge_thirds(a, b, c))
.collect();
PairwiseAuthShare::try_new(value, macs, keys).unwrap()
}
#[allow(clippy::type_complexity)]
pub fn chunks<CS: Positive>(
&self,
) -> BatchedSharesChunks<
<HeapArray<V, M> as IntoIterator>::IntoIter,
<HeapArray<B, M> as IntoIterator>::IntoIter,
A,
<HeapArray<B, M> as IntoIterator>::IntoIter,
CS,
>
where
M: PartialDiv<CS>,
{
BatchedSharesChunks {
inner: self.into_iter(),
remaining_chunks: M::USIZE / CS::USIZE,
_ds: PhantomData,
}
}
pub fn swap(&mut self, i: usize, j: usize) {
self.value.swap(i, j);
for mac in self.macs.iter_mut() {
mac.swap(i, j);
}
for key in self.keys.iter_mut() {
key.beta.swap(i, j);
}
}
}
pub struct BatchedSharesChunks<VIter: Iterator, MacIter: Iterator, A, BIter: Iterator, DS: Positive>
{
inner: BatchedSharesIterator<VIter, MacIter, A, BIter>,
remaining_chunks: usize,
_ds: PhantomData<DS>,
}
impl<VIter: Iterator, MacIter: Iterator, A: Clone, BIter: Iterator, DS: Positive>
BatchedSharesChunks<VIter, MacIter, A, BIter, DS>
{
pub fn len(&self) -> usize {
self.remaining_chunks
}
pub fn is_empty(&self) -> bool {
self.remaining_chunks == 0
}
}
impl<
VIter: Iterator,
MacIter: Iterator,
A: Clone,
BIter: Iterator<Item = MacIter::Item>,
DS: Positive,
> Iterator for BatchedSharesChunks<VIter, MacIter, A, BIter, DS>
where
HeapArray<VIter::Item, DS>: FromIterator<VIter::Item>,
HeapArray<MacIter::Item, DS>: FromIterator<MacIter::Item>,
{
type Item = BatchedShare<VIter::Item, A, MacIter::Item, DS>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining_chunks == 0 {
return None;
}
let chunk: Vec<_> = self.inner.by_ref().take(DS::to_usize()).collect();
if chunk.is_empty() {
return None;
}
self.remaining_chunks -= 1;
Some(chunk.into_iter().collect())
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining_chunks, Some(self.remaining_chunks))
}
}
impl<
VIter: Iterator,
MacIter: Iterator,
A: Clone,
BIter: Iterator<Item = MacIter::Item>,
DS: Positive,
> ExactSizeIterator for BatchedSharesChunks<VIter, MacIter, A, BIter, DS>
where
HeapArray<VIter::Item, DS>: FromIterator<VIter::Item>,
HeapArray<MacIter::Item, DS>: FromIterator<MacIter::Item>,
{
fn len(&self) -> usize {
self.remaining_chunks
}
}
impl<V, A, B, N: Positive> Reconstructible for HeapArray<PairwiseAuthShare<V, A, B>, N>
where
PairwiseAuthShare<V, A, B>: Reconstructible,
<PairwiseAuthShare<V, A, B> as Reconstructible>::Opening: Clone,
{
type Opening = HeapArray<<PairwiseAuthShare<V, A, B> as Reconstructible>::Opening, N>;
type Value = HeapArray<<PairwiseAuthShare<V, A, B> as Reconstructible>::Value, N>;
fn open_to(&self, for_peer: PeerIndex) -> Result<Self::Opening, PrimitiveError> {
self.into_iter()
.map(|s| s.open_to(for_peer))
.collect::<Result<_, _>>()
}
fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening> {
let per_share: Vec<Vec<<PairwiseAuthShare<V, A, B> as Reconstructible>::Opening>> = self
.into_iter()
.map(|s| s.open_to_all_others().collect())
.collect();
transpose(per_share)
.into_iter()
.map(|col| col.try_into().expect("size mismatch in open_to_all_others"))
}
fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError> {
self.iter()
.enumerate()
.map(|(i, share)| {
let my_openings: Vec<_> = openings
.iter()
.map(|o| o.get(i).cloned())
.collect::<Option<_>>()
.ok_or_else(|| {
PrimitiveError::InvalidParameters(
"Opening is missing for some share.".to_string(),
)
})?;
share.reconstruct(my_openings)
})
.collect::<Result<_, _>>()
}
}
impl<C: Curve> From<ScalarShare<C>> for PointShare<C> {
#[inline]
fn from(scalar_share: ScalarShare<C>) -> Self {
scalar_share * &Point::<C>::generator()
}
}
impl<C: Curve, M: Positive> From<ScalarShares<C, M>> for PointShares<C, M> {
#[inline]
fn from(scalar_shares: ScalarShares<C, M>) -> Self {
scalar_shares * &Point::<C>::generator()
}
}
#[cfg(test)]
mod tests {
use std::{fmt::Debug, ops::Div};
use typenum::{U2, U3};
use super::*;
use crate::{random::test_rng, sharing::Verifiable};
pub(super) trait ShareValue<A, B, Const>:
Clone
+ PartialEq
+ Debug
+ Random
+ AdditiveShares
+ ConstantTimeEq
+ ConditionallySelectable
+ Neg<Output = Self>
+ for<'a> Sub<&'a Self, Output = Self>
+ for<'a> AddAssign<&'a Self>
+ for<'a> Mul<&'a A, Output = B>
+ for<'a> Mul<&'a Const, Output = Self>
+ for<'a> MulAssign<&'a Const>
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
+ SchemaWrite<Src = Self>
+ for<'de> SchemaRead<'de, Dst = Self>
{
}
impl<V, A, B, Const> ShareValue<A, B, Const> for V where
V: Clone
+ PartialEq
+ Debug
+ Random
+ AdditiveShares
+ ConstantTimeEq
+ ConditionallySelectable
+ Neg<Output = V>
+ for<'a> Sub<&'a V, Output = V>
+ for<'a> AddAssign<&'a V>
+ for<'a> Mul<&'a A, Output = B>
+ for<'a> Mul<&'a Const, Output = V>
+ for<'a> MulAssign<&'a Const>
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
+ SchemaWrite<Src = V>
+ for<'de> SchemaRead<'de, Dst = V>
{
}
pub(super) trait ShareKey:
Clone + PartialEq + Debug + Random + ConstantTimeEq + ConditionallySelectable
{
}
impl<A> ShareKey for A where
A: Clone + PartialEq + Debug + Random + ConstantTimeEq + ConditionallySelectable
{
}
pub(super) trait ShareMac<V, A, Const>:
Clone
+ PartialEq
+ Debug
+ Random
+ ConstantTimeEq
+ ConditionallySelectable
+ SubAssign
+ Neg<Output = Self>
+ for<'b> Add<&'b Self, Output = Self>
+ for<'b> AddAssign<&'b Self>
+ for<'b> Sub<&'b Self, Output = Self>
+ for<'b> SubAssign<&'b Self>
+ for<'c> Mul<&'c Const, Output = Self>
+ for<'c> MulAssign<&'c Const>
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
+ SchemaWrite<Src = Self>
+ for<'de> SchemaRead<'de, Dst = Self>
{
}
impl<B, V, A, Const> ShareMac<V, A, Const> for B where
B: Clone
+ PartialEq
+ Debug
+ Random
+ ConstantTimeEq
+ ConditionallySelectable
+ SubAssign
+ Neg<Output = B>
+ for<'b> Add<&'b B, Output = B>
+ for<'b> AddAssign<&'b B>
+ for<'b> Sub<&'b B, Output = B>
+ for<'b> SubAssign<&'b B>
+ for<'c> Mul<&'c Const, Output = B>
+ for<'c> MulAssign<&'c Const>
+ Send
+ Sync
+ 'static
+ Serialize
+ DeserializeOwned
+ SchemaWrite<Src = B>
+ for<'de> SchemaRead<'de, Dst = B>
{
}
pub(super) trait BatchedShareItem<A, IB>:
Copy
+ Clone
+ PartialEq
+ Debug
+ Random
+ ConstantTimeEq
+ ConditionallySelectable
+ for<'a> Mul<&'a A, Output = IB>
{
}
impl<IV, A, IB> BatchedShareItem<A, IB> for IV where
IV: Copy
+ Clone
+ PartialEq
+ Debug
+ Random
+ ConstantTimeEq
+ ConditionallySelectable
+ for<'a> Mul<&'a A, Output = IB>
{
}
pub(super) trait BatchedShareMacItem<IV, A>:
Copy + Clone + PartialEq + Debug + Random + ConstantTimeEq + ConditionallySelectable
{
}
impl<IB, IV, A> BatchedShareMacItem<IV, A> for IB where
IB: Copy + Clone + PartialEq + Debug + Random + ConstantTimeEq + ConditionallySelectable
{
}
pub(super) fn test_open_to<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let share = PairwiseAuthShare::<V, A, B>::random_with(&mut rng, n_parties);
for i in 0..n_parties - 1 {
let open = share.open_to(i).unwrap();
assert_eq!(open.get_value(), &share.value);
assert_eq!(open.get_mac(), &share.macs[i]);
}
}
pub(super) fn test_random<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let share = PairwiseAuthShare::<V, A, B>::random_with(&mut rng, n_parties);
assert_eq!(share.get_macs().len(), n_parties - 1);
assert_eq!(share.get_keys().len(), n_parties - 1);
let value = V::random(&mut rng);
let share_with_value =
PairwiseAuthShare::<V, A, B>::random_with(&mut rng, (n_parties, value.clone()));
assert_eq!(share_with_value.get_value(), &value);
assert_eq!(share_with_value.get_macs().len(), n_parties - 1);
assert_eq!(share_with_value.get_keys().len(), n_parties - 1);
}
pub(super) fn test_random_vec_and_reconstruct<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let shares: Vec<_> = PairwiseAuthShare::<V, A, B>::random_n(&mut rng, n_parties);
assert_eq!(shares.len(), n_parties);
for share in &shares {
assert_eq!(share.get_macs().len(), n_parties - 1);
assert_eq!(share.get_keys().len(), n_parties - 1);
}
let unauth: Vec<_> = shares.iter().map(|s| s.get_value().clone()).collect();
let expected = V::from_additive_shares(&unauth);
let reconstructed = PairwiseAuthShare::<V, A, B>::reconstruct_all(shares).unwrap();
assert_eq!(reconstructed, expected);
let value = V::random(&mut rng);
let shares: Vec<_> =
PairwiseAuthShare::<V, A, B>::random_n_with(&mut rng, n_parties, value.clone());
let reconstructed = PairwiseAuthShare::<V, A, B>::reconstruct_all(shares).unwrap();
assert_eq!(reconstructed, value);
}
pub(super) fn test_random_vec_with_global_key_and_reconstruct<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let alphas: Vec<Vec<GlobalKey<A>>> = (0..n_parties)
.map(|_| GlobalKey::<A>::random_n::<Vec<_>>(&mut rng, n_parties - 1))
.collect();
let shares_from_alphas: Vec<_> =
PairwiseAuthShare::<V, A, B>::random_n_with_each(&mut rng, alphas.clone());
assert_eq!(shares_from_alphas.len(), n_parties);
for (share, my_alphas) in izip_eq!(&shares_from_alphas, &alphas) {
assert_eq!(share.get_macs().len(), n_parties - 1);
assert_eq!(share.get_keys().len(), n_parties - 1);
assert_eq!(share.get_alphas().collect::<Vec<_>>(), *my_alphas);
}
let _ = PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_from_alphas).unwrap();
let value = V::random(&mut rng);
let alphas: Vec<Vec<GlobalKey<A>>> = (0..n_parties)
.map(|_| GlobalKey::<A>::random_n::<Vec<_>>(&mut rng, n_parties - 1))
.collect();
let shares_from_value_and_alphas: Vec<_> = PairwiseAuthShare::<V, A, B>::random_n_with(
&mut rng,
n_parties,
(value.clone(), alphas.clone()),
);
assert_eq!(shares_from_value_and_alphas.len(), n_parties);
for (share, my_alphas) in izip_eq!(&shares_from_value_and_alphas, &alphas) {
assert_eq!(share.get_macs().len(), n_parties - 1);
assert_eq!(share.get_keys().len(), n_parties - 1);
assert_eq!(share.get_alphas().collect::<Vec<_>>(), *my_alphas);
}
let reconstructed =
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_from_value_and_alphas).unwrap();
assert_eq!(reconstructed, value);
let value = V::random(&mut rng);
let unauth = value.to_additive_shares(n_parties, &mut rng);
let alphas: Vec<Vec<GlobalKey<A>>> = (0..n_parties)
.map(|_| GlobalKey::<A>::random_n::<Vec<_>>(&mut rng, n_parties - 1))
.collect();
let shares_from_unauth: Vec<_> = PairwiseAuthShare::<V, A, B>::random_n_with_each(
&mut rng,
izip_eq!(unauth, alphas.clone()),
);
assert_eq!(shares_from_unauth.len(), n_parties);
for (share, my_alphas) in izip_eq!(&shares_from_unauth, &alphas) {
assert_eq!(share.get_macs().len(), n_parties - 1);
assert_eq!(share.get_keys().len(), n_parties - 1);
assert_eq!(share.get_alphas().collect::<Vec<_>>(), *my_alphas);
}
let reconstructed =
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_from_unauth).unwrap();
assert_eq!(reconstructed, value);
}
pub(super) fn test_verify_mac<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let shares: Vec<_> = PairwiseAuthShare::<V, A, B>::random_n(&mut rng, n_parties);
for i in 0..shares.len() {
for j in 0..shares.len() {
if i == j {
continue;
}
let open = shares[j].open_to(i - (i > j) as usize).unwrap();
shares[i].verify_from(open, j - (j > i) as usize).unwrap();
}
}
PairwiseAuthShare::<V, A, B>::verify_all(shares).unwrap();
}
pub(super) fn test_add<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let alphas: Vec<Vec<GlobalKey<A>>> = (0..n_parties)
.map(|_| GlobalKey::<A>::random_n::<Vec<_>>(&mut rng, n_parties - 1))
.collect();
let a = V::random(&mut rng);
let b = V::random(&mut rng);
let shares_a: Vec<_> = PairwiseAuthShare::<V, A, B>::random_n_with(
&mut rng,
n_parties,
(a.clone(), alphas.clone()),
);
let shares_b: Vec<_> =
PairwiseAuthShare::<V, A, B>::random_n_with(&mut rng, n_parties, (b.clone(), alphas));
let expected = a.clone() + &b;
let sum: Vec<_> = izip_eq!(&shares_a, &shares_b)
.map(|(sa, sb)| sa + sb)
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(sum).unwrap(),
expected
);
let sum: Vec<_> = izip_eq!(&shares_a, shares_b.clone())
.map(|(sa, sb)| sa + sb)
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(sum).unwrap(),
expected
);
let sum: Vec<_> = izip_eq!(shares_a.clone(), &shares_b)
.map(|(sa, sb)| sa + sb)
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(sum).unwrap(),
expected
);
let sum: Vec<_> = izip_eq!(shares_a.clone(), shares_b.clone())
.map(|(sa, sb)| sa + sb)
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(sum).unwrap(),
expected
);
let mut shares_a_mut = shares_a.clone();
izip_eq!(&mut shares_a_mut, &shares_b).for_each(|(sa, sb)| *sa += sb);
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_a_mut).unwrap(),
expected
);
let mut shares_a_mut = shares_a;
izip_eq!(&mut shares_a_mut, shares_b).for_each(|(sa, sb)| *sa += sb);
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_a_mut).unwrap(),
expected
);
}
pub(super) fn test_add_plaintext<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let a = V::random(&mut rng);
let k = V::random(&mut rng);
let shares_a: Vec<_> =
PairwiseAuthShare::<V, A, B>::random_n_with(&mut rng, n_parties, a.clone());
let shares_plus_k_ref: Vec<_> = shares_a
.iter()
.enumerate()
.map(|(i, share_a)| share_a.to_owned().add_plaintext(&k, i == 0))
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_plus_k_ref).unwrap(),
a.clone() + &k,
);
let shares_plus_k: Vec<_> = shares_a
.into_iter()
.enumerate()
.map(|(i, share_a)| share_a.to_owned().add_plaintext(&k, i == 0))
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_plus_k).unwrap(),
a + &k,
);
}
pub(super) fn test_mul_constant<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random + PartialEq + Debug,
{
let mut rng = test_rng();
let a = V::random(&mut rng);
let k = Const::random(&mut rng);
let shares_a: Vec<_> =
PairwiseAuthShare::<V, A, B>::random_n_with(&mut rng, n_parties, a.clone());
let shares_a_times_k: Vec<_> = izip_eq!(shares_a.clone()).map(|sa| sa * &k).collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_a_times_k).unwrap(),
a.clone() * &k,
);
let mut shares_a_mut = shares_a;
izip_eq!(&mut shares_a_mut).for_each(|sa| *sa *= &k);
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_a_mut).unwrap(),
a * &k,
);
}
pub(super) fn test_sub<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let alphas: Vec<Vec<GlobalKey<A>>> = (0..n_parties)
.map(|_| GlobalKey::<A>::random_n::<Vec<_>>(&mut rng, n_parties - 1))
.collect();
let a = V::random(&mut rng);
let b = V::random(&mut rng);
let shares_a: Vec<_> = PairwiseAuthShare::<V, A, B>::random_n_with(
&mut rng,
n_parties,
(a.clone(), alphas.clone()),
);
let shares_b: Vec<_> =
PairwiseAuthShare::<V, A, B>::random_n_with(&mut rng, n_parties, (b.clone(), alphas));
let expected = a.clone() - &b;
let diff: Vec<_> = izip_eq!(&shares_a, &shares_b)
.map(|(sa, sb)| sa - sb)
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(diff).unwrap(),
expected
);
let diff: Vec<_> = izip_eq!(&shares_a, shares_b.clone())
.map(|(sa, sb)| sa - sb)
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(diff).unwrap(),
expected
);
let diff: Vec<_> = izip_eq!(shares_a.clone(), &shares_b)
.map(|(sa, sb)| sa - sb)
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(diff).unwrap(),
expected
);
let diff: Vec<_> = izip_eq!(shares_a.clone(), shares_b.clone())
.map(|(sa, sb)| sa - sb)
.collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(diff).unwrap(),
expected
);
let mut shares_a_mut = shares_a.clone();
izip_eq!(&mut shares_a_mut, &shares_b).for_each(|(sa, sb)| *sa -= sb);
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_a_mut).unwrap(),
expected
);
let mut shares_a_mut = shares_a;
izip_eq!(&mut shares_a_mut, shares_b).for_each(|(sa, sb)| *sa -= sb);
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(shares_a_mut).unwrap(),
expected
);
}
pub(super) fn test_neg<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let a = V::random(&mut rng);
let shares_a: Vec<_> =
PairwiseAuthShare::<V, A, B>::random_n_with(&mut rng, n_parties, a.clone());
let neg_ref: Vec<_> = shares_a.iter().map(|sa| -sa).collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(neg_ref).unwrap(),
-a.clone(),
);
let neg: Vec<_> = shares_a.into_iter().map(|sa| -sa).collect();
assert_eq!(
PairwiseAuthShare::<V, A, B>::reconstruct_all(neg).unwrap(),
-a,
);
}
pub(super) fn test_conditional_select<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let shares_a = PairwiseAuthShare::<V, A, B>::random_with(&mut rng, n_parties);
let shares_b = PairwiseAuthShare::<V, A, B>::random_with(&mut rng, n_parties);
let selected = PairwiseAuthShare::<V, A, B>::conditional_select(
&shares_a,
&shares_b,
Choice::from(0u8),
);
assert_eq!(selected, shares_a);
let selected = PairwiseAuthShare::<V, A, B>::conditional_select(
&shares_a,
&shares_b,
Choice::from(1u8),
);
assert_eq!(selected, shares_b);
}
pub(super) fn test_ct_eq<V, A, B, Const>(n_parties: usize)
where
V: ShareValue<A, B, Const>,
A: ShareKey,
B: ShareMac<V, A, Const>,
Const: Random,
{
let mut rng = test_rng();
let shares_a = PairwiseAuthShare::<V, A, B>::random_with(&mut rng, n_parties);
let shares_b = PairwiseAuthShare::<V, A, B>::random_with(&mut rng, n_parties);
assert!(Into::<bool>::into(shares_a.ct_eq(&shares_a.clone())));
assert!(Into::<bool>::into(shares_b.ct_eq(&shares_b.clone())));
assert!(!Into::<bool>::into(shares_a.ct_eq(&shares_b)));
assert!(!Into::<bool>::into(shares_b.ct_eq(&shares_a)));
}
pub(super) fn test_split_halves<IV, A, IB, M, MDiv2>(n_parties: usize)
where
IV: BatchedShareItem<A, IB>,
A: ShareKey,
IB: BatchedShareMacItem<IV, A>,
M: Positive + Div<U2, Output = MDiv2>,
MDiv2: Positive + Mul<U2, Output = M>,
{
let mut rng = test_rng();
let m_div2 = MDiv2::to_usize();
let shares = BatchedShare::<IV, A, IB, M>::random_with(&mut rng, n_parties);
let (shares1, shares2) = shares.clone().split_halves::<MDiv2>();
assert_eq!(shares1.get_value().len(), m_div2);
assert_eq!(shares2.get_value().len(), m_div2);
assert_eq!(shares1.get_value().as_ref(), &shares.get_value()[..m_div2]);
assert_eq!(shares2.get_value().as_ref(), &shares.get_value()[m_div2..]);
izip_eq!(&shares1.macs, &shares2.macs, &shares.macs).for_each(|(mac1, mac2, mac)| {
assert_eq!(mac1.as_ref(), &mac[..m_div2]);
assert_eq!(mac2.as_ref(), &mac[m_div2..]);
});
izip_eq!(&shares1.keys, &shares2.keys, &shares.keys).for_each(|(key1, key2, key)| {
assert_eq!(key1.alpha, key.alpha);
assert_eq!(key2.alpha, key.alpha);
assert_eq!(key1.beta.as_ref(), &key.beta[..m_div2]);
assert_eq!(key2.beta.as_ref(), &key.beta[m_div2..]);
});
let merged = BatchedShare::<IV, A, IB, MDiv2>::merge_halves(shares1, shares2);
assert_eq!(merged, shares);
}
pub(super) fn test_split_thirds<IV, A, IB, M, MDiv3>(n_parties: usize)
where
IV: BatchedShareItem<A, IB>,
A: ShareKey,
IB: BatchedShareMacItem<IV, A>,
M: Positive,
MDiv3: Positive + Mul<U3, Output = M>,
M: Mul<U3, Output: Positive>,
{
let mut rng = test_rng();
let m_div3 = MDiv3::to_usize();
let shares = BatchedShare::<IV, A, IB, M>::random_with(&mut rng, n_parties);
let (shares1, shares2, shares3) = shares.clone().split_thirds::<MDiv3>();
assert_eq!(shares1.get_value().len(), m_div3);
assert_eq!(shares2.get_value().len(), m_div3);
assert_eq!(shares3.get_value().len(), m_div3);
assert_eq!(shares1.get_value().as_ref(), &shares.get_value()[..m_div3]);
assert_eq!(
shares2.get_value().as_ref(),
&shares.get_value()[m_div3..(2 * m_div3)]
);
assert_eq!(
shares3.get_value().as_ref(),
&shares.get_value()[(2 * m_div3)..]
);
izip_eq!(&shares1.macs, &shares2.macs, &shares3.macs, &shares.macs).for_each(
|(mac1, mac2, mac3, mac)| {
assert_eq!(mac1.as_ref(), &mac[..m_div3]);
assert_eq!(mac2.as_ref(), &mac[m_div3..(2 * m_div3)]);
assert_eq!(mac3.as_ref(), &mac[(2 * m_div3)..(3 * m_div3)]);
},
);
izip_eq!(&shares1.keys, &shares2.keys, &shares3.keys, &shares.keys).for_each(
|(key1, key2, key3, key)| {
assert_eq!(key1.alpha, key.alpha);
assert_eq!(key2.alpha, key.alpha);
assert_eq!(key3.alpha, key.alpha);
assert_eq!(key1.beta.as_ref(), &key.beta[..m_div3]);
assert_eq!(key2.beta.as_ref(), &key.beta[m_div3..(2 * m_div3)]);
assert_eq!(key3.beta.as_ref(), &key.beta[(2 * m_div3)..(3 * m_div3)]);
},
);
let merged = BatchedShare::<IV, A, IB, MDiv3>::merge_thirds(shares1, shares2, shares3);
assert_eq!(merged, shares);
}
pub(super) fn test_into_iter<IV, A, IB, M>(n_parties: usize)
where
IV: BatchedShareItem<A, IB>,
A: ShareKey,
IB: BatchedShareMacItem<IV, A>,
M: Positive,
{
let mut rng = test_rng();
let m = M::to_usize();
let shares = BatchedShare::<IV, A, IB, M>::random_with(&mut rng, n_parties);
let mut iter = shares.clone().into_iter();
assert_eq!(iter.len(), m);
for i in 0..m {
assert_eq!(iter.len(), m - i);
let share = iter.next().unwrap();
assert_eq!(share.value, shares.get_value()[i]);
for j in 0..n_parties - 1 {
assert_eq!(share.macs[j], shares.macs[j][i]);
assert_eq!(share.keys[j].alpha, shares.keys[j].alpha);
assert_eq!(share.keys[j].beta, shares.keys[j].beta[i]);
}
}
}
pub(super) fn test_from_iterator<IV, A, IB, M>(n_parties: usize)
where
IV: BatchedShareItem<A, IB>,
A: ShareKey,
IB: BatchedShareMacItem<IV, A>,
M: Positive,
{
let mut rng = test_rng();
let shares = BatchedShare::<IV, A, IB, M>::random_with(&mut rng, n_parties);
let collected: Vec<_> = shares.clone().into_iter().collect();
let from_iterator: BatchedShare<IV, A, IB, M> = collected.into_iter().collect();
assert_eq!(shares, from_iterator);
}
pub(super) fn test_from_iterator_unequal_sizes<IV, A, IB, M>(n_parties: usize)
where
IV: BatchedShareItem<A, IB>,
A: ShareKey,
IB: BatchedShareMacItem<IV, A>,
M: Positive,
BatchedShare<IV, A, IB, M>: RandomWith<usize>,
{
let mut rng = test_rng();
let shares = BatchedShare::<IV, A, IB, M>::random_with(&mut rng, n_parties);
let mut collected: Vec<_> = shares.into_iter().collect();
collected.pop();
let _: BatchedShare<IV, A, IB, M> = collected.into_iter().collect();
}
pub(super) fn test_chunks<IV, A, IB, M, CS>(n_parties: usize)
where
IV: BatchedShareItem<A, IB>,
A: ShareKey,
IB: BatchedShareMacItem<IV, A>,
M: Positive + typenum::PartialDiv<CS>,
CS: Positive,
BatchedShare<IV, A, IB, M>: RandomWith<usize> + Clone + Debug,
{
let mut rng = test_rng();
let m = M::to_usize();
let chunk_size = CS::to_usize();
let n_chunks = m / chunk_size;
let shares = BatchedShare::<IV, A, IB, M>::random_with(&mut rng, n_parties);
let mut chunks_iter = shares.chunks::<CS>();
assert_eq!(chunks_iter.len(), n_chunks);
for i in 0..n_chunks {
assert_eq!(chunks_iter.len(), n_chunks - i);
let chunk = chunks_iter.next().unwrap();
assert_eq!(chunk.value.len(), chunk_size);
for j in 0..chunk_size {
assert_eq!(chunk.value[j], shares.get_value()[i * chunk_size + j]);
}
for (mac_chunk, macs) in izip_eq!(&chunk.macs, &shares.macs) {
for j in 0..chunk_size {
assert_eq!(mac_chunk[j], macs[i * chunk_size + j]);
}
}
for (key_chunk, keys) in izip_eq!(&chunk.keys, &shares.keys) {
assert_eq!(key_chunk.alpha, keys.alpha);
for j in 0..chunk_size {
assert_eq!(key_chunk.beta[j], keys.beta[i * chunk_size + j]);
}
}
}
assert!(chunks_iter.next().is_none());
}
mod field_share_tests {
use crate::algebra::{
elliptic_curve::{Curve25519Ristretto as C, ScalarAsExtension, ScalarField},
field::SubfieldElement,
};
type V = SubfieldElement<ScalarField<C>>;
type A = ScalarAsExtension<C>; type B = ScalarAsExtension<C>;
type Const = SubfieldElement<ScalarField<C>>;
const N: usize = 3;
#[test]
fn test_open_to() {
super::test_open_to::<V, A, B, Const>(N);
}
#[test]
fn test_random() {
super::test_random::<V, A, B, Const>(N);
}
#[test]
fn test_random_vec_and_reconstruct() {
super::test_random_vec_and_reconstruct::<V, A, B, Const>(N);
}
#[test]
fn test_random_vec_with_global_key_and_reconstruct() {
super::test_random_vec_with_global_key_and_reconstruct::<V, A, B, Const>(N);
}
#[test]
fn test_verify_mac() {
super::test_verify_mac::<V, A, B, Const>(N);
}
#[test]
fn test_add() {
super::test_add::<V, A, B, Const>(N);
}
#[test]
fn test_add_plaintext() {
super::test_add_plaintext::<V, A, B, Const>(N);
}
#[test]
fn test_mul_constant() {
super::test_mul_constant::<V, A, B, Const>(N);
}
#[test]
fn test_sub() {
super::test_sub::<V, A, B, Const>(N);
}
#[test]
fn test_neg() {
super::test_neg::<V, A, B, Const>(N);
}
#[test]
fn test_conditional_select() {
super::test_conditional_select::<V, A, B, Const>(N);
}
#[test]
fn test_ct_eq() {
super::test_ct_eq::<V, A, B, Const>(N);
}
}
mod point_share_tests {
use crate::algebra::{
elliptic_curve::{Curve25519Ristretto as C, Point, ScalarAsExtension, ScalarField},
field::SubfieldElement,
};
type V = Point<C>;
type A = ScalarAsExtension<C>;
type B = Point<C>;
type Const = SubfieldElement<ScalarField<C>>; const N: usize = 3;
#[test]
fn test_open_to() {
super::test_open_to::<V, A, B, Const>(N);
}
#[test]
fn test_random() {
super::test_random::<V, A, B, Const>(N);
}
#[test]
fn test_random_vec_and_reconstruct() {
super::test_random_vec_and_reconstruct::<V, A, B, Const>(N);
}
#[test]
fn test_random_vec_with_global_key_and_reconstruct() {
super::test_random_vec_with_global_key_and_reconstruct::<V, A, B, Const>(N);
}
#[test]
fn test_verify_mac() {
super::test_verify_mac::<V, A, B, Const>(N);
}
#[test]
fn test_add() {
super::test_add::<V, A, B, Const>(N);
}
#[test]
fn test_add_plaintext() {
super::test_add_plaintext::<V, A, B, Const>(N);
}
#[test]
fn test_mul_constant() {
super::test_mul_constant::<V, A, B, Const>(N);
}
#[test]
fn test_sub() {
super::test_sub::<V, A, B, Const>(N);
}
#[test]
fn test_neg() {
super::test_neg::<V, A, B, Const>(N);
}
#[test]
fn test_conditional_select() {
super::test_conditional_select::<V, A, B, Const>(N);
}
#[test]
fn test_ct_eq() {
super::test_ct_eq::<V, A, B, Const>(N);
}
}
mod field_shares_tests {
use std::ops::Div;
use typenum::{U12, U2, U3, U4};
use crate::{
algebra::{
elliptic_curve::{Curve25519Ristretto as C, ScalarAsExtension, ScalarField},
field::SubfieldElement,
},
types::heap_array::{FieldElements, SubfieldElements},
};
type F = ScalarField<C>;
type M = U12;
type IV = SubfieldElement<F>;
type A = ScalarAsExtension<C>; type IB = ScalarAsExtension<C>; type V = SubfieldElements<F, M>;
type B = FieldElements<F, M>;
type Const = V; const N: usize = 3;
#[test]
fn test_open_to() {
super::test_open_to::<V, A, B, Const>(N);
}
#[test]
fn test_random() {
super::test_random::<V, A, B, Const>(N);
}
#[test]
fn test_random_vec_and_reconstruct() {
super::test_random_vec_and_reconstruct::<V, A, B, Const>(N);
}
#[test]
fn test_random_vec_with_global_key_and_reconstruct() {
super::test_random_vec_with_global_key_and_reconstruct::<V, A, B, Const>(N);
}
#[test]
fn test_verify_mac() {
super::test_verify_mac::<V, A, B, Const>(N);
}
#[test]
fn test_add() {
super::test_add::<V, A, B, Const>(N);
}
#[test]
fn test_add_plaintext() {
super::test_add_plaintext::<V, A, B, Const>(N);
}
#[test]
fn test_mul_constant() {
super::test_mul_constant::<V, A, B, Const>(N);
}
#[test]
fn test_sub() {
super::test_sub::<V, A, B, Const>(N);
}
#[test]
fn test_neg() {
super::test_neg::<V, A, B, Const>(N);
}
#[test]
fn test_conditional_select() {
super::test_conditional_select::<V, A, B, Const>(N);
}
#[test]
fn test_ct_eq() {
super::test_ct_eq::<V, A, B, Const>(N);
}
type MDiv2 = <U12 as Div<U2>>::Output;
type MDiv3 = <U12 as Div<U3>>::Output;
#[test]
fn test_split_halves() {
super::test_split_halves::<IV, A, IB, M, MDiv2>(N);
}
#[test]
fn test_split_thirds() {
super::test_split_thirds::<IV, A, IB, M, MDiv3>(N);
}
#[test]
fn test_into_iter() {
super::test_into_iter::<IV, A, IB, M>(N);
}
#[test]
fn test_from_iterator() {
super::test_from_iterator::<IV, A, IB, M>(N);
}
#[test]
#[should_panic]
fn test_from_iterator_unequal_sizes() {
super::test_from_iterator_unequal_sizes::<IV, A, IB, M>(N);
}
#[test]
fn test_chunks() {
super::test_chunks::<IV, A, IB, M, U4>(N);
}
}
mod point_shares_tests {
use std::ops::Div;
use typenum::{U12, U2, U3, U4};
use crate::{
algebra::elliptic_curve::{Curve25519Ristretto as C, Point, ScalarAsExtension},
types::heap_array::{CurvePoints, Scalars},
};
type M = U12;
type IV = Point<C>;
type A = ScalarAsExtension<C>;
type IB = Point<C>;
type V = CurvePoints<C, M>;
type B = CurvePoints<C, M>;
type Const = Scalars<C, M>;
const N: usize = 3;
#[test]
fn test_open_to() {
super::test_open_to::<V, A, B, Const>(N);
}
#[test]
fn test_random() {
super::test_random::<V, A, B, Const>(N);
}
#[test]
fn test_random_vec_and_reconstruct() {
super::test_random_vec_and_reconstruct::<V, A, B, Const>(N);
}
#[test]
fn test_random_vec_with_global_key_and_reconstruct() {
super::test_random_vec_with_global_key_and_reconstruct::<V, A, B, Const>(N);
}
#[test]
fn test_verify_mac() {
super::test_verify_mac::<V, A, B, Const>(N);
}
#[test]
fn test_add() {
super::test_add::<V, A, B, Const>(N);
}
#[test]
fn test_add_plaintext() {
super::test_add_plaintext::<V, A, B, Const>(N);
}
#[test]
fn test_mul_constant() {
super::test_mul_constant::<V, A, B, Const>(N);
}
#[test]
fn test_sub() {
super::test_sub::<V, A, B, Const>(N);
}
#[test]
fn test_neg() {
super::test_neg::<V, A, B, Const>(N);
}
#[test]
fn test_conditional_select() {
super::test_conditional_select::<V, A, B, Const>(N);
}
#[test]
fn test_ct_eq() {
super::test_ct_eq::<V, A, B, Const>(N);
}
type MDiv2 = <U12 as Div<U2>>::Output;
type MDiv3 = <U12 as Div<U3>>::Output;
#[test]
fn test_split_halves() {
super::test_split_halves::<IV, A, IB, M, MDiv2>(N);
}
#[test]
fn test_split_thirds() {
super::test_split_thirds::<IV, A, IB, M, MDiv3>(N);
}
#[test]
fn test_into_iter() {
super::test_into_iter::<IV, A, IB, M>(N);
}
#[test]
fn test_from_iterator() {
super::test_from_iterator::<IV, A, IB, M>(N);
}
#[test]
#[should_panic]
fn test_from_iterator_unequal_sizes() {
super::test_from_iterator_unequal_sizes::<IV, A, IB, M>(N);
}
#[test]
fn test_chunks() {
super::test_chunks::<IV, A, IB, M, U4>(N);
}
}
}