Nullifiers

It’s important to note that the nullifiers exist for one purpose only: to provide anonymity while preventing an account from repeating an action. For this to make sense at all creating accounts needs to be gated somehow. For anonymous currency (where nullifiers originate) an account is created on receiving a coin. In our case it is created on biometrically proven uniqueness.

Nullifiers achieve their purpose by assigning each (account, action) pair a verifiably unique pseudo-random number, the nullifier. The same account repeating the same action can then be blocked by rejecting repeated nullifiers. Anonymity is achieved by the pseudo-randomness of the nullifiers, which can not be linked back to accounts using public information. In our implementation, the nullifier is the hash of the private key with the action. The associated public key is publicly attached to the account. This allows the user to generate a zk-proof that it generated the nullifier correctly.

Note that while the zk-proof in the process also proofs knowledge of the private key and allows signing a message, this a side-effects and could also be implemented in other ways. The major drawback of this approach is that it permanently attaches a unique private key to the user, or at least for the duration of the repeat protection. Knowledge of this key allows computing all the account’s nullifiers, thus a leak also implies full traceability of this account’s actions. Conversely, a loss of key means permanent inability to generate nullifiers for the account.

Nullifiers as we use them are just one way of achieving the purpose, and others could be imagined. It is however, to the best of our knowledge, the only way to achieve the whole goal in a fully decentralized setting. In situations where we do not care about anonymity, repeated actions or decentralization, we don’t need nullifiers and could substitute other methods with different trade-offs. Specifically: If we don’t care about anonymity, regular signatures suffice. If we don’t care about repeatability, zk-signatures suffice. If we allow limited repeatability, reset counters If we don’t care about decentralization and verifiability, a trusted service can provide repeat-prevention while keeping users secret. If we don’t care about decentralization, a trusted service can generate verifiable nullifiers.

Before we go further I want to address the wide-spread abuse of our nullifiers. They are not intended to be re-used! By design they are there to prevent an action from re-occurring (e.g. double-spend in the case of anonymous currencies). So the idea of using them as ‘logins’ is wrong and there can be no problem of replayability.

The major drawback of nullifiers having long-lived keys is exacerbated by our abuse of nullifiers and our reliance on its side-effect of signing. A more conformant design for one-per-human accounts would use a nullifier to gate account creation, and then use traditional methods to do authentication, authorization, recovery, etc. If this account needs anonymity, it can use its own methods (including nullifiers using a different keypair) to achieve that. This doesn’t solve all the problems of WorldID nullifier private keys, but should limit the impact of leak to deanonymization and loss to ability to create new accounts.

Remco Bloemen
Math & Engineering
https://2π.com