This directory contains formal specifications and proofs for Meow-Encode's security-critical components.
| Tool | Purpose | Location | Status |
|---|---|---|---|
| TLA+/TLC | State machine model checking | tla/ |
β Complete |
| ProVerif | Symbolic protocol analysis (MEOW2-5) | proverif/ |
β Complete |
| Tamarin | Observational equivalence (MEOW3/4/5 PQ) | tamarin/ |
β Optional |
| Lean 4 | Mathematical proofs | lean/ |
β Complete |
| Verus | Rust implementation proofs | ../crypto_core/ |
β Complete |
Protocol source of truth: docs/protocol.md
One-command verification:
make verifyNote: Tamarin runs only if
tamarin-proveris installed. Localmake verifywill fail if it is missing; CI skips Tamarin unless installed.
cd /workspaces/meow-decoder/formal/tla
# Option 1: Direct Java (if you have tla2tools.jar)
java -jar tla2tools.jar -config MeowEncode.cfg MeowEncode.tla
# Option 2: Download TLC first
wget -q https://github.com/tlaplus/tlaplus/releases/download/v1.8.0/tla2tools.jar
java -jar tla2tools.jar -config MeowEncode.cfg MeowEncode.tla
# Option 3: Docker (no Java required)
docker run --rm -v $(pwd):/models toolsmiths/tla:latest tlc -config MeowEncode.cfg MeowEncode.tlaExpected output (success):
Model checking completed. No error has been found.
States found: XXXX, distinct: XXXX
cd /workspaces/meow-decoder/formal/proverif
# Option 1: Local ProVerif
eval $(opam env)
proverif meow_encode.pv
# Option 2: With HTML report
proverif -html output meow_encode.pv
# Option 3: Docker
docker run --rm -v $(pwd):/work proverif/proverif proverif /work/meow_encode.pvcd /workspaces/meow-decoder/formal/tamarin
./run.shYou can also use Makefile shortcuts:
make formal-proverif
make formal-proverif-htmlExpected output (success):
Query not attacker(real_secret[]) is true.
Query not attacker(real_password[]) is true.
...
RESULT All queries proved.
cd /workspaces/meow-decoder/crypto_core
# Verify with Verus
verus src/lib.rsOr run all formal checks at once:
make formal-allThe TLA+ model has been optimized for practical run times:
| Parameter | Original | Optimized | Reason |
|---|---|---|---|
MaxFrames |
4 | 2 | Fewer frame combinations |
MaxSessions |
3 | 1 | Single session sufficient |
MaxNonces |
10 | 3 | Still catches nonce reuse |
Passwords |
{1,2,3,4} | {1,2} | Real + duress only |
AttackerActionLimit |
none | 3 | Prevents state explosion |
Result: ~10K-50K states in 1-5 minutes (vs. 10M+ states in hours)
The optimized config still verifies all 6 security invariants.
The TLA+ model verifies these safety invariants over all reachable states:
| Invariant | Description |
|---|---|
DuressNeverOutputsReal |
Duress password β only decoy output |
NoOutputOnAuthFailure |
Auth failure β error state, no output |
ReplayNeverSucceeds |
Replayed frames always rejected |
NonceNeverReused |
Fresh nonce for each encryption |
TamperedFramesRejected |
Modified ciphertext β auth failure |
NoAuthBypass |
Output requires successful auth |
UnsealRequiresMatchingPCRs |
TPM unseal only with correct PCRs |
TamperPreventsUnseal |
Platform tampering prevents key access |
NoRealOutputWithoutUnsealedKey |
Real output requires unsealed hardware key |
SealedKeyNeverInChannel |
Hardware-sealed keys never appear in channel |
FailedUnsealBlocksDecrypt |
Failed unseal β no successful decryption |
KeyDerivationRequiresUnsealedOrSoftware |
Key derivation bound to hardware state |
AttackerCannotForgeUnseal |
Unseal is outside attacker's capabilities |
The ProVerif model proves these properties against a Dolev-Yao attacker:
| Query | Description |
|---|---|
attacker(real_secret) |
Plaintext confidentiality |
attacker(real_password) |
Password never leaked |
DecoderOutputReal ==> EncoderEncrypted |
Payload authenticity |
ReplayRejected |
Replay attack resistance |
DuressCorrectness |
Duress mode works correctly |
NoAuthBypass |
No authentication bypass |
The Verus proofs verify these implementation-level invariants:
| Property | Description |
|---|---|
nonce_uniqueness_invariant |
Nonce counter is strictly monotonic |
auth_then_output_invariant |
Plaintext only after GCM auth |
key_zeroization_invariant |
Key zeroed on drop |
no_nonce_reuse |
All encryptions use unique nonces |
GuardedBuffer / SecureBox bounds proofs (verus_guarded_buffer.rs):
| Property ID | Property | Lemma |
|---|---|---|
| GB-001 | Guard-page layout: data_ptr == mmap_base + page_size |
lemma_guard_layout_established |
| GB-002 | Overflow prevention: index β₯ data_size hits upper PROT_NONE guard | lemma_overflow_hits_upper_guard |
| GB-003 | Underflow prevention: data_ptr - k hits lower PROT_NONE guard |
lemma_underflow_hits_lower_guard |
| GB-004 | Data size correctness: data_size() == size_of::<T>() |
lemma_data_size_correctness |
| GB-005 | Total size β₯ data_size + 2 Γ page_size | lemma_total_size_at_least_data_plus_two_guards |
| GB-006 | data_region_size % page_size == 0 (mprotect alignment) |
lemma_data_region_page_aligned |
| GB-007 | Zeroize-on-drop: bytes set to 0 before munmap |
lemma_zeroize_erases_data |
| GB-008 | Valid access strictly within data region (not in either guard) | theorem_guarded_buffer_safety |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FORMAL VERIFICATION STACK β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β
β β TLA+/TLC β β ProVerif β β Verus β β
β β State Machine β β Protocol β β Implementation β β
β β Model β β Analysis β β Proofs β β
β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ β
β β β β β
β βΌ βΌ βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β VERIFIED PROPERTIES β β
β β β β
β β β’ Nonce uniqueness (TLA+, Verus) β β
β β β’ Auth-then-output (TLA+, Verus) β β
β β β’ Replay resistance (TLA+, ProVerif) β β
β β β’ Tamper detection (TLA+, ProVerif) β β
β β β’ Duress mode correctness (TLA+, ProVerif) β β
β β β’ Key confidentiality (ProVerif) β β
β β β’ Forward secrecy (ProVerif) β β
β β β’ Key zeroization (Verus) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β IMPLEMENTATION β β
β β β β
β β meow_decoder/crypto.py βββββ Python Implementation β β
β β rust_crypto/src/lib.rs βββββ Rust Backend β β
β β crypto_core/src/*.rs βββββ Verified Crypto Core β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The formal verification covers the following threat model:
- β Intercept - Attacker can read all network traffic
- β Inject - Attacker can send arbitrary messages
- β Replay - Attacker can replay old messages
- β Reorder - Attacker can reorder messages
- β Tamper - Attacker can modify messages (detected)
- β Break crypto - Cannot break AES-256-GCM, Argon2id
| Attack | TLA+ | ProVerif | Verus |
|---|---|---|---|
| Nonce reuse | β | β | β |
| Replay attack | β | β | - |
| Frame tampering | β | β | - |
| Frame injection | β | β | - |
| Auth bypass | β | β | β |
| Duress mode abuse | β | β | - |
| Key extraction | - | β | β |
| Forward secrecy break | - | β | - |
| Guard page underflow | β (Tamarin symbolic) | - | β
(GB-003, real verus!{}) |
| Buffer layout violation | - | - | β (GB-001, GB-005, GB-006) |
formal/
βββ README.md # This file
βββ tla/
β βββ MeowEncode.tla # TLA+ state machine specification
β βββ MeowEncode.cfg # TLC model checker configuration
β βββ README.md # TLA+ documentation
βββ proverif/
β βββ meow_encode.pv # ProVerif protocol specification
β βββ README.md # ProVerif documentation
βββ ../crypto_core/
βββ Cargo.toml # Rust crate configuration
βββ src/lib.rs # Crate entry point
βββ src/aead_wrapper.rs # AEAD wrapper (Verus annotations)
βββ src/verus_guarded_buffer.rs # β NEW: real verus!{} bounds proofs (GB-001βGB-008)
βββ src/verus_proofs.rs # AEAD/nonce invariants (doc-comment annotations)
βββ src/verus_kdf_proofs.rs # KDF invariants (doc-comment annotations)
βββ README.md # Verus documentation
All 3 models should report "No error has been found":
- MeowEncode: ~300K distinct states (main protocol pipeline)
- MeowFountain: ~44 states (fountain code properties)
- MeowStreaming: ~57K states (streaming protocol)
Model checking completed. No error has been found.
22 queries should report TRUE (critical security properties). 13 session-correspondence queries report FALSE β this is expected and documented (ProVerif overapproximates; these are not security violations).
Critical properties verified:
- Confidentiality:
attacker(real_secret)= FALSE - Password secrecy:
attacker(real_password)= FALSE - Authentication:
DecoderAuthenticated ==> EncoderStarted= TRUE - Duress safety: duress password never reveals real secret = TRUE
- PQ secrecy:
attacker(pq_shared_marker)= FALSE - Replay:
ReplayAttempted ==> ReplayRejected= TRUE
lake build
# Exit 0, no errors
Sorry gate: no unapproved sorry keywords (documentation references excluded).
cargo build --release
# Finished `release` profile
verification results:: verified: 16 errors: 0
nonce_uniqueness_invariant ... verified
auth_then_output_invariant ... verified
key_zeroization_invariant ... verified
no_nonce_reuse ... verified
lemma_guard_layout_established ... verified
lemma_overflow_hits_upper_guard ... verified
lemma_underflow_hits_lower_guard ... verified
lemma_data_size_correctness ... verified
lemma_total_size_at_least_data_plus_two_guards ... verified
lemma_data_region_page_aligned ... verified
lemma_zeroize_erases_data ... verified
lemma_valid_access_in_data_region ... verified
theorem_guarded_buffer_safety ... verified
(+ 3 spec fn definitions)
Add to .github/workflows/formal-verification.yml:
name: Formal Verification
on: [push, pull_request]
jobs:
tla-model-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run TLC
uses: docker://talex5/tlaplus
with:
args: tlc -config formal/tla/MeowEncode.cfg formal/tla/MeowEncode.tla
proverif-analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ProVerif
run: |
sudo apt-get update
sudo apt-get install -y proverif
- name: Run ProVerif
run: proverif formal/proverif/meow_encode.pv
verus-verification:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Verus
run: |
git clone https://github.com/verus-lang/verus
cd verus && ./tools/get-z3.sh && ./tools/build.sh
- name: Verify
run: ./verus/target-verus/release/verus crypto_core/src/lib.rsTo add new verified properties:
- TLA+: Add invariant to
MeowEncode.tlaandMeowEncode.cfg - ProVerif: Add query to
meow_encode.pv - Verus: Add proof to
aead_wrapper.rs
All verification must pass before merging security-critical changes.
CC BY-NC-SA 4.0 - See LICENSE file