//! Format v2 invariants: VERSION_BYTE = 0x02, v1 blobs are rejected with //! UnsupportedFormatVersion, length-prefix construction guarantees domain //! separation. use relicario_core::{ RelicarioError, crypto::{KdfParams, VERSION_BYTE}, decrypt, derive_master_key, encrypt, }; use zeroize::Zeroizing; fn fast_params() -> KdfParams { KdfParams { argon2_m: 256, argon2_t: 1, argon2_p: 1 } } #[test] fn version_byte_is_2() { assert_eq!(VERSION_BYTE, 0x02); } #[test] fn fresh_ciphertext_starts_with_0x02() { let key = Zeroizing::new([0u8; 32]); // encrypt(key: &[u8; 32], plaintext: &[u8]) let ct = encrypt(&key, b"hello").unwrap(); assert_eq!(ct[0], 0x02); } #[test] fn v1_blob_is_rejected_with_unsupported_format_version() { // v1 layout: [0x01][24 nonce bytes][16 tag bytes] let mut blob = vec![0x01u8]; blob.extend_from_slice(&[0u8; 24 + 16]); let key = Zeroizing::new([0u8; 32]); // decrypt(key: &[u8; 32], data: &[u8]) let err = decrypt(&key, &blob); match err { Err(RelicarioError::UnsupportedFormatVersion { found, expected }) => { assert_eq!(found, 0x01); assert_eq!(expected, 0x02); } other => panic!("expected UnsupportedFormatVersion, got {other:?}"), } } #[test] fn length_prefix_distinguishes_concat_collisions() { let salt = [0u8; 32]; let img = [0x44u8; 32]; let p1 = b"abc"; let p2 = b"abcD"; // Pre-length-prefix, ("abc", [0x44, ...]) and ("abcD", ...) // could be made to collide. With length-prefix they cannot. let k1 = derive_master_key(p1, &img, &salt, &fast_params()).unwrap(); let k2 = derive_master_key(p2, &img, &salt, &fast_params()).unwrap(); assert_ne!(*k1, *k2); }