Signatures

Overview

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 key
const privKey = PrivateKey.fromRandom();
const messageHash = Hash.sha256(Array.from(Buffer.from('Hello BSV')));

// Create signature
const signature = privKey.sign(messageHash);

// Verify signature
const pubKey = privKey.toPublicKey();
const isValid = signature.verify(messageHash, pubKey);
console.log('Signature valid:', isValid); // true

// Get DER encoding of signature
const derEncoded = signature.toDER();
console.log('DER:', Buffer.from(derEncoded).toString('hex'));
// Parse DER encoded signature
const parsedSig = 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

Static Methods

Signature.sign(hash: number[], privKey: PrivateKey, ephemeralKey?: boolean): Signature

Creates a signature for a given hash using a private key.

Parameters:

  • hash: number[] - The hash to sign (typically 32 bytes)

  • privKey: PrivateKey - The private key to sign with

  • ephemeralKey?: boolean - Whether to use deterministic (RFC 6979) or random k value

Returns: Signature - The created signature

Example:

Signature.fromDER(der: number[] | Buffer): Signature

Parses a DER-encoded signature.

Parameters:

  • der: number[] | Buffer - The DER-encoded signature bytes

Returns: Signature - The parsed signature

Signature.fromCompact(compact: number[] | Buffer): Signature

Parses a compact 64-byte signature format.

Parameters:

  • compact: number[] | Buffer - The compact signature (32 bytes R + 32 bytes S)

Returns: Signature - The parsed signature

Instance Methods

verify(hash: number[], pubKey: PublicKey): boolean

Verifies the signature against a hash and public key.

Parameters:

  • hash: number[] - The hash that was signed

  • pubKey: PublicKey - The public key to verify against

Returns: boolean - True if signature is valid

toDER(): number[]

Converts the signature to DER encoding.

Returns: number[] - DER-encoded signature bytes

toCompact(): number[]

Converts the signature to compact 64-byte format.

Returns: number[] - Compact signature (32 bytes R + 32 bytes S)

toChecksigFormat(): number[]

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

  1. Always Use Low-S Signatures: The SDK automatically normalizes signatures to use low-S values to prevent transaction malleability. Never modify this behavior.

  2. 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.

  3. Hash Before Signing: Always hash your data before signing. Never sign raw data directly.

  4. Sighash Type Validation: Ensure the correct sighash type is used for your use case. SIGHASH_ALL is the most secure default.

  5. Signature Malleability: DER encoding prevents signature malleability. Always use DER format for transaction signatures.

  6. Private Key Protection: Never expose private keys. Keep them in secure storage and use them only for signature generation.

Performance Considerations

  1. Signature Verification: ECDSA verification is computationally expensive. Cache verification results when possible.

  2. Batch Verification: When verifying multiple signatures, consider implementing batch verification algorithms for better performance.

  3. 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.

  4. Deterministic Signatures: RFC 6979 deterministic signatures are slightly slower than random k values but provide better security.

  • PrivateKey - Generate private keys for signing

  • PublicKey - Verify signatures and derive addresses

  • Transaction - Use signatures in transaction inputs

  • Script - Include signatures in Bitcoin Script

Code Examples

See complete working examples in:

Best Practices

  1. Always use deterministic signatures (RFC 6979) by setting ephemeralKey: true in Signature.sign()

  2. Verify sighash types match your transaction signing requirements before broadcasting

  3. Use low-S signatures to prevent transaction malleability (automatic in SDK)

  4. Hash your data with SHA-256 or SHA-256d before signing

  5. Include recovery parameters when you need public key recovery from signatures

  6. Validate signatures before accepting them in your application logic

  7. Use appropriate sighash flags for your specific transaction pattern (ANYONECANPAY for crowdfunding, etc.)

  8. Store signatures in DER format for Bitcoin transactions

  9. Never reuse signatures across different messages or transactions

  10. Implement proper error handling for signature verification failures

Troubleshooting

Issue: Signature verification fails

Solution: Ensure you're using the same hash that was signed and the correct public key.

Issue: Transaction signature invalid

Solution: Verify you're using the correct sighash type and preimage.

Issue: DER encoding error

Solution: Ensure R and S values are valid and properly normalized.

Issue: Cannot recover public key from signature

Solution: Ensure the signature was created with a recovery parameter.

Further Reading

Status

✅ Complete

Last updated