MACE is a lightweight, high-performance symmetric encryption framework designed for cryptographic systems. It provides a flexible core encryption primitive based on the BLAKE3 hash function and layered round transformations.
This implementation is intentionally low-level and avoids reliance on common encryption frameworks (like AES-GCM or ChaCha20-Poly1305). Instead, it focuses on deterministic, composable, and structurally reversible transformations that make it easier to experiment with advanced cryptographic architectures.
MACE operates as a reversible transformation engine that processes data in fixed-size chunks. Each chunk of plaintext (or ciphertext) is combined with its neighbors and hashed through BLAKE3 to produce diffusion and nonlinearity. The process repeats across several rounds, where each round depends on a difficulty parameter.
Unlike conventional ciphers, MACE:
- Derives its key stream dynamically from a BLAKE3 hasher.
- Uses the key and salt to generate a session-specific keyed BLAKE3 instance.
- Performs forward and backward transformations that are mathematically invertible.
The structure of MACE makes it adaptable for use in deterministic or randomized encryption, AEAD-like integrity protection, and even mixin-based key diversification.
| Property | Description |
|---|---|
| Algorithm Base | BLAKE3 (keyed + deriveKey) |
| Mode of Operation | Chunk-based iterative diffusion rounds |
| Encryption/Decryption | Fully symmetric and reversible |
| Determinism | Optional (for reproducible ciphertexts) |
| Salt | 12 bytes random (omitted if deterministic) |
| Chunk Size | 32 or 64 bytes (auto-selected) |
| Security Layer | Strength depends on difficulty (round depth) |
The base encryption and decryption functions. They perform reversible transformation using a key, context, salt, and difficulty.
Adds a mixin input that is folded into key derivation. It’s useful for session binding or additional entropy but does not act as authenticated data.
Extends MACE with a MAC tag generated from the final keyed BLAKE3 state. The tag authenticates both the ciphertext and the difficulty value. Use this when authenticity matters.
Combines both mixin-based key diversification and AEAD-style authentication. The strongest and safest variant.
- Always check the
validflag from AEAD decryptions before using the plaintext. (This implementation always return decrypted value, even if its totally broken - avoides time attacks but could break the functionality if you forget to checkvalidflag) - Deterministic mode leaks message equality and should be used only when intentional.
- Input buffers are modified in-place. Make a copy if you need to preserve input.
- Padding errors return truncated data even when invalid. Always check the returned error.
Each encryption round works as follows:
- Split the data into chunks of fixed size (32 or 64 bytes).
- Process from the last chunk to the first (for encryption) and vice versa for decryption.
- For each chunk, compute a BLAKE3 hash of its neighbor chunk(s) and round/chunk indices.
- XOR the digest with the current chunk to introduce diffusion.
- Repeat for multiple rounds based on the difficulty parameter.
The decryption process mirrors this exactly but iterates rounds in reverse order.
// Encrypt
data := []byte("hello world")
key := []byte("supersecretkey123")
cipher, salt := MACE_Encrypt(key, data, "demo", 4, false)
// Decrypt
plain, err := MACE_Decrypt(key, cipher, salt, "demo", 4)
if err != nil {
panic(err)
}
fmt.Println(string(plain))- Difficulty controls the number of rounds:
rounds = 2*difficulty + 3. - Salt is 12 bytes and random unless deterministic mode is on.
- Key derivation combines:
key + salt + contextusing BLAKE3 deriveKey. - MACE is fully reversible — no internal state loss.
- The AEAD tag is 16 bytes derived from keyed BLAKE3.
This project is licensed under the GNU LGPL v3.0 License.
Copyright (c) 2025 MHSarmadi