Algorithm Specification

RCEA: Rubik's Cube Encryption Algorithm

Version 1.0 — February 2026

Category: Symmetric Block Cipher Specification

1.Abstract

This document specifies the Rubik's Cube Encryption Algorithm (RCEA), a symmetric block cipher that uses permutations derived from an N×N×N Rubik's Cube as its primary diffusion mechanism. RCEA operates on blocks of 6N² bytes and supports configurable cube sizes (N = 2..6) and round counts (R = 4..20). The cipher combines four operations per round — byte substitution, cube rotation, face mixing, and round key addition — to achieve confusion and diffusion.

RCEA is designed as an educational and experimental cipher to demonstrate how geometric transformations can serve as cryptographic primitives. It uses the AES S-Box for substitution, SHA-256 for key derivation, and HMAC-SHA-256 for message authentication.

2.Scope and Purpose

This specification defines the complete RCEA algorithm including: the cube geometry model, key derivation procedure, four round operations, block encryption/decryption, CBC mode with Encrypt-then-MAC authentication, and the binary file format for encrypted files.

This specification is intended for implementors who wish to create compatible RCEA implementations in any programming language, as well as for cryptographic study and analysis of cube-based diffusion mechanisms.

3.Definitions and Notation

3.1. Symbols and Operators

SymbolDefinition
NCube size parameter. An integer in [2, 6].
RNumber of encryption rounds. An integer in [4, 20].
BSBlock size in bytes: BS = 6 × N².
MTotal number of available cube moves: M = 6 × N.
RPRRotations per round: RPR = N + 2.
Bitwise exclusive OR (XOR).
||Byte string concatenation.
S[x]S-Box lookup: substitution of byte x.
state[i]The i-th byte of the cipher state, where 0 ≤ i < BS.
πA permutation array: π[i] = j means position i maps to position j.
π⁻¹The inverse permutation of π.
π₁ ∘ π₂Composition of permutations: (π₁ ∘ π₂)[i] = π₂[π₁[i]].

3.2. Parameters

The following table shows derived values for each supported cube size:

NBlock Size (bytes)Moves (M)Rotations/Round (RPR)
224124
354185
496246
5150307
6216368

4.Cube Geometry

4.1. Face Enumeration

The virtual cube has six faces, each assigned a fixed integer identifier:

Face NameIndex
FRONT0
BACK1
LEFT2
RIGHT3
UP4
DOWN5

Each face contains N×N cells arranged in a row-major grid with rows indexed top-to-bottom and columns indexed left-to-right.

4.2. Cell Indexing

The cipher state is a flat array of BS = 6N² bytes. The mapping from a (face, row, col) triple to a linear index is:

cellIndex(face, row, col, N) = face × N² + row × N + col

where face ∈ [0, 5], row ∈ [0, N−1], col ∈ [0, N−1].

4.3. Move Definitions

A move is a pair of permutations (forward, inverse) that together define a single clockwise/counter-clockwise rotation. RCEA constructs M = 6N moves total, organized in three axes with two directions each.

4.3.1. Face Rotation

A clockwise face rotation of face f maps each cell as:

faceRotateCW(f, N):
  For each (row, col) on face f:
    π[cellIndex(f, row, col, N)] = cellIndex(f, col, N−1−row, N)
  All other positions map to themselves.

Counter-clockwise rotation is the inverse: faceRotateCCW = (faceRotateCW)⁻¹.

4.3.2. Axis Rings

For each axis, there are N layers (indexed k = 0..N−1). Each layer defines a ring permutation that cycles cells across four adjacent faces.

Z-Axis Ring (layer k):

For each column c in [0, N):
  UP[N−1−k, c]    → RIGHT[c, k]
  RIGHT[c, k]     → DOWN[k, N−1−c]
  DOWN[k, c]      → LEFT[c, N−1−k]
  LEFT[c, N−1−k]  → UP[N−1−k, N−1−c]

X-Axis Ring (layer k):

For each row r in [0, N):
  UP[r, k]            → FRONT[r, k]
  FRONT[r, k]         → DOWN[r, k]
  DOWN[r, k]          → BACK[N−1−r, N−1−k]
  BACK[N−1−r, N−1−k]  → UP[r, k]

Y-Axis Ring (layer k):

For each column c in [0, N):
  FRONT[N−1−k, c]  → RIGHT[N−1−k, c]
  RIGHT[N−1−k, c]  → BACK[N−1−k, c]
  BACK[N−1−k, c]   → LEFT[N−1−k, c]
  LEFT[N−1−k, c]   → FRONT[N−1−k, c]

4.3.3. Move Construction

For each axis (Z, X, Y) and each layer k in [0, N):

ring = axisRing(k, N)

If k = 0:
  moveCW = ring ∘ faceRotateCW(boundaryFace, N)
Else if k = N−1:
  moveCW = ring ∘ faceRotateCW(oppositeFace, N)  // or CCW depending on axis
Else:
  moveCW = ring

moveCCW = (moveCW)⁻¹

Emit two moves: (moveCW, moveCCW) and (moveCCW, moveCW)

Boundary face assignments per axis:

Axisk = 0 face (CW rotation)k = N−1 face
ZFRONT (CW)BACK (CCW)
XLEFT (CCW)RIGHT (CW)
YDOWN (CCW)UP (CW)

The total number of moves is 3 axes × N layers × 2 directions = 6N.

5.Substitution Box (S-Box)

RCEA uses the AES (Rijndael) S-Box as defined in FIPS 197, Section 5.1.1. The S-Box is a fixed 256-byte lookup table providing non-linear byte substitution. The inverse S-Box is computed such that INV_SBOX[SBOX[x]] = x for all x ∈ [0, 255].

The S-Box is presented here in hexadecimal. Row index = high nibble, column index = low nibble:

.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f
0.637c777bf26b6fc53001672bfed7ab76
0.ca82c97dfa5947f0add4a2af9ca472c0
0.b7fd9326363ff7cc34a5e5f171d83115
0.04c723c31896059a071280e2eb27b275
0.09832c1a1b6e5aa0523bd6b329e32f84
0.53d100ed20fcb15b6acbbe394a4c58cf
0.d0efaafb434d338545f9027f503c9fa8
0.51a3408f929d38f5bcb6da2110fff3d2
0.cd0c13ec5f974417c4a77e3d645d1973
0.60814fdc222a908846eeb814de5e0bdb
0.e0323a0a4906245cc2d3ac629195e479
0.e7c8376d8dd54ea96c56f4ea657aae08
0.ba78252e1ca6b4c6e8dd741f4bbd8b8a
0.703eb5664803f60e613557b986c11d9e
0.e1f8981169d98e949b1e87e9ce5528df
0.8ca1890dbfe6426841992d0fb054bb16

6.Key Derivation Function

RCEA derives all key material from a variable-length user key using a counter-mode construction based on SHA-256:

KDF(key, label, length):
  result = empty byte string
  counter = 0

  While len(result) < length:
    counterBytes = counter as 4-byte big-endian uint32
    input = key || encode_utf8(label) || counterBytes
    hash = SHA-256(input)
    result = result || hash
    counter = counter + 1

  Return first 'length' bytes of result

Each derived quantity uses a unique label string to ensure domain separation. The labels used are specified in Section 7.

7.Key Schedule

The key schedule transforms the user-provided key into all material required for encryption: a keyed cube state, per-round keys, per-round rotation sequences, and an HMAC key.

7.1. Phase 1: Keyed Cube State

The keyed cube state is a BS-byte array used as the initial whitening key.

// 1. Derive initial state bytes
state = KDF(key, "rcea_phase1_columns", BS)

// 2. Derive rotation material
rotMaterial = KDF(key, "rcea_phase1_rotations", RPR)

// 3. Apply RPR cube rotations to the state
For i = 0 to RPR−1:
  moveIndex = rotMaterial[i] mod M
  state = applyPermutation(state, allMoves[moveIndex].forward)

keyedState = state

7.2. Phase 2: Round Material

For each round r ∈ [0, R):

// Round key (BS bytes)
roundKeys[r] = KDF(key, "rcea_round_key_" || str(r), BS)

// Rotation sequence (RPR indices)
rotBytes = KDF(key, "rcea_round_rot_" || str(r), RPR)
roundRotations[r][i] = rotBytes[i] mod M   for i in [0, RPR)

The string representation of r is its decimal ASCII encoding (e.g., round 0 uses label "rcea_round_key_0", round 12 uses "rcea_round_key_12").

7.3. HMAC Key

hmacKey = KDF(key, "rcea_hmac_key", 32)

The HMAC key is always 32 bytes regardless of block size.

8.Block Cipher Operations

Each encryption round applies four operations in sequence. This section defines each operation precisely.

8.1. SubBytes

Non-linear byte substitution using the AES S-Box (Section 5):

SubBytes(state):
  For i = 0 to BS−1:
    state'[i] = SBOX[state[i]]
  Return state'

This operation provides confusion — it breaks the linear relationship between key and ciphertext. Each byte is substituted independently.

8.2. CubeRotate

Positional permutation of the state by applying a sequence of cube rotations:

CubeRotate(state, moveIndices, allMoves):
  result = state
  For each idx in moveIndices:   // RPR indices
    result = applyPermutation(result, allMoves[idx].forward)
  Return result

Where applyPermutation is defined as:

applyPermutation(state, perm):
  newState = new array of BS bytes
  For i = 0 to BS−1:
    newState[perm[i]] = state[i]
  Return newState

This operation provides diffusion — it spatially rearranges bytes across cube faces, ensuring that a single byte change propagates across the entire state.

8.3. FaceMix

Intra-face byte mixing using two sequential XOR scans with S-Box feedback:

FaceMix(state, N):
  result = copy of state

  For each face f in [0, 5]:
    // Pass 1: Row scan (left to right)
    For row = 0 to N−1:
      For col = 1 to N−1:
        idx = cellIndex(f, row, col, N)
        prevIdx = cellIndex(f, row, col−1, N)
        result[idx] = result[idx] ⊕ SBOX[result[prevIdx]]

    // Pass 2: Column scan (top to bottom)
    For col = 0 to N−1:
      For row = 1 to N−1:
        idx = cellIndex(f, row, col, N)
        aboveIdx = cellIndex(f, row−1, col, N)
        result[idx] = result[idx] ⊕ SBOX[result[aboveIdx]]

  Return result

FaceMix provides local diffusion within each face. Each byte depends on its left and upper neighbors through the S-Box, creating a cascade effect where changing one byte on a face affects all bytes below and to the right of it.

8.4. AddRoundKey

XOR the state with the round key:

AddRoundKey(state, roundKey):
  For i = 0 to BS−1:
    state'[i] = state[i] ⊕ roundKey[i]
  Return state'

9.Block Encryption

Given a BS-byte plaintext block, the encryption procedure is:

EncryptBlock(block, keyedState, roundKeys, roundRotations, allMoves, N, R):
  // Initial whitening
  state = block ⊕ keyedState

  // R rounds
  For r = 0 to R−1:
    state = SubBytes(state)
    state = CubeRotate(state, roundRotations[r], allMoves)
    state = FaceMix(state, N)
    state = AddRoundKey(state, roundKeys[r])

  Return state
Note: The initial XOR with keyedState ensures that even before the first round, the plaintext is mixed with key-dependent material. This is analogous to AES's initial AddRoundKey step.

10.Block Decryption

Decryption applies the inverse of each operation in reverse round order:

DecryptBlock(block, keyedState, roundKeys, roundRotations, allMoves, N, R):
  state = copy of block

  // Reverse R rounds
  For r = R−1 down to 0:
    state = state ⊕ roundKeys[r]           // Inverse AddRoundKey
    state = InvFaceMix(state, N)            // Inverse FaceMix
    state = InvCubeRotate(state, roundRotations[r], allMoves)
    state = InvSubBytes(state)              // Inverse SubBytes

  // Undo initial whitening
  state = state ⊕ keyedState

  Return state

10.1. Inverse Operations

InvSubBytes: Uses the inverse S-Box table.

InvSubBytes(state):
  For i = 0 to BS−1:
    state'[i] = INV_SBOX[state[i]]

InvCubeRotate: Applies inverse permutations in reverse order.

InvCubeRotate(state, moveIndices, allMoves):
  result = state
  For i = len(moveIndices)−1 down to 0:
    result = applyPermutation(result, allMoves[moveIndices[i]].inverse)
  Return result

InvFaceMix: Undoes the two passes in reverse order.

InvFaceMix(state, N):
  result = copy of state

  For each face f in [0, 5]:
    // Undo Pass 2: Column scan (bottom to top)
    For col = 0 to N−1:
      For row = N−2 down to 0:
        idx = cellIndex(f, row+1, col, N)
        aboveIdx = cellIndex(f, row, col, N)
        result[idx] = result[idx] ⊕ SBOX[result[aboveIdx]]

    // Undo Pass 1: Row scan (right to left)
    For row = 0 to N−1:
      For col = N−2 down to 0:
        idx = cellIndex(f, row, col+1, N)
        prevIdx = cellIndex(f, row, col, N)
        result[idx] = result[idx] ⊕ SBOX[result[prevIdx]]

  Return result

11.Mode of Operation (CBC)

RCEA uses Cipher Block Chaining (CBC) mode with PKCS#7 padding and an Encrypt-then-MAC construction using HMAC-SHA-256.

11.1. Padding (PKCS#7)

PKCS7Pad(data, BS):
  padLen = BS − (len(data) mod BS)
  // padLen is in [1, BS]; if data is already aligned, a full block of padding is added
  Return data || repeat(padLen, padLen)

PKCS7Unpad(data, BS):
  padLen = data[len(data) − 1]
  If padLen < 1 or padLen > BS: ERROR "invalid padding"
  For i = len(data) − padLen to len(data) − 1:
    If data[i] ≠ padLen: ERROR "invalid padding"
  Return data[0 .. len(data) − padLen]

11.2. CBC Encryption

CBC-Encrypt(plaintext, key, N, R):
  Derive all key material via KeySchedule(key, N, R)
  padded = PKCS7Pad(plaintext, BS)
  IV = random(BS)             // cryptographically random
  numBlocks = len(padded) / BS

  C₀ = IV
  For i = 1 to numBlocks:
    Pᵢ = padded[(i−1)×BS .. i×BS]
    Cᵢ = EncryptBlock(Pᵢ ⊕ Cᵢ₋₁, ...)

  body = IV || C₁ || C₂ || ... || Cₙ
  tag = HMAC-SHA-256(hmacKey, body)

  Return body || tag

11.3. CBC Decryption

CBC-Decrypt(ciphertext, key, N, R):
  Derive all key material via KeySchedule(key, N, R)

  If len(ciphertext) < BS + BS + 32: ERROR "ciphertext too short"

  tag = ciphertext[−32 ..]
  body = ciphertext[.. −32]

  // Verify authentication BEFORE decryption
  expectedTag = HMAC-SHA-256(hmacKey, body)
  If NOT constantTimeCompare(tag, expectedTag):
    ERROR "authentication failed"

  IV = body[0 .. BS]
  encData = body[BS ..]
  numBlocks = len(encData) / BS

  C₀ = IV
  For i = 1 to numBlocks:
    Cᵢ = encData[(i−1)×BS .. i×BS]
    Pᵢ = DecryptBlock(Cᵢ, ...) ⊕ Cᵢ₋₁

  Return PKCS7Unpad(P₁ || P₂ || ... || Pₙ, BS)

11.4. Authentication (HMAC)

RCEA uses the Encrypt-then-MAC paradigm. The HMAC tag is computed over the IV and all ciphertext blocks (but not the tag itself). Authentication is verified before any decryption is performed. This prevents chosen-ciphertext attacks and ensures integrity.

The HMAC key is 32 bytes derived via KDF with label "rcea_hmac_key". The MAC function is HMAC-SHA-256 as defined in RFC 2104 and FIPS 198-1.

Comparison of the received tag and expected tag MUST be performed in constant time to prevent timing side-channel attacks.

12.File Format

The RCEA binary file format encapsulates cipher parameters, the original filename, and the CBC-encrypted payload:

Offset  Size     Field
──────  ───────  ──────────────────────────
0       4        Magic bytes: 0x52 0x43 0x45 0x41 ("RCEA")
4       1        Cube size N (uint8)
5       1        Rounds R (uint8)
6       2        Filename length L (uint16, big-endian)
8       L        Original filename (UTF-8 encoded)
8+L     ...      CBC payload: IV || C₁ || ... || Cₙ || HMAC tag

The CBC payload follows the format described in Section 11.2: the first BS bytes are the IV, followed by ciphertext blocks, followed by a 32-byte HMAC-SHA-256 tag.

Note: Implementations MUST check the magic bytes before attempting to parse the rest of the header. If the magic bytes do not match, the file is not an RCEA-encrypted file.

13.Parameter Ranges and Recommendations

ParameterRangeRecommendedNotes
Cube Size (N)2 – 63N=3 gives 54-byte blocks; larger cubes increase block size quadratically
Rounds (R)4 – 2010More rounds increase security margin but slow encryption linearly
Key≥ 1 byte≥ 16 bytesKey is hashed via SHA-256 in KDF; longer keys do not exceed 256-bit security

13.1. Block Size Implications

The block size grows as 6N². A 2×2 cube produces 24-byte blocks, while a 6×6 cube produces 216-byte blocks. Larger blocks mean:

  • Greater diffusion per round (more positions to scramble)
  • Larger round keys (more KDF output required)
  • More padding waste for short messages
  • More cube moves available (6N total)

14.Test Vectors

The following test vectors can be used to verify a correct RCEA implementation. All values are in hexadecimal.

14.1. S-Box Verification

SBOX[0x00] = 0x63
SBOX[0x01] = 0x7C
SBOX[0x11] = 0x82
SBOX[0xFF] = 0x16

INV_SBOX[0x63] = 0x00
INV_SBOX[0x7C] = 0x01
INV_SBOX[0x16] = 0xFF

14.2. Block Size Verification

blockSize(2) = 24
blockSize(3) = 54
blockSize(4) = 96
blockSize(5) = 150
blockSize(6) = 216

14.3. Move Count Verification

numMoves(2) = 12
numMoves(3) = 18
numMoves(4) = 24
numMoves(5) = 30
numMoves(6) = 36

rotsPerRound(2) = 4
rotsPerRound(3) = 5
rotsPerRound(4) = 6
rotsPerRound(5) = 7
rotsPerRound(6) = 8

14.4. KDF Verification

Given key = encode_utf8("test") and label = "rcea_phase1_columns":

KDF input for counter=0:
  SHA-256( 0x74 0x65 0x73 0x74 ||        // "test"
           "rcea_phase1_columns" ||        // label
           0x00 0x00 0x00 0x00 )           // counter = 0

The output depends on the SHA-256 implementation.
Implementors should verify: KDF("test", "label", 32) produces
a deterministic 32-byte output matching their SHA-256.

14.5. Round-Trip Verification

For any key K, plaintext P, and parameters (N, R):

DecryptBlock(EncryptBlock(P, ...), ...) = P
CBC-Decrypt(CBC-Encrypt(P, K, N, R), K, N, R) = P

An implementation MUST verify round-trip correctness for all supported parameter combinations during testing.

15.Security Considerations

15.1. Intended Use

RCEA is designed as an experimental and educational cipher. It has not been subjected to formal cryptanalysis by the academic community. It SHOULD NOT be used for protecting sensitive data where established algorithms (AES, ChaCha20) are available.

15.2. Confusion and Diffusion

RCEA achieves confusion through the AES S-Box (SubBytes) and S-Box feedback in FaceMix. It achieves diffusion through CubeRotate (global byte position permutation) and FaceMix (local intra-face mixing). The combination of global and local diffusion mechanisms is intended to ensure full avalanche within a few rounds.

15.3. Key Schedule Security

The key schedule uses SHA-256 based KDF with domain-separated labels, providing:

  • Independence between derived quantities (different labels)
  • Pre-image resistance from SHA-256
  • Up to 256 bits of effective key strength

15.4. Authentication

The Encrypt-then-MAC construction with HMAC-SHA-256 provides:

  • Ciphertext integrity and authenticity
  • Protection against chosen-ciphertext attacks
  • Verification before decryption (fail-fast)

The constant-time comparison prevents timing oracle attacks on the MAC verification.

15.5. Known Limitations

  • No formal security proof or reduction to a hard problem
  • Permutation-based diffusion is linear; differential and linear cryptanalysis resistance has not been formally evaluated
  • Variable block size may leak information about cube parameters if block boundaries are observable
  • CBC mode is malleable (mitigated by HMAC); implementations requiring nonce-misuse resistance should consider alternative modes
  • Side-channel resistance (timing, power analysis) has not been evaluated

16.References

  • [FIPS 197] National Institute of Standards and Technology, "Advanced Encryption Standard (AES)," FIPS PUB 197, November 2001.
  • [FIPS 198-1] National Institute of Standards and Technology, "The Keyed-Hash Message Authentication Code (HMAC)," FIPS PUB 198-1, July 2008.
  • [FIPS 180-4] National Institute of Standards and Technology, "Secure Hash Standard (SHS)," FIPS PUB 180-4, August 2015.
  • [RFC 2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication," RFC 2104, February 1997.
  • [RFC 5652] Housley, R., "Cryptographic Message Syntax (CMS)," RFC 5652, Section 6.3 (PKCS#7 padding), September 2009.
  • [SP 800-38A] Dworkin, M., "Recommendation for Block Cipher Modes of Operation," NIST Special Publication 800-38A, December 2001.