A compression/decompresson script (with optional GUI) that allows user to compress/decompress Nintendo Switch ROMs loselessly, thanks to zstd compression algorithm. The compressed file can be installed directly with supported NSW Homebrew Title Installers.
How to install:
There are several ways the install the script. You can find details on installation for all of them below.
You need to have a hactool compatible keys file in a suitable directory to use the script.
The keys file must be located as prod.keys file in %USERPROFILE%/.switch/(Windows)/$HOME/.switch/(UNIX) or keys.txt in the working directory.
It can be dumped with Lockpick_RCM.
NSZ files are not a real format, they are functionally identical to NSP files. Their sole purpose to alert the user that it contains compressed NCZ files. NCZ files can be mixed with NCA files in the same container.
NSC_Builder supports compressing NSP to NSZ, and decompressing NSZ to NSP. The sample scripts located here are just examples of how the format works.
XCZ files are not a real format, they are functionally identical to XCI files. Their sole purpose to alert the user that it contains compressed NCZ files. NCZ files can be mixed with NCA files in the same container.
These are compressed NCA files. The NCA's are decrypted, and then compressed using zStandard. Only NCA's with a 0x4000 byte header are supported (CNMT nca's are not supported).
The first 0x4000 bytes of a NCZ file is exactly the same as the original NCA (and still encrypted).
At 0x4000, there is the variable sized NCZ Header. It contains a list of sections which tell the decompressor how to re-encrypt the NCA data after decompression. It can also contain an optional block compression header allowing random read access.
All of the information in the header can be derived from the original NCA + Ticket, however it is provided preparsed to make decompression as easy as possible for third parties.
Directly after the NCZ header, the zStandard stream begins and ends at EOF. The stream is decompressed to offset 0x4000. If block compression is used the stream is splatted into independent blocks and can be decompressed as shown in https://github.com/nicoboss/nsz/blob/master/nsz/BlockDecompressorReader.py
class Section: def __init__(self, f): self.magic = f.read(8) # b'NCZSECTN' self.offset = f.readInt64() self.size = f.readInt64() self.cryptoType = f.readInt64() f.readInt64() # padding self.cryptoKey = f.read(16) self.cryptoCounter = f.read(16) class Block: def __init__(self, f): self.magic = f.read(8) # b'NCZBLOCK' self.version = f.readInt8() self.type = f.readInt8() self.unused = f.readInt8() self.blockSizeExponent = f.readInt8() self.numberOfBlocks = f.readInt32() self.decompressedSize = f.readInt64() self.compressedBlockSizeList =  for i in range(self.numberOfBlocks): self.compressedBlockSizeList.append(f.readInt32()) nspf.seek(0x4000) sectionCount = nspf.readInt64() for i in range(sectionCount): sections.append(Section(nspf)) if blockCompression: BlockHeader = Block(nspf)
Requires latest hactool compatible prod.keys at
Windows: %userprofile%.switch\ (enter .switch. as foldername to get a folder named .switch)
or keys.txt at the location of nsz.py/nsz.exe
Please dump your keys using Lockpick_RCM
Always keep your keys up to date as otherwise newer games can't be decrypted anymore.
nsz --level 18 -C title1.nsp title2.nsp title3.nsp
will generate title1.nsz title2.nsz title3.nsz
This tool was only tested with base games, updates and DLCs.
nsz.py --help usage: nsz.py [-h] [-C] [-D] [-l LEVEL] [-B] [-s BS] [-V] [-p] [-t THREADS] [-o OUTPUT] [-w] [-r] [-i INFO] [--depth DEPTH] [-x EXTRACT [EXTRACT ...]] [-c CREATE] [--rm-source] [file [file ...]] positional arguments: file optional arguments: -h, --help show this help message and exit -C Compress NSP -D Decompress NSZ -l LEVEL, --level LEVEL Compression Level -B, --block Uses highly multithreaded block compression with random read access allowing compressed games to be played without decompression in the future however this comes with a low compression ratio cost. Current title installers do not support this yet. -s BS, --bs BS Block Size for random read access 2^x while x between 14 and 32. Default is 20 => 1 MB. Current title installers do not support this yet. -V, --verify Verifies files after compression raising an unhandled exception on hash mismatch and verify existing NSP and NSZ files when given as parameter -p, --parseCnmt Extract TitleId/Version from Cnmt if this information cannot be obtained from the filename. Required for skipping/overwriting existing files and --rm-old- version to work properly if some not every file is named properly. Supported filenames: *TitleID*[vVersion]* -t THREADS, --threads THREADS Number of threads to compress with. Numbers < 1 corresponds to the number of logical CPU cores. -o OUTPUT, --output OUTPUT Directory to save the output NSZ files -w, --overwrite Continues even if there already is a file with the same name or title id inside the output directory -r, --rm-old-version Removes older version if found -i INFO, --info INFO Show info about title or file --depth DEPTH Max depth for file info and extraction -x EXTRACT [EXTRACT ...], --extract EXTRACT [EXTRACT ...] extract / unpack a NSP -c CREATE, --create CREATE create / pack a NSP --rm-source Deletes source file/s after compressing/decompressing. It's recommended to only use this in combination with --verify
SciresM for his hardware crypto functions; the blazing install speeds (50 MB/sec +) achieved here would not be possible without this.
Que novedades incluye la versión 4.0
- Implemented Drag & Drop support as requested in #51
Implemented CRC32 key validation and added support for future masterkeys
- Fixed the issue of master_key_0a not being recognized
- Added CRC32 for master_key_0a
- Windows 7 support for Windows builds
- Improved GUI font size scaling
Set the NSZ GUI window to be TopMost (always on top) on Windows so Drag & Drop gets much more convenient
- Added a setting to specify if the Kivy window should be always on top or not
- XCI/XCZ finally extracts to folders containing the NCA/NCZ files instead of HFS0 partition dumps
- Fixed a major XCI compatibility bug by implementing compression/decompression support for NCA files with the first section having a smaller or larger offset then 0x4000. This fixes #49
- Added NSPZ (nsZip legacy file format) extraction support
- Make GUI an optional install
- Fixed #59 ncz decompression is not working
- Cleaned up imports for nsz package
- Stop bar manager to avoid broken shells
- Added pywin32 as GUI dependency for Windows. This fixes #56
- Fixed BlockDecompressorReader.seek with whence = 2 (seek relative to the file's end). This fixes #64
Starting nsz.py from within a different working directory finally works
- Fixes the current Azure Pipeline issue
- Added solid decompression, block decompression, solid compression and block compression tests to azure-pipelines.yml
- Made NSZ new returning with error code 1 if there are any exceptions
- Fixed deadlock in BlockCompressor.py
- Highly improved block decompression speed by caching the current block
- Added Visual Studio 2019 Python Project
- Added titleId and version to the file list and highly improved its design
- The SelectableLabel items inside the game list now properly scales its height according to the available width and text length of the file path. This fixes #50
- Added a multi-language supporting open source font for #61
- Implemented input folder as output folder by default for #61
- Waiting for Enter before exit when started over GUI so errors and console output can be seen before it closes for #74
- Fixed install failing on Kubuntu 20.04 and a lot of other modern Linux distributions by improving install_linux.sh for #75
- Removed code that manipulated the XCI header size for absolutely no reason which fixes #77
- Improved decompression speed by 400% by heavily reducing the amount of performance intensive status bar refresh calls
- The decision if the last block should be decompressed or copied now matches the file format specifications by comparing the decompressed block size of that specific block with its compressed size. This issue was caused by missing the (unlikely) edge case that the last block can be larger when compressed without exceeding the general block size. This fixes #79
- Improved BlockCompression performance and overall CPU usage by reducing the amount of performance intensive status bar refresh calls.
- Ensure that the line right to the curser is clean when the application terminates
- Implemented undupe, undupe-dryrun, undupe-prioritylist, undupe-whitelist and undupe-old-versions to remove duplicate games
- Highly improved the missing prod.keys/keys.txt error message by not showing the stack trace and waiting for a user input before exiting
- Highly improved README.md
- General system stability improvements to enhance the user's experience.