Using ZK Sessions to improve UX

Rarimo
7 min readSep 24, 2024

With love for ZK use cases

Oleksandr Kurbatov

Love, Death & Robots Key Management

Let’s start with a little backstory. Let me introduce Bob (all names and events in the article are fictitious; any similarities with real people are accidental). Bob has an active lifestyle: he pets his dog, sits on social networks, uses financial applications, and chats with friends and his beloved Alice (❤️).

Bob has a lot of daily digital routines, which require the help of his personal robot assistant, Chappie (🤖). Chappie has enough information about Bob to imitate his behavior in the digital space: entertain Alice with jokes, go through KYC procedures on the exchange, leave reviews on the refrigerator that broke yesterday, etc. All that holds Chappie back from dominating the digital space over Bob () is strict role management.

Here is a quick note about the cornerstone of Bob’s security — his key pair. Let’s call it the main identity key pair. With this key pair, Bob can:

  • Ensure the authenticity and integrity of data sent by Bob (digital signature of messages, requests, transactions, etc.).
  • Log in to applications.
  • Build all sorts of cryptographic tricks that ensure his privacy in the digital space.
  • Authorize other keys to act on his behalf (in conjunction with permissions).

Notations

We plan to use a series of notations for the basic cryptographic transformations we refer to in this article. We will keep them as simple as possible without losing consistency.

ski,Pi — the keypair of the user i. Pi=skiG, where G is a group generator.

sigGen(sk,m)→sig is the message signature function that takes a user’s secret key and a message as input and returns a digital signature value

sigVer(P,m,sig)→{0,1} is a signature verification function that takes as input the user’s public key, a message, and a signature and returns 0 if the signature value is correct, 1 otherwise

We will refer to zero-knowledge proofs as π{(pn,s~m):relk} where pn is an array of public signals, s~m is an array of private signals, relk is a set of relations that must be satisfied between signals.

Naive delegation

When Alice is in a bad mood, Bob prefers to delegate communication with her to Chappie, naturally ensuring the authenticity and integrity of the messages sent.

In this case, the worst way to delegate is to give Chappie the main keypair. We have already hinted that Chappie is smart enough to use the received opportunities to its advantage, so giving the keys may lead to Chappie writing to Eve instead of Alice (the consequences are anyone’s guess), leaving its owner without money or making a post that offends the owners of memecoins.

In each of these possible scenarios, an act of digital identity theft takes place.

Protected but traceable delegation

Bob can organize control of Chappie by creating additional keys and delegating access to them. We can model this protocol as follows:

  1. Bob generates a new session key pair sks,Ps. An alternative approach is Chappie generates its own keypair and provides Ps to Bob for confirmation and signing.
  2. Bob signs Ps, the set of permitted actions and expiration time using his main keypair sigGen(skB,m(Ps,rules,exp))→sigs
  3. Bob transfers sigs,rules,exp,sks,Ps to Chappie

Now Chappie can use the session key pair to sign and send messages to Alice within today’s evening and prove the validity of the session key and permissions via sigVer(PB,m(Ps,rules,exp),sigs)→0.

Suppose Chappie tries to use this key pair for other actions. In that case, the application verification service will not allow it to do so since the list of permissions does not match the one specified during delegation (or the delegation time has expired).

A little privacy for context

The protocol mentioned above works great, but it’s too public, right? Alice sees that there is a new session pair with specific permissions and expiration time, sees that it is directly certified by Bob, and sees that the connection is cryptographically provable. This approach suits Alice since she already knows that we are communicating with Bob (let’s say she doesn’t know that his robot representative exists).

However, such a session mechanism is fundamentally unsuitable for privacy-oriented applications. If Bob leaves the delegation certificate of a specific key while in an anonymous chat, this will be clearly visible.

To understand how a private solution can be arranged (using a chat as an example), let’s refer to this great Mr. Chewbacca article. So, an anonymous chat, which at the same time ensures the uniqueness of messages’ senders, can be organized as follows:

  1. Users have their keypairs ski,Pi
  2. There is a tree of chat participants, each leaf containing a corresponding public key.
  3. To send a message, the user:
  4. a. Generates the signature for the message as sigGen(ski,m)→sigi
  5. b. Calculates an account nullifier as hash(sk∣∣chatid)→null
  6. c. Generates the proof πi:

d. Sends a message along with the proof

Other chat participants see that the message was sent from the user with the specified nullifier (all messages are tied to one nullifier), but it is not known who exactly.

Such proof requires knowledge of the master secret key. Given the impossibility of transferring the key from Bob to Chappie, a delegation scheme that ensures privacy is needed.

Private delegation aka zkSessions

So, our task is to allow Chappie to get permission to act on Bob’s behalf:

  • Provable (Bob has authorized keys managed by Chappie)
  • Controllable (Chappie can only perform actions authorized by Bob in advance)
  • Private (using the proposed delegation method should not violate Bob’s anonymity in applications)

Let’s not create intrigue; the approach is as follows:

  1. Bob generates a new session key pair sks,Ps. The only difference is that the key pair is not random but is generated hierarchically (and provably) from the master secret:
  2. sks=hash(sk∣∣rand),Ps=sksG
  3. Bob generates the signature sigGen(skB,m(rules,exp))→sigs
  4. Bob generates the delegation proof πs as:

When the proof is generated:

  1. Bob passes Chappie the key pair sks,Ps, and the delegation proof πs
  2. When Chappie sends messages, it additionally signs them with sigGen(sks,m′)→sig′ and provides a proof πs that establishes the relationship between Ps,null, rules and expiration time.
  3. Other chat participants verify the signature sig′ and proof πs and associate the message with Bob’s nullifier.

With the same proof, Chappie cannot verify its actions for other applications or at other times. At the same time, the proof does not disclose the identity of the delegator himself.

One might reasonably ask, can Chappie disclose a Bob’s identity? The answer is yes, but it cannot create a cryptographic proof of this, even with the session key and delegation proof. And yes, such attempts are easily tracked by Bob, and the amount of scrap metal in the dump may increase.

A step towards more real cases today

Despite the prosaic nature of the story, robots will not be able to receive delegations from users to participate in core aspects of their digital lives for some time. Accordingly, the described approach will not be immediately applicable in this area. However, there is another use case that is more relevant today.

There is a myth that privacy and security exclude the possibility of good UX for users. We will show how ZK can actually improve UX for some decentralized applications. You got it right: ZK for good UX…

Potentially (and very often), we can have the following situation:

  1. The user stores and manages the keys locally, say on a mobile device (using more protected hardware devices is also possible).
  2. The user wants to use a decentralized application, the interface launched, for example, on a laptop in a browser.

This is where the problem arises: the environment where the keys are stored differs from the environment where these keys are needed to generate signatures, proofs, etc.

As in Bob’s case, a naive approach would be to export the keys from the mobile device to the laptop and manage them there, but this approach is pursued by many risks (managing keys by the browser, an unprotected laptop, etc.). Absolutely bad!

Another approach, supported by some applications, is displaying QR codes for each user step. The QR code usually stores information that needs to be signed (transaction, request, data). The user reads it, signs it locally, and transmits back only the signature value without compromising the main secret. This is more secure, but at the same time, it turns the UX into hell. Something like this funny video of the game, where each action is confirmed using Metamask.

Imagine that Metamask is installed on your phone, and each action is a new QR code. Enjoy using it…

We tried to describe an alternative approach in this article: You can create a session and delegate session keys to the device while defining policies for using these session keys. In this case, you do not compromise the master secret and provide yourself with a pleasant UX during the session (one QR per session sounds better, no?).

But… Use it wisely

--

--

Rarimo

Making digital identities & the decentralized social layer multi-chain