> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/mahdiyari/hive-tx/llms.txt
> Use this file to discover all available pages before exploring further.

# Signature

> ECDSA signature creation, verification, and public key recovery

## Overview

The `Signature` class handles ECDSA (secp256k1) signatures for the Hive blockchain. It provides methods for creating signatures, verifying them, recovering public keys, and converting between different signature formats.

Signatures include recovery information that allows the original public key to be recovered from the signature and message, which is essential for Hive's signature verification system.

## Constructor

```typescript theme={null}
const signature = new Signature(data, recovery, compressed?)
```

<ParamField path="data" type="Uint8Array" required>
  Raw signature data (64 bytes: 32 bytes r-value + 32 bytes s-value)
</ParamField>

<ParamField path="recovery" type="number" required>
  Recovery byte (0-3) used to recover the public key
</ParamField>

<ParamField path="compressed" type="boolean" optional default="true">
  Whether the signature uses compressed format (default: true)
</ParamField>

### Example

```typescript theme={null}
import { Signature } from 'hive-tx'

// Create from raw components
const data = new Uint8Array(64) // 64-byte signature data
const recovery = 0 // Recovery parameter (0-3)
const signature = new Signature(data, recovery, true)
```

## Static Methods

### from

Creates a Signature from a hex string.

```typescript theme={null}
const signature = Signature.from(hexString)
```

<ParamField path="hexString" type="string" required>
  130-character hex string containing recovery byte and signature data
</ParamField>

<ResponseField name="returns" type="Signature">
  New Signature instance
</ResponseField>

#### Example

```typescript theme={null}
import { Signature } from 'hive-tx'

// From hex string (130 characters: 2 for recovery + 128 for signature)
const sigHex = '1f8a7b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f'
const signature = Signature.from(sigHex)

console.log('Recovery:', signature.recovery)
console.log('Data length:', signature.data.length) // 64
```

## Instance Methods

### customToString

Returns the signature as a 130-character hex string.

```typescript theme={null}
const hexString = signature.customToString()
```

<ResponseField name="returns" type="string">
  130-character hex string representation of the signature
</ResponseField>

#### Example

```typescript theme={null}
import { PrivateKey, Transaction } from 'hive-tx'

// Create and sign a transaction
const privateKey = PrivateKey.fromLogin('alice', 'password', 'active')
const tx = new Transaction()
await tx.addOperation('vote', {
  voter: 'alice',
  author: 'bob',
  permlink: 'my-post',
  weight: 10000
})

const { digest } = tx.digest()
const signature = privateKey.sign(digest)

// Convert to hex string
const sigHex = signature.customToString()
console.log('Signature hex:', sigHex)
console.log('Length:', sigHex.length) // 130
```

### toBuffer

Converts the signature to a 65-byte buffer format (recovery byte + signature data).

```typescript theme={null}
const buffer = signature.toBuffer()
```

<ResponseField name="returns" type="Uint8Array">
  65-byte buffer containing recovery byte + 64-byte signature data
</ResponseField>

#### Example

```typescript theme={null}
import { PrivateKey } from 'hive-tx'
import { sha256 } from '@noble/hashes/sha2'

const privateKey = PrivateKey.fromLogin('alice', 'password', 'active')
const message = sha256('Hello, Hive!')
const signature = privateKey.sign(message)

// Get buffer representation
const buffer = signature.toBuffer()
console.log('Buffer length:', buffer.length) // 65
console.log('Recovery byte:', buffer[0])
console.log('Signature data:', buffer.subarray(1))
```

### getPublicKey

Recovers the public key from this signature and message hash. This is one of the most powerful features of ECDSA signatures on Hive.

```typescript theme={null}
const publicKey = signature.getPublicKey(message)
```

<ParamField path="message" type="Uint8Array | string" required>
  32-byte message hash as Uint8Array or 64-character hex string (must be a valid SHA256 hash)
</ParamField>

<ResponseField name="returns" type="PublicKey">
  Recovered public key that created this signature
</ResponseField>

#### Example

```typescript theme={null}
import { PrivateKey, Transaction } from 'hive-tx'

// Sign a transaction
const privateKey = PrivateKey.fromLogin('alice', 'password', 'active')
const expectedPublicKey = privateKey.createPublic()

const tx = new Transaction()
await tx.addOperation('transfer', {
  from: 'alice',
  to: 'bob',
  amount: '1.000 HIVE',
  memo: ''
})

const { digest } = tx.digest()
const signature = privateKey.sign(digest)

// Recover public key from signature
const recoveredPublicKey = signature.getPublicKey(digest)

// Verify they match
console.log('Expected:', expectedPublicKey.toString())
console.log('Recovered:', recoveredPublicKey.toString())
console.log('Match:', expectedPublicKey.toString() === recoveredPublicKey.toString())
// Output: true
```

## Creating Signatures

Signatures are typically created using a PrivateKey:

```typescript theme={null}
import { PrivateKey } from 'hive-tx'
import { sha256 } from '@noble/hashes/sha2'

const privateKey = PrivateKey.fromLogin('alice', 'password', 'posting')

// Sign a message
const message = sha256('My message to sign')
const signature = privateKey.sign(message)

console.log('Signature:', signature.customToString())
console.log('Recovery:', signature.recovery)
```

## Verifying Signatures

There are two ways to verify signatures:

### Method 1: Using PublicKey.verify

```typescript theme={null}
import { PrivateKey } from 'hive-tx'
import { sha256 } from '@noble/hashes/sha2'

const privateKey = PrivateKey.fromLogin('alice', 'password', 'active')
const publicKey = privateKey.createPublic()
const message = sha256('Message to verify')
const signature = privateKey.sign(message)

// Verify using PublicKey
const isValid = publicKey.verify(message, signature)
console.log('Signature valid:', isValid) // true

// Verify with wrong message
const wrongMessage = sha256('Different message')
const isInvalid = publicKey.verify(wrongMessage, signature)
console.log('Wrong message:', isInvalid) // false
```

### Method 2: Using Signature.getPublicKey

```typescript theme={null}
import { PrivateKey } from 'hive-tx'
import { sha256 } from '@noble/hashes/sha2'

const privateKey = PrivateKey.fromLogin('alice', 'password', 'active')
const expectedPublicKey = privateKey.createPublic()
const message = sha256('Message to verify')
const signature = privateKey.sign(message)

// Recover public key and compare
const recoveredPublicKey = signature.getPublicKey(message)
const isValid = recoveredPublicKey.toString() === expectedPublicKey.toString()
console.log('Signature valid:', isValid) // true
```

## Transaction Signing Example

```typescript theme={null}
import { Transaction, PrivateKey, Signature } from 'hive-tx'

async function signAndVerifyTransaction() {
  // Create transaction
  const tx = new Transaction()
  await tx.addOperation('vote', {
    voter: 'alice',
    author: 'bob',
    permlink: 'awesome-post',
    weight: 10000
  })
  
  // Sign with private key
  const privateKey = PrivateKey.fromLogin('alice', 'password', 'posting')
  const signedTx = tx.sign(privateKey)
  
  // Get the signature from the transaction
  const signatureHex = signedTx.signatures[0]
  const signature = Signature.from(signatureHex)
  
  // Verify signature
  const { digest } = tx.digest()
  const publicKey = privateKey.createPublic()
  const isValid = publicKey.verify(digest, signature)
  
  console.log('Transaction signed:', signatureHex)
  console.log('Signature valid:', isValid)
  
  // Broadcast
  const result = await tx.broadcast()
  console.log('Transaction ID:', result.tx_id)
}

signAndVerifyTransaction()
```

## External Signature Application

You can sign externally (e.g., with hardware wallets) and apply the signature:

```typescript theme={null}
import { Transaction, PrivateKey, Signature } from 'hive-tx'

async function externalSigning() {
  // Create transaction
  const tx = new Transaction()
  await tx.addOperation('transfer', {
    from: 'alice',
    to: 'bob',
    amount: '5.000 HIVE',
    memo: ''
  })
  
  // Get digest for external signing
  const { digest, txId } = tx.digest()
  console.log('Transaction ID:', txId)
  console.log('Digest to sign:', Buffer.from(digest).toString('hex'))
  
  // Sign externally (simulated here with actual key)
  const privateKey = PrivateKey.fromLogin('alice', 'password', 'active')
  const signature = privateKey.sign(digest)
  const signatureHex = signature.customToString()
  
  console.log('External signature:', signatureHex)
  
  // Apply signature to transaction
  tx.addSignature(signatureHex)
  
  // Verify before broadcasting
  const publicKey = privateKey.createPublic()
  const sig = Signature.from(signatureHex)
  const isValid = publicKey.verify(digest, sig)
  console.log('Signature valid:', isValid)
  
  if (isValid) {
    const result = await tx.broadcast()
    console.log('Broadcast successful:', result.tx_id)
  }
}

externalSigning()
```

## Multi-Signature Transactions

```typescript theme={null}
import { Transaction, PrivateKey } from 'hive-tx'

async function multiSigTransaction() {
  const tx = new Transaction()
  await tx.addOperation('transfer', {
    from: 'multisig-account',
    to: 'recipient',
    amount: '100.000 HIVE',
    memo: 'Multi-sig payment'
  })
  
  // Get digest once
  const { digest } = tx.digest()
  
  // Sign with first key
  const key1 = PrivateKey.fromString(process.env.SIGNER1_KEY!)
  const sig1 = key1.sign(digest)
  tx.addSignature(sig1.customToString())
  
  // Sign with second key
  const key2 = PrivateKey.fromString(process.env.SIGNER2_KEY!)
  const sig2 = key2.sign(digest)
  tx.addSignature(sig2.customToString())
  
  // Sign with third key
  const key3 = PrivateKey.fromString(process.env.SIGNER3_KEY!)
  const sig3 = key3.sign(digest)
  tx.addSignature(sig3.customToString())
  
  console.log('Signatures:', tx.transaction?.signatures.length)
  
  // Verify all signatures
  for (let i = 0; i < tx.transaction!.signatures.length; i++) {
    const sig = Signature.from(tx.transaction!.signatures[i])
    const recoveredKey = sig.getPublicKey(digest)
    console.log(`Signer ${i + 1} public key:`, recoveredKey.toString())
  }
  
  // Broadcast
  const result = await tx.broadcast()
  console.log('Multi-sig transaction broadcast:', result.tx_id)
}

multiSigTransaction()
```

## Signature Format

Hive signatures use the following format:

```
[RECOVERY_BYTE][R_VALUE][S_VALUE]
```

* **Recovery byte**: 1 byte (values 31-34 for compressed, 27-30 for uncompressed)
* **R value**: 32 bytes (signature component)
* **S value**: 32 bytes (signature component)
* **Total**: 65 bytes → 130 hex characters

### Format Breakdown

```typescript theme={null}
import { PrivateKey } from 'hive-tx'
import { sha256 } from '@noble/hashes/sha2'

const privateKey = PrivateKey.fromLogin('alice', 'password', 'active')
const message = sha256('Example message')
const signature = privateKey.sign(message)

const hex = signature.customToString()
console.log('Full signature:', hex)
console.log('Length:', hex.length) // 130

const buffer = signature.toBuffer()
console.log('Recovery byte:', buffer[0].toString(16)) // Usually 1f-22
console.log('R value:', Buffer.from(buffer.subarray(1, 33)).toString('hex'))
console.log('S value:', Buffer.from(buffer.subarray(33, 65)).toString('hex'))
```

## Properties

<ResponseField name="data" type="Uint8Array">
  64-byte signature data (r-value + s-value)
</ResponseField>

<ResponseField name="recovery" type="number">
  Recovery parameter (0-3) used to recover the public key
</ResponseField>

## Error Handling

```typescript theme={null}
import { Signature } from 'hive-tx'

try {
  // Invalid hex string
  const sig1 = Signature.from('invalid')
} catch (error) {
  console.error('Invalid signature hex:', error.message)
}

try {
  // Wrong message length
  const sig = Signature.from('1f' + '00'.repeat(64))
  const invalidMessage = new Uint8Array(16) // Should be 32 bytes
  sig.getPublicKey(invalidMessage)
} catch (error) {
  console.error('Invalid message:', error.message)
  // Output: Expected a valid sha256 hash as message
}
```

## See Also

* [PrivateKey](/api/private-key) - Private key management and signing
* [PublicKey](/api/public-key) - Public key management and verification
* [Transaction](/api/transaction) - Transaction signing and broadcasting
