Five-layer obfuscation with a planted LWE puzzle (one-time floor) and a configurable hash-PoW layer.
TLOS is a practical circuit obfuscation framework for EVM. It uses standard LWE with Gaussian noise (σ=25, n=384) for control function hiding, full-rank linear hashing for wire binding, and a planted LWE puzzle that adds a one-time q^128 brute-force floor for recovering the planted solution (lattice estimator ~2^58 for current params). Security is based on standard LWE hardness (~2^112 PQ).
TLOS provides five-layer security for on-chain circuit obfuscation, with configurable PoW throttling:
- Topology layer: Structural mixing defeats structural/statistical attacks (heuristic)
- LWE layer: Standard LWE with Gaussian noise (σ=25, n=384) hides control functions (~2^112 PQ)
- Wire binding layer: Full-rank 64x64 public linear map binds wire values across gates (algebraic binding)
- Planted LWE puzzle: One-time q^128 brute-force floor for recovering the planted solution (8.62M gas, 14% of 60M block)
- Hash-PoW (Layer 5): Hashcash-style work bound to commit-time randomness; throttles on-chain guessing and binds each guess to its commit (set difficulty to 0 to disable)
The wire binding construction is inspired by Ma-Dai-Shi 2025 but is not subspace-evasive in the formal sense - it is a public bijective linear map providing algebraic binding, not cryptographic hiding.
docs/ARCHITECTURE.mddocs/DEPLOYMENT.mddocs/FEATURE_FLAGS.mddocs/API_ENDPOINTS.mddocs/IMPLEMENTATION.mddocs/SECURITY.md
| Layer | Purpose | Security |
|---|---|---|
| Topology | Anti-attack wire patterns (non-pow2 distances, uniform usage) | Heuristic (empirical) |
| Lattice (LWE) | Control function hiding via LWE with Gaussian noise (σ=25) | ~2^112 PQ (n=384) |
| Obfuscation | Circuit representation hiding | Heuristic |
| Wire Binding | Inter-gate wire consistency via full-rank linear hash | Algebraic binding |
| Puzzle | One-time floor for planted-solution recovery (not per-guess) | Computational (q^128 brute-force) |
| PoW (configurable) | On-chain throttling bound to commit-time randomness (per-commit guesses) | Protocol-level |
+--------------------------------------------------------------+
| Input x + puzzle solution s |
+--------------------------------------------------------------+
|
v
+--------------------------------------------------------------+
| Layer 4: Verify puzzle ||A s - b||^2 < threshold |
+--------------------------------------------------------------+
|
v
+--------------------------------------------------------------+
| Wire binding init: acc0 = H(seed || x || H(s)) |
+--------------------------------------------------------------+
|
v
+--------------------------------------------------------------+
| Gates 0..N: LWE C&C + binding update |
+--------------------------------------------------------------+
|
v
+--------------------------------------------------------------+
| Verify: accN == expected AND output == expectedOutput |
+--------------------------------------------------------------+
Total gas below is checkWithPuzzle() (includes the puzzle verification).
| Config (n=384) | Gates | Total Gas | % of 60M Block |
|---|---|---|---|
| Conservative | 64 | 4,734,943 | 7% |
| Balanced | 128 | 5,917,147 | 9% |
| Standard | 256 | 8,981,516 | 14% |
| Full | 640 | 18,184,574 | 30% |
Optimizations applied:
- Seed-derived
avectors: 99.6% storage reduction (11 bytes/gate vs 3083 bytes) - Wire binding PRG: 16 coefficients per keccak (320 calls vs 4096)
- Single mod at end of inner product (vs per-term mod)
- Batch size 128 (binding updates every 128 gates)
- n=384 LWE dimension with Gaussian noise (σ=25) for ~2^112 PQ security
- Layer 4 puzzle: n=128, m=192, q=2039 for a one-time q^128 brute-force floor
TLOS uses seed-derived a vectors - the public LWE vectors are regenerated on-chain from a circuit seed instead of being stored.
| Config (n=384) | Gates | Storage | Old Format | Savings |
|---|---|---|---|---|
| Conservative | 64 | 704 bytes | 394 KB | 99.6% |
| Balanced | 128 | 1.4 KB | 788 KB | 99.6% |
| Full security | 256 | 2.8 KB | 1.58 MB | 99.6% |
Deployment scheme (Tenderly, receipts):
- Deploy circuit data via SSTORE2: 662,099 gas (256 gates) / 1,575,259 gas (640 gates)
- Deploy puzzle
bvia SSTORE2: fixed per-m(384 bytes for n=128, m=192) - Deploy TLOS instance (no data duplication): 1,707,897 gas (256) / 1,707,885 gas (640)
- Total deploy: 2,454,436 gas (256) / 3,367,584 gas (640)
View vs Transaction costs:
check(input): Free (view function, local simulation)reveal(input, puzzleSolution, nonce)/mint(): 4,734,943-18,184,574 gas (state-changing, executes_evaluate()+ puzzle)- If PoW is disabled,
noncecan be 0
- If PoW is disabled,
Why use TLOS instead of keccak256(secret)? For random 256-bit secrets, keccak is simpler and sufficient. However, TLOS provides significant advantage for low-entropy secrets and multi-bit payloads.
| Secret Type | Keccak Attack (est.) | TLOS Attack (GPU) |
|---|---|---|
| Random 256-bit | ~2^256 hashes | min(2^256, ~2^112) |
| Human password (10^6) | Milliseconds | ~181 ms |
| Range 0-100K | ~0.1 seconds | ~17 ms |
| 4-word phrase | Seconds | Seconds |
Critical limitation: Layer 4 provides only ~0.17 µs per-guess overhead on GPU (5.8M guesses/sec on A100). For low-entropy secrets, dictionary attacks complete in milliseconds to seconds. The "q^128 floor" only applies to recovering the planted solution from (A,b) without guessing the secret.
Attack cost formula:
AttackCost = |Dictionary| × 0.17µs (GPU)
AttackCost = |Dictionary| × 75µs (CPU)
PoW throttles on-chain attempts only; it does not affect offline enumeration. High-entropy secrets are required for security against offline adversaries.
- Password-gated vaults: Human phrase unlocks funds
- On-chain treasure hunts: Riddle answer reveals GPS coordinates or URL
- Number guessing games: Hide value in 0-100K range without enumeration
- Multi-code access: OR of N event codes (any code unlocks)
- Hidden game parameters: Tournament seeds revealed at game start
For random 256-bit secrets with no payload beyond TRUE/FALSE, simple keccak commitments are better (cheaper, simpler, no security loss).
Security is based on standard LWE hardness with Gaussian noise (σ=25). The lattice estimator confirms ~2^112 PQ security for n=384, q=65521, m=2560. See paper/tlos-paper.pdf for full analysis.
| Parameter | Value |
|---|---|
| Secret dimension n | 128 |
| Samples m | 192 |
| Modulus q | 2039 |
| Secret distribution | Uniform mod q |
| Error distribution | Uniform {-2,-1,0,1,2} |
| Threshold | 800 |
| Search space | q^128 brute-force (lattice estimator ~2^58) |
| Verification gas | 8.62M (Tenderly, 14% of 60M block) |
Puzzle recovery cost (one-time): Brute-force search over q^128 is computationally infeasible. The lattice estimator suggests ~2^58 security for current parameters. This does not change low-entropy dictionary asymptotics.
- Mix-and-match prevention: Gates cannot be evaluated with inconsistent inputs
- Execution trace binding: Full evaluation history is committed
- Algebraic binding: Full-rank 64x64 matrix provides unique preimage (bijective map)
- Cryptographic hiding: The linear map is public and invertible
- Collision resistance: Trivial to find x given Ax = y
- Key extraction resistance: Still relies on LWE layer for CF hiding
- iO security: Obfuscations of equivalent circuits are not indistinguishable
- VBB security: Virtual black-box is impossible in general
- Long-term secret protection: Not recommended for secrets requiring decades of protection
# Clone
git clone https://github.com/igor53627/tlos.git
cd tlos
# Build contracts
forge build
# Generate circuit data
cargo run --bin generate_tlos -- --secret 0x... --seed 42
# Run benchmarks on Tenderly
source ~/.zsh_secrets
forge script scripts/BenchmarkTLOS.s.sol --rpc-url "$TENDERLY_RPC" --broadcast --unlocked -vvvtlos/
├── contracts/
│ ├── TLOSWithPuzzleV5.sol # Production: 5-layer TLOS (PoW default; difficulty configurable)
│ ├── WeakLWEPuzzleV7.sol # Production puzzle (n=128, m=192, q^128 brute-force floor)
│ └── interfaces/
│ └── IHoneypot.sol # Commit-reveal interface
├── src/ # Rust implementation
│ ├── circuit.rs # Circuit/gate structures (Layer 1)
│ ├── lwe.rs # LWE encoding (Layer 2, Gaussian noise, σ=25)
│ ├── wire_binding.rs # Wire binding implementation (Layer 3)
│ ├── generator.rs # Deployment generator
│ ├── security/ # Security estimation
│ │ └── lattice_estimator.rs # lattice-estimator CLI wrapper
│ └── bin/
│ └── generate_tlos.rs # CLI binary
├── test/ # Foundry tests (168 tests)
│ ├── TLOSWithPuzzleV5.t.sol # Production contract tests (61 tests)
│ ├── TLOSWithPuzzleV5Harness.sol # Test harness for isolated testing
│ ├── PuzzleVariants.t.sol # Puzzle V7 tests (7 tests)
│ └── *.t.sol # Example contract tests
├── scripts/
│ ├── BenchmarkTLOS.s.sol # Tenderly benchmark
│ └── attacks/ # Attack scripts organized by layer
│ ├── layer1-topology/ # SAT/oracle-guided attacks (Rust)
│ ├── layer2-lwe/ # Lattice attacks (Python)
│ ├── layer3-binding/ # Mix-and-match attacks (Python)
│ ├── layer4-puzzle/ # Brute-force attacks (Python/GPU)
│ └── estimators/ # Security estimation tools
├── docs/
│ ├── layers/ # Per-layer technical documentation
│ │ ├── layer1-topology/ # Circuit mixing (heuristic)
│ │ ├── layer2-lwe/ # LWE encryption (~2^112 PQ)
│ │ ├── layer3-binding/ # Wire binding (algebraic)
│ │ └── layer4-puzzle/ # Planted LWE puzzle (q^128 brute-force)
│ ├── SECURITY.md # Security model
│ └── wire-binding.md # Wire binding details
├── paper/
│ ├── tlos-paper.pdf # Full paper (source of truth)
│ └── tlos.pdf # Short paper
└── examples/
├── TLOSDeadManSwitch.sol # Inheritance: Heartbeat + hidden heir codes
├── TLOSRecovery.sol # Wallet: Phrase-based recovery with puzzle
├── TLOSSealedAuction.sol # Gaming: Sealed-bid auction with puzzle
├── TLOSStopLoss.sol # DeFi: Hidden stop-loss triggers
└── TLOSTreasureHunt.sol # Honeypot: Commit-reveal + puzzle (educational)
The examples/ directory contains demonstration contracts showing TLOS integration patterns for various use cases. These are for education only - see warnings in each file.
| Example | Use Case | Layers Used | Puzzle | Production Ready |
|---|---|---|---|---|
| TLOSWithPuzzleV5 | Production | 1-5 (all) | Yes | [OK] |
| TLOSDeadManSwitch | Inheritance | 4 (puzzle) | Yes | [X] Demo only |
| TLOSRecovery | Wallet recovery | 4 (puzzle) | Yes | [X] Needs phrase entropy |
| TLOSSealedAuction | Sealed-bid auction | 4 (puzzle) | Yes | [X] Demo only |
| TLOSStopLoss | Stop-loss trigger | 2 (circuit) | No | [X] Demo only |
| TLOSTreasureHunt | Honeypot | 4 (puzzle) | Yes | [X] Educational |
Layer key:
- Layer 1: Topology mixing (structural)
- Layer 2: LWE control function hiding (n=384, σ=25 for production)
- Layer 3: Wire binding (algebraic)
- Layer 4: Planted LWE puzzle (one-time q^128 brute-force floor for planted-solution recovery)
- Layer 5: Hash-based PoW (commit-time randomness binding; difficulty configurable)
TLOS has comprehensive test coverage with 168 tests across all layers:
# Run all tests
forge test
# Run with gas reporting
forge test --gas-report
# Run specific test file
forge test --match-path test/TLOSWithPuzzleV5.t.solKey test files:
test/TLOSWithPuzzleV5.t.sol- 61 tests for the production contract (deployment, puzzle, wire binding, cross-layer, commit-reveal, gas benchmarks)test/PuzzleVariants.t.sol- 7 tests for the production puzzle V7 (n=128, q^128 brute-force)test/TLOSWithPuzzleV5Harness.sol- Exposes internal functions for isolated layer testing
TLOS security is based on the standard LWE problem with Gaussian noise and the planted LWE puzzle.
- The ~2^112 PQ estimate (for n=384, σ=25) is confirmed by the lattice estimator
- Layer 4 puzzle adds a one-time q^128 brute-force floor for recovering the planted solution; lattice estimator ~2^58 for current params
- Brute-force search over q^128 is computationally infeasible
- We encourage independent cryptanalysis
- Attack scripts organized by layer in
scripts/attacks/- seescripts/attacks/README.md - Do not use for high-value, long-lived secrets until further analysis is available
For programmatic security estimation, set up the lattice-estimator:
# Clone the estimator (requires SageMath)
git clone https://github.com/malb/lattice-estimator estimator
export PYTHONPATH="$PYTHONPATH:$(pwd)/estimator"
# Add the CLI to PATH
export PATH="$PATH:$(pwd)/scripts"
# Verify installation
lattice-estimator-cli 384 65521 \
--s-dist '{"distribution":"uniform_mod"}' \
--e-dist '{"distribution":"discrete_gaussian","stddev":25.0}' \
--m 2560Then run the ignored tests to validate security parameters:
cargo test -- --ignored- Ma-Dai-Shi 2025 - Quasi-Linear iO (wire binding inspiration)
- TLO - Base construction (archived)
- LWE Estimator - Security estimates
MIT