Subject: Re: [Bitcoin-development] BIP for Proof of Payment

From: Pieter Wuille <[email-masked]>
Date: Sat, 6 Jun 2015 16:47:05 +0200

What do you gain by making PoPs actually valid transactions? You could for
example change the signature hashing algorithm (prepend a constant string,
or add a second hashing step) for signing, rendering the signatures in a
PoP unusable for actual transaction, while still committing to the same
actual transaction. That would also remove the need for the OP_RETURN to
catch fees.

Also, I would call it "proof of transaction intent", as it's a commitment
to a transaction and proof of its validity, but not a proof that an actual
transaction took place, nor a means to prevent it from being double spent.

On Sat, Jun 6, 2015 at 4:35 PM, Kalle Rosenbaum <[email-masked]> wrote:

> Hi
>
> Following earlier posts on Proof of Payment I'm now proposing the
> following BIP (To read it formatted instead, go to
> https://github.com/kallerosenbaum/poppoc/wiki/Proof-of-Payment-BIP).
>
> Regards,
> Kalle Rosenbaum
>
> <pre>
>   BIP: <BIP number>
>   Title: Proof of Payment
>   Author: Kalle Rosenbaum <[email-masked]>
>   Status: Draft
>   Type: Standards Track
>   Created: <date created on, in ISO 8601 (yyyy-mm-dd) format>
> </pre>
>
> == Abstract ==
>
> This BIP describes how a wallet can prove to a server that it has the
> ability to sign a certain transaction.
>
> == Motivation ==
>
> There are several scenarios in which it would be useful to prove that you
> have paid for something. For example:
>
> * A pre-paid hotel room where your PoP functions as a key to the door.
> * An online video rental service where you pay for a video and watch it on
> any device.
> * An ad-sign where you pay in advance for e.g. 2 weeks exclusivity. During
> this period you can upload new content to the sign whenever you like using
> PoP.
> * Log in to a pay site using a PoP.
> * A parking lot you pay for monthly and the car authenticates itself using
> PoP.
> * A lottery where all participants pay to the same address, and the winner
> is selected among the transactions to that address. You exchange the prize
> for a PoP for the winning transaction.
>
> With Proof of Payment, these use cases can be achieved without any
> personal information (user name, password, e-mail address, etc) being
> involved.
>
> == Rationale ==
>
> Desirable properties:
>
> # A PoP should be generated on demand.
> # It should only be usable once to avoid issues due to theft.
> # It should be able to create a PoP for any payment, regardless of script
> type (P2SH, P2PKH, etc.).
> # It should prove that you have enough credentials to unlock all the
> inputs of the proven transaction.
> # It should be easy to implement by wallets and servers to ease adoption.
>
> Current methods of proving a payment:
>
> * In BIP0070, the PaymentRequest together with the transactions fulfilling
> the request makes some sort of proof. However, it does not meet 1, 2 or 4
> and it obviously only meets 3 if the payment is made through BIP0070. Also,
> there's no standard way to request/provide the proof. If standardized it
> would probably meet 5.
> * Signing messages, chosen by the server, with the private keys used to
> sign the transaction. This could meet 1 and 2 but probably not 3. This is
> not standardized either. 4 Could be met if designed so.
>
> If the script type is P2SH, any satisfying script should do, just like for
> a payment. For M-of-N multisig scripts, that would mean that any set of M
> keys should be sufficient, not neccesarily the same set of M keys that
> signed the transaction. This is important because strictly demanding the
> same set of M keys would undermine the purpose of a multisig address.
>
> == Specification ==
>
> === Data structure ===
>
> A proof of payment for a transaction T, here called PoP(T), is used to
> prove that one has ownership of the credentials needed to unlock all the
> inputs of T. It has the exact same structure as a bitcoin transaction with
> the same inputs and outputs as T and in the same order as in T. There is
> also one OP_RETURN output inserted at index 0, here called the pop output.
> This output must have the following format:
>
>  OP_RETURN <version> <txid> <nonce>
>
> {|
> ! Field        !! Size [B] !! Description
> |-
> | &lt;version> || 2        || Version, little endian, currently 0x01 0x00
> |-
> | &lt;txid>    || 32       || The transaction to prove
> |-
> | &lt;nonce>   || 6        || Random data
> |}
>
> The value of the pop output is set to the same value as the transaction
> fee of T. Also, if the outputs of T contains an OP_RETURN output, that
> output must not be included in the PoP because there can only be one
> OP_RETURN output in a transaction. The value of that OP_RETURN output is
> instead added to the value of the pop output.
>
> An illustration of the PoP data structure and its original payment is
> shown below.
>
> <pre>
>   T
>  +----------------------------------------------+
>  |inputs       | outputs                        |
>  |       Value | Value   Script                 |
>  +----------------------------------------------+
>  |input0 1     |     0   pay to A               |
>  |input1 3     |     2   OP_RETURN <some data>  |
>  |input2 4     |     1   pay to B               |
>  |             |     4   pay to C               |
>  +----------------------------------------------+
>
>   PoP(T)
>  +----------------------------------------------------------+
>  |inputs       | outputs                                    |
>  |       Value | Value   Script                             |
>  +----------------------------------------------------------+
>  |input0 1     |     3   OP_RETURN <version> <txid> <nonce> |
>  |input1 3     |     0   pay to A                           |
>  |input2 4     |     1   pay to B                           |
>  |             |     4   pay to C                           |
>  +----------------------------------------------------------+
> </pre>
>
> The PoP is signed using the same signing process that is used for bitcoin
> transactions.
>
> The purpose of the nonce is to make it harder to use a stolen PoP; Once
> the PoP has reached the server, that PoP is useless since the server will
> generate a new nonce for every PoP request.
>
> Since a PoP is indistinguishable from a bitcoin transaction, there is a
> risk that it, accidently or maliciously, enters the bitcoin p2p network. If
> T is still unconfirmed, or if a reorg takes place, chances are that PoP(T)
> ends up in a block, invalidating T. Therefore it is important that the
> outputs of the PoP are the same as in T. The zero transaction fee in PoP(T)
> is to minimize the incentives for miners to select PoP(T) for inclusion.
>
> === Process ===
>
> # A proof of payment request is sent from the server to the wallet. The
> PoP request contains:
> ## a random nonce
> ## a destination where to send the PoP, for example a https URL
> ## data hinting the wallet which transaction to create a proof for. For
> example:
> ##* txid, if known by the server
> ##* PaymentRequest.PaymentDetails.merchant_data (in case of a BIP0070
> payment)
> ##* amount, label, message or other information from a BIP0021 URL
> # The wallet identifies a transaction T, if possible. Otherwise it asks
> the user to select among the ones that match the hints in 1.iii.
> # The wallet creates an unsigned PoP (UPoP) for T, and asks the user to
> sign it.
> # The user confirms
> # The UPoP(T) is signed by the wallet, creating PoP(T).
> # The PoP is sent to the destination in 1.ii.
> # The server receiving the PoP validates it and responds with “valid” or
> “invalid”.
> # The wallet displays the response in some way to the user.
>
> '''Remarks:'''
>
> * The method of transferring the PoP request at step 1 is not specified
> here. Instead that is specified in separate specifications. See [btcpop
> scheme BIP](btcpop scheme BIP).
> * The nonce must be randomly generated by the server for every new PoP
> request.
>
> === Validating a PoP ===
>
> The server needs to validate the PoP and reply with "valid" or "invalid".
> That process is outlined below. If any step fails, the validation is
> aborted and "invalid" is returned:
>
> # Check the format of the PoP. It must pass normal transaction checks,
> except that the inputs may already be spent.
> # Check the PoP output at index 0. It must conform to the OP_RETURN output
> format outlined above.
> # Check that the rest of the outputs exactly corresponds to the outputs of
> T and that they appear in the same order as in T. An exception to this is
> that any OP_RETURN outputs of T must not be included in the PoP. All output
> value from the OP_RETURN must instead be included in the PoP output.
> # Check that the nonce is the same as the one you requested.
> # Check that the inputs of the PoP are exactly the same as in transaction
> T, and in the same order.
> # Check the scripts of all the inputs, as would be done on a normal
> transaction.
> # Check that the txid in the PoP output is the transaction you actually
> want proof for. If you don’t know exactly what transaction you want proof
> for, check that the transaction actually pays for the product/service you
> deliver.
> # Return "valid".
>
> == Security considerations ==
>
> * Someone can intercept the PoP-request and change the PoP destination so
> that the user sends the PoP to the bad actor.
> * Someone can intercept the PoP-request and change for example the txid to
> trick the user to sign a PoP for another transaction than the intended.
> This can of course be avoided if the user is actually looking at the UPoP
> before signing it. The bad actor could also set hints for a transaction,
> existing or not, that the user didn’t make, resulting in a broken service.
> * Someone can steal a PoP and try to use the service hoping to get a
> matching nonce. Probability per try: 1/(2^48). The server should have a
> mechanism for detecting a brute force attack of this kind, or at least slow
> down the process by delaying the PoP request by some 100 ms or so.
> * Even if a wallet has no funds it might still be valuable as a generator
> for PoPs. This makes it important to keep the security of the wallet after
> it has been emptied.
> * Transaction malleability may cause the server to have another
> transaction id than the wallet for the payment. In that case the wallet
> will not be able to prove the transaction for the server. Wallets should
> not rely on the transaction id of the outgoing transaction. Instead it
> should listen for the transaction on the network and put that in its list
> of transactions.
>
> The first two issues are the same attack vector as for traditional, ie
> BIP0021, bitcoin payments. They could be mitigated by using secure
> connections.
>
> == Reference implementation ==
>
> [https://github.com/kallerosenbaum/poppoc poppoc on GitHub]
>
> [https://github.com/kallerosenbaum/wallet Mycelium fork on GitHub]
>
> == References ==
>
> [https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki BIP0021]:
> URI Scheme
>
> [https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki BIP0070]:
> Payment Protocol
>
> [[btcpop scheme BIP]]
>
>
>
> ------------------------------------------------------------------------------
>
> _______________________________________________
> Bitcoin-development mailing list
> [email-masked]
> https://lists.sourceforge.net/lists/listinfo/bitcoin-development
>
>