use super::{
base_svole::{Receiver as BaseReceiver, Sender as BaseSender},
spsvole::{SpsReceiver, SpsSender},
utils::Powers,
};
use crate::svole::wykw::specialization::NoSpecialization;
use crate::{
errors::Error,
svole::{SVoleReceiver, SVoleSender},
};
use generic_array::typenum::Unsigned;
use rand::{
distributions::{Distribution, Uniform},
CryptoRng, Rng, SeedableRng,
};
use scuttlebutt::{
field::{Degree, FiniteField},
ring::FiniteRing,
AbstractChannel, AesRng, Block, Malicious, SemiHonest,
};
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct LpnParams {
weight: usize,
cols: usize,
rows: usize,
}
pub const LPN_SETUP_SMALL: LpnParams = LpnParams {
weight: 600,
cols: 9_600, rows: 1_220,
};
pub const LPN_EXTEND_SMALL: LpnParams = LpnParams {
weight: 2_600,
cols: 166_400, rows: 5_060,
};
pub const LPN_SETUP_MEDIUM: LpnParams = LpnParams {
weight: 2_600,
cols: 166_400, rows: 5_060,
};
pub const LPN_EXTEND_MEDIUM: LpnParams = LpnParams {
weight: 4_965,
cols: 10_168_320, rows: 158_000,
};
pub const LPN_SETUP_LARGE: LpnParams = LpnParams {
rows: 19_870,
cols: 642_048,
weight: 2_508,
};
pub const LPN_EXTEND_LARGE: LpnParams = LpnParams {
rows: 589_760,
cols: 10_805_248,
weight: 1_319,
};
const LPN_PARAMS_D: usize = 10;
fn compute_num_saved<FE: FiniteField>(params: LpnParams) -> usize {
params.rows + params.weight + Degree::<FE>::USIZE
}
fn lpn_mtx_indices<FE: FiniteField>(
distribution: &Uniform<u32>,
mut rng: &mut AesRng,
) -> [(usize, FE::PrimeField); LPN_PARAMS_D] {
let mut indices = [0u32; LPN_PARAMS_D];
for i in 0..LPN_PARAMS_D {
let mut rand_idx = distribution.sample(&mut rng);
while indices[0..i].iter().any(|&x| x == rand_idx) {
rand_idx = distribution.sample(&mut rng);
}
indices[i] = rand_idx;
}
let mut out_indices = [(0, FE::PrimeField::ONE); LPN_PARAMS_D];
for i in 0..LPN_PARAMS_D {
out_indices[i].0 = indices[i].try_into().unwrap();
out_indices[i].1 = FE::PrimeField::random_nonzero(&mut rng);
}
out_indices
}
pub struct Sender<FE: FiniteField> {
lpn_setup: LpnParams,
lpn_extend: LpnParams,
spsvole: SpsSender<FE>,
base_voles: Vec<(FE::PrimeField, FE)>,
lpn_rng: AesRng,
}
impl<FE: FiniteField> Sender<FE> {
fn send_internal<C: AbstractChannel, RNG: CryptoRng + Rng>(
&mut self,
channel: &mut C,
params: LpnParams,
num_saved: usize,
rng: &mut RNG,
output: &mut Vec<(FE::PrimeField, FE)>,
) -> Result<(), Error> {
let rows = params.rows;
let cols = params.cols;
let weight = params.weight;
let r = Degree::<FE>::USIZE;
let m = cols / weight;
let used = rows + weight + r;
debug_assert!(
self.base_voles.len() >= used,
"Not enough base sVOLEs: {} < {} + {} + {}",
self.base_voles.len(),
rows,
weight,
r
);
let uws = self
.spsvole
.send(channel, m, &self.base_voles[rows..rows + weight + r], rng)?;
debug_assert_eq!(uws.len(), cols);
let leftover = self.base_voles.len() - used;
let mut base_voles = Vec::with_capacity(num_saved + leftover);
output.clear();
let out_len = cols - num_saved;
output.reserve(out_len);
assert!(rows <= 4_294_967_295); let distribution = Uniform::<u32>::from(0..rows.try_into().unwrap());
for (i, (e, c)) in uws.into_iter().enumerate() {
let indices = lpn_mtx_indices::<FE>(&distribution, &mut self.lpn_rng);
let mut x = e;
let mut z = c;
for (j, a) in indices.iter() {
x += self.base_voles[*j].0 * *a;
z += *a * self.base_voles[*j].1;
}
if i < num_saved {
base_voles.push((x, z));
} else {
output.push((x, z));
}
}
base_voles.extend(self.base_voles[used..].iter());
self.base_voles = base_voles;
debug_assert_eq!(self.base_voles.len(), num_saved + leftover);
debug_assert_eq!(output.len(), cols - num_saved);
Ok(())
}
}
impl<FE: FiniteField> SVoleSender for Sender<FE> {
type Msg = FE;
fn init<C: AbstractChannel, RNG: CryptoRng + Rng>(
channel: &mut C,
rng: &mut RNG,
lpn_setup: LpnParams,
lpn_extend: LpnParams,
) -> Result<Self, Error> {
let pows: Powers<FE> = Default::default();
let mut base_sender = BaseSender::<FE, NoSpecialization>::init(channel, pows.clone(), rng)?;
let base_voles_setup =
base_sender.send(channel, compute_num_saved::<FE>(lpn_setup), rng)?;
let spsvole = SpsSender::<FE>::init(channel, pows, rng)?;
let seed = rng.gen::<Block>();
let seed = scuttlebutt::cointoss::receive(channel, &[seed])?[0];
let lpn_rng = AesRng::from_seed(seed);
let mut sender = Self {
lpn_setup,
lpn_extend,
spsvole,
base_voles: base_voles_setup,
lpn_rng,
};
let mut base_voles_setup = Vec::new();
sender.send_internal(channel, sender.lpn_setup, 0, rng, &mut base_voles_setup)?;
sender.base_voles = base_voles_setup;
Ok(sender)
}
fn send<C: AbstractChannel, RNG: CryptoRng + Rng>(
&mut self,
channel: &mut C,
rng: &mut RNG,
output: &mut Vec<(FE::PrimeField, FE)>,
) -> Result<(), Error> {
self.send_internal(
channel,
self.lpn_extend,
compute_num_saved::<FE>(self.lpn_extend),
rng,
output,
)
}
fn duplicate<C: AbstractChannel, RNG: CryptoRng + Rng>(
&mut self,
channel: &mut C,
rng: &mut RNG,
) -> Result<Self, Error> {
let mut base_voles = Vec::new();
self.send_internal(
channel,
self.lpn_setup,
compute_num_saved::<FE>(self.lpn_setup),
rng,
&mut base_voles,
)?;
debug_assert!(base_voles.len() >= compute_num_saved::<FE>(self.lpn_extend));
debug_assert!(self.base_voles.len() >= compute_num_saved::<FE>(self.lpn_extend));
let spsvole = self.spsvole.duplicate(channel, rng)?;
let lpn_rng = self.lpn_rng.fork();
Ok(Self {
lpn_setup: self.lpn_setup,
lpn_extend: self.lpn_extend,
spsvole,
base_voles,
lpn_rng,
})
}
}
pub struct Receiver<FE: FiniteField> {
lpn_setup: LpnParams,
lpn_extend: LpnParams,
spsvole: SpsReceiver<FE>,
delta: FE,
base_voles: Vec<FE>,
lpn_rng: AesRng,
}
impl<FE: FiniteField> Receiver<FE> {
fn receive_internal<C: AbstractChannel, RNG: CryptoRng + Rng>(
&mut self,
channel: &mut C,
params: LpnParams,
num_saved: usize,
rng: &mut RNG,
output: &mut Vec<FE>,
) -> Result<(), Error> {
let rows = params.rows;
let cols = params.cols;
let weight = params.weight;
let r = Degree::<FE>::USIZE;
let m = cols / weight;
let used = rows + weight + r;
debug_assert!(
self.base_voles.len() >= used,
"{} < {} + {} + {}",
self.base_voles.len(),
rows,
weight,
r
);
let leftover = self.base_voles.len() - used;
let vs =
self.spsvole
.receive(channel, m, &self.base_voles[rows..rows + weight + r], rng)?;
debug_assert!(vs.len() == cols);
let mut base_voles = Vec::with_capacity(num_saved + leftover);
output.clear();
output.reserve(cols - num_saved);
assert!(rows <= 4_294_967_295); let distribution = Uniform::<u32>::from(0..rows.try_into().unwrap());
for (i, b) in vs.into_iter().enumerate() {
let indices = lpn_mtx_indices::<FE>(&distribution, &mut self.lpn_rng);
let mut y = b;
y += indices.iter().map(|(j, a)| *a * self.base_voles[*j]).sum();
if i < num_saved {
base_voles.push(y);
} else {
output.push(y);
}
}
base_voles.extend(self.base_voles[used..].iter());
self.base_voles = base_voles;
debug_assert_eq!(output.len(), cols - num_saved);
Ok(())
}
}
impl<FE: FiniteField> SVoleReceiver for Receiver<FE> {
type Msg = FE;
fn init<C: AbstractChannel, RNG: CryptoRng + Rng>(
channel: &mut C,
rng: &mut RNG,
lpn_setup: LpnParams,
lpn_extend: LpnParams,
) -> Result<Self, Error> {
let pows: Powers<FE> = Default::default();
let mut base_receiver = BaseReceiver::<FE>::init(channel, pows.clone(), rng)?;
let base_voles_setup =
base_receiver.receive(channel, compute_num_saved::<FE>(lpn_setup), rng)?;
let delta = base_receiver.delta();
let spsvole = SpsReceiver::<FE>::init(channel, pows, delta, rng)?;
let seed = rng.gen::<Block>();
let seed = scuttlebutt::cointoss::send(channel, &[seed])?[0];
let lpn_rng = AesRng::from_seed(seed);
let mut receiver = Self {
lpn_setup,
lpn_extend,
spsvole,
delta,
base_voles: base_voles_setup,
lpn_rng,
};
let mut base_voles_setup = Vec::new();
receiver.receive_internal(channel, lpn_setup, 0, rng, &mut base_voles_setup)?;
receiver.base_voles = base_voles_setup;
Ok(receiver)
}
fn delta(&self) -> FE {
self.delta
}
fn receive<C: AbstractChannel, RNG: CryptoRng + Rng>(
&mut self,
channel: &mut C,
rng: &mut RNG,
output: &mut Vec<FE>,
) -> Result<(), Error> {
self.receive_internal(
channel,
self.lpn_extend,
compute_num_saved::<FE>(self.lpn_extend),
rng,
output,
)
}
fn duplicate<C: AbstractChannel, RNG: CryptoRng + Rng>(
&mut self,
channel: &mut C,
rng: &mut RNG,
) -> Result<Self, Error> {
let mut base_voles = Vec::new();
self.receive_internal(
channel,
self.lpn_setup,
compute_num_saved::<FE>(self.lpn_setup),
rng,
&mut base_voles,
)?;
debug_assert!(base_voles.len() >= compute_num_saved::<FE>(self.lpn_extend));
debug_assert!(self.base_voles.len() >= compute_num_saved::<FE>(self.lpn_extend));
let spsvole = self.spsvole.duplicate(channel, rng)?;
let lpn_rng = self.lpn_rng.fork();
Ok(Self {
lpn_setup: self.lpn_setup,
lpn_extend: self.lpn_extend,
spsvole,
delta: self.delta,
base_voles,
lpn_rng,
})
}
}
impl<FF: FiniteField> SemiHonest for Sender<FF> {}
impl<FF: FiniteField> SemiHonest for Receiver<FF> {}
impl<FF: FiniteField> Malicious for Sender<FF> {}
impl<FF: FiniteField> Malicious for Receiver<FF> {}
#[cfg(test)]
mod tests {
use super::{Receiver, SVoleReceiver, SVoleSender, Sender, LPN_EXTEND_SMALL, LPN_SETUP_SMALL};
use scuttlebutt::{
field::{F128b, F40b, F61p, FiniteField as FF},
AesRng, Channel,
};
use std::{
io::{BufReader, BufWriter},
os::unix::net::UnixStream,
};
fn test_lpn_svole_<FE: FF, Sender: SVoleSender<Msg = FE>, Receiver: SVoleReceiver<Msg = FE>>() {
let (sender, receiver) = UnixStream::pair().unwrap();
let handle = std::thread::spawn(move || {
let mut rng = AesRng::new();
let reader = BufReader::new(sender.try_clone().unwrap());
let writer = BufWriter::new(sender);
let mut channel = Channel::new(reader, writer);
let mut vole =
Sender::init(&mut channel, &mut rng, LPN_SETUP_SMALL, LPN_EXTEND_SMALL).unwrap();
let mut out = Vec::new();
vole.send(&mut channel, &mut rng, &mut out).unwrap();
out
});
let mut rng = AesRng::new();
let reader = BufReader::new(receiver.try_clone().unwrap());
let writer = BufWriter::new(receiver);
let mut channel = Channel::new(reader, writer);
let mut vole =
Receiver::init(&mut channel, &mut rng, LPN_SETUP_SMALL, LPN_EXTEND_SMALL).unwrap();
let mut vs = Vec::new();
vole.receive(&mut channel, &mut rng, &mut vs).unwrap();
let uws = handle.join().unwrap();
for i in 0..uws.len() as usize {
let right = uws[i].0 * vole.delta() + vs[i];
assert_eq!(uws[i].1, right);
}
}
fn test_duplicate_svole_<
FE: FF,
Sender: SVoleSender<Msg = FE>,
Receiver: SVoleReceiver<Msg = FE>,
>() {
let (sender, receiver) = UnixStream::pair().unwrap();
let handle = std::thread::spawn(move || {
let mut rng = AesRng::new();
let reader = BufReader::new(sender.try_clone().unwrap());
let writer = BufWriter::new(sender);
let mut channel = Channel::new(reader, writer);
let mut vole =
Sender::init(&mut channel, &mut rng, LPN_SETUP_SMALL, LPN_EXTEND_SMALL).unwrap();
let mut uws = Vec::new();
vole.send(&mut channel, &mut rng, &mut uws).unwrap();
let mut vole2 = vole.duplicate(&mut channel, &mut rng).unwrap();
let mut uws2 = Vec::new();
vole2.send(&mut channel, &mut rng, &mut uws2).unwrap();
let mut uws3 = Vec::new();
vole.send(&mut channel, &mut rng, &mut uws3).unwrap();
assert_ne!(uws2, uws3);
uws.extend(uws2);
uws.extend(uws3);
uws
});
let mut rng = AesRng::new();
let reader = BufReader::new(receiver.try_clone().unwrap());
let writer = BufWriter::new(receiver);
let mut channel = Channel::new(reader, writer);
let mut vole =
Receiver::init(&mut channel, &mut rng, LPN_SETUP_SMALL, LPN_EXTEND_SMALL).unwrap();
let mut vs = Vec::new();
vole.receive(&mut channel, &mut rng, &mut vs).unwrap();
let mut vole2 = vole.duplicate(&mut channel, &mut rng).unwrap();
let mut vs2 = Vec::new();
vole2.receive(&mut channel, &mut rng, &mut vs2).unwrap();
let mut vs3 = Vec::new();
vole.receive(&mut channel, &mut rng, &mut vs3).unwrap();
assert_ne!(vs2, vs3);
vs.extend(vs2);
vs.extend(vs3);
let uws = handle.join().unwrap();
for i in 0..uws.len() as usize {
let right = uws[i].0 * vole.delta() + vs[i];
assert_eq!(uws[i].1, right);
}
}
#[test]
fn test_lpn_svole_gf128() {
test_lpn_svole_::<F128b, Sender<F128b>, Receiver<F128b>>();
}
#[test]
fn test_lpn_svole_f61p() {
test_lpn_svole_::<F61p, Sender<F61p>, Receiver<F61p>>();
}
#[test]
fn test_lpn_svole_f40b() {
test_lpn_svole_::<F40b, Sender<F40b>, Receiver<F40b>>();
}
#[test]
fn test_duplicate_svole() {
test_duplicate_svole_::<F61p, Sender<F61p>, Receiver<F61p>>();
}
#[test]
fn test_duplicate_svole_f40b() {
test_duplicate_svole_::<F40b, Sender<F40b>, Receiver<F40b>>();
}
}