Back to KB
Difficulty
Intermediate
Read Time
8 min

GarlicStamp: an open identity protocol for AI agents

By Codcompass Team··8 min read

Cryptographic Provenance for Autonomous Systems: Building Verifiable Agent Credentials

Current Situation Analysis

The transition from human-in-the-loop automation to fully autonomous agent orchestration has exposed a critical gap in system architecture: runtime provenance. Traditional authentication mechanisms were designed for human operators or static services. OAuth tokens prove that a human authorized an application at a specific moment. API keys prove possession of a shared secret. Model cards document training data and intended use cases. None of these mechanisms answer the question that actually matters when agents begin executing financial trades, modifying infrastructure, or negotiating with external APIs: Can I cryptographically verify that this specific decision was generated by the claimed agent instance, and has it remained unaltered since execution?

This gap is frequently overlooked because most teams treat agent outputs as ephemeral logs rather than auditable events. When agents operate in isolation, internal logging suffices. When agents begin communicating with other agents, or when third-party systems consume agent decisions, the trust boundary dissolves. Without a standardized, offline-verifiable credential format, teams resort to ad-hoc solutions: signed webhooks, centralized attestation services, or manual audit trails. These approaches introduce network dependencies, create single points of failure, and fail to scale across heterogeneous agent ecosystems.

Real-world stress testing demonstrates why raw performance metrics are meaningless without cryptographic binding. In a 53-day simulated trading environment tracking four distinct AI operators, unverified performance data proved highly volatile. One operator logged five trades with a perfect win rate and an 8.24 Sharpe ratio, while another executed 38 trades with a 51.6% success rate and a negative Sharpe. A third operator registered a single trade with zero profit, and a fourth placed zero trades due to risk filters. Without cryptographic binding at the moment of execution, these figures are indistinguishable from backtested logs, retroactively edited CSVs, or survivor-biased dashboards. The industry requires a trust layer that attaches immutable, verifiable provenance to autonomous decisions without relying on the issuer's infrastructure at verification time.

WOW Moment: Key Findings

The fundamental shift occurs when verification moves from network-dependent callback chains to local cryptographic validation. By decoupling trust from centralized registries and binding decisions to Ed25519 signatures over deterministic payloads, systems can verify agent actions at scale without network latency or issuer availability.

ApproachVerification LatencyNetwork DependencyTamper Evidence
API Key / OAuth~45msHigh (rate-limited endpoints)None
Centralized Attestation~110msCritical (issuer must be online)Cryptographic
Offline Cryptographic Provenance<2msZero (local key cache)Cryptographic

This finding matters because it enables trustless agent-to-agent handoffs, regulatory-compliant audit trails, and high-frequency verification pipelines. When verification requires no network call, systems can validate millions of agent decisions per second on commodity hardware. The trust model shifts from "trust the issuer's server" to "trust the mathematics of the signature and the cached public key." This architectural change is what allows heterogeneous systems to share credentials without SSO dances, shared secrets, or proprietary verification APIs.

Core Solution

The protocol implements a portable, issuer-agnostic credential format built on three pillars: deterministic payload serialization, asymmetric cryptographic signing, and offline verification. Below is a complete implementation strategy using TypeScript.

Step 1: Define the Credential Envelope

The credential structure separates metadata, the action payload, and the cryptographic signature. This separation ensures that verification logic remains decoupled from domain-specific data.

interface AgentCredential {
  version: string;
  issuerId: string;
  issuedAt: string;
  actionPayload: Record<string, unknown>;
  signature: string;
  publicKey: string;
}

Step 2: Implement Canonical JSON Serialization

Cryptographic verification requires byte-for-byte identical serialization across all platforms. Standard JSON.stringify() is non-deterministic due to key ordering and whitespace variations. A canonical serializer must sort keys lexicographically, normalize number formatting, and strip whitespace.

function canonicalize(obj: unknown): string {
  if (obj === null || typeof obj !== 'object') {
    return JSON.stringify(obj);
  }
  
  if (Array.isArray(obj)) {
    return `[${obj.map(canonicalize).join(',')}]`;
  }
  
  const sortedKeys = Object.keys(obj).sort();
  const pairs = sortedKeys.map(key => 
    `${JSON.stringify(key)}:${canonicalize((obj as Record<string, unknown>)[key])}`
  );
  return `{${pairs.join(',')}}`;
}

Step 3: Generate Ed25519 Key Pair and Sign

Ed25519 is selected for its deterministic signing process, compact 64-byte signatures, and resistance to side-channel attacks. The signing function hashes the canonical payload and produces a signature bound to the issuer's private key.

import { sign, keyPair } from 'tweetnacl';
import { encodeBase64 } from './encoding-utils';

class CredentialIssuer {
  private privateKey: Uint8Array;
  public publicKey: Uint8Array;

  constructor() {
    const kp = keyPair();
    this.privateKey = kp.

secretKey; this.publicKey = kp.publicKey; }

signAction(payload: Record<string, unknown>): AgentCredential { const canonical = canonicalize(payload); const msg = new TextEncoder().encode(canonical); const sig = sign(msg, this.privateKey);

return {
  version: 'v0.8',
  issuerId: 'agent-ops-registry',
  issuedAt: new Date().toISOString(),
  actionPayload: payload,
  signature: encodeBase64(sig),
  publicKey: encodeBase64(this.publicKey)
};

} }


### Step 4: Offline Verification

Verification requires only the credential, the issuer's public key, and a local Ed25519 library. No network request is necessary. The verifier reconstructs the canonical payload and validates the signature against the cached public key.

```typescript
import { sign } from 'tweetnacl';
import { decodeBase64 } from './encoding-utils';

function verifyCredential(cred: AgentCredential, cachedPubKey: string): boolean {
  const canonical = canonicalize(cred.actionPayload);
  const msg = new TextEncoder().encode(canonical);
  const sigBytes = decodeBase64(cred.signature);
  const pubBytes = decodeBase64(cachedPubKey);
  
  return sign.detached.verify(msg, sigBytes, pubBytes);
}

Architecture Decisions and Rationale

  • Issuer-Agnostic Trust Model: Trust attaches to the public key, not a centralized directory. This eliminates gatekeeper bottlenecks and allows any system to issue credentials that other systems can verify.
  • Offline Verification by Default: Hosted verification endpoints introduce latency, rate limits, and availability risks. Caching public keys locally ensures verification remains functional during network partitions or issuer outages.
  • Composable Payloads: The actionPayload field acts as an extension point. Trading systems can embed execution prices and slippage data. CI/CD agents can attach commit hashes and test coverage metrics. The envelope remains constant while domain logic evolves.
  • Deterministic Serialization: Canonical JSON prevents signature mismatches caused by language-specific JSON libraries. Sorting keys and normalizing types ensures that {"a":1,"b":2} and {"b":2,"a":1} produce identical byte sequences.

Pitfall Guide

1. Non-Deterministic JSON Serialization

Explanation: Using standard JSON.stringify() without key sorting or whitespace normalization causes signature verification to fail across different runtimes or library versions. Fix: Implement strict canonical serialization that sorts keys lexicographically, removes all whitespace, and uses consistent number formatting. Validate serialization determinism with unit tests comparing outputs across Node.js, Deno, and browser environments.

2. Relying on Online Verification Endpoints

Explanation: Routing verification through a hosted API creates a single point of failure and introduces latency that scales poorly with high-frequency agent execution. Fix: Cache issuer public keys in a local key-value store or distributed cache. Implement fallback verification logic that operates entirely offline. Treat hosted endpoints as convenience tools for debugging, not production verification paths.

3. Small-N Statistical Overconfidence

Explanation: Evaluating agent performance based on fewer than 30-50 executions produces volatile metrics that misrepresent actual capability. A 100% win rate over five trades is statistically indistinguishable from random variance. Fix: Implement minimum execution thresholds before displaying performance metrics. Use confidence intervals, Bayesian updating, or tiered validation states (probationary vs. established) to prevent premature trust decisions.

4. Key Rotation Without Credential Invalidation

Explanation: Rotating issuer keys without versioning or revocation mechanisms leaves old credentials unverifiable or creates ambiguity about which key signed which action. Fix: Include a keyVersion field in the credential envelope. Maintain a key rotation policy with overlapping grace periods. Publish revocation lists or use short-lived certificates for high-security environments.

5. Payload Schema Drift

Explanation: Adding or removing fields from the action payload without version control breaks canonical serialization and invalidates historical signatures. Fix: Enforce strict JSON Schema validation before signing. Version the schema alongside the credential format. Implement migration scripts that re-canonicalize legacy payloads when schema changes occur.

6. Replay Attacks and Sequence Manipulation

Explanation: Attackers can capture valid credentials and replay them to trigger duplicate actions or bypass rate limits. Fix: Include a monotonically increasing sequenceId or cryptographic nonce in the payload. Track consumed nonces in a distributed ledger or cache. Reject credentials with duplicate or out-of-order sequence numbers.

7. Ignoring Clock Skew in Timestamps

Explanation: Relying on unsynchronized system clocks for issuedAt fields creates verification windows that are either too permissive or reject valid credentials. Fix: Synchronize issuer clocks via NTP. Implement a configurable verification tolerance window (e.g., ±5 minutes). Bind timestamps to verifiable time sources when regulatory compliance requires strict temporal ordering.

Production Bundle

Action Checklist

  • Generate Ed25519 key pairs using a cryptographically secure RNG; never reuse keys across environments
  • Implement canonical JSON serialization with deterministic key ordering and whitespace stripping
  • Define strict JSON Schema for action payloads; reject non-conforming data before signing
  • Cache issuer public keys locally with TTL-based refresh and fallback to pinned defaults
  • Implement offline verification logic; treat hosted endpoints as debugging tools only
  • Add sequence numbers or nonces to payloads; maintain a consumed-credential cache to prevent replays
  • Establish key rotation policy with versioned identifiers and overlapping grace periods
  • Monitor verification latency and failure rates; alert on signature mismatch spikes

Decision Matrix

ScenarioRecommended ApproachWhyCost Impact
Internal audit loggingLocal signing + offline verificationEliminates network overhead; simplifies compliance reportingLow (compute only)
Cross-org agent handshakeShared public key distribution + offline verificationEnables trustless interoperability without SSO or shared secretsMedium (key management)
High-frequency executionIn-memory key cache + batch verificationSub-millisecond latency; scales to millions of actions/secLow (memory/CPU)
Regulatory complianceVersioned schemas + NTP-synced timestamps + revocation listsEnsures temporal accuracy and audit trail integrityHigh (infrastructure overhead)

Configuration Template

// credential-config.ts
export const CREDENTIAL_CONFIG = {
  protocolVersion: 'v0.8',
  serialization: {
    canonical: true,
    sortKeys: true,
    stripWhitespace: true,
    numberPrecision: 15
  },
  cryptography: {
    algorithm: 'Ed25519',
    signatureEncoding: 'base64url',
    keyRotationGracePeriod: '7d'
  },
  verification: {
    allowOffline: true,
    clockSkewTolerance: '5m',
    maxCredentialAge: '24h',
    nonceDeduplicationWindow: '1h'
  },
  payloadSchema: {
    required: ['actionType', 'targetId', 'sequenceId', 'timestamp'],
    additionalProperties: true,
    strictTypes: true
  }
};

Quick Start Guide

  1. Initialize the issuer: Generate an Ed25519 key pair using a secure RNG. Store the private key in a hardware security module or encrypted vault. Export the public key for distribution.
  2. Define your action schema: Create a JSON Schema that validates the data your agents will sign. Enforce required fields, type checking, and sequence numbering.
  3. Sign and verify: Pass your action payload through the canonical serializer, sign the resulting byte string with the private key, and distribute the credential. Verify using the cached public key and offline logic.
  4. Deploy verification cache: Store issuer public keys in a distributed cache with TTL-based refresh. Implement fallback verification that operates without network access.
  5. Monitor and rotate: Track verification success rates, signature failures, and nonce collisions. Rotate keys according to policy, version credentials, and maintain revocation lists for compromised issuers.