x402 trust layer. Give AI agents ZK identity, a role, and a budget. Let them pay autonomously.
For AI agents to evolve from simple API callers into true economic actors, they need identity, authorization boundaries, and verifiable audit trails. Trust402 is the trust layer for the x402 payment protocol that makes this possible. It equips AI agents with ZK-proof artifacts: committing their credential via Poseidon hashes, proving their role membership and spend limits through Circom circuits (Groth16 on BN254), and submitting both proofs to the Lemma oracle for immutable on-chain settlement. While this implementation uses Groth16/Poseidon, the underlying Lemma protocol is algorithm-agnostic: developers can register arbitrary ZK circuits (Circom, Halo2, etc.) and swap commitment schemes (Poseidon2, Rescue-Prime, lattice-hash) without protocol-level changes. The result: agents can autonomously pay for data, but only within cryptographically enforced constraints. No valid proof, no payment. Every transaction is backed by an on-chain attestation, currently deployed on Base Sepolia with mainnet deployment ready.
Trust402 is a TypeScript monorepo (pnpm workspaces) with five packages, two Circom circuits, and a Rust-to-WASM normalization pipeline.
・Circom circuits: I wrote two Groth16/BN254 circuits in Circom 2.x. agent-identity-v1 verifies that a credential is well-formed, not revoked, and not expired by checking Poseidon section hashes, an issuer MAC, and timestamp constraints. role-spend-limit-v1 enforces four R1CS constraints per payment: (1) roleHash === requiredRoleHash for role membership, (2) spendLimit <= maxSpend via a 128-bit LessEqThan comparator, (3) Poseidon4(commitment, roleHash, spendLimit, salt) === roleGateCommitment for binding integrity, and (4) credentialCommitment === credentialCommitmentPublic for cross-proof correlation, linking the identity proof to the role proof without revealing the underlying credential.
・Proof-before-payment pipeline: The core is a three-layer fetch composition: paymentFetch → proofFetch → native fetch. wrapFetchWithProof (from @trust402/protocol) intercepts fetch, generates both the identity and role proofs via @lemmaoracle/sdk, submits them to the Lemma oracle for on-chain settlement, and only then delegates to the underlying fetch. wrapFetchWithPayment (from @x402/fetch) then adds the x402 payment envelope. Because the proof layer sits above the payment layer, if proveRole rejects (e.g., spend limit exceeded), the Promise chain short-circuits and the x402 fetch is never reached. This is the "fail-closed" guarantee: no valid proof, no payment, enforced purely on the buyer side, with zero server-side trust assumptions.
・Cryptography stack: All heavy lifting delegates to @lemmaoracle/sdk: Groth16 proof generation, Poseidon commitments, and encrypted document storage on IPFS (Pinata). Credential normalization uses a Rust-to-WASM pipeline (@lemmaoracle/agent) that maps arbitrary JSON into BN254 field elements. For field-element derivation from role names, we use SHA-256 with top-nibble masking to keep the digest below the BN254 prime, avoiding modular bias at the cost of reduced output space (~2^252 of ~2^253 field elements). A future iteration would use RFC 9380 hash-to-field for uniform distribution across the full scalar field. While this implementation uses Groth16 over BN254, the Lemma protocol is not bound to any single proving system. The CommitmentScheme field in DocumentCommitments supports "poseidon", "poseidon2", "rescue-prime", and is extensible to lattice-based hashes for post-quantum migration without changing the on-chain bytes32 root format or the registry contract interface. Similarly, circuits.register accepts arbitrary circuitId values backed by any proving backend (Circom, Halo2, etc.), all verified through the same prover.prove / proofs.submit interface. Trust402's "fail-closed" guarantee is a property of the protocol architecture, not of any specific cryptographic algorithm.
・Demo flow: The demo agent runs a two-scenario TUI: a $0.01 GET for financial data (proof succeeds, payment completes, attestation verified via Lemma oracle and ProofSettled event on Base Sepolia) and a $500 POST for a contract (proof fails at the spendLimit <= maxSpend constraint, payment never attempted). On-chain attestation is verified by querying DocumentRegistered and ProofSettled events via viem on Base Sepolia. The resource server is built with Hono and @lemmaoracle/x402 middleware using EIP-3009 USDC transfers. Base Sepolia is used as the demo testnet; the same pipeline deploys to Base mainnet without code changes.

