//! Benchmarks for message decryption, //! comparing decryption of symmetrically-encrypted messages //! to decryption of asymmetrically-encrypted messages. //! //! Call with //! //! ```text //! cargo bench --bench decrypting --features="internals" //! ``` //! //! or, if you want to only run e.g. the 'Decrypt and parse a symmetrically encrypted message' benchmark: //! //! ```text //! cargo bench --bench decrypting --features="internals" -- 'Decrypt and parse a symmetrically encrypted message' //! ``` //! //! You can also pass a substring: //! //! ```text //! cargo bench --bench decrypting --features="internals" -- 'symmetrically' //! ``` //! //! Symmetric decryption has to try out all known secrets, //! You can benchmark this by adapting the `NUM_SECRETS` variable. use std::hint::black_box; use std::sync::LazyLock; use criterion::{Criterion, criterion_group, criterion_main}; use deltachat::internals_for_benches::create_broadcast_secret; use deltachat::internals_for_benches::save_broadcast_secret; use deltachat::securejoin::get_securejoin_qr; use deltachat::{ Events, chat::ChatId, config::Config, context::Context, internals_for_benches::key_from_asc, internals_for_benches::parse_and_get_text, internals_for_benches::store_self_keypair, stock_str::StockStrings, }; use tempfile::tempdir; static NUM_BROADCAST_SECRETS: LazyLock = LazyLock::new(|| { std::env::var("NUM_BROADCAST_SECRETS") .unwrap_or("500".to_string()) .parse() .unwrap() }); static NUM_AUTH_TOKENS: LazyLock = LazyLock::new(|| { std::env::var("NUM_AUTH_TOKENS") .unwrap_or("5000".to_string()) .parse() .unwrap() }); async fn create_context() -> Context { let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); let context = Context::new(dbfile.as_path(), 100, Events::new(), StockStrings::new()) .await .unwrap(); context .set_config(Config::ConfiguredAddr, Some("bob@example.net")) .await .unwrap(); let secret = key_from_asc(include_str!("../test-data/key/bob-secret.asc")).unwrap(); store_self_keypair(&context, &secret) .await .expect("Failed to save key"); context } fn criterion_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("Decrypt"); // =========================================================================================== // Benchmarks for the whole parsing pipeline, incl. decryption (but excl. receive_imf()) // =========================================================================================== let rt = tokio::runtime::Runtime::new().unwrap(); let mut secrets = generate_secrets(); // "secret" is the shared secret that was used to encrypt text_symmetrically_encrypted.eml. // Put it into the middle of our secrets: secrets[*NUM_BROADCAST_SECRETS / 2] = "secret".to_string(); let context = rt.block_on(async { let context = create_context().await; for (i, secret) in secrets.iter().enumerate() { save_broadcast_secret(&context, ChatId::new(10 + i as u32), secret) .await .unwrap(); } for _i in 0..*NUM_AUTH_TOKENS { get_securejoin_qr(&context, None).await.unwrap(); } println!("NUM_AUTH_TOKENS={}", *NUM_AUTH_TOKENS); context }); group.bench_function("Decrypt and parse a symmetrically encrypted message", |b| { b.to_async(&rt).iter(|| { let ctx = context.clone(); async move { let text = parse_and_get_text( &ctx, include_bytes!("../test-data/message/text_symmetrically_encrypted.eml"), ) .await .unwrap(); assert_eq!(black_box(text), "Symmetrically encrypted message"); } }); }); group.bench_function("Decrypt and parse a public-key encrypted message", |b| { b.to_async(&rt).iter(|| { let ctx = context.clone(); async move { let text = parse_and_get_text( &ctx, include_bytes!("../test-data/message/text_from_alice_encrypted.eml"), ) .await .unwrap(); assert_eq!(black_box(text), "hi"); } }); }); group.finish(); } fn generate_secrets() -> Vec { let secrets: Vec = (0..*NUM_BROADCAST_SECRETS) .map(|_| create_broadcast_secret()) .collect(); println!("NUM_BROADCAST_SECRETS={}", *NUM_BROADCAST_SECRETS); secrets } criterion_group!(benches, criterion_benchmark); criterion_main!(benches);