secret_rotation/
secret_rotation.rs

1use anyhow::Result;
2use iroh::{Endpoint, SecretKey};
3use iroh_gossip::{api::Event, net::Gossip};
4use sha2::Digest;
5
6// Imports from distrubuted-topic-tracker
7use distributed_topic_tracker::{
8    AutoDiscoveryBuilder, AutoDiscoveryGossip, SecretRotation, TopicId,
9};
10
11
12#[derive(Debug, Clone, Copy)]
13#[derive(Default)]
14struct MySecretRotation;
15
16impl SecretRotation for MySecretRotation {
17    fn get_unix_minute_secret(
18        &self,
19        topic_hash: [u8; 32],
20        unix_minute: u64,
21        initial_secret_hash: [u8; 32],
22    ) -> [u8; 32] {
23        let mut hash = sha2::Sha512::new();
24        hash.update(topic_hash);
25        hash.update(unix_minute.to_be_bytes());
26        hash.update(initial_secret_hash);
27        hash.update(b"as long as you return 32 bytes this is a valid secret rotation function");
28        hash.finalize()[..32].try_into().expect("hashing failed")
29    }
30}
31
32#[tokio::main]
33async fn main() -> Result<()> {
34    // Generate a new random secret key
35    let secret_key = SecretKey::generate(rand::rngs::OsRng);
36
37    // Set up endpoint with discovery enabled
38    let endpoint = Endpoint::builder()
39        .secret_key(secret_key)
40        .discovery_n0()
41        .bind()
42        .await?;
43
44    // Initialize gossip with auto-discovery
45    let gossip = Gossip::builder()
46        .spawn_with_auto_discovery::<MySecretRotation>(endpoint.clone(), None)
47        .await?;
48
49    // Set up protocol router
50    let _router = iroh::protocol::Router::builder(endpoint.clone())
51        .accept(iroh_gossip::ALPN, gossip.gossip.clone())
52        .spawn();
53
54    let topic_id = TopicId::new("my-iroh-gossip-topic".to_string());
55    let initial_secret = b"my-initial-secret".to_vec();
56
57    // Split into sink (sending) and stream (receiving)
58    let (sink, mut stream) = gossip
59        .subscribe_and_join_with_auto_discovery(topic_id, initial_secret)
60        .await?
61        .split();
62
63    println!("Joined topic");
64
65    // Spawn listener for incoming messages
66    tokio::spawn(async move {
67        let mut reader = stream.subscribe().await.unwrap();
68        while let Ok(event) = reader.recv().await {
69            if let Event::Received(msg) = event {
70                println!(
71                    "\nMessage from {}: {}",
72                    &msg.delivered_from.to_string()[0..8],
73                    String::from_utf8(msg.content.to_vec()).unwrap()
74                );
75            } else if let Event::NeighborUp(peer) = event {
76                println!("\nJoined by {}", &peer.to_string()[0..8]);
77            }
78        }
79    });
80
81    // Main input loop for sending messages
82    let mut buffer = String::new();
83    let stdin = std::io::stdin();
84    loop {
85        print!("\n> ");
86        stdin.read_line(&mut buffer).unwrap();
87        sink.broadcast(buffer.clone().replace("\n", "").into())
88            .await
89            .unwrap();
90        println!(" - (sent)");
91        buffer.clear();
92    }
93}