> For AI agents: the complete documentation index is available at https://renmori.mewbaka.cn/en/llms.txt, the full documentation bundle is available at https://renmori.mewbaka.cn/en/llms-full.txt.

# M4: polymorphism, launchers, platforms and Steam

M4 covers per-build divergence, cross-platform launch and Steam. Under the project's own open-core split, **the polymorphism engine and the native launcher are the closed component**, and Steam, Proton, Windows and Linux each need their own hardware to exercise. This page states precisely what the open baseline delivers and verifies here, and what is closed or pending hardware.

## Per-build divergence (baseline, working)

The property that "a break of one game does not port to the next" starts in the baseline: every `protect` run produces a cryptographically independent build.

- A random 16-byte `container_id` salts all key derivation (HKDF), in addition to random per-file IDs and keys and per-chunk nonces
- As a result, the same game protected twice yields a different `container_id`, different per-file keys and a different container, and one build's keys cannot read another's; this is proven in `tests/test_cli.py::test_two_builds_are_cryptographically_independent`
- The script key is independent of the container key (see [Script layer and engine lockdown](https://renmori.mewbaka.cn/en/technical/script-layer.md))

What the baseline does **not** randomize: the container's byte layout and field order, and the script AST class names, which are left standard (only re-encrypted).

### Closed upgrade: the polymorphism engine

The closed binary plugin randomizes the _structure_ per build, namely the container layout and the compiled-script encoding, so that no universal reader or decompiler can be written even with the keys in hand. It plugs into `renmori protect` over the stable, documented process interface (see [Architecture](https://renmori.mewbaka.cn/en/technical/architecture.md) and [Plugin interface](https://renmori.mewbaka.cn/en/technical/plugin-interface.md)); the open CLI is the integration point and runs the baseline when the plugin is absent. The mechanism and implementation are proprietary and live in the private `MewBaka/RenMori-core` repository.

## Launchers and platforms

The baseline loads through Ren'Py's **extension mechanism** (`game/renmori.rpe`), which runs inside Ren'Py's own bundled Python during normal startup. It is platform-agnostic: the same `.rpe` works on Windows, macOS, Linux and Steam Deck, because it relies only on Ren'Py's Python and `ctypes`, not on a per-OS launcher binary.

AES-GCM backend per platform (one interface, `container/crypto.py`):

| Platform             | Backend                                           | Status                                                                                   |
| -------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| macOS (arm64/x86_64) | OpenSSL EVP exported by `librenpython.dylib`      | **Verified here** (round trip and in-engine, on Ren'Py 8.5.2)                            |
| Linux / Steam Deck   | OpenSSL EVP exported by `librenpython.so`         | EVP exports confirmed via `nm`; same code path as macOS; full run pending Linux hardware |
| Windows              | Operating system CNG (`bcrypt.dll`), hardware AES | Code complete; run pending Windows                                                       |

The library is located beside the Python executable (`runtime_lib_candidates`, unit-tested), never via `CDLL(None)`.

### Native launcher (closed, later)

A native per-platform launcher that boots the embedded Python from the container and performs **runtime key derivation** (so that no key sits in `autorun.py`) is the closed hardening, not an open deliverable. On macOS it is ad-hoc signed automatically at build time (free, and required on Apple Silicon) and remains re-signable with a Developer ID. The **baseline ships no new executable**, so it adds no signing burden over the original Ren'Py build.

## Steam

- **The Steam overlay is safe by construction**: the overlay injects a DLL into the game process, while RenMori only hooks Ren'Py's _file loading_ and never performs process or DLL injection or anti-tamper on the hot path, so it cannot block the overlay
- **Files read outside `renpy.loader` stay on disk**: the Steam SDK reads `steam_appid.txt` directly (not through the loader), so it is kept unencrypted by default (`DEFAULT_KEEP_ON_DISK`); other such files can be added via `keep_on_disk` in `renmori.toml`; this is proven in `tests/test_cli.py::test_steam_appid_kept_on_disk`
- **Achievements and Cloud save data** go through Ren'Py's Python API, which is untouched; `.rmc` is a static file, so Steam's file verification and updates work normally
- **Do not double-wrap with Steam DRM**: it edits the executable, can conflict with a native launcher's self-check, and is weak in any case

Full Steam, Proton and Steam Deck runs are pending the corresponding hardware; the properties above are structural (based on hooks and file placement) and have not been run-tested here.

For the developer-facing release flow (build, protect, SteamPipe upload, which files go to which depot, and launch options), see [Releasing to Steam](https://renmori.mewbaka.cn/en/integration/steam-release.md).

## Also in M4

- `renpy.exists()` (previously disk-only) now also consults the container, so games that probe files with it see packed files (`_install_exists_fallback`)

## Current status

Open baseline, verified on macOS with Ren'Py 8.5.2: per-build divergence, the cross-platform `.rpe` path, Steam file placement and overlay safety by construction, and the `renpy.exists` fallback. Closed or pending hardware: the polymorphism engine, the native key-deriving launcher, and live Windows, Linux and Steam runs.
