chacha20poly1305-nostd

Crates.iochacha20poly1305-nostd
lib.rschacha20poly1305-nostd
version0.1.0
created_at2025-12-22 11:26:26.737148+00
updated_at2025-12-22 11:26:26.737148+00
descriptionPure-Rust ChaCha20-Poly1305 AEAD implementation for no_std/bare-metal targets (avoids LLVM SIMD issues)
homepagehttps://github.com/artst3in/chacha20poly1305-nostd
repositoryhttps://github.com/artst3in/chacha20poly1305-nostd
max_upload_size
id1999582
size32,595
The Architect (artst3in)

documentation

https://docs.rs/chacha20poly1305-nostd

README

chacha20poly1305-nostd

Pure-Rust ChaCha20-Poly1305 AEAD (Authenticated Encryption with Associated Data) implementation for no_std and bare-metal targets.

Why This Crate Exists

The standard chacha20poly1305 crate (from RustCrypto) fails to compile on certain bare-metal targets like x86_64-unknown-none with LLVM errors:

LLVM ERROR: Do not know how to split the result of this operator!

This happens because the crate depends on other crates that use SIMD intrinsics unavailable on all targets. This pure-Rust implementation avoids SIMD entirely, making it portable to any Rust target.

Features

  • 100% Pure Rust: No assembly, no SIMD, no platform-specific code
  • no_std compatible: Works in bare-metal and embedded environments
  • Constant-time: Side-channel resistant implementation
  • RFC 8439 compliant: Passes official test vectors
  • AEAD: Provides both confidentiality and authenticity
  • Simple API: Encrypt and decrypt with associated data support

Security Properties

  • 256-bit key, 96-bit nonce
  • 128-bit authentication tag
  • Constant-time operations
  • ~4 cycles/byte on modern x86_64
  • Resists tampering, replay, and forgery attacks

Usage

Add to your Cargo.toml:

[dependencies]
chacha20poly1305-nostd = "0.1"

Basic Encryption/Decryption

use chacha20poly1305_nostd::ChaCha20Poly1305;

let key = [0u8; 32];   // 256-bit key
let nonce = [0u8; 12]; // 96-bit nonce (MUST be unique per message)

let cipher = ChaCha20Poly1305::new(&key).unwrap();

// Encrypt
let plaintext = b"Hello, Luna!";
let ciphertext = cipher.encrypt(&nonce, plaintext, None).unwrap();
// ciphertext = encrypted_data || 16-byte authentication tag

// Decrypt
let decrypted = cipher.decrypt(&nonce, &ciphertext, None).unwrap();
assert_eq!(decrypted, plaintext);

With Associated Authenticated Data (AAD)

use chacha20poly1305_nostd::ChaCha20Poly1305;

let key = [0u8; 32];
let nonce = [0u8; 12];
let cipher = ChaCha20Poly1305::new(&key).unwrap();

let plaintext = b"Secret message";
let aad = b"public header"; // Authenticated but not encrypted

// Encrypt with AAD
let ciphertext = cipher.encrypt(&nonce, plaintext, Some(aad)).unwrap();

// Decrypt with AAD (must match!)
let decrypted = cipher.decrypt(&nonce, &ciphertext, Some(aad)).unwrap();
assert_eq!(decrypted, plaintext);

// Wrong AAD fails authentication
let result = cipher.decrypt(&nonce, &ciphertext, Some(b"wrong"));
assert!(result.is_err());

Algorithm

ChaCha20-Poly1305 combines two primitives:

  1. ChaCha20: Stream cipher for encryption

    • 20 rounds of the ChaCha quarter-round function
    • 256-bit key, 96-bit nonce, 32-bit counter
  2. Poly1305: Message authentication code

    • One-time MAC using key derived from ChaCha20
    • 128-bit authentication tag

Construction (RFC 8439)

  1. Generate Poly1305 key from ChaCha20 block 0
  2. Encrypt plaintext with ChaCha20 (starting from block 1)
  3. Compute Poly1305 MAC over: AAD || pad || ciphertext || pad || lengths
  4. Append authentication tag to ciphertext

Implementation Details

  • Uses poly1305-nostd for authentication
  • Uses standard chacha20 crate (no SIMD issues)
  • Constant-time tag comparison to prevent timing attacks
  • No heap allocations except for output buffers

Performance

On modern x86_64 CPUs:

  • ~4 cycles/byte for encryption + authentication
  • ~2 µs for 1 KB message

(Performance varies by target; bare-metal may differ)

Compatibility

Tested on:

  • x86_64-unknown-none (bare-metal)
  • x86_64-unknown-linux-gnu (std)
  • Other targets should work but are untested

Security Notes

  1. Never reuse nonces: Each (key, nonce) pair must be unique
  2. Nonce handling: Use a counter or random nonces (96 bits provides good margin)
  3. AAD validation: Ensure AAD matches on decryption
  4. Tag verification: Always check decrypt() return value

Use Cases

  • WireGuard: Transport data encryption
  • SSH: chacha20-poly1305@openssh.com cipher
  • TLS 1.3: Modern cipher suite
  • Secure messaging: Signal Protocol, Matrix
  • File encryption: With proper key derivation

Testing

Run the test suite:

cargo test

Includes RFC 8439 Appendix A.5 test vector.

License

Licensed under Apache License 2.0.

References

Contributing

Contributions welcome! This crate was extracted from a bare-metal OS project to help the Rust embedded and bare-metal community overcome LLVM SIMD limitations.

Commit count: 0

cargo fmt