use std::{fs, path::Path};
use beaconcrypt::{
BeaconCryptPqxdh, CryptoProvider, ED25519_SEED_SIZE, ProviderBeacon, ProviderServer,
};
const SERVER_KID: u64 = 0;
const REGISTRATION_MESSAGE: &[u8] = b"registration ok";
#[derive(serde::Deserialize)]
struct StateUpdate {
kid: u64,
seq: u64,
state: serde_json::Value,
data: Vec<u8>,
}
fn deserialize_state_update(serialized: &str) -> StateUpdate {
serde_json::from_str(serialized).expect("failed to deserialize state update")
}
fn main() {
libsodium_rs::ensure_init().expect("failed to initialize libsodium");
let server_seed = libsodium_rs::random::bytes(ED25519_SEED_SIZE);
let mut server = BeaconCryptPqxdh::new(false, SERVER_KID, None, Some(&server_seed));
let mut beacon = BeaconCryptPqxdh::new(
true,
SERVER_KID,
Some(server.identity_pk().as_bytes()),
None,
);
let transport = Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/rust/transport");
let b_reg_1 = beacon
.get_registration_bundle()
.expect("failed to generate registration");
fs::write(&transport, b_reg_1).expect("failed to write registration to transport");
let s_reg_1 = fs::read(&transport).expect("failed to read registration from transport");
let registration = server
.get_shared_secret(&s_reg_1)
.expect("failed to process registration");
let s_reg_resp = server
.build_registration_response(registration, Some(REGISTRATION_MESSAGE))
.expect("failed to build registration response");
fs::write(&transport, &s_reg_resp.serialized)
.expect("failed to write registration response to transport");
let b_reg_1 =
fs::read(&transport).expect("failed to read registration response from transport");
let first_message = beacon
.finish_registration(&b_reg_1)
.expect("failed to finish registration");
println!(
"Beacon got initial message: {}",
String::from_utf8_lossy(&first_message)
);
let b_ping = beacon
.encrypt_message(b"ping", SERVER_KID)
.expect("failed to encrypt ping");
fs::write(&transport, b_ping).expect("failed to write ping to transport");
let s_ping = fs::read(&transport).expect("failed to read ping from transport");
let ping = server
.decrypt_and_update_json(&s_ping)
.expect("failed to decrypt ping");
let ping = deserialize_state_update(&ping);
println!("Server got ping: {}", String::from_utf8_lossy(&ping.data));
println!("Key ID: {}", ping.kid);
println!("Consumed key sequence: {}", ping.seq);
println!("Ratchet state: {}", ping.state);
let s_task_0 = server
.encrypt_and_update_json(b"task contents", s_reg_resp.kid)
.expect("failed to encrypt task");
let s_task_0 = deserialize_state_update(&s_task_0);
println!("Key ID: {}", s_task_0.kid);
println!("Consumed key sequence: {}", s_task_0.seq);
println!("Ratchet state: {}", s_task_0.state);
fs::write(&transport, &s_task_0.data).expect("failed to write task to transport");
let b_task_0 = fs::read(&transport).expect("failed to read task from transport");
let task_0 = beacon
.decrypt_message(&b_task_0)
.expect("failed to decrypt task");
assert_eq!(task_0.key_id, SERVER_KID);
println!(
"Beacon got first task: {}",
String::from_utf8_lossy(&task_0.plaintext)
);
let b_task_1 = beacon
.encrypt_message(b"task response", SERVER_KID)
.expect("failed to encrypt task response");
fs::write(&transport, b_task_1).expect("failed to write task response to transport");
let s_task_1 = fs::read(&transport).expect("failed to read task response from transport");
let task_1 = server
.decrypt_and_update_json(&s_task_1)
.expect("failed to decrypt task response");
let task_1 = deserialize_state_update(&task_1);
println!(
"Server got response to first task: {}",
String::from_utf8_lossy(&task_1.data)
);
println!("Key ID: {}", task_1.kid);
println!("Consumed key sequence: {}", task_1.seq);
println!("Ratchet state: {}", task_1.state);
fs::remove_file(transport).expect("failed to remove transport file");
}