Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mnemonic Generator

中文文档

A Rust command-line tool for generating, importing, encrypting, and exporting BIP39 wallet material.

The keystore stores the BIP39 entropy inside an encrypted JSON document. Mnemonic words are not stored in plaintext. After successful authentication, the mnemonic can be printed directly to the console, and derived mainnet addresses can be exported as a separate JSON document.

Features

  • Rust CLI application.
  • BIP39 English mnemonic support.
  • Generate cryptographically secure entropy using the operating system CSPRNG.
  • Import an existing BIP39 mnemonic.
  • Import hexadecimal entropy.
  • Optional entropy mixing with an additional file:
    • SHA-256 is calculated over the file contents.
    • HKDF-SHA256 derives the final entropy.
    • The auxiliary file is never the only entropy source.
    • Files larger than 16 MiB are rejected.
  • BIP39 passphrase support, including an intentionally empty passphrase.
  • Password-protected JSON keystore:
    • Scrypt for password-based key derivation.
    • AES-256-GCM for authenticated encryption.
    • Independent salt for the BIP39 passphrase verifier.
  • Mainnet address derivation for:
    • Bitcoin Legacy P2PKH.
    • Bitcoin Nested SegWit P2SH-P2WPKH.
    • Bitcoin Native SegWit P2WPKH.
    • Bitcoin Taproot P2TR.
    • Ethereum Mainnet, with chain_id = 1.
    • Tron Mainnet.
    • Solana Mainnet using SLIP-0010 Ed25519.
  • Address selection using --chains and --bitcoin-version; Bitcoin defaults to Native SegWit only.
  • Address derivation by a single index or an inclusive index range.
  • Mnemonic import from a command-line argument or stdin.
  • Mnemonic export directly to the console; no mnemonic output file is created.
  • Address export as plain text to the console or as a protected JSON file.
  • Secure output file permissions on Unix platforms.

Security Model

The project uses two different secrets:

  1. Encryption password

    • Protects the JSON keystore.
    • Must not be empty.
    • Is processed with Scrypt and used to derive the AES-256-GCM key.
  2. BIP39 passphrase

    • Is part of the standard BIP39 seed derivation process.
    • Changes all derived wallet addresses.
    • May be empty.
    • Is verified using a separate Scrypt verifier.
    • Is not stored in the JSON file.

The BIP39 passphrase is passed to the standard BIP39 PBKDF2-HMAC-SHA512 derivation. The Scrypt-derived verifier is only used to validate the passphrase and must not replace the original passphrase during BIP39 derivation.

The current Scrypt parameters are:

N      = 32768
r      = 8
p      = 1
dkLen  = 32 bytes

The JSON keystore uses AES-256-GCM with a 12-byte nonce and a 16-byte authentication tag.

Requirements

Rust 1.88 or newer.

  • Cargo.

Build

cargo build --release

The compiled binary is located at:

target/release/mnemonicgen

You can also run the application through Cargo:

cargo run --release -- <command> [options]

Commands

mnemonicgen generate
mnemonicgen import-mnemonic
mnemonicgen import-entropy
mnemonicgen export-mnemonic
mnemonicgen export-addresses

Display general help:

mnemonicgen --help

Display command-specific help:

mnemonicgen generate --help
mnemonicgen import-mnemonic --help
mnemonicgen import-entropy --help
mnemonicgen export-mnemonic --help
mnemonicgen export-addresses --help

Password and Passphrase Input

The application does not accept passwords through ordinary command-line arguments.

Interactive input

By default, passwords are read interactively without echoing them to the terminal:

mnemonicgen generate --output wallet.json

During creation or import:

  1. The encryption password is requested twice.
  2. The BIP39 passphrase is requested once.
  3. The BIP39 passphrase may be empty. An empty line means an empty passphrase.

Environment variables

The following environment variables are supported:

MNEMONICGEN_PASSWORD
MNEMONICGEN_PASSPHRASE

Example:

MNEMONICGEN_PASSWORD='correct horse battery staple' \\
MNEMONICGEN_PASSPHRASE='wallet passphrase' \\
cargo run --release -- generate --output wallet.json

Do not use environment variables for long-lived secrets on shared systems. Environment variables may be visible through process inspection, shell configuration, CI logs, or debugging tools.

stdin input

Use --password-stdin to read the encryption password from stdin. During keystore creation, stdin must contain two identical non-empty lines:

printf 'correct horse battery staple\\ncorrect horse battery staple\\n' | \\
cargo run --release -- generate \\
  --chains ethereum \\
  --password-stdin \\
  --output wallet.json

Use --passphrase-stdin to read the BIP39 passphrase from stdin:

printf 'wallet passphrase\\n' | \\
MNEMONICGEN_PASSWORD='correct horse battery staple' \\
cargo run --release -- generate \\
  --chains ethereum \\
  --passphrase-stdin \\
  --output wallet.json

Only one secret may be read from stdin in a single command. Mnemonic input, encryption password input, and BIP39 passphrase input cannot all use stdin at the same time.

Generate a Keystore

Generate 256-bit entropy (the default) and create a keystore with the default address set:

mnemonicgen generate --output wallet.json

The default chain selection is:

  • Bitcoin Native SegWit.
  • Ethereum Mainnet.
  • Tron Mainnet.
  • Solana Mainnet.

The default Bitcoin selection includes Native SegWit only. Other Bitcoin address types can be selected explicitly with --bitcoin-version.

Specify the entropy size:

mnemonicgen generate \
  --entropy-bits 128 \
  --output wallet.json

Supported entropy sizes are:

128, 160, 192, 224, 256 bits

You can specify the size using mnemonic word count instead:

mnemonicgen generate \\
  --entropy-len 12 \\
  --output wallet.json

Allowed --entropy-len values are 12, 15, 18, 21, and 24, mapping to 128, 160, 192, 224, and 256 bits. The default is --entropy-len 24. --entropy-bits and --entropy-len are mutually exclusive.

Select chains

--chains accepts a comma-separated list:

mnemonicgen generate \
  --chains ethereum,tron \
  --output wallet.json

Allowed values are:

bitcoin, ethereum, tron, solana

If bitcoin is not selected, passing --bitcoin-version is an error.

Select Bitcoin address types

Select one Bitcoin address type:

mnemonicgen generate \
  --chains bitcoin \
  --bitcoin-version native-segwit \
  --output wallet.json

Select multiple types:

mnemonicgen generate \
  --chains bitcoin \
  --bitcoin-version legacy,native-segwit,taproot \
  --output wallet.json

Allowed values are:

legacy
nested-segwit
native-segwit
taproot

Account and address index

The default account is 0. A single account can be selected with --account; valid account values are 0..=100.

The current CLI default index range is 0. A single index can be selected:

mnemonicgen generate \
  --index-range 2 \
  --output wallet.json

An inclusive range can also be selected:

mnemonicgen generate \
  --index-range 0..=2 \
  --output wallet.json

Valid indexes are between 0 and 100. The same index selection is applied to all selected chains. For Bitcoin, the project index follows MetaMask's account-selection model: it is used as the hardened account component and the receive address index is fixed at 0. Thus Bitcoin index 1 uses m/84'/0'/1'/0/0 for Native SegWit. Solana follows MetaMask's rule: the current index is used as groupIndex in m/44'/501'/index'/0'; the final hardened component is always 0', and --account does not affect Solana derivation. Bitcoin change addresses are not supported; Bitcoin paths use change 0.

Auxiliary entropy file

An auxiliary file can be included in entropy derivation:

mnemonicgen generate \
  --entropy-file auxiliary.bin \
  --output wallet.json

The primary entropy still comes from the CSPRNG. The auxiliary file cannot be used as the only entropy source.

Import a Mnemonic

Import a mnemonic supplied as a command-line value:

mnemonicgen import-mnemonic \
  --mnemonic "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" \
  --chains ethereum \
  --output wallet.json

The mnemonic is validated against the BIP39 English word list and checksum. The mnemonic itself is not saved in plaintext; its entropy is extracted and encrypted in the keystore.

For better privacy, read the mnemonic from stdin:

printf '%s\\n' \\
  'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' | \\
MNEMONICGEN_PASSWORD='correct horse battery staple' \\
MNEMONICGEN_PASSPHRASE='' \\
cargo run --release -- import-mnemonic \\
  --stdin \\
  --chains ethereum \\
  --output wallet.json

--mnemonic and --stdin are mutually exclusive. If neither is specified, the program interactively prompts for the mnemonic without echoing it to the terminal. --output remains required because it is the destination for the encrypted keystore, not a mnemonic input option.

Import Hexadecimal Entropy

Import valid BIP39 entropy as hexadecimal text:

mnemonicgen import-entropy \
  --entropy 00000000000000000000000000000000 \
  --chains ethereum \
  --output wallet.json

The entropy must contain an even number of hexadecimal characters and must be 128, 160, 192, 224, or 256 bits long.

Export a Mnemonic

export-mnemonic requires only the encryption password. It decrypts the Entropy and prints the mnemonic directly to the console; it does not request or verify the BIP39 passphrase because no addresses are derived. Stored address records are not used to authenticate or unlock the keystore:

MNEMONICGEN_PASSWORD='correct horse battery staple' \\\\ 
cargo run --release -- export-mnemonic \\\\
  --input wallet.json

No --output option is accepted for this command. The program intentionally does not create a plaintext mnemonic file.

Be aware that console output can still be captured by terminal scrollback, shell logging, screen recording, or command redirection. Avoid redirecting the output to a file unless you explicitly understand the risk.

Export Addresses

export-addresses requires the encryption password and BIP39 passphrase. By default, it uses Native SegWit for Bitcoin and inherits the chain selection, account, and index range stored in the keystore. Other Bitcoin address types must be selected explicitly with --bitcoin-version.

The following options can override the export selection without modifying the original keystore:

--account ACCOUNT
--index-range INDEX or START..=END
--chains bitcoin,ethereum,tron,solana
--bitcoin-version legacy,nested-segwit,native-segwit,taproot

Without --output, verified addresses are printed as plain text, one record per line:

MNEMONICGEN_PASSWORD='correct horse battery staple' \\
MNEMONICGEN_PASSPHRASE='wallet passphrase' \\
cargo run --release -- export-addresses \\
  --input wallet.json \\
  --chains ethereum \\
  --index-range 0..=2

Example output:

ethereum account index=0 path=m/44'/60'/0'/0/0 address=0x...

To export the verified addresses as JSON, specify --output:

MNEMONICGEN_PASSWORD='correct horse battery staple' \\
MNEMONICGEN_PASSPHRASE='wallet passphrase' \\
cargo run --release -- export-addresses \\
  --input wallet.json \\
  --output addresses.json

The exported document contains only:

  • schema_version.
  • generator_version.
  • The verified address records.

It does not contain entropy, mnemonic words, passphrase, seed, or private keys. Existing files are not overwritten unless --force is supplied. Using --force without --output is an error. A selection that produces no addresses is also an error.

Keystore Structure

A keystore contains versioned metadata, encrypted cryptographic material, and plaintext public address records. A simplified structure is:

{
  "version": 2,
  "schema_version": 2,
  "generator_version": "0.1.0",
  "type": "bip39-entropy-keystore",
  "crypto": {
    "kdf": "scrypt",
    "kdfparams": {
      "n": 32768,
      "r": 8,
      "p": 1,
      "dklen": 32,
      "salt": "<lowercase-hex>"
    },
    "cipher": "aes-256-gcm",
    "cipherparams": {
      "nonce": "<lowercase-hex>"
    },
    "ciphertext": "<lowercase-hex>",
    "tag": "<lowercase-hex>"
  },
  "metadata": {
    "language": "english",
    "entropy_bits": 256,
    "entropy_source": "csprng",
    "entropy_file_used": false,
    "created_at": "<RFC3339>",
    "derivation_version": 1,
    "chains": ["bitcoin", "ethereum", "tron", "solana"],
    "bitcoin_versions": ["nativesegwit"],
    "index_range": "0",
    "account": 0
  },
  "addresses": []
}

Addresses are plaintext because they are public information. Entropy and the passphrase verifier are inside the authenticated encrypted payload.

Address Derivation Paths

The application currently derives mainnet addresses using these paths:

Network Derivation path
Bitcoin Legacy m/44'/0'/index'/0/0
Bitcoin Nested SegWit m/49'/0'/index'/0/0
Bitcoin Native SegWit m/84'/0'/index'/0/0
Bitcoin Taproot m/86'/0'/index'/0/0
Ethereum Mainnet m/44'/60'/account'/0/index
Tron Mainnet m/44'/195'/account'/0/index
Solana Mainnet m/44'/501'/index'/0'

All supported networks are mainnet-only. Bitcoin follows MetaMask's account model: index selects the hardened account component and the receive address index is fixed at 0. Ethereum addresses use chain_id = 1. Solana uses SLIP-0010 Ed25519 with MetaMask's path rule: index is groupIndex and the final hardened component is fixed at 0'.

File Safety

  • Output files are created with restrictive permissions on Unix platforms (0600).
  • Existing files are not overwritten by default.
  • Use --force only when intentionally replacing an existing keystore or address file.
  • Do not commit wallet JSON files, mnemonic files, entropy files, or address exports containing sensitive operational data.
  • Keep encryption passwords and passphrases out of shell history whenever possible.
  • Never log entropy, mnemonic words, passwords, passphrases, seeds, or private keys.

Disclaimer

This software is provided for informational and development purposes only, without warranties of any kind. It is not financial, investment, legal, or security advice, and it should not be relied upon as a substitute for professional review or an independently audited wallet implementation. Cryptocurrency operations involve substantial risks, including permanent loss of funds, incorrect address derivation, software defects, compromised devices, password or passphrase loss, and accidental disclosure of sensitive data. You are solely responsible for verifying the generated addresses and all cryptographic outputs, protecting your passwords, passphrases, entropy, and mnemonic words, and determining whether this software is appropriate for your use. The authors and contributors are not responsible for any loss, damage, or funds lost through the use or misuse of this software.

Desktop GUI

The repository also contains a local Tauri v2 desktop GUI in crates/gui. It uses the shared Rust kernel crate for all cryptography, BIP39 processing, Keystore handling, and address derivation; it never launches the CLI as a subprocess.

The GUI currently targets macOS first and provides:

  • a shared Create / Import wizard for generated entropy and mnemonic import;
  • encrypted Keystore creation with chain, Bitcoin address type, account, and index configuration;
  • Keystore inspection and temporary mnemonic reveal;
  • address derivation and public address JSON export;
  • an About & Safety page.

GUI requirements

Rust 1.88 or newer and Cargo;

  • Node.js 22 LTS;
  • pnpm 10.12.1;
  • macOS for the primary desktop build and acceptance workflow.

Install frontend dependencies and run the frontend checks:

cd crates/gui/frontend
pnpm install
pnpm typecheck
pnpm test
pnpm build

Run the Tauri development application from the repository root:

cargo tauri dev --manifest-path crates/gui/tauri.conf.json

Build an unsigned macOS application bundle:

cargo tauri build --debug --bundles app --no-sign

Build an unsigned macOS DMG without Finder automation:

./scripts/bundle_dmg.sh --debug

The script uses macOS hdiutil directly, so it does not require Finder Automation permission. The application bundle is written under target/debug/bundle/macos/, and the DMG is written under target/debug/bundle/dmg/. GUI secrets are kept only for the active operation, are not stored in browser storage, and are cleared after the configured timeout or when leaving the relevant view. The GUI does not export mnemonic words to a file.

Development

Format the code:

cargo fmt

Run static checks:

cargo clippy --all-targets --all-features -- -D warnings

Run tests:

cargo test

The project currently includes tests for:

  • BIP39 entropy and mnemonic round trips.
  • Index range validation.
  • Scrypt and AES-256-GCM encryption/decryption.
  • Tamper detection.
  • Bitcoin, Ethereum, Tron, and Solana address derivation.

License

This project is licensed under the MIT License.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages