Skip to main content

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:

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],
}

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:

  1. Manual Code Blocks: For examples, pseudocode, or simplified versions
  2. File Import: When you want to show the actual implementation
  3. Collapsible Sections: For large files that might overwhelm the page
  4. Tabs: When showing related files or different approaches
  5. Line Highlighting: To draw attention to specific parts
  6. Playground Links: For runnable examples

Tips:

  • Use title attribute to show file paths
  • Use showLineNumbers for 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';