A Go library and CLI for generating, validating, and deriving seeds from Electrum wallet mnemonics — both the legacy v1 (old-style, 12-word) format and the modern v2 format (with version-prefixed seed types: standard, segwit, and 2FA).
- Multi-language wordlists — English, Chinese (Simplified), Japanese, Portuguese, and Spanish for v2.
- Compressed and uncompressed keys — control WIF / public-key compression on derivation for both v1 and v2.
- Multi-chain support — Bitcoin, Litecoin, Dash, Ravencoin, Bitcoin Cash, and Bitcoin SV out of the box.
- BIP-39 skip — generation discards phrases that are also valid BIP-39 mnemonics, matching official Electrum behaviour.
- Wordlist validation — v2 validation checks that every word exists in the active wordlist (not only the version prefix).
- Full v1 + v2 coverage — encode/decode, generate, validate, seed derivation, and BIP32-style address derivation for both formats.
- Electrum v1 (
electrumv1)- Generate 12-word mnemonics from random entropy
- Encode/decode between hex entropy and mnemonic words
- Validate mnemonics
- Derive seed bytes (entropy) from a mnemonic
- Derive addresses / WIF across supported networks (compressed or uncompressed)
- Electrum v2 (
electrumv2)- Generate mnemonics for a chosen seed version (
standard,segwit,2fa,2fa-segwit) and strength (132 or 264 bits) - Encode/decode entropy to/from mnemonic words
- Validate a mnemonic against a specific seed version prefix and wordlist membership
- Derive a 64-byte BIP-39-style PBKDF2 seed from a mnemonic (with optional passphrase)
- Detect which seed version a mnemonic matches
- Multiple wordlists: English, Chinese (Simplified), Japanese, Portuguese, Spanish
- Address / key derivation with compressed or uncompressed keys
- Generate mnemonics for a chosen seed version (
- CLI (
electrumnemonic) wrapping both packages for quick command-line use
go get github.com/postnd/electrumnemonicOr clone and build the CLI:
git clone https://github.com/postnd/electrumnemonic
cd electrumnemonic
go build -o electrumnemonic ./cmd/electrumnemonicpackage main
import (
"fmt"
"log"
"github.com/postnd/electrumnemonic/pkg/electrumv1"
"github.com/postnd/electrumnemonic/pkg/electrumv2"
)
func main() {
// v1 — always 12 words
m1, err := electrumv1.GenerateMnemonic()
if err != nil {
log.Fatal(err)
}
fmt.Println("v1:", m1)
// v2 — default segwit, 132-bit (~12 words); skip BIP-39-valid phrases
m2, err := electrumv2.GenerateMnemonic(electrumv2.VersionSegwit, electrumv2.Strength132, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("v2 segwit 12w:", m2)
// v2 — 24-word (264-bit) standard mnemonic
m24, err := electrumv2.GenerateMnemonic(electrumv2.VersionStandard, electrumv2.Strength264, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("v2 standard 24w:", m24)
}package main
import (
"fmt"
"github.com/postnd/electrumnemonic/pkg/electrumv1"
"github.com/postnd/electrumnemonic/pkg/electrumv2"
)
func main() {
// v1
ok := electrumv1.ValidateMnemonic("heartbeat some whole laugh self distance okay radio battle pop quite cloud")
fmt.Println("v1 valid:", ok)
// v2 — checks wordlist membership + version prefix
ok = electrumv2.ValidateMnemonic(
"whip arrow install joy spin labor vivid certain view fire radar abuse",
electrumv2.VersionSegwit,
)
fmt.Println("v2 segwit valid:", ok)
// Detect any known version
version := electrumv2.DetectVersion("donkey dish social eternal tissue inform puzzle athlete upon foot mutual noble")
fmt.Println("v2 version:", version)
}package main
import (
"fmt"
"log"
"github.com/postnd/electrumnemonic/pkg/electrumv1"
"github.com/postnd/electrumnemonic/pkg/electrumv2"
"github.com/postnd/electrumnemonic/pkg/network"
)
func main() {
// v2 segwit → Bitcoin native SegWit, compressed WIF
addrs, err := electrumv2.FromMnemonic(
"whip arrow install joy spin labor vivid certain view fire radar abuse",
"", // passphrase
network.NetworkBitcoin,
false, // receiving chain
1, // count
true, // compressed
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("v2 path=%s address=%s wif=%s\n",
addrs[0].DerivationPath, addrs[0].Address, addrs[0].PrivateKeyWIF)
// v2 standard → Litecoin, uncompressed
addrs, err = electrumv2.FromMnemonic(
"regret elephant online fruit neck pave debate mansion mobile future spin suffer",
"",
network.NetworkLitecoin,
false,
1,
false, // uncompressed
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("v2 LTC path=%s address=%s wif=%s\n",
addrs[0].DerivationPath, addrs[0].Address, addrs[0].PrivateKeyWIF)
// v1 → Bitcoin (uncompressed in this example)
v1addrs, err := electrumv1.FromMnemonic(
"heartbeat some whole laugh self distance okay radio battle pop quite cloud",
network.NetworkBitcoin,
false,
1,
false,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("v1 path=%s address=%s wif=%s\n",
v1addrs[0].DerivationPath, v1addrs[0].Address, v1addrs[0].PrivateKeyWIF)
}package main
import (
"encoding/hex"
"fmt"
"log"
"github.com/postnd/electrumnemonic/pkg/electrumv1"
)
func main() {
mnemonic, err := electrumv1.GenerateMnemonic()
if err != nil {
log.Fatal(err)
}
fmt.Println("mnemonic:", mnemonic)
mnemonic, err = electrumv1.Encode("232ccc9d2352b116c4e2222c04d73c86")
if err != nil {
log.Fatal(err)
}
fmt.Println("encoded:", mnemonic)
entropy, err := electrumv1.Decode(mnemonic)
if err != nil {
log.Fatal(err)
}
fmt.Println("entropy:", hex.EncodeToString(entropy))
ok := electrumv1.ValidateMnemonic(mnemonic)
fmt.Println("valid:", ok)
}package main
import (
"encoding/hex"
"fmt"
"log"
"github.com/postnd/electrumnemonic/pkg/electrumv2"
)
func main() {
mnemonic, err := electrumv2.GenerateMnemonic(electrumv2.VersionSegwit, electrumv2.Strength132, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("mnemonic:", mnemonic)
ok := electrumv2.ValidateMnemonic(mnemonic, electrumv2.VersionSegwit)
fmt.Println("valid:", ok)
seed, err := electrumv2.MnemonicToSeed(mnemonic, "optional-passphrase")
if err != nil {
log.Fatal(err)
}
fmt.Println("seed:", hex.EncodeToString(seed))
version := electrumv2.DetectVersion(mnemonic)
fmt.Println("detected version:", version)
electrumv2.SetWordlistLanguage(electrumv2.WordlistJapanese)
}Supported seed versions:
| Version | Prefix | Description |
|---|---|---|
VersionStandard |
01 |
Legacy P2PKH / P2SH |
VersionSegwit |
100 |
Native SegWit (bech32) |
Version2FA |
101 |
TrustedCoin 2FA (legacy) |
Version2FASegwit |
102 |
TrustedCoin 2FA + SegWit |
Derivation lives inside the electrumv1 and electrumv2 packages and uses
btcsuite/btcd's hdkeychain (v2) or
Electrum's classic stretch-and-add scheme (v1).
FromMnemonic / FromSeed take a change bool to select receiving vs change:
| Version | Receiving (change=false) |
Change (change=true) |
|---|---|---|
VersionSegwit / Version2FASegwit |
m/0'/0/<index> |
m/0'/1/<index> |
VersionStandard / Version2FA |
m/0/<index> |
m/1/<index> |
| Electrum v1 | m/0/<index> |
m/1/<index> |
Built-in networks:
| Network | Network constant |
Native SegWit? |
|---|---|---|
| Bitcoin | NetworkBitcoin |
Yes |
| Litecoin | NetworkLitecoin |
Yes |
| Dash | NetworkDash |
No |
| Ravencoin | NetworkRavencoin |
No |
| Bitcoin Cash | NetworkBitcoinCash |
No |
| Bitcoin SV | NetworkBitcoinSV |
No |
For networks without native SegWit support, deriving with
VersionSegwit / Version2FASegwit will produce invalid addresses — use
VersionStandard / Version2FA for those instead.
go get github.com/btcsuite/btcd/btcutil
go get github.com/btcsuite/btcd/btcutil/hdkeychain
go get github.com/btcsuite/btcd/chaincfgSecurity note: private keys and WIFs derived this way control real funds if used on mainnet with a real mnemonic. Never print, log, or transmit them outside of a trusted, offline environment.
electrumnemonic v1 <command> [args]
electrumnemonic v2 <command> [args]
electrumnemonic v1 generate
electrumnemonic v1 encode <entropy-hex>
electrumnemonic v1 decode <mnemonic...>
electrumnemonic v1 validate <mnemonic...>
electrumnemonic v1 derive mnemonic [-network ...] [-change] [-count N] [-compressed] <mnemonic...>
electrumnemonic v1 derive seed [-network ...] [-change] [-count N] [-compressed] <seed-hex>
electrumnemonic v1 derive wif [-network ...] [-compressed] <wif>electrumnemonic v2 generate [-version segwit|standard|2fa|2fa-segwit] [-strength 132|264] [-lang en|zh|ja|pt|es]
electrumnemonic v2 encode <entropy-hex>
electrumnemonic v2 decode <mnemonic...>
electrumnemonic v2 validate [-version ...] [-lang ...] <mnemonic...>
electrumnemonic v2 seed [-passphrase ...] [-lang ...] <mnemonic...>
electrumnemonic v2 detect <mnemonic...>
electrumnemonic v2 derive mnemonic [-passphrase ...] [-network ...] [-change] [-count N] [-compressed] [-lang ...] <mnemonic...>
electrumnemonic v2 derive seed [-version ...] [-network ...] [-change] [-count N] [-compressed] <seed-hex>
electrumnemonic v2 derive wif [-version ...] [-network ...] <wif>-network accepts bitcoin, litecoin, dash, ravencoin, bitcoincash, or
bitcoinsv (default bitcoin). -count sets how many addresses to derive
(default 1; ignored by derive wif). -change derives the change (internal)
chain instead of receiving. -compressed (default true) controls WIF /
public-key compression. Dash, Ravencoin, Bitcoin Cash, and Bitcoin SV don't
support native SegWit — use -version standard or -version 2fa when
targeting those networks.
# Generate a new v2 segwit mnemonic (~12 words)
electrumnemonic v2 generate
# Generate a 24-word (264-bit) standard mnemonic in Spanish
electrumnemonic v2 generate -version standard -strength 264 -lang es
# Validate a mnemonic against the segwit version (also checks wordlist)
electrumnemonic v2 validate -version segwit "abandon abandon abandon ... about"
# Derive a seed with a passphrase
electrumnemonic v2 seed -passphrase "my secret" "abandon abandon abandon ... about"
# Detect a mnemonic's seed version
electrumnemonic v2 detect "abandon abandon abandon ... about"
# Derive 5 compressed receiving addresses from a v2 mnemonic
electrumnemonic v2 derive mnemonic -count 5 "abandon abandon abandon ... about"
# Derive 3 change addresses (uncompressed)
electrumnemonic v2 derive mnemonic -change -count 3 -compressed=false "abandon abandon abandon ... about"
# Derive a Litecoin address
electrumnemonic v2 derive mnemonic -network litecoin "abandon abandon abandon ... about"
# Recover the address for a WIF private key
electrumnemonic v2 derive wif -version segwit <wif-private-key>
# Generate a v1 mnemonic and derive addresses
electrumnemonic v1 generate
electrumnemonic v1 derive mnemonic -network bitcoin -count 3 "heartbeat some whole ..."- v1 mnemonics encode 16 bytes of entropy into 12 words using Electrum's original algorithm (each group of 3 words encodes 4 bytes via modular arithmetic against the wordlist size).
- v2 mnemonics encode arbitrary entropy as a base-N number (N = wordlist size) and validate seed type by computing
HMAC-SHA512("Seed version", normalized_mnemonic)and checking that the resulting hex digest starts with the version's prefix. Seeds are then derived via PBKDF2-HMAC-SHA512 (2048 iterations, salt"electrum" + passphrase), matching Electrum's own seed derivation. - Generation skips any phrase that is also a valid BIP-39 mnemonic (same as official Electrum).
- Validation for v2 requires every word to exist in the active wordlist in addition to a matching version prefix.
- Mnemonic normalization follows Electrum's approach: NFKD Unicode normalization, lowercasing, stripping combining marks, and collapsing whitespace.
.
├── cmd/electrumnemonic/ # CLI entrypoint
├── pkg/electrumv1/ # Legacy (pre-2.0) mnemonic + derivation
├── pkg/electrumv2/ # Modern versioned mnemonic + derivation
├── pkg/network/ # Shared network params and Address type
└── wordlist/ # v1 and v2 wordlists (multiple languages for v2)
- tyler-smith/go-bip39 — BIP-39 wordlists (English, Chinese Simplified, Japanese, Portuguese, Spanish) used by the v2 package, and BIP-39 validity checks during mnemonic generation.
- Electrum seed phrase specification
- spesmilo/electrum — mnemonic.py
- spesmilo/electrum — old_mnemonic.py
- hdwallet-io/python-hdwallet — electrum mnemonics
- bitcoinjs/electrum-mnemonic
This code handles cryptographic wallet seed material. Review it carefully, run it in a trusted/offline environment when generating real wallet seeds, and never share generated mnemonics or entropy with anyone.
This project is licensed under the MIT License — see LICENSE for the full text.