Files
mfahampshire a70e68c7bd Max/smolmix docs (#6716)
* Smolmix documentation

* Add smolmix docs: landing page, tutorials, and developer page links

* Add Exit Gateway services page (NR vs IPR) and link from existing docs

* Update auto-generated command and API outputs

* Reorg of tutorials and architecture pages

* License information + remove TODO from docs.rs visibile comment + reorg
readme

* Add versions file for doc-wide versioning

* Relative -> absolute links

* Relative -> absolute links

* Update license + add old tutorial code as examples

* Streamline smolmix docs

* Clippy

* Clean up doc comments

* Last pass

* Add larger file download to list

* set new versions

* Clippy

* Remove blake pin from docs + add version range to root Cargo.toml

* Format example logging

* Remove crate blocked component

* Loose whitespace

* Add doc verification script for inline mdx

* Formatting

* Components regen

* Reorg + tighten text

* Voicing cohesion pass + remove bloated examples

* Voicing cont.

* Reduce max download size

* Small suggested clarifications

* Max/docs voicing consistency (#6769)

* Reduce max download size

* voicing consistency across docs

* New landing order w smolmix

* Tweaks

* Final tweaks
2026-05-13 11:19:44 +00:00

85 lines
3.0 KiB
Rust

//! Anonymous replies using SURBs (Single Use Reply Blocks).
//!
//! Sends a message to self, extracts the `AnonymousSenderTag` from the
//! incoming message, and replies using `send_reply()` without knowing
//! the sender's Nym address. The SDK bundles SURBs with every outgoing
//! message by default, so the recipient can always reply anonymously.
//!
//! ## What this demonstrates
//!
//! - Every incoming message carries a `sender_tag`, an opaque
//! [`AnonymousSenderTag`] that enables replies without revealing the
//! sender's address
//! - `send_reply()` consumes a SURB to route the reply back through the
//! mixnet. Each SURB is single-use; the SDK replenishes them automatically
//! - This is the foundation for anonymous communication: the server never
//! learns who is talking to it
//!
//! ```sh
//! cargo run --example surb_reply
//! ```
use nym_sdk::mixnet::{
AnonymousSenderTag, MixnetClientBuilder, MixnetMessageSender, ReconstructedMessage,
StoragePaths,
};
use std::path::PathBuf;
use tempfile::TempDir;
#[tokio::main]
async fn main() {
nym_bin_common::logging::setup_tracing_logger();
// Build a client with persistent key storage.
// Keys are generated on first run, then loaded from disk on subsequent runs.
let config_dir: PathBuf = TempDir::new().unwrap().path().to_path_buf();
let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap();
let client = MixnetClientBuilder::new_with_default_storage(storage_paths)
.await
.unwrap()
.build()
.unwrap();
let mut client = client.connect_to_mixnet().await.unwrap();
let our_address = client.nym_address();
println!("\nOur client nym address is: {our_address}");
// Send a message to ourselves.
client
.send_plain_message(*our_address, "hello there")
.await
.unwrap();
// Receive the message.
println!("Waiting for message\n");
let mut message: Vec<ReconstructedMessage> = Vec::new();
// Filter empty messages: these are SURB replenishment requests.
while let Some(new_message) = client.wait_for_messages().await {
if new_message.is_empty() {
continue;
}
message = new_message;
break;
}
let parsed = String::from_utf8(message[0].message.clone()).unwrap();
// Extract the AnonymousSenderTag from the incoming message.
// This opaque token lets you reply without knowing the sender's address.
// The SDK includes SURBs with every message by default.
let return_recipient: AnonymousSenderTag = message[0].sender_tag.unwrap();
println!("Received: {parsed}\nSender tag: {return_recipient}");
// Reply anonymously using send_reply() instead of send_plain_message().
println!("Replying using SURBs...");
client
.send_reply(return_recipient, "hi an0n!")
.await
.unwrap();
// Receive the reply.
println!("Waiting for reply (ctrl-c to exit)\n");
client
.on_messages(|msg| println!("Received: {}", String::from_utf8_lossy(&msg.message)))
.await;
}