use std::convert::{AsMut, AsRef};
use std::fmt::Debug;
use std::io;
use std::ops::{Add, Mul, Sub};
use mcircuit::WireValue;
use num_traits::identities::Zero;
use rand::RngCore;
use crate::crypto::hash;
use crate::crypto::prg::{Key, PRG};
use crate::generator::ShareGen;
use crate::{BATCH_SIZE, PACKED, PLAYERS};
#[allow(clippy::suspicious_arithmetic_impl)] pub mod gf2;
pub mod z64;
pub trait Serialize {
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()>;
}
pub trait Deserialize {
fn deserialize<R: io::Read>(&mut self, reader: &mut R) -> io::Result<()>;
}
impl<T: AsRef<[u8]>> Serialize for T {
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(self.as_ref())
}
}
impl<T: AsMut<[u8]>> Deserialize for T {
fn deserialize<R: io::Read>(&mut self, reader: &mut R) -> io::Result<()> {
reader.read_exact(self.as_mut())
}
}
pub trait Hashable {
fn hash(&self, hashers: &mut hash::PackedHasher);
}
pub trait Recon:
Sized
+ Pack
+ Zero
+ Add<Output = Self>
+ Mul<Output = Self>
+ Sub<Output = Self>
+ Copy
+ Debug
+ Clone
+ Hashable
+ Default
+ PartialEq
+ Eq
+ EqIndex
{
}
pub trait Batch: Sized + Add + Zero + Default {
fn random(&mut self, prg: &mut PRG);
}
pub trait Pack: Sized {
fn pack(
dst: &mut [Vec<u8>; PACKED], src: &[Self], selected: &[bool; PACKED], );
#[allow(clippy::ptr_arg)]
fn unpack(
dst: &mut Vec<Self>, src: &[&[u8]; PACKED], );
}
pub trait PackSelected: Sized {
fn pack_selected(dst: &mut [Vec<u8>; PACKED], src: &[Self], selected: [usize; PACKED]);
#[allow(clippy::ptr_arg)]
fn unpack_selected(dst: &mut Vec<Self>, src: &[&[u8]; PACKED], selected: [usize; PACKED]);
}
pub trait Share:
Sized
+ PackSelected
+ Debug
+ Zero
+ Add<Output = Self>
+ Sub<Output = Self>
+ Default
+ Copy
+ Clone
+ Hashable
+ EqIndex
{
}
pub trait EqIndex {
fn compare_index(
_rep1: usize,
_p1: usize,
_v1: &Self, _rep2: usize,
_p2: usize,
_v2: &Self, ) -> bool {
true
}
}
pub trait Domain: Copy + Clone + Debug {
type Batch: Batch;
type Recon: Recon;
type Share: Share
+ Mul<Self::Recon, Output = Self::Share>
+ Add<Self::Recon, Output = Self::Share>;
fn reconstruct(share: &Self::Share) -> Self::Recon;
fn batches_to_shares(
to: &mut [Self::Share; BATCH_SIZE],
from: &[[Self::Batch; PLAYERS]; PACKED],
);
fn random_shares<R: RngCore>(rng: &mut R, num: usize) -> Vec<Self::Share> {
let mut keys: [[Key; PLAYERS]; PACKED] = [[Default::default(); PLAYERS]; PACKED];
for packed_keys in keys.iter_mut().take(PACKED) {
for player_key in packed_keys.iter_mut().take(PLAYERS) {
rng.fill_bytes(player_key);
}
}
let mut share_gen: ShareGen<Self> = ShareGen::new(&keys, [PLAYERS; PACKED]);
let mut shares: Vec<Self::Share> = Vec::with_capacity(num);
for _ in 0..num {
shares.push(share_gen.next());
}
shares
}
fn random_recon<R: RngCore>(rng: &mut R, num: usize) -> Vec<Self::Recon> {
let shares = Self::random_shares(rng, num);
shares.iter().map(|s| Self::reconstruct(s)).collect()
}
type ConstType: Into<Self::Recon> + Copy + Debug + PartialEq + WireValue;
const ONE: Self::ConstType;
const ZERO: Self::ConstType;
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use rand::rngs::OsRng;
use rand::Rng;
use super::*;
fn test_recon_pack<D: Domain>() {
let tests = vec![
(2, 1),
];
for (num_reps, num_recons) in tests.into_iter() {
let mut selected = vec![false; PACKED * num_reps];
let mut rem = PACKED;
while rem > 0 {
let i = OsRng.gen::<usize>() % selected.len();
if !selected[i] {
rem -= 1;
selected[i] = true;
}
}
let recon: Vec<Vec<D::Recon>> = (0..num_reps)
.map(|_| D::random_recon(&mut OsRng, num_recons))
.collect();
let mut packed: Vec<Vec<u8>> = (0..PACKED * num_reps).map(|_| vec![]).collect();
for i in 0..num_reps {
let range = i * PACKED..(i + 1) * PACKED;
D::Recon::pack(
<&mut [Vec<u8>; PACKED]>::try_from(&mut packed[range.clone()]).unwrap(),
&recon[i][..],
<&[bool; PACKED]>::try_from(&selected[range]).unwrap(),
);
}
let mut recovered: Vec<D::Recon> = vec![];
let mut streams: Vec<&[u8]> = vec![];
for (i, sel) in selected.iter().copied().enumerate() {
if sel {
streams.push(&packed[i][..]);
}
}
assert_eq!(streams.len(), PACKED);
D::Recon::unpack(
&mut recovered,
<&[&[u8]; PACKED]>::try_from(&streams[..]).unwrap(),
);
assert!(recovered.len() >= num_recons);
for i in 0..num_recons {
let mut nxt = 0;
for (j, sel) in selected.iter().copied().enumerate() {
if sel {
let v1 = &recovered[i];
let v2 = &recon[j / PACKED][i];
let rep1 = nxt;
let rep2 = j % PACKED;
assert!(
D::Recon::compare_index(
nxt,
0,
&recovered[i], j % PACKED,
0,
&recon[j / PACKED][i],
),
"recovered[_] = {:?}, recon[_] = {:?}, rep1 = {}, rep2 = {}",
v1,
v2,
rep1,
rep2
);
nxt += 1;
}
}
}
}
let selected: [bool; PACKED] = [true; PACKED];
for num in vec![1, 2, 3, 6, 18, 32, 64, 63, 65, 128, 127] {
let shares = D::random_shares(&mut OsRng, num);
let recon: Vec<D::Recon> = shares.iter().map(|s| D::reconstruct(s)).collect();
let mut dst = [
vec![],
vec![],
vec![],
vec![],
vec![],
vec![],
vec![],
vec![],
];
D::Recon::pack(&mut dst, &recon[..], &selected);
let mut recon_unpacked: Vec<D::Recon> = vec![];
D::Recon::unpack(
&mut recon_unpacked,
&[
&dst[0], &dst[1], &dst[2], &dst[3], &dst[4], &dst[5], &dst[6], &dst[7],
],
);
for i in 0..recon.len() {
assert_eq!(recon_unpacked[i], recon[i]);
}
}
}
fn test_share_partial_pack<D: Domain>() {
for num in vec![1, 2, 3, 6, 18, 32, 64, 63, 65, 128, 127] {
let shares = D::random_shares(&mut OsRng, num);
let selected: [usize; PACKED] = [
OsRng.gen::<usize>() % PLAYERS,
OsRng.gen::<usize>() % PLAYERS,
OsRng.gen::<usize>() % PLAYERS,
OsRng.gen::<usize>() % PLAYERS,
OsRng.gen::<usize>() % PLAYERS,
OsRng.gen::<usize>() % PLAYERS,
OsRng.gen::<usize>() % PLAYERS,
OsRng.gen::<usize>() % PLAYERS,
];
let mut shares_packed = [
vec![],
vec![],
vec![],
vec![],
vec![],
vec![],
vec![],
vec![],
];
D::Share::pack_selected(&mut shares_packed, &shares[..], selected);
let mut shares_partial: Vec<D::Share> = vec![];
D::Share::unpack_selected(
&mut shares_partial,
&[
&shares_packed[0],
&shares_packed[1],
&shares_packed[2],
&shares_packed[3],
&shares_packed[4],
&shares_packed[5],
&shares_packed[6],
&shares_packed[7],
],
selected,
);
assert!(shares_partial.len() >= shares.len());
println!("{:?}", shares_packed);
for j in 0..shares.len() {
for rep in 0..PACKED {
let p = selected[rep];
assert!(
D::Share::compare_index(rep, p, &shares_partial[j], rep, p, &shares[j]),
"{:?}",
selected
);
}
}
}
}
fn test_domain<D: Domain>() {
test_recon_pack::<D>();
test_share_partial_pack::<D>();
}
#[test]
fn test_gf2() {
test_domain::<gf2::Domain>();
}
#[test]
fn test_z64() {
test_domain::<z64::Domain>();
}
}