The Signature class in the BSV TypeScript SDK provides comprehensive functionality for creating, managing, and verifying ECDSA (Elliptic Curve Digital Signature Algorithm) signatures used in Bitcoin transactions. It handles DER encoding/decoding, sighash type management, and signature verification operations that are fundamental to Bitcoin's security model.
Purpose
Create and verify ECDSA signatures for Bitcoin transactions
Handle DER (Distinguished Encoding Rules) encoding and decoding of signatures
Manage sighash types and flags for transaction signing
Support various signature formats (DER, compact, raw R and S values)
Provide cryptographic verification of signatures against public keys
Enable custom signature operations for advanced Bitcoin Script use cases
Basic Usage
import{Signature,PrivateKey,PublicKey,Hash}from'@bsv/sdk';// Sign a message hash with a private keyconstprivKey=PrivateKey.fromRandom();constmessageHash=Hash.sha256(Array.from(Buffer.from('Hello BSV')));// Create signatureconstsignature=privKey.sign(messageHash);// Verify signatureconstpubKey=privKey.toPublicKey();constisValid=signature.verify(messageHash,pubKey);console.log('Signature valid:',isValid);// true// Get DER encoding of signatureconstderEncoded=signature.toDER();console.log('DER:',Buffer.from(derEncoded).toString('hex'));// Parse DER encoded signatureconstparsedSig=Signature.fromDER(derEncoded);console.log('Parsed signature equals original:',Buffer.from(parsedSig.toDER()).equals(Buffer.from(signature.toDER())));// true
Key Features
1. Creating Signatures with Sighash Types
Sighash types control which parts of a transaction are signed, enabling various transaction patterns:
2. DER Encoding and Decoding
DER encoding is the standard format for signatures in Bitcoin transactions:
3. Low-S Signature Normalization
Bitcoin requires signatures to use low-S values (S <= N/2) to prevent transaction malleability:
4. Signature Recovery and Verification
Signatures can be verified against public keys, and public keys can be recovered from signatures:
API Reference
Constructor
Creates a new Signature instance with R and S values.
Parameters:
r: bigint - The R component of the ECDSA signature
s: bigint - The S component of the ECDSA signature
recoveryParam?: number - Optional recovery parameter (0-3) for public key recovery
Converts signature to format used in Bitcoin Script CHECKSIG operations (DER + sighash byte).
Returns:number[] - DER signature with sighash type appended
Instance Properties
Common Patterns
Pattern 1: Transaction Signature Creation
Creating signatures for Bitcoin transaction inputs:
Pattern 2: Message Signing and Verification
Signing arbitrary messages for proof of ownership:
Pattern 3: Multi-Signature Verification
Verifying multiple signatures for multi-sig transactions:
Security Considerations
Always Use Low-S Signatures: The SDK automatically normalizes signatures to use low-S values to prevent transaction malleability. Never modify this behavior.
Deterministic vs Random K Values: Using ephemeralKey: true enables RFC 6979 deterministic signatures, which is more secure than random k values that could leak private keys if reused.
Hash Before Signing: Always hash your data before signing. Never sign raw data directly.
Sighash Type Validation: Ensure the correct sighash type is used for your use case. SIGHASH_ALL is the most secure default.
Signature Malleability: DER encoding prevents signature malleability. Always use DER format for transaction signatures.
Private Key Protection: Never expose private keys. Keep them in secure storage and use them only for signature generation.
Performance Considerations
Signature Verification: ECDSA verification is computationally expensive. Cache verification results when possible.
Batch Verification: When verifying multiple signatures, consider implementing batch verification algorithms for better performance.
DER Encoding Overhead: DER encoding adds 6-8 bytes overhead compared to compact format. Use compact format for storage when sighash type is not needed.
Deterministic Signatures: RFC 6979 deterministic signatures are slightly slower than random k values but provide better security.
signature.r // bigint - The R component
signature.s // bigint - The S component
signature.scope // number - Sighash type (SIGHASH_ALL, SIGHASH_NONE, etc.)
signature.recoveryParam // number | undefined - Recovery parameter for pubkey recovery
import {
Transaction,
PrivateKey,
PublicKey,
Signature,
Hash,
SighashType
} from '@bsv/sdk';
// Transaction signing workflow
const privKey = PrivateKey.fromWif('L5EY1SbTvvPNSdCYQe1EJHfXCBBT4PmnF6CDbzCm9iifZptUvDGB');
const pubKey = privKey.toPublicKey();
// Create transaction
const tx = new Transaction();
// ... add inputs and outputs ...
// Get sighash preimage for input 0
const inputIndex = 0;
const sighashType = SighashType.SIGHASH_ALL | SighashType.SIGHASH_FORKID;
// Calculate transaction hash to sign
const preimage = tx.getPreimage(inputIndex, sighashType);
const txHash = Hash.sha256sha256(preimage);
// Create signature
const signature = Signature.sign(txHash, privKey, true);
signature.scope = sighashType;
// Convert to format for unlocking script
const sigBytes = signature.toChecksigFormat();
// Create unlocking script (scriptSig)
import { Script, OP } from '@bsv/sdk';
const unlockingScript = new Script()
.writeBin(sigBytes)
.writeBin(pubKey.encode(true)); // compressed public key
console.log('Unlocking script created:', unlockingScript.toHex());
// Ensure sighash type matches
signature.scope = SighashType.SIGHASH_ALL | SighashType.SIGHASH_FORKID;
const sigBytes = signature.toChecksigFormat(); // Includes sighash byte
// SDK handles this automatically, but if working with raw values:
const curveN = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
if (signature.s > curveN / 2n) {
signature.s = curveN - signature.s; // Normalize to low-S
}
// Create signature with recovery information
const signature = Signature.sign(hash, privKey, true);
console.log('Recovery param:', signature.recoveryParam); // Should be 0-3