Should be a nullifier, I believe
I just realized that there is still a problem in the context of authorization via signed messages in the extra data (a type alias in the Juvix code hid it for me until now).
If we require the nullifier nf
instead of the commitment cm
, we must be able to reproduce it as part of the authorization check (i.e., isAuthorizedByOwner
) being part of the resource logic (see the implementation code at the end of this post).
However, resource logic functions being currently defined as
logic : (self : Resource) (tx : Transaction) -> Bool
only receive the resource plaintext self
and transaction tx
as inputs, which is not enough to compute the nullifier \texttt{nf} = h_\texttt{nf}(\texttt{nk}, r). We need the nullifier key nk
as well, to which the resource logic function does not have access.
I am also aware that we most likely do not want to share the nullifier key, although it can be a randomly generated secret used only once for this specific resource – @vveiln explained it here:
If we are ok with sharing it, we could put nk
(encrypted?) into the extra
data map, but then the question is under which key to find it. The only way seems to be to use the commitment h_\texttt{cm}(\texttt{self}) of the self
resource as the lookup key, which we don’t want to use as it reveals information about the creation date and brings us back to the beginning.
Any ideas how to solve this more simply and elegantly @vveiln @cwgoes @degregat ?
I am not sure if this changes with an action stack. It could work if an action contains exactly one consumed resource, because then there is only one nullifier to search for.
Implementation Code
tokenLogic
(self : Resource) (tx : Transaction) : Bool :=
if
| isConsumed self tx := isAuthorizedByOwner self tx -- <-- NOTE: `nk` cannot be passed here
| isCreated self tx := true
| else := false;
isAuthorizedByOwner
(self : Resource)
(tx : Transaction)
(nk : NullifierKey) -- <-- NOTE: This argument is not available in `tokenLogic.
: Bool :=
let
owner : PublicKey := getOwner self;
selfNf : Helper.Nullifier := nullifier self nk;
lookupResult : Maybe (Pair AuthMessage Signature) :=
lookupExtraData (natToBytes32 selfNf) tx;
in case lookupResult of
| nothing := false
| just (msg, sig) :=
AuthMessage.consumed msg == selfNf
&& anomaVerifyDetached sig msg owner
&& isSubset
(AuthMessage.mustBeCreated msg)
(commitmentSet tx);
type AuthMessage :=
mkAuthMessage {
consumed : Nullifier;
mustBeCreated : Set Commitment
};