use primitives::{
algebra::field::binary::Gf2_128,
correlated_randomness::{
bundler::{errors::BundlerError, Bundler},
dabits::DaBit,
singlets::Singlet,
stream::{
Buffer,
CorrelatedStream,
CorrelatedStreamError,
PrefetchHandle,
ResyncHandle,
SharedBufferConfig,
},
triples::Triple,
Correlation,
},
};
use crate::{
circuit::preprocessing::CircuitPreprocessing,
config::{BaseFieldOf, MpcConfig, MpcFieldOf, ScalarFieldOf},
errors::AbortError,
preprocessing::{iterator::PreprocessingIterator, PerStream, PreprocessingKind},
};
macro_rules! build_iterator {
($self:ident, $req:ident, $(($field:ident, $stream:ident, $kind:ident)),+ $(,)?) => {
PreprocessingIterator {
$( $field: $self.$stream.next_n($req[PreprocessingKind::$kind])?.into_iter() ),+
}
};
}
macro_rules! with_stream {
($self:ident, $kind:expr, $($call:tt)+) => {
match $kind {
PreprocessingKind::BitSinglets => $self.binary_singlet_stream.$($call)+,
PreprocessingKind::BitTriples => $self.binary_triple_stream.$($call)+,
PreprocessingKind::BaseFieldSinglets => $self.basefield_singlet_stream.$($call)+,
PreprocessingKind::BaseFieldTriples => $self.basefield_triple_stream.$($call)+,
PreprocessingKind::BaseFieldDaBits => $self.basefield_dabit_stream.$($call)+,
PreprocessingKind::ScalarSinglets => $self.scalar_singlet_stream.$($call)+,
PreprocessingKind::ScalarTriples => $self.scalar_triple_stream.$($call)+,
PreprocessingKind::ScalarDaBits => $self.scalar_dabit_stream.$($call)+,
PreprocessingKind::MpcFieldSinglets => $self.mpc_field_singlet_stream.$($call)+,
PreprocessingKind::MpcFieldTriples => $self.mpc_field_triple_stream.$($call)+,
PreprocessingKind::MpcFieldDaBits => $self.mpc_field_dabit_stream.$($call)+,
}
};
}
pub trait BundledStream<P: Correlation>: CorrelatedStream<P, Error = AbortError> + Buffer {}
impl<P: Correlation, T: CorrelatedStream<P, Error = AbortError> + Buffer> BundledStream<P> for T {}
type Slot<P> = Box<dyn BundledStream<P>>;
pub struct StreamBundler<C: MpcConfig> {
pub basefield_dabit_stream: Slot<DaBit<BaseFieldOf<C>>>,
pub basefield_singlet_stream: Slot<Singlet<BaseFieldOf<C>>>,
pub basefield_triple_stream: Slot<Triple<BaseFieldOf<C>>>,
pub binary_singlet_stream: Slot<Singlet<Gf2_128>>,
pub binary_triple_stream: Slot<Triple<Gf2_128>>,
pub mpc_field_dabit_stream: Slot<DaBit<MpcFieldOf<C>>>,
pub mpc_field_singlet_stream: Slot<Singlet<MpcFieldOf<C>>>,
pub mpc_field_triple_stream: Slot<Triple<MpcFieldOf<C>>>,
pub scalar_dabit_stream: Slot<DaBit<ScalarFieldOf<C>>>,
pub scalar_singlet_stream: Slot<Singlet<ScalarFieldOf<C>>>,
pub scalar_triple_stream: Slot<Triple<ScalarFieldOf<C>>>,
}
impl<C: MpcConfig> StreamBundler<C> {
#[allow(clippy::too_many_arguments)]
pub fn new(
basefield_dabit_stream: impl BundledStream<DaBit<BaseFieldOf<C>>> + 'static,
basefield_singlet_stream: impl BundledStream<Singlet<BaseFieldOf<C>>> + 'static,
basefield_triple_stream: impl BundledStream<Triple<BaseFieldOf<C>>> + 'static,
binary_singlet_stream: impl BundledStream<Singlet<Gf2_128>> + 'static,
binary_triple_stream: impl BundledStream<Triple<Gf2_128>> + 'static,
mpc_field_dabit_stream: impl BundledStream<DaBit<MpcFieldOf<C>>> + 'static,
mpc_field_singlet_stream: impl BundledStream<Singlet<MpcFieldOf<C>>> + 'static,
mpc_field_triple_stream: impl BundledStream<Triple<MpcFieldOf<C>>> + 'static,
scalar_dabit_stream: impl BundledStream<DaBit<ScalarFieldOf<C>>> + 'static,
scalar_singlet_stream: impl BundledStream<Singlet<ScalarFieldOf<C>>> + 'static,
scalar_triple_stream: impl BundledStream<Triple<ScalarFieldOf<C>>> + 'static,
) -> Self {
Self {
basefield_dabit_stream: Box::new(basefield_dabit_stream),
basefield_singlet_stream: Box::new(basefield_singlet_stream),
basefield_triple_stream: Box::new(basefield_triple_stream),
binary_singlet_stream: Box::new(binary_singlet_stream),
binary_triple_stream: Box::new(binary_triple_stream),
mpc_field_dabit_stream: Box::new(mpc_field_dabit_stream),
mpc_field_singlet_stream: Box::new(mpc_field_singlet_stream),
mpc_field_triple_stream: Box::new(mpc_field_triple_stream),
scalar_dabit_stream: Box::new(scalar_dabit_stream),
scalar_singlet_stream: Box::new(scalar_singlet_stream),
scalar_triple_stream: Box::new(scalar_triple_stream),
}
}
pub fn positions(&self) -> CircuitPreprocessing {
let mut pos = CircuitPreprocessing::default();
for kind in PreprocessingKind::ALL {
pos[kind] = with_stream!(self, kind, position()) as usize;
}
pos
}
pub fn buffered(&self) -> CircuitPreprocessing {
let mut buf = CircuitPreprocessing::default();
for kind in PreprocessingKind::ALL {
buf[kind] = with_stream!(self, kind, buffered()) as usize;
}
buf
}
pub async fn resync(&self, targets: &CircuitPreprocessing) -> Result<(), AbortError> {
let current = self.positions();
for kind in PreprocessingKind::ALL {
if targets[kind] < current[kind] {
return Err(CorrelatedStreamError::ResyncRewind {
current: current[kind] as u64,
target: targets[kind] as u64,
}
.into());
}
}
ResyncHandle::join_all(
PreprocessingKind::ALL
.map(|kind| with_stream!(self, kind, resync(targets[kind] as u64))),
)
.await
}
pub fn buffer_configs(&self) -> PerStream<SharedBufferConfig> {
PerStream::from_fn(|kind| with_stream!(self, kind, config().clone()))
}
}
impl<C: MpcConfig> Bundler for StreamBundler<C> {
type Iterator = PreprocessingIterator<C>;
fn fetch(
&mut self,
req: &CircuitPreprocessing,
) -> Result<PreprocessingIterator<C>, BundlerError> {
Ok(build_iterator!(
self,
req,
(binary_singlets, binary_singlet_stream, BitSinglets),
(binary_triples, binary_triple_stream, BitTriples),
(
base_field_singlets,
basefield_singlet_stream,
BaseFieldSinglets
),
(
base_field_triples,
basefield_triple_stream,
BaseFieldTriples
),
(base_field_dabits, basefield_dabit_stream, BaseFieldDaBits),
(scalar_singlets, scalar_singlet_stream, ScalarSinglets),
(scalar_triples, scalar_triple_stream, ScalarTriples),
(scalar_dabits, scalar_dabit_stream, ScalarDaBits),
(
mpc_field_singlets,
mpc_field_singlet_stream,
MpcFieldSinglets
),
(mpc_field_triples, mpc_field_triple_stream, MpcFieldTriples),
(mpc_field_dabits, mpc_field_dabit_stream, MpcFieldDaBits),
))
}
fn prefetch(&self, req: &CircuitPreprocessing) -> PrefetchHandle<AbortError> {
PrefetchHandle::join_all(
PreprocessingKind::ALL.map(|kind| with_stream!(self, kind, prefetch_n(req[kind]))),
)
}
}