Complete script compilation, decompilation, and analysis utilities with support for script validation, ASM representation, and Bitcoin script operations including push data handling and signature validation.
type StackElement = Buffer | number;
type Stack = StackElement[];
/** Operation codes object mapping names to opcodes */
const OPS: { [key: string]: number };Convert between human-readable and binary script formats.
/**
* Compiles an array of chunks into a Buffer
* @param chunks - Array of chunks or raw buffer to compile
* @returns Compiled script Buffer
* @throws Error if compilation fails
*/
function compile(chunks: Buffer | Stack): Buffer;
/**
* Decompiles a script buffer into array of chunks
* @param buffer - Script buffer or array to decompile
* @returns Array of chunks or null if decompilation fails
*/
function decompile(buffer: Buffer | Array<number | Buffer>): Array<number | Buffer> | null;Usage Examples:
import { script } from 'bitcoinjs-lib';
// Compile script from chunks
const chunks = [
script.OPS.OP_DUP,
script.OPS.OP_HASH160,
Buffer.from('a54d79f79f1f7b7e2d3e8b4f8c7a6e9f8c7a6e9f', 'hex'),
script.OPS.OP_EQUALVERIFY,
script.OPS.OP_CHECKSIG
];
const compiledScript = script.compile(chunks);
console.log('P2PKH script:', compiledScript.toString('hex'));
// Decompile script to chunks
const scriptBuffer = Buffer.from('76a914a54d79f7...88ac', 'hex');
const decompiled = script.decompile(scriptBuffer);
console.log('Decompiled chunks:', decompiled);Convert scripts to and from human-readable ASM format.
/**
* Converts chunks into ASM (Assembly) string representation
* @param chunks - Chunks to convert or buffer to decompile first
* @returns ASM string representation
*/
function toASM(chunks: Buffer | Array<number | Buffer>): string;
/**
* Converts ASM string to script buffer
* @param asm - ASM string to convert
* @returns Compiled script buffer
*/
function fromASM(asm: string): Buffer;Usage Examples:
import { script } from 'bitcoinjs-lib';
// Script to ASM
const p2pkhScript = Buffer.from('76a914a54d79f7...88ac', 'hex');
const asm = script.toASM(p2pkhScript);
console.log('P2PKH ASM:', asm);
// Output: "OP_DUP OP_HASH160 a54d79f79f1f7b7e2d3e8b4f8c7a6e9f8c7a6e9f OP_EQUALVERIFY OP_CHECKSIG"
// ASM to script
const asmString = 'OP_DUP OP_HASH160 a54d79f79f1f7b7e2d3e8b4f8c7a6e9f8c7a6e9f OP_EQUALVERIFY OP_CHECKSIG';
const scriptFromAsm = script.fromASM(asmString);
console.log('Script from ASM:', scriptFromAsm.toString('hex'));
// Multisig ASM
const multisigAsm = '2 03a34b... 03b45c... 03c56d... 3 OP_CHECKMULTISIG';
const multisigScript = script.fromASM(multisigAsm);Convert scripts to stack format for execution analysis.
/**
* Converts chunks into stack of buffers
* @param chunks - Chunks to convert or buffer to decompile first
* @returns Stack of buffers
*/
function toStack(chunks: Buffer | Array<number | Buffer>): Buffer[];Usage Examples:
import { script } from 'bitcoinjs-lib';
const scriptSig = Buffer.from('473044...', 'hex'); // Signature + pubkey
const stack = script.toStack(scriptSig);
console.log('Stack items:', stack.length);
console.log('Signature:', stack[0].toString('hex'));
console.log('Public key:', stack[1].toString('hex'));Analyze script properties and validation.
/**
* Check if stack contains only push operations (no opcodes)
* @param value - Stack to analyze
* @returns True if contains only push operations
*/
function isPushOnly(value: Stack): boolean;
/**
* Count non-push operations in stack
* @param value - Stack to analyze
* @returns Number of non-push operations
*/
function countNonPushOnlyOPs(value: Stack): number;
/**
* Check if buffer contains canonical public key
* @param buffer - Buffer to check
* @returns True if canonical public key format
*/
function isCanonicalPubKey(buffer: Buffer): boolean;
/**
* Check if hash type is valid/defined
* @param hashType - Hash type to check
* @returns True if valid hash type
*/
function isDefinedHashType(hashType: number): boolean;
/**
* Check if buffer contains canonical script signature
* @param buffer - Buffer to check
* @returns True if canonical signature format
*/
function isCanonicalScriptSignature(buffer: Buffer): boolean;Usage Examples:
import { script } from 'bitcoinjs-lib';
// Analyze P2PKH scriptSig (should be push-only)
const p2pkhScriptSig = [
Buffer.from('3044...', 'hex'), // signature
Buffer.from('03a34b...', 'hex') // pubkey
];
console.log('Is push only:', script.isPushOnly(p2pkhScriptSig)); // true
console.log('Non-push ops:', script.countNonPushOnlyOPs(p2pkhScriptSig)); // 0
// Analyze public key
const pubkey = Buffer.from('03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd', 'hex');
console.log('Is canonical pubkey:', script.isCanonicalPubKey(pubkey)); // true
// Check signature
const signature = Buffer.from('3044...01', 'hex'); // DER + SIGHASH_ALL
console.log('Is canonical signature:', script.isCanonicalScriptSignature(signature));
// Check hash type
console.log('Valid hash type:', script.isDefinedHashType(0x01)); // true
console.log('Invalid hash type:', script.isDefinedHashType(0xFF)); // falseHandle Bitcoin script number encoding and decoding.
const number: {
/**
* Decode script number from buffer
* @param buffer - Buffer containing script number
* @param maxLength - Maximum length of script number (default: 4)
* @param minimal - Whether encoding should be minimal (default: true)
* @returns Decoded number
* @throws TypeError if number overflows or isn't minimal
*/
decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number;
/**
* Encode number into script number buffer
* @param _number - Number to encode
* @returns Encoded number as buffer
*/
encode(_number: number): Buffer;
};Usage Examples:
import { script } from 'bitcoinjs-lib';
// Encode numbers for scripts
const encoded1 = script.number.encode(1);
const encoded42 = script.number.encode(42);
const encodedNeg1 = script.number.encode(-1);
console.log('Encoded 1:', encoded1.toString('hex')); // '01'
console.log('Encoded 42:', encoded42.toString('hex')); // '2a'
console.log('Encoded -1:', encodedNeg1.toString('hex')); // '81'
// Decode script numbers
const decoded1 = script.number.decode(Buffer.from('01', 'hex'));
const decoded42 = script.number.decode(Buffer.from('2a', 'hex'));
const decodedNeg1 = script.number.decode(Buffer.from('81', 'hex'));
console.log('Decoded:', decoded1, decoded42, decodedNeg1); // 1, 42, -1
// Handle OP_1 through OP_16 (special encoding)
const op2Chunks = [script.OPS.OP_2]; // Represents number 2
const op2Script = script.compile(op2Chunks);
console.log('OP_2 script:', op2Script.toString('hex')); // '52'Handle Bitcoin script signature encoding and decoding.
const signature: {
/**
* Decode script signature buffer
* @param buffer - Buffer containing signature and hash type
* @returns Object with signature and hash type
* @throws Error if hash type is invalid
*/
decode(buffer: Buffer): { signature: Buffer; hashType: number };
/**
* Encode signature and hash type into buffer
* @param signature - DER-encoded signature
* @param hashType - Signature hash type
* @returns Encoded signature buffer
* @throws Error if hash type is invalid
*/
encode(signature: Buffer, hashType: number): Buffer;
};Usage Examples:
import { script, Transaction } from 'bitcoinjs-lib';
// Encode signature with hash type
const derSig = Buffer.from('3044...', 'hex'); // DER signature
const hashType = Transaction.SIGHASH_ALL;
const encodedSig = script.signature.encode(derSig, hashType);
console.log('Encoded signature:', encodedSig.toString('hex'));
// Decode signature from scriptSig
const scriptSigBuffer = Buffer.from('473044...01', 'hex');
const decoded = script.signature.decode(scriptSigBuffer);
console.log('DER signature:', decoded.signature.toString('hex'));
console.log('Hash type:', decoded.hashType); // 1 (SIGHASH_ALL)
// Handle different hash types
const sighashNone = script.signature.encode(derSig, Transaction.SIGHASH_NONE);
const sighashSingle = script.signature.encode(derSig, Transaction.SIGHASH_SINGLE);
const sighashAnyoneCanPay = script.signature.encode(derSig, Transaction.SIGHASH_ANYONECANPAY);Access Bitcoin operation codes and their reverse mappings.
/** Operation codes mapping names to numbers */
const OPS: {
// Push data
OP_0: 0;
OP_PUSHDATA1: 76;
OP_PUSHDATA2: 77;
OP_PUSHDATA4: 78;
OP_1NEGATE: 79;
OP_1: 81;
OP_2: 82;
// ... (all other opcodes)
OP_CHECKSIG: 172;
OP_CHECKSIGVERIFY: 173;
OP_CHECKMULTISIG: 174;
OP_CHECKMULTISIGVERIFY: 175;
// ... etc
};
/** Reverse mapping from opcode numbers to names */
const REVERSE_OPS: { [key: number]: string };Usage Examples:
import { script } from 'bitcoinjs-lib';
// Use opcodes in scripts
const p2pkhTemplate = [
script.OPS.OP_DUP,
script.OPS.OP_HASH160,
// 20-byte pubkey hash goes here
script.OPS.OP_EQUALVERIFY,
script.OPS.OP_CHECKSIG
];
// Numbers for multisig
const multisig2of3 = [
script.OPS.OP_2, // m = 2
// pubkeys go here
script.OPS.OP_3, // n = 3
script.OPS.OP_CHECKMULTISIG
];
// Check specific opcodes
console.log('OP_CHECKSIG:', script.OPS.OP_CHECKSIG); // 172
console.log('OP_RETURN:', script.OPS.OP_RETURN); // 106
// Reverse lookup
console.log('Opcode 172:', script.REVERSE_OPS[172]); // 'OP_CHECKSIG'Build complex scripts programmatically:
import { script, crypto } from 'bitcoinjs-lib';
// Create P2PKH script
function createP2PKH(pubkeyHash: Buffer): Buffer {
return script.compile([
script.OPS.OP_DUP,
script.OPS.OP_HASH160,
pubkeyHash,
script.OPS.OP_EQUALVERIFY,
script.OPS.OP_CHECKSIG
]);
}
// Create multisig script
function createMultisig(m: number, pubkeys: Buffer[]): Buffer {
const chunks = [
script.OPS[`OP_${m}` as keyof typeof script.OPS],
...pubkeys,
script.OPS[`OP_${pubkeys.length}` as keyof typeof script.OPS],
script.OPS.OP_CHECKMULTISIG
];
return script.compile(chunks);
}
// Create timelock script
function createTimelock(locktime: number, pubkeyHash: Buffer): Buffer {
return script.compile([
script.number.encode(locktime),
script.OPS.OP_CHECKLOCKTIMEVERIFY,
script.OPS.OP_DROP,
script.OPS.OP_DUP,
script.OPS.OP_HASH160,
pubkeyHash,
script.OPS.OP_EQUALVERIFY,
script.OPS.OP_CHECKSIG
]);
}Analyze scripts for debugging and understanding:
import { script } from 'bitcoinjs-lib';
function analyzeScript(scriptBuffer: Buffer): void {
console.log('Raw script:', scriptBuffer.toString('hex'));
const chunks = script.decompile(scriptBuffer);
if (!chunks) {
console.log('Failed to decompile script');
return;
}
console.log('ASM:', script.toASM(scriptBuffer));
console.log('Chunks:', chunks.length);
console.log('Is push only:', script.isPushOnly(chunks));
console.log('Non-push ops:', script.countNonPushOnlyOPs(chunks));
// Analyze each chunk
chunks.forEach((chunk, i) => {
if (Buffer.isBuffer(chunk)) {
console.log(`Chunk ${i}: DATA(${chunk.length}) ${chunk.toString('hex')}`);
} else {
const opName = script.REVERSE_OPS[chunk] || `UNKNOWN(${chunk})`;
console.log(`Chunk ${i}: ${opName}`);
}
});
}
// Analyze different script types
const p2pkhScript = Buffer.from('76a914...88ac', 'hex');
analyzeScript(p2pkhScript);Handle witness scripts for SegWit transactions:
import { script } from 'bitcoinjs-lib';
// Witness script for P2WSH
const witnessScript = script.compile([
script.OPS.OP_2,
Buffer.from('03a34b...', 'hex'),
Buffer.from('03b45c...', 'hex'),
Buffer.from('03c56d...', 'hex'),
script.OPS.OP_3,
script.OPS.OP_CHECKMULTISIG
]);
console.log('Witness script:', witnessScript.toString('hex'));
console.log('Witness script ASM:', script.toASM(witnessScript));
// Create P2WSH output script
const witnessScriptHash = crypto.sha256(witnessScript);
const p2wshOutput = script.compile([script.OPS.OP_0, witnessScriptHash]);
console.log('P2WSH output:', p2wshOutput.toString('hex'));type StackElement = Buffer | number;
type Stack = StackElement[];
interface ScriptSignature {
signature: Buffer;
hashType: number;
}