- # 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**](SPEC.md) file. For a detailed performance analysis, see [**BENCHMARKS.md**](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.
```rust
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";
let mut encrypt_stream = quasor.create_encrypt_stream(plaintext, associated_data);
encrypt_stream.init();
let nonce = encrypt_stream.get_nonce().unwrap().to_vec();
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();
let mut decrypt_stream = quasor.create_decrypt_stream(&nonce, associated_data, &tag);
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
- [https://github.com/JessicaMulein/Quasor](https://github.com/JessicaMulein/Quasor)
- [https://quasor.jessicamulein.com](https://quasor.jessicamulein.com/)