Skip to content

Commit 73556dd

Browse files
committed
feat(client_lib): bundle a crypto_selftest microbench triggered by env var
1 parent 9bc5210 commit 73556dd

6 files changed

Lines changed: 147 additions & 2 deletions

File tree

camera_hub/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

camera_hub/src/main.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,21 @@ struct Args {
131131
flag_save_all: bool,
132132
}
133133

134-
fn main() -> io::Result<()> {
134+
fn main() -> anyhow::Result<()> {
135135
let version = env!("CARGO_PKG_NAME").to_string() + ", version: " + env!("CARGO_PKG_VERSION");
136136
env_logger::init();
137137

138138
// ring TLS backend (armv6/Pi Zero W) needs provider installed before any HTTPS request
139139
#[cfg(feature = "crypto-ring")]
140140
secluso_client_lib::http_client::install_crypto_provider();
141141

142+
// SECLUSO_CRYPTO_SELFTEST=1 RUST_LOG=info /usr/bin/secluso-camera-hub
143+
// Runs MLS in hot loop on the otherwise idle process, then exits without starting the camera pipeline
144+
if std::env::var_os("SECLUSO_CRYPTO_SELFTEST").is_some() {
145+
secluso_client_lib::crypto_selftest::run()?;
146+
return Ok(());
147+
}
148+
142149
let args: Args = Docopt::new(USAGE)
143150
.map(|d| d.help(true))
144151
.map(|d| d.version(Some(version)))

client_lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ openmls_libcrux_crypto = "=0.3.1"
2424
openmls_memory_storage = { version = "=0.5.0", features = ["persistence"] }
2525
openmls_basic_credential = "=0.5.0"
2626
bincode = "1.3.3"
27+
libc = "0.2"
2728
reqwest = { version = "0.13", default-features = false, features = ["blocking", "multipart"], optional = true }
2829
rustls = { version = "0.23", default-features = false, features = ["std", "tls12", "logging"], optional = true }
2930
base64 = { version = "0.22.1", optional = true }

client_lib/src/crypto_selftest.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//! SPDX-License-Identifier: GPL-3.0-or-later
2+
//!
3+
//! Startup diagnostic (microbench) for MLS on constrained hardware (right now, testing the Pi Zero W, ARMv6)
4+
//! Runs the exact crypto the camera hub uses in a tight hot loop in an (otherwise) idle process.
5+
//! Reports wall time, thread CPU time, throughput
6+
7+
use crate::openmls_rust_persistent_crypto::OpenMlsRustPersistentCrypto;
8+
use anyhow::{anyhow, Context};
9+
use openmls::prelude::*;
10+
use openmls_basic_credential::SignatureKeyPair;
11+
use openmls_traits::crypto::OpenMlsCrypto;
12+
use openmls_traits::signatures::Signer;
13+
use openmls_traits::types::AeadType;
14+
use openmls_traits::OpenMlsProvider;
15+
use std::time::{Duration, Instant};
16+
17+
// Matches mls_client::CIPHERSUITE
18+
const CIPHERSUITE: Ciphersuite = Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519;
19+
const PAYLOAD_BYTES: usize = 64 * 1024;
20+
const ITERS: usize = 20;
21+
22+
/// Thread CPU time consumed so far (not wall time).
23+
/// Get the on-core cost, excluding time the scheduler gave to other threads.
24+
pub fn thread_cpu_time() -> anyhow::Result<Duration> {
25+
let mut ts = libc::timespec {
26+
tv_sec: 0,
27+
tv_nsec: 0,
28+
};
29+
let rc = unsafe { libc::clock_gettime(libc::CLOCK_THREAD_CPUTIME_ID, &raw mut ts) };
30+
if rc != 0 {
31+
return Ok(Duration::ZERO);
32+
}
33+
Ok(Duration::new(ts.tv_sec.cast_unsigned(), u32::try_from(ts.tv_nsec)?))
34+
}
35+
36+
fn report(name: &str, wall: Duration, cpu: Duration, bytes: usize) -> anyhow::Result<()> {
37+
let wall_ms = wall.as_secs_f64() * 1000.0f64 / f64::from(u32::try_from(ITERS)?);
38+
let cpu_ms = cpu.as_secs_f64() * 1000.0f64 / f64::from(u32::try_from(ITERS)?);
39+
let mb = f64::from(u32::try_from(bytes)?) / (1024.0f64 * 1024.0f64);
40+
let mbps = mb / (wall_ms / 1000.0f64);
41+
log::info!("{name} wall={wall_ms}ms cpu={cpu_ms}ms {mbps} MB/s");
42+
Ok(())
43+
}
44+
45+
/// Run the diagnostic at process startup if the caller passes the env var.
46+
pub fn run() -> anyhow::Result<()> {
47+
log::info!("payload={} kb, iters={}", PAYLOAD_BYTES / 1024, ITERS);
48+
49+
let provider = OpenMlsRustPersistentCrypto::default();
50+
let signer = SignatureKeyPair::new(CIPHERSUITE.signature_algorithm())?;
51+
signer.store(provider.storage())?;
52+
let credential = BasicCredential::new(b"secluso-selftest".to_vec());
53+
let credential_with_key = CredentialWithKey {
54+
credential: credential.into(),
55+
signature_key: signer.to_public_vec().into(),
56+
};
57+
let group_config = MlsGroupCreateConfig::builder()
58+
.ciphersuite(CIPHERSUITE)
59+
.use_ratchet_tree_extension(true)
60+
.build();
61+
let mut group = MlsGroup::new(&provider, &signer, &group_config, credential_with_key)?;
62+
63+
let payload = vec![0xABu8; PAYLOAD_BYTES];
64+
65+
// Raw ChaCha20Poly1305 seal
66+
{
67+
let key = vec![0u8; 32];
68+
let nonce = vec![0u8; 12];
69+
let aad = b"secluso-selftest";
70+
let _ =
71+
provider
72+
.crypto()
73+
.aead_encrypt(AeadType::ChaCha20Poly1305, &key, &payload, &nonce, aad);
74+
let w = Instant::now();
75+
let c = thread_cpu_time()?;
76+
for _ in 0..ITERS {
77+
let _ct = provider.crypto().aead_encrypt(
78+
AeadType::ChaCha20Poly1305,
79+
&key,
80+
&payload,
81+
&nonce,
82+
aad,
83+
)?;
84+
}
85+
report(
86+
"aead_seal",
87+
w.elapsed(),
88+
thread_cpu_time()?.checked_sub(c).context("failed to subtract s from thread cpu time")?,
89+
PAYLOAD_BYTES,
90+
)?;
91+
}
92+
93+
// Ed25519 signature over the full payload
94+
{
95+
let _ = signer.sign(&payload);
96+
let w = Instant::now();
97+
let c = thread_cpu_time()?;
98+
for _ in 0..ITERS {
99+
// SignerError does not have StdError trait
100+
if let Err(e) = signer.sign(&payload) {
101+
println!("{e:?}");
102+
return Err(anyhow!("Signer error."));
103+
}
104+
}
105+
report(
106+
"ed25519_sign",
107+
w.elapsed(),
108+
thread_cpu_time()?.checked_sub(c).context("failed to subtract s from thread cpu time")?,
109+
PAYLOAD_BYTES,
110+
)?;
111+
}
112+
113+
// MlsGroup::create_message
114+
{
115+
let _ = group.create_message(&provider, &signer, &payload);
116+
let w = Instant::now();
117+
let c = thread_cpu_time()?;
118+
for _ in 0..ITERS {
119+
let _m = group.create_message(&provider, &signer, &payload)?;
120+
}
121+
report(
122+
"create_message",
123+
w.elapsed(),
124+
thread_cpu_time()?.checked_sub(c).context("failed to subtract s from thread cpu time")?,
125+
PAYLOAD_BYTES,
126+
)?;
127+
}
128+
129+
log::info!("done");
130+
Ok(())
131+
}

client_lib/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! SPDX-License-Identifier: GPL-3.0-or-later
22
33
pub mod config;
4+
pub mod crypto_selftest;
45
pub mod identity;
56
pub mod mls_client;
67
pub mod mls_clients;

client_lib/src/mls_client.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
88
use super::identity::Identity;
99
use super::openmls_rust_persistent_crypto::OpenMlsRustPersistentCrypto;
10+
use crate::crypto_selftest::thread_cpu_time;
1011
use openmls_traits::{storage::StorageProvider as StorageProviderTrait};
1112
use crate::pairing;
1213
use openmls::prelude::*;
@@ -853,13 +854,16 @@ impl MlsClient {
853854
group.mls_group.set_aad(group_aad.as_bytes().to_vec());
854855

855856
let create_start = Instant::now();
857+
let create_cpu_start = thread_cpu_time().expect("thread cpu time failed");
856858
let message_out = group
857859
.mls_group
858860
.create_message(&self.provider, &self.identity.signer, bytes)
859861
.map_err(|e| io::Error::other(format!("{e}")))?;
862+
let create_cpu_end = thread_cpu_time().expect("thread cpu time failed");
860863
log::debug!(
861-
"encrypt: create_message took {}ms for {} input bytes",
864+
"encrypt: create_message took {}ms wall / {}ms cpu for {} input bytes",
862865
create_start.elapsed().as_millis(),
866+
(create_cpu_end - create_cpu_start).as_millis(),
863867
bytes.len()
864868
);
865869

0 commit comments

Comments
 (0)