Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposed v0 DLC TLV messages and Deterministic Fee Computation #81

Merged
merged 16 commits into from
Sep 29, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 118 additions & 7 deletions Messaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ All data fields are unsigned big-endian unless otherwise specified.
* [Connection Handling and Multiplexing](#connection-handling-and-multiplexing)
* [Message Format](#message-format)
* [Fundamental Types](#fundamental-types)
* [DLC Specific Types](#dlc-specific-types)
* [The `contract_info` Type](#the-contract_info-type)
* [Version 0 `contract_info`](#version-0-contract_info)
* [The `oracle_info` Type](#the-oracle_info-type)
* [Version 0 `oracle_info`](#version-0-oracle_info)
* [The `funding_input` Type](#the-funding_input-type)
* [Temporary `funding_input`](#temporary-funding_input)
* [The `cet_adaptor_signatures` Type](#the-cet_adaptor_signatures-type)
* [Version 0 `cet_adaptor_signatures`](#version-0-cet_adaptor_signatures)
* [The `funding_signatures` Type](#the-funding_signatures-type)
* [Version 0 `funding_signatures`](#version-0-funding_signatures)
* [Authors](#authors)

## Connection Handling and Multiplexing
Expand All @@ -20,7 +31,13 @@ Implementations MUST use a single connection per peer; contract messages (which

## Message Format

We reuse the [Lightning Message Format](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#lightning-message-format) and the [Type-Length-Value Format](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#type-length-value-format)
We reuse the [Lightning Message Format](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#lightning-message-format) and the [Type-Length-Value Format](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#type-length-value-format) (TLV).
To be clear, any encoded binary blob that can be sent over the wire will follow the Lightning Message Format
while all sub-types internal to these messages will follow the Type-Length-Value Format.
This means that types on outer-messages will be represented with `u16` integers (defined below) and their length
is omitted from their encoding because the transport layer has the length in a separate unencrypted field.
Meanwhile all typed sub-messages (which follow TLV format) will have their types represented using `bigsize` integers
(defined below) and their lengths (also `bigsize`) are included in their encodings.

## Fundamental Types

Expand All @@ -44,20 +61,114 @@ The following convenience types are also defined:
* `contract_id`: a 32-byte contract_id (see [Protocol Specification](Protocol.md))
* `sha256`: a 32-byte SHA2-256 hash
* `signature`: a 64-byte bitcoin Elliptic Curve signature
* `ecdsa_adaptor_signature`: a 65-byte ECDSA adaptor signature (TODO: link to doc once [#50](https://github.com/discreetlogcontracts/dlcspecs/issues/50) is done)
* `dleq_proof`: a 97-byte zero-knowledge proof of discrete log equality (TODO: link to doc once [#50](https://github.com/discreetlogcontracts/dlcspecs/issues/50) is done)
* `x_point`: a 32-byte x-only public key with implicit y-coordinate being even as in [BIP 340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#design)
Tibo-lg marked this conversation as resolved.
Show resolved Hide resolved
* `point`: a 33-byte Elliptic Curve point (compressed encoding as per [SEC 1 standard](http://www.secg.org/sec1-v2.pdf#subsubsection.2.3.3))
* `spk`: A bitcoin script public key encoded as ASM prefixed with a Bitcoin CompactSize unsigned integer
* `short_contract_id`: an 8 byte value identifying a contract funding transaction on-chain (see [BOLT #7](https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#definition-of-short-channel-id))
* `bigsize`: a variable-length, unsigned integer similar to Bitcoin's CompactSize encoding, but big-endian. Described in [BigSize](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#appendix-a-bigsize-test-vectors).
* `contract_info`: ???
* `oracle_info`: ???
* `funding_input`: ???
* `cet_signatures`: ???
* `funding_signatures`: ???

## DLC Specific Types

The following DLC-specific types are used throughout the specification. All type numbers are placeholders subject to change both here and in [Protocol.md](Protocol.md).

### The `contract_info` Type

This type contains information about a contracts outcomes and their corresponding payouts. To save space, only one side's POV is included in this message as the other can be derived using `remote_payout = total_collateral - local_payout`.

#### Version 0 `contract_info`

1. type: 42768 (`contract_info_v0`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if it's temporary can you assign them in the LN's messages waiting rooms : lightning/bolts#716 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'll wait a while longer on this until we are sure we will actually be using LN message format long-term (e.g. does #96 work as an approach) before adding to here but I will do so if it becomes clear we won't be using an incompatible variant.

2. data:
* [`sha256`:`outcome_1`]
* [`u64`:`outcome_1_local_payout`]
* ...
* [`sha256`:`outcome_n`]
* [`u64`:`outcome_n_local_payout`]

This type of contract info is a simple enumeration where the value `n` is omitted from being explicitly included as it can be derived from the length field of the TLV.

### The `oracle_info` Type

This type contains information about the oracle(s) to be used in executing a DLC, and possibly the outcomes possible if these are not specified in the corresponding `contract_info`.

#### Version 0 `oracle_info`

1. type: 42770 (`oracle_info_v0`)
2. data:
* [`x_point`:`oracle_public_key`]
* [`x_point`:`oracle_nonce`]

This type of oracle info is for single-oracle, single signature (and hence single nonce) events.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A side-note, we should make mandatory in the Oracle spec-side to verify public key ownership to avoid someone impersonating the oracle and thus blocking the state of your contract.

Though I don't know the state of oracle discovery, if we rely on common public key infrastructure.

cc @LLFourn

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#97

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A side-note, we should make mandatory in the Oracle spec-side to verify public key ownership to avoid someone impersonating the oracle and thus blocking the state of your contract.

I didn't understand what this meant. How can you impersonate the oracle?
Note I made a comment here: #61 about how I don't think it makes sense to send oracle_nonce. If you do you the oracle must sign it along with the event data it is associated with. Perhaps this is what you are getting at.


### The `funding_input` Type

This type contains information about a specific input to be used in a funding transaction, as well as its corresponding on-chain UTXO.

#### Version 0 `funding_input`

1. type: 42772 (`funding_input_v0`)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite confusing, in contract_info_v0 we have a single TLV record for many outcomes. Here we have one TLV record for each input.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because contract information follows a uniform type (all outcomes fall under the same version, and if they don't a future version will have separate TLV records) whereas different inputs are independent (e.g. taproot input could be funding_input_v1 and not have prev_tx at the same time as another input is v0)

2. data:
* [`u16`:`prevtx_len`]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in theory not needed, as a parser knows how big is a transaction.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is to allow clients which don't have transaction parser to make external calls to one after having parsed the transaction. Regardless of why I have made this record as close to this as possible: https://github.com/niftynei/lightning-rfc/pull/1/files#diff-3369c5aa1774fef2ff1e246979f223eaR169

* [`prevtx_len*byte`:`prevtx`]
* [`u32`:`prevtx_vout`]
* [`u32`:`sequence`]
* [`u16`:`max_witness_len`]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing the script field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what you are referring to? If you're talking about p2sh that is the redeem script below and if not then you definitely must not include a witness script when giving your funding input as funding signatures must be delayed until after CET signatures are received.

Copy link

@NicolasDorier NicolasDorier Sep 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, I don't understand the purpose of max_witness_len.
I can see what it is, but why is it needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For deterministic fee computation

* [`u16`:`redeemscript_len`]
nkohen marked this conversation as resolved.
Show resolved Hide resolved
* [`redeemscript_len*byte`:`script`]

`prevtx_tx` is the serialized transaction whose `prevtx_vout` output is being spent.
Copy link

@NicolasDorier NicolasDorier Sep 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a deal breaker for me.

In BTCPay Server, we don't have the prevtx, because if the user restored his wallet, it is through scantxoutsetinfo and we work on pruned node, so no way to get back this data.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this requirement can be dropped, because the signatures already cover the input value (it's a segwit feature).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it was not needed in the non-TLV version of the spec, why has it been added?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a receiver you have to verify that announced inputs aren't malleable ones, how do you combine this with pruning mode ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devrandom it covers your own input value but not the others https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification

If you don't include the full prev tx they can give you a valid txid pointing to a non-segwit address and convince you it is segwit (because you're trusting them by not requiring the full prevtx) once you sign the funding tx, they can include a script signature you weren't expecting, your signatures are still valid but the txid changes and all CETs and refund tx become invalid.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh and I think I misunderstood, if I now understand correctly, with this new versioned approach you should be able to be trustless if your counter-party accepts txid+vout instead of prevtx (if they are a full node for example) as the issue for you is getting your own prevtx, not validating the counter party's if you are given a prevtx right?

Copy link

@NicolasDorier NicolasDorier Sep 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nkohen so I searched a bit:

  • Bitcoin core is including previous transaction when creating a new PSBT for the wallet since 0.20.1. (latest version)
  • So I swtiched BTCPay Server to mirror the same behavior by default. Sadly, this won't work for restored wallet.

as the issue for you is getting your own prevtx, not validating the counter party's if you are given a prevtx right?

Correct.

Stepping back a bit, I think the best reason for allowing witness_utxo in the protocol, is not about making it easier for wallets with the full utxo set. But to prepare taproot. Once we have taproot, the non_witness_utxo won't be needed in any case. So I think it makes sense to allow it in the protocol for this reason.
On my side, my implementation of this protocol I would allow witness_utxo even for segwit v0 as we have the utxo set, but still try to add non_witness_utxo, if possible, to offer/accept.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great news :) Lmk if there's anything I can do to help. And also to clarify, you're cool with moving forward with prevtx and adding a non-prevtx version in the near future (potentially the subsequent PR to this one)?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, seems good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#98

The transaction is used to validate this spent output's value and to validate that it is a SegWit output.

`max_witness_len` is the total serialized length of the witness data that will be supplied
(e.g. sizeof(varint) + sizeof(witness) for each) in `funding_signatures`.

`script` is the script signature field for the input. Only applicable for P2SH-wrapped inputs.
The length of the script should not be included in the transmitted script data.

### The `cet_adaptor_signatures` Type

This type contains CET signatures and any necessary information linking the signatures to their corresponding outcome.

#### Version 0 `cet_adaptor_signatures`

1. type: 42774 (`cet_adaptor_signatures_v0`)
2. data:
* [`ecdsa_adaptor_signature`:`signature_1`]
* [`dleq_proof`:`dleq_prf_1`]
* ...
* [`ecdsa_adaptor_signature`:`signature_n`]
* [`dleq_proof`:`dleq_prf_n`]

This type should be used with [`contract_info_v0`](#version-0-contract_info) where each indexed signature in the data corresponds to the outcome of the same index. As in [`contract_info_v0`](#version-0-contract_info), the number of signatures is omitted as it can be derived from the length field of the TLV.

### The `funding_signatures` Type

This type contains signatures of the funding transaction and any necessary information linking the signatures to their inputs.

#### Version 0 `funding_signatures`

1. type: 42776 (`funding_signatures_v0`)
Tibo-lg marked this conversation as resolved.
Show resolved Hide resolved
2. data:
* [`u16`:`num_witnesses`]
* [`u16`:`num_witness_elems_1`]
* [`num_witness_elems_1*witness_element`:`witness_elements_1`]
* ...
* [`u16`:`num_witness_elems_num_witnesses`]
* [`num_witness_elems_num_witnesses*witness_element`:`witness_elements_num_witnesses`]
3. subtype: `witness_element`
4. data:
* [`u16`:`len`]
* [`len*byte`:`witness`]

`witness` is the data for a witness element in a witness stack. An empty `witness_stack` is an error,
as every input must be Segwit. Witness elements should *not* include their length as part of the witness data.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Christewart Can we tag as a V0.2 to reject malleable witness scripts ? I don't think Miniscript compilers have the interface yet but that something to consider in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I'm not sure this is a feasible constraint seeing as one party never sees the other's witnesses before they see them on-chain. Is there any reason witness malleability is an issue in this context as it doesn't invalidate future txs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes witness malleability is a pinning vector and as such you can prevent confirmation of the funding transaction and escape the contract in case of non-favorable outcome.

In theory you can parse a witnessScript and decide if a solving witness is malleable. But as pointed IIRC Miniscript isn't supporting this.


## Authors

Nadav Kohen <nadavk25@gmail.com>

![Creative Commons License](https://i.creativecommons.org/l/by/4.0/88x31.png "License CC-BY")
<br>
This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).
This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).
27 changes: 14 additions & 13 deletions Protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ This message contains information about a node and indicates its
desire to enter into a new contract. This is the first step toward creating
the funding transaction and CETs.

1. type: ??? (`offer_dlc`)
1. type: 42778 (`offer_dlc_v0`)
2. data:
* [`byte`:`contract_flags`]
* [`chain_hash`:`chain_hash`]
Expand Down Expand Up @@ -154,7 +154,7 @@ acceptance of the new DLC, as well as its CET and refund transaction
signatures. This is the second step toward creating the funding transaction
and closing transactions.

1. type: ??? (`accept_dlc`)
1. type: 42780 (`accept_dlc_v0`)
2. data:
* [`32*byte`:`temporary_contract_id`]
* [`u64`:`total_collateral_satoshis`]
Expand All @@ -163,7 +163,7 @@ and closing transactions.
* [`u16`:`num_funding_inputs`]
* [`num_funding_inputs*funding_input`:`funding_inputs`]
* [`spk`:`change_spk`]
* [`cet_signatures`:`cet_signatures`]
* [`cet_adaptor_signatures`:`cet_adaptor_signatures`]
* [`signature`:`refund_signature`]

#### Requirements
Expand All @@ -173,8 +173,8 @@ The `temporary_contract_id` MUST be the SHA256 hash of the `offer_dlc` message.
The sender MUST:

- set `total_collateral_satoshis` sufficiently large so that the sum of both parties' total collaterals is at least as large as the largest payout in the `offer_dlc`'s `contract_info`.
- set `cet_signatures` to valid adaptor signatures, using its `funding_pubkey` for each CET, as defined in the [transaction specification](Transactions.md#contract-execution-transaction) and using signature public keys computed using the `offer_dlc`'s `contract_info` and `oracle_info` as adaptor points.
- include an adaptor signature in `cet_signatures` for every event specified in the `offer_dlc`'s `contract_info`.
- set `cet_adaptor_signatures` to valid adaptor signatures, using its `funding_pubkey` for each CET, as defined in the [transaction specification](Transactions.md#contract-execution-transaction) and using signature public keys computed using the `offer_dlc`'s `contract_info` and `oracle_info` as adaptor points.
- include an adaptor signature in `cet_adaptor_signatures` for every event specified in the `offer_dlc`'s `contract_info`.
- set `refund_signature` to the valid signature, using its `funding_pubkey` for the refund transaction, as defined in the [transaction specification](Transactions.md#refund-transaction).

The sender SHOULD:
Expand All @@ -186,7 +186,7 @@ The receiver:

- if `total_collateral_satoshis` is not large enough:
- MAY reject the contract.
- if `cet_signatures` or `refund_signature` fail validation:
- if `cet_adaptor_signatures` or `refund_signature` fail validation:
- MUST reject the contract.
- if `funding_inputs` do not contribute at least `total_collateral_satohis` plus [fee payment](Transactions.md#fee-payment)
- MUST reject the contract.
Expand All @@ -201,10 +201,10 @@ all closing transactions.

This message introduces the [`contract_id`](#definition-of-contract_id) to identify the contract.

1. type: ??? (`sign_dlc`)
1. type: 42782 (`sign_dlc_v0`)
2. data:
* [`contract_id`:`contract_id`]
* [`cet_signatures`:`cet_signatures`]
* [`cet_adaptor_signatures`:`cet_adaptor_signatures`]
* [`signature`:`refund_signature`]
* [`funding_signatures`:`funding_signatures`]

Expand All @@ -213,16 +213,17 @@ This message introduces the [`contract_id`](#definition-of-contract_id) to ident
The sender MUST:

- set `contract_id` by exclusive-OR of the `funding_txid` and the `funding_output_index` from the `offer_dlc` and `accept_dlc` messages.
- set `cet_signatures` to valid adaptor signatures, using its `funding_pubkey` for each CET, as defined in the [transaction specification](Transactions.md#contract-execution-transaction) and using signature public keys computed using the `offer_dlc`'s `contract_info` and `oracle_info` as adaptor points.
- include an adaptor signature in `cet_signatures` for every event specified in the `offer_dlc`'s `contract_info`.
- set `cet_adaptor_signatures` to valid adaptor signatures, using its `funding_pubkey` for each CET, as defined in the [transaction specification](Transactions.md#contract-execution-transaction) and using signature public keys computed using the `offer_dlc`'s `contract_info` and `oracle_info` as adaptor points.
- include an adaptor signature in `cet_adaptor_signatures` for every event specified in the `offer_dlc`'s `contract_info`.
- set `refund_signature` to the valid signature, using its `funding_pubkey` for the refund transaction, as defined in the [transaction specification](Transactions.md#refund-transaction).
- set `funding_signatures` to valid input signatures.
- include a signature in `funding_signatures` for every funding input specified in the `offer_dlc` message.
- set `funding_signatures` to contain valid witnesses for every funding input specified in the `offer_dlc` message and in the same order.

The recipient:

- if any `signature` is incorrect:
- if any `signature` or `witness` is incorrect:
- MUST reject the contract.
- if any witness exceeds its corresponding `max_witness_len` from the `offer_dlc` message:
- MAY reject the contract.
- MUST NOT broadcast the funding transaction before receipt of a valid `sign_dlc`.
- on receipt of a valid `sign_dlc`:
- SHOULD broadcast the funding transaction.
Expand Down
Loading