UNPKG

@btc-vision/transaction

Version:

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

310 lines (231 loc) 10.8 kB
# Address Verification Guide ## Table of Contents - [ML-DSA Public Key Validation](#ml-dsa-public-key-validation) - [Address Type Detection](#address-type-detection) - [Classical Address Validation](#classical-address-validation) - [Complete Validation Example](#complete-validation-example) ## ML-DSA Public Key Validation ### Validating ML-DSA Public Keys The `AddressVerificator` provides methods to validate ML-DSA public keys and determine their security level: ```typescript import { AddressVerificator, MLDSASecurityLevel } from '@btc-vision/transaction'; // Valid ML-DSA-44 public key (1312 bytes) const level2Key = new Uint8Array(1312); const level2Check = AddressVerificator.isValidMLDSAPublicKey(level2Key); console.log('LEVEL2 valid:', level2Check); // MLDSASecurityLevel.LEVEL2 // Valid ML-DSA-65 public key (1952 bytes) const level3Key = new Uint8Array(1952); const level3Check = AddressVerificator.isValidMLDSAPublicKey(level3Key); console.log('LEVEL3 valid:', level3Check); // MLDSASecurityLevel.LEVEL3 // Valid ML-DSA-87 public key (2592 bytes) const level5Key = new Uint8Array(2592); const level5Check = AddressVerificator.isValidMLDSAPublicKey(level5Key); console.log('LEVEL5 valid:', level5Check); // MLDSASecurityLevel.LEVEL5 // Invalid length const invalidKey = new Uint8Array(1000); const invalidCheck = AddressVerificator.isValidMLDSAPublicKey(invalidKey); console.log('Invalid:', invalidCheck); // null ``` ### Input Format Support Validation supports multiple input formats: ```typescript import { AddressVerificator, MLDSASecurityLevel } from '@btc-vision/transaction'; // Hex string (with 0x prefix) const hexWith0x = '0x' + 'a'.repeat(2624); // 1312 bytes in hex const check1 = AddressVerificator.isValidMLDSAPublicKey(hexWith0x); console.log('Hex with 0x:', check1); // MLDSASecurityLevel.LEVEL2 // Hex string (without 0x prefix) const hexWithout0x = 'a'.repeat(2624); const check2 = AddressVerificator.isValidMLDSAPublicKey(hexWithout0x); console.log('Hex without 0x:', check2); // MLDSASecurityLevel.LEVEL2 // Uint8Array const uint8Array = new Uint8Array(1312); const check3 = AddressVerificator.isValidMLDSAPublicKey(uint8Array); console.log('Uint8Array:', check3); // MLDSASecurityLevel.LEVEL2 ``` ### Validating Wallet Keys ```typescript import { Mnemonic, AddressVerificator, MLDSASecurityLevel } from '@btc-vision/transaction'; import { networks } from '@btc-vision/bitcoin'; // Generate wallet const mnemonic = Mnemonic.generate(undefined, '', networks.bitcoin, MLDSASecurityLevel.LEVEL2); const wallet = mnemonic.derive(0); // Validate quantum public key const quantumKeyHex = wallet.quantumPublicKeyHex; const securityLevel = AddressVerificator.isValidMLDSAPublicKey(quantumKeyHex); console.log('Quantum key valid:', securityLevel !== null); console.log('Security level:', securityLevel); // MLDSASecurityLevel.LEVEL2 console.log('Expected:', wallet.securityLevel); // MLDSASecurityLevel.LEVEL2 console.log('Match:', securityLevel === wallet.securityLevel); // true ``` ### Error Cases ```typescript // Empty string console.log(AddressVerificator.isValidMLDSAPublicKey('')); // null // Empty Uint8Array console.log(AddressVerificator.isValidMLDSAPublicKey(new Uint8Array(0))); // null // Invalid hex console.log(AddressVerificator.isValidMLDSAPublicKey('not hex')); // null // Wrong length (classical key size) const classicalKey = new Uint8Array(33); console.log(AddressVerificator.isValidMLDSAPublicKey(classicalKey)); // null // Wrong length (arbitrary size) const wrongSize = new Uint8Array(1500); console.log(AddressVerificator.isValidMLDSAPublicKey(wrongSize)); // null ``` ## Address Type Detection ### Detecting Address Types ```typescript import { AddressVerificator, AddressTypes } from '@btc-vision/transaction'; import { networks } from '@btc-vision/bitcoin'; const wallet = mnemonic.derive(0); // P2TR Detection const p2tr = wallet.p2tr; const p2trType = AddressVerificator.detectAddressType(p2tr, networks.bitcoin); console.log('P2TR type:', p2trType); // AddressTypes.P2TR // P2WPKH Detection const p2wpkh = wallet.p2wpkh; const p2wpkhType = AddressVerificator.detectAddressType(p2wpkh, networks.bitcoin); console.log('P2WPKH type:', p2wpkhType); // AddressTypes.P2WPKH // P2PKH Detection const p2pkh = wallet.p2pkh; const p2pkhType = AddressVerificator.detectAddressType(p2pkh, networks.bitcoin); console.log('P2PKH type:', p2pkhType); // AddressTypes.P2PKH // P2MR Detection (quantum-safe, BIP 360) const p2mrAddr = 'bc1z...'; // P2MR address from useP2MR output const p2mrType = AddressVerificator.detectAddressType(p2mrAddr, networks.bitcoin); console.log('P2MR type:', p2mrType); // AddressTypes.P2MR ``` ### Available Address Types ```typescript enum AddressTypes { P2PKH = 'P2PKH', // Legacy (1...) P2OP = 'P2OP', // OPNet contract (bc1s...) P2SH_OR_P2SH_P2WPKH = 'P2SH_OR_P2SH-P2WPKH', // Script hash (3...) P2PK = 'P2PK', // Public key P2TR = 'P2TR', // Taproot (bc1p...) P2MR = 'P2MR', // Merkle Root / BIP 360 (bc1z...) P2WPKH = 'P2WPKH', // SegWit (bc1q...) P2WSH = 'P2WSH', // SegWit script (bc1q...) P2WDA = 'P2WDA', // Witness data auth } ``` ### Distinguishing Similar Addresses ```typescript const wallet = mnemonic.derive(0); // P2TR vs P2WPKH (both Bech32 formats) const p2tr = wallet.p2tr; const p2wpkh = wallet.p2wpkh; const p2trType = AddressVerificator.detectAddressType(p2tr, networks.bitcoin); const p2wpkhType = AddressVerificator.detectAddressType(p2wpkh, networks.bitcoin); console.log('P2TR detected as:', p2trType); // AddressTypes.P2TR console.log('P2WPKH detected as:', p2wpkhType); // AddressTypes.P2WPKH console.log('Different types:', p2trType !== p2wpkhType); // true ``` ### Network-Specific Detection ```typescript // Mainnet address on mainnet const mainnetAddr = wallet.p2tr; const mainnetDetect = AddressVerificator.detectAddressType(mainnetAddr, networks.bitcoin); console.log('Mainnet on mainnet:', mainnetDetect); // AddressTypes.P2TR // Mainnet address on wrong network const wrongNetwork = AddressVerificator.detectAddressType(mainnetAddr, networks.testnet); console.log('Mainnet on testnet:', wrongNetwork); // null ``` ## Classical Address Validation ### Validating Classical Public Keys ```typescript import { AddressVerificator } from '@btc-vision/transaction'; import { networks } from '@btc-vision/bitcoin'; const wallet = mnemonic.derive(0); // Validate compressed public key (33 bytes) const compressedKey = wallet.toPublicKeyHex(); const isValid = AddressVerificator.isValidPublicKey(compressedKey, networks.bitcoin); console.log('Compressed key valid:', isValid); // true // Validate uncompressed public key (65 bytes) const uncompressedKey = wallet.toUncompressedPublicKey().toString('hex'); const isUncompressedValid = AddressVerificator.isValidPublicKey(uncompressedKey, networks.bitcoin); console.log('Uncompressed key valid:', isUncompressedValid); // true ``` ### Validating Other Address Types ```typescript // P2TR validation const p2tr = wallet.p2tr; const isP2TRValid = AddressVerificator.isValidP2TRAddress(p2tr, networks.bitcoin); console.log('P2TR valid:', isP2TRValid); // true // P2WPKH validation const p2wpkh = wallet.p2wpkh; const isP2WPKHValid = AddressVerificator.isP2WPKHAddress(p2wpkh, networks.bitcoin); console.log('P2WPKH valid:', isP2WPKHValid); // true // P2PKH or P2SH validation const p2pkh = wallet.p2pkh; const isLegacyValid = AddressVerificator.isP2PKHOrP2SH(p2pkh, networks.bitcoin); console.log('Legacy valid:', isLegacyValid); // true ``` ## Complete Validation Example ```typescript import { Mnemonic, AddressVerificator, AddressTypes, MLDSASecurityLevel, } from '@btc-vision/transaction'; import { networks } from '@btc-vision/bitcoin'; // Generate wallet const mnemonic = Mnemonic.generate(undefined, '', networks.bitcoin, MLDSASecurityLevel.LEVEL2); const wallet = mnemonic.derive(0); console.log('=== ML-DSA Public Key Validation ==='); // Validate quantum public key const quantumKeyHex = wallet.quantumPublicKeyHex; const quantumKeyBytes = wallet.quantumPublicKey; const securityLevelFromHex = AddressVerificator.isValidMLDSAPublicKey(quantumKeyHex); const securityLevelFromBytes = AddressVerificator.isValidMLDSAPublicKey(quantumKeyBytes); console.log('Hex validation:', securityLevelFromHex); // MLDSASecurityLevel.LEVEL2 console.log('Uint8Array validation:', securityLevelFromBytes); // MLDSASecurityLevel.LEVEL2 console.log('Matches wallet:', securityLevelFromHex === wallet.securityLevel); // true console.log('\n=== Address Type Detection ==='); // Detect all address types const addresses = { p2tr: wallet.p2tr, p2wpkh: wallet.p2wpkh, p2pkh: wallet.p2pkh, }; for (const [name, addr] of Object.entries(addresses)) { const type = AddressVerificator.detectAddressType(addr, networks.bitcoin); console.log(`${name}: ${type}`); } console.log('\n=== Classical Key Validation ==='); // Validate classical public key const classicalKey = wallet.toPublicKeyHex(); const isClassicalValid = AddressVerificator.isValidPublicKey(classicalKey, networks.bitcoin); console.log('Classical key:', classicalKey); console.log('Classical valid:', isClassicalValid); // true console.log('\n=== Cross-Network Validation ==='); // Test network mismatch const mainnetP2TR = wallet.p2tr; const testnetMnemonic = Mnemonic.generate(undefined, '', networks.testnet, MLDSASecurityLevel.LEVEL2); const testnetWallet = testnetMnemonic.derive(0); const testnetP2TR = testnetWallet.p2tr; const mainnetType = AddressVerificator.detectAddressType(mainnetP2TR, networks.bitcoin); const wrongNetworkType = AddressVerificator.detectAddressType(mainnetP2TR, networks.testnet); console.log('Mainnet P2TR on mainnet:', mainnetType); // AddressTypes.P2TR console.log('Mainnet P2TR on testnet:', wrongNetworkType); // null console.log('\n=== Complete Wallet Validation ==='); function validateWallet(wallet: any, network: any): boolean { // Validate quantum key const quantumValid = AddressVerificator.isValidMLDSAPublicKey( wallet.quantumPublicKey ) !== null; // Validate classical key const classicalValid = AddressVerificator.isValidPublicKey( wallet.toPublicKeyHex(), network ); return quantumValid && classicalValid; } const isWalletValid = validateWallet(wallet, networks.bitcoin); console.log('Complete wallet validation:', isWalletValid); // true ``` ## Next Steps - [Message Signing](./04-message-signing.md) - Sign and verify messages - [Introduction](./01-introduction.md) - Back to overview