Every number we had published came from a laptop. A prover built for client-side proving should be judged on the client, and for most people the client is a phone. We took two iPhones off the desk, one of them a 2019 model, and spent a day finding out what on-device proving costs there.
The short version. A post-quantum ML-DSA (Dilithium) signature, made inside the iPhone's Secure Enclave, proves in zero knowledge in 1.34 s on an iPhone 14 Pro Max. An RSA-2048 signature proves in 485 ms on that phone and in 832 ms on an iPhone 11 Pro Max. A private payment that spends four notes and creates four proves in 1.02 s. Every proof verifies in 15 to 34 ms on the phone that made it.

§ What the phone proves
Hekate is our zero-knowledge prover: hash-based, with no trusted setup, working over
binary fields. The mobile toolkit packs it into an iOS framework and an Android library, and an
app calls it with one async function in Swift or one suspend function in Kotlin.
The test app does what a real app would do with a hardware key. It makes a key on the phone, signs a fresh 32-byte challenge with Apple's own library and hands the signature to Rust. Rust proves the signature is valid without revealing it, and the app verifies the proof. The private key never reaches our code. The ML-DSA key never leaves the Secure Enclave.
The two statements hide different things:
- ML-DSA-65, the post-quantum signature of FIPS 204. The message and a hash of the public key are public. The public key and the signature stay hidden.
- RSA-2048 with PKCS#1 v1.5. The modulus is public. The message and the signature stay hidden.
One limit belongs next to every such claim. The proof shows that its maker holds a valid signature. It does not show that the maker holds the private key: any signature the key ever released will do. A verifier that wants a fresh one chooses the message, which the ML-DSA statement allows because its message is public.
§ The setup
Three commands build the Rust crate into frameworks and open the Xcode project. iOS hides its Developer Mode switch until the phone has met Xcode. A free Apple account is enough to sign the app. Apple gives each bundle identifier to a single team, and every other team has to change the app's before Xcode will sign it.
§ A hot phone that was no slower
The first report came from the iPhone 11 Pro Max while it was charging, with iOS reporting its thermal state as "serious": 846 ms to prove the RSA signature. We expected the heat to have cost something. We unplugged the phone, let it cool until the state read "nominal" and ran again: 832 ms. Under 2% apart, on one phone and one pair of runs.
The clean runs, each the best of three proofs, on battery, thermal state nominal, Low Power Mode off, with the released constant-time prover 0.15.0 and hekate 0.37.0. The iPhone 14 Pro Max ran iOS 26.7.1 and the iPhone 11 Pro Max iOS 18.6.2.
| ML-DSA-65, iPhone 14 Pro Max | RSA-2048, iPhone 14 Pro Max | RSA-2048, iPhone 11 Pro Max | |
|---|---|---|---|
| Witness | 190.4 ms | 89.9 ms | 150.0 ms |
| Prove | 1339.7 ms | 484.6 ms | 832.0 ms |
| Whole call | 1546.4 ms | 594.4 ms | 1014.8 ms |
| Verify | 26.2 ms | 20.7 ms | 34.1 ms |
| Proof size | 1,577 KiB | 1,808 to 1,814 KiB | 1,811 to 1,815 KiB |
The iPhone 11 Pro Max ran iOS 18, which has no ML-DSA signer, and its column stops at RSA.
For scale, the same constant-time build on an Apple M3 Max proves the RSA signature in about 240 ms and the ML-DSA signature in about 570 ms. The iPhone 14 Pro Max is 2.0 and 2.3 times slower. The seven-year-old iPhone 11 Pro Max is 3.5 times slower on RSA.
The app reports the highest physical footprint since it was launched, across the three proofs: 156 MiB for ML-DSA and 252 MiB for RSA on the iPhone 14 Pro Max, 187 MiB for RSA on the iPhone 11 Pro Max. The two phones run different iOS versions, which may count a footprint differently, and we do not compare them.
§ A private payment in one proof
Signatures are building blocks. We wanted a whole application on the phone, and we had one: the shielded payment circuit of a private-payments chain we are building. One proof covers the whole payment.

Each spent note is shown to exist in a 256-level Merkle tree. Nullifiers stop a double spend. Amounts balance per asset. A clearance rule can demand that the spender is on a whitelist or off a blacklist. Audit and recovery capsules are encrypted with AES-256 inside the proof. The payments we measured did not ask for clearance.

Four notes in and four out prove in 1.02 s. One note in and four out take 1.03 s, and a mint 1.11 s. Each verifies in 15 ms. The proof is about 1,050 KiB at 100 bits of soundness. One proof peaks at 125 MiB: the app held 14 MiB before the first proof, 125 MiB after it, and the same after the second and the third.
These three ran in one launch, mint first, with the phone on its charger, on a local SHA3 build of the prover with Hekate 0.37.0 plus six unreleased commits. The released prover hashes with BLAKE3. Treat these figures as a first measurement.
§ What these numbers are
One day and two iPhones. No Android phone has run these proofs yet. The signature figures come from the released, signed prover and are kept on the mobile benchmarks page.
§ Run it on your own phone
Pick your team in Xcode, select the phone and run. The app reports the same rows as the table above, and the examples README says what each one means.