The pipeline
A successful build runs the full compiler pipeline: lexer and parser, semantic analysis, a configurable source-level IR pass, bytecode optimization, protected serialization with per-build encryption, and a generated custom VM loader.
What each layer of protection does:
- Custom bytecode VM. Your source is compiled to register bytecode with a per-build opcode map, encrypted operands, and scrambled constant pools. The VM interpreter is generated fresh every build with randomized dispatch structure, handler variants, and opaque predicates.
- Stacked VMs. Higher presets nest the build inside further, independently randomized VMs, each with its own opcode map and integrity seal, so analysis must peel every layer.
- Control flow. State-machine flattening, jump scrambling, dead handlers, and bogus branches that survive static reading.
- Data protection. String and constant encryption at build time with runtime decryption, variable and function renaming, table key protection, and environment capture hiding.
- Anti-tamper. Per-proto and per-chunk integrity checksums verified during execution, VM prerequisite validation, and fail-closed behavior on modification.
- Anti-env. Environment fingerprinting guards against env-loggers and tampering harnesses; builds validate their runtime before executing your script.
- Watermark. Every build carries a build ID inside the encrypted payload, so a leaked script traces back to the build that produced it.
The dashboard
Enter your key at the start page, then open the dashboard. Paste Luau source or drop a .lua / .luau file onto the upload zone, pick a preset, optionally set a seed (same seed = identical build) and a build ID watermark, then Process Script. The build runs entirely in your browser; the output downloads as yourscript.protected.luau. Build stats show engine, VM count, seed, payload size, opcode count, and integrity chunks.
Presets (Cyrway levels)
- Cyrway 1 (Lightweight) — single VM, no junk, no integrity overhead. Fastest runtime, smallest output.
- Cyrway 2 (Balanced) — single VM with the IR pass, payload compression, and fast integrity checks. The everyday default.
- Cyrway 3 (Maximum) — secure VM layout, full integrity verification, scrambled constants, compressed payload.
- Cyrway 4 (Paranoid) — maximum plus a second stacked VM and heavy junk injection. Strongest protection; much larger output and much slower runtime. Test it before relying on it.
Every build is polymorphic: the seed drives identifier names, constant layout, opcode numbering, VM structure, instruction encoding, string encoding and junk generation, so two builds of the same source share nothing. Integrity is checksum-based and fails closed. Cyrway is deliberately not an exploit detector: it protects the script, it does not fingerprint or attack the user's environment.
Keys
Keys are signed by the Cloudflare Worker and verified by POST /api/verify-key. Owners generate user keys with POST /api/owner/generate-key (name, days, build limit). Health check at GET /api/health. Keep the owner key secret: set it as the CYRWAY_OWNER_KEY environment variable in Cloudflare Pages and never commit it.
CLI
node bin/cyrway.js input.luau output.luau --preset maximum node bin/cyrway.js input.luau -o out.luau --preset paranoid --seed myseed --build-id myname-001 --quiet
Presets: lightweight | balanced | maximum | paranoid. Flags: --seed, --junk, --guard, --integrity, --vm-layers, --vm-mode, --ir, --name-style, --compression, --lock-place, --lock-universe, --config (JSON file of engine options). The CLI uses the same engine as the dashboard.
Benchmarks
Measured with tools/bench.js (seed cyr-bench-1). Workload: recursive fib, table build, string concat, about 105 ms in the reference Luau VM. Median of 3 runs for each level, parity verified per run. This microbenchmark hits the VM dispatcher worst case; event-driven Roblox scripts sit much closer to the floor than fib does.
| Level | Output | Build | Runtime |
|---|---|---|---|
| Cyrway 1 (Lightweight) | 15.6 KB | 89 ms | ~29.7 s, about 284x |
| Cyrway 2 (Balanced) | 45.6 KB | 177 ms | ~63.1 s, about 603x |
| Cyrway 3 (Maximum) | 61.1 KB | 74 ms | ~82.0 s, about 784x |
| Cyrway 4 (Paranoid) | 1.19 MB | 1.18 s | over 120 s (stacked VMs) |
Straight talk: the custom VM trades runtime for protection and this benchmark shows that trade at its worst. Use Cyrway 2 for scripts with hot loops, Cyrway 3 when the script runs briefly or behind a loader, Cyrway 4 only for payloads that execute once. The optimization roadmap is dispatch cost, not more layers.
Fidelity
After generating output the engine re-parses it with the real Luau parser and refuses to return anything invalid. The full behavior-parity suite (243 corpus cases, 126 IR cases, 10 anti-tamper cases) runs protected builds and originals in a real Luau interpreter and requires identical output. Protection raises reverse-engineering cost; it is not impossible to defeat, and we do not claim generic Lua or unknown runtimes as supported targets. Test protected builds where you intend to run them.