All articles

Benchmarking Zero-knowledge Credential Proofs on Low-end Mobile Devices

We measured zero-knowledge credential proofs on ten Android phones, from 4 GB low-end models to flagships, to see which proofs fit which phones.

This post was kindly reviewed by John Guilding, Vikas Rushi, and Zoey.

The article is part of a series on decentralised identity and private payments for humanitarian assistance on Ethereum. Read the overview: Decentralized Identity and Private Payments on Ethereum.

Summary

To preserve privacy, checks such as age verification that involve sensitive information, must run on the devices people already own, which in many markets are low-end Android phones. We measured zero-knowledge (ZK) proofs on ten Android phones ranging from 4 GB RAM low-end models to flagships inside an ordinary application. This ensured Android’s memory limits applied just as they would in real-world use.

We ran field checks, device binding and hashing of a standard credential, all locally on the phone. The check on the standard credential in a single proof strained the low-end phones; on one of our three low-end phones, it hit Android’s memory limit and the operating system terminated it.

For more details, the benchmark results are published in the coordination-network and zkID repositories.

The problem

Some privacy checks require verifiable statements as the source of truth: that the person is enrolled in and eligible for a programme, or meets an age requirement. A ZK proof lets the phone provide that statement without disclosing the rest of the credential stored on the phone, such as a date of birth. We call the answers from the credential, together with their proof, a presentation.

In the full flow, an issuer signs the credential, the holder’s phone stores it and generates the proof, and a verifier sends the request and checks the proof. Because the phone generates the proof, the credential never leaves it and no server sees it. This improves privacy, since the sensitive information stays on the user’s phone throughout. Therefore, the proof has to fit the device the holder owns, in both speed (fast enough for good UX) and memory (generating proofs reliably without Android closing the app).

Existing benchmarks such as client-side proving (CSP) benchmarks and laptop runs cannot show which proofs fit which phones under each Android phone’s memory limits. We found that on a low-end phone, RAM can be a major limit for generating ZK proofs over a standard credential. The limit is easier to hit because the phone may be running other apps in the background, and part of the RAM serves the operating system.

To measure performance in real-world use cases, we benchmarked two credential systems, the Coordination Network and OpenAC, alongside three distinct single-statement proof circuits.

Why it matters

Understanding the user experience of running ZK systems on low-end devices in real-world use cases helps us find the bottlenecks to mass adoption. In Southeast Asia, more than 60% of smartphones shipped in the third quarter of 2025 cost under US$200, according to Omdia.

For UX, the wait before each presentation and the size of the files to download before first use (including keys and related artifacts, if any) are critical to both users and products adopting privacy-preserving solutions. Solid progress can only be made with a thorough understanding of the current landscape.

What we built

We built a benchmark of ZK proofs on ten Android phones. It runs inside an app so that Android’s memory limits apply. It measures time and memory. We group the phones into three tiers by memory: low-end (4 GB), mid-range (6 to 8 GB) and flagship (12 to 16 GB).

Only the every-presentation band runs while the user waits. Times are repeat presentations on low-end phones.

Figure 1. Only the every-presentation band runs while the user waits. Times are repeat presentations on low-end phones.

The two credential systems

The coordination network, which is featured in this work, is an identity and payment system for networks of organizations. Its issuer signs credentials in a format designed for proofs (EdDSA over Poseidon hashes), and one proof covers the eight checks listed in Figure 1. The proof incorporates the verifier’s challenge, so it cannot begin before the request arrives. In its trust model, the device key resides on the holder’s phone alongside about 11 MB of files. The verifier holds a 3.7 KB key and learns that an approved issuer signed the credential, but not which one.

The latest version of OpenAC+ (v5.0.0, used in this benchmark), supporting generalized predicates from the zkID project, produces ZK presentations from SD-JWT (Selective Disclosure for JSON Web Tokens) credentials. Prepare runs once per credential: it hashes and parses the token, checks the issuer’s signature, selects two claim fields and saves the state. Each presentation re-randomizes the Prepare proof, so that verifiers cannot link two presentations, and generates a Show proof of the device key and up to two checks. Only Show incorporates the verifier’s challenge. In its trust model, the device key resides on the phone alongside about 500 MB of files, and the verifier holds about 437 MB of keys. The verifier currently learns which issuer signed, and revocation is handled outside the proof.

Single-check proofs

To separate the cost of a check from the cost of the prover, we added three single-check proofs: CSP’s circuits compiled with our toolchain. They are SHA-256 over a 2 KB message on UltraHonk (the coordination network’s prover) and on Spartan2 (OpenAC’s prover), and a P-256 signature check, as used in device binding.

Results on ten phones

Most checks completed on every phone; one large proof strained the low-end phones.

Which checks fit which phones

Field checks are a laptop gate count; every other cell ran on phones. An OpenAC presentation is two rows taken together, re-randomizing and Show.

Figure 2. Field checks are a laptop gate count; every other cell ran on phones. An OpenAC presentation is two rows taken together, re-randomizing and Show.

Field checks, such as age verification or programme eligibility, fit every phone we tested, as do membership and signatures designed for proofs. A full coordination network proof takes 8 to 10s on a low-end phone, about three times as long as on a mid-range phone. Moreover, hashing a standard 2 KB credential with SHA-256 also fits every phone, on either prover. Checking a whole SD-JWT in one proof, OpenAC’s Prepare step, is the exception: on one of our three low-end phones, Android terminated it when it hit the memory limit.

Memory and wait time

Memory determines whether a proof can be generated or not; latency can be accommodated in the application’s design. On Android, background applications and your own application share the RAM, and Android’s low-memory killer closes applications when memory runs short.

As a rule of thumb, we assume one application can use about half of a low-end phone’s RAM, approximately 2 GiB on a 4 GB phone.

Highest peak across our three low-end phones. To evaluate OpenAC presentations on the A06 without disruption, we used Prepare output generated on a laptop.

Figure 3. Highest peak across our three low-end phones. To evaluate OpenAC presentations on the A06 without disruption, we used Prepare output generated on a laptop.

A small proof such as OpenAC’s Show peaks at about 0.3 GiB and the coordination network’s presentation at about 0.5 GiB, while OpenAC’s Prepare and re-randomizing peak close to the line. On the Galaxy A06, Android terminated Prepare in the foreground at about 2.2 GiB, so the application closed before the credential was ready. On the other two low-end phones, Prepare’s first run took 15 and 35s.

On a low-end phone, a repeat OpenAC presentation takes 6 to 12s, most of it spent re-randomizing (5.4 to 7.2s), against 1 to 2s on a flagship. Show takes under a second on most low-end phones. A coordination network presentation takes about 3s on a mid-range phone and about 2s on a flagship. Its first presentation after installation takes 13 to 17s on a low-end phone, including a one-time derivation of its verification key.

What each check costs

In the coordination network, device binding is the most costly check. Device binding, a P-256 signature by the device key, accounts for 40% of the circuit’s gates, because P-256 arithmetic is foreign to the curve the circuit proves over. Removing it made laptop proving 25% faster. The issuer’s signature accounts for 5%, because it uses EdDSA on the Baby Jubjub curve over Poseidon hashes, both designed to be inexpensive inside a proof. The validity window and the programme and country check take a dozen gates.

Gates saved by removing each check, counted on a laptop. The bars do not add up to the total because some minor checks are not counted.

Figure 4. Gates saved by removing each check, counted on a laptop. The bars do not add up to the total because some minor checks are not counted.

OpenAC proves over a curve matched to P-256, so its device check fits within the small Show proof. Its large proof is Prepare, about 1.6 million constraints, mostly hashing and parsing the SD-JWT; Show is about 19,000. Gates and constraints are not directly comparable.

The single checks show the prover trading time for memory. On a low-end phone, SHA-256 over a standard credential took about 10s and at most 0.72 GiB on UltraHonk, against about 3.6s and 1.33 GiB on Spartan2. P-256 alone took about 3.0s. All three completed on the low-end phones, though the UX could be further improved.

As for the strain, we infer that it comes from hashing and parsing a whole SD-JWT in one proof. On OpenAC’s prover the hash alone peaked at 1.0 to 1.5 GiB, and the whole of Prepare at 1.8 to 2.8 GiB. Prepare adds decoding, substring matching and a second hash of each disclosed field, and the P-256 arithmetic in its signature check is small on OpenAC’s curve.

What moves a proof between columns is the credential format, how much of a standard credential one proof hashes and parses, and the prover. The number of checks matters less: eight checks fit comfortably within the coordination network’s proof.

How it is different

A laptop run and the published CSP benchmarks provide a useful first estimate. We measured on phones, against predictions committed in two steps: for the two systems before any phone ran, and for the single checks before their own runs. A laptop predicted presentation time well and memory poorly.

Presentation memory came in higher than predicted on every tier: OpenAC’s by up to 35%, and the coordination network’s most on low-end phones (0.62 against 0.38 GiB). An interesting fact is that the moto g05 and the Infinix SMART 8 have nearly the same chip score, yet differed threefold on repeat Prepare runs. A chip score is only a guide.

The two systems only; Appendix B lists the single-check predictions. On the center line the phone matched the prediction; shaded bands mark a miss.

Figure 5. The two systems only; Appendix B lists the single-check predictions. On the center line the phone matched the prediction; shaded bands mark a miss.

As a rough rule for readers who have only the published numbers, a presentation proof took a low-end phone about 6 to 7 times as long as CSP’s benchmark machine, a mid-range phone about twice as long, and a flagship about 1.5 times as long. On the single checks the rule came close for SHA-256 on low-end phones, overestimated P-256, whose published circuit is larger than ours, and underestimated Spartan2 on faster phones (Appendix A).

Limitations and next steps

We tested ten physical phones, with one set of runs per phone per workload set. The table lists what the results do not cover, what each gap means for a reader, and a potential mitigation. Notice that the mitigations are proposals drawn from our own observations; none has been tested.

Limitations

Limitation What it means for the results Potential mitigation
One set of runs per phone: a first run and five repeats, on two dates Medians rest on five repeats, and the Infinix SMART 8’s firmware changed between the two dates Repeat the runs across more sessions and dates, and hold firmware constant within any comparison
Peak memory is resident memory (VmHWM), which includes mapped key files and excludes pages compressed into zRAM. The Infinix SMART 8’s repeat runs reported far lower peaks than its first runs Peaks are comparable within our runs, but they are a floor on the Infinix and are not the quantity the low-memory killer acts on Measure PSS as well as VmHWM, separate anonymous from file-backed memory, and record memory-pressure signals alongside each peak
Laptop predictions underestimated memory on every tier and missed four single-check cells A laptop alone will under-provision memory for low-end phones Calibrate memory predictions with a factor measured on at least one low-end phone, and calibrate time per prover and tier rather than by chip score alone
Application size, battery use, integration effort and the wait users accept were not measured A proof that fits may still be too slow for a service point, and key downloads affect installation Run a study of users’ Tolerable Waiting Time. Load keys at application start, which removes the first-presentation delay from the point of use

Try it, talk to us

The benchmark results are on the coordination network’s bench/android branch and zkID’s bench/android-midrange branch.

If you are looking for a privacy-preserving credential system and would like a feasibility check on your target users’ devices, contact us: epic@ethereum.org

Appendix A. How we tested

Tier RAM Phones
Low-end 4 GB Galaxy A06 (Helio G85), Infinix SMART 8 (Unisoc T606), moto g05 (Helio G81 Extreme)
Mid-range 6 to 8 GB Galaxy A35 (Exynos 1380), Galaxy A55 (Exynos 1480), Pixel 8a (Tensor G3)
Flagship 12 to 16 GB Pixel 9 Pro (Tensor G4), Galaxy S23 Ultra (Snapdragon 8 Gen 2), Pixel 11 Pro (Tensor G6), Galaxy S26+ (Snapdragon 8 Elite Gen 5)

We rented ten physical phones on Google’s Developer Device Platform. The low-end selection follows regional sales data: the Galaxy A06 was Latin America’s best-selling phone of 2025, and the moto g05 was sixth on the same list (Counterpoint, via GSMArena). Transsion, which makes Infinix phones, leads in Indonesia and the Philippines (Omdia). The platform does not offer the S26 Ultra, so the S26+ stands in for the newest Samsung flagship.

On each phone:

  • We recorded the model, chip, RAM and Android version, the free memory before every run, and the thermal status every 10 seconds.
  • Each workload ran in a fresh application process: one first run, then five repeats, reported as their median.
  • The phone wrote its last proof to storage, and we verified it on a laptop. A run without a verifying proof does not count as having run.
  • Before each run, we waited for the phone to return to a normal thermal state. No phone reached a throttling state.
  • A run that Android terminated was retried once, and we kept the evidence of the termination from the system log.

We ran an application rather than a command-line binary because a binary is not subject to Android’s low-memory killer, and would therefore understate the memory pressure a real application faces.

Memory figures are in GiB and file sizes in MB. A phone sold as 4 GB reports about 3.6 GiB of usable RAM, so the 2 GiB rule sits a little above half of what the phone reports. Peak memory is the application process’s peak resident memory (VmHWM in /proc/self/status), reset just before each step; we report the highest across a workload’s runs. The Infinix SMART 8’s repeat runs reported far lower peaks than its first runs (0.22 against 1.29 GiB for an OpenAC presentation), so we treat its peaks as a floor.

The single-check proofs use the circuits from the client-side proving (CSP) benchmarks: SHA-256 over a 2 KB message and ECDSA P-256 verification, compiled for UltraHonk with nargo 1.0.0-beta.22, the version the coordination network’s prover uses. Under it the SHA-256 circuit is 153,813 gates and the ECDSA circuit 46,000, against the 72,683 CSP publishes for ECDSA under an older compiler. For OpenAC’s prover we ported CSP’s SHA-256 circuit to the Spartan2 version OpenAC uses (873,466 constraints). That version’s prover failed on CSP’s layout, so the port commits the hash’s witness in a different phase; the statement it proves, the digest of the message, is unchanged.

System On the phone Verifier needs Proof
Coordination network 2.1 MB circuit, 8.4 MB of setup data shared across circuits 3.7 KB verification key 14.7 KB
OpenAC 437 MB of keys shared by all credentials, plus 67.2 MB of saved Prepare state per credential about 437 MB of verification keys 159.5 KB (two proofs)

Appendix B. Per-phone results

Repeat presentation time per phone, for both systems:

The first presentation after the application starts took about 1.7 times as long.

Figure 6. The first presentation after the application starts took about 1.7 times as long.

Peak memory per phone, against the 2 GiB rule on the 4 GB phones:

Free memory is not a hard limit. The A06’s presentation completed at 1.93 GiB with 1.3 to 1.6 GiB free, which suggests Android closed background applications to make room.

Figure 7. Free memory is not a hard limit. The A06’s presentation completed at 1.93 GiB with 1.3 to 1.6 GiB free, which suggests Android closed background applications to make room.

On the low-end phones, a repeat OpenAC presentation split into the following steps, as medians in seconds. The whole presentation is its own median, not the sum of the steps.

Phone Show Show re-randomizing Prepare re-randomizing Whole presentation
Galaxy A06 0.51 0.26 5.35 6.2
Infinix SMART 8 3.69 1.14 7.24 12.1
moto g05 0.69 0.31 5.91 7.0

Times in seconds, first / repeat:

Phone Free before run Coordination network OpenAC Show OpenAC Prepare
Galaxy A06 1.3 to 1.6 GiB 13.3 / 7.9 11.2 / 6.2 terminated by Android
Infinix SMART 8 2.3 to 2.5 GiB 15.7 / 9.1 15.8 / 12.1 35.3 / 33.5
moto g05 1.8 to 2.0 GiB 16.9 / 9.6 11.4 / 7.0 14.6 / 10.2
Galaxy A35 2.7 GiB 6.1 / 3.6 4.9 / 2.7 5.1 / 3.4
Galaxy A55 3.9 to 4.1 GiB 4.7 / 2.8 4.1 / 2.3 4.2 / 2.9
Pixel 8a 3.2 to 3.5 GiB 4.8 / 2.8 3.9 / 2.5 5.4 / 4.4
Pixel 9 Pro 10.2 to 10.5 GiB 4.7 / 2.8 3.5 / 2.2 4.4 / 3.6
Galaxy S23 Ultra 6.8 to 6.9 GiB 3.3 / 1.9 2.8 / 1.5 2.7 / 1.9
Pixel 11 Pro 6.6 to 6.7 GiB 3.3 / 2.0 3.1 / 1.9 4.2 / 3.4
Galaxy S26+ 6.0 GiB 2.4 / 1.4 2.2 / 1.2 2.1 / 1.5

Peak memory in GiB:

Phone Coordination network OpenAC Show OpenAC Prepare
Galaxy A06 0.62 1.93 terminated by Android
Infinix SMART 8 0.41 1.29 1.48
moto g05 0.39 1.67 1.79
Galaxy A35 0.48 1.67 1.80
Galaxy A55 0.50 1.76 1.90
Pixel 8a 0.44 1.72 1.82
Pixel 9 Pro 0.40 1.74 1.83
Galaxy S23 Ultra 0.42 1.96 2.79
Pixel 11 Pro 0.40 1.73 1.82
Galaxy S26+ 0.45 1.73 1.82

The single-check proofs, first / repeat seconds and peak MiB:

Phone SHA-256, UltraHonk P-256, UltraHonk SHA-256, Spartan2
Galaxy A06 18.1 / 10.7, 739 4.7 / 3.3, 250 4.4 / 2.9, 1,359
Infinix SMART 8 17.1 / 10.3, 458 4.6 / 3.0, 235 12.8 / 11.8, 655
moto g05 17.5 / 10.5, 448 4.8 / 3.0, 253 5.2 / 3.6, 1,013
Galaxy A35 6.6 / 4.0, 502 1.8 / 1.2, 283 2.0 / 1.3, 1,027
Galaxy A55 5.1 / 3.1, 572 1.4 / 1.0, 319 1.6 / 1.1, 1,090
Pixel 8a 5.3 / 3.2, 490 1.6 / 1.1, 274 2.0 / 1.7, 1,030
Pixel 9 Pro 5.2 / 3.2, 468 1.6 / 1.1, 262 1.7 / 1.5, 1,040
Galaxy S23 Ultra 3.5 / 2.1, 509 1.1 / 0.8, 308 1.1 / 0.8, 1,547
Pixel 11 Pro 3.6 / 2.2, 459 1.0 / 0.8, 262 1.7 / 1.4, 1,029
Galaxy S26+ 2.6 / 1.6, 503 0.7 / 0.5, 269 0.8 / 0.5, 1,034

The low-end OpenAC Prepare row shows the moto g05 and the Infinix SMART 8 separately, because their median would hide the spread; Prepare did not complete on the A06. The A06’s OpenAC presentations used Prepare output generated on a laptop. The Infinix’s firmware changed between the two run dates, and its peaks are a floor on both.

Sources