Skip to content

czeti/shamus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Shamus 🔍 A Deterministic Wallet Recovery Tool

Shamus is a high‑performance, deterministic recovery engine for Ethereum wallets. If you have a partially known BIP‑39 mnemonic (some words missing or uncertain), a target Ethereum address, and an optional BIP‑32 derivation path, Shamus exhaustively enumerates all possible completions, derives the corresponding private keys, computes the resulting address, and checks for a match. It is the go‑to tool for recovering funds when you’ve lost a few words of your seed phrase.

Crates.io License: MIT Rust


Why Shamus?

  • Deterministic & Reproducible: Every operation is pure; the same inputs always yield the same outputs.
  • Partial Mnemonic Recovery: Use ? placeholders for unknown words. Supports any number of unknowns.
  • Arbitrary BIP‑32 Paths: Specify custom paths (e.g., m/44'/60'/0'/0/0 for standard Ethereum, or any other wallet path).
  • Parallel Search: Automatically utilises all CPU cores (--threads 0) for massive speedups.
  • Checkpointing & Resumability: Save progress to a file and resume later, even after Ctrl+C.
  • Dual CLI & Library: Use as a command‑line tool or embed directly in your Rust applications.
  • Battle‑Tested: Verified against official BIP‑39 and BIP‑32 test vectors.

Features at a Glance

  • Multi‑threaded brute‑force of BIP‑39 mnemonic combinations
  • Ethereum address derivation from private keys
  • Flexible derivation path parsing (hardened indices with ')
  • Checkpoint files: never lose progress
  • Signal‑handling: clean exit on Ctrl+C
  • Zero‑cost abstractions: fast, safe Rust code

Installation

From source (recommended)

git clone https://github.com/ten-ops/shamus.git
cd shamus
make --release

The binary will be at target/release/shamus. Optionally copy it to a directory in your PATH:

cp target/release/shamus ~/.local/bin/   # or /usr/local/bin

Using the Makefile

A Makefile is provided for common tasks:

make release      # builds release binary
make test         # runs all tests
make fmt          # formats code
make lint         # runs clippy
make doc          # generates documentation
make run ARGS="..."  # runs the CLI with arguments

Usage

Basic syntax

shamus [OPTIONS] <MNEMONIC> --address <ADDRESS>
  • <MNEMONIC>: space‑separated BIP‑39 words; use ? for unknown slots.
  • --address: target Ethereum address (hex, with or without 0x prefix).

Common options

Flag Description
-p, --passphrase <PASSPHRASE> Optional BIP‑39 passphrase (default: empty)
-t, --threads <N> Number of threads (0 = use all available cores)
--path <PATH> Derivation path (default: m/44'/60'/0'/0/0)
--resume-from <INDEX> Resume search from a specific candidate index
--checkpoint-file <FILE> File to read/write resume index (default: .shamus.checkpoint)
--checkpoint-interval <N> Write checkpoint every N candidates (default: 100000)
-h, --help Print help

Examples

1. Verify a full mnemonic

shamus "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" \
  --address 0xcf6335e1c68b1f7c9d8aa84c647ffcd9595f0b03

2. Recover the last two words (12‑word mnemonic)

shamus "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon ? ?" \
  --address 0xcf6335e1c68b1f7c9d8aa84c647ffcd9595f0b03

3. Use a custom derivation path

shamus "abandon ? ? ? ? ? ? ? ? ? ? ?" \
  --address 0x... \
  --path "m/44'/60'/0'/0/0"

4. Parallel search with checkpointing

shamus "abandon ? ? ? ? ? ? ? ? ? ? ?" \
  --address 0x... \
  --threads 8 \
  --checkpoint-file ./recovery.checkpoint

5. Resume an interrupted search

shamus "abandon ? ? ? ? ? ? ? ? ? ? ?" \
  --address 0x... \
  --resume-from $(cat ./recovery.checkpoint) \
  --threads 8

Using as a Library

Add shamus to your Cargo.toml:

[dependencies]
shamus = { git = "https://github.com/ten-ops/shamus.git" }

Basic example:

use shamus::{verify_mnemonic_against_eth_address, MnemonicConstraint, WordConstraint};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let words = vec!["abandon", "abandon", "abandon", "abandon", "abandon",
                     "abandon", "abandon", "abandon", "abandon", "abandon",
                     "abandon", "?"];
    let passphrase = "";
    let target = hex_literal::hex!("cf6335e1c68b1f7c9d8aa84c647ffcd9595f0b03");
    let path = [44 | 0x80000000, 60 | 0x80000000, 0 | 0x80000000, 0, 0];

    let constraints = words.iter()
        .map(|&w| if w == "?" { WordConstraint::Any } else { WordConstraint::Fixed(w.to_string()) })
        .collect();
    let constraint = MnemonicConstraint::new(constraints)?;

    // Sequential search (use 1 thread)
    if let Some(found) = shamus::search_partial_mnemonic(
        &constraint, passphrase, &target, 1, &path, None, &|_| {}
    ) {
        println!("Found: {}", found.join(" "));
    }
    Ok(())
}

How It Works (The Cryptography)

  1. Mnemonic validation – Checks that all provided words are in the BIP‑39 English wordlist and that the checksum is correct.
  2. Seed derivation – Applies PBKDF2‑HMAC‑SHA512 with the salt "mnemonic" + passphrase to produce a 64‑byte seed.
  3. Master key – Uses BIP‑32's "Bitcoin seed" to derive the master private key and chain code.
  4. Path derivation – Iteratively applies CKDpriv (hardened or normal) along the user‑supplied path.
  5. Address computation – Derives the uncompressed public key, takes Keccak‑256 of (X || Y), and keeps the last 20 bytes.
  6. Comparison – Compares the resulting address with the target. If they match, the mnemonic is printed.

The entire pipeline is deterministic and reproducible.


Development & Contributing

This project is rushed and under active development, I threw it together to solve this problem and I’m continuously improving it. There are probably edge cases I haven't thought of yet, and missing features. Contributions are warmly welcomed!

How to contribute

  1. Fork the repository.
  2. Create a feature branch (git checkout -b feature/awesome-thing).
  3. Commit your changes (git commit -am 'Add awesome thing').
  4. Push to the branch (git push origin feature/awesome-thing).
  5. Open a Pull Request.

Please make sure tests pass (make test) and code is formatted (make fmt).


Star this repo! ⭐

If you find Shamus useful, please star the repository if you want to keep track of improvements. I plan to add more features (like progress bars, GPU acceleration, and support for other cryptocurrencies) in future updates. Starring ensures you’ll be aware of new releases.


Limitations

  • Only supports the English BIP‑39 wordlist (for now).
  • Assumes the Ethereum address format (derived from uncompressed public key).
  • Currently no GPU acceleration purely CPU‑based (but highly optimised).
  • Rushed code: some parts may be rough around the edges; contributions to polish are welcome!

License

This project is licensed under the MIT License. Use it freely, but please attribute.


Contact me

If you have questions or suggestions, you can reach me on Session: 05113397ab0111e2ec2615d8a0d71499d8eaa5b5a92ebf5e2f2d79cbd858c73830


Shamus. because sometimes you just need a private eye for your wallet. 🔍

About

Deterministic Ethereum wallet recovery for partial BIP39 mnemonics. Brute‑force missing words with parallel CPU search, checkpointing, and a Rust CLI/library.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors