🔓Anonymous Authentication

An online authentication application for storing profiles

Anonymous authentication is another demo app developed using HollowDB, users can create profiles while keeping their identity anonymous and the only way to update the profile is to provide a zero-knowledge proof. The full structure consists of a frontend developed with Next.js and an Express server. Refer to the GitHub repos for implementation details:

The Authentication App

This demo is intended to demonstrate the power of ZK-proofs in HollowDB by storing a profile on HollowDB contracts without revealing any information about yourself.

Connect Wallet

Wallet infrastructure uses Rainbowkit, you can simply use the Connect Wallet button and choose Metamask. Any chain supported by Metamask is good to go as HollowDB is chain agnostic!

Create Profile

HollowDB supports any type of data to be stored, for the sake of this demo, only a username and an image URL are stored.

After the Upload button is pressed, a pop-up appears requesting your signature. The hashed version of your signature will be used as the key to your profile information.

Here you go! Your profile is safely and anonymously stored on HollowDB. Any application using the same HollowDB contract can access the information.

But what about the anonymity?

Anonymous Authentication

If your information is stored publicly, how can you be anonymous? Through the power of ZK! If you refresh your page and connect your wallet again, you still won't be able to see your profile because your information can't be tracked through your address.

Retrieve Profile

A profile must be retrieved by generating the same signature again. As there is no instant way the application can know you own that key.

After generating the signature, your profile is retrieved!

Anonymity

Let's have a look at an example transaction input to see if there is any sensitive information.

{
  "data":
  {
    "key":"4735904570539279682275507070929548418220332715061423656258515080175565373207",
    "value":
    {
      "pfp":"https://expertphotography.b-cdn.net/wp-content/uploads/2020/06/stock-photography-trends11.jpg",
      "username":"Merdo"
    }
  }
}

It only contains the hashed version of your signature, which can't be tracked back as hash functions are one-way. Even if you look at the transaction, you won't be able to see any information related to your address because the transaction was created by the wallet living in the express server.

Update Profile

When a HollowDB contract state is set to enable ZK-proofs, a proof must be provided to update a key-value pair. The proof requires the pre-image (your secret) of your hashed key, meaning you're safe as long as you keep your private key safe.

Just like creating a profile, enter your new information, press the Upload button and approve the signature request.

Congrats! You have successfully created an anonymous profile using HollowDB.

Code Snippets

Here are simplified code snippets.

Create Profile

 const handleUpload = async () => {
    ...
    // Request signature using Wagmi
    const secret = await signMessageAsync();
    const key = await computeKey(valueToBigInt(secret));

    const profile = await getProfile(key);
    const curValue = profile.data.data.value;

    if (!curValue) {
      createProfile(key, form.values)
        .then((res) => {
          if (res.statusText == "OK") {
            setProfileLocal(form.values);
          }
        })
     };
     else {...} // Key exists, try to update
     ...
  };

Update Profile

  const handleUpload = async () => {
    ...
    // Request signature using Wagmi
    const secret = await signMessageAsync();
    const key = await computeKey(valueToBigInt(secret));

    const profile = await getProfile(key);
    const curValue = profile.data.data.value;

    if (!curValue) {...} // Key doesn't exists, try to create a profile
    else {
      // Generate the proof
      const { proof } = await generateProof(
        valueToBigInt(secret),
        curValue,
        form.values
      );

      updateProfile(key, form.values, proof)
        .then((res) => {
          if (res.statusText == "OK") {
            setProfileLocal(form.values);
          }
        })
     }
     ...
  };

Retrieve Profile

 const handleRetrieve = async () => {
    ...
    // Request signature using Wagmi
    const secret = await signMessageAsync();
    const key = await computeKey(valueToBigInt(secret));

    const profile = await getProfile(key);
    const curValue = profile.data.data.value;
    if (curValue) {
      setProfileLocal(curValue);
    } 
    ...
  };

Last updated