Measurements

On-chain costs and limits on Stellar testnet, re-measured on 2026-10-05, with method.

Re-measured on 2026-10-05 on Stellar testnet, protocol 29 (ledger 5,029,400), against OpenZeppelin stellar-contracts v0.9.0 (df602b6). Source: MEASUREMENTS.md; raw data: ct/measurements.testnet.json.

Method

Every on-chain figure comes from simulateTransaction: the resources the RPC returns, the minimum resource fee, and the size of the assembled transaction. Limits are read live with stellar network settings. Simulation figures include whatever margin the RPC applies; that margin was not measured separately. Where a transaction was submitted, its hash is given.

Re-run with:

pnpm measure            # on-chain costs (needs a deployment and the tally-deployer identity)
pnpm bench:aggregate    # local proving times for the aggregate circuits

Network limits

LimitValue
Instructions per transaction400,000,000
Transaction size132,096 B
Disk-read entries per transaction200
Write entries per transaction200
Write bytes per transaction132,096 B
Memory per transaction41,943,040 B

Single operations

OperationCPU instructionsShare of 400MTx sizeWrite BRO / RW entriesMin resource fee (stroops)
register88,344,01622.1 %30,464 B5687 / 1550,806
confidential_transfer91,193,85422.8 %31,876 B1,1367 / 21,311,887

Proof generation

Local, Apple M4 Pro, Node 24.20.0, bb.js 0.87.0. "Warm" is the second proof after the backend is initialised.

CircuitFirst proofWarm proofProof size
register (6 public inputs)1,199 ms696 ms14,592 B
transfer (25 public inputs)2,005 ms1,321 ms14,592 B
tally_aggregate_n16, zero-knowledge (pnpm demo)2,260 ms—16,224 B

Transfers per transaction

A Stellar transaction carries one contract call, so batching needs a contract that makes the calls itself. ct/contracts/bench-batch is a measurement-only wrapper that calls confidential_transfer k times for one sender.

kCPU instructionsShare of 400MTx sizeShare of 132,096 BFits?
191,550,83822.9 %32,084 B24.3 %yes
2182,067,64245.5 %63,264 B47.9 %yes
3272,645,81168.2 %94,444 B71.5 %yes
4363,272,17190.8 %125,624 B95.1 %yes, submitted
5over budget———no

Four transfers from one sender landed in one transaction: fe362834…b59384, ledger 5,029,434, through bench contract CB6U7QX2OR3ADD3NW6NSZQWNADIC3LFJKM3MN3NND4VPPDWTPQDDA3VV. Instructions and transaction size bind together at four.

How the wrapper authorises matters. Authorising the batch with require_auth() copies every proof into the root authorisation entry, which pushed the envelope over the size limit at k = 3. Authorising with empty arguments (require_auth_for_args([])) avoids the copy.

The demo still sends one transfer per transaction.

Aggregate proofs verified on-chain (capacity only)

Tally verifies aggregate proofs off-chain. These figures only answer whether on-chain verification would fit. They were taken on a separate measurement-only verifier, CACEIWIWMRIC4XQJKO4BYUWGBSV5DTMI36JPLARUCUNLV6Q6VWO54UQJ, with non-zk proofs, because the on-chain verifier implements only the non-zk flavour.

nPublic inputsCPU instructionsShare of 400MTx sizeVerified
88091,214,36222.8 %17,452 Btrue
16152100,835,05925.2 %19,756 Btrue
64584150,810,86437.7 %33,580 Btrue

All three fit. Verification stays off-chain anyway: putting it on-chain would publish that a disclosure happened, to whom and when, and would force a proof mode that is not witness-hiding.

In-browser verification

Measured on 2026-10-05 against round-004, in headless Chromium on an Apple M4 Pro, from a production build of the site. bb.js runs single-threaded on the /verify page.

ItemValue
bb.js, loaded on the first button press2,488 KB
Structured reference string from crs.aztec.network2,051 KB
Round, deployment, circuits and pinned keys from the siteabout 300 KB
Button press to total7.7 s

Most of that time is reading account keys and events from RPC; deriving the verification key and verifying the proof take about 2 s.

Corrected figures

Previously published (August 2026, 100M cap)Now
confidential_transfer about 93,000,000 instructions, 93 % of the cap91,193,854, 22.8 % of a 400M cap
One transfer per transaction; batching impossible4 per transaction from one sender, demonstrated
Transaction size is not the constraintIt is when batching: 95.1 % at k = 4
Aggregate n = 16 verifies on-chain with 17,126 instructions to spare25.2 % of the cap; still verified off-chain, for privacy
register 87,995,074 instructions, 88.0 %88,344,016, 22.1 %
Transfer proof about 1.26 s steady state1.32 s warm on different hardware; not a regression claim