A problem with any implementation of a shielded resource machine is that all the data is shielded! Meaning if we wished to use partial transactions to make complete transactions we can not use the data included, this makes solving things very hard. As I understand there are active conversations on how to solve shielded transactions, this post is meant to be a compatible technique that can work with those methods but is a post on a technique on how to make transparent data shielded in a final transaction in a seamless way for the user.
For the sake of simplicity let us take a Resource data type
Resource =
{ logic-reference, label-reference, value-reference, quantity
, ephmeral?, nonce, nullifier-key-commitment, randseed }
The specification lays out alongside this fixed types, instead of taking fixed types, I’d rather take the types as an interface for us to care about. Meaning that if quantity
is of type Quantity
in the spec, then I take it to mean that every message a Quantity
can accept the quantity
slot in our Resource
type can as well.
For clarification let us look at the Quantity
type in some detail, let us say it’s an interface that just has a single value:
Interface Quantity = {
value : Quantity -> Field
}
Now let us define out two different quantity types
ShieldedQuantity = { value }
ShieldedQuantity >> value
^ value
ShieldedQuantity >> value: a-value
value := a-value shield
( Example Usage )
foo := ShieldedQuantity new value: 5.
foo value ( we get back 5 shielded )
This version is the shielded version, we can see that we respect the interface as we implement the value
method. It simply returns the slot value
. The only interesting thing is that our value:
setter method takes a-value
and calls shield
on it such that it will be opaque from that point on.
Now let us look at a transparent version
Quantity = { value }
Quantity >> value
^ value
Quantity >> value: a-value
value := a-value
( Example Usage )
bar := Quantity new value: 5.
bar value ( we get back 5 )
Here the only difference between this and the shielded one is that we get back the actual value from the object (5 in the case of bar value
).
Now From Resource’s Point of view it doesn’t care, it may only ever call value
on it’s quantity field
Resource >> quantity: a-quantity
quantity := a-quantity
Resource >> amount
^ quantity value
Thus we can have either
a-more-transparent-resource := Resource ... quantity: bar
a-more-shielded-resource := Resource ... quantity: foo
and all messages that we would want on these objects should just work!
Why would we want to give more transparent data? Well the rational may be to help solvers, maybe we want to give some information but not all information, and by doing this on a data structure by data structure basis we can effectively control how much information we divulge.
Now… this is unsatisfying, if we implemented our RM this way, we will have to deal with processing with transparent data and shielded data, even if this is possible, we have the problem that this information is stored for time in memoria. However I believe there is a very easy solution to this.
So I suggest we have another interface all data types that populate the RM
data structures must accept. That is:
Interface Shield = {
shield : Shield -> Opaque
}
Thus we can implement it like this
ShieldedQuantity >> shield
^ self
Quantity >> shield
^ ShieldedQuantity new value: self value
Thus we can do something like this
Resource >> shield
quantity := quantity shield.
logic-reference := logic-reference shield.
....
Now, when we send it to the intent pool we can decode some of the values we wish to be used in solving, and before it is submitted to the mempool, we simply need to say our-transaction shield
, now all the data is now shielded to be stored online.
We can have many variants on this idea since we are using objects:
- If the particular RM allows transparent data, then if a user wishes it, they can implement a data structure that refuses to shield it’s data in case the transparent data wants to be preserved (I’m not sure why)
- We can have a more complicated a more generic
shieldedQuantity
that can determine whatRM
it wants to be used in and more effictively shield itself. - What if we wanted to partially shield the data inside, meaning that we wish to keep some data always revealed..
- What if we can shield data to certain keys? Can we implement this with the proper data types?
What does everyone think of this technique?
Here are some interesting directions we can go:
- For
resource-logics
, if we imagineresource-logics
as posing constraints, can we have a version of this that partially shields some of the constraints but not all? (growing on 2) - Could we generalize the idea of a shielded resource machine data type and have
shield-to:
which takes a backend and knows how to handle that?