Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dotandev/hintents/llms.txt

Use this file to discover all available pages before exploring further.

Erst can generate signed audit logs that provide cryptographic proof of simulation results. This is essential for compliance, forensics, and maintaining tamper-evident records of transaction analysis.

Overview

Audit log signing creates a cryptographically signed record containing:
  • Transaction hash
  • Simulation results (events, logs, traces)
  • Timestamp
  • Digital signature
  • Public key for verification
  • Optional hardware attestation
Audit logs provide:
  • Tamper evidence: Any modification invalidates the signature
  • Non-repudiation: Proof that a specific key signed the data
  • Compliance: Auditable trail for regulatory requirements
  • Hardware attestation: Proof that signing keys are HSM-protected

Signing methods

Erst supports two signing methods:

Software signing

Uses Ed25519 private keys stored in PEM format
  • Fast and convenient
  • Suitable for development
  • Keys can be backed up

HSM signing

Uses hardware security modules via PKCS#11
  • Production-grade security
  • Keys never leave hardware
  • Compliance-ready

Software signing

Sign audit logs using an Ed25519 private key.

Generate a signing key

Create an Ed25519 key pair:
# Generate private key
openssl genpkey -algorithm ed25519 -out ed25519-private-key.pem

# Extract public key
openssl pkey -in ed25519-private-key.pem -pubout -out ed25519-public-key.pem
Protect your private key file with restricted permissions:
chmod 600 ed25519-private-key.pem

Sign with environment variable

Provide the private key via environment variable:
export ERST_AUDIT_PRIVATE_KEY_PEM="$(cat ./ed25519-private-key.pem)"

node dist/index.js audit:sign \
  --payload '{"input":{},"state":{},"events":[],"timestamp":"2026-01-01T00:00:00.000Z"}'

Sign with CLI flag

Provide the private key directly:
node dist/index.js audit:sign \
  --payload '{"input":{},"state":{},"events":[],"timestamp":"2026-01-01T00:00:00.000Z"}' \
  --software-private-key "$(cat ./ed25519-private-key.pem)"
The audit:sign command is part of the TypeScript bindings. For Go CLI integration, see the implementation in internal/cmd/audit.go.

HSM signing (PKCS#11)

Sign audit logs using a hardware security module.

Prerequisites

Install PKCS#11 provider:
# Install YubiKey manager
sudo apt-get install yubikey-manager
# or on macOS:
brew install ykman

# Verify PKCS#11 module
ls /usr/lib/x86_64-linux-gnu/libykcs11.so

Configure environment

Set required environment variables:
# PKCS#11 module path
export ERST_PKCS11_MODULE=/usr/lib/x86_64-linux-gnu/libykcs11.so

# PIN for accessing the HSM
export ERST_PKCS11_PIN=123456

# Key identifier (choose ONE method):
# Option 1: Key label
export ERST_PKCS11_KEY_LABEL=erst-audit-ed25519

# Option 2: Key ID (hex)
export ERST_PKCS11_KEY_ID=01

# Option 3: YubiKey PIV slot
export ERST_PKCS11_PIV_SLOT=9a  # 9a, 9c, 9d, 9e, 82-95, f9

# Public key for verification (SPKI PEM format)
export ERST_PKCS11_PUBLIC_KEY_PEM="$(cat ./ed25519-public-key-spki.pem)"
# Token label (alternative to slot index)
export ERST_PKCS11_TOKEN_LABEL="YubiKey PIV"

# Slot index (numeric)
export ERST_PKCS11_SLOT=0

Sign with HSM

Generate a signed audit log:
node dist/index.js audit:sign \
  --hsm-provider pkcs11 \
  --payload '{"input":{},"state":{},"events":[],"timestamp":"2026-01-01T00:00:00.000Z"}'
The command outputs signed JSON to stdout:
{
  "version": "1.1.0",
  "timestamp": "2026-03-03T10:30:45.123Z",
  "transaction_hash": "abc123...",
  "trace_hash": "def456...",
  "signature": "789abc...",
  "public_key": "012def...",
  "payload": {
    "envelope_xdr": "...",
    "result_meta_xdr": "...",
    "events": [...],
    "logs": [...]
  },
  "hardware_attestation": {
    "certificates": [...],
    "token_info": "YubiKey PIV",
    "key_non_exportable": true,
    "retrieved_at": "2026-03-03T10:30:45.123Z"
  }
}

Hardware attestation

HSM signing can include hardware attestation proving the signing key is hardware-protected.

Attestation data

When signing with an HSM, the audit log includes:
  • Certificates: X.509 certificate chain (leaf to root)
  • Token info: HSM device information
  • Key non-exportable: Confirmation that the key cannot be extracted
  • Retrieved timestamp: When attestation was captured

Verification

The attestation is included in the signature hash, so:
  • Removing attestation invalidates the signature
  • Modifying attestation invalidates the signature
  • Attestation proves the key is HSM-protected
Hardware attestation is optional but recommended for high-security environments where you need cryptographic proof that keys are hardware-protected.

Audit log structure

Version 1.1.0 schema

interface AuditLog {
  version: string;                          // Schema version ("1.1.0")
  timestamp: string;                        // ISO 8601 timestamp
  transaction_hash: string;                 // Transaction hash (hex)
  trace_hash: string;                       // SHA256 hash of payload (hex)
  signature: string;                        // Ed25519 signature (hex)
  public_key: string;                       // Ed25519 public key (hex)
  payload: Payload;                         // Simulation results
  hardware_attestation?: HardwareAttestation; // Optional HSM attestation
}

interface Payload {
  envelope_xdr: string;     // Base64 transaction envelope
  result_meta_xdr: string;  // Base64 result metadata
  events: string[];         // Diagnostic events
  logs: string[];           // Execution logs
}

interface HardwareAttestation {
  certificates: Certificate[];  // X.509 chain (leaf to root)
  token_info: string;           // HSM device info
  key_non_exportable: boolean;  // Key protection status
  retrieved_at: string;         // ISO 8601 timestamp
}

Hash computation

The trace_hash is computed as:
trace_hash = SHA256(JSON.stringify({
  payload: <payload>,
  hardware_attestation: <attestation>  // If present
}))
The signature is:
signature = Ed25519.sign(private_key, trace_hash)

Verification

Verify an audit log’s integrity and signature:

Programmatic verification

import { VerifyAuditLog } from './audit';

const auditLog: AuditLog = JSON.parse(auditLogJson);
const isValid = await VerifyAuditLog(auditLog);

if (isValid) {
  console.log('✓ Audit log signature is valid');
} else {
  console.log('✗ Audit log signature is INVALID');
}

Manual verification

1
Extract public key
2
echo "<public_key_hex>" | xxd -r -p > public_key.bin
3
Reconstruct trace hash
4
# Extract payload + attestation
jq '{payload: .payload, hardware_attestation: .hardware_attestation}' audit-log.json \
  | openssl dgst -sha256 -hex
5
Verify signature
6
openssl pkeyutl \
  -verify \
  -pubin -inkey public_key.pem \
  -sigfile signature.bin \
  -in trace_hash.bin

Verification results

  • Valid: Hash matches and signature verifies
  • Invalid: Payload was modified, signature is wrong, or key is incorrect
  • Attestation removed: Hash won’t match if attestation was stripped

YubiKey PIV integration

Use YubiKey devices for HSM signing.

PIV slots

YubiKey PIV supports multiple key slots:
SlotPurposeUse Case
9aPIV AuthenticationGeneral signing
9cDigital SignatureDocument signing
9dKey ManagementEncryption
9eCard AuthenticationLow-security auth
82-95Retired SlotsKey rotation
f9AttestationKey attestation
Recommended for audit logs: Slot 9c (Digital Signature)

Generate key on YubiKey

# Generate Ed25519 key in slot 9c
yubico-piv-tool -a generate -s 9c -o public_key.pem -A ECCP256

# Set slot to require PIN
yubico-piv-tool -a set-mgm-key --new-key <new-management-key>

Configure for Erst

export ERST_PKCS11_MODULE=/usr/lib/x86_64-linux-gnu/libykcs11.so
export ERST_PKCS11_PIN=123456
export ERST_PKCS11_PIV_SLOT=9c
export ERST_PKCS11_PUBLIC_KEY_PEM="$(cat ./public_key.pem)"

node dist/index.js audit:sign --hsm-provider pkcs11 --payload '...'
See docs/pkcs11-yubikey.md for detailed YubiKey setup.

Common workflows

Generate audit log after debugging

1
Debug transaction
2
erst debug abc123...def --network mainnet
3
Extract simulation results
4
Simulation results are stored in the active session.
5
Generate signed audit log
6
# Using software key
export ERST_AUDIT_PRIVATE_KEY_PEM="$(cat ./key.pem)"
node dist/index.js audit:sign \
  --payload "$(erst session export-payload)" \
  > audit-log.json
7
Store audit log
8
# Save to compliance archive
cp audit-log.json /archives/2026-03-03-abc123.json

Batch audit log generation

Generate audit logs for multiple transactions:
#!/bin/bash
# batch-audit.sh

export ERST_AUDIT_PRIVATE_KEY_PEM="$(cat ./key.pem)"

for tx in "abc123..." "def456..." "789abc..."; do
  echo "Processing $tx..."
  
  # Debug transaction
  erst debug "$tx" --network mainnet
  
  # Generate audit log
  node dist/index.js audit:sign \
    --payload "$(erst session export-payload)" \
    > "audit-log-$tx.json"
    
  echo "✓ Audit log saved: audit-log-$tx.json"
done

Verify archived audit logs

Check integrity of stored logs:
#!/bin/bash
# verify-archives.sh

for log in /archives/*.json; do
  echo "Verifying $log..."
  
  if node dist/index.js audit:verify --log "$log"; then
    echo "✓ Valid"
  else
    echo "✗ INVALID"
    exit 1
  fi
done

echo "All audit logs verified successfully"

Security best practices

For software keys:
  • Store with restricted permissions: chmod 600 key.pem
  • Never commit to version control
  • Use environment variables, not hardcoded paths
  • Rotate keys periodically
  • Back up securely (encrypted storage)
For HSM keys:
  • Never export private keys
  • Use strong PINs (not default PINs)
  • Enable PIN retry limits
  • Physical security for HSM devices
  • Audit HSM access logs
Software keys are convenient for development, but production audit logs should use HSM:
  • Keys cannot be extracted
  • Tamper-evident hardware
  • Compliance-ready (FIPS 140-2)
  • Hardware attestation available
  • Centralized key management
When using HSM, always include attestation:
  • Proves keys are hardware-protected
  • Cannot be forged
  • Required for high-assurance compliance
  • Covered by signature (tamper-evident)
  • Store in append-only storage
  • Use write-once media for immutability
  • Encrypt at rest
  • Replicate to multiple locations
  • Test restoration procedures
  • Document retention policies

Troubleshooting

Invalid signature

Error: audit log signature verification failed
Solutions:
  • Verify you’re using the correct public key
  • Check audit log wasn’t modified
  • Ensure payload format matches schema version
  • Re-generate audit log if corrupted

HSM not detected

Error: failed to initialize PKCS#11 module
Solutions:
  • Check PKCS#11 module path: ls $ERST_PKCS11_MODULE
  • Install HSM drivers/software
  • Verify HSM is connected: yubico-piv-tool -a status
  • Check permissions: sudo usermod -a -G plugdev $USER

PIN incorrect

Error: CKR_PIN_INCORRECT
Solutions:
  • Verify PIN is correct
  • Check PIN hasn’t been locked (retry limit)
  • Reset PIN if needed (requires PUK)
  • Use correct PIN for the token

Key not found in HSM

Error: private key not found in HSM
Solutions:
  • List available keys: yubico-piv-tool -a list
  • Verify key label or ID is correct
  • Check you’re using the right slot
  • Generate key if it doesn’t exist

Implementation details

Source files

Audit log signing is implemented in:
  • internal/cmd/audit.go - Go implementation
  • internal/signer/ - Signer interface
  • internal/signer/memory.go - Software signer
  • internal/signer/pkcs11.go - HSM signer

Key functions

Audit log generation:
  • Generate() - Legacy function (software key)
  • GenerateWithSigner() - Generic signer interface
  • VerifyAuditLog() - Verify signature and hash
Location: internal/cmd/audit.go:73, internal/cmd/audit.go:84, internal/cmd/audit.go:143

Signer interface

type Signer interface {
    Sign(data []byte) ([]byte, error)
    PublicKey() ([]byte, error)
}
Implementations:
  • InMemorySigner - Ed25519 software signing
  • Pkcs11Signer - PKCS#11 HSM signing

Next steps

HSM integration guide

Detailed HSM setup and configuration

Working with sessions

Save debugging context for audit log generation

Debugging failed transactions

Generate simulation results for signing