test: add MLS and MeshEnvelope size measurement tests
- measure_mls_wire_sizes: KeyPackage, Welcome, Commit, AppMessage sizes - measure_mls_wire_sizes_hybrid: same with post-quantum mode - measure_mesh_envelope_overhead: MeshEnvelope overhead for various payloads These tests print actual byte sizes to inform constrained link feasibility planning (LoRa SF12, MLS-Lite design).
This commit is contained in:
@@ -1079,4 +1079,96 @@ mod tests {
|
||||
"send_message before join must return an error"
|
||||
);
|
||||
}
|
||||
|
||||
/// Measure actual MLS artifact sizes for mesh planning.
|
||||
/// These numbers inform the MLS-Lite design and constrained link feasibility.
|
||||
#[test]
|
||||
fn measure_mls_wire_sizes() {
|
||||
let creator_id = Arc::new(IdentityKeypair::generate());
|
||||
let joiner_id = Arc::new(IdentityKeypair::generate());
|
||||
|
||||
let mut creator = GroupMember::new(Arc::clone(&creator_id));
|
||||
let mut joiner = GroupMember::new(Arc::clone(&joiner_id));
|
||||
|
||||
// 1. KeyPackage size
|
||||
let kp_bytes = joiner.generate_key_package().expect("generate KP");
|
||||
println!("=== MLS Wire Format Sizes ===");
|
||||
println!("KeyPackage: {} bytes", kp_bytes.len());
|
||||
|
||||
// 2. Create group (no wire message, just local state)
|
||||
creator.create_group(b"size-test").expect("create group");
|
||||
|
||||
// 3. Add member -> Commit + Welcome
|
||||
let (commit_bytes, welcome_bytes) = creator.add_member(&kp_bytes).expect("add member");
|
||||
println!("Commit (add): {} bytes", commit_bytes.len());
|
||||
println!("Welcome: {} bytes", welcome_bytes.len());
|
||||
|
||||
// Join the group
|
||||
joiner.join_group(&welcome_bytes).expect("join");
|
||||
|
||||
// 4. Application message (short payload)
|
||||
let short_msg = creator.send_message(b"hello").expect("short msg");
|
||||
println!("AppMessage (5B): {} bytes", short_msg.len());
|
||||
|
||||
// 5. Application message (medium payload ~100 bytes)
|
||||
let medium_payload = vec![0x42u8; 100];
|
||||
let medium_msg = creator.send_message(&medium_payload).expect("medium msg");
|
||||
println!("AppMessage (100B): {} bytes", medium_msg.len());
|
||||
|
||||
// 6. Self-update proposal
|
||||
let update_proposal = creator.propose_self_update().expect("update proposal");
|
||||
println!("UpdateProposal: {} bytes", update_proposal.len());
|
||||
|
||||
// Joiner processes the proposal
|
||||
joiner.receive_message(&update_proposal).expect("recv proposal");
|
||||
|
||||
// 7. Commit (update only, no welcome)
|
||||
let (update_commit, _) = joiner.commit_pending_proposals().expect("commit update");
|
||||
println!("Commit (update): {} bytes", update_commit.len());
|
||||
|
||||
// Summary for LoRa feasibility
|
||||
println!("\n=== LoRa Feasibility (SF12/BW125, MTU=51 bytes) ===");
|
||||
println!("KeyPackage: {} fragments ({:.0}s at 1% duty)",
|
||||
(kp_bytes.len() + 50) / 51,
|
||||
(kp_bytes.len() as f64 / 51.0).ceil() * 36.0 / 60.0);
|
||||
println!("Welcome: {} fragments ({:.0}s at 1% duty)",
|
||||
(welcome_bytes.len() + 50) / 51,
|
||||
(welcome_bytes.len() as f64 / 51.0).ceil() * 36.0 / 60.0);
|
||||
println!("AppMessage (5B): {} fragments",
|
||||
(short_msg.len() + 50) / 51);
|
||||
|
||||
// Assertions to catch regressions / validate estimates
|
||||
assert!(kp_bytes.len() < 1000, "KeyPackage should be under 1KB");
|
||||
assert!(welcome_bytes.len() < 3000, "Welcome should be under 3KB");
|
||||
assert!(short_msg.len() < 300, "Short AppMessage should be under 300B");
|
||||
}
|
||||
|
||||
/// Measure MLS sizes with hybrid (post-quantum) mode enabled.
|
||||
#[test]
|
||||
fn measure_mls_wire_sizes_hybrid() {
|
||||
let creator_id = Arc::new(IdentityKeypair::generate());
|
||||
let joiner_id = Arc::new(IdentityKeypair::generate());
|
||||
|
||||
let mut creator = GroupMember::new_hybrid(Arc::clone(&creator_id));
|
||||
let mut joiner = GroupMember::new_hybrid(Arc::clone(&joiner_id));
|
||||
|
||||
// KeyPackage with hybrid (X25519 + ML-KEM-768) init key
|
||||
let kp_bytes = joiner.generate_key_package().expect("generate hybrid KP");
|
||||
println!("=== MLS Wire Format Sizes (Hybrid PQ Mode) ===");
|
||||
println!("KeyPackage (PQ): {} bytes", kp_bytes.len());
|
||||
|
||||
creator.create_group(b"hybrid-size-test").expect("create group");
|
||||
let (commit_bytes, welcome_bytes) = creator.add_member(&kp_bytes).expect("add member");
|
||||
println!("Commit (add, PQ): {} bytes", commit_bytes.len());
|
||||
println!("Welcome (PQ): {} bytes", welcome_bytes.len());
|
||||
|
||||
joiner.join_group(&welcome_bytes).expect("join");
|
||||
|
||||
let short_msg = creator.send_message(b"hello").expect("short msg");
|
||||
println!("AppMessage (PQ): {} bytes", short_msg.len());
|
||||
|
||||
// PQ KeyPackages are larger due to ML-KEM-768 public key (1184 bytes)
|
||||
assert!(kp_bytes.len() > 1000, "Hybrid KeyPackage should be >1KB due to ML-KEM");
|
||||
assert!(kp_bytes.len() < 3000, "Hybrid KeyPackage should be <3KB");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user