crypto_speed/
crypto_speed.rs

1use std::env::args;
2use std::fs::File;
3use std::io::{Read, Seek, Write};
4use std::path::Path;
5use std::sync::Arc;
6use std::time::Instant;
7use std::{fs, io};
8
9use anyhow::Result;
10use rand_core::RngCore;
11use shush_rs::SecretVec;
12
13use rencfs::crypto;
14use rencfs::crypto::write::{CryptoInnerWriter, CryptoWrite};
15use rencfs::crypto::Cipher;
16
17#[tokio::main]
18async fn main() -> Result<()> {
19    tracing_subscriber::fmt().init();
20
21    let cipher = Cipher::ChaCha20Poly1305;
22    let key = Arc::new(get_key(cipher)?);
23
24    println!("chacha\n");
25
26    let mut args = args();
27    let _ = args.next(); // skip the program name
28    let path_in = args.next().expect("path_in is missing");
29    let path_out = format!(
30        "/tmp/{}.enc",
31        Path::new(&path_in).file_name().unwrap().to_str().unwrap()
32    );
33    let out = Path::new(&path_out).to_path_buf();
34    if out.exists() {
35        fs::remove_file(&out)?;
36    }
37
38    stream_speed(&path_in, &path_out, cipher, &key)?;
39    println!();
40    file_speed(&path_in, &path_out, cipher, &key)?;
41
42    let cipher = Cipher::Aes256Gcm;
43    let key = Arc::new(get_key(cipher)?);
44
45    println!("\naesgcm\n");
46
47    stream_speed(&path_in, &path_out, cipher, &key)?;
48    println!();
49    file_speed(&path_in, &path_out, cipher, &key)?;
50
51    Ok(())
52}
53
54fn speed<F>(f: F, label: &str, size: u64) -> io::Result<()>
55where
56    F: FnOnce() -> io::Result<()>,
57{
58    let start = Instant::now();
59    f()?;
60    let duration = start.elapsed();
61    println!(
62        "{label} duration = {:?}, speed MB/s {:.2}",
63        duration,
64        (size as f64 / duration.as_secs_f64()) / 1024.0 / 1024.0
65    );
66    Ok(())
67}
68
69fn check_hash(r1: &mut impl Read, r2: &mut (impl Read + ?Sized)) -> Result<()> {
70    let hash1 = crypto::hash_reader(r1)?;
71    let hash2 = crypto::hash_reader(r2)?;
72    assert_eq!(hash1, hash2);
73    Ok(())
74}
75
76fn stream_speed(
77    path_in: &str,
78    path_out: &str,
79    cipher: Cipher,
80    key: &Arc<SecretVec<u8>>,
81) -> Result<()> {
82    println!("stream speed");
83    let _ = fs::remove_file(path_out);
84    let mut file_in = File::open(path_in)?;
85    let file_out = File::create(path_out)?;
86    let path_out2 = Path::new(&path_out).to_path_buf().with_extension("dec");
87    let _ = fs::remove_file(path_out2.clone());
88    let mut file_out2 = File::create(path_out2.clone())?;
89    let mut writer = crypto::create_write(file_out, cipher, key);
90    let size = file_in.metadata()?.len();
91    let f = || crypto::create_read(File::open(path_out).unwrap(), cipher, key);
92    test_speed(&mut file_in, &mut writer, &mut file_out2, size, f)?;
93    file_in.seek(io::SeekFrom::Start(0))?;
94    check_hash(&mut file_in, &mut f())?;
95    fs::remove_file(path_out)?;
96    fs::remove_file(path_out2)?;
97    Ok(())
98}
99
100fn file_speed(path_in: &str, path_out: &str, cipher: Cipher, key: &SecretVec<u8>) -> Result<()> {
101    println!("file speed");
102    let _ = fs::remove_file(path_out);
103    let mut file_in = File::open(path_in)?;
104    let mut writer = crypto::create_write(File::create(Path::new(path_out))?, cipher, key);
105    let path_out2 = Path::new(&path_out).to_path_buf().with_extension("dec");
106    let _ = fs::remove_file(path_out2.clone());
107    let mut file_out2 = File::create(path_out2.clone())?;
108    let size = file_in.metadata()?.len();
109    let f = || crypto::create_read(File::open(path_out).unwrap(), cipher, key);
110    test_speed(&mut file_in, &mut writer, &mut file_out2, size, f)?;
111    file_in.seek(io::SeekFrom::Start(0)).unwrap();
112    check_hash(&mut file_in, &mut f())?;
113    fs::remove_file(path_out)?;
114    fs::remove_file(path_out2)?;
115    Ok(())
116}
117
118fn test_speed<W: CryptoInnerWriter + Send + Sync, R: Read + Send + Sync, FR>(
119    r: &mut impl Read,
120    w: &mut (impl CryptoWrite<W> + ?Sized),
121    w2: &mut impl Write,
122    size: u64,
123    r2: FR,
124) -> io::Result<()>
125where
126    FR: FnOnce() -> R,
127{
128    let mut r = io::BufReader::new(r);
129    let mut w = io::BufWriter::new(w);
130    speed(
131        || {
132            io::copy(&mut r, &mut w)?;
133            w.into_inner()
134                .map_err(|err| {
135                    let (err, _) = err.into_parts();
136                    err
137                })?
138                .finish()?;
139            Ok(())
140        },
141        "write",
142        size,
143    )?;
144    speed(
145        || {
146            io::copy(&mut r2(), w2)?;
147            w2.flush()?;
148            Ok(())
149        },
150        "read",
151        size,
152    )?;
153    Ok(())
154}
155
156fn get_key(cipher: Cipher) -> io::Result<SecretVec<u8>> {
157    let mut key = vec![0; cipher.key_len()];
158    crypto::create_rng().fill_bytes(key.as_mut_slice());
159    Ok(SecretVec::from(key))
160}