diff --git a/.aspell.en.pws b/.aspell.en.pws index 7de4fad86..97b6ebdbd 100644 --- a/.aspell.en.pws +++ b/.aspell.en.pws @@ -358,6 +358,7 @@ optimizations structs CompactSize encodings +remotekey bigsize BigSize namespaces diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 0ca3722d2..49f49bff8 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -366,6 +366,12 @@ This message introduces the `channel_id` to identify the channel. It's derived f #### Requirements +Both peers: + - if `option_static_remotekey` was negotiated: + - `option_static_remotekey` applies to all commitment transactions + - otherwise: + - `option_static_remotekey` does not apply to any commitment transactions + The sender MUST set: - `channel_id` by exclusive-OR of the `funding_txid` and the `funding_output_index` from the `funding_created` message. - `signature` to the valid signature, using its `funding_pubkey` for the initial commitment transaction, as defined in [BOLT #3](03-transactions.md#commitment-transaction). @@ -377,6 +383,12 @@ The recipient: - on receipt of a valid `funding_signed`: - SHOULD broadcast the funding transaction. +#### Rationale + +We decide on `option_static_remotekey` at this point when we first have to generate the commitment +transaction. Even if a later reconnection does not negotiate this parameter, this channel will continue to use `option_static_remotekey`; we don't support "downgrading". +This simplifies channel state, particularly penalty transaction handling. + ### The `funding_locked` Message This message indicates that the funding transaction has reached the `minimum_depth` asked for in `accept_channel`. Once both nodes have sent this, the channel enters normal operating mode. @@ -1119,8 +1131,8 @@ messages are), they are independent of requirements here. * [`channel_id`:`channel_id`] * [`u64`:`next_commitment_number`] * [`u64`:`next_revocation_number`] - * [`32*byte`:`your_last_per_commitment_secret`] (option_data_loss_protect) - * [`point`:`my_current_per_commitment_point`] (option_data_loss_protect) + * [`32*byte`:`your_last_per_commitment_secret`] (option_data_loss_protect,option_static_remotekey) + * [`point`:`my_current_per_commitment_point`] (option_data_loss_protect,option_static_remotekey) `next_commitment_number`: A commitment number is a 48-bit incrementing counter for each commitment transaction; counters @@ -1168,10 +1180,13 @@ The sending node: next `commitment_signed` it expects to receive. - MUST set `next_revocation_number` to the commitment number of the next `revoke_and_ack` message it expects to receive. - - if it supports `option_data_loss_protect`: + - if `option_static_remotekey` applies to the commitment transaction: + - MUST set `my_current_per_commitment_point` to a valid point. + - otherwise, if it supports `option_data_loss_protect`: - MUST set `my_current_per_commitment_point` to its commitment point for the last signed commitment it received from its channel peer (i.e. the commitment_point corresponding to the commitment transaction the sender would use to unilaterally close). + - if `option_static_remotekey` applies to the commitment transaction, or the sending node supports `option_data_loss_protect`: - if `next_revocation_number` equals 0: - MUST set `your_last_per_commitment_secret` to all zeroes - otherwise: @@ -1210,7 +1225,16 @@ A node: - SHOULD fail the channel. A receiving node: - - if it supports `option_data_loss_protect`, AND the `option_data_loss_protect` + - if `option_static_remotekey` applies to the commitment transaction: + - if `next_revocation_number` is greater than expected above, AND + `your_last_per_commitment_secret` is correct for that + `next_revocation_number` minus 1: + - MUST NOT broadcast its commitment transaction. + - SHOULD fail the channel. + - otherwise: + - if `your_last_per_commitment_secret` does not match the expected values: + - SHOULD fail the channel. + - otherwise, if it supports `option_data_loss_protect`, AND the `option_data_loss_protect` fields are present: - if `next_revocation_number` is greater than expected above, AND `your_last_per_commitment_secret` is correct for that @@ -1303,6 +1327,14 @@ is valid. However, this also means the fallen-behind node has revealed this fact (though not provably: it could be lying), and the other node could use this to broadcast a previous state. +`option_static_remotekey` removes the changing `to_remote` key, +so the `my_current_per_commitment_point` is unnecessary and thus +ignored (for parsing simplicity, it remains and must be a valid point, +however), but the disclosure of previous secret still allows +fall-behind detection. An implementation can offer both, however, and +fall back to the `option_data_loss_protect` behavior if +`option_static_remotekey` is not negotiated. + # Authors [ FIXME: Insert Author List ] diff --git a/03-transactions.md b/03-transactions.md index 805e6983d..c72bd0981 100644 --- a/03-transactions.md +++ b/03-transactions.md @@ -411,9 +411,9 @@ committed HTLCs: ## Key Derivation -Each commitment transaction uses a unique set of keys: `localpubkey` and `remotepubkey`. +Each commitment transaction uses a unique `localpubkey`, and a `remotepubkey`. The HTLC-success and HTLC-timeout transactions use `local_delayedpubkey` and `revocationpubkey`. -These are changed for every transaction based on the `per_commitment_point`. +These are changed for every transaction based on the `per_commitment_point`, with the exception of `remotepubkey` if `option_static_remotekey` is negotiated. The reason for key change is so that trustless watching for revoked transactions can be outsourced. Such a _watcher_ should not be able to @@ -426,8 +426,9 @@ avoid storage of every commitment transaction, a _watcher_ can be given the the scripts required for the penalty transaction; thus, a _watcher_ need only be given (and store) the signatures for each penalty input. -Changing the `localpubkey` and `remotepubkey` every time ensures that commitment -transaction ID cannot be guessed; every commitment transaction uses an ID +Changing the `localpubkey` every time ensures that commitment +transaction ID cannot be guessed except in the trivial case where there is no +`to_local` output, as every commitment transaction uses an ID in its output script. Splitting the `local_delayedpubkey`, which is required for the penalty transaction, allows it to be shared with the _watcher_ without revealing `localpubkey`; even if both peers use the same _watcher_, nothing is revealed. @@ -441,14 +442,13 @@ For efficiency, keys are generated from a series of per-commitment secrets that are generated from a single seed, which allows the receiver to compactly store them (see [below](#efficient-per-commitment-secret-storage)). -### `localpubkey`, `remotepubkey`, `local_htlcpubkey`, `remote_htlcpubkey`, `local_delayedpubkey`, and `remote_delayedpubkey` Derivation +### `localpubkey`, `local_htlcpubkey`, `remote_htlcpubkey`, `local_delayedpubkey`, and `remote_delayedpubkey` Derivation These pubkeys are simply generated by addition from their base points: pubkey = basepoint + SHA256(per_commitment_point || basepoint) * G The `localpubkey` uses the local node's `payment_basepoint`; -the `remotepubkey` uses the remote node's `payment_basepoint`; the `local_htlcpubkey` uses the local node's `htlc_basepoint`; the `remote_htlcpubkey` uses the remote node's `htlc_basepoint`; the `local_delayedpubkey` uses the local node's `delayed_payment_basepoint`; @@ -459,6 +459,19 @@ secrets are known (i.e. the private keys corresponding to `localpubkey`, `local_ privkey = basepoint_secret + SHA256(per_commitment_point || basepoint) +### `remotepubkey` Derivation + +If `option_static_remotekey` is negotiated the `remotepubkey` is simply the +remote node's `payment_basepoint`, otherwise it is calculated as above using +the remote node's `payment_basepoint`. + +The simplified derivation means that a node can spend a commitment +transaction even if it has lost data and doesn't know the +corresponding `per_commitment_point`. A watchtower could correlate +transactions given to it which only have a `to_remote` output if it +sees one of them onchain, but such transactions do not need any +enforcement and should not be handed to a watchtower. + ### `revocationpubkey` Derivation The `revocationpubkey` is a blinded key: when the local node wishes to create a new diff --git a/09-features.md b/09-features.md index 7665d8d57..ee79290d4 100644 --- a/09-features.md +++ b/09-features.md @@ -27,6 +27,7 @@ These flags may only be used in the `init` message: | 4/5 | `option_upfront_shutdown_script` | Commits to a shutdown scriptpubkey when opening channel | [BOLT #2][bolt02-open] | | 6/7 | `gossip_queries` | More sophisticated gossip control | [BOLT #7][bolt07-query] | | 10/11 | `gossip_queries_ex` | Gossip queries can include additional information | [BOLT #7][bolt07-query] | +| 12/13| `option_static_remotekey` | Static key for remote output | [BOLT #3](03-transactions.md) | ## Assigned `globalfeatures` flags