secret_rotation/
secret_rotation.rs1use anyhow::Result;
2use ed25519_dalek::SigningKey;
3use iroh::{Endpoint, SecretKey};
4use iroh_gossip::{api::Event, net::Gossip};
5use sha2::Digest;
6
7use distributed_topic_tracker::{
9 AutoDiscoveryGossip, Config, RecordPublisher, RotationHandle, SecretRotation, TopicId
10};
11
12struct MySecretRotation;
13impl SecretRotation for MySecretRotation {
14 fn derive(
15 &self,
16 topic_hash: [u8; 32],
17 unix_minute: u64,
18 initial_secret_hash: [u8; 32],
19 ) -> [u8; 32] {
20 let mut hash = sha2::Sha512::new();
21 hash.update(topic_hash);
22 hash.update(unix_minute.to_be_bytes());
23 hash.update(initial_secret_hash);
24 hash.update(b"as long as you return 32 bytes this is a valid secret rotation function");
25 hash.finalize()[..32].try_into().expect("hashing failed")
26 }
27}
28
29#[tokio::main]
30async fn main() -> Result<()> {
31 let secret_key = SecretKey::generate();
33 let signing_key = SigningKey::from_bytes(&secret_key.to_bytes());
34
35 let endpoint = Endpoint::builder(iroh::endpoint::presets::N0)
37 .secret_key(secret_key.clone())
38 .bind()
39 .await?;
40
41 let gossip = Gossip::builder().spawn(endpoint.clone());
43
44 let _router = iroh::protocol::Router::builder(endpoint.clone())
46 .accept(iroh_gossip::ALPN, gossip.clone())
47 .spawn();
48
49 let topic_id = TopicId::new("my-iroh-gossip-topic".to_string());
50 let initial_secret = b"my-initial-secret".to_vec();
51
52 let record_publisher = RecordPublisher::new(
53 topic_id.clone(),
54 signing_key.clone(),
55 Some(RotationHandle::new(MySecretRotation)),
56 initial_secret,
57 Config::default(),
58 );
59 let (gossip_sender, mut gossip_receiver) = gossip
60 .subscribe_and_join_with_auto_discovery(record_publisher)
61 .await?
62 .split()
63 .await?;
64
65 println!("Joined topic");
66
67 tokio::spawn(async move {
69 while let Ok(event) = gossip_receiver.next().await {
70 if let Event::Received(msg) = event {
71 println!(
72 "\nMessage from {}: {}",
73 &msg.delivered_from.to_string()[0..8],
74 String::from_utf8(msg.content.to_vec()).unwrap()
75 );
76 } else if let Event::NeighborUp(peer) = event {
77 println!("\nJoined by {}", &peer.to_string()[0..8]);
78 }
79 }
80 println!("\nGossip receiver stream ended");
81 });
82
83 let mut buffer = String::new();
85 let stdin = std::io::stdin();
86 loop {
87 print!("\n> ");
88 stdin.read_line(&mut buffer).unwrap();
89 gossip_sender
90 .broadcast(buffer.clone().replace("\n", "").into())
91 .await
92 .unwrap();
93 println!(" - (sent)");
94 buffer.clear();
95 }
96}