CAP: 0040
Title: Signed-Payload: Ed25519 Signed Payload Signer for Atomic Transaction Signature Disclosure
Working Group:
Owner: Leigh McCulloch <@leighmcculloch>
Authors: Leigh McCulloch <@leighmcculloch>
Consulted: Jon Jove <@jonjove>, David Mazières <@stanford-scs>
Status: Final
Created: 2021-07-14
Discussion: https://groups.google.com/g/stellar-dev/c/Wp7gNaJvt40
Protocol version: 19
This proposal adds a new signer type that simplifies the signing process that multiple parties must use in some contracts, such as payment channels, by allowing all parties to share a set of transactions for signing and guaranteeing that if one transaction is signed, authorized, and submitted that information is revealed that allows all other transactions in the set to be authorized.
This protocol change was authored by Leigh McCulloch, with input from the consulted individuals mentioned at the top of this document.
CAP-21 adds transaction precondition primitives that make it possible for multi-party contracts, such as payment channels, to be implemented where a relative time delay must occur between two transactions that have been mutually agreed by all parties to the contract.
Signing a set of transactions in contracts that have a time delay as specified in CAP-21 requires participants to exchange signatures for each transaction across multiple-steps, exchanging the signatures for the transactions in reverse order that they can be executed.
A party must not share their signature for an earlier transaction before receiving all signatures for latter transactions otherwise another party may be able to submit that earlier transaction and lock the contract by refusing to authorize a latter transaction.
In the payment channel designs identified in the design rationale of CAP-21 this requires participants to exchange signatures across at least three messages. This coordination increases implementation complexity. This complexity increases significantly for payment channel implementations that are asynchronous or payment channels where receiving participants are allowed to fall behind confirming payments from a sending participant.
Making it safe for parties of a contract to exchange all signatures for a set of transactions in a single message without risk that only a subset of the transactions could be authorized simplifies payment channel implementations.
This CAP is aligned with the following Stellar Network Goals:
- The Stellar Network should make it easy for developers of Stellar projects to create highly usable products
This patch of XDR changes is based on the XDR files in tag v17.2.0
of
[stellar-core].
diff --git a/src/xdr/Stellar-types.x b/src/xdr/Stellar-types.x
index 8f7d5c20..03149f3d 100644
--- a/src/xdr/Stellar-types.x
+++ b/src/xdr/Stellar-types.x
@@ -19,6 +19,7 @@ enum CryptoKeyType
KEY_TYPE_ED25519 = 0,
KEY_TYPE_PRE_AUTH_TX = 1,
KEY_TYPE_HASH_X = 2,
+ KEY_TYPE_ED25519_SIGNED_PAYLOAD = 3,
// MUXED enum values for supported type are derived from the enum values
// above by ORing them with 0x100
KEY_TYPE_MUXED_ED25519 = 0x100
@@ -33,7 +34,8 @@ enum SignerKeyType
{
SIGNER_KEY_TYPE_ED25519 = KEY_TYPE_ED25519,
SIGNER_KEY_TYPE_PRE_AUTH_TX = KEY_TYPE_PRE_AUTH_TX,
- SIGNER_KEY_TYPE_HASH_X = KEY_TYPE_HASH_X
+ SIGNER_KEY_TYPE_HASH_X = KEY_TYPE_HASH_X,
+ SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD = KEY_TYPE_ED25519_SIGNED_PAYLOAD
};
union PublicKey switch (PublicKeyType type)
@@ -52,6 +54,13 @@ case SIGNER_KEY_TYPE_PRE_AUTH_TX:
case SIGNER_KEY_TYPE_HASH_X:
/* Hash of random 256 bit preimage X */
uint256 hashX;
+case SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD:
+ struct {
+ /* Public key that must sign the payload. */
+ uint256 ed25519;
+ /* Payload to be raw signed by ed25519. */
+ opaque payload<64>;
+ } ed25519SignedPayload;
};
// variable size as the size depends on the signature scheme used
This proposal introduces one new type of signer, the ed25519 signed payload signer, that is defined as a variable length opaque payload with a maximum size of 64 bytes and an ed25519 public key. A signature for the signer is the result of signing the payload with the private key that the public key is derived.
The ed25519 signed payload signer is usable everywhere existing signers may be
used, including in the extraSigners
transaction precondition added in
CAP-21.
The signature of an ed25519 signed payload signer is the raw ed25519 signature of the signer's payload using the private key that derives the signer's ed25519 public key.
For example, given:
- A private key
Ks
and its derived public keyKp
. - A ed25519 signed payload signer
S
that contains:- Payload
P
. - Public key
Kp
.
- Payload
A signature that satisfies signer S
is produced by:
- Ed25519 signing
P
withKs
.
Unlike transaction signatures in the Stellar protocol, the payload of this signer is not combined with the network ID or hashed before passing it to the ed25519 signing algorithm.
The signature hint of an ed25519 signed payload signer is the last 4 bytes of the ed25519 public key XORed with last 4 bytes of the payload. If the payload has a length less than 4 bytes, then 1 to 4 zero bytes are appended to the payload such that it has a length of 4 bytes, for calculating the hint.
This proposal makes no structural changes to transaction envelopes other than the signature of an ed25519 signed payload signer may be included in the list of decorated signatures.
Signature checking is changed to include verifying that any ed25519 signed payload signer's have matching signatures.
Ed25519 signed payload signer signatures are verified by performing ed25519 signature verification using the signature, the payload from the signer, and the ed25519 public key from the signer.
The current protocol validates signers in this order :
SIGNER_KEY_TYPE_PRE_AUTH_TX
-> SIGNER_KEY_TYPE_HASH_X
->
SIGNER_KEY_TYPE_ED25519
. This CAP will verify
SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD
last after SIGNER_KEY_TYPE_ED25519
.
The order can matter in the context of txBAD_AUTH_EXTRA
, because we stop
checking signatures once we have matched enough signatures to meet the required
weight. If there are any signatures that have not been used, the transaction
fails with txBAD_AUTH_EXTRA
.
If a payload signer is used in the extraSigners
precondition specified in
CAP-21, and the payload is empty, the transaction will fail with txMALFORMED
(also specified in CAP-21).
SetOptionsOp
will fail validation with SET_OPTIONS_BAD_SIGNER
if the new
signed payload signer is used prior to the protocol upgrade, or if the payload
is empty.
This proposal provides a primitive that makes it possible to construct a set of transactions where all transactions can be authorized and submitted if the first transaction is authorized and submitted.
This proposal makes this possible since a Stellar transaction hash can be
specified as the payload of an ed25519 signed payload signer. A Stellar
transaction hash is the SHA-256 hash of the TransactionSignaturePayload
containing the Stellar transaction. A valid signature for the signer will also
be a valid signature of the other Stellar transaction if the ed25519 key used to
sign the payload is also required to sign the other transaction.
An ed25519 signed payload signer can be constructed for each subsequent
transaction that needs authorizing, and included in the extraSigners
precondition of the first transadction. This will require the signatures of all
subsequent transactions to be disclosed on the first transaction.
While it is possible to achieve a similar effect of this proposal with the existing protocol by using the preauth transaction signer, use of that signer requires creating a new ledger entry which is impractical in contracts with multiple iterations.
The maximum size of the set of transactions is three, limited to being one
more than the maximum number of extraSigners
specified in CAP-21, currently
two, and can be increased past three if the maximum size of extraSigners
is
changed.
The hint is specified as an XOR of the last 4 bytes of all elements of the signer – the ed25519 public key and the payload – so as to reduce the number of decorated signatures validators must verify in full. If the hint for the signed payload used only the ed25519 public key as input, like an ed25519 signer does, a transaction that requires signatures by an ed25519 key for a signed payload signer and an ed25519 signer would have two decorated signatures with the same hint. Validators would be required to compare the full signature twice for both signers, rather than once if the hint allows for pruning signers of the different type.
In the payment channel designs specified in CAP-21 this proposal simplifies the requirements on when participants may exchange signatures for transactions.
The following paragraph in CAP-21:
To update the payment channel state, the parties 1) increment i, 2) sign and exchange a closing transaction C_i, and finally 3) sign and exchange a declaration transaction D_i.
May be changed to:
To update the payment channel state, the parties 1) increment i, 2) sign and exchange a closing transaction C_i and declaration transaction D_i.
This changes the number of messages the parties must send to each other to update the payment channel, reducing the number from three to two. It reduces the number of messages down to one for any the payment channel implementation where the receiving party of a payment update is the beneficiary.
Three messages using CAP-21:
+---+ +---+
| A | | B |
+---+ +---+
| |
| C_i |
|----------->|
| |
| C_i, D_i |
|<-----------|
| |
| D_i |
|----------->|
| |
Simplified two message process using CAP-21 and CAP-40:
+---+ +---+
| A | | B |
+---+ +---+
| |
| C_i, D_i |
|----------->|
| |
| C_i, D_i |
|<-----------|
| |
Simplified one message process using CAP-21 and CAP-40 where B is the only beneficiary of the update, supporting queue-like processing of payments:
+---+ +---+
| A | | B |
+---+ +---+
| |
| C_i, D_i |
|----------->|
| |
This simplified exchange would be implemented by requiring the sender of a
payment to include in D_i the extraSigners
precondition with an ed25519 signed
payload signer where the payload is the transaction hash of C_i and the ed25519
public key is the public key of the receiving participant that must sign D_i and
C_i.
The effect of this change is the receiving participant must sign the transaction hash of C_i to authorize D_i, embedding their signature for C_i into D_i. If the receiving participant nefariously authorizes and submits D_i without sharing a signature for C_i, the sender who is watching the network may see D_i be submitted, extract the signature for C_i from the signatures on D_i, attach the signature to C_i, and submit C_i.
The use of the payload signer in CAP-21's payment channel requires a payload of 32 bytes to store the hash of another Stellar transaction. 32 bytes are required because Stellar transaction hashes utilize the SHA-256 algorithm.
This new signer is likely to have other applications in scenarios similar to where HASH_X signers are currently used, except that the data revealed would not only be a hash shared by multiple transactions across multiple chains, but could be a signature for a hash validated by a smart contract on another chain, or a signature for any other use. However, this has limited use to only signatures of ed25519 keys as specified.
The use of the payload signer in these other applications could require a variety of different payload sizes. It would be impractical to permit large payloads without changes to Stellar's fee participation because the sizes of transactions and account sub-entries in the ledger could explode.
A payload with a maximum length of 64 bytes, rather than 32 bytes, would support payloads that are hashes for most hashing algorithms defined today – e.g. SHA-384, SHA-512 – which may support future cross-chain applications that choose to use ed25519 signatures of hashes.
This proposal is backwards compatible.
No substantial changes to resource utilization.
The size of signatures, and therefore transactions, remain the same.
The effort to verify the signature is equivalent to the effort to verify an ed25519 signature.
The size of signers stored in the ledger will be 3x the size, at 96 bytes, for ed25519 signed payload signers compared to 32 bytes for all other signers.
None yet.
If a transaction requires the signature of a Signed Payload Signer and a signer signs it without understanding the preimage of the payload, the signer could be authorizing another Stellar transaction if the payload is a Stellar transaciton hash, or the signer could be authorizing some other operation on another network or application. People and applications should never sign a hash that they do not completely understand the consequences of signing, in all the contexts that their key provides authentication or authorization. People and applications should never sign a transaction they do not completely understand. There are many cases where signing a transaction not completely understood can pose a security concern for the signer because the signer could be authorizing something they would not approve of if they did understand the transaction. This proposal introduces a new case with the Signed Payload Signer.
None yet.