The Lockbox Disbursement key rotation mechanism (https://hackmd.io/@nuttycom/SJuZdFMbxx) offers a way to rotate issuance keys for ZSA.
TL;DR:
- It introduces the concept of a "rotation key" which is separate from the issuance key used by the ZSA Issuer.
- Key rotation bundles can be used to rotate keys (e.g. signing keys or the rotation key itself)
- A key rotation bundle for ZSA basically:
- Specifies which ZSA we rotate keys for (i.e. contains a UID for the ZSA issuance and rotation key)
- Specifies which key (for the given ZSA) is rotated: is it the issuance key? the rotation key itself?
- Contains the new key
- Contains a Proof of Possession for the new key
- Contains a "Rotation auth sig" that uses the currently active rotation key to sign the bundle (i.e. prove that the rotation is done the the authorized party)
Few things to note w.r.t applying the key rotation to the ZSA issuance as specified in ZIP227
ik (the issuance / signing key) is "baked" in the AssetId. This AssetId is used to compute AssetDigest which is used to compute the AssetBase. As such, "changing ik" means -> changing the AssetBase, which isn't desired.
- We can still stick to the original value of
ik (denoted ik_{original} in this doc) in AssetId even if ik gets rotated later on. Doing so, "anchors" the chain of key rotations to the initial ik_{original} value which itself serves as the root of the "chain of trust" for the key rotation. But, given that the original value ik_{original} is used to compute AssetId, we should understand that after rotating this key, the AssetId isn't "derived" from ik anymore, but from a "successor" to the original ik_{original} (which isn't derived from ik_{original})
- In section: https://zcash-zips-qedit.netlify.app/zip-0227#specification-consensus-rule-changes, we need to change
- The issuance authorization signature, $\mathsf{issueAuthSig}$, MUST be a valid $\mathsf{IssueAuthSig}$ signature over $\mathsf{SigHash}$, i.e. $\mathsf{IssueAuthSig}.\!\mathsf{Validate}(\mathsf{ik}, \mathsf{SigHash}, \mathsf{issueAuthSig}) = 1$.
to
- The issuance authorization signature, $\mathsf{issueAuthSig}$, MUST be a valid $\mathsf{IssueAuthSig}$ signature over $\mathsf{SigHash}$ under the most recent \mathsf{ik} for the Asset, i.e. $\mathsf{IssueAuthSig}.\!\mathsf{Validate}(\mathsf{ik}, \mathsf{SigHash}, \mathsf{issueAuthSig}) = 1$.
where \mathsf{ik} is the most recent value of the issuance key for this ZSA.
TL;DR: we must now do a lookup in the state to retrieve the latest ik for the asset being issued, to make sure the issuance transaction is signed under this key (and not under the original value ik_{original}).
Note: Given that we can now rotate ik, we need to make sure rotation transactions are properly mined BEFORE carrying out issuance transactions. In fact, imagine Tx1 does a ZSA issuance under ik_1, and imagine Tx2 does a key rotation to rotate ik_1 to ik2. Then, if Tx2 gets mined before Tx1, then the $\mathsf{issueAuthSig}$ check above will fail for Tx1.
-
The section https://github.com/QED-it/zips/blob/zsa1/zips/zip-0227.rst#hash-of-the-asset-description needs to be changed. Namely, this part:
"""
The lack of key rotation in this issuance protocol means that it is not sufficient to mark an ik as trusted and then accept whatever asset descriptions are issued by it. Each Asset Identifier needs to be independently verified, which requires some out-of-band protocol that can also convey the corresponding asset description.
"""
-
We need to add the concept of rotation is multiple sections e.g. https://zcash-zips-qedit.netlify.app/zip-0227#issuance-bundle , https://zcash-zips-qedit.netlify.app/zip-0227#issuance-bundle etc
- Basically, we need to make it clear that "issueAuthSig is the the signature of the transaction SIGHASH, signed by the current issuance authorizing key, isk, that validates the issuance". TL;DR: we don't have "one isk and ik" anymore. We have a set of such keys, with only ONE tuple being the correct tuple at every single point in time.
- In https://zcash-zips-qedit.netlify.app/zip-0227#issuance-protocol we need to clarify what
ik we need to use to compute the AssetDigest. The sentence:
"""
compute AssetDigest from the issuance validating key ik
"""
becomes:
"""
compute AssetDigest from the original issuance validating key ik_{original}
"""
and
"""
For the IssueBundle:
- encode the
vIssueActions vector.
- encode the
ik as 32 byte-string.
- sign the SIGHASH transaction hash with the issuance authorizing key,
isk, using the IssueAuthSig signature scheme. The signature is then added to the issuance bundle.
"""
needs to become something like
"""
For the IssueBundle:
- encode the
vIssueActions vector.
- encode the current
ik as ikLength byte-string.
- sign the SIGHASH transaction hash with the current issuance authorizing key,
isk, using the IssueAuthSig signature scheme. The signature is then added to the issuance bundle.
"""
Moreover, IssueAuthSig needs to become a variable here too because the Lockbox Disbursement protocol states that the "signature protocol" is specified for each key rotation (so, if we rotate an ik generated as specified in BIP340 by an ik for a different signature scheme, then we need to make sure the correct IssueAuthSig scheme is selected to be consistent with the rotated key - see screenshot below - from https://hackmd.io/@nuttycom/SJuZdFMbxx)
Likewise, the length of ik as well as the length of the signature generated with IssueAuthSig will vary based on the signature scheme used. As such, the size of the IssueBundle will be a function of the scheme selected, which itself is obtained by doing a Zcash state lookup to retrieve the current "active" issuance keys.
As such ikLength and issueAuthSigLength (see https://zcash-zips-qedit.netlify.app/zip-0230) are parameters that are retrieved from the Zcash state (which stores the results of the key rotations)
So, in essence, to be compatible with the Lockbox Disbursement key rotation proposal, the ZIP 227 needs to be "parameterized" to support different / changing values for ik and isk, and to support different signature schemes (which means, signatures and public keys of different lengths in the IssueBundles). Then, the ZIP needs to specify the protocol initialization step, which is:
- The signature scheme
IssueAuthSig is initialized with the sig scheme from BIP340 (this defines the spaces from which ik, isk and the signatures are in at setup).
ik is initialized with ik_{original} and isk is initialized with isk_{original}, where isk_{original} and ik_{original} are BIP340 keys.
AFAICT, in a transfer, the AssetBase for the ZSAs is passed as a private input to the circuit (see https://docs.google.com/document/d/1DzXBqZl_l3aIs_gcelw3OuZz2OVMnYk6Xe_1lBsTji8/edit?tab=t.0) and doesn't need to be recomputed / validated in the circuit. This means, that we don't need to pass ik_{original} as input to the OrchardZSA circuit. So, we should be good here.
The Lockbox Disbursement key rotation mechanism (https://hackmd.io/@nuttycom/SJuZdFMbxx) offers a way to rotate issuance keys for ZSA.
TL;DR:
Few things to note w.r.t applying the key rotation to the ZSA issuance as specified in ZIP227
ik(the issuance / signing key) is "baked" in theAssetId. ThisAssetIdis used to computeAssetDigestwhich is used to compute theAssetBase. As such, "changing ik" means -> changing the AssetBase, which isn't desired.ik(denotedik_{original}in this doc) inAssetIdeven ifikgets rotated later on. Doing so, "anchors" the chain of key rotations to the initialik_{original}value which itself serves as the root of the "chain of trust" for the key rotation. But, given that the original valueik_{original}is used to computeAssetId, we should understand that after rotating this key, the AssetId isn't "derived" fromikanymore, but from a "successor" to the originalik_{original}(which isn't derived fromik_{original})to
TL;DR: we must now do a lookup in the state to retrieve the latest
ikfor the asset being issued, to make sure the issuance transaction is signed under this key (and not under the original valueik_{original}).Note: Given that we can now rotate ik, we need to make sure rotation transactions are properly mined BEFORE carrying out issuance transactions. In fact, imagine Tx1 does a ZSA issuance under
ik_1, and imagine Tx2 does a key rotation to rotateik_1toik2. Then, if Tx2 gets mined before Tx1, then the $\mathsf{issueAuthSig}$ check above will fail for Tx1.The section https://github.com/QED-it/zips/blob/zsa1/zips/zip-0227.rst#hash-of-the-asset-description needs to be changed. Namely, this part:
"""
The lack of key rotation in this issuance protocol means that it is not sufficient to mark an
ikas trusted and then accept whatever asset descriptions are issued by it. Each Asset Identifier needs to be independently verified, which requires some out-of-band protocol that can also convey the corresponding asset description."""
We need to add the concept of rotation is multiple sections e.g. https://zcash-zips-qedit.netlify.app/zip-0227#issuance-bundle , https://zcash-zips-qedit.netlify.app/zip-0227#issuance-bundle etc
ikwe need to use to compute theAssetDigest. The sentence:"""
compute
AssetDigestfrom the issuance validating keyik"""
becomes:
"""
compute
AssetDigestfrom the original issuance validating keyik_{original}"""
and
"""
For the IssueBundle:
vIssueActionsvector.ikas 32 byte-string.isk, using theIssueAuthSigsignature scheme. The signature is then added to the issuance bundle."""
needs to become something like
"""
For the IssueBundle:
vIssueActionsvector.ikasikLengthbyte-string.isk, using theIssueAuthSigsignature scheme. The signature is then added to the issuance bundle."""
Moreover,
IssueAuthSigneeds to become a variable here too because the Lockbox Disbursement protocol states that the "signature protocol" is specified for each key rotation (so, if we rotate anikgenerated as specified in BIP340 by anikfor a different signature scheme, then we need to make sure the correctIssueAuthSigscheme is selected to be consistent with the rotated key - see screenshot below - from https://hackmd.io/@nuttycom/SJuZdFMbxx)Likewise, the length of
ikas well as the length of the signature generated withIssueAuthSigwill vary based on the signature scheme used. As such, the size of theIssueBundlewill be a function of the scheme selected, which itself is obtained by doing a Zcash state lookup to retrieve the current "active" issuance keys.As such
ikLengthandissueAuthSigLength(see https://zcash-zips-qedit.netlify.app/zip-0230) are parameters that are retrieved from the Zcash state (which stores the results of the key rotations)So, in essence, to be compatible with the Lockbox Disbursement key rotation proposal, the ZIP 227 needs to be "parameterized" to support different / changing values for
ikandisk, and to support different signature schemes (which means, signatures and public keys of different lengths in theIssueBundles). Then, the ZIP needs to specify the protocol initialization step, which is:IssueAuthSigis initialized with the sig scheme from BIP340 (this defines the spaces from whichik,iskand the signatures are in at setup).ikis initialized withik_{original}andiskis initialized withisk_{original}, where isk_{original} andik_{original}are BIP340 keys.AFAICT, in a transfer, the AssetBase for the ZSAs is passed as a private input to the circuit (see https://docs.google.com/document/d/1DzXBqZl_l3aIs_gcelw3OuZz2OVMnYk6Xe_1lBsTji8/edit?tab=t.0) and doesn't need to be recomputed / validated in the circuit. This means, that we don't need to pass
ik_{original}as input to the OrchardZSA circuit. So, we should be good here.