UTXO Cryptography

Panther's UTXO encryption/decryption model

TL;DR

  • Spender encrypts a message to recipient that is published on-chain

  • All zAccount holders scan the chain for UTXO commitments and attempt to read the message

  • Only the intended recipient, the account holding the cryptographic key, may read the message and assume spend rights to a UTXO

Introduction

An essential requirement of Panther's Shielded Pools is to ensure the untracability of transactions. To achieve this, the mainnet beta Protocol supports non-interactive transactions. That is, the spender can pass assets to the receiver's zAccount using the receiver's public read key and the public root spending key available on an public lookup registry maintained by the smart contract.

Every zAsset UTXO has one “owner” or zAccount able to spend it. This is achieved by including a unique public (spending) key in the generation of the UTXO commitment, for which the corresponding private (spending) key is only known by the recipient.

In order to spend a UTXO the owner needs to prove (in zero-knowledge) that they hold the spending private key.

A high-level overview of how the Protocol follows.

High-level overview of Panther's UTXO cryptography

The following conventions are applied to formulae:

  • lowercase letters in formulae bellow denote prime field elements ("scalars") - i.e. private keys

  • capital letters denote points on the elliptic curve - i.e. the public keys

  • '*' denotes the multiplication of an elliptic curve point by a scalar, i.e. scalar multiplication

  • The Protocol uses a shared symmetric key for encryption/decryption of messages with secrets

  • Secrets. M are UTXO's "opening values" for recipients and data for spenders to track past transactions

  • Messages passed to the smart contract are encrypted:

    • spender to receiver

    • spender to self

  • Sender publishes the Ephemeral key, E and ciphertext M' on-chain — formalizing a transaction

  • Recipient scans chain to extract M (from M' using E) to take ownership of a UTXO

  • Spender can re-create history by decrypting messages to self, M'

  • Although spender knows the UTXO's public key, only the recipient who holds the root spending private key may spend the UTXO

Next, let's take a closer look at how the cryptography behind this Protocol is implemented.

Panther Protocol keys

A "key pair" is a pair composed of a private key and its corresponding public key.

The private key is a big integer ("scalar") from the prime field defined by the Baby Jubjub elliptic curve.

The public key, P corresponding to the private key, p is a point on the curve, such that the following equation holds:

P = p * G

Where, P and p are the public and private keys, and G is the generator of the group of elliptic curve points.

The, so called Base8 point is used as the generator. This point generates a "commutative group" of curve points that cryptographers call the "Baby Jubjub subgroup".

The ECDH key agreement protocol (over the Baby Jubjub elliptic curve) is used to share the symmetric key and to derive the spending keys of UTXOs.

The following key pairs are essential to the transfer of zAssets in the form of UTXO updates:

  1. Recipient reading key pair (w, W = w * G): allows the recipient to decode messages with opening values of UTXOs, i.e. knowledge of the private key is needed to decrypt a message.

  2. Root spending key pair (s, S = s * G): enables spending of a UTXO by the owner, i.e. no matter who generates a UTXO only the holder of the private key may spend the UTXO.

The term "root" applies as spending keys for UTXOs are "derived" from this key pair.

  1. Nullifier key (n, N = n * G): required in order to generate the nullifiers for UTXOs.

This key enables compliance, by encoding the nullifier so that information in the Data Safe may reveal whether the UTXO has been spent.

Next, let's consider how spending and encryption keys are derived.

Creating a new UTXO

When a zAsset is spent, an output, i.e. a new UTXO is created.

  1. Spender selects two randoms, r and e, to derive the spending and message encryption keys.

  2. Spender derives the spending public key S' for the new UTXO from the recipient's root spending public key S and the random r:

S' = r * S

  1. Spender creates an ephemeral key using the random (e) from Step 1:

E = e * G

  1. Spender creates the shared key, K to encrypt the message to the recipient with, based on recipient's public reading key, W and the random, e:

K = e * W

  1. Spender composes the message to the recipient, M and encrypts the message into the ciphertext, M'.

5.1 Message composition. The message, M contains the information needed to spend the UTXO: random, r required for the recipient to generate the spending key, S' and other opening values (such as zAssetId and the value the UTXO represents).

5.2 Message encryption. The spender encrypts the message to the recipient with the shared key, K applying the symmetric encryption (applying the method AES-128-cbc): M' = Enc(M, K)

  1. Spender calls the Shielded Pool contract to publish the new UTXO as well the encrypted message to the recipient.

6.1 Publishes the ephemeral key, E and the ciphertext M'.

6.2 Using the same encryption key derivation method, but with own reading key instead of the recipient's reading key, the spender encrypts the message "to self". This encrypted message (which only the spender may decrypt) contains data required to reconstruct an audit trail of the spender's transactions.

Taking ownership of a UTXO

The following steps detail how a recipient is able to take ownership of the input UTXO.

1. Scan chain for ciphertexts

Each zAccount holder behaves as it is a potential recipient and scans the chain for ciphertexts, M' and ephemeral keys, E.

2. Attempt to decrypt every ciphertext

2.1 Compute the shared key, K

K = w * E

Note, if the spender encrypted the message with the recipient's public reading key (i.e. the message is intended for the recipient), the recipient derives the same shared key that the spender used:

K = w * E = w * (e * G) = e * (w * G) = e * W

2.2 Decrypt the ciphertext using that key

M = Dec(M', K)

2.3 Analyze whether the decrypted message, M is meaningful

If an encrypted message (i.e. the ciphertext and the ephemeral key) was intended for a different recipient, and thus the non-recipient computed the wrong encryption key, the decryption algorithm still returns some random (meaningless) decrypted text. However, the true recipient can easily distinguish if the decrypted text, M contains properly formed or meaningless data.

So, IF M is invalid, message is ignored. IF M is valid, recipient extracts from M the random, r and other opening values required to spend the UTXO.

2.4 Derive the private spending key for the UTXO

The recipient derives the private spending key for the UTXO:

s' = rs here, '∙' denotes multiplication of integers (in the prime field).

Note, that the private spending key derived this way indeed corresponds to its public key that the spender derived:

S' = (rs) * G = r * (s * G) = r * S

This method provides an efficient encryption/decryption mechanism, and a unique spending public key which is unlinkable to other transactions by the same recipient, even given that E is publicly accessible on-chain.

What next?

  • Learn how UTXOs represent assets locked in the Panther vault, zAssets

  • Understand how users enter a Shielded Pool to create a zAccount and transact with other account holders and the wider DeFi ecosystem

Last updated