A Proposal For a Flexibly Shielded RM Implementation

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:

  1. 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)
  2. We can have a more complicated a more generic shieldedQuantity that can determine what RM it wants to be used in and more effictively shield itself.
  3. What if we wanted to partially shield the data inside, meaning that we wish to keep some data always revealed..
  4. 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:

  1. For resource-logics, if we imagine resource-logics as posing constraints, can we have a version of this that partially shields some of the constraints but not all? (growing on 2)
  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?