Skip to content

Latest commit

Β 

History

History
254 lines (184 loc) Β· 8.77 KB

File metadata and controls

254 lines (184 loc) Β· 8.77 KB

🐾 Cat Style Guide β€” Personality Rules for Meow Decoder

Purpose: Prevent future refactors β€” human or AI β€” from stripping the project's personality OR accidentally renaming cryptographic invariants. Both failures are real risks, and this guide draws the line between them.


Why This Guide Exists

Meow Decoder has two properties that must coexist:

  1. Serious cryptography. AES-256-GCM, Argon2id, X25519, ML-KEM, HKDF, HMAC β€” implemented in Rust, with proof sketches where applicable, and tested with 1000+ assertions.
  2. Cat-themed personality. Collar tags, kibbles, purring progress bars, whisker checks β€” a deliberate design choice that makes the project approachable without weakening security.

Past refactors have accidentally flattened one or the other. This guide prevents both.


βœ… Allowed β€” Where the Cat Lives

Playful Wrapper Names (Layer 4 FaΓ§ade)

Cat-themed function names are encouraged in meow_decoder/cat_api.py and similar faΓ§ade modules, as long as they delegate to real primitives without adding logic.

# βœ… Good β€” personality wrapper, delegates directly
def purr_encrypt(key, nonce, plaintext, aad=None):
    """Encrypt with a contented purr. (AES-256-GCM)"""
    return _get_backend().aes_gcm_encrypt(key, nonce, plaintext, aad)

# βœ… Good β€” themed name, identical semantics
def scratch_mac(key, message):
    """Leave a scratch mark β€” compute a MAC. (HMAC-SHA256)"""
    return _get_backend().hmac_sha256(key, message)

# βœ… Good β€” playful class wrapping a protocol object
class CollarTag:
    """A cat's collar tag β€” wraps a MEOW manifest."""
    def __init__(self, manifest_bytes):
        self._manifest = unpack_manifest(manifest_bytes)

Cat-Themed Comments Above Crypto Boundaries

Brief personality in comments is fine at module and section level in Layer 3+.

# βœ… Good β€” playful section divider in encode.py
# --- 🐾 Attach the collar tag (manifest) to frame 0 ---
manifest_frame = pack_manifest(...)

# βœ… Good β€” lighthearted docstring in a Layer 4 module
"""
🐱 Meow Encoder β€” Turn secrets into yarn balls (animated QR GIFs).
All the real hissing happens in crypto_backend.
"""

Cat Tone in Demos and Documentation

Layers 4–5 (demos, docs, README, QUICKSTART, examples) are fully open to personality.

<!-- βœ… Good β€” README blurb -->
πŸ”’ Under the Fur: All secret-handling cryptography now lives in the Rust
core. The cat may look playful β€” but the claws are constant-time.

<!-- βœ… Good β€” QUICKSTART encouragement -->
🐱 Your secret file is now wearing its invisible collar!

Themed CLI Messages

User-facing CLI output can (and should) be fun.

🐱 Encoding secret.txt...
βœ… Encrypted (AES-256-GCM)
βœ… Generated 18 QR frames (1.5x redundancy)
βœ… Saved to secret.gif β€” the cat is packed!

Cat-Themed Error Classes

# βœ… Good β€” wraps ValueError with a friendly message
class CatError(Exception):
    """Something scared the cat."""
    pass

class WhiskerCheckFailed(CatError):
    """HMAC verification failed β€” someone touched the whiskers."""
    pass

🚫 Forbidden β€” What Must Never Change

Renaming Domain Separation Labels

Domain separation strings are protocol constants. They appear in formal proofs, test vectors, and interop specs. Changing them silently breaks every existing encoded file.

# ❌ FORBIDDEN β€” renaming a domain separation label
info = b"kitty_kdf_magic"        # NO
info = b"purr_pqxdh_v1"          # NO
info = b"meow-purr-chain"        # NO

# βœ… CORRECT β€” these are frozen protocol constants
info = b"meow_pqxdh_v1"          # YES β€” do not touch
info = b"meow-fs-block"          # YES β€” do not touch
info = b"meow-ratchet-chain"     # YES β€” do not touch

Renaming HKDF Info Strings

HKDF info parameters are domain separators. They are not branding.

# ❌ FORBIDDEN
derived = backend.hkdf_expand(prk, b"cat_treats_key", 32)

# βœ… CORRECT
derived = backend.hkdf_expand(prk, b"meow-ratchet-chain", 32)

Renaming Nonce Derivation Logic

Nonce construction is security-critical. Changing variable names, field order, or derivation steps risks catastrophic nonce reuse.

# ❌ FORBIDDEN β€” renaming nonce variables for fun
catnip_nonce = os.urandom(12)          # NO
yarn_iv = hkdf_expand(prk, info, 12)   # NO

# βœ… CORRECT β€” standard cryptographic names
nonce = os.urandom(12)
synthetic_iv = hkdf_expand(prk, info, 12)

Altering Ratchet Invariants

The symmetric ratchet (MSR v1.2) has 10 HKDF domain separation constants, header encryption masks, and key commitment tags. These are protocol-level invariants.

# ❌ FORBIDDEN β€” renaming ratchet state variables
yarn_key = hkdf(...)         # NO β€” this is chain_key
paw_key = hkdf(...)          # NO β€” this is message_key

# βœ… CORRECT
chain_key = hkdf(...)
message_key = hkdf(...)

Adding Jokes Inside Primitive Logic

Layers 1–2 (Rust crypto core, crypto_backend.py) must contain zero humor. Auditors read this code.

// ❌ FORBIDDEN β€” joke in Rust primitive
fn paws_gcm_encrypt(key: &[u8], nonce: &[u8], pt: &[u8]) -> Vec<u8> { ... }

// βœ… CORRECT
fn aes_gcm_encrypt(key: &[u8], nonce: &[u8], pt: &[u8]) -> Vec<u8> { ... }
# ❌ FORBIDDEN β€” joke in crypto_backend.py
class CatCryptoBackend:
    def scratch_key(self, password, salt): ...

# βœ… CORRECT
class CryptoBackend:
    def derive_key_argon2id(self, password, salt, ...): ...

Modifying Rust Primitive Function Names

The 52 PyO3 bindings in meow_crypto_rs are the API contract (16 base ops + 36 opaque handle ops). Every Layer 3 module depends on these exact names.

❌ FORBIDDEN renames:
  aes_gcm_encrypt    β†’ cat_encrypt
  derive_key_hkdf    β†’ knead_key
  x25519_exchange    β†’ hiss_exchange
  hmac_sha256        β†’ scratch_hash
  secure_zero        β†’ shred_yarn

βœ… These names are permanent:
  aes_gcm_encrypt, aes_gcm_decrypt, aes_ctr_crypt
  derive_key_argon2id, derive_key_hkdf
  hkdf_extract, hkdf_expand
  hmac_sha256, hmac_sha256_verify
  sha256
  x25519_generate_keypair, x25519_exchange, x25519_public_from_private
  constant_time_compare, secure_zero, secure_random

Renaming Manifest Constants

# ❌ FORBIDDEN
MANIFEST_MAGIC = b"KITTY"
MODE_BYTE_PURR = 0x02

# βœ… CORRECT β€” these are frozen
MANIFEST_MAGIC = b"MEOW"
MODE_BYTE_MEOW2 = 0x02
MODE_BYTE_MEOW3 = 0x03
MODE_BYTE_MEOW4 = 0x04
MODE_BYTE_MEOW5 = 0x05

Quick Reference Table

Area Personality? Example
Rust function names (crypto_core/src/) No aes_gcm_encrypt stays aes_gcm_encrypt
crypto_backend.py method names No CryptoBackend.derive_key_argon2id stays as-is
Domain separation labels No "meow_pqxdh_v1" is frozen
HKDF info strings No "meow-ratchet-chain" is frozen
Protocol variable names No chain_key, message_key, ephemeral_public_key
Manifest magic/mode bytes No MEOW2=0x02 through MEOW5=0x05
AAD field ordering No Fixed struct layout, never reorder
cat_api.py wrapper names Yes purr_encrypt(), scratch_mac()
CLI output messages Yes "🐱 Encoding secret.txt..."
Docstrings in Layer 4+ Yes """Encrypt with a contented purr."""
Section comments in Layer 3 Light # --- 🐾 Attach the collar tag ---
README / QUICKSTART / demos Yes Cat puns, emoji, playful framing
THREAT_MODEL / SECURITY_INVARIANTS No Formal, precise, no jokes

πŸ” Crypto Core Is Sacred

The cryptographic core is the trust anchor of this project. It is not a branding surface.

What "sacred" means:

  • Do not rename any function in crypto_core/src/ or crypto_backend.py for aesthetic reasons.
  • Do not alter domain separation strings, HKDF info labels, nonce derivation, AAD field order, or manifest byte layouts.
  • Do not weaken Argon2id parameters, MAC verification, or AAD bindings for convenience.
  • Do not add new cryptographic algorithms in Layer 4 or Layer 5. All crypto lives in Layer 1; orchestration lives in Layer 3.
  • Do not bypass the CryptoBackend() abstraction. If a module needs crypto, it calls Layer 2.

The personality exists because the core is sacred. Cat wrappers like purr_encrypt() are safe precisely because they add zero logic β€” they forward arguments unchanged to aes_gcm_encrypt() and return the result untouched. The moment a wrapper modifies a parameter, skips a check, or introduces a new algorithm, it stops being personality and becomes a security defect.

The cat is playful. The claws are constant-time. Both must remain true.


See docs/ARCHITECTURE.md for the full 5-layer boundary model.