RetroAchievementsSharp 1.0.0

dotnet add package RetroAchievementsSharp --version 1.0.0
                    
NuGet\Install-Package RetroAchievementsSharp -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RetroAchievementsSharp" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RetroAchievementsSharp" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RetroAchievementsSharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RetroAchievementsSharp --version 1.0.0
                    
#r "nuget: RetroAchievementsSharp, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RetroAchievementsSharp@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RetroAchievementsSharp&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RetroAchievementsSharp&version=1.0.0
                    
Install as a Cake Tool

RetroAchievementsSharp

NuGet .NET License: GPL-2.0-or-later Repo

A native C# port of the RAHasher hashing engine (rcheevos 40d916d → 12.4.0) that produces 100% identical hashes to the original for every supported console — the same hashes the RetroAchievements website and its clients use to identify ROMs and disc images.

  • LibraryRetroAchievementsSharp (NuGet), targets net8.0, net9.0, and net10.0; GPL-2.0-or-later.
  • CLIRetroAchievementsSharp.Cli.exe, byte-identical in behavior to RAHasher 1.8.3, plus convenience subcommands (scan, identify, consoles, checkkeys, fetch-db).
  • Verified — 415/415 fast tests + 172/172 slow (parity, real-ROM, RVZ, published-DB) green on each supported TFM, including a parity harness against source-built C oracles, RVZ-vs-ISO equality on real GameCube/Wii discs, and spot checks against the published RetroAchievements game database.

Installation

dotnet add package RetroAchievementsSharp

Works with the .NET 8, 9, and 10 SDKs/runtimes on Windows, Linux, macOS, x64 and arm64.

Using the library

Requires .NET 8, 9, or 10 (older runtimes are not supported). Add the package:

dotnet add package RetroAchievementsSharp

All API entry points live in the RetroAchievementsSharp namespace; every hash is a 32-character lowercase hex string that matches the hash published on retroachievements.org for the same file.

Hash a ROM file

using RetroAchievementsSharp;

if (RcHash.GenerateFromFile(out string hash, ConsoleIds.RcConsoleNintendo, "game.nes"))
    Console.WriteLine(hash); // e.g. "a3f5c0f8e1b2d9a4c7d6e5f4a3b2c1d0"

GenerateFromFile returns true when the file hashed successfully. The ConsoleIds constants cover every supported console (RcConsoleGameboy, RcConsoleMegaDrive, RcConsolePlaystation, …).

Hash in-memory data

byte[] data = File.ReadAllBytes("rom.bin");
if (RcHash.GenerateFromBuffer(out string hash, ConsoleIds.RcConsoleGameboy, data, data.Length))
    Console.WriteLine(hash);

Auto-detect the console (? mode)

When you don't know the console, use the iterator API — it tries every console's handler in the engine's exact table order and returns the first match:

var iterator = new RcHashIterator();
HashIterator.InitializeIterator(iterator, "Super Mario (USA).sfc", null, 0);
while (HashIterator.Iterate(out string hash, iterator) != 0)
    Console.WriteLine(hash); // the first hash that matched a console
HashIterator.DestroyIterator(iterator);

A single file can produce several hashes (e.g. a multi-disc .m3u), which is why Iterate is a loop.

Disc images (.cue, .iso, .gdi, .chd, .rvz, .wia)

Discs hash directly — no conversion needed. CHD is read via CHDSharp; GameCube/Wii RVZ/WIA images are decoded live via RVZSharp:

if (RcHash.GenerateFromFile(out string hash, ConsoleIds.RcConsolePlaystation, "disc.cue"))
    Console.WriteLine(hash);

if (RcHash.GenerateFromFile(out hash, ConsoleIds.RcConsoleGamecube, "game.rvz"))
    Console.WriteLine(hash);

if (RcHash.GenerateFromFile(out hash, ConsoleIds.RcConsoleWii, "game.chd"))
    Console.WriteLine(hash);

3DS .cia / .3ds (key files required)

Call Hash3Ds.InitHash3Ds(systemDir) once with a directory containing aes_keys.txt (and optionally seeddb.bin for seed-encrypted titles):

Hash3Ds.InitHash3Ds(@"C:\RetroArch\system");
if (RcHash.GenerateFromFile(out string hash, ConsoleIds.RcConsoleNintendo3Ds, "game.cia"))
    Console.WriteLine(hash);

Error handling

  • GenerateFromFile / GenerateFromBuffer return false (never throw) on unsupported files, missing 3DS keys, or hashing failures.
  • The engine reports errors through the message callbacks (see RcHash.InitErrorMessageCallback) — the CLI wires these to Serilog.
  • HashIterator.Iterate returns 0 when no console accepted the file.

Notes

  • Global configuration is process-wideHash3Ds.InitHash3Ds and the custom filereader/cdreader registrations (RcHash.InitCustomFilereader, RcHash.InitCustomCdreader) are global state, matching the C engine. Initialize once at startup; concurrent hashing from multiple threads is not supported.
  • Full API reference: https://purelogiccode.github.io/RetroAchievementsSharp/reference/public-api/. For exact engine behavior (64 MiB cap, header-stripping rules, track selection, verbose messages), see the documentation and known quirks.

Supported formats

Raw ROMs (all cartridge consoles), .zip (pre-loaded ROM, Arduboy FX, DOSZ/Zip64/DOSC), .m3u playlists, discs (.cue/.bin/.iso/.gdi/.chd, GameCube/Wii .rvz/.wia), 3DS .cia/.3ds/.3dsx (keys via -s / Hash3Ds.InitHash3Ds), and Neo Geo .neo carts. Console list: NES/Famicom, SNES/SFC, N64, GB/GBC/GBA, Master System, Mega Drive/Genesis, Game Gear, 32X, SG-1000, PCE/TG-16, PCE-CD, Saturn, Sega CD, Dreamcast, PS1, PS2, PSP, 3DO, PC-FX, Jaguar(+CD), Neo Geo Pocket(+Color), Neo Geo CD, NDS/DSi/3DS — the full rcheevos console table (~59 consoles), including classic microcomputers.

CLI usage

Identical to RAHasher 1.8.3:

RetroAchievementsSharp [-v] [-s systempath] system filepath...
  • -v — verbose messages for debugging
  • -s systempath — directory with aes_keys.txt / seeddb.bin (3DS)
  • system — console key (case-insensitive) or numeric id; ? auto-detects by trying every console
  • filepath — file(s) to hash; may contain wildcards in the filename; multiple files hash each in turn

Examples:

RetroAchievementsSharp NES game.nes
RetroAchievementsSharp PS1 disc.cue
RetroAchievementsSharp -s C:\RetroArch\system 3DS game.cia

Supported input formats: raw ROMs, .zip (pre-loaded ROM / Arduboy FX / DOSZ), .m3u playlists, .cue/.bin/.iso/.gdi discs, .chd discs, 3DS .cia/.3ds/.3dsx (keys required via -s), and .neo Neo Geo carts (Geolith format, hashed by ROM content). Exit codes: 0 success, 1 any failure.

Quirk faithfully reproduced from the original: console keys are only accepted for consoles with a non-empty RA group; NULL-group consoles (Oric, TI83, TIC-80, ESCV, DOS, 3DS, …) must be addressed by numeric id — e.g. RetroAchievementsSharp 62 game.cia. (The C's find_console_id falls back to atoi, so the key 3DS would silently resolve to console 3!)

RetroAchievementsSharp scan — hash a whole ROM library

(not present in RAHasher 1.8.3 — the legacy positional interface above is unchanged) hashes each file with per-file console auto-detection and emits one manifest row per file:

RetroAchievementsSharp scan [options] <path>...
  -f, --format <text|csv|json>  output format (default: text)
  -s <systempath>               supplementary files directory (3DS keys)
      --match <db.json>         RetroAchievements database snapshot
      --move <dir>              move matched files into <dir>/<console-key>/
      --dry-run                 preview --move without moving anything
      --no-recursive            do not descend into subdirectories
  -h, --help                    show help

Each file is auto-detected the same way the ? system key works for a single file; matched rows append => <Title> (ID <id>). The manifest goes to stdout, the summary (Scanned N file(s): X hashed, Y failed) to stderr; exit code 0 when every file hashed, 1 when any failed.

Other subcommands

  • RetroAchievementsSharp consoles [--format text|csv|json] — dump the console table.
  • RetroAchievementsSharp checkkeys [-s <systempath>] — validate 3DS key files.
  • RetroAchievementsSharp identify <system> <file> [--db <RetroAchievements.json> | --user <u> --api-key <k>] — hash one file and resolve it to a game with achievements (local snapshot or live API).
  • RetroAchievementsSharp fetch-db <url-or-path> [--out <file>] — download a database snapshot, validate it, save atomically.

Full details for every subcommand: docs/getting-started/usage.md.

Building

dotnet build RetroAchievementsSharp.sln -c Release

Requires any .NET 8+ SDK. All three projects multi-target net8.0;net9.0;net10.0 (CHDSharp, VideoGameFileSystemParser 1.2.0 and Serilog 4.4.0 all ship portable libs for these TFMs). Build a single target with -f net8.0 (faster).

Publishing the CLI

Self-contained single-file executables (no runtime needed on the target):

dotnet publish RetroAchievementsSharp.Cli -c Release -r win-x64    --self-contained true -p:PublishSingleFile=true -o artifacts/win-x64
dotnet publish RetroAchievementsSharp.Cli -c Release -r linux-x64  --self-contained true -p:PublishSingleFile=true -o artifacts/linux-x64

Produces RetroAchievementsSharp.Cli.exe (Windows) / RetroAchievementsSharp (Linux) in artifacts\<rid>\. (The parity suite's oracle is a Windows PE, so Tier-2 parity runs on Windows; on Linux the parity cases skip and the ported vectors still run.)

Packaging the NuGet library

dotnet pack RetroAchievementsSharp -c Release
# publishes RetroAchievementsSharp.1.0.0.nupkg + .snupkg (default: bin/Release); make artifacts/:
dotnet pack RetroAchievementsSharp -c Release -o artifacts

The package includes the net8/9/10 assemblies, XML docs, the GPL-2.0-or-later license and third-party notices, SourceLink/symbols, and runs NuGet package validation on every pack. Publishing to NuGet.org:

dotnet nuget push artifacts/RetroAchievementsSharp.1.0.0.nupkg --api-key <key> --source https://api.nuget.org/v3/index.json

See publishing.md for details.

Testing

Tests are split into two projects:

dotnet test RetroAchievementsSharp.sln -c Release          # fast suite, all TFMs (net8, net9, net10)
dotnet test RetroAchievementsSharp.sln -f net10.0          # fast suite, one TFM
dotnet test RetroAchievementsSharp.Slow.Tests -c Release   # slow suite (manual — not in the sln)

The fast suite (RetroAchievementsSharp.Tests, in the solution — 415 tests, seconds) runs every ported rcheevos test/rhash vector (cartridge, disc, cdreader, zip, m3u, handler order), synthetic 3DS/CHD fixtures, and CLI/engine unit tests. The slow suite (RetroAchievementsSharp.Slow.Tests, kept out of the solution — 172 tests, minutes) is run manually and covers:

  • Tier-2 parity harness vs. a source-built C oracle (rcheevos 12.4.0, falling back to the pinned 1.8.3 build): 90 generated cases + all CLI arg modes; stdout/stderr + exit codes byte-identical.
  • RVZ validation — real GameCube/Wii RVZ images hashed live through RVZSharp must equal the DolphinTool-converted ISO hash (6 files; skips when the libraries or DolphinTool are absent).
  • Real-ROM parity — first files of 60 user library directories vs. the pinned 1.8.3 binary (skipped-with-note when the libraries or oracle are absent).
  • Published-hash spot checks — real ROM samples hashed and looked up in a RetroAchievements game-database snapshot, asserting official matches per library (skips when the snapshot isn't present).

See parity-evidence.md for the coverage table and known-quirks.md for the unsupported-format behavior (ROM encoding not part of rcheevos).

Parity evidence

Current: 415/415 fast + 172/172 slow green on net8.0, net9.0, net10.0 — byte-identical CLI output between RetroAchievementsSharp.Cli.exe and the C oracles, including verbose mode, error paths, and exit codes; RVZ-vs-ISO equality 6/6 (GameCube and Wii); real-ROM parity 61/61; published-hash spot-check 15/15 library/console pairs. The harness has caught and fixed real port bugs (arg-count guard crash, wildcard path construction, usage banner blank line, silent merge_callbacks bug) — parity is never "accepted" as a difference; it's asserted.

Documentation

Full docs — architecture, engine deep-dives, testing, known quirks, and the release-sync playbook for absorbing future rcheevos releases:

Credits

  • LeXofLeviafan — author of the RALibretro RAHasher CLI this project is behaviorally compatible with. We use his RAHasher binaries as the reference oracle in our parity test suite (byte-identical output vs. the C original is asserted on every run). Thank you!
  • RetroAchievements / rcheevos — the hashing engine, ported 1:1 (MIT).

License

GPL-2.0-or-later — see LICENSE and THIRD-PARTY-NOTICES.md. Copyright (c) 2026 Peterson Fernandes and Pure Logic Code. The rcheevos engine is ported 1:1 (MIT, credited in the notices); RVZ/WIA hashing links RVZSharp which is GPL-2.0-or-later (Dolphin-derived). Program.cs, FileUtil.cs, Hash3DS.cs, and ChdCdReader.cs are new implementations written for behavior parity with the GPL-3.0 RALibretro RAHasher by LeXofLeviafan (used as read-only reference, never copied; the GPL binary and sources live in References\ only and are not shipped).

Changelog

See CHANGELOG.md.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 34 8/16/2026