◐ Off-By-One · answer catalog

aes-128-scratch

2 answer(s)pythonpython3pythonpython3

aes-128-scratch

📦 Source in repository (JSON)

Answer 1

The implementation is in ~/final_aes128.py. An AES-128 block cipher from scratch with:

Core primitives: - SubBytes – Byte-wise substitution via the AES S-box (a 256-byte lookup table) - ShiftRows – Circular left shift of rows (row 0: 0, row 1: 1, row 2: 2, row 3: 3) - MixColumns – Column-wise matrix multiplication in GF(2⁸) using the polynomial x⁸ + x⁴ + x³ + x + 1 - AddRoundKey – XOR state with 4 words of the expanded key - Key expansion – 44 words from 4 initial key words using RotWord, SubWord, and Rcon

Key design decisions: - State is stored column-major (4×4), matching FIPS 197 convention - GF(2⁸) multiplication uses xtime (multiply by x) and a bit-loop for general multiplication - encrypt_block / decrypt_block accept both bytes and list[int] for flexibility

Example usage:

from final_aes128 import encrypt_block, decrypt_block

key = bytes.fromhex("2b7e151628aed2a6abf7158809cf4f3c")
pt  = bytes.fromhex("6bc1bee22e409f96e93d7e117393172a")

ct = encrypt_block(pt, key)   # -> list of 16 ints
dec = decrypt_block(ct, key)  # -> back to original plaintext

Evidence & signatures

Verified against multiple sources:

| Test | Source | Status |
|------|--------|--------|
| FIPS 197 full example | FIPS 197 Table 7/8 | ✅ `3925841d02dc09fbdc118597196a0b32` |
| `key=2b7e...` / `pt=6bc1...` | NIST AES Core | ✅ `3ad77bb40d7a3660a89ecaf32466ef97` |
| `key=0001...` / `pt=0011...` | NIST AESAVS | ✅ `69c4e0d86a7b0430d8cdb78070b4c55a` |
| `key=000...0` / `pt=000...0` | NIST AESAVS | ✅ `66e94bd4ef8a2c3b884cfa59ca342b2e` |
| `key=fff...f` / `pt=fff...f` | OpenSSL `openssl enc -aes-128-ecb` | ✅ `bcbf217cb280cf30b2517052193ab979` |
| Random round-trip (100 blocks) | Encrypt then decrypt | ✅ 100/100 pass |
| Single-bit avalanche | 1 bit change → all 16 bytes differ | ✅ Strong diffusion |

---
{"model": "claude-sonnet-4-20250514", "problem_class": "aes-128-scratch", "result": "passed", "tests": 6}

Answer 2

The implementation is in ~/final_aes128.py. An AES-128 block cipher from scratch with:

Core primitives: - SubBytes – Byte-wise substitution via the AES S-box (a 256-byte lookup table) - ShiftRows – Circular left shift of rows (row 0: 0, row 1: 1, row 2: 2, row 3: 3) - MixColumns – Column-wise matrix multiplication in GF(2⁸) using the polynomial x⁸ + x⁴ + x³ + x + 1 - AddRoundKey – XOR state with 4 words of the expanded key - Key expansion – 44 words from 4 initial key words using RotWord, SubWord, and Rcon

Key design decisions: - State is stored column-major (4×4), matching FIPS 197 convention - GF(2⁸) multiplication uses xtime (multiply by x) and a bit-loop for general multiplication - encrypt_block / decrypt_block accept both bytes and list[int] for flexibility

Example usage:

from final_aes128 import encrypt_block, decrypt_block

key = bytes.fromhex("2b7e151628aed2a6abf7158809cf4f3c")
pt  = bytes.fromhex("6bc1bee22e409f96e93d7e117393172a")

ct = encrypt_block(pt, key)   # -> list of 16 ints
dec = decrypt_block(ct, key)  # -> back to original plaintext

Evidence & signatures

Verified against multiple sources:

| Test | Source | Status |
|------|--------|--------|
| FIPS 197 full example | FIPS 197 Table 7/8 | ✅ `3925841d02dc09fbdc118597196a0b32` |
| `key=2b7e...` / `pt=6bc1...` | NIST AES Core | ✅ `3ad77bb40d7a3660a89ecaf32466ef97` |
| `key=0001...` / `pt=0011...` | NIST AESAVS | ✅ `69c4e0d86a7b0430d8cdb78070b4c55a` |
| `key=000...0` / `pt=000...0` | NIST AESAVS | ✅ `66e94bd4ef8a2c3b884cfa59ca342b2e` |
| `key=fff...f` / `pt=fff...f` | OpenSSL `openssl enc -aes-128-ecb` | ✅ `bcbf217cb280cf30b2517052193ab979` |
| Random round-trip (100 blocks) | Encrypt then decrypt | ✅ 100/100 pass |
| Single-bit avalanche | 1 bit change → all 16 bytes differ | ✅ Strong diffusion |

---
{"model": "claude-sonnet-4-20250514", "problem_class": "aes-128-scratch", "result": "passed", "tests": 6}
Generated from the verified corpus · MIT licensedBack to the catalog