Skip to content

Commit 8db537b

Browse files
committed
HTTPS test for sharded shuffle
This almost completes the setup for TLS/encryption infrastructure with one major exception - match key encryption keys are not re-used across shards. I have a PR almost ready, but decided to split that functionality to make PR somewhat revieweable
1 parent cf7efd4 commit 8db537b

File tree

12 files changed

+183
-144
lines changed

12 files changed

+183
-144
lines changed

ipa-core/src/app.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,6 @@ impl RequestHandler<HelperIdentity> for Inner {
220220
data: BodyStream,
221221
) -> Result<HelperResponse, ApiError> {
222222
let qp = &self.query_processor;
223-
224223
Ok(match req.route {
225224
r @ RouteId::Records => {
226225
return Err(ApiError::BadRequest(

ipa-core/src/bin/helper.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ pub async fn main() {
371371
let res = match args.command {
372372
None => server(args.server, handle).await,
373373
Some(HelperCommand::Keygen(args)) => keygen(&args),
374-
Some(HelperCommand::TestSetup(args)) => test_setup(args),
374+
Some(HelperCommand::TestSetup(args)) => test_setup(&args),
375375
Some(HelperCommand::Confgen(args)) => client_config_setup(args),
376376
Some(HelperCommand::ShardedConfgen(args)) => sharded_client_config_setup(args),
377377
};

ipa-core/src/cli/clientconf.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
},
1010
error::BoxError,
1111
helpers::HelperIdentity,
12+
sharding::ShardIndex,
1213
};
1314

1415
#[derive(Debug, Args)]
@@ -157,7 +158,7 @@ fn create_sharded_conf_from_files(
157158
let mut shard_dir = base_dir.clone();
158159
let id_nr: u8 = id.into();
159160
shard_dir.push(format!("helper{id_nr}"));
160-
shard_dir.push(format!("shard{ix}"));
161+
shard_dir.push(shard_conf_folder(ix));
161162

162163
let host_name = find_file_with_extension(&shard_dir, "pem").unwrap();
163164
let tls_cert_file = shard_dir.join(format!("{host_name}.pem"));
@@ -223,3 +224,7 @@ fn gen_conf_from_args(
223224
);
224225
Ok(())
225226
}
227+
228+
pub fn shard_conf_folder<I: TryInto<ShardIndex>>(shard_id: I) -> PathBuf {
229+
format!("shard{}", shard_id.try_into().ok().unwrap()).into()
230+
}

ipa-core/src/cli/config_parse.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ fn parse_sharded_network_toml(input: &str) -> Result<ShardedNetworkToml, Error>
123123

124124
/// Generates client configuration file at the requested destination. The destination must exist
125125
/// before this function is called
126-
pub fn gen_client_config(
127-
clients_conf: impl Iterator<Item = HelperClientConf>,
126+
pub fn gen_client_config<I: IntoIterator<Item = HelperClientConf>>(
127+
clients_conf: I,
128128
use_http1: bool,
129129
conf_file: &mut File,
130130
) -> Result<(), BoxError> {
@@ -352,7 +352,7 @@ pub fn sharded_server_from_toml_str(
352352
identities: shard_count.iter().collect(),
353353
};
354354
Ok((mpc_network, shard_network))
355-
} else if missing_urls == [0, 1, 2] && shard_count == ShardIndex(1) {
355+
} else if missing_urls == [0, 1, 2] && shard_count == ShardIndex::from(1) {
356356
// This is the special case we're dealing with a non-sharded, single ring MPC.
357357
// Since the shard network will be of size 1, it can't really communicate with anyone else.
358358
// Hence we just create a config where I'm the only shard. We take the MPC configuration

ipa-core/src/cli/test_setup.rs

Lines changed: 48 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use std::{
22
fs::{DirBuilder, File},
33
iter::zip,
4-
path::PathBuf,
4+
path::{Path, PathBuf},
55
};
66

77
use clap::Args;
88

9+
use super::clientconf::shard_conf_folder;
910
use crate::{
1011
cli::{
1112
config_parse::{gen_client_config, HelperClientConf},
@@ -66,7 +67,7 @@ impl TestSetupArgs {
6667
///
6768
/// # Panics
6869
/// If something that shouldn't happen goes wrong.
69-
pub fn test_setup(args: TestSetupArgs) -> Result<(), BoxError> {
70+
pub fn test_setup(args: &TestSetupArgs) -> Result<(), BoxError> {
7071
assert_eq!(
7172
args.ports.len(),
7273
args.shard_ports.len(),
@@ -97,96 +98,72 @@ pub fn test_setup(args: TestSetupArgs) -> Result<(), BoxError> {
9798
}
9899
}
99100

100-
fn sharded_keygen(args: TestSetupArgs) -> Result<(), BoxError> {
101-
let localhost = String::from("localhost");
102-
let keygen_args: Vec<_> = [1, 2, 3]
103-
.into_iter()
104-
.cycle()
105-
.take(args.ports.len())
106-
.enumerate()
107-
.map(|(i, id)| {
108-
let shard_dir = args.output_dir.join(format!("shard{i}"));
109-
DirBuilder::new().create(&shard_dir)?;
110-
Ok::<_, BoxError>(if i < 3 {
111-
// Only leader shards generate MK keys
112-
KeygenArgs {
113-
name: localhost.clone(),
114-
tls_cert: shard_dir.helper_tls_cert(id),
115-
tls_key: shard_dir.helper_tls_key(id),
116-
tls_expire_after: 365,
117-
mk_public_key: Some(shard_dir.helper_mk_public_key(id)),
118-
mk_private_key: Some(shard_dir.helper_mk_private_key(id)),
119-
}
120-
} else {
121-
KeygenArgs {
122-
name: localhost.clone(),
123-
tls_cert: shard_dir.helper_tls_cert(id),
124-
tls_key: shard_dir.helper_tls_key(id),
125-
tls_expire_after: 365,
126-
mk_public_key: None,
127-
mk_private_key: None,
128-
}
129-
})
130-
})
131-
.collect::<Result<_, _>>()?;
132-
133-
for ka in &keygen_args {
134-
keygen(ka)?;
135-
}
101+
fn sharded_keygen(args: &TestSetupArgs) -> Result<(), BoxError> {
102+
const RING_SIZE: usize = 3;
136103

104+
// we split all ports into chunks of 3 (for each MPC ring) and go over
105+
// all of them, creating configuration
137106
let clients_config: Vec<_> = zip(
138-
keygen_args.iter(),
139-
zip(
140-
keygen_args.clone().into_iter().take(3).cycle(),
141-
zip(args.ports, args.shard_ports),
142-
),
143-
)
144-
.map(
145-
|(keygen, (leader_keygen, (port, shard_port)))| HelperClientConf {
146-
host: localhost.to_string(),
147-
port,
148-
shard_port,
149-
tls_cert_file: keygen.tls_cert.clone(),
150-
mk_public_key_file: leader_keygen.mk_public_key.clone().unwrap(),
151-
},
107+
args.ports.chunks(RING_SIZE),
108+
args.shard_ports.chunks(RING_SIZE),
152109
)
153-
.collect();
110+
.enumerate()
111+
.flat_map(|(shard_id, (mpc_ports, shard_ports))| {
112+
let shard_dir = args.output_dir.join(shard_conf_folder(shard_id));
113+
DirBuilder::new().create(&shard_dir)?;
114+
make_client_configs(mpc_ports, shard_ports, &shard_dir)
115+
})
116+
.flatten()
117+
.collect::<Vec<_>>();
154118

155119
let mut conf_file = File::create(args.output_dir.join("network.toml"))?;
156-
gen_client_config(clients_config.into_iter(), args.use_http1, &mut conf_file)
120+
gen_client_config(clients_config, args.use_http1, &mut conf_file)
157121
}
158122

159123
/// This generates directories and files needed to run a non-sharded MPC.
160124
/// The directory structure is flattened and does not include per-shard configuration.
161-
fn non_sharded_keygen(args: TestSetupArgs) -> Result<(), BoxError> {
125+
fn non_sharded_keygen(args: &TestSetupArgs) -> Result<(), BoxError> {
126+
let client_configs = make_client_configs(&args.ports, &args.shard_ports, &args.output_dir)?;
127+
128+
let mut conf_file = File::create(args.output_dir.join("network.toml"))?;
129+
gen_client_config(client_configs, args.use_http1, &mut conf_file)
130+
}
131+
132+
fn make_client_configs(
133+
mpc_ports: &[u16],
134+
shard_ports: &[u16],
135+
config_dir: &Path,
136+
) -> Result<Vec<HelperClientConf>, BoxError> {
137+
assert_eq!(shard_ports.len(), mpc_ports.len());
138+
assert_eq!(3, shard_ports.len());
139+
162140
let localhost = String::from("localhost");
163-
let clients_config: [_; 3] = zip([1, 2, 3], zip(args.ports, args.shard_ports))
164-
.map(|(id, (port, shard_port))| {
141+
zip(mpc_ports.iter(), shard_ports.iter())
142+
.enumerate()
143+
.map(|(i, (&mpc_port, &shard_port))| {
144+
let id = u8::try_from(i + 1).unwrap();
145+
146+
// TODO: only leader shards should generate MK encryptions.
165147
let keygen_args = KeygenArgs {
166148
name: localhost.clone(),
167-
tls_cert: args.output_dir.helper_tls_cert(id),
168-
tls_key: args.output_dir.helper_tls_key(id),
149+
tls_cert: config_dir.helper_tls_cert(id),
150+
tls_key: config_dir.helper_tls_key(id),
169151
tls_expire_after: 365,
170-
mk_public_key: Some(args.output_dir.helper_mk_public_key(id)),
171-
mk_private_key: Some(args.output_dir.helper_mk_private_key(id)),
152+
mk_public_key: Some(config_dir.helper_mk_public_key(id)),
153+
mk_private_key: Some(config_dir.helper_mk_private_key(id)),
172154
};
173155

174156
keygen(&keygen_args)?;
175157

176158
Ok(HelperClientConf {
177159
host: localhost.to_string(),
178-
port,
160+
port: mpc_port,
179161
shard_port,
180162
tls_cert_file: keygen_args.tls_cert,
181163
mk_public_key_file: keygen_args.mk_public_key.unwrap(),
182164
})
183165
})
184-
.collect::<Result<Vec<_>, BoxError>>()?
185-
.try_into()
186-
.unwrap();
187-
188-
let mut conf_file = File::create(args.output_dir.join("network.toml"))?;
189-
gen_client_config(clients_config.into_iter(), args.use_http1, &mut conf_file)
166+
.collect::<Result<_, _>>()
190167
}
191168

192169
#[cfg(test)]
@@ -212,7 +189,7 @@ mod tests {
212189
ports: vec![3000, 3001, 3002, 3003, 3004, 3005],
213190
shard_ports: vec![6000, 6001, 6002, 6003, 6004, 6005],
214191
};
215-
test_setup(args).unwrap();
192+
test_setup(&args).unwrap();
216193
let network_config_path = outdir.join("network.toml");
217194
let network_config_string = &fs::read_to_string(network_config_path).unwrap();
218195
let _r = sharded_server_from_toml_str(
@@ -237,7 +214,7 @@ mod tests {
237214
ports: vec![],
238215
shard_ports: vec![],
239216
};
240-
test_setup(args).unwrap();
217+
test_setup(&args).unwrap();
241218
}
242219

243220
#[test]
@@ -252,6 +229,6 @@ mod tests {
252229
ports: vec![3000, 3001],
253230
shard_ports: vec![6000, 6001, 6002],
254231
};
255-
test_setup(args).unwrap();
232+
test_setup(&args).unwrap();
256233
}
257234
}

ipa-core/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,6 @@ mod tests {
602602
let pc1 = PeerConfig::new(uri1, None);
603603
let client = ClientConfig::default();
604604
let conf = NetworkConfig::new_shards(vec![pc1.clone()], client);
605-
assert_eq!(conf.peers[ShardIndex(0)].url, pc1.url);
605+
assert_eq!(conf.peers[ShardIndex::FIRST].url, pc1.url);
606606
}
607607
}

ipa-core/src/net/test.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl TestNetwork<Shard> {
138138
/// Creates all the shards for a helper and creates a network.
139139
fn new_shards(id: HelperIdentity, ports: Vec<Option<u16>>, conf: &TestConfigBuilder) -> Self {
140140
let servers: Vec<_> = (0..conf.shard_count)
141-
.map(ShardIndex)
141+
.map(ShardIndex::from)
142142
.zip(ports)
143143
.map(|(ix, p)| {
144144
let sid = ShardedHelperIdentity::new(id, ix);
@@ -296,7 +296,7 @@ impl TestConfig {
296296
/// Creates a new [`TestConfig`] using the provided configuration.
297297
fn new(conf: &TestConfigBuilder) -> Self {
298298
let rings = (0..conf.shard_count)
299-
.map(ShardIndex)
299+
.map(ShardIndex::from)
300300
.map(|s| {
301301
let ports = conf.get_ports_for_shard_index(s);
302302
TestNetwork::<Helper>::new_mpc(s, ports, conf)
@@ -1049,7 +1049,7 @@ mod tests {
10491049
let builder = TestConfigBuilder::with_http_and_default_test_ports();
10501050
assert_eq!(
10511051
vec![Some(3000), Some(3001), Some(3002)],
1052-
builder.get_ports_for_shard_index(ShardIndex(0))
1052+
builder.get_ports_for_shard_index(ShardIndex::FIRST)
10531053
);
10541054
assert_eq!(
10551055
vec![Some(6001)],
@@ -1060,6 +1060,9 @@ mod tests {
10601060
#[test]
10611061
fn get_os_ports() {
10621062
let builder = TestConfigBuilder::default();
1063-
assert_eq!(3, builder.get_ports_for_shard_index(ShardIndex(0)).len());
1063+
assert_eq!(
1064+
3,
1065+
builder.get_ports_for_shard_index(ShardIndex::FIRST).len()
1066+
);
10641067
}
10651068
}

ipa-core/src/protocol/hybrid/agg.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ pub mod test {
187187
// the inputs are laid out to work with exactly 2 shards
188188
// as if it we're resharded by match_key/prf
189189
const SHARDS: usize = 2;
190+
const SECOND_SHARD: ShardIndex = ShardIndex::from_u32(1);
190191

191192
// we re-use these as the "prf" of the match_key
192193
// to avoid needing to actually do the prf here
@@ -374,8 +375,8 @@ pub mod test {
374375
let results: Vec<[Vec<[AggregateableHybridReport<BA8, BA3>; 2]>; 3]> = world
375376
.malicious(records.clone().into_iter(), |ctx, input| {
376377
let match_keys = match ctx.shard_id() {
377-
ShardIndex(0) => SHARD1_MKS,
378-
ShardIndex(1) => SHARD2_MKS,
378+
ShardIndex::FIRST => SHARD1_MKS,
379+
SECOND_SHARD => SHARD2_MKS,
379380
_ => panic!("invalid shard_id"),
380381
};
381382
async move {
@@ -446,8 +447,8 @@ pub mod test {
446447
let results: Vec<[Vec<AggregateableHybridReport<BA8, BA3>>; 3]> = world
447448
.malicious(records.clone().into_iter(), |ctx, input| {
448449
let match_keys = match ctx.shard_id() {
449-
ShardIndex(0) => SHARD1_MKS,
450-
ShardIndex(1) => SHARD2_MKS,
450+
ShardIndex::FIRST => SHARD1_MKS,
451+
SECOND_SHARD => SHARD2_MKS,
451452
_ => panic!("invalid shard_id"),
452453
};
453454
async move {
@@ -572,8 +573,8 @@ pub mod test {
572573
let _results: Vec<[Vec<AggregateableHybridReport<BA8, BA3>>; 3]> = world
573574
.malicious(records.clone().into_iter(), |ctx, input| {
574575
let match_keys = match ctx.shard_id() {
575-
ShardIndex(0) => SHARD1_MKS,
576-
ShardIndex(1) => SHARD2_MKS,
576+
ShardIndex::FIRST => SHARD1_MKS,
577+
SECOND_SHARD => SHARD2_MKS,
577578
_ => panic!("invalid shard_id"),
578579
};
579580
async move {

0 commit comments

Comments
 (0)