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

# Keys and Signatures

> Understanding cryptographic keys, signatures, and encryption in hive-tx

Cryptographic keys are fundamental to blockchain security. hive-tx provides complete implementations of Hive's key system through the `PrivateKey`, `PublicKey`, and `Signature` classes.

## Key Hierarchy

Hive uses ECDSA (secp256k1) keys, the same cryptographic system as Bitcoin. Each account has multiple key types with different permission levels:

<Steps>
  <Step title="Owner Key">
    Highest authority. Used to change all other keys and recover accounts. Keep this offline and secure.
  </Step>

  <Step title="Active Key">
    Financial authority. Required for transfers, powering up/down, and account updates.
  </Step>

  <Step title="Posting Key">
    Content authority. Used for voting, posting, following, and other social actions. Safe for apps.
  </Step>

  <Step title="Memo Key">
    Encryption authority. Used to encrypt/decrypt transfer memos. Not used for signing transactions.
  </Step>
</Steps>

<Warning>
  Never share your private keys with untrusted applications. Posting keys are safer for apps since they can't access funds.
</Warning>

## PrivateKey Class

The `PrivateKey` class handles all private key operations: creation, signing, and key derivation.

### Creating Private Keys

#### From WIF String

Wallet Import Format (WIF) is the standard way to store and transmit private keys:

```typescript src/helpers/PrivateKey.ts:57 theme={null}
import { PrivateKey } from 'hive-tx'

const key = PrivateKey.from('5JdeC9P7Pbd1uGdFVEsJ41EkEnADbbHGq6p1BwFxm6txNBsQnsw')
```

#### Generate Random Key

Create a cryptographically secure random key:

```typescript src/helpers/PrivateKey.ts:179 theme={null}
const randomKey = PrivateKey.randomKey()
console.log(randomKey.toString()) // WIF format
```

<Info>
  Random key generation may take up to 250ms due to secure entropy collection. This is normal and ensures cryptographic security.
</Info>

#### From Seed

Derive a key from a seed string or bytes:

```typescript src/helpers/PrivateKey.ts:83 theme={null}
// From string seed
const keyFromSeed = PrivateKey.fromSeed('my-secret-seed')

// From hex seed
const keyFromHex = PrivateKey.fromSeed('a1b2c3d4e5f6...')

// From bytes
const bytes = new Uint8Array([1, 2, 3, ...])
const keyFromBytes = PrivateKey.fromSeed(bytes)
```

The seed is hashed with SHA256 to produce the 32-byte private key.

#### From Login Credentials

Generate keys from username and password using Hive's standard derivation:

```typescript src/helpers/PrivateKey.ts:105 theme={null}
const postingKey = PrivateKey.fromLogin('alice', 'password', 'posting')
const activeKey = PrivateKey.fromLogin('alice', 'password', 'active')
const ownerKey = PrivateKey.fromLogin('alice', 'password', 'owner')
const memoKey = PrivateKey.fromLogin('alice', 'password', 'memo')
```

This uses the formula: `SHA256(username + role + password)`

<Tip>
  Login-based keys match what Hive wallets generate. This is perfect for apps that authenticate with username/password instead of storing WIF keys.
</Tip>

### Signing Messages

Sign a 32-byte hash to create a recoverable signature:

```typescript src/helpers/PrivateKey.ts:117 theme={null}
import { sha256 } from '@noble/hashes/sha2'

const message = new TextEncoder().encode('Hello Hive')
const hash = sha256(message)  // Must be 32 bytes

const signature = key.sign(hash)
console.log(signature.customToString()) // 130-character hex string
```

<Warning>
  The `sign()` method expects a 32-byte hash, not the raw message. Always hash your message first with SHA256.
</Warning>

### Deriving Public Keys

Every private key has a corresponding public key:

```typescript src/helpers/PrivateKey.ts:133 theme={null}
const privateKey = PrivateKey.from('5JdeC9P7Pbd1uGdFVEsJ41Ek...')
const publicKey = privateKey.createPublic()

console.log(publicKey.toString())
// Output: STM8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA
```

Optionally specify a custom address prefix:

```typescript theme={null}
const testnetPubKey = privateKey.createPublic('TST')
// Output: TST8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA
```

### Exporting Private Keys

#### As WIF String

```typescript src/helpers/PrivateKey.ts:143 theme={null}
const wif = key.toString()
console.log(wif) // 5JdeC9P7Pbd1uGdFVEsJ41EkEnADbbHGq6p1BwFxm6txNBsQnsw
```

#### Safe Logging

For debugging without exposing the full key:

```typescript src/helpers/PrivateKey.ts:154 theme={null}
console.log(key.inspect())
// Output: PrivateKey: 5JdeC9...NsQnsw
```

Only the first and last 6 characters are shown.

### Shared Secrets for Encryption

Compute ECDH shared secrets for memo encryption:

```typescript src/helpers/PrivateKey.ts:166 theme={null}
const alicePrivate = PrivateKey.fromLogin('alice', 'password', 'memo')
const bobPublic = PublicKey.fromString('STM7...')

const sharedSecret = alicePrivate.getSharedSecret(bobPublic)
// Returns 64-byte Uint8Array used for AES encryption
```

Both parties derive the same shared secret:

* Alice: `alicePrivate.getSharedSecret(bobPublic)`
* Bob: `bobPrivate.getSharedSecret(alicePublic)`

This enables encrypted memos that only the sender and receiver can read.

<Info>
  The shared secret is `SHA512(ECDH(privateKey, publicKey))`. The parity byte is stripped before hashing.
</Info>

## PublicKey Class

Public keys are derived from private keys and used for signature verification and encryption.

### Creating Public Keys

#### From String

```typescript src/helpers/PublicKey.ts:30 theme={null}
import { PublicKey } from 'hive-tx'

const pubKey = PublicKey.fromString('STM8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA')
```

#### From Private Key

```typescript theme={null}
const privateKey = PrivateKey.from('5JdeC9P7Pbd1uGdFVEsJ41Ek...')
const publicKey = privateKey.createPublic()
```

### Verifying Signatures

Check if a signature is valid for a given message:

```typescript src/helpers/PublicKey.ts:54 theme={null}
import { sha256 } from '@noble/hashes/sha2'

const message = new TextEncoder().encode('Hello Hive')
const hash = sha256(message)

const isValid = publicKey.verify(hash, signature)
console.log(isValid) // true or false
```

You can pass either a `Signature` object or a hex string:

```typescript theme={null}
// With Signature object
const sig = Signature.from('1f4c3d2e...')
const valid1 = publicKey.verify(hash, sig)

// With hex string
const valid2 = publicKey.verify(hash, '1f4c3d2e...')
```

### Exporting Public Keys

```typescript src/helpers/PublicKey.ts:68 theme={null}
const str = publicKey.toString()
console.log(str) // STM8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA

const json = publicKey.toJSON() // Same as toString()
```

## Signature Class

Signatures prove that a message was signed by a specific private key.

### Creating Signatures

#### From Signing

```typescript theme={null}
const privateKey = PrivateKey.from('5JdeC9P7Pbd1uGdFVEsJ41Ek...')
const hash = sha256(new TextEncoder().encode('message'))
const signature = privateKey.sign(hash)
```

#### From Hex String

```typescript src/helpers/Signature.ts:28 theme={null}
const sig = Signature.from('1f4c3d2e1a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e')
```

Signatures are 130 hex characters (65 bytes):

* 1 byte: Recovery ID (allows public key recovery)
* 64 bytes: ECDSA signature (r, s values)

### Signature Format

#### As Hex String

```typescript src/helpers/Signature.ts:65 theme={null}
const hex = signature.customToString()
console.log(hex) // 130-character hex string
```

#### As Buffer

```typescript src/helpers/Signature.ts:50 theme={null}
const buffer = signature.toBuffer()
console.log(buffer) // Uint8Array(65)
```

### Recovering Public Keys

Signatures are "recoverable" - you can extract the public key that created them:

```typescript src/helpers/Signature.ts:75 theme={null}
const message = sha256(new TextEncoder().encode('Hello'))
const recoveredPubKey = signature.getPublicKey(message)

console.log(recoveredPubKey.toString())
// STM8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA
```

You can pass either a Uint8Array hash or a 64-character hex string:

```typescript theme={null}
// From hash bytes
const pubKey1 = signature.getPublicKey(hashBytes)

// From hex string
const pubKey2 = signature.getPublicKey('a1b2c3d4...')
```

<Tip>
  Signature recovery is how Hive nodes verify transactions without storing public keys separately. The signature itself contains enough information to derive the signer's public key.
</Tip>

## Key Formats

### Private Key (WIF)

Wallet Import Format includes network ID and checksum:

```
5JdeC9P7Pbd1uGdFVEsJ41EkEnADbbHGq6p1BwFxm6txNBsQnsw
│└─────────────────────────────────────────────────┘
└─ Always starts with '5' for Hive mainnet
```

Encoding: `base58(0x80 + 32-byte-key + 4-byte-checksum)`

### Public Key

Includes address prefix and checksum:

```
STM8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA
│  └────────────────────────────────────────────────┘
└─ Address prefix (STM for mainnet, TST for testnet)
```

Encoding: `prefix + base58(33-byte-compressed-key + 4-byte-checksum)`

### Signature

130-character hex string:

```
1f 4c3d2e1a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e
││ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
│└─ 64-byte ECDSA signature (r, s)
└─ 1-byte recovery ID
```

## Security Best Practices

<AccordionGroup>
  <Accordion title="Key Storage">
    * **Never** hardcode private keys in source code
    * Use environment variables or secure key management systems
    * Encrypt keys at rest with strong passwords
    * Use hardware wallets for owner/active keys when possible
  </Accordion>

  <Accordion title="Key Usage">
    * Use **posting keys** for apps when possible (can't access funds)
    * Never send private keys over unencrypted connections
    * Validate key formats before using them
    * Clear key data from memory after use in sensitive contexts
  </Accordion>

  <Accordion title="Authority Hierarchy">
    * Keep **owner keys** offline and secure (paper wallet, hardware wallet)
    * Use **active keys** only for financial operations
    * Share **posting keys** with trusted apps for convenience
    * Rotate keys periodically, especially if compromised
  </Accordion>

  <Accordion title="Development">
    * Use testnet accounts for development
    * Never commit real keys to version control
    * Use `.env` files with `.gitignore` for local development
    * Audit dependencies that handle keys
  </Accordion>
</AccordionGroup>

## Complete Example

Here's a complete workflow showing key generation, signing, and verification:

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

// Generate keys from login
const postingKey = PrivateKey.fromLogin('alice', 'password', 'posting')
const publicKey = postingKey.createPublic()

console.log('Private Key (WIF):', postingKey.toString())
console.log('Public Key:', publicKey.toString())

// Sign a message
const message = 'I agree to the terms'
const messageHash = sha256(new TextEncoder().encode(message))
const signature = postingKey.sign(messageHash)

console.log('Signature:', signature.customToString())

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

// Recover public key from signature
const recoveredKey = signature.getPublicKey(messageHash)
console.log('Keys match:', recoveredKey.toString() === publicKey.toString()) // true

// Create shared secret for encryption
const aliceMemoKey = PrivateKey.fromLogin('alice', 'password', 'memo')
const bobMemoKey = PrivateKey.fromLogin('bob', 'bobpassword', 'memo')

const aliceSecret = aliceMemoKey.getSharedSecret(bobMemoKey.createPublic())
const bobSecret = bobMemoKey.getSharedSecret(aliceMemoKey.createPublic())

console.log('Secrets match:', 
  Buffer.from(aliceSecret).toString('hex') === Buffer.from(bobSecret).toString('hex')
) // true
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Transactions" icon="file-contract" href="/concepts/transactions">
    Use keys to sign transactions
  </Card>

  <Card title="Operations" icon="layer-group" href="/concepts/operations">
    Learn which operations need which keys
  </Card>

  <Card title="Memo Encryption" icon="lock" href="/guides/memo-encryption">
    Encrypt transfer memos
  </Card>

  <Card title="PrivateKey API" icon="code" href="/api/private-key">
    Full API reference
  </Card>
</CardGroup>
