Code Import Examples
This page demonstrates different ways to include code in Docusaurus documentation.
Method 1: Manual Code Blocks
The simplest approach is to manually write code blocks:
Manual Example
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExampleStruct {
pub field1: String,
pub field2: u32,
}
Method 2: Import Entire Files
Import and display entire source files using raw-loader:
crates/wire-protocol/src/invitation.rs
//! Group invitation message types for PQXDH-based secure invitations
//!
//! This module defines the message types used in the group invitation flow,
//! providing type-safe structures for the multi-step verification process.
use crate::{Tag, VerifyingKey};
use serde::{Deserialize, Serialize};
/// Protocol version for invitation messages
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub enum InboxHandshakeProtocolVersion {
V1,
}
/// Purpose of the PQXDH handshake session
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub enum HandshakePurpose {
GroupInvitation,
DirectMessage,
FileTransfer,
// Future purposes can be added here
}
/// Initial handshake request sent in PqxdhInitialMessage payload
///
/// This message establishes the PQXDH session and requests verification.
/// It contains NO sensitive group information for security.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct VerificationHandshakeRequest {
pub protocol_version: InboxHandshakeProtocolVersion,
pub purpose: HandshakePurpose,
pub timestamp: u64,
}
/// Response sent after emoji verification by the invitee
///
/// This message indicates whether the user accepted or rejected the invitation
/// after verifying the emoji sequence derived from the shared PQXDH secret.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct HandshakeResponse {
pub accepted: bool,
pub timestamp: u64,
}
/// User profile information
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct UserProfile {
pub display_name: String,
pub avatar: Option<Vec<u8>>, // Optional avatar data
pub public_key: VerifyingKey,
}
/// Group metadata shared during invitation
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct GroupMetadata {
pub name: String,
pub description: Option<String>,
pub member_count: u32,
pub created_at: u64,
}
/// Sensitive group data sent only after successful verification
///
/// This message contains all the information needed for the invitee to join
/// the group. It is only sent after the handshake has been confirmed.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct GroupInvitationData {
pub group_tag: Tag,
pub shared_aes_key: [u8; 32],
pub inviter_profile: UserProfile,
pub group_metadata: GroupMetadata,
pub timestamp: u64,
}
/// Event sent to the group to announce a new member
///
/// This is sent outside the PQXDH session to the group's regular channel
/// to notify existing members of the new joiner.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ProfileSetEvent {
pub event_type: String, // "member_joined"
pub user_profile: UserProfile,
pub timestamp: u64,
}
/// Generate a random ephemeral group invite protocol ID
///
/// Returns a random value in the range 0-999 for use with
/// PqxdhInboxProtocol::EphemeralGroupInvite(id).
/// This provides unlinkability between different invitation sessions.
pub fn generate_ephemeral_group_invite_id() -> u32 {
use rand::Rng;
let mut rng = rand::thread_rng();
rng.gen_range(0..1000)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ephemeral_id_range() {
for _ in 0..100 {
let id = generate_ephemeral_group_invite_id();
assert!(id < 1000, "Generated ID {id} should be less than 1000");
}
}
#[test]
fn test_message_serialization() {
let request = VerificationHandshakeRequest {
protocol_version: InboxHandshakeProtocolVersion::V1,
purpose: HandshakePurpose::GroupInvitation,
timestamp: 1234567890,
};
let serialized = postcard::to_allocvec(&request).unwrap();
let deserialized: VerificationHandshakeRequest = postcard::from_bytes(&serialized).unwrap();
assert_eq!(request, deserialized);
}
#[test]
fn test_handshake_response() {
let response = HandshakeResponse {
accepted: true,
timestamp: 1234567890,
};
let serialized = postcard::to_allocvec(&response).unwrap();
let deserialized: HandshakeResponse = postcard::from_bytes(&serialized).unwrap();
assert_eq!(response, deserialized);
}
}
Method 3: Collapsible Code Sections
Use details/summary for large code blocks:
Click to view full implementation
crates/app-primitives/src/invitation.rs
//! Group invitation utilities and emoji verification
//!
//! This module provides utilities for the group invitation flow, including
//! the cryptographic emoji derivation function used for PQXDH verification.
use blake3::Hasher;
/// 64 carefully chosen emojis for maximum visual distinction
///
/// These emojis are organized into categories to avoid confusion and ensure
/// cross-platform consistency. They are chosen for:
/// - Visual distinction (no similar-looking emojis)
/// - Cross-platform consistency (common emojis that render similarly)
/// - Accessibility (high contrast, distinct shapes)
/// - Cultural neutrality (avoid emojis with cultural/religious significance)
pub const EMOJI_SET: [&str; 64] = [
// Objects & Symbols (16)
"🔑", "🌟", "🚀", "🎯", "🌈", "🔒", "⚡", "🎨", "🌸", "🔥", "💎", "🎪", "🌊", "🎭", "🍀", "🌺",
// Animals & Nature (16)
"🐱", "🐶", "🦋", "🐸", "🦊", "🐧", "🦁", "🐯", "🐨", "🐼", "🦉", "🐺", "🦄", "🐙", "🦀", "🐢",
// Food & Drinks (16)
"🍎", "🍌", "🍇", "🍓", "🥝", "🍑", "🥕", "🌽", "🍄", "🥑", "🍕", "🍔", "🎂", "🍪", "☕", "🍯",
// Activities & Objects (16)
"⚽", "🏀", "🎸", "🎹", "🎲", "🎮", "📱", "💻", "⌚", "📷", "🎧", "🔍", "💡", "🔧", "⚖️", "🎁",
];
/// Derive a 6-emoji verification sequence from a PQXDH shared secret
///
/// This function takes a 32-byte shared secret and derives a sequence of 6 emojis
/// that can be displayed to users for manual verification. The derivation uses
/// BLAKE3 with domain separation to ensure the emojis cannot be used to recover
/// the original shared secret.
///
/// # Security Properties
///
/// - **One-way function**: BLAKE3 is cryptographically one-way
/// - **Domain separation**: Uses unique context string for verification
/// - **Limited exposure**: Only 48 bits of derived data used for emojis
/// - **Uniform distribution**: Each emoji has equal probability (1/64)
/// - **High collision resistance**: 64^6 = 68.7 billion possible sequences
///
/// # Algorithm
///
/// 1. Derive 32-byte fingerprint using BLAKE3 with domain separation
/// 2. Split fingerprint into 6 chunks of ~5.33 bytes each
/// 3. Convert each chunk to little-endian integer
/// 4. Map integer modulo 64 to emoji index
///
/// # Arguments
///
/// * `shared_secret` - 32-byte PQXDH shared secret
///
/// # Returns
///
/// Array of 6 emoji strings for user verification
///
/// # Example
///
/// ```rust
/// use zoe_app_primitives::invitation::derive_emoji_verification;
///
/// let shared_secret = [0u8; 32]; // Example shared secret
/// let emojis = derive_emoji_verification(&shared_secret);
/// println!("Verify these emojis match: {}", emojis.join(" "));
/// ```
pub fn derive_emoji_verification(shared_secret: &[u8; 32]) -> [&'static str; 6] {
// Derive verification fingerprint using BLAKE3 with domain separation
let mut hasher = Hasher::new();
hasher.update(shared_secret);
hasher.update(b"PQXDH-VERIFICATION-FINGERPRINT-v1");
let verification_fingerprint = hasher.finalize();
let fingerprint_bytes = verification_fingerprint.as_bytes();
// Split into 6 chunks and derive emoji for each chunk
let mut emojis = [""; 6];
for (i, emoji) in emojis.iter_mut().enumerate() {
let start = i * 5;
let end = std::cmp::min(start + 5, 32);
let chunk = &fingerprint_bytes[start..end];
// Combine bytes in chunk to get index (little-endian)
let mut index = 0u64;
for (j, &byte) in chunk.iter().enumerate() {
index += (byte as u64) << (j * 8);
}
*emoji = EMOJI_SET[(index % 64) as usize];
}
emojis
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_emoji_derivation_deterministic() {
let shared_secret = [42u8; 32];
let emojis1 = derive_emoji_verification(&shared_secret);
let emojis2 = derive_emoji_verification(&shared_secret);
assert_eq!(emojis1, emojis2, "Emoji derivation should be deterministic");
}
#[test]
fn test_emoji_derivation_different_secrets() {
let secret1 = [1u8; 32];
let secret2 = [2u8; 32];
let emojis1 = derive_emoji_verification(&secret1);
let emojis2 = derive_emoji_verification(&secret2);
assert_ne!(
emojis1, emojis2,
"Different secrets should produce different emojis"
);
}
#[test]
fn test_emoji_set_size() {
assert_eq!(
EMOJI_SET.len(),
64,
"Emoji set should contain exactly 64 emojis"
);
}
#[test]
fn test_emoji_set_uniqueness() {
let mut unique_emojis = std::collections::HashSet::new();
for emoji in &EMOJI_SET {
assert!(
unique_emojis.insert(emoji),
"Emoji set should not contain duplicates: {emoji}"
);
}
}
#[test]
fn test_domain_separation() {
let shared_secret = [100u8; 32];
// Test that different domain strings produce different results
let mut hasher1 = Hasher::new();
hasher1.update(&shared_secret);
hasher1.update(b"PQXDH-VERIFICATION-FINGERPRINT-v1");
let fingerprint1 = hasher1.finalize();
let mut hasher2 = Hasher::new();
hasher2.update(&shared_secret);
hasher2.update(b"DIFFERENT-DOMAIN-STRING");
let fingerprint2 = hasher2.finalize();
assert_ne!(
fingerprint1.as_bytes(),
fingerprint2.as_bytes(),
"Different domain strings should produce different fingerprints"
);
}
}
Method 4: Code Tabs
Show multiple related files using tabs:
- Invitation Types
- Crypto Primitives
crates/wire-protocol/src/invitation.rs (excerpt)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VerificationHandshakeRequest {
pub protocol_version: ProtocolVersion,
pub purpose: HandshakePurpose,
pub timestamp: SystemTime,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HandshakeResponse {
pub success: bool,
pub emoji_sequence: [String; 6],
}
crates/app-primitives/src/invitation.rs (excerpt)
pub const EMOJI_SET: [&str; 64] = [
"🎯", "🚀", "⭐", "🔥", "💎", "🌟", "⚡", "🎨",
"🎭", "🎪", "🎨", "🎯", "🎲", "🎸", "🎺", "🎻",
// ... more emojis
];
pub fn derive_emoji_verification(shared_secret: &[u8]) -> [&'static str; 6] {
// Implementation here...
}
Method 5: Inline Code with Highlighting
Highlight specific lines in code blocks:
Example with highlighted lines
use blake3::Hasher;
use serde::{Deserialize, Serialize}; // This line is highlighted
pub fn example_function() {
let mut hasher = Hasher::new(); // These lines
hasher.update(b"domain-separation"); // are also
let result = hasher.finalize(); // highlighted
}
Method 6: Live Code Playground
For interactive examples, you can link to the Rust Playground:
Try this in Rust Playground
fn main() {
println!("Hello from Zoe Relay!");
// Example of emoji verification
let emojis = ["🎯", "🚀", "⭐", "🔥", "💎", "🌟"];
println!("Verification emojis: {:?}", emojis);
}
▶️ Run this code in Rust Playground
Best Practices
When to Use Each Method:
- Manual Code Blocks: For examples, pseudocode, or simplified versions
- File Import: When you want to show the actual implementation
- Collapsible Sections: For large files that might overwhelm the page
- Tabs: When showing related files or different approaches
- Line Highlighting: To draw attention to specific parts
- Playground Links: For runnable examples
Tips:
- Use
titleattribute to show file paths - Use
showLineNumbersfor longer code blocks - Use
{1,3-5}syntax to highlight specific lines - Keep manual examples concise and focused
- Use collapsible sections for reference implementations
Configuration
To use raw-loader imports, make sure you have it installed:
npm install --save raw-loader
Then import files using the !!raw-loader! prefix:
import SourceCode from '!!raw-loader!../../path/to/file.rs';