use algochat::{derive_keys_from_seed, encode_psk_envelope, encrypt_message, encrypt_psk_message};
use std::collections::HashMap;
use std::fs;
use std::path::Path;
const ALICE_SEED_HEX: &str = "0000000000000000000000000000000000000000000000000000000000000001";
const BOB_SEED_HEX: &str = "0000000000000000000000000000000000000000000000000000000000000002";
const TEST_PSK_HEX: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
fn test_messages() -> HashMap<&'static str, String> {
let mut messages: HashMap<&'static str, String> = HashMap::new();
messages.insert("empty", String::new());
messages.insert("single_char", "X".to_string());
messages.insert("whitespace", " \t\n ".to_string());
messages.insert("numbers", "1234567890".to_string());
messages.insert(
"punctuation",
"!@#$%^&*()_+-=[]{}\\|;':\",./<>?".to_string(),
);
messages.insert("newlines", "Line 1\nLine 2\nLine 3".to_string());
messages.insert("emoji_simple", "Hello 👋 World 🌍".to_string());
messages.insert("emoji_zwj", "Family: 👨👩👧👦".to_string());
messages.insert("chinese", "你好世界 - Hello World".to_string());
messages.insert("arabic", "مرحبا بالعالم".to_string());
messages.insert("japanese", "こんにちは世界 カタカナ 漢字".to_string());
messages.insert("korean", "안녕하세요 세계".to_string());
messages.insert("accents", "Café résumé naïve".to_string());
messages.insert("cyrillic", "Привет мир".to_string());
messages.insert("json", r#"{"key": "value", "num": 42}"#.to_string());
messages.insert("html", r#"<div class="test">Content</div>"#.to_string());
messages.insert("url", "https://example.com/path?q=test&lang=en".to_string());
messages.insert("code", r#"func hello() { print("Hi") }"#.to_string());
messages.insert(
"long_text",
"The quick brown fox jumps over the lazy dog. ".repeat(11),
);
messages.insert("max_payload", "A".repeat(882));
messages
}
fn psk_test_messages() -> HashMap<&'static str, String> {
let mut messages: HashMap<&'static str, String> = HashMap::new();
messages.insert("empty", String::new());
messages.insert("single_char", "X".to_string());
messages.insert("whitespace", " \t\n ".to_string());
messages.insert("numbers", "1234567890".to_string());
messages.insert(
"punctuation",
"!@#$%^&*()_+-=[]{}\\|;':\",./<>?".to_string(),
);
messages.insert("newlines", "Line 1\nLine 2\nLine 3".to_string());
messages.insert("emoji_simple", "Hello 👋 World 🌍".to_string());
messages.insert("emoji_zwj", "Family: 👨👩👧👦".to_string());
messages.insert("chinese", "你好世界 - Hello World".to_string());
messages.insert("arabic", "مرحبا بالعالم".to_string());
messages.insert("japanese", "こんにちは世界 カタカナ 漢字".to_string());
messages.insert("korean", "안녕하세요 세계".to_string());
messages.insert("accents", "Café résumé naïve".to_string());
messages.insert("cyrillic", "Привет мир".to_string());
messages.insert("json", r#"{"key": "value", "num": 42}"#.to_string());
messages.insert("html", r#"<div class="test">Content</div>"#.to_string());
messages.insert("url", "https://example.com/path?q=test&lang=en".to_string());
messages.insert("code", r#"func hello() { print("Hi") }"#.to_string());
messages.insert(
"long_text",
"The quick brown fox jumps over the lazy dog. ".repeat(11),
);
messages.insert("max_payload", "A".repeat(878));
messages
}
fn main() {
let args: Vec<String> = std::env::args().collect();
let output_dir = args
.get(1)
.map(|s| s.as_str())
.unwrap_or("test-envelopes-rust");
let alice_seed = hex::decode(ALICE_SEED_HEX).unwrap();
let bob_seed = hex::decode(BOB_SEED_HEX).unwrap();
let (alice_private, alice_public) = derive_keys_from_seed(&alice_seed).unwrap();
let (_, bob_public) = derive_keys_from_seed(&bob_seed).unwrap();
let output_path = Path::new(output_dir);
fs::create_dir_all(output_path).unwrap();
let messages = test_messages();
let mut count = 0;
for (key, message) in &messages {
let envelope =
encrypt_message(message, &alice_private, &alice_public, &bob_public).unwrap();
let encoded = envelope.encode();
let hex_encoded = hex::encode(&encoded);
let file_path = output_path.join(format!("{}.hex", key));
fs::write(&file_path, &hex_encoded).unwrap();
println!(" v1.0 ✓ {}", key);
count += 1;
}
println!("Rust: exported {} standard v1.0 envelopes", count);
let psk = hex::decode(TEST_PSK_HEX).unwrap();
let psk_dir = output_path.join("psk");
fs::create_dir_all(&psk_dir).unwrap();
let psk_messages = psk_test_messages();
let mut psk_count = 0;
for (key, message) in &psk_messages {
let envelope =
encrypt_psk_message(message, &alice_private, &alice_public, &bob_public, &psk, 0)
.unwrap();
let encoded = encode_psk_envelope(&envelope);
let hex_encoded = hex::encode(&encoded);
let file_path = psk_dir.join(format!("{}.hex", key));
fs::write(&file_path, &hex_encoded).unwrap();
println!(" v1.1 ✓ {} (counter=0)", key);
psk_count += 1;
}
let boundary_envelope = encrypt_psk_message(
"Session boundary test",
&alice_private,
&alice_public,
&bob_public,
&psk,
100,
)
.unwrap();
let boundary_encoded = encode_psk_envelope(&boundary_envelope);
fs::write(
psk_dir.join("session_boundary.hex"),
hex::encode(&boundary_encoded),
)
.unwrap();
println!(" v1.1 ✓ session_boundary (counter=100)");
psk_count += 1;
let mid_envelope = encrypt_psk_message(
"Mid-session test at counter 42",
&alice_private,
&alice_public,
&bob_public,
&psk,
42,
)
.unwrap();
let mid_encoded = encode_psk_envelope(&mid_envelope);
fs::write(psk_dir.join("mid_session.hex"), hex::encode(&mid_encoded)).unwrap();
println!(" v1.1 ✓ mid_session (counter=42)");
psk_count += 1;
println!(
"Rust: exported {} PSK v1.1 envelopes to {}/psk",
psk_count, output_dir
);
println!(
"Total: {} envelopes exported to {}",
count + psk_count,
output_dir
);
}