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, and this page is available as Markdown at https://renmori.mewbaka.cn/en/index.md.
  • English
  • RenMori
    Full-data protection for
    commercial Ren'Py visual novels

    Released by MewBaka, protecting your visual novel without getting in the way

    pip
    uv
    pipx
    pip install renmori
    RenMoriRenMori

    Full-data encryption

    Scripts, sprites, CGs, audio, video, fonts, translations and configuration are packed into an encrypted container and decrypted only inside the running engine, leaving no plaintext assets on disk

    Non-invasive

    Works directly on the distribution build or .zip archive produced by the Ren'Py launcher, with no changes to the project source or existing workflow

    Per-build variation

    Every build is protected differently, so reverse-engineering results for one title or version do not carry over to other builds

    Zero configuration

    Works out of the box; an optional renmori.toml controls chunk size, exclusion lists, locking, protection strength and key source

    Built for CI

    Emits machine-readable JSON results with explicit exit codes, and renmori verify serves as a pipeline gate that packs and verifies every distribution build automatically

    Free for commercial use

    Protecting any Ren'Py game is free, commercial titles included, and the runtime may be redistributed with the game at no cost

    Data and verification

    All figures below are taken from the milestone verification records and the container format specification in the RenMori repository, with the measurement or derivation conditions stated for each.

    74 MB/s
    In-engine sequential decryption
    Measured, baseline reference reader ¹
    ≈ 0.024%
    Container size overhead
    Derived from the format spec ²
    7 / 7
    Asset types byte-identical
    SHA-256 comparison ³
    0
    Recoverable file signatures
    Gigabyte-scale container scan ³

    Decryption throughput vs. real-time playback

    The baseline Python reference reader measured about 74 MB/s of in-engine sequential decryption on multi-megabyte assets, far above the few MB/s that real-time video and audio decoding require. The shipped native decryptor removes the per-chunk Python call overhead; its throughput has not been measured separately.

    Chunk layout and size overhead

    Schematic, not to scale

    offset(i) = data_offset + i × (chunk_size + 16)

    Each chunk is encrypted independently with a 16-byte GCM authentication tag, giving a size overhead of 16 / 65,536 ≈ 0.024%, plus a 64-byte header and the encrypted index. The fixed chunk stride allows any position to be reached by seeking directly, and large files are decrypted as a stream without being loaded into memory in full.

    Files on disk

    BeforeTypical distribution build (illustrative)
    • game/archive.rpaPlaintext
    • game/images.rpaPlaintext
    • game/script.rpycPlaintext
    • game/script.rpyPlaintext
    After
    • game/renmori.rmcEncrypted container
    • game/renmori.rpeRuntime loader

    After protection, no plaintext archive, .rpyc or .rpy remains on disk; every asset exists only in encrypted form inside the container, and the runtime adds only a cache/ directory.

    Off-the-shelf tools and signature scan

    ToolMeasured result
    unrpaRejects the container: version auto-detection fails because the file is not an RPA archive
    unrpycNothing to decompile: no .rpyc or .rpy exists on disk
    Multi-byte file signatures
    • PNGNot found
    • RENPY RPC2Not found
    • OggSNot found
    • RIFFNot found
    • OTTONot found
    • zipNot found

    Signature carving over a gigabyte-scale container found no multi-byte file signatures, only the three-byte coincidental matches expected by chance, none of them recoverable; the container is indistinguishable from random data.

    Asset type verification

    Asset typeDelivery pathResult
    Images: sprites, CGs (PNG/JPG)BufferedByte-identical
    Audio (Opus/OGG)BufferedByte-identical
    Scripts (.rpyc)BufferedByte-identical
    Translations (tl/<language>/)BufferedByte-identical
    Fonts, small (TTF)BufferedByte-identical
    Fonts, large multi-MB (TTF)StreamedByte-identical
    Video, large (WebM/OGV/AVI)StreamedByte-identical

    Every asset type was decrypted through the real in-engine renpy.loader and compared against the SHA-256 of the original file.

    Cryptographic specification

    Authenticated encryption
    AES-256-GCM
    Key derivation
    HKDF-SHA256 (RFC 5869)
    Key granularity
    Independent key per file
    Chunking
    64 KB by default, 16-byte authentication tag per chunk
    Random access
    Seek directly to any chunk; large files are streamed
    Build independence
    Each build generates its own container_id and per-file keys; keys from one build cannot read another
    Per-build polymorphism and native obfuscation
    Build-time transforms with no runtime overhead
    1. ¹ Measured inside the Ren'Py 8.5.2 engine with the Python reference reader (OpenSSL EVP in librenpython via ctypes), reading multi-megabyte assets sequentially with AES-256-GCM in 64 KB chunks; the shipped native decryptor has not been measured.
    2. ² Derived from the container format v1 specification, not a measured value.
    3. ³ Verified on Ren'Py 8.5.2 with the SDK sample project the_question and a gigabyte-scale distribution build containing thousands of assets.

    Sources: M1 results · Container format v1 · Architecture · M4