arcium-primitives 0.8.0

Arcium primitives
Documentation
use std::fmt::Debug;

use crate::{correlated_randomness::CorrelatedBatch, utils::TryFuture};

/// Generates preprocessing elements for a given preprocessing type.
pub trait CorrelationGenerator<PB: CorrelatedBatch>: Send {
    /// The interface to the network used to send/receive messages.
    type Net: Send;
    /// The error type returned by the generator.
    type Error: Debug + Clone + Send;

    /// Whether one party may skip ahead independently, without all parties drawing identical
    /// amounts in lockstep: `true` for dealer-style generators (deterministic per index), `false`
    /// for interactive ones (where an asymmetric skip would desync the joint protocol).
    ///
    /// If set to `true` you **must** override [`skip`](Self::skip) — the default panics (it can't
    /// construct a `Self::Error`). When `false`, `skip` is never called.
    const SUPPORTS_UNILATERAL_SKIP: bool = false;

    /// Runs the preprocessing generation protocol and produces a batch of preprocessing elements
    /// with compile-time known size.
    fn run(&mut self, net: &mut Self::Net) -> impl TryFuture<Ok = PB, Error = Self::Error>;

    /// Advances the logical position by `n_elements` without materializing the skipped elements,
    /// to burn correlated elements during resync. Only called when
    /// [`SUPPORTS_UNILATERAL_SKIP`](Self::SUPPORTS_UNILATERAL_SKIP) is `true`; the default panics.
    fn skip(
        &mut self,
        _n_elements: usize,
        _net: &mut Self::Net,
    ) -> impl TryFuture<Ok = (), Error = Self::Error> {
        async move {
            unreachable!(
                "skip() called on a generator without SUPPORTS_UNILATERAL_SKIP; the stream \
                 dispatcher must guard on the const before ever calling skip()"
            )
        }
    }

    /// Runs the preprocessing generation protocol until at least `n_elements` are produced, and
    /// returns a vector of preprocessing elements.
    fn run_for(
        &mut self,
        n_elements: usize,
        net: &mut Self::Net,
    ) -> impl TryFuture<Ok = Vec<PB::Item>, Error = Self::Error> {
        let n_batches = n_elements.div_ceil(PB::batch_size());
        let mut result = Vec::with_capacity(n_batches * PB::batch_size());
        async move {
            for _ in 0..n_batches {
                let batch = self.run(net).await?;
                result.extend(batch.into_iter());
            }
            Ok(result)
        }
    }
}