A hierarchical deterministic (HD) wallet CLI for Ethereum key management, implementing BIP-39 and BIP-44 standards with enterprise-grade security features.
- BIP-39 Compliant: Complete 2048-word English dictionary with comprehensive validation
- BIP-44 HD Derivation: Hierarchical deterministic key derivation (m/44'/60'/0'/0/index)
- Secure Memory Management: Automatic cleanup of sensitive data with runtime finalizers
- Thread-Safe Operations: Safe for concurrent use with mutex protection
- Input Validation: Comprehensive error handling and mnemonic validation
- Enterprise Security: Secure random generation, proper entropy handling
# Clone the repository
git clone https://github.com/Jasonyou1995/simple-eth-hd-wallet.git
cd simple-eth-hd-wallet
# Build the application
go build -o bin/skms ./cmd/skms
# Make it executable (Unix/Linux/macOS)
chmod +x bin/skms
# Add to PATH (optional)
sudo ln -sf $(pwd)/bin/skms /usr/local/bin/skms# Generate 12-word mnemonic (128-bit entropy)
./bin/skms generate
./bin/skms generate 128
# Generate 15-word mnemonic (160-bit entropy)
./bin/skms generate 160
# Generate 18-word mnemonic (192-bit entropy)
./bin/skms generate 192
# Generate 21-word mnemonic (224-bit entropy)
./bin/skms generate 224
# Generate 24-word mnemonic (256-bit entropy)
./bin/skms generate 256Example Output:
Generating new 128-bit mnemonic phrase...
β
Mnemonic generated successfully!
Mnemonic Phrase:
abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
Entropy: 128 bits
Word Count: 12 words
BIP-39 Compliant: β
β οΈ SECURITY WARNING:
β’ Write down this mnemonic phrase and store it securely offline
β’ Anyone with this phrase can access your funds
β’ Never share it online or store it digitally
β’ This phrase cannot be recovered if lost
# Derive account at index 0 (first account)
./bin/skms derive "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" 0
# Derive account at index 1 (second account)
./bin/skms derive "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" 1
# Derive account at index 5 (sixth account)
./bin/skms derive "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" 5Example Output:
Deriving account at index 0...
β
Account derived successfully!
Account Details:
β’ Index: 0
β’ Derivation Path: m/44'/60'/0'/0/0
β’ Ethereum Address: 0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
β’ Private Key: 0xd1c6b983c2fedb08abb6c137677984004c3172b573cada2633597070c5e182bc
β’ Public Key: 0xb0c135c99bf524101ef59ed8737e6b743f3b6a4a950eb4939e46f71a5576ba7d...
BIP-44 Path Components:
β’ Purpose: 44' (BIP-44)
β’ Coin Type: 60' (Ethereum)
β’ Account: 0' (First account)
β’ Change: 0 (External chain)
β’ Address Index: 0
β οΈ CRITICAL SECURITY WARNING:
β’ Keep your private key secure and never share it
β’ Anyone with the private key can control this address
β’ Consider using hardware wallets for significant funds
# Invalid entropy (will fail)
./bin/skms generate 100
# Output: Error: invalid entropy bits (must be 128, 160, 192, 224, or 256)
# Invalid mnemonic (will fail)
./bin/skms derive "invalid word list test validation" 0
# Output: Error: invalid mnemonic phrase
# Invalid account index (will fail)
./bin/skms derive "valid mnemonic here" abc
# Output: Error: invalid account index (must be a number)Generate a new BIP-39 compliant mnemonic phrase.
Parameters:
entropy(optional): Entropy bits (128, 160, 192, 224, or 256)- Default: 128 bits (12 words)
Examples:
./bin/skms generate # 12 words (128-bit)
./bin/skms generate 128 # 12 words (128-bit)
./bin/skms generate 160 # 15 words (160-bit)
./bin/skms generate 192 # 18 words (192-bit)
./bin/skms generate 224 # 21 words (224-bit)
./bin/skms generate 256 # 24 words (256-bit)Entropy to Word Count Mapping:
| Entropy | Words | Security Level |
|---|---|---|
| 128-bit | 12 | Standard |
| 160-bit | 15 | Enhanced |
| 192-bit | 18 | High |
| 224-bit | 21 | Very High |
| 256-bit | 24 | Maximum |
Derive an Ethereum account from a mnemonic phrase.
Parameters:
mnemonic: BIP-39 compliant mnemonic phrase (12-24 words)index: Account index (0-based, must be a non-negative integer)
Examples:
# Standard usage
./bin/skms derive "word1 word2 ... word12" 0
# Multiple accounts from same mnemonic
./bin/skms derive "word1 word2 ... word12" 0 # First account
./bin/skms derive "word1 word2 ... word12" 1 # Second account
./bin/skms derive "word1 word2 ... word12" 2 # Third account
# Using 24-word mnemonic
./bin/skms derive "word1 word2 ... word24" 0Derivation Path: m/44'/60'/0'/0/{index}
44': Purpose (BIP-44 standard)60': Coin type (Ethereum)0': Account (first account)0: Change (external chain for receiving){index}: Address index
Display help information and usage examples.
./bin/skms help
./bin/skms --help
./bin/skms -hDisplay version information.
./bin/skms version
./bin/skms --version
./bin/skms -v#!/bin/bash
# Generate multiple accounts from a single mnemonic
MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
echo "Generating accounts 0-4..."
for i in {0..4}; do
echo "=== Account $i ==="
./bin/skms derive "$MNEMONIC" $i
echo
done# Test various mnemonic formats
./bin/skms derive "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" 0 # Valid 12-word
./bin/skms derive "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" 0 # Valid 15-word
# These will fail validation:
./bin/skms derive "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon" 0 # 11 words (invalid)
./bin/skms derive "invalid words not in bip39 dictionary test validation check" 0 # Invalid wordsWith jq for JSON processing:
# Extract just the address (requires modification to output JSON)
ADDRESS=$(./bin/skms derive "$MNEMONIC" 0 2>/dev/null | grep "Address:" | cut -d' ' -f3)
echo "Address: $ADDRESS"Environment variable usage:
export WALLET_MNEMONIC="your mnemonic phrase here"
./bin/skms derive "$WALLET_MNEMONIC" 0The project includes comprehensive Go tests covering all wallet functionality:
# Run all tests
go test ./...
# Run wallet tests with verbose output
go test ./internal/wallet -v
# Run specific test functions
go test ./internal/wallet -run TestBIP39WordListInitialization
go test ./internal/wallet -run TestGenerateMnemonic
go test ./internal/wallet -run TestWalletDerivation
# Run benchmarks
go test ./internal/wallet -bench=.
# Test coverage
go test ./internal/wallet -cover
go test ./internal/wallet -coverprofile=coverage.out
go tool cover -html=coverage.outTest Coverage Includes:
- β BIP-39 word list validation (2048 words)
- β Mnemonic generation (all entropy levels)
- β Mnemonic validation (comprehensive edge cases)
- β Wallet creation from mnemonic and seed
- β Account derivation and deterministic generation
- β Private/public key extraction and formatting
- β Address generation and validation
- β Thread safety and concurrent operations
- β Security functions (memory clearing)
- β Error handling and edge cases
# Test all entropy levels
for entropy in 128 160 192 224 256; do
echo "Testing $entropy-bit entropy:"
./bin/skms generate $entropy
echo "---"
done
# Test invalid entropy (should fail)
./bin/skms generate 100 # Invalid
./bin/skms generate 300 # Invalid# Use known test vectors for consistency
TEST_MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
echo "Testing account derivation..."
for i in {0..4}; do
echo "Account $i:"
./bin/skms derive "$TEST_MNEMONIC" $i | grep "Address:"
done# Test invalid mnemonics
./bin/skms derive "too few words" 0 # Invalid word count
./bin/skms derive "invalid words not in dictionary" 0 # Invalid words
./bin/skms derive "" 0 # Empty mnemonic
# Test invalid indices
./bin/skms derive "$TEST_MNEMONIC" -1 # Negative index
./bin/skms derive "$TEST_MNEMONIC" abc # Non-numeric index# Verify deterministic behavior (same mnemonic = same addresses)
MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
echo "First run:"
./bin/skms derive "$MNEMONIC" 0 | grep "Address:"
echo "Second run:"
./bin/skms derive "$MNEMONIC" 0 | grep "Address:"
# Addresses should be identicalFor validation against external tools, use these test vectors:
Test Vector 1:
- Mnemonic:
abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about - Index: 0
- Expected Path:
m/44'/60'/0'/0/0
Test Vector 2:
- Entropy: 128 bits
- Expected: 12-word mnemonic
- All words must be in BIP-39 word list
Verify results using these tools:
-
Ian Coleman's BIP39 Tool: https://iancoleman.io/bip39/
- Set coin to ETH (Ethereum)
- Use derivation path:
m/44'/60'/0'/0 - Compare generated addresses
-
MyEtherWallet (Legacy): https://vintage.myetherwallet.com/
- Import mnemonic phrase
- Compare addresses at same indices
-
MetaMask:
- Import wallet with same mnemonic
- Compare first address
simple-eth-hd-wallet/
βββ cmd/
β βββ skms/ # CLI application entry point
β βββ main.go # Command-line interface
βββ internal/
β βββ wallet/ # Core wallet implementation
β βββ simple_wallet.go # HD wallet with security features
β βββ simple_wallet_test.go # Comprehensive test suite
β βββ bip39_wordlist.go # Complete BIP-39 word list (2048 words)
βββ bin/ # Built binaries (created after build)
βββ docs/ # Additional documentation
β βββ architecture/ # Technical architecture docs
βββ go.mod # Go module definition
βββ README.md # This file
βββ LICENSE.md # MIT license
βββ SECURITY.md # Security guidelines
BIP-39 (Mnemonic Codes):
- β Complete 2048-word English dictionary
- β Proper entropy-to-word mapping (128β12, 160β15, 192β18, 224β21, 256β24)
- β Comprehensive mnemonic validation
- β Checksum validation (basic implementation)
- β Passphrase support via WalletConfig
BIP-44 (Multi-Account Hierarchy):
- β
Standard derivation path:
m/44'/60'/0'/0/{index} - β Purpose: 44' (BIP-44)
- β Coin type: 60' (Ethereum)
- β Account: 0' (first account)
- β Change: 0 (external chain)
- β Address index: configurable
Memory Protection:
- Sensitive data cleared after use
- Runtime finalizers for automatic cleanup
- Secure random number generation with
crypto/rand - Zero-copy operations where possible
Thread Safety:
- Mutex protection for concurrent access
- Read-write locks for optimal performance
- Atomic operations for counters and flags
Input Validation:
- Comprehensive mnemonic validation
- Entropy validation (32-bit alignment)
- Path validation for derivation
- Address format validation
Error Handling:
- Detailed error messages without sensitive data leakage
- Proper error wrapping and context
- Graceful degradation on failures
Core Components:
SimpleWallet: Main wallet implementationAccount: Individual account representationAddress: Ethereum address type with utilitiesDerivationPath: BIP-32 path representation
Key Derivation:
- SHA-256 based derivation (simplified)
- ECDSA key pair generation with P-256 curve
- Deterministic address generation
- Proper private key format handling
Standard Library Only:
crypto/ecdsa: Elliptic curve cryptographycrypto/rand: Secure random number generationcrypto/sha256: Hash functions for derivationencoding/hex: Hexadecimal encoding/decoding- No external dependencies for maximum security
- Use Hardware Wallets: For significant amounts
- Code Audit: Have the code professionally audited
- Test Thoroughly: Verify with multiple tools
- Backup Strategy: Implement proper backup procedures
- Air-Gapped Systems: Generate keys offline when possible
Mnemonic Handling:
- Store mnemonics offline (paper, metal backup)
- Never store mnemonics digitally without encryption
- Use passphrases for additional security
- Verify mnemonics with multiple tools
Private Key Management:
- Never share private keys
- Use environment variables for automation
- Clear private keys from memory after use
- Monitor for private key exposure
Development:
- Use testnet for development
- Implement proper logging (without sensitive data)
- Regular security updates
- Follow principle of least privilege
- Simplified Implementation: Uses basic SHA-256 derivation instead of full BIP-32
- Single Curve: Only supports P-256 (consider secp256k1 for production)
- Basic Checksum: Simplified checksum validation
- Memory Protection: Platform-dependent memory clearing
# Clone repository
git clone https://github.com/yourusername/simple-eth-hd-wallet.git
cd simple-eth-hd-wallet
# Install dependencies (none required)
go mod tidy
# Build for current platform
go build -o bin/skms ./cmd/skms
# Build for multiple platforms
GOOS=linux GOARCH=amd64 go build -o bin/skms-linux-amd64 ./cmd/skms
GOOS=windows GOARCH=amd64 go build -o bin/skms-windows-amd64.exe ./cmd/skms
GOOS=darwin GOARCH=amd64 go build -o bin/skms-darwin-amd64 ./cmd/skms# Format code
go fmt ./...
# Lint code
golangci-lint run
# Vet code
go vet ./...
# Security scan
gosec ./...
# Test coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Add comprehensive tests for new functionality
- Ensure all tests pass (
go test ./...) - Update documentation as needed
- Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Issues: Report bugs and feature requests on GitHub Issues
- Documentation: See
/docsdirectory for detailed technical docs - Security: Report security issues privately to [security contact]
- Community: Join discussions in GitHub Discussions
This project is licensed under the MIT License - see the LICENSE.md file for details.