Skip to content

Instantly share code, notes, and snippets.

@steebchen
Created March 19, 2021 15:59
Show Gist options
  • Save steebchen/e1a01db55f0270c5f8e5a2d0378e4d7b to your computer and use it in GitHub Desktop.
Save steebchen/e1a01db55f0270c5f8e5a2d0378e4d7b to your computer and use it in GitHub Desktop.
Recover mnemonic seed phrase with a single missing word and a public key
package main
import (
"bufio"
"log"
"os"
"strconv"
"strings"
hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
)
// main: finds out a missing single word from a mnemonic seed phrase, e.g. if you know only 11 of 12 AND the public address
// it doesn't matter at which index the word is missing
//
// usage:
// go run . "<11 word seed phrase with spaces>" "public address in hex" "derivation path" <word count>
//
// e.g.
// go run . "eternal health later rebel giraffe dynamic ..." "0xA46D2CF...." "m/44'/60'/0'/0/0" 12
//
// get the wordlist via:
// curl -sL https://raw.githubusercontent.com/mcdallas/cryptotools/master/cryptotools/BTC/HD/wordlist.txt -o wordlist.txt
func main() {
originalSeed := strings.TrimSpace(os.Args[1])
originalAddress := strings.TrimSpace(os.Args[2])
derivationPath := strings.TrimSpace(os.Args[3])
wordCountRaw, _ := strconv.ParseInt(strings.TrimSpace(os.Args[4]), 10, 64)
wordCount := int(wordCountRaw)
originalWords := strings.Split(originalSeed, " ")
f, err := os.Open("wordlist.txt")
if err != nil {
panic(err)
}
var words []string
s := bufio.NewScanner(f)
for s.Scan() {
words = append(words, s.Text())
}
if err := s.Err(); err != nil {
log.Fatal(err)
}
defer f.Close()
for _, word := range words {
for i := 0; i < wordCount; i++ {
var f string
var seed []string
offset := 0
for j := 0; j < wordCount; j++ {
if i == j {
f = word
seed = append(seed, word)
offset = 1
} else {
seed = append(seed, originalWords[j-offset])
}
}
mnemonic := strings.Join(seed, " ")
log.Printf("mnemonic: %s", mnemonic)
wallet, err := hdwallet.NewFromMnemonic(mnemonic)
if err != nil {
if err.Error() == "mnemonic is invalid" {
continue
}
log.Fatal(err)
}
path := hdwallet.MustParseDerivationPath(derivationPath)
account, err := wallet.Derive(path, false)
if err != nil {
log.Fatal(err)
}
if account.Address.Hex() == originalAddress {
log.Printf("missing word was: %s", f)
log.Printf("found mnemonic: %s", mnemonic)
os.Exit(0)
}
}
}
log.Fatal("no matching originalAddress found")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment