use crate::error::{MlsError, Result};
pub(crate) fn canonical_payload(domain: &[u8], fields: &[&[u8]]) -> Result<Vec<u8>> {
let mut buf =
Vec::with_capacity(domain.len() + fields.iter().map(|f| 4 + f.len()).sum::<usize>());
buf.extend_from_slice(domain);
for field in fields {
let len: u32 = field.len().try_into().map_err(|_| {
MlsError::Serialization(format!(
"Field too large for canonical payload length prefix: {} bytes",
field.len()
))
})?;
buf.extend_from_slice(&len.to_be_bytes());
buf.extend_from_slice(field);
}
Ok(buf)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn canonical_payload_length_prefixes_every_field() {
let payload = canonical_payload(b"dom", &[b"ab", b"c"]).expect("payload");
assert_eq!(payload, b"dom\x00\x00\x00\x02ab\x00\x00\x00\x01c".to_vec());
}
#[test]
fn canonical_payload_distinguishes_field_splits() {
let a = canonical_payload(b"dom", &[b"ab", b"c"]).expect("payload");
let b = canonical_payload(b"dom", &[b"a", b"bc"]).expect("payload");
assert_ne!(a, b);
}
#[test]
fn canonical_payload_distinguishes_domains() {
let a = canonical_payload(b"dom-a", &[b"x"]).expect("payload");
let b = canonical_payload(b"dom-b", &[b"x"]).expect("payload");
assert_ne!(a, b);
}
}