Get a Demo
Get a Demo

A journey towards a distributed ledger with privacy features

One of the main properties of DLTs is that they enjoy public verifiability, i.e. any participant in the system can evaluate the consistency and correctness of the ledger and assess its non-repudiation and no-double-spending properties while keeping no private information. At the same time, DLTs are known for maintaining some information of the ledger obscured, such as who owns which address. Each distributed ledger aims to find a balance between public verifiability and privacy. The more private a ledger is, the more difficult it is for any participant to verify its properties if they don’t have access to private information. Research in cryptography is active in finding ways to allow these systems to augment the number of privacy features while maintaining their public verifiability property. This is a series of posts where we will be adding privacy features to a distributed ledger whilst retaining public verifiability, and will discuss its trade-offs and implications.


Starting point: A ledger where only participants’ identity is private
Most of distributed ledgers, like Bitcoin or Ethereum, store their participants anonymously, while the rest of the data exchanged is public. Whether it is a permissioned or permissionless ledger, any party with access to these kind of systems will be able to see in the clear certain details of each transaction. This may not be desirable for the parties involved in that transaction. For example, a DLT may leak sensitive trading information or violate data privacy regulations. We’ll take this kind of ledger as our starting point to build privacy features on top of.


Enabling private transfers
Encrypting transaction data naively certainly achieves privacy, but we also lose our public verifiability property, as well as the possibility for third-party auditing, hindering compliance with regulations. How do we convert a ledger with anonymous participants and non-encrypted data (for parties with access to the ledger) to a private one? One of the most straight-forward applications of a DL is transferring holdings of a specific asset (i.e. money), so we will take this use case as our example. When we say private we mean that we aim to transfer holdings without revealing the participants of each transaction and without revealing the transaction graph (i.e. linkages between transactions). What properties does our encrypted data need to have in order to guarantee public verifiability and keep the door open to third-party auditing?


Homomorphic encryption
We certainly need to be able to compute arithmetic operations on top of our encrypted data. Homomorphic encryption achieves precisely this and Pedersen commitments are an example of homomorphic commitment schemes. Using Pedersen commitments to hide amounts in every transaction in our ledger, we can now guarantee that the sum of encrypted values is the encrypted sum of the values and perform our desired arithmetic operations on commitments. In short, a Pedersen commitment is a one-way function of two inputs with the following property:
cm(v1, r1) * cm(v2, r2) = cm(v1 + v2, r1 + r2)
Let’s see how we can put commitments in practice in our ledger and perform calculations on it:

null

 

For example, commitments in column Account A may have the following inputs:
 cm1A = cm(-3, r1A)
 cm2A = cm(3, r2A)
 cm3A = cm(0, r3A)
 where {r1A, r2A, r3A} are random values that Account A knows.


As we can see, each transaction is now a set of commitments, instead of a set of clear values as it was before. We not only have the identity of the participant obfuscated, but also the amount being transferred. What kind of claims can we make with the current state of the ledger where amounts are hidden using Pedersen commitments? It certainly allows an arbitrary party–let’s call them auditor–to query the ledger and verify the validity of its responses. In our example, the auditor could ask Account A to provide its current balance. It would work as follows:

  • Account A would return its balance (which is -3 + 3 + 0 = 0 in our example), alongside the sum of the random values (rsA = r1A + r2A + r3A) used to generate each commitment.
  • The auditor would multiply all commitments that are publicly visible in the ledger on Account A’s column (cmsA = cm1A * cm2A * cm3A) and will verify that it coincides with cm(0, rsA). That is, he will check that cmsA= cm(0, rsA).

Zero-knowledge proofs
Although we have achieved auditability, we haven’t tackled any of the other guarantees we want our ledger to hold: non-repudiation and no-double-spending. Here is where zero-knowledge proofs come into play. In order to keep our ledger consistent, we’ll make use of some zero-knowledge proof objects that will accompany the commitments. These proof objects ascertain that nobody has spent more money than they had and that they have only spent their own money. The proof objects and their verification do not reveal any other information than just that: they do not reveal the participants in the transfers nor the amounts transferred. Three zero-knowledge proofs will suffice to maintain consistency in our ledger while allowing parties to transfer amounts of a specific asset privately. We’ve taken the ideas and terminology from the paper “zkLedger: privacy-preserving auditing for distributed ledgers”. We’ll see later how we extend their work with the ability to swap assets atomically and privately.


The first proof proves that assets are not created or destroyed in a transaction, i.e. the sum of all the values in a transaction must be 0. In order to guarantee such a thing, we will also require that the sum of the random values used in all the commitments of a transaction is also 0. Then, a verifier can check that the product of all the commitments in a transaction is equal to cm(0,0). This proof is called “Proof of balance”. The second proof, named “Proof of assets” by Narula et al., guarantees that the spender has enough holdings of the asset he is about to spend. The third proof is called “Proof of consistency” and is a mere technicality that the reader can look up in our paper or the zkLedger paper.


Another technicality is the use of range proofs to guarantee that the inputs of our commitments lie within a range because commitments rely on modulus. We use Bulletproofs to create small and fast range proofs that, unlike zkSNARKS, require no trusted setup.


We have now achieved our initial goal: building a ledger where the amounts and parties involved in each transaction are completely hidden while still having public verifiability and third-party auditability. We’ve only talked about private transfers. What if we want to extend its functionality to swap assets atomically and privately? How is it different from private transfers?


The main difference between simply transferring assets and swapping assets is that the latter action is an asynchronous operation, while the former is synchronous. The proposal of a swap and its acceptance or rejection are normally performed at different points in time and they should not block new transactions to enter the system.


We would need to make a few changes in our private ledger in order to deal with race conditions that may arise when attempting to swap assets. We’ll explore how these changes enable multiparty workflows in our system in the next part and introduce Overlay/Upperlink, Adjoint’s implementation of a private ledger.

Extending zkLedger with private swaps

 

  • Return to News