---
title: "Vultisig Share Decoder: From Inspector to Recovery Tool"
date: "2026-03-07"
description: "How I rebuilt the Vultisig Share Decoder from a simple vault inspector into a full key recovery pipeline — adding DKLS support, a CLI, pure JS derivation, and 13+ blockchain networks."
tags: ["crypto", "security", "go", "wasm", "project"]
urlPrev: "cuddlepuddle-first-customer.md"
urlNext: "vault-compiler.md"
---

Back in January I wrote about the [Vultisig Share Decoder](/blog/vultisig-share-decoder) — a browser tool for inspecting `.vult` backup files from Vultisig multi-sig wallets. Since then, I've rebuilt it from the ground up. What was a simple share viewer is now a full private key recovery tool.

## What changed

The original version could parse vault shares and show you what was inside. Useful for verification, but it couldn't actually reconstruct your private keys. The new version does the full pipeline: parse shares, reconstruct the master key, and derive wallet addresses with importable private keys for 13+ blockchains.

Here's what I added:

### Full codebase restructure

The old codebase was a monolithic `main.go` with everything in one file. I broke it into a proper Go project structure:

```
internal/
  vault/       # File parsing, protobuf, AES-GCM decryption
  recovery/    # GG20 + DKLS key reconstruction
  derive/      # BIP32/BIP44 address derivation per chain
  format/      # Text and JSON output formatters
cmd/
  cli/         # Native CLI binary
  wasm/        # Go WASM entry point
```

This made it possible to build multiple targets (CLI, WASM, web server) from the same codebase using Go build tags.

### DKLS key recovery

Vultisig has two TSS schemes: the older GG20 (Shamir-based) and the newer DKLS. GG20 recovery was relatively straightforward — it's well-documented secret sharing reconstruction using `bnb-chain/tss-lib`.

DKLS was the harder problem. The keyshares are opaque binary blobs, and reconstruction requires Vultisig's proprietary Rust libraries. I integrated two separate Rust WASM modules for the browser — `vs_wasm` for ECDSA key export and `vs_schnorr_wasm` for EdDSA/Schnorr. For the CLI, I used CGo bindings to the same Rust libraries compiled natively via `vultisig/go-wrappers`.

A fun bug: DKLS vaults store two keyshares per file (one ECDSA, one EdDSA), and my detection logic was tripping over reshare prefixes in vault names. Small stuff, but the kind of thing that only surfaces with real test data.

### Pure JS address derivation

Originally all the address derivation happened in Go WASM (~5.5MB gzipped). I replaced it with a pure JavaScript implementation using `@noble/curves` and `@scure/bip32` — battle-tested crypto libraries that bundle to ~27KB. The Go WASM now only handles key reconstruction, and derivation is near-instant in JS.

### CLI

Not everyone wants a browser. The CLI gives you the same recovery pipeline from the terminal:

```bash
make cli
./dist/cli recover --files "share1.vult" --files "share2.vult"
./dist/cli recover --files "share1.vult" --files "share2.vult" --format json
```

Because the CLI compiles natively with CGo, it supports both GG20 and DKLS without any WASM overhead.

### 13+ supported chains

The tool now derives keys for:

- **UTXO**: Bitcoin, Bitcoin Cash, Dogecoin, Litecoin (WIF keys for Electrum import)
- **Cosmos**: THORChain, MayaChain, Cosmos Hub, Kujira, dYdX, Terra Classic, Terra
- **EVM**: Ethereum, Tron (hex keys for MetaMask import)
- **EdDSA**: Solana, Sui, TON

Adding a new chain is just a derivation function in `internal/derive/` and a registration in `coins.go`.

## The security constraint

Same as before: **no key material leaves your machine**. The web app is a static site on Cloudflare Pages with no backend. The CLI reads files from disk and prints to stdout. You can verify by checking the network tab — the only requests are loading static assets.

Try it at [vultisig-share-decoder.pages.dev](https://vultisig-share-decoder.pages.dev), or clone it and run the CLI locally.
