Smart accounts make ownership programmable. Authentication, authorization, and recovery often depend on information that users should not have to publish: signer identities, organizational roles, policy configurations, or recovery participants.
Zero-knowledge proofs offer another approach. An account can verify that its conditions were satisfied without receiving all the sensitive data used to satisfy them.
Our goal was to make that approach usable and carry it beyond a circuit-level demonstration. That led us from circuit development to questions about on-chain representation, verification interfaces, and developer tooling. Each question exposed another piece of infrastructure we needed.
00 · Starting point
Starting with the statement
A ZK statement describes a claim that a proof establishes. For a smart account, that claim can govern authentication, authorization, or recovery.
Authentication
I control a key belonging to the account’s authorized signer set.
Authorization
This transaction satisfies the account’s committed policy.
Recovery
The conditions for replacing the account’s ownership configuration have been met.
The circuit constrains what must be true. Private inputs supply the sensitive evidence. Public inputs connect the proof to the account’s commitments and the operation being authorized.
This is what we mean by programming private-state logic. The rules can remain inspectable while signer identities, policy parameters, and other witness data stay private. What is disclosed depends on the statement and its public inputs.
Our research did not give us a ready-made, shared workflow for bringing ZK cryptography, proving systems, and smart accounts together around private account logic. We found ourselves asking three practical questions.
01 · Representation
How do we represent a statement on-chain?
Our first question was about identity and trust: how can a smart account reference a specific ZK statement, and how could that statement become an entry in a trusted registry?
A proof is evidence for a claim, rather than a description of the claim. A Merkle root commits to state, while leaving the governing rules unstated. Neither tells an account developer what they are trusting on its own.
A circuit or program and its corresponding verification configuration.
Represented on-chain through commitments such as Merkle roots.
The contract that checks evidence against the statement and supplied public inputs.
This distinction shaped our architecture. A deployed verifier can serve as an on-chain reference to a statement and proof-system implementation, while the account stores or references the commitments relevant to its configuration.
It also clarified what a trusted registry would need to do. A useful registry must connect an entry to the intended verifier, statement version, and supporting review information. Registering an address or attaching a description does not establish that a circuit is correct or safe.
02 · Verification
Can accounts verify proofs through one interface?
Working across Groth16 with Circom, Honk with Noir, and systems such as SP1 zkVM brought the next problem into focus: their verifier interfaces differ. Proof formats and public-input encodings differ, and some APIs require extra system-specific arguments. Without an abstraction, these differences become part of the smart account’s integration code.
We developed ERC-8039, authored by Microchain Labs, as a proposed common interface for on-chain ZK-proof verification. Its design follows the ERC-1271 pattern: callers use a stable interface while the implementation handles the underlying verification mechanism.
function verifyProof(
bytes calldata publicInputs,
bytes calldata proof
) external view returns (bytes4 magicValue);
function getProofType() external view returns (bytes32);
function metadata() external view returns (string memory);
The functions answer three questions: does the proof verify, which proof-system implementation verifies it, and what does the verifier describe itself as proving?
Successful verification returns 0x534f5876. Invalid proofs return 0x00000000. Each verifier specializes in a statement and proof-system implementation; its adapter handles the underlying encoding and verification call.
Metadata is descriptive. Replacing a verifier still requires checking statement equivalence, public-input semantics, security assumptions, and account upgrade permissions. Proofs must also bind to the relevant operation and context, while the account enforces its commitments and replay rules.
03 · Tooling
How do developers understand and test a statement?
Once a statement has an on-chain verifier, another gap remains: how does someone understand what it means before relying on it?
A verifier address cannot show how a signer set becomes a commitment. An interface cannot demonstrate why a transaction passes one policy and fails another. Circuit source is essential, though these relationships still need a form developers can explore.
We built the zk-smart-account-kit playground to explain a statement, expose its inputs, simulate its behavior, and let developers experiment with proofs.
Explore label-to-identifier bindings, Merkle commitments, and membership inputs.
Explore signature-based membership in an authorized signer set.
Configure signer sets and thresholds, then simulate participation.
Configure transaction rules and inspect whether candidate transactions satisfy them.
The implementation includes browser-side Noir circuit execution, UltraHonk proof generation, and local proof verification for supported circuits.
These provide distinct forms of feedback. A simulation explains behavior. Circuit execution checks a witness against constraints. Proof verification checks the resulting cryptographic evidence. Each remains separate from an audit of whether the circuit expresses the intended policy.
Our direction is to generalize this workflow beyond the initial primitives: a statement should come with a way to understand it, configure its inputs, and test its behavior. The current interface supports dedicated experiences for its included statements. Private recovery remains part of the broader motivation and is not yet a dedicated playground module.
04 · Synthesis
One research effort, complementary contributions
These contributions came from trying to make each previous layer usable. Programming private account logic required precise statements and state commitments. Referencing those statements raised questions about identity and trust. Integrating multiple proving systems led to ERC-8039. Making the primitives understandable led to the playground.
A trusted registry can build on these foundations and add its own review and governance model. That is the focus of our R&D: turning cryptographic capabilities into reusable smart-account infrastructure, with a workflow where private account logic can be specified, inspected, tested, and integrated without every team reconstructing the same foundations.
Explore the work