diff --git a/mpc-algebra/examples/algebra.rs b/mpc-algebra/examples/algebra.rs index f6703018..9c8e9856 100644 --- a/mpc-algebra/examples/algebra.rs +++ b/mpc-algebra/examples/algebra.rs @@ -64,7 +64,7 @@ fn test_div() { } fn test_sum() { - let a = [ + let a = vec![ MF::from_public(F::from(1u64)), MF::from_public(F::from(2u64)), MF::from_public(F::from(3u64)), diff --git a/mpc-algebra/src/channel.rs b/mpc-algebra/src/channel.rs index 6fac7fbb..43452aac 100644 --- a/mpc-algebra/src/channel.rs +++ b/mpc-algebra/src/channel.rs @@ -1,26 +1,26 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use mpc_net::MpcNet; +use mpc_net::MPCNet; use rand::RngCore; use sha2::{Digest, Sha256}; use std::cell::Cell; /// A trait for MPC networks that can serialize and deserialize. -pub trait MpcSerNet: MpcNet { +pub trait MPCSerNet: MPCNet { /// Broadcast a value to each other. - fn broadcast(out: &T) -> Vec { + fn broadcast(&self,out: &T) -> Vec { let mut bytes_out = Vec::new(); out.serialize(&mut bytes_out).unwrap(); - let bytes_in = Self::broadcast_bytes(&bytes_out); + let bytes_in = self.broadcast(&bytes_out); bytes_in .into_iter() .map(|b| T::deserialize(&b[..]).unwrap()) .collect() } - fn send_to_king(out: &T) -> Option> { + fn send_to_king(&self,out: &T) -> Option> { let mut bytes_out = Vec::new(); out.serialize(&mut bytes_out).unwrap(); - Self::send_bytes_to_king(&bytes_out).map(|bytes_in| { + self.send_to_king(&bytes_out).map(|bytes_in| { bytes_in .into_iter() .map(|b| T::deserialize(&b[..]).unwrap()) @@ -28,8 +28,8 @@ pub trait MpcSerNet: MpcNet { }) } - fn recieve_from_king(out: Option>) -> T { - let bytes_in = Self::recv_bytes_from_king(out.map(|outs| { + fn recieve_from_king(&self,out: Option>) -> T { + let bytes_in = self.recieve_from_king(out.map(|outs| { outs.iter() .map(|out| { let mut bytes_out = Vec::new(); @@ -41,20 +41,20 @@ pub trait MpcSerNet: MpcNet { T::deserialize(&bytes_in[..]).unwrap() } - fn atomic_broadcast(out: &T) -> Vec { + fn atomic_broadcast(&self,out: &T) -> Vec { let mut bytes_out = Vec::new(); out.serialize(&mut bytes_out).unwrap(); let ser_len = bytes_out.len(); bytes_out.resize(ser_len + COMMIT_RAND_BYTES, 0); rand::thread_rng().fill_bytes(&mut bytes_out[ser_len..]); - let commitment = CommitHash::new().chain(&bytes_out).finalize(); - // exchange commitments - let all_commits = Self::broadcast_bytes(&commitment[..]); - // exchange (data || randomness) - let all_data = Self::broadcast_bytes(&bytes_out); - let self_id = Self::party_id(); + let commitment = CommitHash::new().chain(&bytes_out).finalize().to_vec(); + // コミットメントを交換 + let all_commits = self.broadcast(&commitment); + // データとランダムネスを交換 + let all_data = self.broadcast(&bytes_out); + let self_id = self.party_id(); for i in 0..all_commits.len() { - if i != self_id { + if i as u32 != self_id { // check other commitment assert_eq!( &all_commits[i][..], @@ -69,15 +69,15 @@ pub trait MpcSerNet: MpcNet { } fn king_compute( + &self, x: &T, f: impl Fn(Vec) -> Vec, ) -> T { - let king_response = Self::send_to_king(x).map(f); - Self::recieve_from_king(king_response) + let king_response = self.send_to_king(x).map(f); + self.recieve_from_king(king_response) } } - -impl MpcSerNet for N {} +impl MPCSerNet for N {} const ALLOW_CHEATING: Cell = Cell::new(true); diff --git a/mpc-algebra/src/share/additive.rs b/mpc-algebra/src/share/additive.rs index e0483fef..55a23fed 100644 --- a/mpc-algebra/src/share/additive.rs +++ b/mpc-algebra/src/share/additive.rs @@ -3,6 +3,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use std::hash::Hash; use std::io::{self, Read, Write}; use std::marker::PhantomData; +use std::sync::{Arc, Mutex}; use ark_ec::{group::Group, PairingEngine, ProjectiveCurve}; use ark_ff::{Field, FromBytes, ToBytes}; @@ -17,8 +18,8 @@ use derivative::Derivative; use crate::reveal::Reveal; use crate::{BeaverSource, DenseOrSparsePolynomial, DensePolynomial, Msm, SparsePolynomial}; -use crate::channel::MpcSerNet; -use mpc_net::{MpcMultiNet as Net, MpcNet}; +use crate::channel::MPCSerNet; +use mpc_net::LocalTestNet as Net; // use super::pairing::ExtendedPairingEngine; // use super::group::GroupAffineShare; @@ -28,9 +29,11 @@ use super::{ pairing::{AffProjShare, PairingShare}, }; -#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct AdditiveFieldShare { pub val: T, + // reference to Net + net: Arc>, } impl AdditiveFieldShare { @@ -76,21 +79,22 @@ impl AdditiveFieldShare { impl Reveal for AdditiveFieldShare { type Base = F; - fn reveal(self) -> Self::Base { - Net::broadcast(&self.val).into_iter().sum() + fn reveal(&self) -> Self::Base { + self.net.broadcast(&self.val).into_iter().sum() } - fn from_add_shared(b: Self::Base) -> Self { - Self { val: b } + fn from_add_shared(b: Self::Base, net: Net) -> Self { + Self { val: b, net } } - fn from_public(f: Self::Base) -> Self { + fn from_public(f: Self::Base, net: Net) -> Self { Self { - val: if Net::am_king() { f } else { F::zero() }, + val: if net. { f } else { F::zero() }, + net: self.net.clone(), } } - fn unwrap_as_public(self) -> Self::Base { + fn unwrap_as_public(&self) -> Self::Base { self.val } } @@ -202,7 +206,7 @@ macro_rules! impl_field_basics { impl_field_basics!(AdditiveFieldShare, Field); -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Debug)] pub struct AdditiveExtFieldShare(pub PhantomData); impl ExtFieldShare for AdditiveExtFieldShare { @@ -210,6 +214,8 @@ impl ExtFieldShare for AdditiveExtFieldShare { type Ext = AdditiveFieldShare; } +impl Copy for AdditiveExtFieldShare {} + #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct MulFieldShare { pub val: T, diff --git a/mpc-algebra/src/share/spdz.rs b/mpc-algebra/src/share/spdz.rs index a6913fa4..6e506d04 100644 --- a/mpc-algebra/src/share/spdz.rs +++ b/mpc-algebra/src/share/spdz.rs @@ -16,8 +16,8 @@ use std::hash::Hash; use std::io::{self, Read, Write}; use std::marker::PhantomData; -use crate::channel::{can_cheat, MpcSerNet}; -use mpc_net::{MpcMultiNet as Net, MpcNet}; +use crate::channel::{can_cheat, MPCSerNet}; +use mpc_net::{LocalTestNet as Net, MPCNet}; use super::additive::{AdditiveFieldShare, AdditiveGroupShare, MulFieldShare}; use super::field::{DenseOrSparsePolynomial, DensePolynomial, ExtFieldShare, FieldShare}; @@ -46,7 +46,7 @@ pub fn mac() -> F { } } -#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct SpdzFieldShare { sh: AdditiveFieldShare, mac: AdditiveFieldShare, diff --git a/mpc-algebra/src/wire/edwards.rs b/mpc-algebra/src/wire/edwards.rs index ac7abf59..8aba5e7a 100644 --- a/mpc-algebra/src/wire/edwards.rs +++ b/mpc-algebra/src/wire/edwards.rs @@ -10,10 +10,10 @@ use ark_crypto_primitives::commitment::pedersen::{Parameters, Randomness}; use ark_crypto_primitives::encryption::elgamal::Parameters as ElGamalParameters; use ark_crypto_primitives::encryption::elgamal::Randomness as ElGamalRandomness; -use mpc_net::MpcMultiNet as Net; +use mpc_net::LocalTestNet as Net; use mpc_trait::MpcWire; -use crate::{channel::MpcSerNet, SpdzFieldShare}; +use crate::{channel::MPCSerNet, SpdzFieldShare}; use crate::{AdditiveFieldShare, MpcField, Reveal}; type AdditiveFq = MpcField>; diff --git a/mpc-algebra/src/wire/field.rs b/mpc-algebra/src/wire/field.rs index 0f206344..6f5fb028 100644 --- a/mpc-algebra/src/wire/field.rs +++ b/mpc-algebra/src/wire/field.rs @@ -25,7 +25,7 @@ use ark_serialize::{ use crate::share::field::FieldShare; use crate::{BeaverSource, BitAdd, BitDecomposition, BitwiseLessThan, LessThan, LogicalOperations, Reveal}; use crate::{EqualityZero, UniformBitRand}; -use mpc_net::{MpcMultiNet as Net, MpcNet}; +use mpc_net::{LocalTestNet as Net, MPCNet}; #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum MpcField> { diff --git a/mpc-algebra/src/wire/macros.rs b/mpc-algebra/src/wire/macros.rs index ff1b214b..39a39eaf 100644 --- a/mpc-algebra/src/wire/macros.rs +++ b/mpc-algebra/src/wire/macros.rs @@ -1,7 +1,7 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use crate::channel::MpcSerNet; -use mpc_net::MpcNet; +use crate::channel::MPCSerNet; +use mpc_net::MPCNet; use std::fmt::Display; @@ -9,13 +9,13 @@ pub fn check_eq = Mutex::new(Connections::default()); -} - -/// Macro for locking the FieldChannel singleton in the current scope. -macro_rules! get_ch { - () => { - CONNECTIONS.lock().expect("Poisoned FieldChannel") - }; -} - -#[derive(Debug)] -struct Peer { - id: usize, - addr: SocketAddr, - stream: Option, -} - -impl Default for Peer { - fn default() -> Self { - Self { - id: 0, - addr: "127.0.0.1:8000".parse().unwrap(), - stream: None, - } - } -} - -#[derive(Default, Debug, Clone)] -pub struct Stats { - pub bytes_sent: usize, - pub bytes_recv: usize, - pub broadcasts: usize, - pub to_king: usize, - pub from_king: usize, -} - -#[derive(Default, Debug)] -struct Connections { - id: usize, - peers: Vec, - stats: Stats, -} - -impl Connections { - /// Given a path and the `id` of oneself, initialize the structure - fn init_from_path(&mut self, path: &str, id: usize) { - let f = BufReader::new(File::open(path).expect("host configuration path")); - let mut peer_id = 0; - for line in f.lines() { - let line = line.unwrap(); - let trimmed = line.trim(); - if !trimmed.is_empty() { - let addr: SocketAddr = trimmed - .parse() - .unwrap_or_else(|e| panic!("bad socket address: {}:\n{}", trimmed, e)); - let peer = Peer { - id: peer_id, - addr, - stream: None, - }; - self.peers.push(peer); - peer_id += 1; - } - } - assert!(id < self.peers.len()); - self.id = id; - } - fn connect_to_all(&mut self) { - let timer = start_timer!(|| "Connecting"); - let n = self.peers.len(); - for from_id in 0..n { - for to_id in (from_id + 1)..n { - debug!("{} to {}", from_id, to_id); - if self.id == from_id { - let to_addr = self.peers[to_id].addr; - debug!("Contacting {}", to_id); - let stream = loop { - let mut ms_waited = 0; - match TcpStream::connect(to_addr) { - Ok(s) => break s, - Err(e) => match e.kind() { - std::io::ErrorKind::ConnectionRefused - | std::io::ErrorKind::ConnectionReset => { - ms_waited += 10; - std::thread::sleep(std::time::Duration::from_millis(10)); - if ms_waited % 3_000 == 0 { - debug!("Still waiting"); - } else if ms_waited > 30_000 { - panic!("Could not find peer in 30s"); - } - } - _ => { - panic!("Error during FieldChannel::new: {}", e); - } - }, - } - }; - stream.set_nodelay(true).unwrap(); - self.peers[to_id].stream = Some(stream); - } else if self.id == to_id { - debug!("Awaiting {}", from_id); - let listener = TcpListener::bind(self.peers[self.id].addr).unwrap(); - let (stream, _addr) = listener.accept().unwrap(); - stream.set_nodelay(true).unwrap(); - self.peers[from_id].stream = Some(stream); - } - } - // Sender for next round waits for note from this sender to prevent race on receipt. - if from_id + 1 < n { - if self.id == from_id { - self.peers[self.id + 1] - .stream - .as_mut() - .unwrap() - .write_all(&[0u8]) - .unwrap(); - } else if self.id == from_id + 1 { - self.peers[self.id - 1] - .stream - .as_mut() - .unwrap() - .read_exact(&mut [0u8]) - .unwrap(); - } - } - } - // Do a round with the king, to be sure everyone is ready - let from_all = self.send_to_king(&[self.id as u8]); - self.recv_from_king(from_all); - for id in 0..n { - if id != self.id { - assert!(self.peers[id].stream.is_some()); - } - } - end_timer!(timer); - } - fn am_king(&self) -> bool { - self.id == 0 - } - fn broadcast(&mut self, bytes_out: &[u8]) -> Vec> { - let timer = start_timer!(|| format!("Broadcast {}", bytes_out.len())); - let m = bytes_out.len(); - let own_id = self.id; - self.stats.bytes_sent += (self.peers.len() - 1) * m; - self.stats.bytes_recv += (self.peers.len() - 1) * m; - self.stats.broadcasts += 1; - let r = self - .peers - .par_iter_mut() - .enumerate() - .map(|(id, peer)| { - let mut bytes_in = vec![0u8; m]; - match id.cmp(&own_id) { - std::cmp::Ordering::Less => { - let stream = peer.stream.as_mut().unwrap(); - stream.read_exact(&mut bytes_in[..]).unwrap(); - stream.write_all(bytes_out).unwrap(); - } - std::cmp::Ordering::Equal => { - bytes_in.copy_from_slice(bytes_out); - } - std::cmp::Ordering::Greater => { - let stream = peer.stream.as_mut().unwrap(); - stream.write_all(bytes_out).unwrap(); - stream.read_exact(&mut bytes_in[..]).unwrap(); - } - } - bytes_in - }) - .collect(); - end_timer!(timer); - r - } - fn send_to_king(&mut self, bytes_out: &[u8]) -> Option>> { - let timer = start_timer!(|| format!("To king {}", bytes_out.len())); - let m = bytes_out.len(); - let own_id = self.id; - self.stats.to_king += 1; - let r = if self.am_king() { - self.stats.bytes_recv += (self.peers.len() - 1) * m; - Some( - self.peers - .par_iter_mut() - .enumerate() - .map(|(id, peer)| { - let mut bytes_in = vec![0u8; m]; - if id == own_id { - bytes_in.copy_from_slice(bytes_out); - } else { - let stream = peer.stream.as_mut().unwrap(); - stream.read_exact(&mut bytes_in[..]).unwrap(); - }; - bytes_in - }) - .collect(), - ) - } else { - self.stats.bytes_sent += m; - self.peers[0] - .stream - .as_mut() - .unwrap() - .write_all(bytes_out) - .unwrap(); - None - }; - end_timer!(timer); - r - } - fn recv_from_king(&mut self, bytes_out: Option>>) -> Vec { - let own_id = self.id; - self.stats.from_king += 1; - if self.am_king() { - let bytes_out = bytes_out.unwrap(); - let m = bytes_out[0].len(); - let timer = start_timer!(|| format!("From king {}", m)); - let bytes_size = (m as u64).to_le_bytes(); - self.stats.bytes_sent += (self.peers.len() - 1) * (m + 8); - self.peers - .par_iter_mut() - .enumerate() - .filter(|p| p.0 != own_id) - .for_each(|(id, peer)| { - let stream = peer.stream.as_mut().unwrap(); - assert_eq!(bytes_out[id].len(), m); - stream.write_all(&bytes_size).unwrap(); - stream.write_all(&bytes_out[id]).unwrap(); - }); - end_timer!(timer); - bytes_out[own_id].clone() - } else { - let stream = self.peers[0].stream.as_mut().unwrap(); - let mut bytes_size = [0u8; 8]; - stream.read_exact(&mut bytes_size).unwrap(); - let m = u64::from_le_bytes(bytes_size) as usize; - self.stats.bytes_recv += m; - let mut bytes_in = vec![0u8; m]; - stream.read_exact(&mut bytes_in).unwrap(); - bytes_in - } - } - fn uninit(&mut self) { - for p in &mut self.peers { - p.stream = None; - } - } -} - -pub trait MpcNet { - /// Am I the first party? - #[inline] - fn am_king() -> bool { - Self::party_id() == 0 - } - /// How many parties are there? - fn n_parties() -> usize; - /// What is my party number (0 to n-1)? - fn party_id() -> usize; - /// Initialize the network layer from a file. - /// The file should contain one HOST:PORT setting per line, corresponding to the addresses of - /// the parties in increasing order. - /// - /// Parties are zero-indexed. - fn init_from_file(path: &str, party_id: usize); - /// Is the network layer initalized? - fn is_init() -> bool; - /// Uninitialize the network layer, closing all connections. - fn deinit(); - /// Set statistics to zero. - fn reset_stats(); - /// Get statistics. - fn stats() -> Stats; - /// All parties send bytes to each other. - fn broadcast_bytes(bytes: &[u8]) -> Vec>; - /// All parties send bytes to the king. - fn send_bytes_to_king(bytes: &[u8]) -> Option>>; - /// All parties recv bytes from the king. - /// Provide bytes iff you're the king! - fn recv_bytes_from_king(bytes: Option>>) -> Vec; - - /// Everyone sends bytes to the king, who recieves those bytes, runs a computation on them, and - /// redistributes the resulting bytes. - /// - /// The king's computation is given by a function, `f` - /// proceeds. - #[inline] - fn king_compute(bytes: &[u8], f: impl Fn(Vec>) -> Vec>) -> Vec { - let king_response = Self::send_bytes_to_king(bytes).map(f); - Self::recv_bytes_from_king(king_response) - } - - fn uninit(); -} - -pub struct MpcMultiNet; - -impl MpcNet for MpcMultiNet { - #[inline] - fn party_id() -> usize { - get_ch!().id - } - - #[inline] - fn n_parties() -> usize { - get_ch!().peers.len() - } - - #[inline] - fn init_from_file(path: &str, party_id: usize) { - let mut ch = get_ch!(); - ch.init_from_path(path, party_id); - ch.connect_to_all(); - } - - #[inline] - fn is_init() -> bool { - get_ch!() - .peers - .first() - .map(|p| p.stream.is_some()) - .unwrap_or(false) - } - - #[inline] - fn deinit() { - get_ch!().uninit() - } - - #[inline] - fn reset_stats() { - get_ch!().stats = Stats::default(); - } - - #[inline] - fn stats() -> crate::Stats { - get_ch!().stats.clone() - } - - #[inline] - fn broadcast_bytes(bytes: &[u8]) -> Vec> { - get_ch!().broadcast(bytes) - } - - #[inline] - fn send_bytes_to_king(bytes: &[u8]) -> Option>> { - get_ch!().send_to_king(bytes) - } - - #[inline] - fn recv_bytes_from_king(bytes: Option>>) -> Vec { - get_ch!().recv_from_king(bytes) - } - - #[inline] - fn uninit() { - get_ch!().uninit() - } -} +pub use v2::*; \ No newline at end of file diff --git a/mpc-net/src/v2.rs b/mpc-net/src/v2.rs index a31673b6..17d9a4aa 100644 --- a/mpc-net/src/v2.rs +++ b/mpc-net/src/v2.rs @@ -1,4 +1,5 @@ pub mod multi; +pub use multi::*; use async_trait::async_trait; use auto_impl::auto_impl; diff --git a/mpc-net/src/v2/multi.rs b/mpc-net/src/v2/multi.rs index 4be3772d..46892123 100644 --- a/mpc-net/src/v2/multi.rs +++ b/mpc-net/src/v2/multi.rs @@ -8,7 +8,7 @@ use std::time::Duration; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, self}; use tokio::net::{TcpListener, TcpStream}; -use crate::{MPCNetError, MultiplexedStreamID}; +use crate::v2::{MPCNetError, MultiplexedStreamID}; use async_smux::{MuxBuilder, MuxStream}; use async_trait::async_trait; use futures::stream::{FuturesOrdered, FuturesUnordered}; diff --git a/src/bin_test_groth16.rs b/src/bin_test_groth16.rs index 89bd9044..f9bceca9 100644 --- a/src/bin_test_groth16.rs +++ b/src/bin_test_groth16.rs @@ -1,4 +1,4 @@ -use mpc_net::{MpcMultiNet as Net, MpcNet}; +use mpc_net::{LocalTestNet as Net, MPCNet}; use std::path::PathBuf; use structopt::StructOpt; diff --git a/src/bin_test_marlin.rs b/src/bin_test_marlin.rs index 140e16c3..494669cc 100644 --- a/src/bin_test_marlin.rs +++ b/src/bin_test_marlin.rs @@ -1,4 +1,4 @@ -use mpc_net::{MpcMultiNet as Net, MpcNet}; +use mpc_net::{LocalTestNet as Net, MPCNet}; use std::path::PathBuf; use structopt::StructOpt; diff --git a/src/bin_werewolf.rs b/src/bin_werewolf.rs index 343f02a0..2b870cd6 100644 --- a/src/bin_werewolf.rs +++ b/src/bin_werewolf.rs @@ -20,7 +20,7 @@ use serialize::{write_r, write_to_file}; use std::{fs::File, path::PathBuf}; use structopt::StructOpt; -use mpc_net::{MpcMultiNet as Net, MpcNet}; +use mpc_net::{LocalTestNet as Net, MPCNet}; mod marlin; use marlin::*; diff --git a/src/input.rs b/src/input.rs index 586faaf6..3f0b6e60 100644 --- a/src/input.rs +++ b/src/input.rs @@ -14,7 +14,7 @@ use ark_std::PubUniformRand; use ark_std::UniformRand; use derivative::Derivative; use mpc_algebra::{FieldShare, FromLocal, Reveal, ToLocal}; -use mpc_net::{MpcMultiNet as Net, MpcNet}; +use mpc_net::{LocalTestNet as Net, MPCNet}; use num_traits::One; use num_traits::Zero; use rand::Rng; diff --git a/src/marlin.rs b/src/marlin.rs index 5561cfe3..9a6ba601 100644 --- a/src/marlin.rs +++ b/src/marlin.rs @@ -10,7 +10,7 @@ use blake2::Blake2s; // use mpc_algebra::honest_but_curious::*; use mpc_algebra::malicious_majority::*; use mpc_algebra::{FromLocal, Reveal}; -use mpc_net::{MpcMultiNet, MpcNet}; +use mpc_net::{LocalTestNet, MPCNet}; use ark_std::{One, Zero}; @@ -206,7 +206,7 @@ pub fn mpc_test_prove_and_verify_pedersen(n_iters: usize) { //// input let x = MFr::rand(rng); - let input_bit = match MpcMultiNet::party_id() { + let input_bit = match LocalTestNet::party_id() { 0 => x .clone() .reveal() diff --git a/src/online.rs b/src/online.rs index cc32754c..44601d31 100644 --- a/src/online.rs +++ b/src/online.rs @@ -6,7 +6,7 @@ use ark_serialize::{CanonicalDeserialize, Read}; use ark_std::test_rng; use mpc_algebra::Reveal; -use mpc_net::{MpcMultiNet as Net, MpcNet}; +use mpc_net::{LocalTestNet as Net, MPCNet}; use serde::Deserialize; use std::{fs::File, path::PathBuf, vec};