quasor

Crates.ioquasor
lib.rsquasor
version6.1.6
created_at2025-07-05 23:53:57.96084+00
updated_at2025-07-14 03:02:39.643144+00
descriptionA high-security AEAD based on a Duplex Sponge construction with SHAKE256, Argon2id, and BLAKE3.
homepage
repositoryhttps://github.com/Digital-Defiance/Quasor
max_upload_size
id1739583
size101,696
Jessica Mulein (JessicaMulein)

documentation

README

  • Quasor: A High-Security AEAD

    Version 6.1.3

    1. Overview

    Quasor is an experimental, high-security Authenticated Encryption with Associated Data (AEAD) scheme implemented in Rust. It is designed for modern applications where robustness, defense-in-depth, and resistance to common implementation pitfalls are critical.

    The construction is based on a duplex sponge using SHAKE256, providing a strong foundation for post-quantum security. The v6.1 release includes significant performance optimizations, increasing throughput by 5-7x over previous versions without compromising any security features.

    ⚠️ Warning: Quasor is a research-grade cipher. It has not undergone formal, third-party cryptographic review. It should be used for experimental, educational, or research purposes, not for production systems handling sensitive data.

    2. Core Features

    • Post-Quantum Resistance: The core cipher uses a SHAKE256 sponge, which is built on a 1600-bit permutation, providing a high security margin against both classical and quantum cryptanalysis.
    • Nonce-Misuse Resistance: Implements a Synthetic Initialization Vector (SIV) mechanism using a keyed BLAKE3 hash. The nonce is derived deterministically from the message and associated data.
    • Forward Secrecy & Key Erasure: An automatic rekeying mechanism is integrated into the duplexing process. After every 1 MiB of data, the sponge's internal state is used to generate a new key, and the old key material is cryptographically erased.
    • Memory-Hard Key Derivation: Uses Argon2id with its recommended secure defaults to derive the master encryption key from a user-provided password.
    • Streaming API: A chunk-based processing API for large files to minimize memory usage.
    • Side-Channel Resistant: Critical comparisons (e.g., tag verification) are performed using constant-time functions from the subtle crate to protect against timing attacks.
    • Secure Memory Management: The implementation uses the zeroize crate to securely overwrite sensitive key material in memory as soon as it goes out of scope.

    3. Cryptographic Construction

    Quasor is a stateful AEAD built on the following primitives:

    Role Primitive Rationale
    Password Hashing Argon2id Memory-hard KDF to protect user passwords.
    Nonce Derivation (SIV) BLAKE3 (Keyed) Extremely fast, parallelizable hash for deriving a unique nonce from message content.
    Core Cipher SHAKE256 Duplex A single, elegant primitive for providing both confidentiality and authentication.

    The high-level process is as follows:

    1. A master key K is derived from a password and salt using Argon2id.
    2. A nonce N is derived via N = BLAKE3(K, len(AD) || AD || len(P) || P).
    3. A SHAKE256 sponge is initialized by absorbing K, N, and AD.
    4. The plaintext is processed sequentially in efficient 1KB chunks, duplexing with the sponge to produce ciphertext. The sponge is automatically re-keyed every 1 MiB.
    5. A final authentication tag T is squeezed from the sponge's state.

    For a complete technical description, see the SPEC.md file. For a detailed performance analysis, see BENCHMARKS.md.

    4. Usage Example

    use quasor::Quasor;
    
    fn main() {
        // 1. Derive the master key from a password and a unique salt.
        // This is intentionally slow.
        let quasor = Quasor::new(b"a_very_strong_password", b"a_unique_salt_for_this_user").unwrap();
    
        let plaintext = b"This data is highly confidential.";
        let associated_data = b"message_id:12345";
    
        // 2. Encrypt the data.
        // The nonce is derived internally and returned.
        let (ciphertext, tag, nonce) = quasor.encrypt(plaintext, associated_data);
    
        // 3. Store the ciphertext, tag, and nonce together.
        // ...
    
        // 4. Decrypt the data.
        let result = quasor.decrypt(&nonce, &ciphertext, associated_data, &tag);
    
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), plaintext);
    }
    

    4.1. Streaming API Usage

    For large files, a streaming API is available. This allows you to process data in chunks, which is useful for applications with memory constraints.

    Note: The entire plaintext is required upfront for the encryption stream to derive the nonce. The encryption of the data itself can then be done in a streaming fashion.

    use quasor::Quasor;
    
    fn main() {
        let quasor = Quasor::new(b"a_very_strong_password", b"a_unique_salt_for_this_user").unwrap();
        let plaintext = b"This is a very long message that we want to stream.";
        let associated_data = b"streaming_message_id:67890";
    
        // --- Streaming Encryption ---
        let mut encrypt_stream = quasor.create_encrypt_stream(plaintext, associated_data);
        encrypt_stream.init(); // Must be called first!
    
        let nonce = encrypt_stream.get_nonce().unwrap().to_vec();
    
        // Process plaintext in chunks
        let chunk1 = &plaintext[0..20];
        let chunk2 = &plaintext[20..];
        let c_chunk1 = encrypt_stream.process(chunk1).unwrap();
        let c_chunk2 = encrypt_stream.process(chunk2).unwrap();
    
        let tag = encrypt_stream.finalize().unwrap().to_vec();
        let ciphertext = [c_chunk1.as_slice(), c_chunk2.as_slice()].concat();
    
        // --- Streaming Decryption ---
        let mut decrypt_stream = quasor.create_decrypt_stream(&nonce, associated_data, &tag);
    
        // Process ciphertext in chunks
        let p_chunk1 = decrypt_stream.process(&ciphertext[0..c_chunk1.len()]);
        let p_chunk2 = decrypt_stream.process(&ciphertext[c_chunk1.len()..]);
    
        let result = decrypt_stream.finalize();
        assert!(result.is_ok());
    
        let decrypted_plaintext = [p_chunk1.as_slice(), p_chunk2.as_slice()].concat();
        assert_eq!(decrypted_plaintext, plaintext);
    }
    

    5. Building and Testing

    The project is a standard Cargo package.

    # Run all fast unit and integration tests
    cargo test
    
    # Run the slow, exhaustive property-based tests (requires patience)
    cargo test -- --ignored
    
    # Run the performance benchmark suite
    cargo bench
    

    Forks

Commit count: 0

cargo fmt