Oh, no. All right, I think we're live.
I will just double check something and be right back.
All right, maybe somebody on the Aptos team can confirm they can hear me.
So let's just get started then.
I am the head of cryptography at Aptos Labs.
I've been with Aptos for four years since we started the project.
And today I have the great
pleasure of telling you about confidential assets which is one of my
dearest project so I'll just begin by having a moment of silence for veiled
coins which was the initial name of confidential assets this was very dear
to my heart where unfortunately it didn't stick and with that, this is what we're going to talk about today.
I'm going to explain to you what confidential assets are.
I'm going to explain to you why we built confidential assets.
I'm going to show you a little demo to see how nice the UX can be for confidentiality.
And then the most fun part for me is I'm going to discuss how confidential assets work at a
really low cryptographic level. And with that being said, let's
get started. So as many of you know, the current status quo on
blockchains, including Aptos is that everything is public.
These, these things are really designed for public state and
public transactions. So if I have two Aptos accounts, Alice and
Bob here with their secret keys, if Alice has a public balance for public state and public transactions. So if I have two Aptos accounts, Alice and Bob,
here with their secret keys,
if Alice has a public balance of 250
and Bob has a public balance of 100,
Alice can send the public transaction,
and then the blockchain will validate
and adjust their balances.
So we're all familiar with this.
This is kind of great, but it's not so great for privacy.
Everybody sees Alice's balances and Bob's balances. Everybody sees the transaction amount
being transferred, and everybody sees that Alice and Bob are transacting. So how can we improve
over this? The idea is to add confidentiality as an option for transfers.
So imagine we let our users to keep or maintain a confidential balance next to their public balance.
So here Alice has 700 confidential coins and Bob has 500 confidential coins.
And now we create this new transaction type, which is still sort of a public transaction in the sense that it still leaks that address is sending and it still leaks that Bob is receiving,
but it no longer leaks the amount.
And the amount is going to be transferred between Alice's confidential to Bob's confidential
And so that's kind of what we're trying to get here.
We're trying to add optionality for confidentiality by creating a separate balance and allowing users to transfer
between the separate confidential balances right so the idea here is that
nobody sees that your confidential balance nobody sees the transferred
amount people of course will continue to see our public balance that there's
nothing we can do about that the blockchain is live it's been designed
with with public balances from from the get-go we would have to break everybody by removing
public balances but what we can do is we can add confidential balances right uh and an important
caveat here is that if there is an auditor installed via governance then this auditor can
also optionally see the transferred amount and And although not depicted in this slide,
it can also see the encrypted balances, which will also be
encrypted for the order. And as I mentioned before, everybody,
the validators, the full nodes, everybody who has access access
to the state or the chain's history, can see the sender and
the recipient addresses being involved
in these confidential transactions. So that is not a goal of this work. That is separate work.
Maybe we'll do that too later on down the road. All right. So now let's talk a little bit about
the why. Why are we doing this? So the reason we're doing this is because fundamentally
confidentiality is about user safety.
So if you can hide balances and amounts, then you can protect your users.
A lot of users are getting targeted because people can see how much coins they have.
Another reason to do it is because it unlocks new use cases.
So you can imagine now you could have on-chain salaries being paid into your confidential balance
without linking to everybody how much money you make.
We can also think about doing the same things
for RSU and token grants.
And I think there's other use cases too
that are much more open-ended like DeFi
and maybe we'll touch upon that later.
That being said, I do want to emphasize
that this feature is just about sending money
If you want to do DeFi, that'll involve more work
being built on top of this
feature. So currently that's not supported. Another reason to do things this way is to
have some regulatory compliance. So we want third party auditors to see things in order
to detect abuse and maintain a same deployment, let's say. Lastly, I think it's really about building more human systems, right?
So if you think of the public world that we have right now on chain,
it's not exactly an intuitive world for people to live in.
Like your bank account right now is not public.
Your transaction history right now in Bank of America is not public.
And I think the commissioner of the SEC recently, Hester Pierce, put this very beautifully. She said that human
dignity is about your ability to choose what information you reveal about yourself. And I
think that's exactly right. And so what confidential assets let you do is avoid revealing your balance
and avoid revealing your transferred amounts.
And so this is at a high level why we're doing this work.
We're trying to protect our users.
We're trying to unlock new use cases.
We're trying not to break the law.
And at the same time, we're trying
to build more human systems.
All right, so with that being said,
I'm gonna show you a small demo.
problems. So I will share my screen. This is actually before I'm going to show you, I'm just
going to discuss a little bit what's going to happen. So we built this Venmo-like application
at confidential.aptoslabs.com, where you can sign in using your Google account. And then this uses
Aptos keyless accounts. There's
no key management that you need to do as a user, there's no wallet that you need
to install and when you log in you get pretty much a Venmo-like flow. So you can
deposit some coins and then you can send coins confidentially and then if you've
received coins you can sort of publicly withdraw them back into your public
ballots if you want. And importantly, we have a very nice confidential send feature
where you can send to a username rather than a user
And so all of this is possible via Aptos names.
Now let's see if this works.
So this demo has been deployed on testnet for a while.
Hopefully it doesn't have any issues.
It's always fun to do live demos.
So I am going to log in with my Google.
As you can see, I'm logged in.
And maybe I'm going to send five APT to one of you guys
if you send me an address.
I don't know who has access to the chat,
but if you put a username here,
I can send you some APT on testnet.
Maybe, I don't know, Nick, if you're still on the call, if you have a username here, I can send you some APT on testnet. Maybe, I don't know, Nick, if you're still on the call,
if you have a username there.
But if you don't, for now, I'm just gonna do this.
I'm just gonna send to my friend,
dport to APT, send confidentially.
And as you can see, my activity here has been updated.
The transaction can be seen on Aptos Explorer. And so if you go to Aptos
Explorer, the interesting thing is you can see it came from me. And I think you can also see that it
went to D port. And let's look a little bit at the payload, right? So what's being called is this
confidential transfer function. And the arguments are kind of just
cryptographic random stuff, right?
There's nowhere where you can see the balance too.
You'll have to take my word for that,
but in a few minutes I'll explain you how it works
and you won't have to take my word as much.
And so, yeah, let me check if somebody put in
No, I don't see anything.
Maybe the chat feature is not working.
But yeah, that's the chat. No, I don't see anything. Maybe the chat feature is not working. But yeah, that's the demo. We think this kind of experience is really cool for Web3. So no
key management, signing with your Google account. You don't need to install a wallet. You send money
confidentially. This can be, I think, really, really nice. So let me go back to the slides.
Okay, so now I think, so let's see.
Okay, that was pretty fast, 10 minutes.
So for the rest of the talk,
I will describe how confidential assets work.
And this is kind of the reason
why I wanted to do this Twitter Live
was to get into the nitty-gritty cryptographic details.
But before we do that, let me tell you a little bit about what are the next steps with confidential
assets on Aptos. So we are going to deploy the feature in Mainnet in V143, which I think is
going to happen within a week or within probably April. Testnet deployment is going to happen this
week or next week, I think. And then we're going to enable confidentiality for the APT token.
And then we are going to add native support in Petro Wallet
to have a confidential balance and to transfer in and out from it.
And with that being said, I will pause here for a minute to take some Q&A.
Nick is telling me that the chat is only working for premium users.
So I am not sure if I'm going to see anything there.
But nonetheless, I'll stop for a second, drink some water.
And let's see if anything shows up
So I'm going to get into the how.
This is the fun part for me.
This is probably not going to be fun for a lot of you unless you like cryptography and
you are familiar with some of these things I'm going to talk about.
So this is not going to make a lot of sense unless you're familiar with elliptic curve
groups of some prime order p generated by some element G, right?
So if this doesn't make any sense to you,
it's gonna be really hard to follow.
Some familiarity with L-Gamal encryption
is gonna help a lot, but it's not necessary.
Similarly, Sigma protocol familiarity
We're gonna be proving a lot of linear relations
amongst group elements, but really not necessary.
Mostly you should be familiar with the concept
of a zero knowledge proof for an NP relation,
So really this is the prerequisites for the next part.
I will explain all of the prerogaries we use.
So maybe it'll make some sense
even if you're not an expert, but the first one is kind of a non-negotiable. All right. So I'll begin first by comparing
Aptos confidential assets to previous confidential asset protocols in the account model. So in
cryptocurrencies like Aptos or Ethereum, right? The reason I'm focusing on the account model is
because this is a much harder model to do confidentiality in than the UTXO model.
And so when I'm comparing a protocol, I'm going to be looking at a lot of dimensions.
So I'm going to be looking at the maximum number of bits that a confidential balance can support, the maximum number of bits that a confidential transfer can support.
So can you transfer 64-bit amounts or just 32-bit amounts?
So can you transfer 64-bit amounts or just 32-bit amounts?
Then during decryption of your confidential balance or of your transferred amount,
most protocols need to compute discrete logarithms.
Some of you may be familiar with this, so DLs.
And the larger the discrete logarithm instances are in terms of number of bits, the slower it is.
In particular, if you look at the confidentiality demo here,
in order for this website to display
these decrypted amounts for you, like I received,
or let's see, Nuuly sent me 0.01 apt.
Also in order for the website to display my apt balance,
three apt, it has to do a decryption.
So it has to do a discrete logarithm for that.
And so we are gonna to be interested in protocols
that support as many bits as possible here.
Then we're going to look at how much on-chain storage overhead
Then we're going to look at whether the protocol is susceptible
to these front-running attacks where you can be sort of locked
and prevented from spending your account by an attacker.
And then we're going to look at whether it supports auditors. So can you audit the
transferred amounts? Can you audit the confidential balances? And most importantly,
we're going to reason about whether the protocol supports rotating the auditor's key,
since it's very unlikely that an auditor will maintain the same encryption
key for the duration of the system. And then we're also going to look at whether the protocol
allows users to rotate their decryption key, which is used to encrypt their bounds.
And lastly, we're going to look at the building block, the cryptographic building block used to
instantiate the protocol. So I'll start with Zether. So this is academic work by Boone Zetao from 2020.
They support 32-bit balances and amounts.
Their maximum discrete log instance is 32 bits,
It's very fast to decrypt.
On-chain storage overhead is very small.
They're the first work that prevent these front-running attacks
that arise in the account model,
which I'm going to touch upon later. But they do not support auditors as far as I know. I don't
think they describe an extension. And they do not support rotating the decryption key of the user.
Most interestingly, they use a very cool building block called Sigma Bullets, which is a generalization
of bulletproofs for proving
linear relations amongst group elements, like we need to in confidential assets.
There's some follow-up work called pretty good confidentiality, which is very similar to
bulletproofs. As far as I can tell, it sort of ignores the front-running problem, but it adds
auditor support, and it kind of moves away from sigma bullets,
which is a custom implementation of bullet proofs
that can be a little bit error-prone for some people,
and instead proposes composing classical bullet proofs
And that's kind of the contribution that PGC does.
It's a very modular design where you can take any range proof
that works over Peterson commitments, as we'll discuss later, and compose it with Sigma protocols.
And in fact, this will be the approach that we take at Aptos.
Solana recently also released confidential assets.
The feature is currently disabled, but they also have a very interesting design where
they support 64-bit balances 48-bit transferred amounts and they
have to compute slightly larger discrete logs so 48-bit discrete logs this can be a little bit
tricky to do but with state-of-the-art algorithms you can probably do it fast enough and they prevent
front running and they allow auditors but they only encrypt transferred amounts for auditors they
do not maintain encrypted balances for the auditors,
which kind of makes it difficult to allow
for auditor key rotation because the new key
that the amount is encrypted for will not be able
to decrypt the old encrypted amounts.
And they don't support any decryption key rotation
There's also a proposal from Ripple. I can't tell if this is
sort of production ready or not, or it's just a proposal, but it's a little bit similar. Yeah,
it's a little bit similar to PGC, I think, support 64 bit balances and amounts. But the discrete
logs that they have to compute are a bit large, far as I could tell from their code these are 64 bit discrete logs you really need to do some some very fancy
schmancy discrete log algorithms to decrypt fast and on all other
dimensions it's kind of the same like Solana and lastly avalanche has an
encrypted ERC repository.
They support 256 bit amounts, both for the balance and both for the transfer amount and the balance.
But unfortunately, as far as I could tell,
you cannot really decrypt these things efficiently.
You need to compute 256 bit discrete logs,
which is sort of unfathomable.
And the on-chain storage of their approach
is linear in the number of incoming transfers
since the last time the account sent the transfer out.
And the way they achieve this is by using
a general purpose ZK-SNARK scheme.
I mark this in red because I think this is a little bit of a brave design in the sense
that writing zk-circuits can be tricky business and if there is a implementation, then the
attacker can steal funds.
Let's see something happen here.
Okay. All right, I'm not sure. I hope folks can still see. All right, so now let's get back to artwork.
So what does artwork do differently? So we support 256-bit balances, 256-bit amounts,
while ensuring that the max discrete logs we have to compute are 32 bits.
And while ensuring constant storage on-chain,
we prevent front-running almost like everybody else.
We allow auditors to maintain encrypted balances, unlike previous work.
This makes it possible for auditors to rotate their keys
and still have access to past balances,
well, to the current and future balances.
And we allow users to rotate their keys
and we take the same approach as PGC,
which we really like conceptually.
It's a very modular approach
of combining Bulletproofs and sigma
protocols and so yeah that took a little bit to go through but i think it's important to relate
to past work there's a long history of progress on this problem and so we make a our own contribution
here and uh and yeah i just wanted to clarify where we stand all All right. So with that being said, let's kind of talk about the fun
stuff. I'm just going to describe, I think, deposits, withdrawal, and transfers, which are
the three key operations of confidential assets. So in a deposit, you're really enrolling for
confidentiality. You're taking public coins from your public balance, and you're depositing them
into your confidential account.
So let's talk about how deposits work.
But before we can do that,
we have to go through some prerequisites
to make sure folks are familiar with the primitives we're going to use.
So we use this version of twisted Elgamal encryption
that we called chunked in twisted Elgamal encryption.
So in Elgamal encryption, as many of you know,
there's a key generation algorithm that returns your decryption key and your encryption key. chunked and twisted Elgamal encryption. So in Elgamal encryption, as many of you know,
there's a key generation algorithm that returns your decryption key and your encryption key.
The decryption key is just a field element in a finite field. Actually, this should be a Q,
not a P. This is ZP. And then the encryption key is just the inverse of your decryption key times a group generator H. And to encrypt, what you do is there's an encryption algorithm
that takes your encryption key and your L chunks
that you want to encrypt and L pieces of randomness.
These pieces of randomness are just field elements in ZP
and it returns a ciphertext.
How does encryption work?
Well, it kind of first takes your encryption key
and multiplies it by all of the pieces of randomness,
And then it does a Peterson commitment
to these VIs using the RIs.
And so a ciphertext should be thought as conceptually
as just a Peterson commitment and a re-randomized encryption key, right?
Where the Peterson commitment and the re-randomized encryption key share the randomness.
And we have L of these because we have L chunks that were encrypted.
And what I want to emphasize here is that the randomness is important, right?
So if you use randomness zero, you're not really going to hide anything.
Vi times g is very easy to recover vi for vi times g right if vi is small that's a small discrete log
instance. And again very important for the purpose of this work and this
presentation is that these twisted El-Gamal encryptions have these
Peterson commitment components right components that contain that commit to
And throughout the presentation,
when you see a bolded underlying variable like this,
it usually denotes a vector.
So we're gonna be using this convention.
And another convention we use is that C.ped
denotes the Peterson components of the ciphertext.
So it basically returns all of these PIs.
Okay, so that's chunked and twisted Elgamal encryption.
We're gonna use it a lot throughout this presentation
to encrypt amounts and to encrypt balances
as I'm about to show you.
The other thing that I wanna talk about is chunking.
So for Aptos, we're gonna work work with 128-bit balances A. But again,
our scheme supports 256-bit. Luckily, we only need 128-bit for balances. And the way we're
going to work with these balances is by splitting them into L is equal to eight chunks. So there's
a vector A of eight chunks, where each chunk is a 16-bit value, right?
Similarly, for the amounts, V,
we're going to split them into N is equal to four chunks because in Aptos, the amounts are only 64 bits.
And this is going to produce a vector V of four entries
where each entry has B is equal to 16 bits.
So this L and B notation,
you're going to see it a lot throughout the presentation.
And one convention that we have
is there is this two chunks algorithm
that basically returns to you this chunking.
So given an input U and a bit with B
and a number of chunks M,
it splits U into M chunks of B bits each
and returns U right and there's also the opposite or
the inverse operation called unchunk where you take a chunk vector and you return back u and
it's the inverse in the sense that if you unchunk the result of two chunks on u you get back u right
result of two chunks on u, you get back u, right? And in other words, what two chunks really does
is it returns u's base two to the b representation, right? And so, for example, if you call two chunks
on an available balance a, it returns to you these a i's such that A is the sum overall of the Is of 2 to the 16
raised to the I times AIs. So this is just a base 2 to the 16 representation of A, right?
And actually, that's exactly how Anchang works. What Anchang does is it takes the AIs and it
computes the sum and it returns back A. So that's why this holds.
Same thing for V, of course. And yeah, I do realize this is a lot of notation, but just to
recap, we have El Gamal encryption, we have chunking. Let's look at deposits. So I'm going
to be talking about a user, Sherry, who's generated her Elgamal encryption key EKS and has some public balance of $10,
right? And what Sherry is interested in doing is in moving some of these public coins into
her confidential balance, which is currently empty or unset. And so we want to have some
kind of transaction where Sherry specifies the public amount V that she wants to move
into her balance. And at the end of this transaction, we want Sherry's available balance AS to be updated to AS prime,
such that AS prime contains a chunked and twisted El Gamal encryption of the public amount V that Sherry put in the transaction.
And so actually, this is pretty trivial.
What the validators do is they take V, they chunk it,
they obtain this V vector,
and then they apply this poor man's El Gamal encryption
with randomness zero, right?
And what I want to emphasize here
is that the deposited amount is public, right?
And so that's why we kind of use zero here is because there's no hope to hide the deposited amount is public, right? And so that's why we kind of use zero here
is because there's no hope to hide the deposited amount. By definition, you're moving it from public
to confidential. Just the difference between 10 and 10 minus V on your public balance will leak
the deposited amount. So there's no way to hide anything in this deposit phase. In order to hide
things, you have to actually send a transfer out of your confidential balance
or receive a transfer in.
And that'll hide your confidential balance
and the transferred amounts.
And I'll get to that later.
But for now, I just want to show you
how easy it is to deposit.
You just put in a public amount, the validator chunk it,
the Elgamal encrypted with randomness zero, done. So Sherry can now deposit confidential
coins into her account. Now let's talk about the inverse operation, which is withdrawal.
Withdrawal is when Sherry wants to take back coins from her confidential balance and put them back
into her public balance. So in other words, she wants to dispose of confidentiality.
And before we can talk about withdrawal, there's more prerequisites I need to introduce.
So I'm going to introduce zero knowledge proofs.
So for what you really need to be familiar with when discussing zero knowledge proofs
is that a zero knowledge proof is always a proof for a relation, which is a publicly known algorithm, R, that takes some public statement X as input that both the prover and the
verifier know, and takes a private witness input that only the prover has, and the goal of a ZKP
is to hide W from the verifier while convincing the verifier that this algorithm holds over the secret W,
right? So in other words, we kind of use this terminology that is EKP for the public statement
X being in the relation R is a process by which a verifier is convinced that the prover knows a secret W
such that R of X W is one, right?
And a good example of this, if you want,
is to think of R as an algorithm that checks
whether the puzzle X, the Sudoku puzzle X
has a valid solution W, right?
So in that sense, you can have a ZKP for showing that the Sudoku puzzle X is solvable by the prover.
And in fact, the prover knows the solution W to the Sudoku puzzle, right?
But in general, we're going to be working with NP relations, with relations that are kind of abstract.
that are kind of abstract.
Okay, and I'll give you another example of such a relation,
which is gonna be very helpful for confidential assets.
This is the zero knowledge range proof relation
for Peterson committed values.
So in this relation, the public statement
is a bunch of Peterson commitments,
like the ones you saw in the Algamal ciphertext.
And the secret statement is the openings
of those Peterson commitments.
So PI commits to VI using randomness RI.
But these are secret and these are public.
In other words, the blockchain will see this,
but we don't want the blockchain to see this
because this will be either a transfer amount
And we want it to stay secret.
And so what this relation will do is for every value Vi,
it'll check that Pi is the Peterson commitment to Vi
And it'll check that Vi is a B bit number, right?
In our case, B is 16. So it'll check that Vi is a 16 bit number, right? In our case, B is 16.
So it'll check that VI is a 16 bit number.
And although right now you're looking at this
and it's probably not going to make a lot of sense,
later on, I'm going to show you
how we use this in the protocol.
But the takeaway here is that there is this NP relation
that takes a Peterson commitment as a public statement.
And we use a zero knowledge proof to convince the blockchain that we know openings to that peterson commitment that are small that
are b bit large all right so again before we can talk about uh withdrawals we have to talk about
how decryption works in chunked into a sterile gamal so to decrypt one of these ciphertexts,
we have a decryption algorithm that takes the ciphertext
and the decryption key and outputs not the values themselves,
but the values times the generator,
which means that in order to get the values,
we're going to have to compute discrete logs.
And I'll touch upon that immediately.
How does decryption work, though?
So you simply parse the ciphertext. This is
actually a typo. This was supposed to be a C. So you parse the ciphertext and you extract the
Peterson commitment and the re-randomized encryption keys. And then you can actually
obtain VI times G by doing a little bit of arithmetic. And I can convince you why this
works. So let's take this equation here and move it here. And if we expand PI, this is just a Peterson commitment.
If we expand RI, this is just a re-randomized encryption key.
And now if we expand the encryption key,
this is DK minus one times H.
And you'll notice that this guy will cancel out
So we get RI times H. And then you notice that this guy will cancel out with this guy. So we get ri times h.
And then you notice that this guy will cancel out
So that's how decryption kind of works.
Unfortunately, we only got vi times g.
And to actually display the balance,
kind of like I showed you on the confidential demo website,
We don't need vi times g.
We have to solve a discrete logarithm problem instance.
So that means that given Vig,
we have to be able to compute Vi somehow.
There are many algorithms for this.
In fact, we propose a faster one
for the elliptic curve that we use.
And I'll give you a link later
to a resource describing it.
What you need to know, though,
for the purpose of this talk
discrete logs is pretty fast when the VIs are small. If they're 32 bits, you can solve
them in 10 milliseconds in Rust. But if they get larger, it gets a little bit tricky. I
think in practice, you can probably deal with 64 bits. But if you want to do this in the
browser, it's going to be a little bit slow. So you want to be kind of conservative. So in our case, we stay conservative.
And so another useful algorithm that I want to talk about, actually, is this decryption star algorithm, which instead of returning the chunks times G, it just returns the unchunked value, right?
And the way this works is it just calls the decryption algorithm that returns
the individual chunks times G,
and then it applies the unchunking operation to these, right?
And it obtains V times G.
And so this we'll be using a little bit.
It's just a small variation
on the traditional decryption algorithm.
Right, and so what I wanna kind of clarify here
is that this decryption algorithm
is kind of an inverse operation to the encryption, right?
So if you encrypt under some EK,
the value you chunked using some randomness R,
then if you apply the decryption algorithm, you get back
U times to the G, right? So decrypt of encrypt of two chunks of U returns U to the G, right?
Naturally, as you would expect it to. If I encrypt U, I need to be able to get back U, right?
There's a little bit of notational complication here due to all of the chunking that we're doing.
there's a little bit of notational complication here
due to all of the chunking that we're doing.
All right, so that was quite a lot of prerequisites.
So let's just recap, right?
So we talked about zero knowledge proofs.
We talked about zero knowledge proofs of range relations
where we prove that Peterson commitments are
to values that are bbit wide.
We talked about how to decrypt an El Gamal
and how we get chunks times G
and we solve discrete logs to get back the chunk.
And we talked about an auxiliary algorithm
that returns the unchunked value times G.
All right, so now let's talk about withdrawal.
So let's say Sherry has a confidential balance, right?
So she has some amount, A sub S, chunked,
encrypted under the scheme, under her encryption key,
with some randomness here that I'm ignoring, right?
So again, this is a chunked representation
of her available balance.
And so what we want Sherry to be able to do is
she has to be able to send some kind of transaction to the blockchain affecting her account.
And by the end of this transaction, we want Sherry's balance to be updated to a new value, AS prime, such that this is a chunking of AS minus V.
So we want Sherry to withdraw V publicly, right?
And so obviously this transaction will need to include the public amount V.
This is a public withdrawal.
The goal is for Sherry to withdraw V coins
from her confidential balance into her public balance.
So I hope there aren't any connection problems.
Okay. problems um okay um and yeah so what what is this transaction gonna include well the first thing it's gonna include it's actually gonna include this new available balance encrypted for sherry
we call this a normalized balance for reasons that'll become apparent later
but most importantly it has to include some kind of proof that this balance is correct
otherwise sherry can encrypt anything there right so this is going to be a so-called withdrawal proof
for an np relation called r withdraw and let me tell you what this empty relation does.
So the public input is this, right?
It's Sherry's encryption key,
the amount she wants to withdraw,
her old available balance,
and her new available balance.
And the secret input that we don't want blockchain to learn
is Sherry's encryption key,
the randomness used to encrypt her new available balance
and her new available balance,
right? So what this relation is going to vouch for essentially is that AS prime is AS minus V,
right? Really that AS prime has been computed correctly. And it does so by doing a bunch of
checks. The first check is that, hey, the encryption key that you have here publicly,
checks. The first check is that, hey, the encryption key that you have here publicly,
I know the decryption key for it. And it's a secret input. And here it is. I'm not going to
leak it. Again, we're doing this in zero knowledge. And hey, the new available dial and ciphertext
is an encryption under this EKS that I just proved to you that I know the DKS for,
of the secret AS prime with the secret R which I'm not going to leak
because we're doing everything in zero knowledge and lastly that if you decrypt the old available
balance using this DKS which we proved we know then you get back the new balance so you get back
AS right this is the unchunking minus v times g minus the transferred
amount so this is really just saying that the new available balance minus v is encrypted in as
because that's what i get by decrypting and here you'll notice how i'm using that auxiliary
decryption algorithm to get back v this is sort of notational uh sugar syntactic sugar for
yeah easily describing this right and so this is the relation that convinces the blockchain
that sherry has correctly updated her new balance to be her old balance minus v the question is is
this enough and the answer is no it's. This would produce an awful infinite money glitch.
And I'll show you how. So imagine Sherry's old available balance is zero. And imagine she puts
V is equal to one in the transferred amount. Then one sort of important thing that I kind of
conveniently forgot to mention is that this arithmetic here happens modulo p because we are in an
elliptic curve group and we're doing mod p arithmetic quote-unquote in the exponent
when doing this here and so what what is actually being computed here is as minus p the problem is that as is zero v is one and as minus v is minus one mod p which is really
p minus one which is really infinite money it's like two to the 256 right and so that's pretty
bad we don't want to do that and to fix that kind of the root of the problem is that R withdraw does not check that V is less than AS.
You see, there's no check here that V is less than AS, right?
That's kind of a problem.
In fact, actually, this may be a typo.
This is the old balance is the new balance minus V.
No, new balance is old minus V.
So this is a typo. There should be a plus.
Yeah, so the core problem is that the relation that we described does not check that V is less
than or equal to AS. And that's why we need a range proof. That's essentially what the range
proof kind of does. And that's all I'm able to say about the range proof without getting into
sort of gnarly details. But I will give you resources at the end these slides will become public and at the end you can see a more
formal argument for why this is sufficient great and so this is the withdrawal protocol
Sherry can now withdraw confidential coins back into her public balance and at the core of it is
zero knowledge proof for this withdrawal relation,
which we instantiate with Sigma protocols, and a zero knowledge range proof for the Peterson
component of the new available balance. Right. So now that we've covered deposits,
we know how we can get money in our confidential account. We covered withdrawals, we know how to
get money out of our confidential accounts.
But of course, these would be kind of useless
if we cannot actually transfer
between our confidential accounts.
So how do we do transfers?
How do you actually leverage these confidential balances?
And in order to talk about transfer,
there is another small prerequisite I need to introduce.
This is a batched variant of the chunked
and twisted El-Gamel scheme that we discussed earlier.
So here we have the encryption algorithm as before,
but now it just takes a bunch of encryption keys.
It doesn't just take EK, it takes EK1 through EKM.
And we want this adjusted algorithm to encrypt,
as before, L chunks using L pieces of randomness.
And we do this slightly more efficiently than we would by naively calling the previous EL,
in the sense that we still create these EK randomized components, but now we only need
to create one Peterson component for the VIs as opposed to M of them. And so the ciphertext will be the Peterson component as before,
and all of these RI components.
And as before, we're going to use the same convention,
C times pet returns the Peterson components.
And the reason this is better in case it's sort of hard to see
is that the ciphertext size here is M plus 1 times L.
So we have M components here and another
one here. That's the m plus 1. And each one of them has l subcomponents. So m plus 1 times l
sized ciphertext. Whereas if we did it naively with the old ciphertext, we would have to do m
separate encryptions. And each encryption would be of size 2l, right? And so that would be a little bit larger,
would be around 2X as large.
And so we prefer this optimized version for a little bit of efficiency.
It's not really crucial, but it helps.
Okay, so the other thing I want to talk about
is the fact that this chunked and twisted El Gamal encryption
has a homomorphism property.
encrypt under the same encryption key, ek, some chunk value a and some chunk value b using some
randomness, then you can combine the ciphertext into a new ciphertext that encrypts the sum of the chunks modulo p right and the randomness for
this new ciphertext would be r plus r prime so that's the homomorphic property you can kind of
see how it holds and I'm going to try and show it to you but it may be a little bit
hairy so let's look at this ciphertext it contains a bunch of our eyes right and a bunch of
pis so ria pi it's the peterson commitment to ai and the re-randomized decay this guy will contain
the same thing except it's gonna have a ri primes and bis right and so you can now kind of notice
that if i add this guy with this guy and then then this guy with this guy, I get something pretty nice, right?
I get ri plus ri prime, and I get ai plus bi, right?
Things kind of combine very, very nicely, and that's why this property holds.
If you don't see this immediately, just take my word for it.
If you don't see this immediately, just take my word for it.
And another convention I want to add here is that,
you know, typically the way I described it here,
this assumes that all ciphertexts are using the same number of chunks L,
but we're also going to allowing for adding smaller ciphertexts with less chunks
by saying that we implicitly pad with zeros.
So for example we're gonna
add to a size L ciphertext a size N ciphertext that's slightly smaller. The
thing still works out if we view the size N ciphertext as a size L one where
the where we have L minus N zeros appended to it. Now some food for
thought is that if A and B were based to the B representations returned by the two chunks algorithm that we described, then when we combine them like this not. It depends on how big A and B are, but in the worst case, this could be,
this could double the B here in the exponent.
So, yeah, this is kind of a caveat
of combining ciphertext in this way,
is that the result may not necessarily be based to the B.
Okay, so let's recap a little bit. I talked about batch encryption. So I've just
added a bunch of EKS here. And I've saved a little bit in my ciphertext size. This is just
kind of an efficiency detail. And I've talked about homomorphism, right? So this is how I can
take two encryptions under the same EK for two different chunk values and get an encryption
So this is component by component vector sum, modulo P over each component.
And next we're ready to describe transfers.
So let's say I have Sherry, she has her available balance as before, and she wants to do some
sort of transaction that's confidential. And in this confidential transaction,
she will obviously need to encrypt the transferred amount V.
This is going to be chunked via the function that we are well familiar with.
And it's going to be encrypted under her encryption key,
but also under the recipient's encryption key, Rob, in this case.
And so what we want to happen after such a transaction is that Sherry's
balance, we want it to be updated to AS prime. And we also want the recipient balance, Rob,
to be updated. And here we're going to need to do some homomorphic update. This is why I
introduced the preliminary. So we're gonna want Rob's available balance
to be his old available balance plus the ciphertext C, right?
Such that we end up with an encryption of his old AR
plus the transfer amount V.
This is a typo, it should have been an L here.
Right, and so again, we want a transaction such that by the end of it, Alice can update her balance and Bob can update his homomorphically.
And what is this transaction going to have to contain? As with withdrawal, we're going to include
Sherry's new balance in here.
And we're going to prove using a new zero-knowledge proof for a new relation that this balance is correct.
This zero-knowledge proof is going to be for an R transfer relation.
And additionally, we're going to prove that the transferred amount
and the new available balance are B bit wide this is going to avoid some problems
like the ones i described before i'll i'll show you in a second but first let's talk about the
transfer relation so how does the transfer relation work it takes the encryption keys of of the sender sherry the recipient rob it takes the ciphertext of the
encrypted amount it takes sherry's old balance it takes sherry's new balance as public right
all of this is public and a secret as before it takes the decryption key of sherry the randomness
for her for her new available balance her new available balance and importantly it takes the
value v that sherry is transferring secretly to rob as a secret input we don't want to leak it
anymore if you recall in withdrawal this v was kind of public and how does the transfer relation
work it's actually embarrassingly simple it's just enforcing a withdrawal where it moves this V as a public input.
So it's really enforcing that Sherry is withdrawing V coins from her available balance
and updating her new balance correctly, as we discussed in the withdrawal protocol.
And the other thing that it's doing is checking that the ciphertext C,
which is a batch ciphertext, is indeed correctly encrypting the secretly
withdrawn value V, which is chunked, right? Using some randomness S, right? That's it. That's the
transfer relation. So the transfer relation can just be cast as a secret withdrawal, together with
a proof that the encrypted amount is the secretly withdrawn amount. And so the question is,
why do we need more beyond the transfer?
So why do we need the range proof?
We know why we need this in the context of the withdrawal,
but why do we need an additional range proof
over the transferred amount?
As before, the attacker can get very clever.
If we don't have this range proof,
the attacker can set the transferred value to be P minus one, where p is the order of the elliptic curve. And so again, the new balance will be
as minus v. And that means it'll be as minus p minus 1. And so p just canceled out because we
do modulo p arithmetic. So the new available balance will be AS plus one for Alice.
So this would be kind of disastrous, right? So Alice started with AS, she transferred some huge
amount of coins, and then she ended up with a new balance that's larger, right? This would be
disastrous. It's an infinite money glitch. This is why we need the range proof here.
glitch. This is why we need the range proof here. Right. And so at a high level, this is how the
transfers work. And this is how Sherry can send coins without anybody learning the amount or the
change to her balance or the change to the recipient's balance. There is a big caveat,
though, which the Zether paper, as I mentioned earlier, handles. The problem is that after such a transfer,
Sherry has updated Rob's available balance.
And so if Rob is in the middle of transferring out of his account,
Rob will have computed a zero-knowledge proof for our transfer
with respect to his balance AR.
The problem is that Sherry's payment to Rob invalidates this AR. AR is now AR prime. And so when the validators verify Rob's
next transfer with respect to AR, it won't verify because the validators will verify it with respect
to the updated available balance. So this creates this front running attack
where a malicious user can just send really small payments
to Rob, constantly changing his available balance
and constantly invalidating any zero knowledge proof
So how do we deal with that?
The way we deal with that is by taking Zether's approach.
So Zether proposed to actually introduce
a pending balance component next to the available balance.
So as you can see before,
we just had the available balance,
you sent money out of it and you received money into it.
we're gonna have an additional pending balance
amount. And so a user's total balance is the sum of what's encrypted here and what's encrypted here.
Right. And now what we do is we still spend from the available balance, but we receive into the
pending balance. Right. So we no longer receive into the available balance. We receive into the pending balance, right? So we no longer receive into the available balance, we receive into the pending balance,
And so what this allows us to do is to completely eliminate the front running attack that I
described earlier, because if Alice continues to pay Bob, only Rob's pending balance gets
updated, his available balance stay the same, and he can spend.
So this is a very nice technique introduced by Zether.
And so to make this work, you kind of have to keep track
of how many receiving transfers you accepted
into your pending balance.
So here, Bob received 21, and after Alice paid him,
we update this to 21 plus 1.
And you'll see in a second why this is necessary. I'll describe it very soon. But it's going to be an important hint
that the validators will need to maintain. And so good. So now we can handle front running.
I also want to describe how to handle auditors. And this is actually quite trivial. You can kind
of see the diff here. The only thing we're going to do is we're just going to do batch encryptions
of the available balance under the auditors encryption key and of the transferred amount
as well although actually this is once again a typo there's supposed to be an eka here
and that's how we add auditory. We simply encrypt stuff for the auditor
using our batch encryption stuff.
There's a small caveat, which is that
the pending balance is not visible to the auditor.
So the auditor will always be a little bit behind.
But ultimately, as I'm about to show you,
the pending will roll over into the available
and the auditor will be able to see everything.
Okay, so what is a caveat with this split,
the pending available split?
One caveat is if Rob receives too many transfers,
his pending chunks become too large,
which means they become very expensive
to decrypt via discrete logarithms.
And so the solution here is to allow Rob
to roll over his pending balance
into his available balance and make it zero. And so that's what I'm going to describe next.
Suppose we have Rob, he has an available balance, he has a pending balance, and suppose he sort of
ran out of transfers, like suppose he received a lot of transfers, these chunks are very big,
out of transfers like suppose you received a lot of transfers these chunks are very big
and he wants to roll over so as to make the encryption faster
so what he does is he sends a rollover transaction and this rollover transaction contains nothing it
just tells the blockchain to roll over and it homomorphically combines the old available balance
with the pending balance deriving the new available balance.
So this is just an encryption of the sum. And as a result, if we enforce that pending chunks are
b-bit and that available chunks are b-bit, then after rollover, the new available chunks will be
at most 2b-bit wide. And so if we want to make sure
that we never compute discrete logarithms
bigger than to be bit wide,
we kind of force the user to normalize
their available bounds to be b bits again
by withdrawing zero from their account.
So basically if you send the transaction withdrawing zero,
that resets your available balance to be a B bit.
Again, if you recall, there was a range proof
in the withdrawal, right?
And so that's how we can make sure
that the available balance remains small.
Because I actually, I should re-explain that
After a rollover, chunks are less than two to the B.
If we were to do another rollover, they would be even bigger. And so we don't allow users to do another rollover, chunks are less than two to the B. If we were to do another rollover,
they would be even bigger.
And so we don't allow users to do another rollover
This ensures that after a rollover,
things remain less than two to the B,
which allows us to compute discrete logs fast.
And all right, that's basically it at a really high level but still with enough detail
that's how confidential assets work the key operations are deposit withdrawal transfer
rollover and normalize which is just a withdrawal of zero there's a lot more details that you can find on my blog
in particular you may be interested in the gas costs for these operations on aptos
you can also find this discrete log algorithm that we we optimized for our elliptic curve and
benchmarks for it you can learn a little bit about how auditing works. We have a global auditor that can be overwritten by an asset-specific auditor. There's this notion of an effective auditor as a result.
There's also a notion of sender-picked voluntary auditors. So the sender in a confidential transfer
can optionally re-encrypt the transferred amount for anybody at once. It doesn't really need to be an auditor. We just call it an auditor.
And that's basically it. There is a bunch of resources on Aptos Dev. In fact, this documentation,
I have to update it with the PR very soon. The confidential asset move contract is here,
but this link has expired. I will update it. The SDK is here. There's another PR that needs to merge.
The payment demo that I showed you is at confidential.aptoslabs.com. It's also a public
repo that also needs to be updated for the new version of the contract. And there's a lot more
resources on my blog, as I mentioned before. And with that being said, there's not a lot of time,
but I don't see any questions in the chat
unfortunately but if I did I would take some questions because it would be really nice too
maybe yeah I really don't that's a bummer but with that being said that's it there's some
interesting appendix slides here in particular.
I kind of described the move APIs
that the confidential asset contract exposes.
And I also describe these additional APIs
for the pending and available balance,
the rollover, the normalization,
how to set an auditor, how to set a global auditor,
how to pause your incoming transfer
to allow for key rotation we didn't really cover
key rotation unfortunately but that's also pretty easy and then sdk api so how do you generate a
key pair how you generate a withdrawal proof transfer proof a key rotation proof how do you
decrypt and so on um yeah and with that being that's all. Thank you so much for tuning in. I hope this
remains here for people to follow up on later when they have questions about how this works.