Mitigating Memory Poisoning in Autonomous Agentic DeFi
Autonomous LLM agents that execute high-value transactions in DeFi protocols face a class of attack that bypasses cryptographic key security entirely: an adversary corrupts the agent's long-term vector memory, RAG corpus, or oracle input stream, causing the agent to sign malicious transactions while believing it operates within safe parameters.
ZKP-RA addresses this by inserting a Reasoning Anchor into every agent-to-chain settlement path:
-
State Commitment — Before reasoning, the agent commits a Poseidon hash of its context window
$X_t$ , state vector$S_t$ , and oracle inputs$I_t$ to an on-chain contract:$$H_t = \text{Poseidon}(X_t,, S_t,, I_t)$$ -
Verifiable Inference — After producing a transaction payload
$T_x$ , the agent generates a Groth16 zk-SNARK (over BN254) proving that$T_x$ was derived from inputs that hash to$H_t$ and satisfy the safety policy$C$ (amount bounds, slippage limits, router whitelist):$$\pi \leftarrow \text{Prove}(\text{pk},; (H_t, T_x),; (X_t, S_t, I_t, r, \sigma))$$ -
On-Chain Settlement — The smart contract verifies
$\pi$ and executes the ERC-20 transfer atomically. Any transaction arising from poisoned inputs fails the pairing check and is rejected.
Key metrics (measured end-to-end, real trusted setup + real on-chain deployment — see Verification Notes): 224 ms median proof generation (SnarkJS WASM, 20-trial), 405,659 gas total on-chain settlement (commitState + verifyAndExecute), 7,449 R1CS constraints.
ZKP-RA/
├── circuits/
│ └── reasoning_anchor.circom # Groth16 circuit: Poseidon state commitment + policy engine
├── contracts/
│ └── Verifier.sol # On-chain Groth16 verifier + ERC-20 settlement
├── src/
│ └── agent_guardian.py # Async Python daemon: intercepts tool calls, drives prover
├── scripts/
│ └── compile_and_setup.sh # Circuit compile + Phase 2 trusted setup automation
├── test/
│ └── Verifier.test.js # Hardhat integration tests (11 passing, incl. a real Groth16 proof)
├── package.json
└── requirements.txt
Manuscript: The companion academic paper is under review. Full text will be made available upon publication.
┌─────────────────────────────────────────────────────────────┐
│ LLM Agent Runtime │
│ │
│ Oracle feeds ──► Context Window (Xt) │
│ RAG memory ──► State Vector (St) ──► Poseidon ──► Ht │
│ User intent ──► Input stream (It) │
│ │ │ │
│ ▼ ▼ │
│ Policy engine C commitState(Ht) │
│ generates Tx ──► chain (block b) │
│ │ │
│ ▼ │
│ SnarkJS / rapidsnark │
│ Groth16 Prove(pk, pub, wit) ──► π │
└───────────────────────────┬─────────────────────────────────┘
│ verifyAndExecute(π, Tx, nonce, ν)
▼
┌─────────────────────────────────────────────────────────────┐
│ ReasoningAnchorVerifier.sol │
│ │
│ 1. Load Ht from pendingCommitments[agent][nonce] │
│ 2. Groth16 pairing check: e(A,B) = e(α,β)·e(vkx,γ)·e(C,δ) │
│ 3. Enforce: amount ≤ cap, slippage ≤ 200 bps, router ∈ W │
│ 4. Mark nullifier ν (replay protection) │
│ 5. ERC-20 safeTransfer to recipient │
└─────────────────────────────────────────────────────────────┘
circuits/reasoning_anchor.circom arithmetizes the following statement in R1CS over the BN254 scalar field:
"I know private witnesses $(X_t, S_t, I_t, r, \sigma)$ such that: (1) $\text{Poseidon}(X_t | S_t | I_t) = H_t$ (2) $T_x.\texttt{amount} \leq \text{MAX_AMOUNT}$ (3) $T_x.\texttt{slippage_bps} \leq 200$ (4) $\text{Poseidon}(r, \sigma) = T_x.\texttt{routerHash}$"
| Parameter | Value |
|---|---|
| Proving system | Groth16 |
| Curve | BN254 (alt_bn128) |
| Hash function | Poseidon ( |
| Context chunks |
8 field elements |
| State chunks |
8 field elements |
| Input chunks |
4 field elements |
| Total R1CS constraints | 7,449 (measured; see below) |
| Public inputs |
|
| Tool | Version |
|---|---|
| Node.js | 20+ (tested on 24) |
| Circom | 2.1.6+ (tested against 2.1.6 and 2.2.3) |
| SnarkJS | 0.7.4 |
| rapidsnark (optional, native prover) | 0.0.1 |
| Python | 3.10+ |
| Hardhat | 2.22+ |
npm install
pip install -r requirements.txtCircom itself is not an npm package; download a platform binary from the
circom releases page and place it
on your PATH (or point scripts/compile_and_setup.sh at it directly).
bash scripts/compile_and_setup.shThis downloads the Hermez BN128 Phase 1 powers-of-tau file, compiles the circuit to R1CS + WASM, runs the Phase 2 Groth16 setup, and exports the verification key.
After setup, extract the hex-encoded VK constants from build/verification_key.json
and update VerificationKey.load() in contracts/Verifier.sol. Watch for two
easy-to-miss conventions when transcribing: (a) the base field modulus q used
for point negation is ...696311157297823662689037894645226208583, not the
scalar field r used for circuit witnesses — they're both BN254-flavored
78-digit numbers and easy to swap; (b) each G2 point's two field-extension
coefficients must be written in reversed order relative to the raw JSON
(x[0] = json_x[1], x[1] = json_x[0], and likewise for y) to match the
EIP-197 pairing precompile's expected input layout. scripts/benchmark/measure_gas.cjs
does this conversion programmatically and is the fastest way to sanity-check
a new ceremony end-to-end before hand-editing the contract.
npx hardhat compile
npx hardhat run scripts/deploy.js --network <network>export AGENT_PRIVATE_KEY=0x...
python src/agent_guardian.py config.jsonconfig.json:
{
"rpc_url": "https://your-rpc-endpoint",
"contract_address": "0xYourDeployedVerifier",
"abi_path": "artifacts/contracts/Verifier.sol/ReasoningAnchorVerifier.json",
"wasm_path": "build/reasoning_anchor_js/reasoning_anchor.wasm",
"zkey_path": "build/reasoning_anchor_final.zkey",
"rapidsnark_bin": "/usr/local/bin/rapidsnark"
}npx hardhat test
npx hardhat coverageMeasured via npm run benchmark:gas (Hardhat local network, a real Groth16
proof against the dev ceremony's verification key, full commitState →
verifyAndExecute flow including the ERC-20 transfer):
| Call | Gas (measured) |
|---|---|
commitState |
73,022 |
verifyAndExecute (pairing check + policy checks + ERC-20 transfer) |
332,637 |
| Total per settled transaction | 405,659 |
This is an aggregate on-chain measurement, not a hand-derived per-opcode
estimate — run npm run benchmark:gas yourself to reproduce it or profile a
finer breakdown with hardhat-gas-reporter.
| Property | Guarantee |
|---|---|
| Completeness | An honest agent with valid witnesses always produces an accepted proof |
| Soundness | Under |
| Zero-Knowledge | The proof reveals nothing about |
Measured via npm run benchmark:input && npm run benchmark:proof
(20-trial snarkjs.groth16.fullProve, witness generation + proving combined):
| Backend | Median | Min | Max |
|---|---|---|---|
| SnarkJS (WASM) | 224 ms | 201 ms | 423 ms |
| rapidsnark (native C++) | not benchmarked in this repo | — | — |
Benchmarked on an AMD Ryzen AI 7 350 (16 threads), Node.js v24.16.0, Windows. rapidsnark requires a native C++ build toolchain not exercised here; expect a meaningful additional speedup consistent with published rapidsnark vs. SnarkJS-WASM comparisons, but treat any specific number as unverified until benchmarked directly.
- B.J. Chen et al., "ZKML," EuroSys 2024. DOI: 10.1145/3627703.3650088
- J. Groth, "On the Size of Pairing-Based Non-interactive Arguments," EUROCRYPT 2016. DOI: 10.1007/978-3-662-49896-5_11
- L. Grassi et al., "Poseidon Hash," USENIX Security 2021. usenix.org
- K. Greshake et al., "Indirect Prompt Injection," AISec@CCS 2023. DOI: 10.1145/3605764.3623985
- S. Lee et al., "vCNN," IEEE TDSC 2024. DOI: 10.1109/TDSC.2023.3348760
- K. Wang et al., "VeriLLM: A Lightweight Framework for Publicly Verifiable Decentralized Inference," arXiv:2509.24257, 2025. DOI: 10.48550/arXiv.2509.24257
- L. Zhou et al., "SoK: DeFi Attacks," IEEE S&P 2023. DOI: 10.1109/SP46215.2023.10179435
- W. Zou, R. Geng, B. Wang, and J. Jia, "PoisonedRAG," arXiv:2402.07867, 2024. DOI: 10.48550/arXiv.2402.07867
- A. Gabizon et al., "PLONK," IACR ePrint 2019/953. eprint.iacr.org
- Z. Peng et al., "ZK Survey," AI Review 2026. DOI: 10.1007/s10462-026-11557-y
- M. Pratiwi and Y.-H. Choi, "DeFiTrace," ACM Trans. Privacy and Security, vol. 29, no. 3, 2026. DOI: 10.1145/3817054
- E. Ben-Sasson et al., "STARKs," IACR ePrint 2018/046. eprint.iacr.org
- N. Romandini, C. Mazzocca, K. Otsuki, and R. Montanari, "SoK: Security and Privacy of AI Agents for Blockchain," arXiv:2509.07131, accepted BCCA 2025. DOI: 10.48550/arXiv.2509.07131
- Y. Xie et al., "DeFort," ISSTA 2024. DOI: 10.1145/3650212.3652137
- S.K. Mudusu and S. Gentyala, "Zero-Trust Data Pipelines for AI Systems: A Framework for Secure, Verifiable, and Auditable Data Engineering," JRTCSE, vol. 14, no. 2.2, 2026. DOI: 10.70589/JRTCSE.2026.14.2.2
This repository was end-to-end verified (circuit compiled, real trusted setup run, a real proof generated and checked both off-chain and on-chain, full Hardhat test suite passing) as part of preparing the companion manuscript. That pass found and fixed several bugs that meant nothing here had actually been compiled or run before:
- The circuit used a top-level
vardeclaration pattern invalid in circom 2.x; it had never successfully compiled. Fixed by moving the constants intofunctions. - The on-chain pairing check used
vk.betainstead ofproof.Bin one term of the Groth16 equation — the proof's own B point was never actually checked. Fixed. - The pairing equation negated
vk_xandproof.Cin addition toproof.A; onlyproof.Ashould be negated. Fixed. - The router whitelist stored entries by address but looked them up via a bytes32→address reinterpretation that could never match a real address; separately, the circuit commits the router via Poseidon while the contract expected keccak256. Unified to a single hash-keyed whitelist.
VerificationKey.load()held literal placeholder values. Replaced with a real ceremony's output (dev/benchmark ceremony — regenerate before any production deployment).- The Python agent's
verify_and_executerecomputed the router hash via keccak256 while the proof committed to a Poseidon-based value, and its nullifier derivation hashed only 2 of the 4 required fields. Both fixed. - No
hardhat.config, noMockERC20contract, and notsconfig.jsonexisted, so nothing could have been compiled or tested as shipped. Added.
All numbers reported above and in the companion paper are real measurements
taken after these fixes, not estimates. Reproduce them with
npm run benchmark:input && npm run benchmark:proof (proof generation) and
npm run benchmark:gas (on-chain settlement cost).
Sunil Gentyala — Lead Cybersecurity and AI Security Consultant, HCL America Inc. IEEE Senior Member · sunil.gentyala@ieee.org · github.com/sunilgentyala
MIT License. See LICENSE for details.