Skip to main content

ps_cypher/
lib.rs

1mod error;
2
3pub use error::{DecryptionError, EncryptionError};
4pub use ps_buffer::Buffer;
5
6use chacha20poly1305::aead::{Aead, KeyInit};
7use chacha20poly1305::ChaCha20Poly1305;
8use ps_compress::{compress, decompress_bounded};
9use ps_ecc::{decode, encode, Codeword, DecodeError};
10use ps_hash::{Hash, PARITY_SIZE};
11use ps_util::subarray;
12use std::ops::Deref;
13
14#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
15pub struct Encrypted {
16    pub bytes: Buffer,
17    pub hash: Hash,
18    pub key: Hash,
19}
20
21const KSIZE: usize = 32;
22const NSIZE: usize = 12;
23
24const PARITY: u8 = 12;
25
26#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
27pub struct ParsedKey {
28    key: [u8; KSIZE],
29    nonce: [u8; NSIZE],
30    length: usize,
31}
32
33impl std::fmt::Debug for ParsedKey {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        f.debug_struct("ParsedKey")
36            .field("key", &"<REDACTED>")
37            .field("nonce", &self.nonce)
38            .field("length", &self.length)
39            .finish()
40    }
41}
42
43impl From<&Hash> for ParsedKey {
44    fn from(value: &Hash) -> Self {
45        Self {
46            key: *value.digest(),
47            length: value.data_max_len().to_usize(),
48            nonce: *subarray(value.parity(), PARITY_SIZE - NSIZE),
49        }
50    }
51}
52
53/// Encrypts a message.
54/// # Errors
55/// - [`PsCypherError::PsDeflateError`] is returned if compression fails.
56/// - [`PsCypherError::ChaChaError`] is returned if encryption fails.
57/// - [`PsCypherError::HashError`] is returned if hashing fails.
58pub fn encrypt(data: &[u8]) -> Result<Encrypted, EncryptionError> {
59    let compressed_data = compress(data)?;
60    let hash_of_raw_data = ps_hash::hash(data)?;
61
62    let ParsedKey {
63        key: encryption_key,
64        length: _,
65        nonce,
66    } = (&hash_of_raw_data).into();
67
68    let chacha = ChaCha20Poly1305::new(&encryption_key.into());
69    let encrypted_data = chacha
70        .encrypt(&nonce.into(), compressed_data.as_ref())
71        .map_err(|_| EncryptionError::ChaCha)?;
72
73    let bytes = encode(&encrypted_data, PARITY)?;
74    let hash = Hash::hash(&bytes)?;
75
76    let encrypted = Encrypted {
77        bytes,
78        hash,
79        key: hash_of_raw_data,
80    };
81
82    Ok(encrypted)
83}
84
85/// Attempts the decryption of encrypted data.
86/// # Errors
87/// [`PsCypherError::ChaChaError`] is returned if decryption fails.
88/// [`PsCypherError::PsDeflateError`] is returned if decompression fails.
89pub fn decrypt(data: &[u8], key: &Hash) -> Result<Buffer, DecryptionError> {
90    let ParsedKey {
91        key: encryption_key,
92        length: out_size,
93        nonce,
94    } = key.into();
95
96    let ecc_decoded = extract_encrypted(data)?;
97    let chacha = ChaCha20Poly1305::new(&encryption_key.into());
98    let compressed_data = chacha
99        .decrypt(&nonce.into(), &ecc_decoded[..])
100        .map_err(|_| DecryptionError::ChaCha)?;
101
102    Ok(decompress_bounded(&compressed_data, out_size)?)
103}
104
105#[inline]
106/// Extracts the raw ChaCha-encrypted content from the provided slice.
107/// # Errors
108/// Returns [`DecodeError`] if `data` is invalid or irrecoverably corrupted.
109pub fn extract_encrypted(data: &[u8]) -> Result<Codeword<'_>, DecodeError> {
110    decode(data, PARITY)
111}
112
113#[inline]
114#[must_use]
115/// Checks whether `data` has been corrupted or tampered with.
116///
117/// Returns `true` if the data's checksum is intact and no errors are detected.
118///
119/// # Parameters
120/// * `data` - The encrypted data buffer to validate
121///
122/// # Examples
123/// ```
124/// # use ps_cypher::{encrypt, validate_ecc};
125/// let data = b"important data";
126/// let encrypted = encrypt(data).expect("encryption failed");
127/// assert!(validate_ecc(&encrypted));
128/// ```
129pub fn validate_ecc(data: &[u8]) -> bool {
130    ps_ecc::validate(data, PARITY)
131}
132
133impl AsRef<[u8]> for Encrypted {
134    fn as_ref(&self) -> &[u8] {
135        self
136    }
137}
138
139impl Deref for Encrypted {
140    type Target = [u8];
141
142    fn deref(&self) -> &Self::Target {
143        &self.bytes
144    }
145}
146
147#[cfg(test)]
148#[allow(clippy::expect_used)]
149#[allow(clippy::unwrap_used)]
150mod tests {
151    use ps_buffer::ToBuffer;
152    use ps_hash::hash;
153
154    use super::*;
155
156    #[test]
157    fn test_encrypt_and_decrypt() {
158        let original_data = b"Hello, World!";
159
160        let encrypted_data = encrypt(original_data).expect("encryption should succeed");
161
162        let decrypted_data =
163            decrypt(&encrypted_data.bytes, &encrypted_data.key).expect("decryption should succeed");
164
165        assert_ne!(
166            original_data
167                .to_buffer()
168                .expect("conversion to buffer should succeed"),
169            encrypted_data.bytes,
170            "Encryption should modify the data"
171        );
172
173        let ecc_payload = extract_encrypted(&encrypted_data.bytes)
174            .expect("extracting ECC payload should succeed");
175
176        assert_eq!(
177            encrypted_data.bytes.len(),
178            ecc_payload.len() + 2 * usize::from(PARITY),
179            "ECC encoding should add parity bytes"
180        );
181
182        assert_eq!(
183            original_data,
184            &decrypted_data[..],
185            "Decryption should reverse encryption"
186        );
187    }
188
189    // Helper function to create a sample key (for testing purposes)
190    fn create_test_key() -> Hash {
191        hash("Hello, world!").expect("hashing test key should succeed")
192    }
193
194    #[test]
195    fn test_parse_key() {
196        let key = &create_test_key();
197
198        let ParsedKey {
199            key: encryption_key,
200            length: _,
201            nonce,
202        } = key.into();
203
204        assert_eq!(encryption_key.len(), 32);
205        assert_eq!(nonce.len(), 12);
206        // Basic check of the key and nonce values.
207        assert_eq!(&encryption_key[0..4], &[220, 186, 155, 106]); // First 4 bytes of key
208        assert_eq!(&nonce[0..4], &[46, 215, 220, 44]); // First 4 bytes of nonce
209    }
210
211    #[test]
212    fn test_encrypt_decrypt() {
213        let data = b"This is some data to encrypt";
214        let encrypted = encrypt(data).expect("encryption should succeed");
215        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
216        assert_eq!(&*decrypted, data);
217    }
218
219    #[test]
220    fn test_encrypt_decrypt_empty_data() {
221        let data = b"";
222        let encrypted = encrypt(data).expect("encryption should succeed");
223        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
224        assert_eq!(&*decrypted, data);
225    }
226
227    #[test]
228    fn test_encrypt_decrypt_long_data() {
229        let data = "This is a very long string to test the encryption and decryption with a large amount of data.  We want to make sure that the compression and decompression work correctly, and that the encryption and decryption can handle a significant amount of data without any issues.  This should be longer than any reasonable message.  Let's add some more to be absolutely sure. And even more, just to be safe.".as_bytes();
230        let encrypted = encrypt(data).expect("encryption should succeed");
231        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
232        assert_eq!(&*decrypted, data);
233    }
234
235    #[test]
236    fn test_encrypt_decrypt_different_key() {
237        let data = b"This is some data";
238        let encrypted = encrypt(data).expect("encryption should succeed");
239        let different_key = create_test_key(); // Use a different key.
240
241        let result = decrypt(&encrypted, &different_key);
242        assert!(result.is_err());
243        match result.unwrap_err() {
244            DecryptionError::ChaCha => {} // Expected error type.
245            _ => panic!("Unexpected error type"),
246        }
247    }
248
249    #[test]
250    fn test_encrypt_decrypt_tampered_data() {
251        let data = b"This is some data";
252        let mut encrypted = encrypt(data).expect("encryption should succeed");
253        // Tamper with the encrypted data
254        encrypted.bytes[0] ^= 0x01; // Flip a bit
255
256        let decrypted = decrypt(&encrypted, &encrypted.key)
257            .expect("decryption should succeed after ECC correction");
258
259        assert_eq!(decrypted.slice(..), data);
260    }
261
262    #[test]
263    fn test_validate_ecc_for_valid_and_truncated_data() {
264        let data = b"ECC validation data";
265        let encrypted = encrypt(data).expect("encryption should succeed");
266
267        assert!(validate_ecc(&encrypted), "fresh ciphertext should validate");
268
269        let truncated = &encrypted.bytes[..encrypted.bytes.len() - 1];
270        assert!(
271            !validate_ecc(truncated),
272            "truncated ciphertext should not validate"
273        );
274    }
275
276    #[test]
277    fn test_extract_encrypted_rejects_truncated_payload() {
278        let data = b"payload";
279        let encrypted = encrypt(data).expect("encryption should succeed");
280        let truncated = &encrypted.bytes[..encrypted.bytes.len() - 1];
281
282        let result = extract_encrypted(truncated);
283        assert!(result.is_err(), "truncated payload must fail ECC decode");
284    }
285
286    #[test]
287    fn test_decrypt_truncated_payload_returns_ecc_error() {
288        let data = b"payload";
289        let encrypted = encrypt(data).expect("encryption should succeed");
290        let truncated = &encrypted.bytes[..encrypted.bytes.len() - 1];
291
292        let result = decrypt(truncated, &encrypted.key);
293        assert!(
294            matches!(result, Err(DecryptionError::Ecc(_))),
295            "truncated payload should surface as ECC error"
296        );
297    }
298
299    #[test]
300    fn test_encrypted_hash_matches_ciphertext_bytes() {
301        let data = b"hash check";
302        let encrypted = encrypt(data).expect("encryption should succeed");
303        let recalculated = Hash::hash(&encrypted.bytes).expect("hashing bytes should succeed");
304
305        assert_eq!(encrypted.hash, recalculated);
306    }
307
308    #[test]
309    fn test_as_ref_encrypted() {
310        let data = b"Test data";
311        let encrypted = encrypt(data).expect("encryption should succeed");
312        let as_ref_data: &[u8] = encrypted.as_ref();
313        assert_eq!(as_ref_data, &*encrypted);
314        assert_eq!(as_ref_data, &encrypted.bytes[..]);
315    }
316
317    #[test]
318    fn test_deref_encrypted() {
319        let data = b"More test data";
320        let encrypted = encrypt(data).expect("encryption should succeed");
321        let deref_data: &[u8] = &encrypted; // Use the Deref trait
322        assert_eq!(deref_data, &encrypted.bytes[..]);
323    }
324
325    #[test]
326    fn test_key_from_hash() {
327        let data = b"Test data for key derivation";
328        let h = hash(data).expect("hashing should succeed");
329
330        let ParsedKey {
331            key,
332            length: _,
333            nonce: _,
334        } = (&h).into();
335
336        assert_eq!(key.len(), 32);
337    }
338
339    #[test]
340    fn test_encrypt_large_data() {
341        // Create a large amount of data (1MB)
342        let data = vec![b'A'; 1024 * 1024];
343        let encrypted = encrypt(&data).expect("encryption should succeed");
344        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
345        assert_eq!(&*decrypted, &data[..]);
346    }
347
348    #[test]
349    fn test_ps_cypher_error_display() {
350        let data = b"test";
351        let encrypted = encrypt(data).expect("encryption should succeed");
352        let bad_key = hash(b"invalid_key").expect("hashing should succeed");
353        let result = decrypt(&encrypted, &bad_key);
354
355        if let Err(e) = result {
356            let error_message = format!("{e}");
357            assert_eq!(
358                error_message,
359                "Encryption/Decryption failure (from chacha20poly1305)"
360            ); // Check for a substring.
361        } else {
362            panic!("Expected an error, but got success");
363        }
364    }
365
366    #[test]
367    fn test_ps_cypher_error_source() {
368        let data = b"test";
369        let encrypted = encrypt(data).expect("encryption should succeed");
370        let bad_key = hash(b"invalid_key").expect("hashing should succeed");
371        let result = decrypt(&encrypted, &bad_key);
372
373        if let Err(e) = result {
374            let source = std::error::Error::source(&e);
375            if let Some(err) = source {
376                let _ = format!("{err}"); //check it does not panic
377            }
378        } else {
379            panic!("Expected an error, but got success");
380        }
381    }
382
383    #[test]
384    fn test_parsed_key_debug_redacts_key() {
385        let key = create_test_key();
386        let parsed: ParsedKey = (&key).into();
387        let debug_output = format!("{parsed:?}");
388
389        assert!(
390            debug_output.contains("<REDACTED>"),
391            "Debug output should redact the key"
392        );
393        // Verify the key field shows REDACTED, not actual bytes
394        assert!(
395            debug_output.contains("key: \"<REDACTED>\""),
396            "key field should be redacted"
397        );
398        // Verify other fields are present
399        assert!(debug_output.contains("nonce:"), "nonce should be present");
400        assert!(debug_output.contains("length:"), "length should be present");
401    }
402
403    #[test]
404    #[allow(clippy::clone_on_copy)]
405    fn test_parsed_key_clone_and_copy() {
406        let key = create_test_key();
407        let parsed: ParsedKey = (&key).into();
408        let cloned = parsed.clone(); // Intentionally testing Clone trait
409        let copied = parsed;
410
411        assert_eq!(parsed, cloned);
412        assert_eq!(parsed, copied);
413    }
414
415    #[test]
416    fn test_parsed_key_hash_trait() {
417        use std::collections::HashSet;
418
419        let key1 = create_test_key();
420        let key2 = hash(b"different data").expect("hashing should succeed");
421
422        let parsed1: ParsedKey = (&key1).into();
423        let parsed2: ParsedKey = (&key2).into();
424
425        let mut set = HashSet::new();
426        set.insert(parsed1);
427        set.insert(parsed2);
428
429        assert_eq!(set.len(), 2, "different keys should hash differently");
430    }
431
432    #[test]
433    fn test_parsed_key_ordering() {
434        let key1 = hash(b"aaa").expect("hashing should succeed");
435        let key2 = hash(b"bbb").expect("hashing should succeed");
436
437        let parsed1: ParsedKey = (&key1).into();
438        let parsed2: ParsedKey = (&key2).into();
439
440        // Just verify ordering is consistent, not specific order
441        let cmp1 = parsed1.cmp(&parsed2);
442        let cmp2 = parsed2.cmp(&parsed1);
443        assert_eq!(cmp1.reverse(), cmp2);
444    }
445
446    #[test]
447    fn test_encrypted_hash_trait() {
448        use std::collections::HashSet;
449
450        let encrypted1 = encrypt(b"data1").expect("encryption should succeed");
451        let encrypted2 = encrypt(b"data2").expect("encryption should succeed");
452
453        let mut set = HashSet::new();
454        set.insert(encrypted1);
455        set.insert(encrypted2);
456
457        assert_eq!(
458            set.len(),
459            2,
460            "different encryptions should hash differently"
461        );
462    }
463
464    #[test]
465    fn test_encrypted_ordering() {
466        let encrypted1 = encrypt(b"aaa").expect("encryption should succeed");
467        let encrypted2 = encrypt(b"bbb").expect("encryption should succeed");
468
469        let cmp1 = encrypted1.cmp(&encrypted2);
470        let cmp2 = encrypted2.cmp(&encrypted1);
471        assert_eq!(cmp1.reverse(), cmp2);
472    }
473
474    #[test]
475    fn test_encrypted_equality() {
476        let data = b"same data";
477        let encrypted1 = encrypt(data).expect("encryption should succeed");
478        let encrypted2 = encrypt(data).expect("encryption should succeed");
479
480        assert_eq!(
481            encrypted1, encrypted2,
482            "same input should produce equal encryptions"
483        );
484    }
485
486    #[test]
487    fn test_encrypt_decrypt_single_byte() {
488        let data = b"x";
489        let encrypted = encrypt(data).expect("encryption should succeed");
490        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
491        assert_eq!(&*decrypted, data);
492    }
493
494    #[test]
495    fn test_encrypt_decrypt_binary_with_nulls() {
496        let data: &[u8] = &[0x00, 0x01, 0x00, 0xFF, 0x00, 0xFE, 0x00];
497        let encrypted = encrypt(data).expect("encryption should succeed");
498        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
499        assert_eq!(&*decrypted, data);
500    }
501
502    #[test]
503    fn test_encrypt_decrypt_all_byte_values() {
504        let data: Vec<u8> = (0u8..=255).collect();
505        let encrypted = encrypt(&data).expect("encryption should succeed");
506        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
507        assert_eq!(&*decrypted, &data[..]);
508    }
509
510    #[test]
511    fn test_encrypt_decrypt_unicode() {
512        let data = "Hello 世界! 🎉 Привет мир".as_bytes();
513        let encrypted = encrypt(data).expect("encryption should succeed");
514        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
515        assert_eq!(&*decrypted, data);
516    }
517
518    #[test]
519    fn test_encrypt_decrypt_highly_compressible_data() {
520        // Repetitive data should compress well
521        let data = vec![b'A'; 10000];
522        let encrypted = encrypt(&data).expect("encryption should succeed");
523
524        // Encrypted size should be significantly smaller due to compression
525        assert!(
526            encrypted.bytes.len() < data.len(),
527            "highly compressible data should result in smaller ciphertext"
528        );
529
530        let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
531        assert_eq!(&*decrypted, &data[..]);
532    }
533
534    #[test]
535    fn test_encryption_determinism() {
536        let data = b"deterministic test data";
537
538        let encrypted1 = encrypt(data).expect("encryption should succeed");
539        let encrypted2 = encrypt(data).expect("encryption should succeed");
540
541        assert_eq!(
542            encrypted1.bytes, encrypted2.bytes,
543            "same input should produce identical ciphertext"
544        );
545        assert_eq!(
546            encrypted1.key, encrypted2.key,
547            "same input should produce identical key"
548        );
549        assert_eq!(
550            encrypted1.hash, encrypted2.hash,
551            "same input should produce identical hash"
552        );
553    }
554
555    #[test]
556    fn test_different_inputs_produce_different_outputs() {
557        let encrypted1 = encrypt(b"input 1").expect("encryption should succeed");
558        let encrypted2 = encrypt(b"input 2").expect("encryption should succeed");
559
560        assert_ne!(
561            encrypted1.bytes, encrypted2.bytes,
562            "different inputs should produce different ciphertexts"
563        );
564        assert_ne!(
565            encrypted1.key, encrypted2.key,
566            "different inputs should produce different keys"
567        );
568    }
569
570    #[test]
571    fn test_ecc_corrects_multiple_bit_errors() {
572        let data = b"ECC multi-bit correction test";
573        let mut encrypted = encrypt(data).expect("encryption should succeed");
574
575        // Flip multiple bits in different bytes (within ECC correction capability)
576        encrypted.bytes[0] ^= 0x01;
577        encrypted.bytes[1] ^= 0x02;
578        encrypted.bytes[2] ^= 0x04;
579
580        let decrypted = decrypt(&encrypted, &encrypted.key)
581            .expect("decryption should succeed with ECC correction");
582        assert_eq!(&*decrypted, data);
583    }
584
585    #[test]
586    fn test_validate_ecc_detects_corruption_within_capability() {
587        let data = b"ECC validation test";
588        let mut encrypted = encrypt(data).expect("encryption should succeed");
589
590        // Minor corruption that ECC can detect but still validates checksum structure
591        encrypted.bytes[5] ^= 0x01;
592
593        // validate_ecc returns true if the checksum structure is valid
594        // (ECC can correct the error, so the data is still "valid")
595        let is_valid = validate_ecc(&encrypted);
596        // Either valid (correctable) or invalid (detected) - both are acceptable
597        // The key point is that decrypt should still work
598        let decrypted = decrypt(&encrypted, &encrypted.key);
599        assert!(
600            decrypted.is_ok() || !is_valid,
601            "corrupted data should either be correctable or detected as invalid"
602        );
603    }
604
605    #[test]
606    fn test_empty_slice_validation() {
607        assert!(
608            !validate_ecc(&[]),
609            "empty slice should not validate as valid ECC"
610        );
611    }
612
613    #[test]
614    fn test_extract_encrypted_empty_slice() {
615        let result = extract_encrypted(&[]);
616        assert!(result.is_err(), "empty slice should fail extraction");
617    }
618
619    #[test]
620    fn test_decrypt_empty_slice() {
621        let key = create_test_key();
622        let result = decrypt(&[], &key);
623        assert!(
624            matches!(result, Err(DecryptionError::Ecc(_))),
625            "empty slice should return ECC error"
626        );
627    }
628
629    #[test]
630    fn test_decryption_error_clone() {
631        let data = b"test";
632        let encrypted = encrypt(data).expect("encryption should succeed");
633        let bad_key = hash(b"wrong_key").expect("hashing should succeed");
634
635        let result = decrypt(&encrypted, &bad_key);
636        if let Err(e) = result {
637            let cloned = e.clone();
638            assert_eq!(format!("{e}"), format!("{cloned}"));
639        } else {
640            panic!("Expected decryption error");
641        }
642    }
643
644    #[test]
645    fn test_encryption_error_clone() {
646        // EncryptionError::ChaCha is the only variant we can easily trigger
647        // by verifying error types are Clone
648        let err = EncryptionError::ChaCha;
649        let cloned = err.clone();
650        assert_eq!(format!("{err}"), format!("{cloned}"));
651    }
652
653    #[test]
654    fn test_decryption_error_debug() {
655        let err = DecryptionError::ChaCha;
656        let debug_output = format!("{err:?}");
657        assert!(debug_output.contains("ChaCha"));
658    }
659
660    #[test]
661    fn test_encryption_error_debug() {
662        let err = EncryptionError::ChaCha;
663        let debug_output = format!("{err:?}");
664        assert!(debug_output.contains("ChaCha"));
665    }
666
667    #[test]
668    fn test_encrypted_debug() {
669        let encrypted = encrypt(b"debug test").expect("encryption should succeed");
670        let debug_output = format!("{encrypted:?}");
671        assert!(debug_output.contains("Encrypted"));
672        assert!(debug_output.contains("bytes"));
673        assert!(debug_output.contains("hash"));
674        assert!(debug_output.contains("key"));
675    }
676
677    #[test]
678    fn test_parsed_key_same_hash_produces_same_key() {
679        let h = hash(b"consistent").expect("hashing should succeed");
680        let parsed1: ParsedKey = (&h).into();
681        let parsed2: ParsedKey = (&h).into();
682
683        assert_eq!(parsed1, parsed2);
684    }
685
686    #[test]
687    fn test_encrypt_decrypt_powers_of_two_sizes() {
688        for power in 0..=10 {
689            let size = 1 << power;
690            let data = vec![0xAB_u8; size];
691            let encrypted = encrypt(&data).expect("encryption should succeed");
692            let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
693            assert_eq!(&*decrypted, &data[..], "failed for size {size}");
694        }
695    }
696
697    #[test]
698    fn test_encrypt_decrypt_boundary_sizes() {
699        // Test sizes around common boundaries
700        for size in [
701            127, 128, 129, 255, 256, 257, 511, 512, 513, 1023, 1024, 1025,
702        ] {
703            let data = vec![0xCD_u8; size];
704            let encrypted = encrypt(&data).expect("encryption should succeed");
705            let decrypted = decrypt(&encrypted, &encrypted.key).expect("decryption should succeed");
706            assert_eq!(&*decrypted, &data[..], "failed for size {size}");
707        }
708    }
709}