Learn RCEA

A beginner-friendly guide to the Rubik's Cube Encryption Algorithm.

What Is Encryption?

Imagine you want to send a secret note to your friend across the room, but other people can see the note as it passes between you. You need a way to scramble the message so that only your friend can read it. That's what encryption does.

The locked box analogy
๐Ÿ“„
Your message
"Hello World!"
๐Ÿ”‘
Lock with key
secret-key-123
๐Ÿ“ฆ
Locked box
7a3f1b9e...
๐Ÿ”‘
Unlock with key
secret-key-123
๐Ÿ“„
Original message
"Hello World!"

Three key terms

Plaintext

The original, readable message. This is what you want to protect.

"Hello World!"
Ciphertext

The scrambled, unreadable output. This is safe to send over insecure channels.

7a3f1b9ec8d2...
Key

The secret that controls the scrambling. Only someone with the same key can undo the encryption.

my-secret-key

What is a block cipher?

There are different ways to do encryption. A block cipher works by chopping your message into fixed-size chunks called blocks, then encrypting each block separately.

How a block cipher processes a message
Block 1: "Hello W"
Block 2: "orld! T"
Block 3: "his is "
Block 4: "a secre"
Block 5: "t messa"
Block 6: "ge."
โ†“ each block encrypted independently โ†“
Block 1: 7a3f1b...
Block 2: c8d2e9...
Block 3: 45f012...
Block 4: 8b6a3c...
Block 5: de9f78...
Block 6: 2c4b5a...

RCEA is a block cipher. What makes it unique is how it scrambles each block โ€” it maps the bytes onto the faces of a virtual Rubik's Cube and uses cube rotations as the scrambling mechanism. The block size depends on the cube size: a 3ร—3 cube has 6 faces ร— 9 cells = 54 bytes per block.

The Rubik's Cube Idea

A real Rubik's Cube has 6 faces, each covered in a grid of colored squares. A standard 3ร—3 cube has 9 squares per face, for a total of 54 squares. Now imagine replacing each colored square with a byte of data (a number from 0 to 255).

Mapping data to the cube

To encrypt a message, RCEA takes a chunk of bytes and lays them out across the 6 faces of the cube. Here's what it looks like for the string "Hello World!" on a 3ร—3 cube:

The 6 faces laid flat (a "cube net"):
Up
Left
Front
Right
Back
Down
Now with data bytes filled in:
00
00
00
00
00
00
00
00
00
Up
00
00
00
00
00
00
00
00
00
Left
48
65
6C
6C
6F
20
57
6F
72
Front
00
00
00
00
00
00
00
00
00
Right
6C
64
21
00
00
00
00
00
00
Back
00
00
00
00
00
00
00
00
0C
Down

Example: "Hello World!" mapped onto a 3ร—3 cube (54 bytes, PKCS#7 padded)

How the mapping works

  1. Bytes fill the Front face first (left-to-right, top-to-bottom)
  2. Then Back, Left, Right, Up, and Down
  3. If the message is shorter than the block, it gets PKCS#7 padded (filled with padding bytes)
  4. Each face is an Nร—N grid, so one block is always 6 ร— Nยฒ bytes

Block size formula

The cube size N determines how many bytes fit in one block:

blockSize = 6 ร— Nยฒ
2ร—2
24 bytes
Tiny โ€” fast but weak diffusion
3ร—3
54 bytes
Default โ€” good balance
4ร—4
96 bytes
Medium โ€” stronger diffusion
5ร—5
150 bytes
Large โ€” very strong mixing
6ร—6
216 bytes
Maximum โ€” most secure

Why a cube?

When you twist a Rubik's Cube, pieces move from one face to another. This creates positional diffusion โ€” a byte that was on the Front face might end up on the Right face. In traditional ciphers like AES, this is done with simple row shifts. RCEA uses the much richer structure of a Rubik's Cube, where a single rotation moves 2N+1 bytes across multiple faces simultaneously.

A 3ร—3 cube has:
  • 6 faces ร— 3 layers = 18 possible moves
  • Each move shifts bytes across 4 face boundaries
  • 5 rotations per round (N+2 = 3+2)
  • ~4.3 ร— 10ยน&sup9; possible cube states
Compare with AES:
  • AES ShiftRows: 3 fixed rotations (always the same)
  • RCEA CubeRotate: key-dependent rotations (different every time)
  • AES works on a flat 4ร—4 grid (2D)
  • RCEA works on a 3D cube structure

How RCEA Works

RCEA encrypts one block at a time. Each block passes through a pipeline of four operations, and this pipeline repeats for a configurable number of rounds (4 to 20). More rounds = more scrambling = harder to break.

Single Block Encryption Pipeline
Plaintext Block
โŠ• XOR with Keyed State
Repeat R times (4โ€“20 rounds)
S
SubBytes
S-box byte substitution
R
CubeRotate
Rubik's cube face rotations
M
FaceMix
Row & column XOR mixing
K
AddRoundKey
XOR with round key
Ciphertext Block

Step by step

1
Map plaintext to cube

The plaintext block (e.g. 54 bytes for a 3ร—3 cube) is laid out across the 6 faces.

2
XOR with Keyed State

Before any rounds begin, the block is XORed with a keyed state โ€” a block-sized value derived from your secret key. This ensures the starting point depends on the key.

3
Run R rounds

Each round applies four operations in order: SubBytes, CubeRotate, FaceMix, AddRoundKey. After all R rounds, the block is thoroughly scrambled.

4
Output ciphertext

The resulting bytes are the encrypted block. In CBC mode, this ciphertext is also fed into the next block's encryption (chaining).

The mixing analogy

Think of it like mixing paint. One stir blends the colors a little โ€” you can still see streaks. Ten stirs and the colors are uniformly blended. Each round is a stir. With 4 rounds, the data is reasonably mixed. With 10+ rounds, every output byte depends on every input byte and every bit of the key.

The actual code

Here's what the encrypt function looks like in pseudocode. This is the exact logic used by RCEA:

// 1. Start with the plaintext block
state = plaintextBlock

// 2. Mix in the key-derived initial state
state = XOR(state, keyedState)

// 3. Run R rounds of transformation
for round = 0 to R-1:
  state = SubBytes(state)          // confusion: S-box lookup
  state = CubeRotate(state, rots)  // diffusion: cube face rotations
  state = FaceMix(state)           // diffusion: row & column XOR scan
  state = XOR(state, roundKey[r])  // key mixing: round key addition

// 4. Output
ciphertextBlock = state

Decryption runs the same steps in reverse order, using inverse operations (inverse S-Box, inverse rotations, inverse FaceMix). Because every operation has a mathematical inverse, decryption perfectly recovers the original plaintext.

Why these four operations?

Good encryption needs two properties, identified by Claude Shannon in 1949:

Confusion

Each bit of the ciphertext should depend on the key in a complex way. If you change one bit of the key, the ciphertext should change unpredictably. SubBytes provides confusion through its non-linear S-Box lookup.

Diffusion

Changing one bit of the plaintext should change many bits of the ciphertext (and vice versa). CubeRotate and FaceMix provide diffusion by moving bytes around and mixing their values together.

The Four Operations

Each round applies four operations in sequence. Let's look at each one in detail โ€” what it does, why it's needed, and exactly how it transforms the data.

S

1. SubBytes โ€” Byte Substitution

Purpose: Provides confusion โ€” makes the relationship between the key and ciphertext as complex as possible.

Every single byte in the block is replaced with a different byte using a fixed lookup table called the S-Box (Substitution Box). This is the same S-Box used in AES โ€” the Rijndael S-Box, which has been studied for decades and is known to have excellent non-linearity properties.

How it works

  1. Take one byte, for example 0x53 (decimal 83)
  2. Split it into two halves: high nibble = 5 (row), low nibble = 3 (column)
  3. Look up row 5, column 3 in the 16ร—16 S-Box table
  4. The value at that position is 0xED โ€” that replaces the original byte
  5. Repeat for every byte in the entire block
S-Box Lookup โ€” One Byte Example
Input byte
0x53
Split into nibbles
Row
5
Col
3
Look up S-Box[5][3]
S-Box
Output byte
0xED
Excerpt from the 16ร—16 S-Box table (row 5 highlighted)
.0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F
4.09832C1A1B6E5AA0523BD6B329E32F84
5.53D100ED20FCB15B6ACBBE394A4C58CF
6.D0EFAAFB434D338545F9027F503C9FA8

Why is it non-linear? If the S-Box were a simple arithmetic operation (like "add 5 to each byte"), an attacker could write a math equation to describe the encryption and solve it with algebra. The S-Box is carefully designed so that no simple equation describes it โ€” it breaks linearity.

Is it reversible? Yes! There's an inverse S-Box (INV_SBOX) where INV_SBOX[SBOX[x]] = x for every byte. This is how decryption undoes the substitution.

In code: result[i] = SBOX[state[i]] โ€” that's it. One lookup per byte.

R

2. CubeRotate โ€” Cube Face Rotations

Purpose: Provides positional diffusion โ€” moves bytes from one face to another so their positions get thoroughly shuffled.

Think of actually twisting a Rubik's Cube. When you rotate a face, the 2N bytes along the edge of that face move to adjacent faces, and the Nยฒ bytes on the face itself get rearranged. RCEA applies N + 2 rotations per round, and the specific rotations are derived from the key.

How it works

  1. The key schedule pre-computes a list of move indices for each round
  2. Each move index selects one of the 6ร—N possible rotations (6 faces ร— N layers)
  3. The rotation is applied as a permutation โ€” bytes get shuffled to new positions
  4. This repeats for each move in the round (N+2 times)
Clockwise rotation of the Front face
Before rotation
Up face
x
y
z
p
q
r
s
t
u
Front face
A
B
C
D
E
F
G
H
I
Right face
1
2
3
4
5
6
7
8
9
Rotate Front CW 90ยฐ
After rotation
Up face
x
y
C
p
q
F
s
t
I
Front face
G
D
A
H
E
B
I
F
C
Right face
z
2
3
r
5
6
u
8
9

The front face's bytes are rearranged (rotated within the face).

Bytes from adjacent faces (Up right column, Right left column) also move.

Highlighted cells show bytes that moved.

Key-dependent rotations: Unlike AES where ShiftRows always shifts by the same amount, RCEA's rotations are different for every key. An attacker who doesn't know the key can't predict which rotations were applied.

Permutation math: Each rotation is stored as a permutation array โ€” position i moves to position perm[i]. Multiple rotations compose by applying them sequentially.

In code: state = applyPermutation(state, allMoves[idx].forward) for each move index.

M

3. FaceMix โ€” Value Mixing

Purpose: Provides value diffusion โ€” makes each byte's value depend on its neighbors, so changing one byte changes many others.

CubeRotate moves bytes around but doesn't change their values. FaceMix does the opposite โ€” it keeps bytes in place but XORs each one with the S-Box of its neighbor. It runs two passes on each face: first along rows (left to right), then along columns (top to bottom).

How it works

  1. Pass 1 โ€” Row scan: For each row, starting from the second cell, XOR the cell with S-Box(left neighbor). Scan left โ†’ right.
  2. Pass 2 โ€” Column scan: For each column, starting from the second cell, XOR the cell with S-Box(cell above). Scan top โ†’ bottom.
  3. Repeat for all 6 faces.
FaceMix โ€” Two-pass XOR scan on one face
Input face
48
65
6C
6C
6F
20
57
6F
72
Pass 1: Row scan โ†’
cell[i] = cell[i] โŠ• S-Box(cell[iโˆ’1])
48
D3
D5
6C
1F
B4
57
B0
8D
scan direction
Pass 2: Column scan โ†“
cell[i] = cell[i] โŠ• S-Box(cell[iโˆ’N])
48
D3
D5
B4
28
90
C8
46
91
scan direction

Why S-Box in the XOR? Using S-Box(neighbor) instead of the raw neighbor adds non-linearity. Without it, the XOR scan would be a linear operation that's easy to reverse-engineer.

Why two passes? The row scan propagates changes horizontally. The column scan propagates vertically. Together, changing any single byte affects every byte in the face.

Ripple effect: Because each cell depends on the previous one, a change in the first cell propagates through the entire row (pass 1) and then through the entire column (pass 2). After both passes, every cell in the face is affected.

The S-Box in the XOR: Using S-Box(neighbor) instead of just neighbor adds non-linearity. Without it, the scan would be a linear operation breakable with algebra.

In code: result[idx] = result[idx] ^ SBOX[result[prevIdx]]

K

4. AddRoundKey โ€” Key Addition

Purpose: Makes the cipher key-dependent โ€” without this step, the same input always produces the same output, regardless of the key.

This is the simplest operation: XOR every byte in the state with the corresponding byte from the round key. Each round uses a different round key (derived from the secret key via the key schedule), so the mixing is unique per round.

How it works

  1. Take the current state (all 6ร—Nยฒ bytes)
  2. Take the round key for this round (also 6ร—Nยฒ bytes, derived from the secret key)
  3. XOR them together, byte by byte: newState[i] = state[i] โŠ• roundKey[i]
AddRoundKey โ€” XOR with round key (one face shown)
State
A3
7F
12
E5
9B
44
D8
01
C6
โŠ•
Round Key
5C
2E
9A
31
F0
67
8B
DE
53
=
New State
FF
51
88
D4
6B
23
53
DF
95
Example (first cell):
A3โŠ•5C=FF

Why XOR? XOR is its own inverse: A โŠ• B โŠ• B = A. This makes decryption trivial โ€” just XOR with the same round key again.

Why per-round keys? If every round used the same key, an attacker could potentially cancel out multiple rounds. Unique round keys prevent this.

In code: state = xorBytes(state, roundKeys[r])

CBC Mode & Authentication

So far we've talked about encrypting a single block. But real messages are usually longer than one block (54 bytes for a 3ร—3 cube). How do we encrypt a 10KB file? We need a mode of operation โ€” a strategy for handling multiple blocks.

The problem with encrypting blocks independently

The simplest approach (called ECB mode) encrypts each block separately. But this has a fatal flaw: identical plaintext blocks produce identical ciphertext blocks. An attacker can spot patterns โ€” for example, if you encrypt an image, the shape of the image is still visible in the ciphertext!

CBC: Cipher Block Chaining

RCEA uses CBC mode. Before encrypting each block, it XORs the plaintext with the previous ciphertext block. This creates a chain โ€” each block's encryption depends on all the blocks before it. Identical plaintext blocks now produce different ciphertext because each is mixed with different previous data.

CBC Mode โ€” Cipher Block Chaining
P1
โŠ•
IV
Random initialization vector
Encrypt Block
C1
P2
โŠ•
C1
Previous ciphertext
Encrypt Block
C2
P3
โŠ•
C2
Previous ciphertext
Encrypt Block
C3
Each block depends on the previous โ†’ identical plaintext blocks produce different ciphertext
Final output format
IV|C1|C2|C3|HMAC
6ร—Nยฒ Bย 6ร—Nยฒ B eachย ย ย ย 32 B

The IV (Initialization Vector)

The first block has no previous ciphertext to chain with. So we generate a random IV (Initialization Vector) โ€” a block-sized random value. This means encrypting the same message with the same key produces completely different ciphertext each time (because the IV is different).

Properties of the IV
  • Must be random (cryptographically secure)
  • Must be unique for each encryption
  • Does NOT need to be secret
  • Sent alongside the ciphertext (prepended)
  • Same size as one block (6ร—Nยฒ bytes)
Why not secret?

The IV's job is to add randomness, not secrecy. Even if an attacker knows the IV, they still can't decrypt without the key. It's like a salt in password hashing โ€” public but essential for security.

PKCS#7 Padding

Messages don't always divide evenly into blocks. If your message is 100 bytes and your block size is 54, you need to pad the last block to fill it up. RCEA uses PKCS#7 padding:

If 8 bytes short: append 08 08 08 08 08 08 08 08

If 3 bytes short: append 03 03 03

If 1 byte short: append 01

If exactly full: add a whole new block of 36 36 36 ... 36 (for 54-byte blocks)

The pad byte tells the decryptor how many padding bytes to remove. This is unambiguous because even a full block gets padding.

HMAC Authentication (Encrypt-then-MAC)

Encryption alone protects confidentiality (nobody can read the message), but not integrity (nobody has tampered with it). An attacker could flip bits in the ciphertext, and decryption would succeed โ€” producing garbage that looks like a valid message.

RCEA uses Encrypt-then-MAC: after encrypting, it computes an HMAC-SHA256 tag over the entire ciphertext (IV + encrypted blocks). This tag is a 32-byte fingerprint. When decrypting, the tag is verified first. If it doesn't match, decryption is refused โ€” the data has been tampered with.

Authentication flow
1

Encrypt all blocks with CBC to produce ciphertext

2

Compute: tag = HMAC-SHA256(hmacKey, IV || C1 || C2 || ...)

3

Append the 32-byte tag to the output

4

On decrypt: verify tag BEFORE attempting any decryption

5

If tag doesn't match โ†’ refuse to decrypt (tampering detected)

Key Schedule

The key schedule is the process of taking your secret key (just 16 or 32 bytes) and expanding it into all the material the cipher needs: a keyed initial state, one round key per round, rotation sequences for CubeRotate, and an HMAC key for authentication. Without this expansion, the short key couldn't fill all these roles.

Key Schedule โ€” From Secret Key to All Round Materials
Secret Key
16 or 32 bytes
KDF (SHA-256)
key + label + counter โ†’ hash โ†’ expand
Keyed State
6ร—Nยฒ bytes โ€” XORed with plaintext before round 1
+ cube rotations applied
Round Keys
R ร— (6ร—Nยฒ bytes) โ€” one per round for AddRoundKey
R separate block-sized keys
Rotation Sequences
R ร— (N+2) indices โ€” which cube moves per round
each index mod (6ร—N)
HMAC Key
32 bytes โ€” for ciphertext authentication
used in Encrypt-then-MAC

Why expand? A short key (16โ€“32 bytes) can't directly fill all the round keys, rotation indices, and the keyed state. The KDF stretches the key into hundreds of bytes of pseudo-random material, each portion derived with a unique label so they're cryptographically independent.

The expansion process

RCEA uses a KDF (Key Derivation Function) based on SHA-256. It works like a deterministic random number generator โ€” given the same key and label, it always produces the same output, but different labels produce completely independent outputs.

KDF formula
KDF(key, label, length):
  output = empty
  counter = 0
  while output.length < length:
    chunk = SHA-256(key || label || counter)
    output = output + chunk
    counter++
  return output[0..length]

Each call with a different label produces independent output. The counter handles cases where more than 32 bytes are needed.

What gets derived

1
Keyed State
rcea_phase1_columns

A block-sized array (6ร—Nยฒ bytes) that's XORed with the plaintext before round 1. This is like a pre-key โ€” it ensures the starting state is already key-dependent.

After generating it from the KDF, RCEA also applies N+2 key-derived cube rotations to it, further scrambling the initial state.

2
Round Keys
rcea_round_key_0, ..._1, ..._2, etc.

One block-sized key per round. Round 0 uses rcea_round_key_0, round 1 uses rcea_round_key_1, and so on.

For a 3ร—3 cube with 10 rounds, that's 10 ร— 54 = 540 bytes of round key material, all derived from the original 16 or 32-byte key.

3
Rotation Sequences
rcea_round_rot_0, ..._1, etc.

Each round needs N+2 rotation indices for CubeRotate. Each index is computed as byte mod (6ร—N) to select from the 6ร—N possible cube moves.

For a 3ร—3 cube: each round has 5 rotations chosen from 18 possible moves. With 10 rounds, that's 50 rotation decisions, all deterministically derived from the key.

4
HMAC Key
rcea_hmac_key

32 bytes for the HMAC-SHA256 computation. This is kept separate from the encryption material โ€” using the same key for both encryption and MAC would be a security weakness. The KDF's different labels ensure cryptographic independence.

Why label-based derivation?

Using unique labels (like rcea_round_key_0) for each derived value ensures key separation:

  • Knowing one round key reveals nothing about other round keys
  • The HMAC key is independent from the encryption keys
  • The keyed state is independent from everything else
  • An attacker who somehow recovers one derived value can't compute the others

Security Notes

Educational Purpose Only

RCEA is designed for learning, not for protecting real secrets. Use AES, ChaCha20, or other well-vetted algorithms for real-world encryption.

What RCEA does well

  • Demonstrates core block cipher concepts (confusion, diffusion, key scheduling)
  • Uses the well-studied AES S-Box for non-linearity
  • Includes proper CBC mode with random IVs
  • Uses HMAC-SHA256 for ciphertext authentication (Encrypt-then-MAC)
  • Key derivation via Web Crypto HKDF

Why you shouldn't use it for real security

  • Not peer-reviewed or cryptanalyzed by experts
  • No formal security proofs
  • Side-channel attacks not considered (timing, cache)
  • Novel cipher design โ€” proven algorithms are always safer

RCEA vs. Established Algorithms

PropertyRCEAAES-256ChaCha20
TypeBlock cipherBlock cipherStream cipher
Block size24โ€“216 bytes
(variable, 6ร—Nยฒ)
16 bytes
(fixed)
64 bytes
(internal state)
Key size128 or 256 bits128, 192, or 256 bits256 bits
Rounds4โ€“20 (configurable)10 / 12 / 1420
S-BoxAES Rijndael S-BoxAES Rijndael S-BoxNone (ARX design)
ConfusionSubBytes (S-Box lookup)SubBytes (S-Box lookup)Addition + XOR (non-linear mixing)
DiffusionCube rotations
(positional permutation)
+ FaceMix
(row/col XOR scan)
ShiftRows
(row rotation)
+ MixColumns
(GF(2&sup8;) matrix multiply)
Quarter-round function
(add, rotate, XOR)
Key scheduleHKDF-SHA256 expansion โ†’ keyed state, round keys, rotation sequencesRijndael key schedule (word rotations + S-Box + Rcon)Key + nonce packed into initial state
Mode of operationCBC + HMAC-SHA256
(Encrypt-then-MAC)
GCM, CBC, CTR, etc.Poly1305 AEAD
(built-in auth)
Hardware accel.NoneAES-NI instructionsSIMD-friendly
PerformanceSlow
(JS, large blocks, many permutations)
Very fast
(~1 cycle/byte with AES-NI)
Fast
(~4 cycles/byte, constant-time)
Side-channel resistanceNot consideredConstant-time with AES-NIConstant-time by design (no S-Box)
StatusEducationalNIST Standard (2001)IETF Standard (2018)

Step-by-Step: RCEA vs. AES Round Comparison

RCEA's round structure is directly inspired by AES. Each step has an analogous operation:

RCEA Round
SubBytes
Same AES S-Box, byte-by-byte substitution
CubeRotate
Key-dependent Rubik's Cube face/layer rotations move bytes across faces
FaceMix
XOR scan along rows and columns within each face
AddRoundKey
XOR state with HKDF-derived round key
AES-256 Round
SubBytes
Same Rijndael S-Box, byte-by-byte substitution
ShiftRows
Fixed cyclic left-shift of rows in the 4ร—4 state matrix
MixColumns
Matrix multiplication over GF(2โธ) โ€” each column becomes a linear combination
AddRoundKey
XOR state with Rijndael key schedule-derived round key

Key Differences

Diffusion strategy
RCEA

Uses 3D Rubik's Cube rotations to permute bytes across 6 faces. The number of possible permutations grows with cube size (e.g., a 3ร—3 cube has ~4.3ร—10ยนโน possible states). Rotation sequences are key-dependent.

AES

Uses fixed ShiftRows (deterministic row shifts) + MixColumns (a specific matrix over GF(2โธ)). The permutation is always the same โ€” security comes from the key addition, not the shuffling pattern.

Block geometry
RCEA

Data lives on 6 faces of a cube: a 3D structure. Rotations mix bytes across face boundaries, providing cross-dimensional diffusion in a single operation.

AES

Data is a flat 4ร—4 byte matrix (2D). ShiftRows works on rows, MixColumns on columns โ€” two separate operations to achieve full diffusion.

Variable block size
RCEA

Block size = 6ร—Nยฒ bytes. A 2ร—2 cube gives 24-byte blocks, a 6ร—6 gives 216-byte blocks. Larger blocks diffuse more data per operation but are slower.

AES

Always 16 bytes (128 bits). This fixed size enables hardware optimization (AES-NI) and is efficient for most use cases.

Mathematical foundation
RCEA

FaceMix uses simple XOR accumulation โ€” effective but not proven optimal. Cube rotations provide permutation diffusion without formal mixing guarantees.

AES

MixColumns is provably optimal for branch number (every output byte depends on all input bytes after 2 rounds). Based on rigorous finite field arithmetic.