Skip to content
!? ReLaX edited this page Apr 8, 2026 · 10 revisions

MASC-256: Memory Accumulator Stack Cipher 256-bit

Complete Technical Documentation β€” v1.0

Classification: Symmetric Stream Cipher Β· Custom Research Design State Width: 256-bit (four 64-bit words) Intended Use: Academic research, demonstration, security experimentation Authors: RlxChap2 License: MIT


1. Introduction

MASC-256 (Memory Accumulator Stack Cipher, 256-bit) is an experimental symmetric stream cipher whose central design thesis is that dynamic runtime memory behavior can be used as an entropy amplifier to increase diffusion without incurring the fixed-round overhead of block cipher constructions.

Design Goals

Goal Mechanism
High diffusion per byte Accumulator round with aggressive rotations
Memory-dependent keystream Stack and heap state folded into every output byte
Symmetric operation Identical encrypt / decrypt logic; state synchronizes on ciphertext bytes
Side-channel disruption Non-deterministic heap allocation addresses at runtime
Simple, auditable core ~120 lines of portable C99

Cipher Family and Positioning

MASC-256 belongs to the additive stream cipher family, where a keystream is generated from a secret key and XOR'd with plaintext byte-by-byte:

$$C_i = M_i \oplus K_i, \quad M_i = C_i \oplus K_i$$

Unlike conventional stream ciphers (RC4, Salsa20, ChaCha20) that evolve state purely through arithmetic, MASC-256 deliberately involves the OS memory allocator and stack frame layout in state evolution, making the keystream partially dependent on process-level memory entropy.

⚠️ Research Note: MASC-256 is a novel design that has not undergone formal peer cryptanalysis. It should not be used to protect sensitive production data without independent security audit. See Section 12.


2. Notation and Conventions

Symbol Meaning
$\oplus$ Bitwise XOR
$+$ Addition modulo $2^{64}$
$\lll r$ Left rotation by $r$ bits (ROTL)
$\ggg r$ Right rotation by $r$ bits (ROTR)
$&$ Bitwise AND
$a, b, c, d$ The four 64-bit words of accumulator state ACC
$K$ Key byte array of length $\ell_K$
$M_i$ Plaintext byte at position $i$
$C_i$ Ciphertext byte at position $i$
$\text{ks}_i$ Keystream byte at position $i$
$\text{ACC}_t$ Accumulator state at time-step $t$

All arithmetic on 64-bit words is implicitly $\bmod\ 2^{64}$.
Constants are 64-bit fractional-part-derived values (similar to SHA-2 IV strategy).


3. Internal State: The Accumulator (ACC)

The entire cipher state is a single 256-bit structure:

$$\text{ACC} = (a,\ b,\ c,\ d) \in \mathbb{F}_{2^{64}}^4$$

3.1 Initial Constants

State is seeded with irrational-constant-derived magic numbers (fractional parts of $\sqrt{2}$, $\sqrt{3}$, the golden ratio $\phi$, and $e$):

Word Hex Value Source Approximation
$a_0$ 0x9E3779B97F4A7C15 $\lfloor 2^{64} / \phi \rfloor$ (Golden ratio)
$b_0$ 0x6A09E667F3BCC909 $\lfloor 2^{64} \cdot {\sqrt{2}} \rfloor$
$c_0$ 0xBB67AE8584CAA73B $\lfloor 2^{64} \cdot {\sqrt{3}} \rfloor$
$d_0$ 0x3C6EF372FE94F82B $\lfloor 2^{64} \cdot {\sqrt{5}} \rfloor$

These are the same constants used in SHA-512 and BLAKE2, providing a well-distributed, bias-free starting point.

3.2 State Transition Model

Each processing step (key byte or plaintext byte) drives a full state transition:

$$\text{ACC}_{t+1} = \text{accumulator_round}\Bigl(\text{heap_mix}\bigl(\text{stack_mix}(\text{ACC}_t,\ v_t),\ s_t\bigr)\Bigr)$$

where $v_t$ and $s_t$ are step-specific values derived from the current input and accumulator.


4. Primitive Operations

4.1 Bitwise Rotation β€” ROTL / ROTR

ROTL(x, r):  (x << r) | (x >> (64 - r))
ROTR(x, r):  (x >> r) | (x << (64 - r))

Mathematical definitions:

$$\text{ROTL}(x,\ r) = (x \lll r) = (x \cdot 2^r) \bmod (2^{64} - 1) \text{ [approx.]}$$

$$\text{ROTR}(x,\ r) = (x \ggg r) = \text{ROTL}(x,\ 64 - r)$$

Diffusion effect: A single-bit change in $x$ produces exactly one bit change in $\text{ROTL}(x,r)$ but at a different position, enabling the XOR and addition operations in mixing functions to spread that change across multiple words rapidly.

In accumulator_round, four consecutive rotations with prime-like offsets (17, 23, 31, 47) are used to ensure no short cycles exist within a 64-bit word.


4.2 Stack Mixing β€” stack_mix

Purpose: Fold transient stack memory values into all four accumulator words, introducing data-dependent entropy from the processor stack frame.

C Implementation (annotated):

void stack_mix(ACC *acc, uint64_t v) {
    uint64_t stack_buf[8];   // 8 Γ— 64-bit values on the stack

    for(int i = 0; i < 8; i++) {
        stack_buf[i] = rotl(v ^ (acc->a + i), i + 1);
        acc->a ^= stack_buf[i];
        acc->b += rotl(stack_buf[i], (i + 3) % 64);
        acc->c ^= acc->b + stack_buf[i];
        acc->d  = rotl(acc->d ^ acc->c, 7);
    }
}

Full per-iteration formulas (for iteration $i \in [0,7]$):

$$S_i = \text{ROTL}\bigl(v \oplus (a + i),; i + 1\bigr)$$

$$a \leftarrow a \oplus S_i$$

$$b \leftarrow b + \text{ROTL}(S_i,; (i + 3) \bmod 64)$$

$$c \leftarrow c \oplus (b + S_i)$$

$$d \leftarrow \text{ROTL}(d \oplus c,; 7)$$

Dependency chain per iteration:

v, a ──► S_i ──► a'
              └──► b' ──► c' ──► d'

Every word is a function of all preceding words after iteration $i$, guaranteeing full intra-state dependency after 8 rounds.

Stack entropy source: The array stack_buf resides at a runtime-determined stack address. While the values are deterministic given $(v, \text{ACC})$, the addresses interact with CPU branch prediction, cache lines, and ASLR-randomized stack base, contributing to implementation-level non-determinism that complicates side-channel modelling.


4.3 Heap Mixing β€” heap_mix

Purpose: Allocate a 512-byte heap buffer whose address is non-deterministic (OS/allocator-dependent), fold it into the state across 64 iterations.

C Implementation (annotated):

void heap_mix(ACC *acc, uint64_t seed) {
    uint64_t *heap = malloc(64 * sizeof(uint64_t));   // 512 bytes on heap

    for(int i = 0; i < 64; i++) {
        heap[i] = rotl(seed ^ (acc->a + i), (i % 31) + 1);
        acc->a += heap[i];
        acc->b ^= rotl(heap[i], (i % 17) + 3);
        acc->c += acc->b ^ heap[i];
        acc->d ^= rotl(acc->c, (i % 13) + 5);
    }

    free(heap);
}

Per-iteration formulas (for $i \in [0, 63]$):

$$H_i = \text{ROTL}\bigl(\text{seed} \oplus (a + i),; (i \bmod 31) + 1\bigr)$$

$$a \leftarrow a + H_i$$

$$b \leftarrow b \oplus \text{ROTL}(H_i,; (i \bmod 17) + 3)$$

$$c \leftarrow c + (b \oplus H_i)$$

$$d \leftarrow d \oplus \text{ROTL}(c,; (i \bmod 13) + 5)$$

Rotation schedule analysis:

Word Rotation modulus Period Values used
$H_i$ seed rotation $(i \bmod 31) + 1$ 31 ${1 \ldots 31}$
$b$ update $(i \bmod 17) + 3$ 17 ${3 \ldots 19}$
$d$ update $(i \bmod 13) + 5$ 13 ${5 \ldots 17}$

The three moduli (31, 17, 13) are mutually coprime, so the joint rotation pattern has period $\text{lcm}(31,17,13) = 6851 \gg 64$, meaning no two iterations ever use the same rotation triplet within a single heap_mix call.

Memory-dependent entropy: The heap allocation address heap varies each call due to ASLR and allocator state. While the values stored in the buffer are deterministically computed, the cache-line layout, page mapping, and hardware prefetcher behavior introduce timing and microarchitectural variations that are invisible to a pure algorithmic model.


4.4 Accumulator Round β€” accumulator_round

Purpose: Apply a final non-linear, ARX (Add-Rotate-XOR) compression across all four state words. This is analogous to the permutation step in sponge constructions.

C Implementation:

void accumulator_round(ACC *acc) {
    acc->a = rotl(acc->a ^ acc->d, 17);
    acc->b = rotl(acc->b + acc->a, 23);
    acc->c = rotl(acc->c ^ acc->b, 31);
    acc->d = rotl(acc->d + acc->c, 47);
}

Formulas:

$$a \leftarrow \text{ROTL}(a \oplus d,\ 17)$$

$$b \leftarrow \text{ROTL}(b + a,\ 23)$$

$$c \leftarrow \text{ROTL}(c \oplus b,\ 31)$$

$$d \leftarrow \text{ROTL}(d + c,\ 47)$$

Rotation constants (17, 23, 31, 47) are all prime numbers, chosen to avoid short cycles and maximize the period of the internal permutation. The alternating XOR/ADD pattern creates algebraic incompatibility between GF(2) and $\mathbb{Z}_{2^{64}}$ analyses, a property shared by ChaCha20 and BLAKE2.

Single-pass diffusion: A 1-bit difference in $a$ before this function propagates to all four output words in a single call:

  • $a \oplus d$ spreads the bit to $a'$
  • $b + a'$ carries it into $b'$ (addition carry chain)
  • $c \oplus b'$ carries it into $c'$
  • $d + c'$ carries it into $d'$

5. Key Initialization β€” init_acc

5.1 Overview

Key initialization transforms a variable-length byte key $K = [K_0, K_1, \ldots, K_{\ell-1}]$ into the initial 256-bit accumulator state. Each key byte drives a full three-stage state update.

5.2 Algorithm

void init_acc(ACC *acc, const uint8_t *key, size_t len) {
    // Load magic constants
    acc->a = 0x9E3779B97F4A7C15ULL;
    acc->b = 0x6A09E667F3BCC909ULL;
    acc->c = 0xBB67AE8584CAA73BULL;
    acc->d = 0x3C6EF372FE94F82BULL;

    for(size_t i = 0; i < len; i++) {
        acc->a ^= key[i] + rotl(acc->d, i % 63);   // Key absorption
        stack_mix(acc, key[i]);                       // Stack entropy
        heap_mix(acc, key[i] ^ acc->a);              // Heap entropy
        accumulator_round(acc);                       // Non-linear mix
    }
}

5.3 Per-Byte Update Formula

For key byte index $i$:

Step 1 β€” Key Absorption: $$a \leftarrow a \oplus \bigl(K_i + \text{ROTL}(d,\ i \bmod 63)\bigr)$$

Step 2 β€” Stack Mixing: $$\text{ACC} \leftarrow \text{stack_mix}(\text{ACC},\ K_i)$$

Step 3 β€” Heap Mixing (seed = $K_i \oplus a$): $$\text{ACC} \leftarrow \text{heap_mix}(\text{ACC},\ K_i \oplus a)$$

Step 4 β€” Accumulator Round: $$\text{ACC} \leftarrow \text{accumulator_round}(\text{ACC})$$

5.4 Key Absorption Flow

Initial Constants
(aβ‚€, bβ‚€, cβ‚€, dβ‚€)
        β”‚
        β–Ό for each key byte Kα΅’
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  a βŠ•= (Kα΅’ + ROTL(d, i%63))  β”‚  ← Key Absorption
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     stack_mix(ACC, Kα΅’)       β”‚  ← Stack Entropy (8 iters)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  heap_mix(ACC, Kα΅’ βŠ• a)      β”‚  ← Heap Entropy (64 iters)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   accumulator_round(ACC)     β”‚  ← Non-linear ARX
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό  (next key byte)
   Final ACC state

5.5 Key Length Impact

For a key of $\ell$ bytes, each byte triggers:

  • 1 key absorption operation
  • 8 iterations of stack_mix
  • 64 iterations of heap_mix
  • 1 accumulator_round

Total operations per key byte: 74 inner loop iterations + 1 ARX round.
For a 16-byte key: 1,184 inner iterations.
For a 32-byte key: 2,368 inner iterations.

The variable-length key schedule means there is no key length upper bound; longer keys increase initialization cost linearly but improve the entropy saturation of the initial state.


6. Encryption Process

6.1 Algorithm

void encrypt(uint8_t *data, size_t len, const uint8_t *key, size_t klen) {
    ACC acc;
    init_acc(&acc, key, klen);

    for(size_t i = 0; i < len; i++) {
        uint64_t mix = acc.a ^ acc.b ^ acc.c ^ acc.d;     // Keystream word
        data[i] ^= (uint8_t)(mix & 0xFF);                  // Encrypt byte

        stack_mix(&acc, data[i]);                           // Update: ciphertext byte
        heap_mix(&acc, mix ^ data[i]);                      // Update: mix βŠ• ciphertext
        accumulator_round(&acc);                            // Final round
    }
}

6.2 Per-Byte Formulas

Keystream generation: $$\text{ks}_i = (a \oplus b \oplus c \oplus d) \mathbin{&amp;} \texttt{0xFF}$$

Encryption: $$C_i = M_i \oplus \text{ks}_i$$

State update (with $C_i$ already computed): $$\text{ACC} \leftarrow \text{stack_mix}(\text{ACC},\ C_i)$$ $$\text{ACC} \leftarrow \text{heap_mix}(\text{ACC},\ \text{ks}_i' \oplus C_i)$$ $$\text{ACC} \leftarrow \text{accumulator_round}(\text{ACC})$$

where $\text{ks}_i' = a \oplus b \oplus c \oplus d$ (the full 64-bit word before masking).

6.3 Encryption Flow

Key ──► init_acc ──► ACCβ‚€
                       β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
          β”‚            β”‚  for each plaintext byte Mα΅’
          β–Ό            β”‚
   ks = (aβŠ•bβŠ•cβŠ•d) & 0xFF
          β”‚            β”‚
   Cα΅’ = Mα΅’ βŠ• ks      β”‚
          β”‚            β”‚
   stack_mix(ACC, Cα΅’)  β”‚
          β”‚            β”‚
   heap_mix(ACC, ks'βŠ•Cα΅’)
          β”‚            β”‚
   accumulator_round    β”‚
          β”‚            β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
          Output: Cβ‚€ C₁ Cβ‚‚ ... Cβ‚™ (as hex)

6.4 Output Encoding

All ciphertext bytes are output as uppercase hexadecimal pairs to handle the full 256-byte space without control character issues:

printf("%02X", data[i]);   // e.g., byte 0xAB β†’ "AB"

7. Decryption Process

7.1 Algorithm

void decrypt(uint8_t *data, size_t len, const uint8_t *key, size_t klen) {
    ACC acc;
    init_acc(&acc, key, klen);

    for(size_t i = 0; i < len; i++) {
        uint64_t mix = acc.a ^ acc.b ^ acc.c ^ acc.d;
        uint8_t cipher = data[i];           // Save raw ciphertext byte
        data[i] ^= (uint8_t)(mix & 0xFF);  // Recover plaintext

        stack_mix(&acc, cipher);            // Update with ciphertext (same as encrypt)
        heap_mix(&acc, mix ^ cipher);
        accumulator_round(&acc);
    }
}

7.2 Per-Byte Formulas

Keystream generation (identical to encryption): $$\text{ks}_i = (a \oplus b \oplus c \oplus d) \mathbin{&amp;} \texttt{0xFF}$$

Decryption: $$M_i = C_i \oplus \text{ks}_i$$

State update (using saved $C_i$, NOT $M_i$): $$\text{ACC} \leftarrow \text{stack_mix}(\text{ACC},\ C_i)$$ $$\text{ACC} \leftarrow \text{heap_mix}(\text{ACC},\ \text{ks}_i' \oplus C_i)$$ $$\text{ACC} \leftarrow \text{accumulator_round}(\text{ACC})$$

7.3 Symmetry Proof

The cipher is symmetric because:

  1. The same init_acc produces identical $\text{ACC}_0$ for the same key.
  2. The keystream byte $\text{ks}_i$ depends only on $\text{ACC}_i$, not on $M_i$ or $C_i$.
  3. The state update after byte $i$ uses the ciphertext byte $C_i$ in both directions, so $\text{ACC}_{i+1}$ is identical in both encrypt and decrypt paths.

Formally: since $C_i = M_i \oplus \text{ks}_i$ and $\text{ks}_i \oplus \text{ks}_i = 0$: $$M_i = C_i \oplus \text{ks}_i = (M_i \oplus \text{ks}_i) \oplus \text{ks}_i = M_i \quad \checkmark$$


8. Security Analysis

Important Disclaimer: The following analysis is a design-intent assessment based on the cipher's structure. It has not been validated by formal cryptanalysis, third-party audit, or peer review. Claims below are theoretical properties, not proven guarantees.

8.1 Keystream Entropy

The keystream byte at position $i$ is: $$\text{ks}_i = (a_i \oplus b_i \oplus c_i \oplus d_i) \mathbin{&amp;} \texttt{0xFF}$$

If the four 64-bit words are treated as independently uniform (after key initialization), the XOR of four uniform values is itself uniform. The expected entropy per keystream byte:

$$H(\text{ks}_i) = 8 \text{ bits (maximum)}$$

In practice, the words are not independent β€” they evolve through shared state β€” but the nonlinear mixing through both addition and XOR (which are algebraically incompatible) makes statistical correlation between consecutive keystream bytes computationally hard to exploit.

8.2 Avalanche Effect

The avalanche criterion requires that a 1-bit change in input produces approximately a 50% change in output bits (Hamming distance β‰ˆ 128 bits for 256-bit state, β‰ˆ 4 bits for the 8-bit output).

Single-byte input change propagation:

Step Words affected Mechanism
Key absorption $a$ $a \leftarrow a \oplus (\delta + \text{ROTL}(d, r))$
stack_mix (8 iters) $a, b, c, d$ Cross-word XOR and addition
heap_mix (64 iters) $a, b, c, d$ 64 rounds of ARX diffusion
accumulator_round $a, b, c, d$ Final ARX mixing

After the full state update, an expected Hamming distance of $\approx 128$ bits (50%) from the 256-bit state change is consistent with similar ARX constructions. Exact measurement requires empirical testing (see Section 9 for a vector-based sanity check).

8.3 Resistance to Linear Cryptanalysis

Linear cryptanalysis looks for affine approximations $L(P) \oplus L(C) = 0$ with probability $p \neq 1/2$.

Mitigating factors in MASC-256:

  • Mixed algebraic groups: Addition in $\mathbb{Z}_{2^{64}}$ and XOR in $\mathbb{F}_2^{64}$ are algebraically incompatible. Linear approximations of $a + b$ over $\mathbb{F}_2$ have maximum bias $\epsilon \leq 2^{-1}$ per bit, decaying rapidly with word width.
  • 64 iterations of heap_mix: Each iteration compounds the approximation error, producing exponential bias reduction: $\epsilon_{64} \leq (1/2)^{64}$ for simple linear trails.
  • State-feedback: Because the state after byte $i$ feeds into the keystream for byte $i+1$, a linear distinguisher must span the entire message, amplifying the required data complexity exponentially.

8.4 Resistance to Differential Cryptanalysis

Differential cryptanalysis tracks how input differences $\Delta M$ propagate to output differences $\Delta C$.

Key property: The state update mixes in the ciphertext byte $C_i$, not $M_i$. For two messages $M$ and $M'$ with $M_i \neq M_i'$, the ciphertext bytes $C_i = M_i \oplus \text{ks}i$ and $C_i' = M_i' \oplus \text{ks}i$ differ in exactly the same bits as $M_i \oplus M_i'$. These different ciphertext bytes then drive divergent state updates, so $\text{ACC}{i+1} \neq \text{ACC}{i+1}'$ for subsequent positions.

This self-synchronizing differential divergence means that a differential characteristic valid at position $i$ does not extend to position $i+1$ with high probability, defeating multi-step differential trails.

8.5 Memory-Dependent Side-Channel Resistance

A timing side-channel on heap_mix is theoretically possible if the adversary can:

  1. Precisely measure malloc execution time.
  2. Correlate that timing to the heap address (which depends on allocator state).
  3. Infer seed or acc->a from that address.

In practice:

  • ASLR randomizes heap base addresses per-process run.
  • malloc timing depends on the allocator's free-list state, which changes unpredictably.
  • Cache-timing attacks on the heap buffer access pattern would require cache-line-level resolution of a 512-byte buffer at a non-constant address β€” a significantly harder target than S-box cache attacks on AES.

However, no formal cache-timing analysis has been performed. This is a claimed property, not a proven one.

8.6 Key Space

For an $\ell$-byte key drawn from the full 256-byte alphabet:

$$|\mathcal{K}| = 256^\ell = 2^{8\ell}$$

For a 32-byte (256-bit) key: $|\mathcal{K}| = 2^{256}$, matching AES-256's key space cardinality.

8.7 State Recovery Attack Complexity

An adversary attempting to recover the full 256-bit state from keystream bytes must:

  1. Collect keystream bytes $\text{ks}_0, \text{ks}_1, \ldots, \text{ks}_n$.
  2. Invert $n$ coupled ARX state transitions.
  3. Match to the initial state space of $2^{256}$ possibilities.

Given the non-invertibility of heap_mix (malloc'd buffer is freed; address is lost), direct algebraic inversion is infeasible. Brute force remains at $O(2^{256})$.


9. Test Vectors

9.1 Reference Test

Key (ASCII): UltraEncryptedKey
Key (Hex): 556C7472614 56E637279707465644B6579
Key Length: 17 bytes

Plaintext (ASCII): Advanced Memory Encryption System
Plaintext (Hex): 416476616E636564204D656D6F727920456E6372797074696F 6E2053797374656D
Plaintext Length: 33 bytes

Expected Output (compile and run main.c to verify):

Encrypted: [Run ./build/Debug/acc_crypto to generate]
Decrypted: Advanced Memory Encryption System

Since the cipher's heap allocation addresses may vary across platforms and OS versions (due to ASLR), the encrypted hex output will differ between executions on different platforms if memory-address values contribute indirectly. However, the ciphertext values must be deterministic on a single clean execution because heap_mix stores computed values in the heap buffer β€” the values are deterministic; only the addresses vary. On any single run, encrypt β†’ decrypt must recover the original plaintext.

9.2 Verifiable Determinism Check

To confirm determinism on your platform:

./build/Debug/acc_crypto
# Run twice; encrypted output must be IDENTICAL both times
# Decrypted output must always be: "Advanced Memory Encryption System"

9.3 Key Sensitivity Test

Changing one bit of the key must produce a completely different ciphertext (avalanche at key level):

Key Expected behavior
UltraEncryptedKey Produces ciphertext $C$
UltraEncryptedKex Produces completely different ciphertext $C'$
ultraEncryptedKey Produces completely different ciphertext $C''$

Quantitatively, $C \oplus C'$ should have a Hamming weight close to $\frac{33 \times 8}{2} = 132$ bits (50% of total bits).


10. Architecture Diagrams

10.1 ACC State Evolution (per byte)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    ACCUMULATOR (256-bit)                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚    a (64)   β”‚  β”‚    b (64)   β”‚  β”‚    c (64)   β”‚  β”‚  d (64)   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β”‚               β”‚               β”‚               β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
                              aβŠ•bβŠ•cβŠ•d
                                  β”‚
                            & 0xFF = ks_i
                                  β”‚
                         Input byte β”€β”€βŠ•β”€β”€β–Ί Output byte
                                  β”‚
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚              stack_mix                   β”‚
               β”‚  (8 iters: S=ROTL(vβŠ•(a+i), i+1))       β”‚
               β”‚  aβŠ•=S, b+=ROTL(S), cβŠ•=(b+S), d=ROTL(dβŠ•c, 7) β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚               heap_mix                   β”‚
               β”‚  (64 iters: H=ROTL(seedβŠ•(a+i), var))   β”‚
               β”‚  a+=H, bβŠ•=ROTL(H), c+=(bβŠ•H), dβŠ•=ROTL(c) β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚           accumulator_round              β”‚
               β”‚  a=ROTL(aβŠ•d,17), b=ROTL(b+a,23)        β”‚
               β”‚  c=ROTL(cβŠ•b,31), d=ROTL(d+c,47)        β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
                            Next ACC state

10.2 Encrypt vs. Decrypt State Coupling

ENCRYPT                           DECRYPT
─────────────────────             ─────────────────────
ACC_i                             ACC_i  (identical, same key)
  β”‚                                 β”‚
  β–Ό                                 β–Ό
ks = (aβŠ•bβŠ•cβŠ•d) & 0xFF           ks = (aβŠ•bβŠ•cβŠ•d) & 0xFF
  β”‚                                 β”‚
  β–Ό                                 β–Ό
C_i = M_i βŠ• ks          save C_i; M_i = C_i βŠ• ks
  β”‚                                 β”‚
  β–Ό                                 β–Ό
stack_mix(ACC, C_i)  ◄──same───► stack_mix(ACC, C_i)
heap_mix(ACC, ks'βŠ•C_i)          heap_mix(ACC, ks'βŠ•C_i)
accumulator_round                accumulator_round
  β”‚                                 β”‚
  β–Ό                                 β–Ό
ACC_{i+1}  ≑  ACC_{i+1}   ← guaranteed identical

10.3 heap_mix Memory Layout

 malloc(64 Γ— 8 bytes)
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ heap[0] β”‚ heap[1] β”‚ ... β”‚ heap[31] β”‚...β”‚heap[63] β”‚
 β”‚  H(0)   β”‚  H(1)   β”‚     β”‚  H(31)  β”‚   β”‚ H(63)   β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     β”‚                                     β”‚
     β–Ό           feeds into              β–Ό
   a += H(i)
   b ^= ROTL(H(i), (i%17)+3)
   c += b ^ H(i)
   d ^= ROTL(c, (i%13)+5)
                                   free(heap)

11. Comparison with AES-256

Property AES-256 MASC-256
Cipher type Block (128-bit block) Stream (1-byte output per step)
Key length Fixed 256-bit Variable (any length)
Internal state 128-bit (4Γ—4 byte matrix) 256-bit (4Γ—64-bit words)
Rounds per block/byte 14 fixed rounds 1 stack + 1 heap + 1 ARX round
Inner loop iterations ~14 Γ— AES ops 73 per byte (8 stack + 64 heap + 1 ARX)
Parallelizability CTR/GCM modes only Inherently sequential
Formal security proof Yes (proofs under standard assumptions) None (research cipher)
NIST standardization Yes No
Side-channel hardening Requires AES-NI Memory-address variation (partial)
Hardware acceleration AES-NI instruction set None
Peer review Extensive, 25+ years None
Memory allocations Zero 1 Γ— 512-byte per plaintext byte

On the Claim of "Beating AES-256"

AES-256 benefits from:

  • 25+ years of public cryptanalysis with no successful key-recovery attacks
  • Hardware acceleration making it extremely fast in practice
  • Formal security reductions and proofs
  • NIST standardization with strict implementation requirements

MASC-256's theoretical strengths β€” memory-dependent entropy, variable-length key absorption, 256-bit state β€” are design properties, not proven security properties. A cipher is not more secure than AES-256 until it survives equivalent public scrutiny.

Recommended path to validation:

  1. Publish the design openly (this document is a start).
  2. Submit to IACR ePrint Archive for community review.
  3. Implement a full statistical test suite (NIST SP 800-22 / TestU01).
  4. Commission a formal cryptanalysis engagement.
  5. Pursue standardization track if results are favorable.

12. Known Limitations and Future Work

12.1 Current Limitations

Limitation Description Impact
No IV/Nonce Encrypting two messages with the same key produces identical keystreams Nonce-reuse attack: XOR two ciphertexts to cancel the keystream
Sequential only State depends on all prior bytes; no random access Cannot parallelize encryption
malloc per byte 512-byte allocation every plaintext byte Significant memory allocator overhead vs. AES
No authentication Pure encryption; no MAC or AEAD Ciphertext tampering is undetected
No formal analysis Claimed properties are unverified Unknown actual security margin
Heap values deterministic Despite non-deterministic addresses, buffer values are computable Side-channel resistance weaker than claimed

12.2 Proposed Improvements

  1. Add a nonce/IV parameter to init_acc β€” mix a random 128-bit nonce into the initial state before key absorption.
  2. Implement AEAD mode β€” append a 128-bit Poly1305 or GHASH authentication tag.
  3. Batch the heap allocation β€” allocate the heap buffer once per message rather than per byte to reduce allocator overhead.
  4. Extract more keystream bits β€” use all 64 bits of mix, not just 8 bits, to encrypt 8 bytes per state update (increasing throughput 8Γ—).
  5. Formal statistical testing β€” run NIST SP 800-22 and Diehard battery on the raw keystream.
  6. Side-channel hardening β€” consider constant-time implementations of rotation and XOR.

13. Compilation and Execution

13.1 Prerequisites

  • C99-compatible compiler: GCC β‰₯ 4.8, Clang β‰₯ 3.5, or MSVC 2019+
  • CMake β‰₯ 3.10
  • Standard C library (stdlib.h, stdint.h, stddef.h)

13.2 Build with CMake

# Configure
cmake -B build -S .

# Build (Debug by default)
cmake --build build

# Run
./build/Debug/acc_crypto

13.3 Build with Make Wrapper

make all       # Equivalent to cmake configure + build
make run       # Build and execute

13.4 Expected Output

Encrypted: <HEX STRING OF 33 BYTES = 66 HEX CHARS>
Decrypted: Advanced Memory Encryption System

13.5 Custom Integration

To use MASC-256 in your own project, include acc_crypto.h and link acc_crypto.c + memory_mix.c:

#include "acc_crypto.h"

// Encrypt a buffer in-place
uint8_t my_key[] = "MySecretKey";
uint8_t my_data[] = "Hello, World!";
size_t  data_len  = sizeof(my_data) - 1;

encrypt(my_data, data_len, my_key, sizeof(my_key) - 1);
// my_data now contains ciphertext

decrypt(my_data, data_len, my_key, sizeof(my_key) - 1);
// my_data restored to "Hello, World!"

14. API Reference

init_acc

void init_acc(ACC *acc, const uint8_t *key, size_t len);

Initializes accumulator acc from key key of byte length len. Must be called before encrypt or decrypt.

encrypt

void encrypt(uint8_t *data, size_t len, const uint8_t *key, size_t klen);

Encrypts len bytes in data in-place using key. Internally calls init_acc.

decrypt

void decrypt(uint8_t *data, size_t len, const uint8_t *key, size_t klen);

Decrypts len bytes in data in-place using key. Internally calls init_acc.

stack_mix

void stack_mix(ACC *acc, uint64_t v);

Applies 8 rounds of stack-entropy mixing to acc using seed value v.

heap_mix

void heap_mix(ACC *acc, uint64_t seed);

Allocates a 512-byte heap buffer, applies 64 rounds of ARX mixing to acc, then frees the buffer.

accumulator_round

void accumulator_round(ACC *acc);

Applies one round of the 4-word ARX permutation to acc.

rotl / rotr

uint64_t rotl(uint64_t x, int r);
uint64_t rotr(uint64_t x, int r);

Circular bit-rotation of x by r positions.


15. References

  1. FIPS 197 β€” Advanced Encryption Standard (AES), NIST, 2001.
  2. Bernstein, D.J. β€” "The Salsa20 Family of Stream Ciphers," ECRYPT eSTREAM, 2008.
  3. Bernstein, D.J. β€” "ChaCha, a variant of Salsa20," SKEW 2008.
  4. Aumasson, J.P., et al. β€” "BLAKE2: simpler, smaller, fast as MD5," ACNS 2013.
  5. Kelsey, J., et al. β€” "Key-Schedule Cryptanalysis of IDEA, G-DES, GOST, SAFER, and Triple-DES," CRYPTO 1996.
  6. Menezes, A., van Oorschot, P., Vanstone, S. β€” Handbook of Applied Cryptography, CRC Press, 1996. (Free PDF: cacr.uwaterloo.ca)
  7. NIST SP 800-22 β€” A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications, 2010.
  8. Ferguson, N., Schneier, B., Kohno, T. β€” Cryptography Engineering, Wiley, 2010.

This document was produced for the MASC-256 research cipher. For questions, contributions, or cryptanalysis results, open an issue in the project repository.