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.
- 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/0for 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.
- ✅ 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
git clone https://github.com/ten-ops/shamus.git
cd shamus
make --releaseThe 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/binA 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 argumentsshamus [OPTIONS] <MNEMONIC> --address <ADDRESS><MNEMONIC>: space‑separated BIP‑39 words; use?for unknown slots.--address: target Ethereum address (hex, with or without0xprefix).
| 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 |
1. Verify a full mnemonic
shamus "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" \
--address 0xcf6335e1c68b1f7c9d8aa84c647ffcd9595f0b032. Recover the last two words (12‑word mnemonic)
shamus "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon ? ?" \
--address 0xcf6335e1c68b1f7c9d8aa84c647ffcd9595f0b033. 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.checkpoint5. Resume an interrupted search
shamus "abandon ? ? ? ? ? ? ? ? ? ? ?" \
--address 0x... \
--resume-from $(cat ./recovery.checkpoint) \
--threads 8Add 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(())
}- Mnemonic validation – Checks that all provided words are in the BIP‑39 English wordlist and that the checksum is correct.
- Seed derivation – Applies PBKDF2‑HMAC‑SHA512 with the salt
"mnemonic" + passphraseto produce a 64‑byte seed. - Master key – Uses BIP‑32's
"Bitcoin seed"to derive the master private key and chain code. - Path derivation – Iteratively applies CKDpriv (hardened or normal) along the user‑supplied path.
- Address computation – Derives the uncompressed public key, takes Keccak‑256 of
(X || Y), and keeps the last 20 bytes. - Comparison – Compares the resulting address with the target. If they match, the mnemonic is printed.
The entire pipeline is deterministic and reproducible.
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!
- Fork the repository.
- Create a feature branch (
git checkout -b feature/awesome-thing). - Commit your changes (
git commit -am 'Add awesome thing'). - Push to the branch (
git push origin feature/awesome-thing). - Open a Pull Request.
Please make sure tests pass (make test) and code is formatted (make fmt).
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.
- 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!
This project is licensed under the MIT License. Use it freely, but please attribute.
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. 🔍