Skip to content

Commit

Permalink
Merge branch 'tor-proto_benchmarks' into 'main'
Browse files Browse the repository at this point in the history
tor-proto: Add benchmarks for cell encryption and decryption

See merge request tpo/core/arti!2608
  • Loading branch information
gabi-250 committed Nov 11, 2024
2 parents 54830ca + 96839d3 commit 4a04490
Show file tree
Hide file tree
Showing 12 changed files with 827 additions and 23 deletions.
207 changes: 184 additions & 23 deletions Cargo.lock

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions crates/tor-proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ full = [
experimental = ["experimental-api", "ntor_v3", "stream-ctrl", "testing"]
ntor_v3 = ["__is_experimental"]

bench = []
hs-client = ["hs-common"]
hs-service = ["hs-common"]
hs-common = ["tor-hscrypto"]
Expand Down Expand Up @@ -100,6 +101,8 @@ void = "1"
zeroize = "1"

[dev-dependencies]
cpu-time = "1.0.0"
criterion = "0.5.1"
hex = "0.4"
hex-literal = "0.4"
humantime = "2"
Expand All @@ -110,3 +113,23 @@ tokio-crate = { package = "tokio", version = "1.7", features = ["full"] }
tor-rtcompat = { path = "../tor-rtcompat", version = "0.24.0", features = ["tokio", "native-tls"] }
[package.metadata.docs.rs]
all-features = true

[[bench]]
name = "cell_decrypt"
harness = false
required-features = ["bench"]

[[bench]]
name = "cell_encrypt"
harness = false
required-features = ["bench"]

[[bench]]
name = "cell_is_recognized"
harness = false
required-features = ["bench"]

[[bench]]
name = "cell_set_digest"
harness = false
required-features = ["bench"]
97 changes: 97 additions & 0 deletions crates/tor-proto/benches/cell_decrypt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use cipher::{KeyIvInit, StreamCipher};
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use digest::Digest;
use rand::prelude::*;

use tor_bytes::SecretBuf;
use tor_cell::relaycell::{RelayCellFormatTrait, RelayCellFormatV0};
use tor_llcrypto::{
cipher::aes::{Aes128Ctr, Aes256Ctr},
d::{Sha1, Sha256},
};
use tor_proto::bench_utils::{
client_decrypt, encrypt_inbound, HopCryptState, InboundCryptWrapper, RelayBody,
};

mod cpu_time;
use cpu_time::*;

// Helper macro to setup a full circuit decryption benchmark.
macro_rules! full_circuit_inbound_setup {
($sc:ty, $d:ty, $f:ty) => {{
let seed1: SecretBuf = b"hidden we are free".to_vec().into();
let seed2: SecretBuf = b"free to speak, to free ourselves".to_vec().into();
let seed3: SecretBuf = b"free to hide no more".to_vec().into();

let mut rng = thread_rng();

let mut circuit_sates = [
HopCryptState::construct(seed1.clone()).unwrap(),
HopCryptState::construct(seed2.clone()).unwrap(),
HopCryptState::construct(seed3.clone()).unwrap(),
];

let mut cc_in = InboundCryptWrapper::new();
cc_in.add_layer_from_seed::<$sc, $d, $f>(seed1).unwrap();
cc_in.add_layer_from_seed::<$sc, $d, $f>(seed2).unwrap();
cc_in.add_layer_from_seed::<$sc, $d, $f>(seed3).unwrap();

let cell = create_inbound_cell::<$sc, $d, $f>(&mut rng, &mut circuit_sates);
(cell, cc_in)
}};
}

/// Encrypt a random cell using the given circuit crypt states
/// as if it were an inbound cell encrypted by each router in the circuit.
fn create_inbound_cell<
SC: StreamCipher + KeyIvInit,
D: Digest + Clone,
RCF: RelayCellFormatTrait,
>(
rng: &mut ThreadRng,
circuit_crypt_states: &mut [HopCryptState<SC, D, RCF>],
) -> RelayBody {
let mut cell = [0u8; 509];
rng.fill(&mut cell[..]);
let mut cell: RelayBody = cell.into();

encrypt_inbound(&mut cell, circuit_crypt_states);

cell
}

/// Benchmark the `client_decrypt` function.
pub fn cell_decrypt_benchmark(c: &mut Criterion<CpuTime>) {
let mut group = c.benchmark_group("cell_decrypt");
group.throughput(Throughput::Bytes(509));

group.bench_function("cell_decrypt_Tor1RelayCrypto", |b| {
b.iter_batched_ref(
|| full_circuit_inbound_setup!(Aes128Ctr, Sha1, RelayCellFormatV0),
|(cell, cc_in)| {
client_decrypt(cell, cc_in).unwrap();
},
criterion::BatchSize::SmallInput,
);
});

group.bench_function("cell_decrypt_Tor1Hsv3RelayCrypto", |b| {
b.iter_batched_ref(
|| full_circuit_inbound_setup!(Aes256Ctr, Sha256, RelayCellFormatV0),
|(cell, cc_in)| {
client_decrypt(cell, cc_in).unwrap();
},
criterion::BatchSize::SmallInput,
);
});

group.finish();
}

criterion_group!(
name = cell_decrypt;
config = Criterion::default()
.with_measurement(CpuTime)
.sample_size(5000);
targets = cell_decrypt_benchmark);
criterion_main!(cell_decrypt);
76 changes: 76 additions & 0 deletions crates/tor-proto/benches/cell_encrypt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use rand::prelude::*;

use tor_bytes::SecretBuf;
use tor_cell::relaycell::RelayCellFormatV0;
use tor_llcrypto::{
cipher::aes::{Aes128Ctr, Aes256Ctr},
d::{Sha1, Sha256},
};
use tor_proto::bench_utils::{client_encrypt, OutboundCryptWrapper, RelayBody};

mod cpu_time;
use cpu_time::*;

const HOP_NUM: u8 = 2;

/// Helper macro to setup a full circuit encryption benchmark.
macro_rules! full_circuit_outbound_setup {
($sc:ty, $d:ty, $f:ty) => {{
let seed1: SecretBuf = b"hidden we are free".to_vec().into();
let seed2: SecretBuf = b"free to speak, to free ourselves".to_vec().into();
let seed3: SecretBuf = b"free to hide no more".to_vec().into();

let mut cc_out = OutboundCryptWrapper::new();
cc_out.add_layer_from_seed::<$sc, $d, $f>(seed1).unwrap();
cc_out.add_layer_from_seed::<$sc, $d, $f>(seed2).unwrap();
cc_out.add_layer_from_seed::<$sc, $d, $f>(seed3).unwrap();

let mut rng = rand::thread_rng();
let cell = create_outbound_cell(&mut rng);
(cell, cc_out)
}};
}

/// Create a random outbound cell.
fn create_outbound_cell(rng: &mut ThreadRng) -> RelayBody {
let mut cell = [0u8; 509];
rng.fill(&mut cell[..]);
cell.into()
}

/// Benchmark the `client_encrypt` function.
pub fn cell_encrypt_benchmark(c: &mut Criterion<CpuTime>) {
let mut group = c.benchmark_group("cell_encrypt");
group.throughput(Throughput::Bytes(509));

group.bench_function("cell_encrypt_Tor1RelayCrypto", |b| {
b.iter_batched_ref(
|| full_circuit_outbound_setup!(Aes128Ctr, Sha1, RelayCellFormatV0),
|(cell, cc_out)| {
client_encrypt(cell, cc_out, HOP_NUM).unwrap();
},
criterion::BatchSize::SmallInput,
);
});

group.bench_function("cell_encrypt_Tor1Hsv3RelayCrypto", |b| {
b.iter_batched_ref(
|| full_circuit_outbound_setup!(Aes256Ctr, Sha256, RelayCellFormatV0),
|(cell, cc_out)| {
client_encrypt(cell, cc_out, HOP_NUM).unwrap();
},
criterion::BatchSize::SmallInput,
);
});

group.finish();
}

criterion_group!(
name = cell_encrypt;
config = Criterion::default()
.with_measurement(CpuTime)
.sample_size(5000);
targets = cell_encrypt_benchmark);
criterion_main!(cell_encrypt);
73 changes: 73 additions & 0 deletions crates/tor-proto/benches/cell_is_recognized.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use criterion::{criterion_group, criterion_main, Criterion};
use digest::{generic_array::GenericArray, Digest};
use rand::prelude::*;

use tor_cell::relaycell::{RelayCellFormatTrait, RelayCellFormatV0};
use tor_llcrypto::d::{Sha1, Sha3_256};
use tor_proto::bench_utils::RelayBody;

mod cpu_time;
use cpu_time::*;

/// Create a random inbound cell with the digest computed.
fn create_digested_cell<D: Digest + Clone, RCF: RelayCellFormatTrait>(
rng: &mut ThreadRng,
d: &mut D,
) -> RelayBody {
let mut cell = [0u8; 509];
rng.fill(&mut cell[..]);
let mut cell: RelayBody = cell.into();
let mut used_digest = GenericArray::default();

cell.set_digest::<_, RCF>(d, &mut used_digest);

cell
}

/// Benchmark the `client_decrypt` function.
pub fn cell_is_recognized_benchmark(c: &mut Criterion<CpuTime>) {
let mut group = c.benchmark_group("cell_is_recognized");
group.throughput(criterion::Throughput::Bytes(509));

group.bench_function("cell_is_recognized_Tor1RelayCrypto", |b| {
b.iter_batched_ref(
|| {
let mut rng = rand::thread_rng();
let mut d = Sha1::new();

let cell = create_digested_cell::<_, RelayCellFormatV0>(&mut rng, &mut d);
(cell, Sha1::new(), GenericArray::default())
},
|(cell, d, rcvd)| {
cell.is_recognized::<_, RelayCellFormatV0>(d, rcvd);
},
criterion::BatchSize::SmallInput,
);
});

group.bench_function("cell_is_recognized_Tor1Hsv3RelayCrypto", |b| {
b.iter_batched_ref(
|| {
let mut rng = rand::thread_rng();
let mut d = Sha3_256::new();

let cell = create_digested_cell::<_, RelayCellFormatV0>(&mut rng, &mut d);
(cell, Sha3_256::new(), GenericArray::default())
},
|(cell, d, rcvd)| {
cell.is_recognized::<_, RelayCellFormatV0>(d, rcvd);
},
criterion::BatchSize::SmallInput,
);
});

group.finish();
}

criterion_group!(
name = cell_is_recognized;
config = Criterion::default()
.with_measurement(CpuTime)
.sample_size(5000);
targets = cell_is_recognized_benchmark);
criterion_main!(cell_is_recognized);
63 changes: 63 additions & 0 deletions crates/tor-proto/benches/cell_set_digest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use criterion::{criterion_group, criterion_main, Criterion};
use digest::{generic_array::GenericArray, Digest};
use rand::prelude::*;

use tor_cell::relaycell::RelayCellFormatV0;
use tor_llcrypto::d::{Sha1, Sha3_256};
use tor_proto::bench_utils::RelayBody;

mod cpu_time;
use cpu_time::*;

/// Create a random inbound cell with the digest computed.
fn create_random_cell(rng: &mut ThreadRng) -> RelayBody {
let mut cell = [0u8; 509];
rng.fill(&mut cell[..]);
cell.into()
}

/// Benchmark the `client_decrypt` function.
pub fn cell_set_digest_benchmark(c: &mut Criterion<CpuTime>) {
let mut group = c.benchmark_group("cell_set_digest");
group.throughput(criterion::Throughput::Bytes(509));

group.bench_function("cell_set_digest_Tor1RelayCrypto", |b| {
b.iter_batched_ref(
|| {
let mut rng = rand::thread_rng();

let cell = create_random_cell(&mut rng);
(cell, Sha1::new(), GenericArray::default())
},
|(cell, d, used_digest)| {
cell.set_digest::<_, RelayCellFormatV0>(d, used_digest);
},
criterion::BatchSize::SmallInput,
);
});

group.bench_function("cell_set_digest_Tor1Hsv3RelayCrypto", |b| {
b.iter_batched_ref(
|| {
let mut rng = rand::thread_rng();

let cell = create_random_cell(&mut rng);
(cell, Sha3_256::new(), GenericArray::default())
},
|(cell, d, used_digest)| {
cell.set_digest::<_, RelayCellFormatV0>(d, used_digest);
},
criterion::BatchSize::SmallInput,
);
});

group.finish();
}

criterion_group!(
name = cell_set_digest;
config = Criterion::default()
.with_measurement(CpuTime)
.sample_size(5000);
targets = cell_set_digest_benchmark);
criterion_main!(cell_set_digest);
Loading

0 comments on commit 4a04490

Please sign in to comment.