1 //! Development-related functionality 2 3 /// Test core functionality of synchronous stream cipher 4 #[macro_export] 5 #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] 6 macro_rules! stream_cipher_test { 7 ($name:ident, $cipher:ty, $test_name:expr) => { 8 #[test] 9 fn $name() { 10 use cipher::generic_array::GenericArray; 11 use cipher::{blobby::Blob4Iterator, NewCipher, StreamCipher}; 12 13 let data = include_bytes!(concat!("data/", $test_name, ".blb")); 14 for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() { 15 let [key, iv, pt, ct] = row.unwrap(); 16 17 for chunk_n in 1..256 { 18 let mut mode = <$cipher>::new_from_slices(key, iv).unwrap(); 19 let mut pt = pt.to_vec(); 20 for chunk in pt.chunks_mut(chunk_n) { 21 mode.apply_keystream(chunk); 22 } 23 if pt != &ct[..] { 24 panic!( 25 "Failed main test №{}, chunk size: {}\n\ 26 key:\t{:?}\n\ 27 iv:\t{:?}\n\ 28 plaintext:\t{:?}\n\ 29 ciphertext:\t{:?}\n", 30 i, chunk_n, key, iv, pt, ct, 31 ); 32 } 33 } 34 } 35 } 36 }; 37 } 38 39 /// Test stream synchronous stream cipher seeking capabilities 40 #[macro_export] 41 #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] 42 macro_rules! stream_cipher_seek_test { 43 ($name:ident, $cipher:ty) => { 44 #[test] 45 fn $name() { 46 use cipher::generic_array::GenericArray; 47 use cipher::{NewCipher, StreamCipher, StreamCipherSeek}; 48 49 fn get_cipher() -> $cipher { 50 <$cipher>::new(&Default::default(), &Default::default()) 51 } 52 53 const MAX_SEEK: usize = 512; 54 55 let mut ct = [0u8; MAX_SEEK]; 56 get_cipher().apply_keystream(&mut ct[..]); 57 58 for n in 0..MAX_SEEK { 59 let mut cipher = get_cipher(); 60 assert_eq!(cipher.current_pos::<usize>(), 0); 61 cipher.seek(n); 62 assert_eq!(cipher.current_pos::<usize>(), n); 63 let mut buf = [0u8; MAX_SEEK]; 64 cipher.apply_keystream(&mut buf[n..]); 65 assert_eq!(cipher.current_pos::<usize>(), MAX_SEEK); 66 assert_eq!(&buf[n..], &ct[n..]); 67 } 68 69 const MAX_CHUNK: usize = 128; 70 const MAX_LEN: usize = 1024; 71 72 let mut buf = [0u8; MAX_CHUNK]; 73 let mut cipher = get_cipher(); 74 assert_eq!(cipher.current_pos::<usize>(), 0); 75 cipher.apply_keystream(&mut []); 76 assert_eq!(cipher.current_pos::<usize>(), 0); 77 for n in 1..MAX_CHUNK { 78 assert_eq!(cipher.current_pos::<usize>(), 0); 79 for m in 1.. { 80 cipher.apply_keystream(&mut buf[..n]); 81 assert_eq!(cipher.current_pos::<usize>(), n * m); 82 if n * m > MAX_LEN { 83 break; 84 } 85 } 86 cipher.seek(0); 87 } 88 } 89 }; 90 } 91 92 /// Test core functionality of asynchronous stream cipher 93 #[macro_export] 94 #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] 95 macro_rules! stream_cipher_async_test { 96 ($name:ident, $test_name:expr, $cipher:ty) => { 97 #[test] 98 fn $name() { 99 use cipher::generic_array::GenericArray; 100 use cipher::{blobby::Blob4Iterator, AsyncStreamCipher, NewCipher}; 101 102 fn run_test( 103 key: &[u8], 104 iv: &[u8], 105 plaintext: &[u8], 106 ciphertext: &[u8], 107 ) -> Option<&'static str> { 108 for n in 1..=plaintext.len() { 109 let mut mode = <$cipher>::new_from_slices(key, iv).unwrap(); 110 let mut buf = plaintext.to_vec(); 111 for chunk in buf.chunks_mut(n) { 112 mode.encrypt(chunk); 113 } 114 if buf != &ciphertext[..] { 115 return Some("encrypt"); 116 } 117 } 118 119 for n in 1..=plaintext.len() { 120 let mut mode = <$cipher>::new_from_slices(key, iv).unwrap(); 121 let mut buf = ciphertext.to_vec(); 122 for chunk in buf.chunks_mut(n) { 123 mode.decrypt(chunk); 124 } 125 if buf != &plaintext[..] { 126 return Some("decrypt"); 127 } 128 } 129 130 None 131 } 132 133 let data = include_bytes!(concat!("data/", $test_name, ".blb")); 134 135 for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() { 136 let [key, iv, pt, ct] = row.unwrap(); 137 if let Some(desc) = run_test(key, iv, pt, ct) { 138 panic!( 139 "\n\ 140 Failed test №{}: {}\n\ 141 key:\t{:?}\n\ 142 iv:\t{:?}\n\ 143 plaintext:\t{:?}\n\ 144 ciphertext:\t{:?}\n", 145 i, desc, key, iv, pt, ct, 146 ); 147 } 148 } 149 } 150 }; 151 } 152 153 /// Create synchronous stream cipher benchmarks 154 #[macro_export] 155 #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] 156 macro_rules! stream_cipher_sync_bench { 157 ($name:ident, $cipher:path, $data_len:expr) => { 158 #[bench] 159 pub fn $name(bh: &mut Bencher) { 160 let key = Default::default(); 161 let nonce = Default::default(); 162 let mut cipher = <$cipher>::new(&key, &nonce); 163 let mut data = get_data($data_len); 164 165 bh.iter(|| { 166 cipher.apply_keystream(&mut data); 167 test::black_box(&data); 168 }); 169 bh.bytes = data.len() as u64; 170 } 171 }; 172 ($cipher:path) => { 173 extern crate test; 174 175 use cipher::{generic_array::GenericArray, NewCipher, StreamCipher}; 176 use test::Bencher; 177 178 #[inline(never)] 179 fn get_data(n: usize) -> Vec<u8> { 180 vec![77; n] 181 } 182 183 $crate::stream_cipher_sync_bench!(bench1_10, $cipher, 10); 184 $crate::stream_cipher_sync_bench!(bench2_100, $cipher, 100); 185 $crate::stream_cipher_sync_bench!(bench3_1000, $cipher, 1000); 186 $crate::stream_cipher_sync_bench!(bench4_10000, $cipher, 10000); 187 $crate::stream_cipher_sync_bench!(bench5_100000, $cipher, 100000); 188 }; 189 } 190 191 /// Create asynchronous stream cipher benchmarks 192 #[macro_export] 193 #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] 194 macro_rules! stream_cipher_async_bench { 195 ($enc_name:ident, $dec_name:ident, $cipher:path, $data_len:expr) => { 196 #[bench] 197 pub fn $enc_name(bh: &mut Bencher) { 198 let key = Default::default(); 199 let nonce = Default::default(); 200 let mut cipher = <$cipher>::new(&key, &nonce); 201 let mut data = get_data($data_len); 202 203 bh.iter(|| { 204 cipher.encrypt(&mut data); 205 test::black_box(&data); 206 }); 207 bh.bytes = data.len() as u64; 208 } 209 210 #[bench] 211 pub fn $dec_name(bh: &mut Bencher) { 212 let key = Default::default(); 213 let nonce = Default::default(); 214 let mut cipher = <$cipher>::new(&key, &nonce); 215 let mut data = get_data($data_len); 216 217 bh.iter(|| { 218 cipher.decrypt(&mut data); 219 test::black_box(&data); 220 }); 221 bh.bytes = data.len() as u64; 222 } 223 }; 224 ($cipher:path) => { 225 extern crate test; 226 227 use cipher::{generic_array::GenericArray, AsyncStreamCipher, NewCipher}; 228 use test::Bencher; 229 230 #[inline(never)] 231 fn get_data(n: usize) -> Vec<u8> { 232 vec![77; n] 233 } 234 235 $crate::stream_cipher_async_bench!(encrypt_10, decrypt_10, $cipher, 10); 236 $crate::stream_cipher_async_bench!(encrypt_100, decrypt_100, $cipher, 100); 237 $crate::stream_cipher_async_bench!(encrypt_1000, decrypt_1000, $cipher, 1000); 238 $crate::stream_cipher_async_bench!(encrypt_10000, decrypt_10000, $cipher, 10000); 239 $crate::stream_cipher_async_bench!(encrypt_100000, decrypt_100000, $cipher, 100000); 240 }; 241 } 242