UNPKG

bitcoinjs-lib

Version:

Client-side Bitcoin JavaScript library

187 lines (186 loc) 6.61 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); exports.signatureBlocksAction = exports.checkInputForSig = exports.pubkeyInScript = exports.pubkeyPositionInScript = exports.witnessStackToScriptWitness = exports.isP2TR = exports.isP2SHScript = exports.isP2WSHScript = exports.isP2WPKH = exports.isP2PKH = exports.isP2PK = exports.isP2MS = void 0; const varuint = require('bip174/src/lib/converter/varint'); const bscript = require('../script'); const transaction_1 = require('../transaction'); const crypto_1 = require('../crypto'); const payments = require('../payments'); function isPaymentFactory(payment) { return script => { try { payment({ output: script }); return true; } catch (err) { return false; } }; } exports.isP2MS = isPaymentFactory(payments.p2ms); exports.isP2PK = isPaymentFactory(payments.p2pk); exports.isP2PKH = isPaymentFactory(payments.p2pkh); exports.isP2WPKH = isPaymentFactory(payments.p2wpkh); exports.isP2WSHScript = isPaymentFactory(payments.p2wsh); exports.isP2SHScript = isPaymentFactory(payments.p2sh); exports.isP2TR = isPaymentFactory(payments.p2tr); /** * Converts a witness stack to a script witness. * @param witness The witness stack to convert. * @returns The script witness as a Buffer. */ /** * Converts a witness stack to a script witness. * @param witness The witness stack to convert. * @returns The converted script witness. */ function witnessStackToScriptWitness(witness) { let buffer = Buffer.allocUnsafe(0); function writeSlice(slice) { buffer = Buffer.concat([buffer, Buffer.from(slice)]); } function writeVarInt(i) { const currentLen = buffer.length; const varintLen = varuint.encodingLength(i); buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); varuint.encode(i, buffer, currentLen); } function writeVarSlice(slice) { writeVarInt(slice.length); writeSlice(slice); } function writeVector(vector) { writeVarInt(vector.length); vector.forEach(writeVarSlice); } writeVector(witness); return buffer; } exports.witnessStackToScriptWitness = witnessStackToScriptWitness; /** * Finds the position of a public key in a script. * @param pubkey The public key to search for. * @param script The script to search in. * @returns The index of the public key in the script, or -1 if not found. * @throws {Error} If there is an unknown script error. */ function pubkeyPositionInScript(pubkey, script) { const pubkeyHash = (0, crypto_1.hash160)(pubkey); const pubkeyXOnly = pubkey.slice(1, 33); // slice before calling? const decompiled = bscript.decompile(script); if (decompiled === null) throw new Error('Unknown script error'); return decompiled.findIndex(element => { if (typeof element === 'number') return false; return ( element.equals(pubkey) || element.equals(pubkeyHash) || element.equals(pubkeyXOnly) ); }); } exports.pubkeyPositionInScript = pubkeyPositionInScript; /** * Checks if a public key is present in a script. * @param pubkey The public key to check. * @param script The script to search in. * @returns A boolean indicating whether the public key is present in the script. */ function pubkeyInScript(pubkey, script) { return pubkeyPositionInScript(pubkey, script) !== -1; } exports.pubkeyInScript = pubkeyInScript; /** * Checks if an input contains a signature for a specific action. * @param input - The input to check. * @param action - The action to check for. * @returns A boolean indicating whether the input contains a signature for the specified action. */ function checkInputForSig(input, action) { const pSigs = extractPartialSigs(input); return pSigs.some(pSig => signatureBlocksAction(pSig, bscript.signature.decode, action), ); } exports.checkInputForSig = checkInputForSig; /** * Determines if a given action is allowed for a signature block. * @param signature - The signature block. * @param signatureDecodeFn - The function used to decode the signature. * @param action - The action to be checked. * @returns True if the action is allowed, false otherwise. */ function signatureBlocksAction(signature, signatureDecodeFn, action) { const { hashType } = signatureDecodeFn(signature); const whitelist = []; const isAnyoneCanPay = hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY; if (isAnyoneCanPay) whitelist.push('addInput'); const hashMod = hashType & 0x1f; switch (hashMod) { case transaction_1.Transaction.SIGHASH_ALL: break; case transaction_1.Transaction.SIGHASH_SINGLE: case transaction_1.Transaction.SIGHASH_NONE: whitelist.push('addOutput'); whitelist.push('setInputSequence'); break; } if (whitelist.indexOf(action) === -1) { return true; } return false; } exports.signatureBlocksAction = signatureBlocksAction; /** * Extracts the signatures from a PsbtInput object. * If the input has partial signatures, it returns an array of the signatures. * If the input does not have partial signatures, it checks if it has a finalScriptSig or finalScriptWitness. * If it does, it extracts the signatures from the final scripts and returns them. * If none of the above conditions are met, it returns an empty array. * * @param input - The PsbtInput object from which to extract the signatures. * @returns An array of signatures extracted from the PsbtInput object. */ function extractPartialSigs(input) { let pSigs = []; if ((input.partialSig || []).length === 0) { if (!input.finalScriptSig && !input.finalScriptWitness) return []; pSigs = getPsigsFromInputFinalScripts(input); } else { pSigs = input.partialSig; } return pSigs.map(p => p.signature); } /** * Retrieves the partial signatures (Psigs) from the input's final scripts. * Psigs are extracted from both the final scriptSig and final scriptWitness of the input. * Only canonical script signatures are considered. * * @param input - The PsbtInput object representing the input. * @returns An array of PartialSig objects containing the extracted Psigs. */ function getPsigsFromInputFinalScripts(input) { const scriptItems = !input.finalScriptSig ? [] : bscript.decompile(input.finalScriptSig) || []; const witnessItems = !input.finalScriptWitness ? [] : bscript.decompile(input.finalScriptWitness) || []; return scriptItems .concat(witnessItems) .filter(item => { return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item); }) .map(sig => ({ signature: sig })); }