Sponsored Content

DEV Community

Komari venkata ramana
Komari venkata ramana

Posted on

Kage: Private Payments for Autonomous AI Agents

Private Payments for Autonomous AI Agents on Stellar

How a scoped session key + a Groth16 shielded pool let an agent spend without your key β€” and without publishing your counterparties.

An AI agent that can spend money on-chain is only as trustworthy as the key it holds. Hand it a raw private key and two things go wrong at once:

  1. Custody β€” the agent (or whoever compromises it) can drain the whole treasury. There is no "just a little" with an ed25519 key.
  2. Transparency β€” every payment the agent makes is a public record of who you paid, how much, and a running map of everything your treasury touches.

Kage fixes both, on Stellar, with two primitives that compose cleanly:
a scoped session account (autonomy without custody) settling through a
zero-knowledge shielded pool (privacy without a trusted relayer).

The problem, precisely

  • A scoped key that just caps spend still leaks to whom.
  • A private pool that hides recipients still needs a way to scope what an agent may pull.
  • On a transparent ledger, the two are usually solved by opposite designs (custodial scope vs. trustless privacy).

The two layers

1. Autonomy without custody β€” the SessionAccount

A Soroban account contract delegates one ephemeral agent key, and its
__check_auth permits exactly one thing:

  • Veil.deposit on the configured pool,
  • moving the configured token,
  • within a cumulative cap,
  • before an expiry.

The agent signs a Soroban auth entry with its session key β€” never the owner's key. The owner can revoke or extend at any time. Worst case for a compromised agent: it spends the remaining cap. It cannot drain, cannot redirect, cannot change the policy.

2. Privacy by math β€” the ZK shielded pool

Each payment is a deposit into a Tornado/Privacy-Pools-style pool, then a withdrawal to a fresh one-time stealth address:

  • Hides the recipient β€” Umbra-style stealth notes; each payee is paid at an address only the recipient can derive.
  • Hides the amount + link β€” a zero-knowledge membership proof breaks the deposit↔withdrawal trail. The proof shows "I own some unspent note" without revealing which.
  • Stops double-spends β€” a per-note nullifier reverts any replay on-chain.
  • Trustless tree β€” every deposit carries a Groth16 insert proof; the contract verifies the new Merkle root itself. No custodian.

Crucially, the contract verifies Groth16 on Soroban's native BN254 host functions β€” no hand-rolled pairing math in the wasm, and the amount is bound into the proof so a depositor can't commit a large note while under-funding the pool.

Why Stellar

  • Soroban native BN254 β€” the pairing check is a host function, so the ZK verifier is a few dozen lines of trust in the protocol, not a ported library.
  • Native-asset settlement β€” the pool runs on XLM via its Stellar Asset Contract, so there's no wrapped token, no bridge, no extra trust.
  • x402 / agent payments β€” Kage slots into the x402 "agent pays for its own API calls" model, giving autonomous agents a private, scoped payment rail.

What's live

A testnet deployment runs the full flow end to end β€” deposit (insert proof verified, USDC/XLM pulled), withdraw (membership proof verified, paid to a stealth address), and a rejected double-spend attempt. On mainnet, the same contracts settle in XLM.

The honest scope

This is not the full two-key Umbra scheme, and Groth16 means a trusted setup (phase 1 reuses the Hermez powers-of-tau). The deposit amount is published in the event (needed for the amount-binding check), so fixed-size notes are the recommended practice. See the repo's security review for the full ledger of limits.

Kage is open source (MIT). Repo: github.com/Venkat5599/kagezks

Top comments (0)