arcium-primitives 0.8.1

Arcium primitives
Documentation
use std::ops::{Add, SubAssign};

use serde::{de::DeserializeOwned, Serialize};

use crate::{
    algebra::field::{FieldExtension, SubfieldElement},
    errors::PrimitiveError,
    random::{CryptoRngCore, Random},
    sharing::{PlaintextOps, Reconstructible},
    types::{Element, HeapArray, PeerIndex, Positive},
};

/// A trait for additive secret sharing schemes.
pub trait AdditiveShares:
    Sized + Clone + Random + for<'a> Add<&'a Self, Output = Self> + for<'s> SubAssign<&'s Self>
{
    /// Split a secret into `n` additive shares.
    fn to_additive_shares(&self, n_parties: usize, mut rng: impl CryptoRngCore) -> Vec<Self> {
        let mut last_share = self.clone();
        let mut shares = (0..n_parties - 1)
            .map(|_| {
                let share = Self::random(&mut rng);
                last_share -= &share;
                share
            })
            .collect::<Vec<_>>();
        shares.push(last_share);
        shares
    }

    /// Reconstruct a secret from `n` additive shares.
    fn from_additive_shares<S: std::borrow::Borrow<Self>>(shares: &[S]) -> Self {
        let mut shares_iter = shares.iter();
        let first = shares_iter
            .next()
            .expect("At least one share is required for reconstruction.");
        shares_iter.fold(first.borrow().clone(), |acc, share| acc + share.borrow())
    }
}

impl<T: AdditiveShares + Serialize + DeserializeOwned + PartialEq + Send + Sync + 'static>
    Reconstructible for T
{
    type Opening = T;
    type Value = T;

    fn open_to(&self, _peer_index: PeerIndex) -> Result<Self::Opening, PrimitiveError> {
        Ok(self.to_owned())
    }

    fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening> {
        if true {
            unimplemented!("No info about number of parties to open to");
        } else {
            std::iter::empty()
        }
    }

    fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError> {
        Ok(openings
            .iter()
            .fold(self.to_owned(), |acc, opening| acc + opening))
    }

    fn reconstruct_all<S: std::borrow::Borrow<Self>>(
        shares: Vec<S>,
    ) -> Result<Self::Value, PrimitiveError> {
        Ok(Self::from_additive_shares(&shares))
    }
}

impl<
        T: Element
            + Clone
            + Random
            + for<'b> derive_more::SubAssign<&'b T>
            + for<'b> derive_more::Add<&'b T, Output = T>,
        M: Positive,
    > AdditiveShares for HeapArray<T, M>
{
}

/// Adding a public constant to an unauthenticated additive share: only the first peer folds the
/// constant into its share (`x_0 ± c`); every other peer's share is unchanged, so the sum shifts
/// by exactly `c`.
impl<F: FieldExtension> PlaintextOps<SubfieldElement<F>> for SubfieldElement<F> {
    #[inline]
    fn add_plaintext(self, ptx: &Self, is_first_peer: bool) -> Self {
        if is_first_peer {
            self + ptx
        } else {
            self
        }
    }

    #[inline]
    fn sub_plaintext(self, ptx: &Self, is_first_peer: bool) -> Self {
        if is_first_peer {
            self - ptx
        } else {
            self
        }
    }
}