### Install Libauth Source: https://context7.com/bitauth/libauth/llms.txt Commands to install the library using npm or yarn. ```bash # Install with npm npm install @bitauth/libauth # Or with yarn yarn add @bitauth/libauth ``` -------------------------------- ### Install Libauth with npm or yarn Source: https://github.com/bitauth/libauth/blob/master/docs/install.md Install the @bitauth/libauth package using either npm or yarn. This is the initial step for using Libauth in your Node.js environment. ```sh npm install @bitauth/libauth # OR yarn add @bitauth/libauth ``` -------------------------------- ### Install and Import Libauth Source: https://github.com/bitauth/libauth/blob/master/README.md Install the @bitauth/libauth package using npm or yarn. Import specific functionality, such as secp256k1, for use in your application. ```sh npm install @bitauth/libauth # OR yarn add @bitauth/libauth ``` ```typescript import { secp256k1 } from '@bitauth/libauth'; import { msgHash, pubkey, sig } from 'somewhere'; secp256k1.verifySignatureDERLowS(sig, pubkey, msgHash) ? console.log('🚀 Signature valid') : console.log('❌ Signature invalid'); ``` -------------------------------- ### Import Libauth Modules Source: https://context7.com/bitauth/libauth/llms.txt Examples of importing library functions in Node.js, web bundlers, and Deno environments. ```typescript // Import in Node.js or web bundlers import { secp256k1, hexToBin, binToHex } from '@bitauth/libauth'; // Import in Deno import { hexToBin } from 'npm:@bitauth/libauth'; console.log(hexToBin('beef')); // => Uint8Array(2) [ 190, 239 ] ``` -------------------------------- ### Debug VM Evaluations with Trace Output Source: https://context7.com/bitauth/libauth/llms.txt Debug virtual machine evaluations to get detailed trace output. This requires creating a compiler and generating a test scenario. ```typescript import { createVirtualMachineBCH, summarizeDebugTrace, stringifyDebugTraceSummary, OpcodesBCH, walletTemplateToCompilerBCH, assertSuccess } from '@bitauth/libauth'; const vm = createVirtualMachineBCH(true); // Create a simple compiler for testing const compiler = walletTemplateToCompilerBCH({ entities: {}, scripts: { lock: { lockingType: 'p2sh20', script: 'OP_SIZE <0> OP_EQUAL OP_NIP' }, unlock: { script: 'OP_0', unlocks: 'lock' }, }, supported: ['BCH_SPEC'], }); // Generate test scenario const { program } = assertSuccess( compiler.generateScenario({ unlockingScriptId: 'unlock' }) ); // Debug the evaluation const trace = vm.debug(program); const summary = summarizeDebugTrace(trace); const formatted = stringifyDebugTraceSummary(summary, { opcodes: OpcodesBCH }); console.log(formatted); // => Shows step-by-step execution with stack contents ``` -------------------------------- ### Convert BIP39 Mnemonic Phrase to BCH Wallet Address Source: https://github.com/bitauth/libauth/blob/master/docs/keys.md Derives a Bitcoin Cash (BCH) wallet address from a BIP39 mnemonic phrase using standard derivation paths. This example uses SLIP44 for BCH and BIP44 for address derivation. ```typescript import { assertSuccess, deriveHdPrivateNodeFromBip39Mnemonic, deriveHdPath, deriveHdPathRelative, privateKeyToP2pkhCashAddress, } from '@bitauth/libauth'; const mnemonic = 'legal winner thank year wave sausage worth useful legal winner thank yellow'; const node = deriveHdPrivateNodeFromBip39Mnemonic(mnemonic); /** * SLIP44 standardizes `m/44'/145'` as the derivation path for BCH accounts, * followed by a hardened index for te account number (here, account `0`). */ const bchAccount0 = deriveHdPath(node, "m/44'/145'/0'"); /** * From account 0, derive the private key for external address 0 (as * standardized by BIP44): */ const { privateKey } = deriveHdPathRelative(bchAccount0, '0/0'); const { address } = assertSuccess(privateKeyToP2pkhCashAddress({ privateKey })); console.log(address); // => "bitcoincash:qpdtccrxx78kcuc65mceurfwg60gmmqu9cwpjdt25n" ``` -------------------------------- ### Patch BCH Instruction Set with Custom Opcode Source: https://github.com/bitauth/libauth/blob/master/docs/verify-transactions.md Import and modify an existing instruction set to add a custom opcode like OP_UNROT. This example demonstrates patching the BCH instruction set to include a new operation and testing it with a wallet template compiler and debugger. ```typescript import type { AuthenticationProgramStateStack } from '@bitauth/libauth'; import { assertSuccess, binToHex, createInstructionSetBCH, createVirtualMachine, OpcodesBCH, pushToStack, stringifyDebugTraceSummary, summarizeDebugTrace, useThreeStackItems, walletTemplateToCompilerBCH, } from '@bitauth/libauth'; const instructionSet = createInstructionSetBCH(true); /** * A hypothetical "OP_UNROT" which rotates the top stack items in the * direction opposite that of OP_ROT. (The generic `` * is only necessary for TypeScript usage.) */ const opUnRot = (state: State) => useThreeStackItems(state, (nextState, [a, b, c]) => pushToStack(nextState, c, a, b), ); /* We assign "OP_UNROT" at the index held by "OP_RESERVED1" */ const opcode = OpcodesBCH.OP_RESERVED1; /* All other features of the BCH instruction set are unmodified: */ const vm = createVirtualMachine({ ...instructionSet, operations: { ...instructionSet.operations, [opcode]: opUnRot, }, }); const OP_UNROT = `0x${binToHex(Uint8Array.of(opcode))}`; /* A compiler for a simple wallet template to test the new opcode: */ const compiler = walletTemplateToCompilerBCH({ entities: {}, scripts: { lock: { lockingType: 'p2sh20', script: `${OP_UNROT} OP_CAT OP_CAT <0x030102> OP_EQUAL`, }, unlock: { script: '<1> <2> <3>', unlocks: 'lock' }, }, supported: ['BCH_SPEC'], }); /* Generate a testing scenario, throwing any errors */ const { program } = assertSuccess( compiler.generateScenario({ unlockingScriptId: 'unlock' }), ); /* Debug the `program`: an inputIndex, sourceOutputs, and transaction */ const trace = vm.debug(program); const summary = summarizeDebugTrace(trace); const formatted = stringifyDebugTraceSummary(summary, { opcodes: { ...OpcodesBCH, [opcode]: 'OP_UNROT' }, }); console.log(formatted); ``` -------------------------------- ### Automatic CashAddress Error Correction (Safe Failure Modes) Source: https://github.com/bitauth/libauth/blob/master/docs/addresses.md This example demonstrates automatic error correction for formats with safe failure modes, such as `libauth-secret-key`. It encodes a payload, introduces errors, and then uses error correction to restore the original payload, verifying the process. ```typescript import { assertSuccess, binsAreEqual, decodeCashAddressFormat, encodeCashAddressFormat, splitEvery, } from '@bitauth/libauth'; import { askUserToTryAgain, promptUserToBackup } from './my/app'; const payload = Uint8Array.from(range(16)); const prefix = 'secretkey'; const raw = encodeCashAddressFormat({ payload, prefix, version: 0 }).address; const hyphenated = `secret-key:${splitEvery(raw.slice(10), 4).join('-')}`; promptUserToBackup(hyphenated); // => 'secret-key:qqqq-zqsr-qszs-vpcg-py9q-krqd-pc8s-5c6s-605f' /* Later, to restore from the backup: */ const userEnters = 'secret-key:qqqq-zasr-qszs-vpcg-py9q-krqd-pc8s-sc6s-605f'; /* `q` mistakenly transcribed as `a` ^, `5` transcribed as `s` ^ */ const compressed = userEnters.replace(/-/gu, ''); const result = attemptCashAddressFormatErrorCorrection(compressed); if (typeof result === 'string') { askUserToTryAgain(result); return; } const corrected = assertSuccess(decodeCashAddressFormat(result.address)); console.log(binsAreEqual(payload, corrected.payload)); // => true ``` -------------------------------- ### Verify a Transaction with Libauth Source: https://github.com/bitauth/libauth/blob/master/docs/verify-transactions.md Use createVirtualMachineBCH to initialize a standard VM and verify a transaction against provided UTXOs. ```ts import { assertSuccess, decodeTransaction, decodeTransactionOutputs, createVirtualMachineBCH, } from '@bitauth/libauth'; const vm = createVirtualMachineBCH(true); /* Example transaction from Virtual Machine Bytecode (VMB) test ID: "dv5k4" */ const vmbTest = { description: 'Basic push operations: OP_0 (A.K.A. OP_PUSHBYTES_0, OP_FALSE): zero is represented by an empty stack item (P2SH20)', id: 'dv5k4', tx: hexToBin( '020000000201000000000000000000000000000000000000000000000000000000000000000000000064417dfb529d352908ee0a88a0074c216b09793d6aa8c94c7640bb4ced51eaefc75d0aef61f7685d0307491e2628da3d4f91e86329265a4a58ca27a41ec0b8910779c32103a524f43d6166ad3567f18b0a5c769c6ab4dc02149f4d5095ccf4e8ffa293e7850000000001000000000000000000000000000000000000000000000000000000000000000100000006000482008777000000000100000000000000000a6a08766d625f7465737400000000', ), utxos: hexToBin( '0210270000000000001976a91460011c6bf3f1dd98cff576437b9d85de780f497488ac102700000000000017a91498e86c508e780cfb822bba3d5ab9b3e30450196b87', ), }; /* Decode the transaction, throwing any errors */ const transaction = assertSuccess(decodeTransaction(vmbTest.tx)); /* Decode the serialized outputs, throwing any errors */ const sourceOutputs = assertSuccess(decodeTransactionOutputs(vmbTest.utxos)); // Result is either `true` or an error message (`string`) const result = vm.verify({ sourceOutputs, transaction }); if (typeof result === 'string') { console.error(result); } else { console.log('Transaction verified 🚀'); } ``` -------------------------------- ### Create Custom Virtual Machines Source: https://context7.com/bitauth/libauth/llms.txt Create custom virtual machines by patching existing instruction sets, such as adding a new opcode. This involves defining the opcode's behavior and assigning it to an unused slot. ```typescript import { createInstructionSetBCH, createVirtualMachine, OpcodesBCH, pushToStack, useThreeStackItems, walletTemplateToCompilerBCH, assertSuccess, binToHex, stringifyDebugTraceSummary, summarizeDebugTrace } from '@bitauth/libauth'; const instructionSet = createInstructionSetBCH(true); // Define custom opcode: OP_UNROT (reverse rotation) const opUnRot = (state) => useThreeStackItems(state, (nextState, [a, b, c]) => pushToStack(nextState, c, a, b) ); // Assign to unused opcode slot const opcode = OpcodesBCH.OP_RESERVED1; const vm = createVirtualMachine({ ...instructionSet, operations: { ...instructionSet.operations, [opcode]: opUnRot, }, }); // Test the custom opcode const OP_UNROT = `0x${binToHex(Uint8Array.of(opcode))}`; const compiler = walletTemplateToCompilerBCH({ entities: {}, scripts: { lock: { lockingType: 'p2sh20', script: `${OP_UNROT} OP_CAT OP_CAT <0x030102> OP_EQUAL` }, unlock: { script: '<1> <2> <3>', unlocks: 'lock' }, }, supported: ['BCH_SPEC'], }); const { program } = assertSuccess(compiler.generateScenario({ unlockingScriptId: 'unlock' })); const trace = vm.debug(program); console.log(stringifyDebugTraceSummary(summarizeDebugTrace(trace), { opcodes: { ...OpcodesBCH, [opcode]: 'OP_UNROT' } })); ``` -------------------------------- ### Wallet Import Format (WIF) Encoding and Decoding Source: https://context7.com/bitauth/libauth/llms.txt Encode private keys into Wallet Import Format (WIF) for mainnet or testnet, and decode WIF strings back into private keys. Use assertSuccess for trusted WIF inputs. ```typescript import { encodePrivateKeyWif, decodePrivateKeyWif, generatePrivateKey, assertSuccess } from '@bitauth/libauth'; // Generate and encode a private key as WIF const privateKey = generatePrivateKey(); const wif = encodePrivateKeyWif(privateKey, 'mainnet'); console.log(wif); // => 'L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi' // Decode a WIF-encoded private key const decoded = decodePrivateKeyWif('L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi'); if (typeof decoded === 'string') { console.error('Decoding error:', decoded); } else { console.log('Private key:', binToHex(decoded.privateKey)); console.log('Network:', decoded.type); // 'mainnet' or 'testnet' } // Using assertSuccess for trusted input const { privateKey: pk } = assertSuccess(decodePrivateKeyWif(wif)); ``` -------------------------------- ### Create BCH Wallet from BIP39 Mnemonic Source: https://context7.com/bitauth/libauth/llms.txt Derive multiple addresses from a BIP39 mnemonic phrase using the SLIP44 standard path. ```typescript import { deriveHdPrivateNodeFromBip39Mnemonic, deriveHdPath, deriveHdPathRelative, privateKeyToP2pkhCashAddress, assertSuccess } from '@bitauth/libauth'; const mnemonic = 'legal winner thank year wave sausage worth useful legal winner thank yellow'; const node = deriveHdPrivateNodeFromBip39Mnemonic(mnemonic); // Derive BCH account 0 using SLIP44 standard path const bchAccount0 = deriveHdPath(node, "m/44'/145'/0'"); // Derive first external address (index 0) const { privateKey } = deriveHdPathRelative(bchAccount0, '0/0'); const { address } = privateKeyToP2pkhCashAddress({ privateKey }); console.log(address); // => 'bitcoincash:qpdtccrxx78kcuc65mceurfwg60gmmqu9cwpjdt25n' // Derive multiple addresses for (let i = 0; i < 5; i++) { const { privateKey: pk } = deriveHdPathRelative(bchAccount0, `0/${i}`); const { address: addr } = privateKeyToP2pkhCashAddress({ privateKey: pk }); console.log(`Address ${i}: ${addr}`); } ``` -------------------------------- ### Generate and Encode WIF Private Key Source: https://github.com/bitauth/libauth/blob/master/docs/keys.md Create a new private key and encode it into the Wallet Import Format (WIF) for a specified network. ```ts import { encodePrivateKeyWif, generatePrivateKey } from '@bitauth/libauth'; const privateKey = generatePrivateKey(); const wif = encodePrivateKeyWif(privateKey, 'mainnet'); console.log(wif); // => "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi" ``` -------------------------------- ### Debug VM Evaluations via CLI Source: https://github.com/bitauth/libauth/blob/master/docs/verify-transactions.md Run unit tests for VMB evaluations using the yarn test:unit:vmb_test command. ```sh ❯ yarn test:unit:vmb_test bch_2023_standard dv5k4 VMB test ID: dv5k4 Description: Basic push operations: OP_0 (A.K.A. OP_PUSHBYTES_0, OP_FALSE): zero is represented by an empty stack item (P2SH20) Test sets: 2022_standard Unlocking ASM: OP_0 Redeem (P2SH20) ASM: OP_SIZE <0> OP_EQUAL OP_NIP Result: Success Evaluation at index 1: 0. OP_0: 0x(0) 1. OP_PUSHBYTES_4: 0x(0) 0x82008777(2005336194) => 0x(0) 0x82008777(2005336194) 0. OP_HASH160: 0x(0) 0x98e86c508e780cfb822bba3d5ab9b3e30450196b 1. OP_PUSHBYTES_20: 0x(0) 0x98e86c508e780cfb822bba3d5ab9b3e30450196b 0x98e86c508e780cfb822bba3d5ab9b3e30450196b 2. OP_EQUAL: 0x(0) 0x01(1) => 0x(0) 0. OP_SIZE: 0x(0) 0x(0) 1. OP_0: 0x(0) 0x(0) 0x(0) 2. OP_EQUAL: 0x(0) 0x01(1) 3. OP_NIP: 0x01(1) => 0x01(1) ``` -------------------------------- ### Demonstrate HD Private Key Recovery Risk Source: https://github.com/bitauth/libauth/blob/master/docs/keys.md Shows how an attacker can derive a parent HD private key if they possess both an HD public key and a single child private key. ```ts import { assertSuccess, deriveHdPublicKey, decodeHdPrivateKey, decodeHdPublicKey, encodeHdPrivateKey, deriveHdPathRelative, crackHdPrivateNodeFromHdPublicNodeAndChildPrivateNode, } from '@bitauth/libauth'; const hdPrivateKey = 'xprv9yG4X8zfB77WS2vwx49tbDtHE1Cyq5wQe2iFcGy5jhizqSEgh22ZXzBaFpMYbLJN4EK459UgFWAxb5rSwzqzx6gw7xxH8z5vvcvUi4oFQqj'; const { hdPublicKey } = deriveHdPublicKey(hdPrivateKey); const hdPrivateNode = assertSuccess(decodeHdPrivateKey(hdPrivateKey)).node; const hdPublicNode = assertSuccess(decodeHdPublicKey(hdPublicKey)).node; /** * The HD public key is shared with an observer, and somehow, the observer * gains access to a non-hardened child private key (in this case, the key at * index `1234`.) */ const someChildNode = deriveHdPathRelative(hdPrivateNode, '1234'); /** * The observer can now trivially derive the parent HD private key using the * HD public key: */ const parentKey = encodeHdPrivateKey({ network: 'mainnet', node: assertSuccess( crackHdPrivateNodeFromHdPublicNodeAndChildPrivateNode( hdPublicNode, someChildNode, ), ), }).hdPrivateKey; console.log(parentKey); // => "xprv9yG4X8zfB77WS2vwx49tbDtHE1Cyq5wQe2iFcGy5jhizqSEgh22ZXzBaFpMYbLJN4EK459UgFWAxb5rSwzqzx6gw7xxH8z5vvcvUi4oFQqj" ``` -------------------------------- ### Handle Insufficient Entropy Errors Source: https://github.com/bitauth/libauth/blob/master/docs/keys.md Demonstrates how the library returns an error when the provided input events do not meet the minimum entropy requirements. ```ts import { generateDeterministicEntropy, splitEvery } from '@bitauth/libauth'; const flip10 = '1110100010'; const faces = 2; const events = splitEvery(flip10, 1).map(parseInt); const result = generateDeterministicEntropy(faces, events); console.log(result); // => "Entropy generation error: the provided list of events contains insufficient entropy. With 2 possible results per event, a minimum of 128 events are required to obtain sufficient entropy. Events provided: 10." ``` -------------------------------- ### Verify Signature with secp256k1 in Node.js Source: https://github.com/bitauth/libauth/blob/master/docs/install.md Import and use the secp256k1 module to verify a signature against a public key and message hash. Ensure you have the necessary signature, public key, and message hash variables available. ```ts import { secp256k1 } from '@bitauth/libauth'; import { msgHash, pubkey, sig } from 'somewhere'; secp256k1.verifySignatureDERLowS(sig, pubkey, msgHash) ? console.log('🚀 Signature valid') : console.log('❌ Signature invalid'); ``` -------------------------------- ### BIP39 Mnemonic Phrase Generation and Handling Source: https://context7.com/bitauth/libauth/llms.txt Generate, encode, decode, and derive seeds from BIP39 mnemonic phrases. Supports 128-bit entropy for 12-word phrases and allows optional passphrases for seed derivation. ```typescript import { generateBip39Mnemonic, encodeBip39Mnemonic, decodeBip39Mnemonic, deriveSeedFromBip39Mnemonic, assertSuccess, binToHex } from '@bitauth/libauth'; // Generate a random 12-word mnemonic const mnemonic = generateBip39Mnemonic(); console.log(mnemonic); // => 'legal winner thank year wave sausage worth useful legal winner thank yellow' // Encode entropy as mnemonic (128 bits = 12 words) const entropy = hexToBin('00000000000000000000000000000000'); const { phrase } = assertSuccess(encodeBip39Mnemonic(entropy)); console.log(phrase); // => 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' // Decode mnemonic to entropy const decoded = assertSuccess(decodeBip39Mnemonic(phrase)); console.log(binToHex(decoded.entropy)); // => '00000000000000000000000000000000' // Derive seed from mnemonic (with optional passphrase) const seed = deriveSeedFromBip39Mnemonic(mnemonic, 'optional-passphrase'); console.log(binToHex(seed)); ``` -------------------------------- ### Derive BIP32 HD Keys from Mnemonic Source: https://context7.com/bitauth/libauth/llms.txt Derive master HD nodes from BIP39 mnemonics and then derive child nodes using BIP44 paths. Extended private keys (xprv) can be encoded for storage, and extended public keys (xpub) can be derived for watch-only wallets. Relative derivation is also supported for address generation. ```typescript import { deriveHdPrivateNodeFromBip39Mnemonic, deriveHdPath, deriveHdPathRelative, deriveHdPublicNode, encodeHdPrivateKey, encodeHdPublicKey, decodeHdPrivateKey, decodeHdPublicKey, deriveHdPublicKey, assertSuccess } from '@bitauth/libauth'; // Derive master HD node from mnemonic const mnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; const masterNode = deriveHdPrivateNodeFromBip39Mnemonic(mnemonic); // Derive BCH account using BIP44/SLIP44 path const bchAccount = deriveHdPath(masterNode, "m/44'/145'/0'"); // Encode as xprv (extended private key) const { hdPrivateKey } = encodeHdPrivateKey({ network: 'mainnet', node: bchAccount }); console.log(hdPrivateKey); // => 'xprv9yG4X8zfB77WS2vwx49tbDtHE1Cyq5wQe2iFcGy5jhizqSEgh22ZXzBaFpMYbLJN4EK459UgFWAxb5rSwzqzx6gw7xxH8z5vvcvUi4oFQqj' // Derive xpub (extended public key) for watch-only wallets const { hdPublicKey } = deriveHdPublicKey(hdPrivateKey); console.log(hdPublicKey); // => 'xpub6CFQveXZ1UfoeX1R45gtxMq1n33UEYfG1FdrQfNhJ3FyiEZqEZLp5nW474QiDWfVQ6NGk5iPv1h14Vhz2CtzNkGNhimgUucyUtWGdMdofhe' // Relative derivation for address generation const addressKey = deriveHdPathRelative(bchAccount, '0/0'); console.log('Derived address key at index 0'); ``` -------------------------------- ### Create BIP39 Mnemonic Phrase from Coin Flips Source: https://github.com/bitauth/libauth/blob/master/docs/keys.md Converts a series of deterministic events into entropy to generate a valid BIP39 mnemonic phrase. ```ts import { assertSuccess, encodeBip39Mnemonic, generateDeterministicEntropy, splitEvery, } from '@bitauth/libauth'; /* 128 simulate coin flips (`binToBinString(generateRandomBytes(16))`) */ const flip128 = '11101000100010110101110111110111000110000001011110001110111011001001111011010011000111000110000010100110101101110100110000001111'; const faces = 2; const events = splitEvery(flip128, 1).map(parseInt); /* `assertSuccess` simply throws any errors */ const entropy = assertSuccess(generateDeterministicEntropy(faces, events)); /* Slice produced entropy at 16 bytes (128 bits) for 12 words: */ const { phrase } = assertSuccess(encodeBip39Mnemonic(entropy.slice(0, 16))); console.log(phrase); // => "crawl actual tool rally crazy lab work paper fragile favorite draft income" ``` -------------------------------- ### Convert Locking Bytecode to CashAddress Source: https://github.com/bitauth/libauth/blob/master/docs/addresses.md Use `lockingBytecodeToCashAddress` to convert transaction output bytecode into a CashAddress. Ensure correct prefix and consider token support. Errors are thrown if conversion fails. ```typescript import { assertSuccess, hexToBin, lockingBytecodeToCashAddress, } from '@bitauth/libauth'; const p2pkhBytecode = hexToBin( '76a914fc916f213a3d7f1369313d5fa30f6168f9446a2d88ac', ); const p2pkh = lockingBytecodeToCashAddress({ bytecode: p2pkhBytecode, prefix: 'bitcoincash', }); // With `assertSuccess`, any errors are simply thrown console.log(assertSuccess(p2pkh).address); // => "bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl" ``` ```typescript const p2pk = hexToBin( '4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac', ); const genesisCoinbase = lockingBytecodeToCashAddress({ bytecode: p2pk, prefix: 'bitcoincash', }); console.log(genesisCoinbase); // => "CashAddress encoding error: no CashAddress type bit has been standardized for P2PK locking bytecode." ``` ```typescript const p2sh32 = hexToBin( 'aa20000000000000000000000000000012345678900000000000000000000000000087', ); const p2sh32WithTokens = lockingBytecodeToCashAddress({ bytecode: p2sh32, prefix: 'bchtest', tokenSupport: true, }); console.log(assertSuccess(p2sh32WithTokens).address); // => "bchtest:rvqqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqszvpgjlk" ``` ```typescript const nonStandard = hexToBin('52935387'); const nonStandardAddress = lockingBytecodeToCashAddress({ bytecode: nonStandard, prefix: 'bitcoincash', }); console.log(nonStandardAddress); // => "CashAddress encoding error: unknown locking bytecode type." ``` -------------------------------- ### Convert Hex to Binary in Deno Source: https://github.com/bitauth/libauth/blob/master/docs/install.md Import and use the hexToBin function from Libauth in a Deno environment using the npm: protocol. This function converts a hexadecimal string to its binary representation. ```ts import { hexToBin } from 'npm:@bitauth/libauth'; console.log(hexToBin('beef')); ``` -------------------------------- ### Derive P2PKH Address from BIP39 Mnemonic Source: https://github.com/bitauth/libauth/blob/master/docs/wallets.md Generates a P2PKH address using a BIP39 mnemonic and a standard SLIP44 derivation path. ```typescript import { deriveHdPrivateNodeFromBip39Mnemonic, encodeHdPrivateKey, generateBip39Mnemonic, hdPrivateKeyToP2pkhCashAddress, } from '@bitauth/libauth'; import { saveSomewhere } from './my/app'; const mnemonic = generateBip39Mnemonic(); // => 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' saveSomewhere(mnemonic); const { hdPrivateKey } = encodeHdPrivateKey({ network: 'mainnet', node: deriveHdPrivateNodeFromBip39Mnemonic(mnemonic), }); /* BCH account standardized by SLIP44 */ const privateDerivationPath = "m/44'/145'/0'/0/i"; const addressIndex = 0; const { address } = hdPrivateKeyToP2pkhCashAddress({ addressIndex, hdPrivateKey, privateDerivationPath, }); console.log( `The address at external BCH account (${privateDerivationPath}) index ${addressIndex} is: ${address}.`, ); // => "The address at external BCH account (m/44'/145'/0'/0/i) index 0 is: bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6." ``` -------------------------------- ### Hash a message with SHA256 Source: https://github.com/bitauth/libauth/blob/master/docs/crypto.md Demonstrates hashing a UTF8-encoded string using the SHA256 primitive. ```typescript import { binToHex, sha256, utf8ToBin } from '@bitauth/libauth'; const message = utf8ToBin('Hello world!'); const hash = sha256.hash(message); const hex = binToHex(hash); console.log(hex); // => 'c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a' ``` -------------------------------- ### Convert Private Key to P2PKH Address Source: https://context7.com/bitauth/libauth/llms.txt Derive a P2PKH CashAddress from a WIF-encoded private key or a raw public key. ```typescript import { privateKeyToP2pkhCashAddress, publicKeyToP2pkhCashAddress, decodePrivateKeyWif, assertSuccess, secp256k1 } from '@bitauth/libauth'; // From WIF-encoded private key const wif = 'KxbEv3FeYig2afQp7QEA9R3gwqdTBFwAJJ6Ma7j1SkmZoxC9bAXZ'; const { privateKey } = assertSuccess(decodePrivateKeyWif(wif)); const { address } = privateKeyToP2pkhCashAddress({ privateKey }); console.log(address); // => 'bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6' // From public key only const publicKey = assertSuccess(secp256k1.derivePublicKeyCompressed(privateKey)); const { address: pubkeyAddr } = publicKeyToP2pkhCashAddress({ publicKey }); console.log(pubkeyAddr); // => 'bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6' ``` -------------------------------- ### Hash160 and Hash256 Utilities Source: https://context7.com/bitauth/libauth/llms.txt Use hash160 for public key hashing (addresses) and hash256 for transaction hashing. Ensure data is converted to binary format before hashing. ```typescript import { hash160, hash256, binToHex, hexToBin } from '@bitauth/libauth'; // hash160: SHA-256 followed by RIPEMD-160 (used for addresses) const pubkey = hexToBin('0376ea9e36a75d2ecf9c93a0be76885e36f822529db22acfdc761c9b5b4544f5c5'); const pubkeyHash = hash160(pubkey); console.log(binToHex(pubkeyHash)); // => '15d16c84669ab46059313bf0747e781f1d13936d' // hash256: Double SHA-256 (used for transaction hashing) const data = hexToBin('01000000'); const doubleHash = hash256(data); console.log(binToHex(doubleHash)); ``` -------------------------------- ### Hash a message with RIPEMD160 Source: https://github.com/bitauth/libauth/blob/master/docs/crypto.md Demonstrates hashing a hex-encoded string using the RIPEMD160 primitive. ```typescript import { binToHex, hexToBin, ripemd160 } from '@bitauth/libauth'; const message = hexToBin('01020304'); const hash = ripemd160.hash(message); const hex = binToHex(hash); console.log(hex); // => '179bb366e5e224b8bf4ce302cefc5744961839c5' ``` -------------------------------- ### Encode and Decode Arbitrary Data to CashAddress Format Source: https://github.com/bitauth/libauth/blob/master/docs/addresses.md Use `encodeCashAddressFormat` and `decodeCashAddressFormat` to encode arbitrary binary data into a CashAddress-like format and decode it back. This is useful for transmitting short strings or identifiers. Ensure correct prefix, version, and payload. Errors are thrown if decoding fails. ```typescript import { assertSuccess, binToHex, decodeCashAddressFormat, encodeCashAddressFormat, hexToBin, } from '@bitauth/libauth'; const txId = '978306aa4e02fd06e251b38d2e961f78f4af2ea6524a3e4531126776276a6af1'; // With `assertSuccess`, any errors are simply thrown const { address } = assertSuccess( encodeCashAddressFormat({ payload: hexToBin(txId), prefix: 'bitauth', version: 3, }), ); console.log(`Encoded authbase: ${address}`); // => "Encoded authbase: bitauth:qwtcxp42fcp06phz2xec6t5krau0ftew5efy50j9xyfxwa38df40zp58z6t5w" const { payload } = assertSuccess(decodeCashAddressFormat(address)); console.log(`Encoded TXID: ${binToHex(payload)}`); // => "Encoded TXID: 978306aa4e02fd06e251b38d2e961f78f4af2ea6524a3e4531126776276a6af1" ``` -------------------------------- ### Derive HD Public Key from Mnemonic Source: https://github.com/bitauth/libauth/blob/master/docs/keys.md Derives an HD public key from a BIP39 mnemonic to share with a watch-only observer. ```ts import { deriveHdPrivateNodeFromBip39Mnemonic, deriveHdPath, deriveHdPublicKey, encodeHdPrivateKey, } from '@bitauth/libauth'; const node = deriveHdPath( deriveHdPrivateNodeFromBip39Mnemonic( 'legal winner thank year wave sausage worth useful legal winner thank yellow', ), "m/44'/145'/0'", ); const { hdPrivateKey } = encodeHdPrivateKey({ network: 'mainnet', node }); // hdPrivateKey: "xprv9yG4X8zfB77WS2vwx49tbDtHE1Cyq5wQe2iFcGy5jhizqSEgh22ZXzBaFpMYbLJN4EK459UgFWAxb5rSwzqzx6gw7xxH8z5vvcvUi4oFQqj" const { hdPublicKey } = deriveHdPublicKey(hdPrivateKey); console.log(hdPublicKey); // => "xpub6CFQveXZ1UfoeX1R45gtxMq1n33UEYfG1FdrQfNhJ3FyiEZqEZLp5nW474QiDWfVQ6NGk5iPv1h14Vhz2CtzNkGNhimgUucyUtWGdMdofhe" ``` -------------------------------- ### Generate a Random BIP39 Mnemonic Phrase Source: https://github.com/bitauth/libauth/blob/master/docs/keys.md Creates a new random BIP39 mnemonic phrase using the generateBip39Mnemonic function. ```ts import { generateBip39Mnemonic } from '@bitauth/libauth'; const phrase = generateBip39Mnemonic(); console.log(phrase); // => "legal winner thank year wave sausage worth useful legal winner thank yellow" ``` -------------------------------- ### Derive P2PKH Address from Non-HD Keys Source: https://github.com/bitauth/libauth/blob/master/docs/wallets.md Utility for deriving addresses from WIF-encoded private keys or raw public keys. ```typescript import { assertSuccess, decodePrivateKeyWif, privateKeyToP2pkhCashAddress, publicKeyToP2pkhCashAddress, secp256k1, } from '@bitauth/libauth'; const wif = 'KxbEv3FeYig2afQp7QEA9R3gwqdTBFwAJJ6Ma7j1SkmZoxC9bAXZ'; // `assertSuccess` simply throws any decoding errors const { privateKey } = assertSuccess(decodePrivateKeyWif(wif)); const { address } = privateKeyToP2pkhCashAddress({ privateKey }); console.log(`The address is: ${address}.`); // => "The address is: bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6." /* Using only the public key: */ const publicKey = assertSuccess( secp256k1.derivePublicKeyCompressed(privateKey), ); const result = publicKeyToP2pkhCashAddress({ publicKey }); console.log(`Address derived from the public key: ${result.address}.`); // => "Address derived from the public key: bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6." ``` -------------------------------- ### Using assertSuccess to Throw Libauth Errors Source: https://github.com/bitauth/libauth/blob/master/docs/errors.md Use `assertSuccess` to immediately throw any runtime errors encountered by Libauth functions. This is useful for simple scripts or when an error is not expected, allowing direct use of the result. ```typescript import { assertSuccess, cashAddressToLockingBytecode } from '@bitauth/libauth'; import { askUserToSelectFromAddressBook, getUtxosByLockingBytecode, } from './my/app'; const address = await askUserToSelectFromAddressBook(); // assertSuccess: all address book entries are valid addresses const result = assertSuccess(cashAddressToLockingBytecode(address)); // `result.bytecode` can now be safely accessed: getUtxosByLockingBytecode(result.bytecode); ``` -------------------------------- ### Convert CashAddress to Locking Bytecode Source: https://github.com/bitauth/libauth/blob/master/docs/addresses.md Use cashAddressToLockingBytecode to directly extract the locking bytecode and network metadata from a CashAddress. ```typescript import { assertSuccess, binToHex, cashAddressToLockingBytecode, } from '@bitauth/libauth'; const address = 'bitcoincash:zq2azmyyv6dtgczexyalqar70q036yund5j2mspghf'; // With `assertSuccess`, any errors are simply thrown const { bytecode, prefix, tokenSupport } = assertSuccess( cashAddressToLockingBytecode(address), ); console.log(` Network: ${prefix} Supports tokens: ${tokenSupport} Locking bytecode: ${binToHex(bytecode)} `); /** * => * Network: bitcoincash * Supports tokens: true * Locking bytecode: 76a91415d16c84669ab46059313bf0747e781f1d13936d88ac */ ``` -------------------------------- ### Attempt CashAddress Error Correction (User Prompt) Source: https://github.com/bitauth/libauth/blob/master/docs/addresses.md Use this when user input may contain errors. It attempts to correct up to 2 errors in a CashAddress format. If corrections are made, it prompts the user to review and re-enter, rather than automatically applying changes, to prevent potential fund loss. ```typescript import { attemptCashAddressFormatErrorCorrection } from '@bitauth/libauth'; import { askUserToTryAgain } from './my/app'; /** * CAUTION: CashAddress error correction is not fail-safe; instead of suggesting * corrections, prompt the user to review the source and manually re-enter * the characters at the error locations: */ const maybeAddress = 'bch-est:qq2azmyyv6dtgczexyalqar70q036yund53jvfde0z'; /* result.address is 'bchtest:qq2azmyyv6dtgczexyalqar70q036yund53jvfde0x' */ const result = attemptCashAddressFormatErrorCorrection(maybeAddress); if (typeof result === 'string') { askUserToTryAgain(result); return undefined; } if (result.corrections.length === 0) { return maybeAddress; } const pointToCorrections = (c: number[]) => Array.from({ length: c[c.length - 1]! + 1 }, (_, i) => c.includes(i) ? '^' : '-', ).join(''); const message = typeof result === 'string' ? result : `You entered: ${maybeAddress} Errors: ${pointToCorrections(result.corrections)} Please review the address for errors and try again.`; askUserToTryAgain(message); return undefined; /* => You entered: bch-est:qq2azmyyv6dtgczexyalqar70q036yund53jvfde0z Errors: ---^---------------------------------------------^ Please review the address for errors and try again. */ ``` -------------------------------- ### Convert Hex and Binary Data Source: https://context7.com/bitauth/libauth/llms.txt Utilities for converting between hexadecimal strings and binary data, including validation and endianness swapping. ```typescript import { hexToBin, binToHex, isHex, swapEndianness } from '@bitauth/libauth'; // Convert hex string to binary const bytes = hexToBin('2a64ff'); console.log(bytes); // => Uint8Array(3) [ 42, 100, 255 ] // Convert binary to hex string const hex = binToHex(new Uint8Array([42, 100, 255])); console.log(hex); // => '2a64ff' // Validate hex string before conversion const valid = isHex('2a64ff'); console.log(valid); // => true // Swap byte order (endianness) const swapped = swapEndianness('01020304'); console.log(swapped); // => '04030201' ``` -------------------------------- ### Derive P2PKH Address from HD Keys Source: https://context7.com/bitauth/libauth/llms.txt Generate addresses from HD private or public keys using specific derivation paths. ```typescript import { hdPrivateKeyToP2pkhCashAddress, hdPublicKeyToP2pkhCashAddress, deriveHdPrivateNodeFromBip39Mnemonic, encodeHdPrivateKey, deriveHdPath, deriveHdPublicNode, encodeHdPublicKey } from '@bitauth/libauth'; // Setup: derive HD keys from mnemonic const mnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; const masterNode = deriveHdPrivateNodeFromBip39Mnemonic(mnemonic); const { hdPrivateKey } = encodeHdPrivateKey({ network: 'mainnet', node: masterNode }); // Derive address from HD private key const privateDerivationPath = "m/44'/145'/0'/0/i"; // BCH external addresses const { address } = hdPrivateKeyToP2pkhCashAddress({ addressIndex: 0, hdPrivateKey, privateDerivationPath, }); console.log(address); // => 'bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6' // For watch-only wallets using HD public key const bchAccount0 = "m/44'/145'/0'"; const accountNode = deriveHdPublicNode(deriveHdPath(masterNode, bchAccount0)); const { hdPublicKey } = encodeHdPublicKey({ network: 'mainnet', node: accountNode }); const { address: watchAddr } = hdPublicKeyToP2pkhCashAddress({ addressIndex: 0, hdPublicKey, hdPublicKeyDerivationPath: bchAccount0, publicDerivationPath: '0/i', }); console.log(watchAddr); // => 'bitcoincash:qqyx49mu0kkn9ftfj6hje6g2wfer34yfnq5tahq3q6' ```