ZK Whiteboard Sessions – Module Sixteen: Multi-Asset Shielded Pools
22 Nov 2022 · 52:11
Joe Bebel of Anoma and Bobbin Threadbare use this ZK Whiteboard Sessions module to break down single- and multi-asset shielded pools. They compare the trade-offs of each design, work through how multi-asset value balance checks and homomorphic value commitments function, and cover applications beyond simple asset transfers, including how NFTs can be represented as asset types inside a shielded pool.
Speakers
Topics
Transcript
foreign [Music] I'm bobbin from polygon and today I'm here with Joe from manoma and we're doing another recording of the CK whiteboard series and today our topic is multi-asset shielded pools so uh Joe what are multi-acid shielded pools and why do we need them thanks for having me so a multi-asset shielded pool is is exactly as the name suggests it's a shielded pool that can contain multiple Assets Now was a shielded pool well shielded pools popularized by Z cash
or the original zero coin paper and the idea of a shielded pool is that instead of having the sender receiver and value all publicly listed on the blockchain as this with with most transparent blockchains the idea is that a shielded pool is a privacy layer that allows transactions to be encrypted in a sense so that they're not broadcast to the entire world so if you and I are using a shielded pool then nobody from the outside can figure out you know who sent money to whom or how much that how big the amount was and all of that stuff right at least you've broken the cryptographic link between
um each transaction okay and so one of the uh things that is true of Z cash is that it supports only a single asset only at least at this time which is zec right and the idea of um when you have a shielded pool with a single asset um every transaction in the shielded pool is transferring the same exact asset and so it's obvious at least from the outside even though the sender receiver and value may be encrypted the asset type is not in question because everyone knows
that this uh transaction within the shielded pool must be the single asset and so our goal of the multi-asset shielded pool is to allow many asset types within a single shielded pool so that for a given transaction is not possible to tell from the outside at least there's no cryptographic evidence of what the um uh asset in that transaction is I guess before we go into the multi-asset uh could you maybe explain at high level like how does a single asset shielded
pool work right so the zero point uh and Z cash model is essentially how um most are all shielded pools today operate and the idea is that we have a note set together which is a Merkle tree thank you of all uh transaction outputs ever recorded in the pool
so this is similar to how Bitcoin has a utxo set except that in this case we make a slight difference where uh notes as actually every transaction output whether they're spent or on spent yep right and so then from this note set we can use zero knowledge proofs to show several things about the transaction so if you start with this Merkle tree and each note looks something like some value of some value of the note and the owner the owner address which is typically a
public key then what you can do is if you want to spend a note use a ZK snark or similar some kind of zero knowledge proof or argument or something like that to show that one the note is unspent as it hasn't been spent already two the owner has authorized which in the case of the owner addresses a public key there's a signature
involved or something like a signature and three the transaction the value of the notes spent is equal to the value of the notes created so sum of inputs is equal to sum of outputs exactly yep so that therefore you cannot you know just create value out of nowhere magically right and in the single asset case this is uh relatively straightforward right you just sum up all of the values of uh the
notes that are spent in the transaction and you sum all the value of the notes that are created and check that they're equal yeah and that happens within this case and you check all this inside of the ZK snark and then you take the notes that are created and then you add them back into the Merkle tree of of the note set and so uh the more transactions that there are the larger this note set becomes and because uh each note in the note set although it contains the encrypted value an owner address it's or more precisely is a commitment um each note in the notes that doesn't
reveal any information about to the public what the value of the owner is and so as the note set grows you get more and more and more privacy and I guess uh maybe this is part about like why can't like we have multiple assets we want to have this you know some privacy grantees bike we can't we just create a single uh asset pool for each asset that we care about right so um this is not such a major problem for if you have a couple pop uh different popular assets uh it's like assets that have many transactions tokens they have many transactions um then the Privacy sets for each of
those might be large enough already and you might get more privacy by uh by merging them together into one shielded pool but the real Advantage is when you have assets um that are wildly different popularities if you have a very common assets that's transferred a lot and then you have some other assets that are very rarely uh transferred or even something like an nft which uh there is only one of and is only transferred um you know when that nft is transferred you know it's transferred and so doesn't put much use to put it in its own shielded pool and so the real advantage of a multi-asset shielded pool is putting
them all in the same shielded pool and getting all of these different tokens to share the same privacy side so basically even infrequently traded or transferred assets get the same kind of force the same guarantees of anonymity and privacy as the most frequently traded asset basically right because if even if some token is traded only once per day and it's in the same shielded pools the token that's traded a million times per day they're still cryptographically indistinguishable from the outside make sense makes sense all right so I think the motivation is clear but um what are the challenges of creating this um multi-acid shielded pools right so so what are the challenges when we try
and add multiple asset types into one shielded pool well for one we don't want to hard code assets so no hard-coded because for one it's uh probably impossible to to make a list of all the assets that you would want to be able to put in the machine of the pool but second it's also not very practical if to to hard code a long list into the ZK snark circuit and so we want to have some kind of protocol which is agnostic to to how many assets might be
in the shielded pool or even if some of those assets may not exist yet we want to support assets which which uh so we want to move it to create us is dynamically almost right there should be some way to create new assets and uh put them in or take them out of the shoulder pool and then some standardized way and so the second uh challenge is that uh oftentimes there are different standards for example value sometimes this is a u64 sometimes this is a u128 and so if you are putting the
different uh different assets that follow different standards into the same shielded pool sometimes you have to address how they uh technically look different yep right another challenge is fee payment um which is when you have um multiple asset types in the same Shield of the tool um if you have a transaction with one asset to type it might not be the native token of the chain or something like that and so how do you negotiate the fee payment for this transaction because um you either have to maybe have the
native token of the chain where you have some kind of mechanism where you unshield some of the other assets to pay the fees but then you're revealing what the asset was in the transaction and so there's some challenges in terms of how you um allow fee payment and then you mentioned native token but I guess in the context of like a multi-asset world do we even need a native token or can we just say all assets are equal or because of the fee payment aspect you do want to have a native token for example right it comes down uh often to the economics of the chain okay um where um the chain might have um some native token which all fee
payments must be in uh maybe the chain doesn't have any requirement for free payments at all um maybe uh the chain allows payment in different asset types and the miners or validators have some mechanism for for valuing these these tokens um maybe there's some mechanism where inside of the shielded pool um the non-native assets can be swapped for the native assets there's lots of different ways you can approach this problem uh but it's a unique problem because uh you have to if you have fee payments of some kind that are required and uh you are unshielding some of the transferred asset
you might leak some of the price uh privacy right right um and uh the last uh challenge which I'll mention is uh heterogeneous transactions which is that you may have in a transaction a single transaction multiple assets types and this is something that cannot happen in a single acid shielded pool um because well every every transfer in a transaction is going to be the same asset and so you don't have to keep track of this but if you have multiple assets allowed then you might have
complex transactions where you're sending more than one asset type within a transaction you might want to allow this what are the benefits of like being able to have the same Assets in the uh or different Assets in the same transaction well for one you don't have to split it across multiple transactions so if you want to make sure that your transaction is atomic for example you definitely don't want to send one token first and then send the second token because one of those two transactions may not execute yeah um you might want to have complex transactions with multiple signers multiple parties but um this is a situation that you maybe come across less commonly in a single asset shielded
pool because it's less likely that someone would want to atomically send the same asset as someone else but say if you and I are swapping a token privately we might want to construct a multi-party transaction where I send the token to you you send the token to me and they're different types and um we're doing some this kind of swap there's no exchange and a decentralized exchange involved or just swapping the assets and we want to do this a Time quickly so so none of us get neither of us can back out of the trade okay I think that's pretty cool actually that we can swap like we basically can exchange assets without involving an exchange and do it fully privately right yeah and so you you get these questions
that that um don't come up so much in the single asset I feel the pool of like how do you handle if you have multiple signers or this kind of thing right and so um you know but but we can start um from the single asset shielded pool model and we can start to address these challenges all right and the most simple uh thing we can do is just add another field to each note asset type so um maybe not describing exactly the form that this field takes but we have some representation of each asset type it can depend maybe on where the the
assets are from if there's some kind of ERC token or if they're a cosmos token or or something like that then they all have some kind of representation for what their asset type is and you want to encode it somehow and put it in the note makes sense right and so if we act if we do this this is conceptually simple but um we do have to to make some changes to the the rest of the protocol right because here where we said that the um sum of all the values of the notes that are spent uh has to equal the sum of all the values of the notes that are created
and when we do this in the multi-asset case um we don't just have to sum all the values of all the notes together we have to sum for each asset type independently so for each asset type we have to sum all of the value of those notes of that asset type and check that it's equal to the value the sum of the values of all the notes I guess that complicates the circuit quite a bit if you want to do that it could yes so there are several different ways that we can um implement this this step in the ZK snark of of checking that the value balance is
correct that you're not creating any value so let's consider some of the different ways that you could do it so um so I'll just call it the value balance check so how do you check that the transactions uh has corrected value balance well one way of doing it is to uh check the sum in the circuit so the circuit inputs many notes
and then some some spent so say two uh spent notes and then two output notes though again in the multi-asset case you might you may need more this is the way that zerocoin worked the Z cash Sprout protocol where you had a single circuit that checked all of the input notes and all the output nodes and all the created notes and check the inside of the circuit that the value sum like this in multi-asset situation like if you have many assets like your circuit needs to be I guess generic enough to be able to
determine like I might have 10 assets and as part of the one node in like 12 Assets in another note or something like that and then I well hopefully not 12. hopefully there's still 10 in each but there could be varying number of assets so like the circuit needs to be able to handle some kind of degree of variability right right and so this might make the circuit uh extra complicated because now you have to sort of keep track of how many different asset types you have to keep a running sum of each different assets type and it's not the most efficient way to do it and there was a reason why um with the zcash sapling upgrade they stopped doing this and they adopted a um a much more clever way
a much more clever way of doing it which uh I'll call homomorphic value commitments and could you explain a little bit more about what exactly a homomorphic value commitments exactly so the idea is that instead of instead of having all of your input notes so if you have value public key and then asset type so suppose that you have four
notes that are being spent [Music] and then you have four notes that are being created [Music] foreign so instead of having one circuit that takes in all uh of these notes and checks the sums independently instead what we do is we associate with each of these notes a value commitment and what is the value commitment basically we can think of it as an encrypted representation of the nook's
value thank you so it's kind of an object that commits to a value but it is done in such a way where you cannot tell what the actual value is right the important properties of it is that it's hiding meaning no one can tell what the value is that it's binding that represents exactly one value and it cannot be cannot be feasibly changed and that it's homomorphic which means that if you take um two value commitments and add them
together that that is going to be equal to the commitment that is the sum of the values okay so um so if you take and I won't say exactly how you add uh just yet but if you take uh two value commitments and you add them together this is going to be equal to uh the value commitment of the sum of its uh values inside make sense okay so basically was this trick you know we had this number two or number three item where we would check the sum of inputs is equal to outputs in the circuit we no longer need to do this
in a circuit am I right exactly the reason that you want to do this is because instead of checking in the circuit that uh the sum of the value commitments is is uh zero uh you can instead just have um one circuit for each note so um perhaps one for each spent at least in the sapling uh model this was the way it worked you have one circuit for each note and the circuit just needs to check that the value commitment is correct
the the value commitment matches the value of the note and the circuit doesn't actually know anything about all the other notes it's not checking the balance directly but instead outside of the circuit we can add up all of the uh um value commitments that are being spent and we can add up all the value commitments that are created and we can check that that is the commitment of the value zero and so from the outside we see that it balances because the sum is zero but we don't actually uh know what is inside of
each of these value commitments and there's some advantages of this basically each circuit is now much smaller you're not constrained to say having two notes in and two notes out and uh generally you just get a lot more efficiency and I think especially in the multi-asset context like this bucketization by asset is much easier to do outside of the circuit than it is inside the circuit I'm guessing so right yeah and the amazing thing now is that because each circuit only deals with one node at a time this means that the circuit only needs to consider one asset at a time but I guess now you need to make this uh commitment somehow unique to each asset
type am I right so like you can't add them to different value commitments from two different assets uh or it will somehow shouldn't make sense exactly so let's look at how it uh works in the single asset case and then I'll describe how it okay generalizes so in the single asset case we get uh too random I'll put random in quotes elliptic curve points this is where it gets mathy right uh
we'll call these points V and r and so what we can do is we can say that um a value commitment for some integer value and some randomness and the randomness is going to serve uh but to make the value commitment private the value commitment is going to be equal to the integer value times this elliptic curve Point V Plus
the randomness times than what the curve Point r and the nice thing about uh using this form of value commitment which is essentially a Pederson commitment is that it meets the requirements that we have it's hiding binding and homomorphic at least to the extent that we need it to be if you had two different V's in our well I guess if you had two different uh another asset you would add them together and they just add up in terms
of the real let's say you had a U or something like that right the same okay because if you have V1 plus the value commitment um V2 and some Randomness this is going to be equal to V1 plus V2 times V plus some Randomness plus some other Randomness times R which is just the value commitment of B1 plus v two and some Randomness yep so we get the properties that we want and in the
single asset case we just check that the sum of all the value commitments is zero and um we if it have guaranteed that the transaction is balanced so what do we do uh in the multi-asset case well there's a very um a clever uh approach that the zcash team electric Coin Company figured out which is that instead of using two points we actually have many random or the curve points okay one
for each asset type that is to say that each separate assets type is going to have its own random elliptic curve point oh God but R is the same for all right R can be the same for all okay okay and this way when you uh now change your value commitment to take in the asset type and the randomness instead of using the single asset value base we use the particular value base for
that asset type and then the claim is that because if we now add value commitments from two different assets together so for example so value commitment of V1 and then let's say asset type 1 and then the randomness is not important plus the value commitment of uh that has value V2 an asset type A2 and some Randomness then this is going to look like V1 and then the elliptic curve point for the asset
type 1 plus V2 times the object curve point for asset type 2. and then randomness and the claim is that because uh va1 and va2 are random that it's not actually feasible to to determine um what uh the relationship between va1 and va2 is so they won't they will never Collide in such a way where you know they can cancel each other out or something like that right because even if even though they're on the same elliptic curve and and more formally in
in the same subgroup same cyclic subgroup on the electric curve so even though we know that there's some potential relationship between them because they were selected at random uh is not feasible to find this relationship and this is a very standard cryptographic assumption yep make sense now uh the only uh thing that we have to do is that we should say that well Randomness is kind of hard to verify so we're going to actually just use uh pseudo random points which are generated using a
hash to a curve what would you caution in this case right exactly so in order to find the value base for a particular asset we want to make sure that it's pseudo-randomly chosen there's no no structure to it no obvious structure to it and that it's Unique to that asset side that no other assets type has this particular value base and so we're going to use this uh
um hashed a curve there's many possible ways to do it of the asset type representation and that's what that representation is it like a string that has an asset name or is it something else it um it could be a token address for example it could be some kind of other representative string the important thing is that it just has to be unique to that assets type and two distinct assets never share the same representation and so by using this uh hash to curve we can get these
value bases for each asset type and in fact we can generate new value bases um whenever the protocol needs it and so this starts to meet our requirement of not hard coding into the protocol uh the assets that are allowed to go in the pool and if new assets come along we just hash whatever their representation is and we can get the new value base make sense okay so I think I understand how kind of the assets work but how do you create new assets I mean usually for Native assets frequently you would have some kind of like you know either cap or schedule of how they appear anything
like that so when we want to create a multi-asset world a new asset we probably need to set some sort of parameters from the get-go and maybe restrict who can create assets and things like that so what are the kind of challenges or some and solutions that are in regard to creating new assets right so uh since most assets probably come from other chains so you you would want to have some kind of bridge um to whatever chain the the multi-asset shielded pool is on and so when you bridge the assets um and this is sort of independent of the shielded pool you want to have that representation of each app of each asset and then you can either make it uh
the shielded pool perhaps permissions you need to have permission to add a new asset or you can make it permissionless whereas long as your asset type is unique and it's a unique representation it doesn't actually harm the other Assets in the pool you just need to make sure that when the this new asset is deposited in the pool that the new value base is created and then when you're adding uh the new assets to the pool then your value commitment so recalling the uh when you had the sum of the transaction
all of the value commitments in a transaction and we said well the sum of all the value commitments of the notes being spent is equal to the sum of the value commitment of the notes being created when you are actively adding assets to the pool then instead of enforcing this equality you're going to have the value commitment of the assets that
are added plus the value commitment of that um uh facets that are being spent and that should be equal to the output notes that are created and when you're taking assets out you just move this to the other side got it okay and I guess the same could work for like not only for bridged assets but if you have like a chain that creates massive assets natively the assets could be created outside of the shielded pool and moved into the shielded pool and the logic for how you create and all of that stuff could live outside of the shielded pool right unfortunately uh right now um
essentially because assets will generally come from another chain you have to have a transparent Bridge okay so whether it's like an ethereum Bridge or a cosmos IBC or something like that um this is all transparent the addresses the values the particular assets that are involved is all visible from the outside and cryptographically late and um what would be really nice is to be able to have a shielded or private Bridge
where uh assets that are in a shielded pool and one chain can be bridged to a shielded pool on another chain however this is a very complex problem because you're already bridging between chains is already kind of a difficult thing um um but when you have a shield in a private bridge now you have to deal with the different trust models and different chains and it's a whole research field and you probably want to have like the asset to be exactly the same like if you're using your elliptic curve representation as you described like for electric points for you kind of encoding assets the same thing has to happen on the other side otherwise it doesn't work
quite work like that right right if um if you're thinking about not just a different trust model between different chains but like actual different technical specifications different token standards and now you're trying to bridge across chains uh is um it's very comfortable yeah okay so we talked about like just simple transfers but is there anything beyond simple transfers like within the multi-asset shielded pool like can we do something more than that absolutely so um of course as soon as you have multiple asset types uh the the kinds of applications that people would want to do are much more complex and much more varied and so
um some of the things that you might want to do are for example General computation foreign so um if we think about uh ethereum and uh smart contracts on ethereum and other kinds of general purpose computation where you can program into your tokens uh lots of interesting functionality that can be unique for each token um you might want to do the same thing inside of a shielded pool um it was a paper called sexy about this which is very interesting and they describe how you might have
different token types inside of the same pool with this kind of custom computation but this is a very very general approach and with generality is sometimes computationally expensive and so there's some trade-offs but certainly something very exciting that you would want to do is just the same kind of of computation and programmability that you have with a transparent tokens then um the other things you might want to do is you might want to have a shielded decks and those projects that are working on this as well um with the idea that if you want to do
a swap inside of your shielded pool you don't want to have to with you know uh unshield your tokens to a transparent address do the swap and then Shield them again because they have some loss of privacy and so if you build your decks sort of natively to work within the shielded pool this is much better and there's a whole it's a whole interesting problem Again by itself so um another thing that you might want to do is you might want to have Rewards or incentives inside of a shielded pool this could take
the form of many different things maybe you just want to have some kind of airdrop inside of a shielded pool or you want to um you know perhaps over time provide some kind of incentive to certain tokens in the pool or maybe you even want to do something like a shield that's staking where they're sticking Rewards or you just somehow want to have more than just a static amounts of token and the challenge of this of course is that because you don't actually know uh where all the tokens are in the shielded pool like how how could you do an airdrop or something right
um and uh and and so um of course the the way to approach this is to say well we need to have a little bit more programmability in the shielded pool where um where we do allow uh some kind of rewards claiming or airdrop claiming process to happen so that even though um uh perhaps from the external world if someone provides rewards um they might not know exactly where they're going because uh the The Shield that obscures this but uh each uh user uh might see that they're eligible and they can prove that they're
eligible and zero knowledge and uh um either claim the reward or airdrop or something like that when we want to ask this question of uh how do you provide Rewards or incentives or or otherwise um just allowing people to somehow um claim or change their tokens inside of the shielded pool this is actually not impossible so if we recall um the reason that tokens are not fungible so if you have two asset types A1 and A2 and we if we put as a hard goal for our shielded pool that um you sum all of the values across
different asset types independently so um the amount of A1 never affects the amount of A2 and this guarantees that these two token types are not fungible with each other but if we want to do something inside of the pool um where uh um actually there was some kind of difference between these two but we still wanted this fungibility so like um asset one acid tube maybe represent the same token type uh transparently but in code
some metadata for example reward claimed or not so for example um maybe A1 is you know some token type that may be the native token of the chain and then A2 is going to represent the same token type outside of the shielded pool but inside of the shielded pool they're going to be distinguished because maybe one has some rewards that has yet to be claimed in this uh
token type represents that the reward has already been claimed okay and so then we want uh Limited fungibility meaning that we want to be able to uh sort of mix these token types and allow their values to to interact but we don't want to break the uh other than the limited fungibility that we add we don't want to break the constraint that otherwise asset types value independently okay so how do we do that how do we do that well the way that we do that is that if we have the value bases va1 and va2
instead of um insisting that uh value bases always have to be derived by this hash to curve so value the value base for asset one was derived from this hashtag curve and this was derived by another hashtag curve instead what we can do is we can um introduce a new kind of value base which is not created by a hash to curve but maybe something like a one two A2
and it's going to be a combination of these two value bases so we might have -1 of va1 Plus 1. v a 2. and this is going to be an entirely new asset to type not one that came from outside of the shield right but it's something that kind of only exists inside the shielded pool and the amazing thing is that this asset type allows you to convert one unit of asset one to one unit of acid two interesting
and the beauty of it is that uh it's because if you uh took one unit of asset one and combined it with one unit of this uh I'll call it magic asset then the value balance a value commitment of this sum magically turns into one unit of assets too very cool and so as long as you're kind of careful in how you uh allow these kinds of magic assets to be constructed you can allow asset one to be converted into asset two and you can Implement some kind of Rewards or something by saying well
maybe you imagine I have some asset three that you want to want to give to everyone that holds asset one well you just have to change uh the magic asset type instead of just saying convert A1 to A2 maybe it's you call it claim reward and every time that you uh um convert uh asset type 1 asset type 2.
you get one of that's a Type 3 as well and so you're converting acetype one into one of acid type two in one of acid type three all right and so now you've given uh people inside or users inside of the shielded pool this ability to sort of um modify this metadata of their their asset in a controlled way such that previously it represented one thing and now it represents something else and as long as um like I said you're careful in how you uh allow these very limited conversions
you can um encode kind of the simple token operations that you might want to do other than like a simple transform and you can do this without having a full programmability which is which is more expensive you can have all of this inside of the homomorphic value commitment which is a very efficient and some of the examples we mentioned air drops rewards is there are there other use cases that are kind of you can do the same way uh right um well certainly if um perhaps some of these asset types encode uh nfts
or something like that maybe maybe you want to under certain circumstances allow some nft to be minted um this nft maybe is a representing um uh that there were some holding at some particular point in time of asset one um that you want to to represent um and so um if if you want to um yeah if you want to uh encode um you know almost arbitrary metadata in in
these asset types although you you don't really get generalized computation you can still get something that can do a lot of things by the way so you mentioned nfts and one thing that I forgot to ask when you were explaining us at types is for nfts would every nft have a different asset base or is there a way to combine them together and to you know like put some nfts under the same asset base or it doesn't make sense right so the interesting thing is that when you have an nft then your uh you know your value of an nft note well value just more or less
doesn't make sense right it's kind of always equal to one so this means that you're encoding all info in the value base okay so this doesn't mean that uh for example um it's not just kind of the type of nft but like all the data as well somehow goes into this value base or or at least it's represented by this value base and
this does mean that when you're choosing the the representations of each acid type and the representation of what an nft looks like that you have to make sure that all of the information um is is encoded um properly in order to make sure that nfts of similar type but different data don't get mixed together makes sense makes sense all right this was super interesting thank you so much for coming on the show and doing this recording thank you for having me great [Music]