arcium-primitives 0.4.2

Arcium primitives
Documentation
use itertools::izip;
use num_traits::identities::{One, Zero};

use crate::{
    algebra::field::{binary::Gf2_128, Bit, FieldExtension, SubfieldElement},
    correlated_randomness::dabits::{DaBit, DaBits, OpenDaBit, OpenDaBits},
    errors::PrimitiveError,
    sharing::{Reconstructible, VerifiableWith},
    types::{HeapArray, PeerIndex, Positive},
};
// ---------------
// |   Opening   |
// ---------------

impl<F: FieldExtension> Reconstructible for DaBit<F> {
    type Value = (Bit, SubfieldElement<F>);
    type Opening = OpenDaBit<F>;

    /// Open the daBit towards another peer.
    fn open_to(&self, peer_index: PeerIndex) -> Result<Self::Opening, PrimitiveError> {
        let opened_bit = self.bit.open_to(peer_index)?;

        Ok(OpenDaBit {
            opened_bit,
            opened_field: self.field.open_to(peer_index)?,
        })
    }

    /// Open the daBit towards all other peers.
    fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening> {
        (0..self.field.get_macs().len())
            .map(|peer_index| self.open_to(peer_index).expect("Opening should not fail"))
    }

    /// Reconstruct a secret from openings coming from all other parties.
    fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError> {
        let (bit_openings, field_openings): (Vec<_>, Vec<_>) = openings
            .iter()
            .map(|dabit_opening| (dabit_opening.bit(), dabit_opening.field()))
            .unzip();

        if field_openings.len() != self.field.get_macs().len() {
            return Err(PrimitiveError::InvalidSize(
                self.field.get_macs().len(),
                field_openings.len(),
            ));
        }

        let field = self.field.reconstruct(field_openings)?;
        let bit = self.bit.reconstruct(bit_openings)?;

        Ok((bit, field))
    }
}

impl<F: FieldExtension> VerifiableWith for DaBit<F> {
    type VerificationData = ();

    /// Verify openings from all peers.
    fn verify_with(&self, openings: Vec<Self::Opening>, _data: ()) -> Result<(), PrimitiveError> {
        let (bit, field) = self.reconstruct(openings)?;

        // Check that the bit has the same value as the field element
        if field == SubfieldElement::<F>::one() {
            if bit != SubfieldElement::<Gf2_128>::one() {
                return Err(PrimitiveError::WrongCorrelation(
                    "daBit bit does not match the field element.".to_string(),
                ));
            }
        } else if field == SubfieldElement::<F>::zero() {
            if bit != SubfieldElement::<Gf2_128>::zero() {
                return Err(PrimitiveError::WrongCorrelation(
                    "daBit bit does not match the field element.".to_string(),
                ));
            }
        } else {
            return Err(PrimitiveError::WrongCorrelation(
                "daBit field element is not 0 or 1.".to_string(),
            ));
        }
        Ok(())
    }
}

impl<F: FieldExtension, N: Positive> Reconstructible for DaBits<F, N> {
    type Opening = OpenDaBits<F, N>;
    type Value = HeapArray<(Bit, SubfieldElement<F>), N>;

    /// Open the share towards another peer.
    fn open_to(&self, peer_index: PeerIndex) -> Result<Self::Opening, PrimitiveError> {
        Ok(OpenDaBits {
            opened_bits: self.bits.open_to(peer_index)?,
            opened_field_shares: self.field_shares.open_to(peer_index)?,
        })
    }

    /// Open the share towards all other peers. Returns an iterator with either one opening for
    /// each peer or a single opening for all peers.
    fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening> {
        izip!(
            self.bits.open_to_all_others(),
            self.field_shares.open_to_all_others()
        )
        .map(|(opened_bits, opened_field_shares)| OpenDaBits {
            opened_bits,
            opened_field_shares,
        })
    }

    /// Reconstruct a secret from openings coming from all other parties.
    fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError> {
        let (bit_openings, field_openings): (Vec<_>, Vec<_>) = openings
            .into_iter()
            .map(|dabit_opening| (dabit_opening.opened_bits, dabit_opening.opened_field_shares))
            .unzip();
        let bits = self.bits.reconstruct(bit_openings)?;
        let field_shares = self.field_shares.reconstruct(field_openings)?;

        Ok(HeapArray::from_iter(izip!(
            bits.into_iter(),
            field_shares.into_iter()
        )))
    }
}

impl<F: FieldExtension, N: Positive> VerifiableWith for DaBits<F, N> {
    type VerificationData = ();

    /// Verify openings from all peers.
    fn verify_with(&self, openings: Vec<Self::Opening>, _data: ()) -> Result<(), PrimitiveError> {
        let openings = self.reconstruct(openings)?;

        for (bit, field) in openings {
            // Check that the bit has the same value as the field element
            if field == SubfieldElement::<F>::one() {
                if bit != SubfieldElement::<Gf2_128>::one() {
                    return Err(PrimitiveError::WrongCorrelation(
                        "daBit bit does not match the field element.".to_string(),
                    ));
                }
            } else if field == SubfieldElement::<F>::zero() {
                if bit != SubfieldElement::<Gf2_128>::zero() {
                    return Err(PrimitiveError::WrongCorrelation(
                        "daBit bit does not match the field element.".to_string(),
                    ));
                }
            } else {
                return Err(PrimitiveError::WrongCorrelation(
                    "daBit field element is not 0 or 1.".to_string(),
                ));
            }
        }

        Ok(())
    }
}