Computationally Efficient & Private Soulbound Tokens
Shrey Jain
May 30th, 2022

One of the major concerns with SBTs is having personally identifiable data (PII) publicly available.

Here we present a framework for how to create a private SBT. The key outcomes of this article demonstrate:

  1. Identity holders are able to protect the contents of their data with the same privacy guarantees of verifiable credentials
  2. Identity holders are able to participate in the on-chain composable logic that the Web3 infrastructure is built on.
  3. Identity holders can provision access to data and control over data storage.
Image 1. Highlights the flow of a private SBT.
Image 1. Highlights the flow of a private SBT.

An SBT is simply a non-transferrable NFT (smart contract implementation of an SBT). Most NFTs will need some kind of structured metadata to describe the token's essential properties. Many encodings and data formats can be used, but the de-facto standard is to store metadata as a JSON object, encoded to a UTF-8 byte string. **

An example of what this metadata may look like in the context of an SBT:


  "Credential name": "Government Approved Age",

  "Age": "05/05/99",


Currently, this metadata is public and accessible to anyone. We focus on presenting a way to create private SBTs so that identity holders can provision access to private information.

Because storing data on a distributed ledger like Ethereum is so expensive, many NFT implementations now use decentralized or centralized storage solutions for this metadata. The average size of an NFT on the Ethereum blockchain is about 50 MB.

Our solution needs to be much smaller than the average if we are going to scale the number of SBTs to be issued for high-frequency actions.

Step 1:  Hash metadata

Using content addressing hash functions we are able to take SBT metadata and create a 32 byte unique address for this content .

We take our plaintext that we want to encode into the SBT and construct a merkle tree with it. This plaintext would be hashed with the private key of the issuer (ie., a DAO’s private key with a members plaintext data that is to be an SBT).  This will then enable us to have a unique root hash for this SBT metadata that is 32 bytes long.

The good part about this process so far, is that the plaintext or identifiable information can be stored anywhere that an identity holder wants: locally; centralized storage; decentralized storage; or on the ledger itself.

The only data that is being appended to metadata of the SBT contract itself is this unique root hash.


  "hash-data": "aPdSgVkYaPdSgVkYaPdSgVkYaPdSgVkYaPdSgVkYaPdSgVkYaPdSgVkYaPdSgVkY",


Step 2: Verifier Contract

The identity holder now has an SBT with metadata that is just a unique 32 byte hash.

A verifier is able to create a smart contract including various different queries (this is currently taken care of by circom, a zk-snark compiling provider). This library is what should be used to verify that a signature was executed by a specific address inside a circuit. A current limitation of this library is that it requires 56 GB of ram to build the ‘verify’ function.

As an example, let’s say that the objective of the contract is to show the age of an individual is over 18 years. The identity holders (whose SBT contains the 32 byte hash), would generate the proof that is the input to the smart contract.

This proof would:

  1. Demonstrate that the plaintext message (that the identity holder has stored somewhere) was signed by the issuer’s private key and when hashed, you get the hashed value in the NFT itself.
  2. Demonstrate the criteria for the claim is met (ie., over the age of 18)

By Shrey Jain and Enrico Bottazzi

Subscribe to Shrey Jain
Receive new entries directly to your inbox.
This entry has been permanently stored onchain and signed by its creator.