Rust Platform Guide

This guide covers the installation, setup, and usage of MetaMUI Crypto Primitives in Rust projects.

Installation

Add MetaMUI to your Cargo.toml:

[dependencies]
metamui-crypto = "0.1.0"

Or install specific algorithms:

[dependencies]
metamui-crypto-aes = "0.1.0"
metamui-crypto-chacha20 = "0.1.0"
metamui-crypto-ed25519 = "0.1.0"

Quick Start

use metamui_crypto::{Ed25519, ChaCha20Poly1305};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Generate Ed25519 keypair
    let keypair = Ed25519::generate_keypair();
    
    // Sign a message
    let message = b"Hello, MetaMUI!";
    let signature = Ed25519::sign(message, &keypair.private_key)?;
    
    // Verify signature
    let is_valid = Ed25519::verify(&signature, message, &keypair.public_key)?;
    println!("Signature valid: {}", is_valid);
    
    // Encrypt with ChaCha20-Poly1305
    let key = ChaCha20Poly1305::generate_key();
    let cipher = ChaCha20Poly1305::new(&key);
    
    let plaintext = b"Secret message";
    let nonce = ChaCha20Poly1305::generate_nonce();
    
    let (ciphertext, tag) = cipher.encrypt(plaintext, &nonce, None)?;
    
    // Decrypt
    let decrypted = cipher.decrypt(&ciphertext, &tag, &nonce, None)?;
    assert_eq!(decrypted, plaintext);
    
    Ok(())
}

Features

Feature Flags

Enable specific features in Cargo.toml:

[dependencies]
metamui-crypto = { version = "0.1.0", features = ["full"] }

# Or select specific features:
metamui-crypto = { 
    version = "0.1.0", 
    features = ["aes", "chacha20", "ed25519", "post-quantum"] 
}

Available features:

No-std Support

For embedded systems:

[dependencies]
metamui-crypto = { version = "0.1.0", default-features = false, features = ["no-std"] }
#![no_std]

use metamui_crypto::{ChaCha20, Poly1305};

// Works in no-std environments

Common Patterns

Error Handling

use metamui_crypto::{Error, Result};

fn encrypt_data(data: &[u8], key: &[u8]) -> Result<Vec<u8>> {
    if key.len() != 32 {
        return Err(Error::InvalidKeyLength);
    }
    
    let cipher = ChaCha20Poly1305::new(key)?;
    let nonce = ChaCha20Poly1305::generate_nonce();
    
    let (ciphertext, tag) = cipher.encrypt(data, &nonce, None)?;
    
    // Combine nonce + tag + ciphertext
    let mut result = Vec::with_capacity(12 + 16 + ciphertext.len());
    result.extend_from_slice(&nonce);
    result.extend_from_slice(&tag);
    result.extend_from_slice(&ciphertext);
    
    Ok(result)
}

Secure Key Management

use metamui_crypto::{SecureBytes, Zeroize};
use std::ops::Drop;

struct SecretKey {
    key: SecureBytes<32>,
}

impl SecretKey {
    fn new() -> Self {
        Self {
            key: SecureBytes::random(),
        }
    }
    
    fn as_bytes(&self) -> &[u8] {
        self.key.as_ref()
    }
}

impl Drop for SecretKey {
    fn drop(&mut self) {
        self.key.zeroize();
    }
}

Async Support

use metamui_crypto::{Argon2, ChaCha20Poly1305};
use tokio::task;

async fn derive_and_encrypt(password: String, data: Vec<u8>) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    // CPU-intensive key derivation in blocking task
    let key = task::spawn_blocking(move || {
        let salt = generate_salt();
        Argon2::default().derive_key(password.as_bytes(), &salt, 32)
    }).await??;
    
    // Encryption can be done in async context
    let cipher = ChaCha20Poly1305::new(&key);
    let nonce = ChaCha20Poly1305::generate_nonce();
    
    let (ciphertext, tag) = cipher.encrypt(&data, &nonce, None)?;
    
    Ok(ciphertext)
}

Performance Optimization

Hardware Acceleration

use metamui_crypto::aes::{Aes256, HardwareAcceleration};

fn setup_aes() -> Aes256 {
    if HardwareAcceleration::available() {
        println!("Using AES-NI hardware acceleration");
        Aes256::with_hardware_acceleration()
    } else {
        println!("Using software AES implementation");
        Aes256::new()
    }
}

Batch Operations

use metamui_crypto::Ed25519;
use rayon::prelude::*;

fn verify_signatures_parallel(
    signatures: &[(Signature, Message, PublicKey)]
) -> Vec<bool> {
    signatures
        .par_iter()
        .map(|(sig, msg, pk)| Ed25519::verify(sig, msg, pk).unwrap_or(false))
        .collect()
}

// Or use built-in batch verification (more efficient)
fn verify_signatures_batch(
    signatures: &[Signature],
    messages: &[Message],
    public_keys: &[PublicKey],
) -> Result<bool, Error> {
    Ed25519::batch_verify(signatures, messages, public_keys)
}

Testing

Unit Tests

#[cfg(test)]
mod tests {
    use super::*;
    use metamui_crypto::test_vectors;
    
    #[test]
    fn test_encryption_roundtrip() {
        let key = ChaCha20Poly1305::generate_key();
        let cipher = ChaCha20Poly1305::new(&key);
        
        let plaintext = b"test message";
        let nonce = ChaCha20Poly1305::generate_nonce();
        
        let (ciphertext, tag) = cipher.encrypt(plaintext, &nonce, None).unwrap();
        let decrypted = cipher.decrypt(&ciphertext, &tag, &nonce, None).unwrap();
        
        assert_eq!(decrypted, plaintext);
    }
    
    #[test]
    fn test_known_vectors() {
        for vector in test_vectors::chacha20_poly1305() {
            let cipher = ChaCha20Poly1305::new(&vector.key);
            let (ciphertext, tag) = cipher.encrypt(
                &vector.plaintext,
                &vector.nonce,
                vector.aad.as_deref()
            ).unwrap();
            
            assert_eq!(ciphertext, vector.expected_ciphertext);
            assert_eq!(tag, vector.expected_tag);
        }
    }
}

Benchmarking

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use metamui_crypto::{ChaCha20Poly1305, Aes256Gcm};

fn benchmark_encryption(c: &mut Criterion) {
    let key = [0u8; 32];
    let nonce = [0u8; 12];
    let data = vec![0u8; 1024 * 1024]; // 1MB
    
    let mut group = c.benchmark_group("encryption");
    
    group.bench_function("chacha20-poly1305", |b| {
        let cipher = ChaCha20Poly1305::new(&key);
        b.iter(|| {
            let (ct, tag) = cipher.encrypt(black_box(&data), &nonce, None).unwrap();
            black_box((ct, tag));
        });
    });
    
    group.bench_function("aes256-gcm", |b| {
        let cipher = Aes256Gcm::new(&key);
        b.iter(|| {
            let (ct, tag) = cipher.encrypt(black_box(&data), &nonce, None).unwrap();
            black_box((ct, tag));
        });
    });
    
    group.finish();
}

criterion_group!(benches, benchmark_encryption);
criterion_main!(benches);

Integration Examples

Web Server (Actix-web)

use actix_web::{web, App, HttpServer, Result};
use metamui_crypto::{Ed25519, ChaCha20Poly1305};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct EncryptRequest {
    data: String,
}

#[derive(Serialize)]
struct EncryptResponse {
    ciphertext: String,
    nonce: String,
    tag: String,
}

async fn encrypt_endpoint(
    req: web::Json<EncryptRequest>,
    key: web::Data<[u8; 32]>,
) -> Result<web::Json<EncryptResponse>> {
    let cipher = ChaCha20Poly1305::new(&**key);
    let nonce = ChaCha20Poly1305::generate_nonce();
    
    let (ciphertext, tag) = cipher
        .encrypt(req.data.as_bytes(), &nonce, None)
        .map_err(|e| actix_web::error::ErrorInternalServerError(e))?;
    
    Ok(web::Json(EncryptResponse {
        ciphertext: base64::encode(&ciphertext),
        nonce: base64::encode(&nonce),
        tag: base64::encode(&tag),
    }))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let key = ChaCha20Poly1305::generate_key();
    
    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(key))
            .route("/encrypt", web::post().to(encrypt_endpoint))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

CLI Tool

use clap::{Parser, Subcommand};
use metamui_crypto::{Ed25519, ChaCha20Poly1305};
use std::fs;
use std::path::PathBuf;

#[derive(Parser)]
#[command(name = "metamui-crypto")]
#[command(about = "MetaMUI Crypto CLI", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Generate a new keypair
    Keygen {
        /// Algorithm to use
        #[arg(short, long, default_value = "ed25519")]
        algorithm: String,
        
        /// Output file
        #[arg(short, long)]
        output: PathBuf,
    },
    
    /// Encrypt a file
    Encrypt {
        /// Input file
        #[arg(short, long)]
        input: PathBuf,
        
        /// Output file
        #[arg(short, long)]
        output: PathBuf,
        
        /// Key file
        #[arg(short, long)]
        key: PathBuf,
    },
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cli = Cli::parse();
    
    match cli.command {
        Commands::Keygen { algorithm, output } => {
            match algorithm.as_str() {
                "ed25519" => {
                    let keypair = Ed25519::generate_keypair();
                    let encoded = serde_json::to_string_pretty(&keypair)?;
                    fs::write(output, encoded)?;
                    println!("Keypair generated successfully");
                }
                _ => eprintln!("Unknown algorithm: {}", algorithm),
            }
        }
        
        Commands::Encrypt { input, output, key } => {
            let key_data = fs::read(key)?;
            let key: [u8; 32] = key_data.try_into()
                .map_err(|_| "Invalid key length")?;
            
            let plaintext = fs::read(input)?;
            
            let cipher = ChaCha20Poly1305::new(&key);
            let nonce = ChaCha20Poly1305::generate_nonce();
            
            let (ciphertext, tag) = cipher.encrypt(&plaintext, &nonce, None)?;
            
            // Write nonce + tag + ciphertext
            let mut output_data = Vec::new();
            output_data.extend_from_slice(&nonce);
            output_data.extend_from_slice(&tag);
            output_data.extend_from_slice(&ciphertext);
            
            fs::write(output, output_data)?;
            println!("File encrypted successfully");
        }
    }
    
    Ok(())
}

Best Practices

  1. Always use zeroize for sensitive data
  2. Generate random values using OsRng or ThreadRng
  3. Use type-safe wrappers for keys and nonces
  4. Enable all compiler warnings and clippy lints
  5. Run tests with --release flag for accurate benchmarks
  6. Use #[must_use] for functions returning Result

Troubleshooting

Common Issues

  1. Compilation Errors
    # Clear cargo cache
    cargo clean
       
    # Update dependencies
    cargo update
       
    # Check for conflicting features
    cargo tree -d
    
  2. Performance Issues
    // Enable optimizations
    #[cfg(not(debug_assertions))]
    compile_error!("This crate should be compiled in release mode");
       
    // Check CPU features
    if is_x86_feature_detected!("aes") {
        // Use AES-NI
    }
    
  3. Memory Leaks
    // Use Valgrind or AddressSanitizer
    RUSTFLAGS="-Z sanitizer=address" cargo test
    

Resources