This is the second article in a series that introduces Zeronym’s Clean Hands verification. Read the first one here.
Crypto needs a way to prevent hackers and bad actors (like North Korea’s Lazarus group bad) from using privacy protocols to funnel stolen funds without compromising privacy for everybody else. This article provides an overview of how Zeronym’s Clean Hands verification solves this long-standing challenge, refuting the arguments for both mass surveillance and for crypto as an effective black-market tool.
Overview of the Clean Hands Flow
There are five steps in the Clean Hands flow.
Credential issuance
Proof generation
Attestation issuance
On-chain activity
Decryption
1. Credential issuance
The user verifies their ID to Zeronym’s server. Zeronym queries whether the user is on any sanctions lists. If the user is not on any sanctions lists and hasn’t already received Clean Hands credentials, Zeronym issues signed credentials to the user. Privacy is crucial here. Zeronym does not store any sensitive user information. The user’s name and birthdate passes through RAM so that the sanctions list query can be made, but is never stored in permanent storage.
2. Proof generation
The user proves, in zero knowledge, that they have been issued “clean hands” credentials by Zeronym and that they have encrypted their information (in this case, name and birthdate) to Mishti Network. Zero knowledge proofs protect the user’s sensitive information, revealing nothing about the user except the fact the user is approved. The user’s personal information isn’t revealed, but the proof still establishes that the correct information is encrypted. For encryption, the user generates an ephemeral private key. They also use this key to sign an access conditions contract, a contract which determines for Mishti Network who is allowed to decrypt the user’s information.
3. Attestation issuance
The user sends the zero knowledge proof (ZKP) and signature of the conditions contract to an Observer node, which stores the encrypted information and issues an on-chain attestation to the user. This attestation says that the user is not on any sanctions lists, has provided the ciphertext of their identifying information, and has signed off on a particular access condition contract.
4. On-chain activity
At this point, with the attestation in-hand, the user can interact with smart contracts that require it, for example, the Ethereum-Aztec bridge which allows verified users to transaction privately.
5. Decryption
In most cases, there will be no reason for the user’s information to be decrypted. However, there will be some cases where a user’s blockchain address is connected to suspicious activity (identified using tools from Elliptic or TRM Labs, for example). In such cases, an entity–such as a regulator or compliance officer at a regulated DeFi project–might want to decrypt the user’s information. The entity can request the ciphertext of the user’s information from the Observer and can then request decryption from Mishti Network. Mishti Network will only accept the request if the conditions contract explicitly grants access to the entity requesting decryption. This prevents unscrupulous surveillance and data breaches, while still allowing for compliance with regulatory guidelines.
Complete flow in one diagram
Aside: Threshold decryption with Mishti Network
Mishti Network is a threshold network. This means the private key corresponding to Mishti’s public key is not controlled by any single entity. So, when we say the user encrypts their data to Mishti, we mean that the user encrypts their data to Mishti’s public key. In the decryption procedure, each Mishti node only returns a decryption share to the decryptor. The shares must be combined in a process known as Lagrange interpolation in order to arrive at the decrypted data. A Mishti node only returns decryption shares to a requester if the requester has been granted access according to the conditions contract that is associated with the ciphertext. This threshold mechanism combined with the conditions contract check is what lets users encrypt data to Mishti, and for another party to decrypt the data according to predefined conditions.
Let’s dive into each step in more detail.
1. Credential issuance
In this part of the flow, the user verifies their identity, and Zeronym uses this verified info to look them up in sanctions lists, politically exposed persons lists, and watchlists. If the user is not on the queried lists, Zeronym issues credentials to the user which can be used to generate zero knowledge proofs. We use a standard KYC flow to verify the user’s name and date of birth, and a third-party API to query the sanctions lists. To ensure Sybil resistance, we store a hash of the user’s identifying data and do not allow the same user to verify multiple times. In the future, we plan on increasing privacy by enabling NFC-based identity verification instead of using standard KYC, allowing the user to avoid sending images of their face or government ID to any server.
The whole flow here is pretty standard, except for one piece. The Clean Hands flow (where the user is issued credentials that say the user is not on any sanctions lists) is actually distinct from the identity verification (IDV) flow (where the user verifies their name, birthdate, address, etc.), and we use a ZKP to allow the user to take their credentials from the IDV flow and prove that they are who they say they are in the Clean Hands flow. We can do this because the server that verifies that the user is not on any sanctions lists only needs to know the user’s name and date of birth. This extra modularity allows better UX and privacy. Users who do not want the Clean Hands credentials do not have to opt out of it in a menu in the regular IDV flow. Users who do want the credentials can get it without any UX friction aside from a loading screen, and our server can trust that the provided identity data is accurate. An additional, future benefit is that we will be able to plug in different methods of identity verification. A user will not be restricted to verifying their identity in a KYC flow but could, e.g., use the name and date of birth from their NFC passport to generate the ZKP used in the Clean Hands flow.
2. Proof generation
The zero knowledge circuit for the Clean Hands attestation verifies Zeronym’s signature of the credentials issued in the last step, encrypts the user’s name and date of birth, and outputs the ciphertext and the public key used for encryption. By verifying Zeronym’s signature, the circuit proves that the encrypted data is the data issued in the credential issuance step. Further, because encryption is performed in-circuit and because the public key is visible, our server knows that the user encrypted their data to Mishti Network. So, our server knows that the user encrypted the correct data to the correct public key, even though the server will never see the plaintext.
At this step, we also establish a verifiable link between the user’s ciphertext and the user’s selected access conditions smart contract, the contract which tells Mishti Network who can decrypt the user’s ciphertext. Before encrypting, the user must generate an ephemeral private key. This private key is used for ElGamal encryption in the circuit. The ElGamal encryption algorithm outputs ciphertext (c1, c2). c1 is a public key derived from the private key. This public key is used to arrive at a shared secret which is then used in decryption. Because this public key is part of the ciphertext, we can use it to verify a signature from the same private key used for encryption–which is what we do. With the same private key, the user signs the access conditions smart contract and encrypts their data, establishing a link between the contract and the ciphertext, a link which Mishti Network verifies before returning the decryption shares.
3. Attestation issuance
The user needs some on-chain representation that they have completed their Clean Hands verification, so we issue an attestation to their blockchain address. We use Sign Protocol to record attestations. (See the attestation schema here.) Before attesting, we do the following.
Verify the ZKP.
Make sure the encryption key output by the circuit is Mishti Network’s public key.
Make sure the issuer address output by the circuit is the Zeronym Clean Hands issuer.
Make sure the conditions contract signed by the user is on our whitelist.
Verify the user’s signature of the conditions contract.
Store the ZKP’s public values, including the ciphertext.
The Clean Hands ZKP also takes as input a blockchain address. It outputs this as well. The user selects which address they want to input here. We use this to establish a link between the user’s blockchain address and their ZKP in the Observer node so that the user’s ciphertext can be queried with their address. We send the attestation to this address.
Like the other Zeronym circuits, the Clean Hands circuit outputs an action nullifier. This allows for uniqueness checks. At credential issuance, each user is given a secret nullifier with their credentials. The circuit outputs a hash of an action ID and the user’s nullifier. We include this nullifier in the attestation in case DApps or other verifying parties want to check for uniqueness.
4. On-chain activity
With this attestation, users can interact with smart contracts that require it. At Holonym, for example, we have built a proof-of-concept bridge on Aztec testnet, which allows honest users to transact privately, prevents known bad actors from transacting privately, and allows for accountability for users who are honest now but at a future time engage in suspicious on-chain activity.
It’s worth noting that the Clean Hands attestation is not meant to be used in isolation. Any compliance organization that relies on the Clean Hands stack to help identify bad actors will want to use other tools to monitor the on-chain activity of users with the attestation before requesting decryption. Access controls for decryption and common concerns around it are discussed below.
5. Decryption
If someone with authority to decrypt wants to decrypt a user’s ciphertext, they do the following. After detecting suspicious on-chain activity, they use the blockchain address to query the Observer for the associated ciphertext, conditions contract address, and the user’s signature of the contract address. They send the contract address, the user’s signature, and their own signature to Mishti Network. The Mishti nodes verify the signatures. Mishti requires a signature from the address requesting decryption so that it can verify the address has been granted access to decrypt by the conditions contract. If the requester has access, and if the user’s signature verifies, the Mishti nodes return the decryption shares.
Access controls
The conditions contract signed at the time of encryption by the user is the contract that determines whether Mishti is allowed to decrypt the associated ciphertext. Given how important the whitelisted contracts are to the privacy guarantees of the system, what kinds of contracts are on or will be on the list? For version 0, we have a contract that allows a single wallet to decrypt. This wallet is controlled by Holonym Foundation. It is rate limited to 10 decryptions per 24 hours so that Holonym Foundation cannot do surveillance or lose user data in a data breach. In the future, we expect to add contracts that require more voices. For example, we want to have a contract that requires a decryptor to first get approval from a DAO multisig; the DAO could set up its own processes, likely making use of on-chain forensics tools, to ensure fair treatment of users who have allegedly engaged in suspicious activity.
Another consideration around access controls is how to present the access control conditions to the user in the UI so that they are capable of making an informed decision about whether or not they want to encrypt their data to Mishti. To make the system as clear as possible while making the UX as easy as possible, we present the user with a consent screen with a simple explanation of the access control conditions. We also keep legibility in mind when implementing conditions contracts. Simple explanations targeted at users should not obfuscate underlying complexities, especially when user privacy is at stake.
Common concerns
Collusion resistance and privacy
How do we prevent a decryptor from abusing their authority? How do we stop them from decrypting all user data and ensure privacy for honest users? The first step to preventing unwanted decryption is to implement the correct access control contracts, as discussed above. A decryptor who has to go through a process with the correct checks and balances before they can access user data will be much more likely to restrict their decryption requests to users who are genuinely suspicious. Secondly, Mishti Network needs to be sufficiently resistant to collusion from operators who might want to bypass the access control conditions set by the smart contracts. Mishti operators are economically incentivized to act honestly. Operators must restake ETH to participate in the network and to receive fees. If operators collude, they risk hurting their reputation and being kicked from the network.
Next steps for the reader
Use the Clean Hands attestation in your dapp: https://docs.holonym.id/for-developers/clean-hands
Checkout the source code for the Proof of Clean Hands with encryption circuit: https://github.com/holonym-foundation/id-hub-contracts/blob/main/zk/circuits/circom/V3CleanHands.circom
About Holonym Foundation
Holonym Foundation develops protocols that enhance the security, transparency, and interoperability of digital interactions through advanced applied cryptographic and distributed systems.
Explore the Holonym Ecosystem:
Zeronym: A private digital identity protocol that verifies users without storing or seeing sensitive information. Data stays on user devices, and only proofs of identity are submitted. Programmable privacy provides transparent accountability for identity verification use cases that require regulatory compliance.
Mishti Network: Provides decentralized cryptography primitives for a better web. It is an AVS on Eigenlayer that enables secure key derivation from passwords and private biometrics, allowing users to create web accounts linked to a private proof of their humanity that are controlled by keys that they only have access to.
Silk: An embeddable zero trust wallet that grants seamless access to the decentralized web with auto-custody. Silk is built on a decentralized back-end for key derivation and recovery. Your keys always belong to you, and only you can authenticate transactions with customizable security settings that stop scammers and hackers from draining your account.
Collect this post!
Not often we introduce a game-changing technology! Collect this post as an NFT to follow us along our journey to bring privacy technology to the masses.