UNPKG

@btc-vision/transaction

Version:

OPNet transaction library allows you to create and sign transactions for the OPNet network.

381 lines (284 loc) 11.7 kB
# Address Generation Guide ## Table of Contents - [Address Types Overview](#address-types-overview) - [P2OP Addresses](#p2op-addresses) - [Classical Addresses](#classical-addresses) - [Address Class Usage](#address-class-usage) - [Network Support](#network-support) - [Address Comparison](#address-comparison) ## Address Types Overview OPNet supports multiple address types for different use cases: | Address Type | Format | Use Case | Quantum Support | |-------------|--------|----------|----------------| | **P2OP** | bc1s... (v16) | OPNet contract addresses | ✅ Quantum (contracts only) | | **P2MR** | bc1z... (v2) | Quantum-safe user wallets (BIP 360) | ✅ Quantum | | **P2QRH** | TBD | Quantum-resistant hash-based addresses | ✅ Quantum (NOT IMPLEMENTED, separate BIP) | | **P2TR** | bc1p... (v1) | Taproot, privacy, efficiency | ❌ Classical | | **P2WPKH** | bc1q... (v0) | SegWit, standard Bitcoin | ❌ Classical | | **P2PKH** | 1... | Legacy Bitcoin | ❌ Classical | | **P2SH** | 3... | Script hash, multi-sig | ❌ Classical | | **P2WDA** | bc1q... (P2WSH) | Witness data authentication | ❌ Classical | ## P2OP Addresses ### What is P2OP? **P2OP (Pay-to-OPNet)** is an address format for OPNet contract addresses: - Uses **witness version 16** (OP_16) - Encoded in **Bech32m format** - Encodes the **quantum address** (SHA256 hash of ML-DSA public key) from `address.toHex()` - Used exclusively for contract addresses on OPNet - **Supports quantum** for contracts only The quantum address (`address.toHex()`) is the user's universal public key - a 32-byte hash that can be encoded in various formats like P2OP. > **Note:** For quantum-safe user wallet outputs, use **P2MR** (Pay-to-Merkle-Root, BIP 360) via the `useP2MR` flag on transaction builders. P2MR eliminates the quantum-vulnerable key-path spend by committing directly to a Merkle root. P2OP is used exclusively for contract addresses. **P2QRH** is a separate, unrelated BIP proposal that is not yet implemented. ## Classical Addresses ### P2TR (Taproot) ```typescript const wallet = mnemonic.derive(0); // Mainnet Taproot const p2trMainnet = wallet.p2tr; console.log('P2TR Mainnet:', p2trMainnet); // Output: bc1p... // Testnet Taproot const p2trTestnet = wallet.address.p2tr(networks.testnet); console.log('P2TR Testnet:', p2trTestnet); // Output: tb1p... // Regtest Taproot const p2trRegtest = wallet.address.p2tr(networks.regtest); console.log('P2TR Regtest:', p2trRegtest); // Output: bcrt1p... ``` ### P2WPKH (SegWit) ```typescript // Mainnet SegWit const p2wpkhMainnet = wallet.p2wpkh; console.log('P2WPKH Mainnet:', p2wpkhMainnet); // Output: bc1q... // Testnet SegWit const p2wpkhTestnet = wallet.address.p2wpkh(networks.testnet); console.log('P2WPKH Testnet:', p2wpkhTestnet); // Output: tb1q... ``` ### P2PKH (Legacy) ```typescript // Mainnet Legacy const p2pkhMainnet = wallet.p2pkh; console.log('P2PKH Mainnet:', p2pkhMainnet); // Output: 1... // Testnet Legacy const p2pkhTestnet = wallet.address.p2pkh(networks.testnet); console.log('P2PKH Testnet:', p2pkhTestnet); // Output: m... or n... ``` ### P2SH-P2WPKH (Wrapped SegWit) ```typescript // Mainnet Wrapped SegWit const p2shMainnet = wallet.address.p2shp2wpkh(networks.bitcoin); console.log('P2SH-P2WPKH Mainnet:', p2shMainnet); // Output: 3... // Testnet Wrapped SegWit const p2shTestnet = wallet.address.p2shp2wpkh(networks.testnet); console.log('P2SH-P2WPKH Testnet:', p2shTestnet); // Output: 2... ``` ### P2WDA (Witness Data Authentication) ```typescript // P2WDA with authenticated data fields const p2wdaAddress = wallet.address.p2wda(networks.bitcoin); console.log('P2WDA:', p2wdaAddress); // Output: P2WSH address (bc1q...) with special witness script ``` ## Address Class Usage ### Creating Addresses Directly ```typescript import { Address } from '@btc-vision/transaction'; import { networks } from '@btc-vision/bitcoin'; import { fromHex } from '@btc-vision/bitcoin'; // From ML-DSA public key hash and classical public key const mldsaHash = new Uint8Array(32).fill(0x01); // SHA256 of ML-DSA public key const classicalKey = fromHex('02...'); // 33-byte compressed key const address = new Address(mldsaHash, classicalKey); // Generate addresses const p2op = address.p2op(networks.bitcoin); const p2tr = address.p2tr(networks.bitcoin); ``` ### From String ```typescript // Create address from hex strings const address = Address.fromString( '0xabcdef1234567890...', // ML-DSA public key hash (32 bytes hex) '0x02...' // Classical public key (33 bytes hex) ); ``` ### Dead Address ```typescript // Special "dead" address (all zeros) const deadAddress = Address.dead(); console.log('Dead address:', deadAddress.toHex()); // Output: 0x0000000000000000000000000000000000000000000000000000000000000000 ``` ### Address Properties ```typescript const address = wallet.address; // Quantum address (SHA256 hash of ML-DSA public key) - Universal public key console.log('Quantum address:', address.toHex()); console.log('Quantum address bytes:', address.toBuffer()); // Classical public key console.log('Classical key (hex):', address.tweakedToHex()); console.log('Classical key (bytes):', address.tweakedPublicKeyToBuffer()); // Original keys console.log('Full ML-DSA public key:', address.mldsaPublicKey); // 1312-2592 bytes console.log('Original classical key:', address.originalPublicKey); ``` ## Network Support ### Mainnet ```typescript import { networks } from '@btc-vision/bitcoin'; const wallet = mnemonic.derive(0); // All mainnet addresses console.log('P2OP:', wallet.address.p2op(networks.bitcoin)); // bc1s... console.log('P2TR:', wallet.address.p2tr(networks.bitcoin)); // bc1p... console.log('P2WPKH:', wallet.address.p2wpkh(networks.bitcoin)); // bc1q... console.log('P2PKH:', wallet.address.p2pkh(networks.bitcoin)); // 1... ``` ### Testnet ```typescript // Testnet with different prefixes const mnemonic = Mnemonic.generate( undefined, // Default strength (24 words) '', // No passphrase networks.testnet, // Testnet network MLDSASecurityLevel.LEVEL2 // Security level ); const wallet = mnemonic.derive(0); console.log('P2OP:', wallet.address.p2op(networks.testnet)); // tb1s... console.log('P2TR:', wallet.address.p2tr(networks.testnet)); // tb1p... console.log('P2WPKH:', wallet.address.p2wpkh(networks.testnet)); // tb1q... console.log('P2PKH:', wallet.address.p2pkh(networks.testnet)); // m... or n... ``` ### Regtest ```typescript // Regtest for local development const regtestMnemonic = Mnemonic.generate( undefined, // Default strength (24 words) '', // No passphrase networks.regtest, // Regtest network MLDSASecurityLevel.LEVEL2 // Security level ); const wallet = regtestMnemonic.derive(0); console.log('P2OP:', wallet.address.p2op(networks.regtest)); // bcrt1s... console.log('P2TR:', wallet.address.p2tr(networks.regtest)); // bcrt1p... ``` ## Address Comparison ### Equality ```typescript const wallet1 = mnemonic.derive(0); const wallet2 = mnemonic.derive(0); const wallet3 = mnemonic.derive(1); const addr1 = wallet1.address; const addr2 = wallet2.address; const addr3 = wallet3.address; // Same derivation index = same address console.log(addr1.equals(addr2)); // true // Different index = different address console.log(addr1.equals(addr3)); // false ``` ### Ordering ```typescript const addresses = [ mnemonic.derive(5).address, mnemonic.derive(2).address, mnemonic.derive(8).address, mnemonic.derive(1).address, ]; // Less than comparison console.log(addresses[0].lessThan(addresses[1])); // Greater than comparison console.log(addresses[0].greaterThan(addresses[1])); // Sort addresses addresses.sort((a, b) => { if (a.lessThan(b)) return -1; if (a.greaterThan(b)) return 1; return 0; }); ``` ## P2MR Addresses (BIP 360) P2MR (Pay-to-Merkle-Root) is a quantum-safe SegWit version 2 output type. Unlike P2TR, P2MR commits directly to a Merkle root without an internal public key, eliminating the quantum-vulnerable key-path spend. ### P2MR in Transactions All transaction builders support P2MR via the `useP2MR` flag: ```typescript // Deploy a contract using P2MR const result = await factory.signDeployment({ // ... other params useP2MR: true, // Use P2MR instead of P2TR }); // Script address starts with bc1z... instead of bc1p... ``` ### P2MR Multi-Signature ```typescript import { P2MR_MS } from '@btc-vision/transaction'; const multisigAddress = P2MR_MS.generateMultiSigAddress( [pubkey1, pubkey2, pubkey3], 2, // 2-of-3 networks.bitcoin, ); console.log('P2MR Multisig:', multisigAddress); // Output: bc1z... ``` ### P2MR CSV Time-Locked ```typescript const csvP2MR = wallet.address.toCSVP2MR(144, networks.bitcoin); console.log('P2MR CSV (144 blocks):', csvP2MR); // Output: bc1z... ``` ## Time-Locked Addresses (CSV) ### CheckSequenceVerify Addresses ```typescript // Create time-locked address (100 blocks) const duration = 100; const csvAddress = wallet.address.toCSV(duration, networks.bitcoin); console.log('CSV Address (100 blocks):', csvAddress); // Different durations const addr1Day = wallet.address.toCSV(144, networks.bitcoin); // ~1 day const addr1Week = wallet.address.toCSV(1008, networks.bitcoin); // ~1 week const addr1Month = wallet.address.toCSV(4320, networks.bitcoin); // ~1 month // Valid range: 1 to 65535 blocks const minLock = wallet.address.toCSV(1, networks.bitcoin); const maxLock = wallet.address.toCSV(65535, networks.bitcoin); ``` ### P2MR CSV Time-Locked ```typescript // Create a P2MR time-locked address (quantum-safe CSV) const csvP2MR = wallet.address.toCSVP2MR(144, networks.bitcoin); console.log('P2MR CSV (1 day):', csvP2MR); // Output: bc1z... (no key-path, quantum-safe) ``` ## Complete Example ```typescript import { Mnemonic, MLDSASecurityLevel } from '@btc-vision/transaction'; import { networks } from '@btc-vision/bitcoin'; // Generate wallet with ML-DSA support const mnemonic = Mnemonic.generate( undefined, // Default strength (24 words) '', // No passphrase networks.bitcoin, // Mainnet MLDSASecurityLevel.LEVEL2 // Security level ); const wallet = mnemonic.derive(0); const address = wallet.address; console.log('=== Universal Public Key (Quantum Address) ==='); console.log('Quantum Address:', address.toHex()); // SHA256 hash of ML-DSA public key console.log('ML-DSA Key Size:', address.mldsaPublicKey?.length, 'bytes'); console.log('\n=== P2OP Address (Contract Address) ==='); console.log('P2OP:', address.p2op(networks.bitcoin)); // Encoded form of quantum address console.log('\n=== Classical Addresses ==='); console.log('P2TR (Taproot):', address.p2tr(networks.bitcoin)); console.log('P2WPKH (SegWit):', address.p2wpkh(networks.bitcoin)); console.log('P2PKH (Legacy):', address.p2pkh(networks.bitcoin)); console.log('P2SH-P2WPKH:', address.p2shp2wpkh(networks.bitcoin)); console.log('\n=== Testnet Addresses ==='); console.log('P2OP:', address.p2op(networks.testnet)); console.log('P2TR:', address.p2tr(networks.testnet)); console.log('\n=== Time-Locked Address ==='); console.log('CSV (100 blocks):', address.toCSV(100, networks.bitcoin)); ``` ## Next Steps - [Message Signing](./04-message-signing.md) - Sign messages with ML-DSA and Schnorr - [Address Verification](./05-address-verification.md) - Validate addresses and keys