@btc-vision/transaction
Version:
OPNet transaction library allows you to create and sign transactions for the OPNet network.
460 lines (341 loc) • 14.2 kB
Markdown
# Mnemonic & Wallet Management
## Table of Contents
- [Generating a Mnemonic](#generating-a-mnemonic)
- [Loading Existing Mnemonic](#loading-existing-mnemonic)
- [Deriving Wallets](#deriving-wallets)
- [Unisat Wallet Compatibility](#unisat-wallet-compatibility)
- [Wallet Properties](#wallet-properties)
- [Security Best Practices](#security-best-practices)
- [Advanced Usage](#advanced-usage)
## Generating a Mnemonic
### Basic Generation
Generate a new 12-word mnemonic with quantum support:
```typescript
import { Mnemonic, MnemonicStrength, MLDSASecurityLevel } from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
// Generate with default 12 words and LEVEL2 security (BIP360 RECOMMENDED DEFAULT)
const mnemonic = Mnemonic.generate();
console.log('Mnemonic phrase:', mnemonic.phrase);
console.log('Security Level:', mnemonic.securityLevel); // LEVEL2 (default)
// Output: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
```
### Custom Strength and Security Level
```typescript
// RECOMMENDED: Use LEVEL2 (BIP360 default) for most applications
const recommendedMnemonic = Mnemonic.generate(
MnemonicStrength.MAXIMUM, // 24 words
'', // No passphrase
networks.bitcoin, // Mainnet
MLDSASecurityLevel.LEVEL2 // RECOMMENDED DEFAULT (BIP360)
);
console.log('Words:', recommendedMnemonic.phrase.split(' ').length); // 24
console.log('Security Level:', recommendedMnemonic.securityLevel); // LEVEL2
// OPTIONAL: Use LEVEL5 only for maximum security in high-value applications
const maxSecurityMnemonic = Mnemonic.generate(
MnemonicStrength.MAXIMUM, // 24 words
'', // No passphrase
networks.bitcoin, // Mainnet
MLDSASecurityLevel.LEVEL5 // Maximum quantum security (optional)
);
console.log('Security Level:', maxSecurityMnemonic.securityLevel); // LEVEL5
```
### Available Mnemonic Strengths
```typescript
enum MnemonicStrength {
MINIMUM = 128, // 12 words - Standard
LOW = 160, // 15 words
MEDIUM = 192, // 18 words
HIGH = 224, // 21 words
MAXIMUM = 256 // 24 words - Maximum entropy
}
```
### With Network and Passphrase
```typescript
// Generate for testnet with BIP39 passphrase
const testnetMnemonic = Mnemonic.generate(
MnemonicStrength.MINIMUM, // 12 words
'my-secret-passphrase', // BIP39 passphrase (optional)
networks.testnet, // Testnet network
MLDSASecurityLevel.LEVEL2 // RECOMMENDED DEFAULT (BIP360)
);
```
## Loading Existing Mnemonic
### From Phrase
```typescript
const phrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
const mnemonic = new Mnemonic(
phrase,
'', // Passphrase (use same as generation)
networks.bitcoin, // Network
MLDSASecurityLevel.LEVEL2 // RECOMMENDED DEFAULT (BIP360) - must match original
);
console.log('Network:', mnemonic.network.bech32); // 'bc'
console.log('Security:', mnemonic.securityLevel); // LEVEL2 (BIP360 default)
```
### Validating Mnemonic
```typescript
import * as bip39 from 'bip39';
const phrase = 'abandon abandon abandon...';
// Validate BIP39 mnemonic
if (!bip39.validateMnemonic(phrase)) {
throw new Error('Invalid mnemonic phrase');
}
const mnemonic = new Mnemonic(phrase);
```
## Deriving Wallets
### Single Wallet Derivation
```typescript
const mnemonic = Mnemonic.generate();
// Derive wallet at index 0
const wallet0 = mnemonic.derive(0);
// Derive wallet at index 1
const wallet1 = mnemonic.derive(1);
// Each wallet has both classical and quantum keys
console.log('Classical Public Key:', wallet0.publicKey);
console.log('Quantum Public Key:', wallet0.quantumPublicKeyHex);
```
### Multiple Wallet Derivation
```typescript
// Derive first 5 wallets
const wallets = mnemonic.deriveMultiple(5);
wallets.forEach((wallet, index) => {
console.log(`Wallet ${index}:`);
console.log(' P2TR:', wallet.p2tr);
console.log(' ML-DSA Hash:', wallet.address.toHex());
});
```
### Custom Derivation Path
```typescript
// Custom BIP44/BIP84 path
const customWallet = mnemonic.deriveCustomPath(
"m/84'/0'/0'/0/5", // BIP84 path for account 0, index 5
"m/360'/0'/0'/0/5" // BIP360 quantum path (parallel)
);
console.log('Custom wallet address:', customWallet.p2wpkh);
```
### Unisat Wallet Compatibility
For compatibility with Unisat and other HD wallets, use `deriveUnisat()` which follows standard BIP derivation paths:
```typescript
import { AddressTypes } from '@btc-vision/transaction';
const mnemonic = Mnemonic.generate();
// Derive P2TR (Taproot) - BIP86
const taprootWallet = mnemonic.deriveUnisat(AddressTypes.P2TR, 0);
console.log('Taproot:', taprootWallet.p2tr); // bc1p...
// Derive P2WPKH (Native SegWit) - BIP84
const segwitWallet = mnemonic.deriveUnisat(AddressTypes.P2WPKH, 0);
console.log('Native SegWit:', segwitWallet.p2wpkh); // bc1q...
// Derive P2PKH (Legacy) - BIP44
const legacyWallet = mnemonic.deriveUnisat(AddressTypes.P2PKH, 0);
console.log('Legacy:', legacyWallet.legacy); // 1...
// Derive P2SH (Nested SegWit) - BIP49
const nestedSegwitWallet = mnemonic.deriveUnisat(AddressTypes.P2SH_OR_P2SH_P2WPKH, 0);
console.log('Nested SegWit:', nestedSegwitWallet.segwitLegacy); // 3...
```
#### BIP Standard Mapping
The `deriveUnisat()` method automatically maps address types to BIP standards:
| Address Type | BIP Standard | Path Format | Address Prefix |
|--------------|-------------|-------------|----------------|
| P2TR | BIP86 | `m/86'/0'/account'/change/index` | bc1p... (mainnet) |
| P2WPKH | BIP84 | `m/84'/0'/account'/change/index` | bc1q... (mainnet) |
| P2PKH | BIP44 | `m/44'/0'/account'/change/index` | 1... (mainnet) |
| P2SH | BIP49 | `m/49'/0'/account'/change/index` | 3... (mainnet) |
**Note**: Unisat-compatible paths always use coin type `0` for the purpose field, regardless of network.
#### Accounts and Change Addresses
```typescript
// Main account (account 0), receiving addresses
const receiving0 = mnemonic.deriveUnisat(AddressTypes.P2TR, 0, 0, false);
const receiving1 = mnemonic.deriveUnisat(AddressTypes.P2TR, 1, 0, false);
// Main account (account 0), change addresses
const change0 = mnemonic.deriveUnisat(AddressTypes.P2TR, 0, 0, true);
const change1 = mnemonic.deriveUnisat(AddressTypes.P2TR, 1, 0, true);
// Second account (account 1), receiving addresses
const account1_0 = mnemonic.deriveUnisat(AddressTypes.P2TR, 0, 1, false);
console.log('Receiving 0:', receiving0.p2tr);
console.log('Receiving 1:', receiving1.p2tr);
console.log('Change 0:', change0.p2tr);
console.log('Account 1:', account1_0.p2tr);
```
#### Bulk Derivation
Derive multiple Unisat-compatible wallets at once:
```typescript
// Derive first 5 Taproot addresses
const taprootWallets = mnemonic.deriveMultipleUnisat(
AddressTypes.P2TR, // Address type
5, // Count
0, // Start index
0, // Account
false // Not change addresses
);
taprootWallets.forEach((wallet, i) => {
console.log(`Address ${i}: ${wallet.p2tr}`);
});
// Derive 10 Native SegWit change addresses starting from index 5
const changeWallets = mnemonic.deriveMultipleUnisat(
AddressTypes.P2WPKH, // Native SegWit
10, // Count
5, // Start at index 5
0, // Account 0
true // Change addresses
);
```
#### Quantum Keys with Unisat Derivation
All Unisat-derived wallets include both classical and quantum keys:
```typescript
const wallet = mnemonic.deriveUnisat(AddressTypes.P2TR, 0);
// Classical Taproot address (BIP86)
console.log('Classical P2TR:', wallet.p2tr);
// Quantum ML-DSA keys (BIP360: m/360'/0'/0'/0/0)
console.log('Quantum Public Key:', wallet.quantumPublicKeyHex);
console.log('Security Level:', wallet.securityLevel);
// Both keys are deterministically derived
console.log('Has quantum keypair:', wallet.mldsaKeypair !== undefined); // true
```
## Wallet Properties
### Classical Keys
```typescript
const wallet = mnemonic.derive(0);
// Public keys
console.log('Compressed:', wallet.publicKey); // 33 bytes
console.log('Hex:', wallet.toPublicKeyHex()); // 0x...
console.log('Uncompressed:', wallet.toUncompressedPublicKey()); // 65 bytes
// Private key (handle with care!)
console.log('Private key:', wallet.privateKey); // 32 bytes hex
// Key pair
console.log('EC Keypair:', wallet.keypair); // UniversalSigner
```
### Quantum Keys
```typescript
// ML-DSA keypair
console.log('ML-DSA Keypair:', wallet.mldsaKeypair);
console.log('Security Level:', wallet.securityLevel); // LEVEL2, LEVEL3, or LEVEL5
// Quantum public keys
console.log('Public Key (hex):', wallet.quantumPublicKeyHex);
console.log('Public Key (buffer):', wallet.quantumPublicKey);
console.log('Public Key Size:', wallet.quantumPublicKey.length); // 1312, 1952, or 2592 bytes
```
### Addresses
```typescript
// Classical addresses
console.log('P2TR:', wallet.p2tr); // bc1p...
console.log('P2WPKH:', wallet.p2wpkh); // bc1q...
console.log('Legacy (P2PKH):', wallet.legacy); // 1...
// Quantum address
console.log('Public Key:', wallet.address.toHex());
// Address object
const address = wallet.address;
console.log('ML-DSA Hash:', address.toHex()); // SHA256 of quantum key
console.log('Classical Key:', address.tweakedToHex()); // Classical public key
```
## Security Best Practices
### ⚠️ Mnemonic Security
```typescript
const mnemonic = Mnemonic.generate();
// ✅ GOOD: Store securely
// - Hardware wallets
// - Encrypted storage
// - Paper backup in secure location
// ❌ BAD: Don't do this!
// - console.log(mnemonic.phrase) // Never log in production
// - Save to file unencrypted
// - Transmit over network
// - Store in version control
// Access sensitive data only when needed
const phrase = mnemonic.phrase; // ⚠️ Warning: Highly sensitive
const seed = mnemonic.seed; // ⚠️ Warning: Highly sensitive
```
### Passphrase Protection
```typescript
// Add extra security layer with passphrase
const passphrase = 'my-very-strong-passphrase-12345';
const mnemonic = Mnemonic.generate(
MnemonicStrength.MAXIMUM, // 24 words
passphrase, // Required to recover wallet
networks.bitcoin, // Mainnet
MLDSASecurityLevel.LEVEL3 // Security level
);
// ⚠️ IMPORTANT: You need BOTH mnemonic AND passphrase to recover!
// Losing either means permanent loss of funds
```
### Network Awareness
```typescript
// Different networks generate different keys!
const mainnetMnemonic = new Mnemonic(phrase, '', networks.bitcoin);
const testnetMnemonic = new Mnemonic(phrase, '', networks.testnet);
const mainnetWallet = mainnetMnemonic.derive(0);
const testnetWallet = testnetMnemonic.derive(0);
// These will be DIFFERENT addresses even with same mnemonic
console.log('Mainnet:', mainnetWallet.p2tr); // bc1p...
console.log('Testnet:', testnetWallet.p2tr); // tb1p...
```
## Advanced Usage
### Accessing Root Keys
```typescript
const mnemonic = Mnemonic.generate();
// Classical BIP32 root
const classicalRoot = mnemonic.classicalRoot;
console.log('Classical xpub:', classicalRoot.toBase58());
// Quantum BIP32 root
const quantumRoot = mnemonic.quantumRoot;
console.log('Quantum key size:', quantumRoot.publicKey.length);
```
### Chain Codes
```typescript
const mnemonic = Mnemonic.generate();
const wallet = mnemonic.derive(0);
import { toHex } from '@btc-vision/bitcoin';
// Chain codes for key derivation
console.log('Classical chain code:', wallet.keypair.chainCode ? toHex(wallet.keypair.chainCode) : undefined);
console.log('Quantum chain code:', toHex(wallet.mldsaKeypair.chainCode));
```
### Deterministic Derivation
```typescript
// Same mnemonic always generates same wallets
const mnemonic1 = new Mnemonic('abandon abandon abandon...', '');
const mnemonic2 = new Mnemonic('abandon abandon abandon...', '');
const wallet1 = mnemonic1.derive(0);
const wallet2 = mnemonic2.derive(0);
console.log(wallet1.p2tr === wallet2.p2tr); // true - deterministic!
```
## Complete Example
```typescript
import {
AddressTypes,
MLDSASecurityLevel,
Mnemonic,
MnemonicStrength,
} from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';
// Step 1: Generate mnemonic
console.log('Generating quantum-resistant wallet...');
const mnemonic = Mnemonic.generate(
MnemonicStrength.MAXIMUM, // 24 words
'', // BIP39 passphrase
networks.regtest, // Network
MLDSASecurityLevel.LEVEL2, // Security level
);
// Step 2: Securely store mnemonic phrase
const phrase = mnemonic.phrase;
console.log('⚠️ IMPORTANT: Backup these 24 words securely:');
console.log(phrase);
// Step 3: Derive wallets
const wallet = mnemonic.derive(0);
const walletUnisat = mnemonic.deriveUnisat(AddressTypes.P2TR, 0);
console.log('\nDerived Wallets:');
console.log('Classical Wallet (Unisat):');
console.log(' P2TR Address:', walletUnisat.p2tr);
console.log(' P2WPKH Address:', walletUnisat.p2wpkh);
console.log('\nQuantum Address:');
console.log('Public Key:', wallet.address.toHex());
// Step 5: Display keys (for demonstration only!)
console.log('\nKey Information:');
console.log('Classical Public Key:', wallet.toPublicKeyHex());
console.log('Quantum Public Key:', wallet.quantumPublicKeyHex);
console.log('Security Level:', wallet.securityLevel);
// Step 4: Get addresses
console.log('\nClassical Addresses:');
console.log('P2TR:', wallet.p2tr);
console.log('P2WPKH:', wallet.p2wpkh);
```
## Next Steps
- [Address Generation](./03-address-generation.md) - Generate classical and quantum addresses
- [Message Signing](./04-message-signing.md) - Sign messages with ML-DSA