# ZK-ID and Registrars

**Note**: the registrars, as described in the below article are optional in the design of shielder, and as such they are not part of any of the production deployments of Shielder (see [poc](https://docs.alephzero.org/aleph-zero/protocol-details/shielder/poc "mention"), [version-0.1.0](https://docs.alephzero.org/aleph-zero/protocol-details/shielder/version-0.1.0 "mention") and subsequent).

Each user of the Shielder must generate a ZK-ID: a uniformly random element `id: Scalar` -- this is a secret the user must not reveal to anyone because it is an analogue of its private key.

There is (optionally) a special party -- a Registrar -- whose role is to register users in the shielder so that they are allowed to create accounts. The Registrar maintains an offchain database of users that are verified. There could be one Registrar, multiple or none, depending on the setup.&#x20;

Each registrar holds a ECDSA "registrar key" whose public counterpart is well known (stored for instance in the shielder smart contract to verify signatures issued by the registrar). This key can be rotated, but the simplified design below does not take that into account.&#x20;

## Signing Up with a Registrar

A user with ZK-ID `id` registers offchain with a Registrar by going through an onboarding process (depending on the specific Registrar) and providing the Registrar with `Com(id)` -- a commitment to its `id`. In the simplest case the commitment can be just `c = Com(id, r) = hash(id, r)` where `r` is a random salt generated by the user (which the user needs to store). The Registrar then marks the fact or registration with a particular `Com(id)` in its internal database.

A registration, by default, is valid for a certain, limited amount of time. After the time passes the user needs to perform a refresh procedure with the Registrar, which might involve repeating some checks, depending on the specific Registrar.&#x20;

## Certifying registration

The user can receive a certificate of registration (with a particular expiration date) from a Registrar using the following procedure:

1. The user holding `id` contacts the Registrar with whom it previously registered.
2. The registrar holds  `c=Com(id, r)` -- the commitment to the `id` created by the user, but it doesn't know the randomness `r`
3. Denote by `date` the expiration timestamp of the registration.&#x20;
4. The Registrar generates a certificate for the user using the following steps:
   * Generate randomness `r'` (optionally this randomness might be contributed by the user instead)
   * Compute `reg_payload = hash(c, date, r')`
   * Compute the ECDSA signature `s` of `payload` using the "registrar key"
5. The registrar provides the user with `s, date, r'` . Apart from that, the user knows `c` because they have generated it in the first place.
6. The user can then use the "certificate" in the form of the signature `s` along with the `reg_payload` (whose content is hidden using `r'`) to certify on-chain that they hold a registered `id` with a particular expiration date. In practice the payload is used as a public input to a particular zk-relation, and the signature `s` is verified in the plain.

## Creating New Notes

After a user has registered its ZK-ID with a registrar it is allowed to create its note (initialize empty account) in the Shielder.

<pre><code>relation R_new_note

inputs:
<strong>    - reg_payload: Scalar, // payload from the Registrar
</strong>    - h_note: Scalar,
    - nullifier_create: Scalar,
    
witnesses:
    - note: Note,
    - trapdoor, nullifier: Scalar,
    - id: Scalar,
    - r: Scalar,
    - r': Scalar,
    - date: Scalar

constraints:
    1. reg_payload = hash(hash(id, r), date, r') 
    2. h_note = hash(note)
    3. note = Note { id, trapdoor, nullifier, h_acc }
    4. acc = Account::new(date)
    5. h_acc = Account::hash(acc) 
    6. nullifier_create = hash(id, NULL) // NULL is a special field element
</code></pre>

Given the above we are ready to describe the `new_note` transaction

```
transaction new_note

inputs:
    - proof_new: ZkProof,
    - h_note: Scalar,
    - proof_id: ZkProof,
    - reg_payload: Scalar,
    - s: EcdsaSignature,
    - root: Scalar, // should be a root of the tree in SC_Registrar
    - nullifier_create: Scalar,
    
    
execution:
    - assert: the signature s under reg_payload verifies with Registrar's key
    - v_new = ZK-Verifier(R_new_note) // initialize verifier for the relation R_new_note
    - assert: v_new.verify(proof_new; (reg_payload, h_note, nullifier_create))
    - assert: root is current or historical Merkle root in SC_Registrar
    - assert: nullifier_create is not in shielder.nullifier_create_set
    - v_id = ZK-Verifier(R_verify_identity)
    - shielder.notes.add_leaf(h_note)
    - shielder.nullifier_create_set.add(nullifier_create)
```

Once a note is initially created the user will keep updating it (spending it and creating a new one) and the information of the user's `id` is persisted within the note. In the above we have also introduced `nullifier_create_set` -- a new storage item in `shielder` that allows us to make sure each `id` has created just one note.&#x20;

&#x20;In [anonymity-revokers](https://docs.alephzero.org/aleph-zero/protocol-details/shielder/anonymity-revokers "mention") we describe how the information about `id` in the note can be used to add a security mechanism to deanonymize bad actors.&#x20;

### ZK-ID Expiration and Refreshing

With zk ids, there is one additional check that must be introduced in the `R_update_note` relation in [notes-and-accounts](https://docs.alephzero.org/aleph-zero/protocol-details/shielder/notes-and-accounts "mention"), namely that the id has not expired (`current_timestamp < date` in the note). In case the note has expired, the user is not allowed to transact within the shielder anymore. It has two options then:

1. Refresh the `id` with the Registrar. This happens by sending a `refresh_id` transaction that allows to bump the expiration date based on a new certificate from the Registrar.&#x20;
2. If the user doesn't want that, or the Registrar refuses to refresh the `id`, then user is allowed to withdraw all the assets, but only withdrawal is possible. Such withdrawal will also cause mandatory deanonymization using the anonymity revoking mechanism, as described in [anonymity-revokers](https://docs.alephzero.org/aleph-zero/protocol-details/shielder/anonymity-revokers "mention").
