From 74e20846eaa373ab3f6d48a916b69c5dfb69b5e6 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Fri, 9 Oct 2020 16:35:09 +0200 Subject: [PATCH 01/13] initial version of early payment proofs --- text/0000-early-payment-proofs.md | 112 ++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 text/0000-early-payment-proofs.md diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md new file mode 100644 index 0000000..dcf2ffd --- /dev/null +++ b/text/0000-early-payment-proofs.md @@ -0,0 +1,112 @@ + +- Title: early-payment-proofs +- Authors: [John Tromp](mailto:john.tromp@gmail.com) +- Start date: Oct 7, 2020 +- RFC PR: Edit if merged: [mimblewimble/grin-rfcs#0000](https://github.com/mimblewimble/grin-rfcs/pull/0000) +- Tracking issue: [Edit if merged with link to tracking github issue] +--- + +# Summary +[summary]: #summary + +Support generating and validating payment proofs for all transactions, including a timestamp and memo field. + +# Motivation +[motivation]: #motivation + +Payment proofs prevent a payment receiver from claiming they didn't receive payment. +Such fraud prevention is an essential ingredient to commercial adoption. + +Former payment proofs used in Grin didn't apply to invcoice flow, at least not +without additional rounds of communication, which made invoices a difficult proposition. + +They also lacked the ability to specify dating and purpose of payment. + +This RFC changes the transaction building process where payers can require +payees to create a "proof" they've received a payment before the payer +finalizes and broadcasts the transaction. + +# Community-level explanation +[community-level-explanation]: #community-level-explanation + +A payment receiver, in their earliest round of communication to a payment sender, +shall provide a signed statement of the following: +appearance of certain on-chain data satisfying certain conditions +shall constitute payment for a specified purpose. + +This early provision of a payment proof commitment enables its use in all possible transaction building flows. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +## Slate changes + +The slate will include the following payment proof related fields: + +* `sender_address` - An ed25519 public key generated by the sender. +* `receiver_address` - An ed25519 public key for the receiver, typically the public key of the user's v3 onion address. +* `timestamp` - The time at which the receiver generates the payment proof +* `memo` - A string of limited size that may contain additional payment details +* `receiver_signature` - A signature that validates against the `receiver_address` + over a payment message consisting of the following fields: + - receiver public nonce + - receiver public excess + - `sender_address` + - `timestamp` + - amount + - `memo` + +## Generating proofs + +When the receiver generates their nonce and excess, they also generate the receiver signature. + +## Witnessing a Payment Proof + +A payment proof witness is a pair (s,i) satisfying s\*G = R + e\*X, where R is the receiver public nonce, X is the receiver public excess, and e is the hash challenge of the on-chain kernel with MMR index i. +A payment proof consists of a receiver signature together with a corresponding witness. + +## Verifying Proofs + +This `payment_proof` can be provided by the sender at any time to convince a payee that a payment was made to them. +The proof can be verified as follows: + +1. Ensure that the i'th kernel has sufficiently many confirmations. +2. Verify that s\*G = R + e\*X, where e is the hash challenge of the i'th kernel. +3. Verify that the `receiver_signature` is valid. + +## Wallet actions + +### receiver excess generation + +The `receiver_signature` is generated and added to the slate as part of the receive tx-building step. + +### sender partial signing + +Before signing, the sender verifies the receiver signature and checks the payment details. + +# Drawbacks +[drawbacks]: #drawbacks + +* Addition of timestamp and memo increase the size of tx slates. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +# Prior art +[prior-art]: #prior-art + +* Wallet713 implements payment proofs for grinbox transactions, which our design adapts and builds on to work more seemlessly with onion addresses and with transaction building methods that don't inherently rely on addresses. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +* What limit is imposed on the size of the memo field? + +# Future possibilities +[future-possibilities]: #future-possibilities + +# References +[references]: #references + +* [Payment Proofs RFC](https://github.com/mimblewimble/grin-rfcs/blob/master/text/0006-payment-proofs.md) +* Beam's payment proof model: https://github.com/BeamMW/beam/blob/c9beb0eae55fa6b7fb3084ebe9b5db2850cf83b9/wallet/wallet_db.cpp#L3231-L3236 From 58ed05a2891446b1bfae4a6e38c254a60c8cdaf5 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Fri, 9 Oct 2020 18:52:40 +0200 Subject: [PATCH 02/13] minimize slate size --- text/0000-early-payment-proofs.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index dcf2ffd..e8c70ce 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -43,7 +43,6 @@ This early provision of a payment proof commitment enables its use in all possib The slate will include the following payment proof related fields: -* `sender_address` - An ed25519 public key generated by the sender. * `receiver_address` - An ed25519 public key for the receiver, typically the public key of the user's v3 onion address. * `timestamp` - The time at which the receiver generates the payment proof * `memo` - A string of limited size that may contain additional payment details @@ -56,6 +55,10 @@ The slate will include the following payment proof related fields: - amount - `memo` +Note that although included in the signature, the `sender_address` need not be included in the slate, +as both sender and receiver necessarily know it. Slates should only contain the absolute minimum of information +that needs to be relayed to the other party. + ## Generating proofs When the receiver generates their nonce and excess, they also generate the receiver signature. From dafe8ce2532d2eef4b35f4f7b3c980b25c7dbf67 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Sat, 10 Oct 2020 12:27:15 +0200 Subject: [PATCH 03/13] fixes and memo size limit set to 32 bytes --- text/0000-early-payment-proofs.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index e8c70ce..18cbf04 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -17,14 +17,13 @@ Support generating and validating payment proofs for all transactions, including Payment proofs prevent a payment receiver from claiming they didn't receive payment. Such fraud prevention is an essential ingredient to commercial adoption. -Former payment proofs used in Grin didn't apply to invcoice flow, at least not +Former payment proofs used in Grin didn't apply to invoice flow, at least not without additional rounds of communication, which made invoices a difficult proposition. -They also lacked the ability to specify dating and purpose of payment. +They also lacked the ability to specify the time and purpose of payment. -This RFC changes the transaction building process where payers can require -payees to create a "proof" they've received a payment before the payer -finalizes and broadcasts the transaction. +This RFC changes the transaction building process so that +payees commit to a proof of payment before the payer signs for the transaction. # Community-level explanation [community-level-explanation]: #community-level-explanation @@ -45,7 +44,8 @@ The slate will include the following payment proof related fields: * `receiver_address` - An ed25519 public key for the receiver, typically the public key of the user's v3 onion address. * `timestamp` - The time at which the receiver generates the payment proof -* `memo` - A string of limited size that may contain additional payment details +* `memo` - A string of size at most 32 bytes that may contain additional payment details, + or the hash of an arbitrary invoice document * `receiver_signature` - A signature that validates against the `receiver_address` over a payment message consisting of the following fields: - receiver public nonce @@ -103,8 +103,6 @@ Before signing, the sender verifies the receiver signature and checks the paymen # Unresolved questions [unresolved-questions]: #unresolved-questions -* What limit is imposed on the size of the memo field? - # Future possibilities [future-possibilities]: #future-possibilities From 3d426000b1df894f4376ab4147c8a9ba2893e5cc Mon Sep 17 00:00:00 2001 From: John Tromp Date: Sun, 11 Oct 2020 15:35:17 +0200 Subject: [PATCH 04/13] motivate use of index and discuss reorgs --- text/0000-early-payment-proofs.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index 18cbf04..1249f40 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -77,6 +77,15 @@ The proof can be verified as follows: 2. Verify that s\*G = R + e\*X, where e is the hash challenge of the i'th kernel. 3. Verify that the `receiver_signature` is valid. +Step 1. benefits from knowing the kernel index rather than the kernel itself, since nodes don't maintain +an index of all kernels, and looking for the index of a potentially very old kernel is rather expensive. + +## Storing Proofs + +When a wallet stores or exports payment proofs, it should store the kernel as well as its index, +in case the chain suffers a large reorg that relocates the kernel to a different index. + + ## Wallet actions ### receiver excess generation From 317a8b19c4310d348c5a9dd7f6d329efe7932ab6 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Mon, 12 Oct 2020 16:27:58 +0200 Subject: [PATCH 05/13] various proof types --- text/0000-early-payment-proofs.md | 128 +++++++++++++++++++----------- 1 file changed, 81 insertions(+), 47 deletions(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index 1249f40..5ed31fd 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -6,16 +6,16 @@ - Tracking issue: [Edit if merged with link to tracking github issue] --- -# Summary +## Summary [summary]: #summary Support generating and validating payment proofs for all transactions, including a timestamp and memo field. -# Motivation +## Motivation [motivation]: #motivation Payment proofs prevent a payment receiver from claiming they didn't receive payment. -Such fraud prevention is an essential ingredient to commercial adoption. +Such dispute/fraud prevention is an essential ingredient to commercial adoption. Former payment proofs used in Grin didn't apply to invoice flow, at least not without additional rounds of communication, which made invoices a difficult proposition. @@ -23,100 +23,134 @@ without additional rounds of communication, which made invoices a difficult prop They also lacked the ability to specify the time and purpose of payment. This RFC changes the transaction building process so that -payees commit to a proof of payment before the payer signs for the transaction. +payees commit to a proof of payment promise before the payer signs for the transaction. -# Community-level explanation +## Community-level explanation [community-level-explanation]: #community-level-explanation A payment receiver, in their earliest round of communication to a payment sender, -shall provide a signed statement of the following: +shall provide a signature that makes the following promise: appearance of certain on-chain data satisfying certain conditions -shall constitute payment for a specified purpose. +shall prove payment for a specified purpose. -This early provision of a payment proof commitment enables its use in all possible transaction building flows. +This early provision of a payment proof promise enables its use in all possible transaction building flows. -# Reference-level explanation +The first byte of signed data will be used as payment proof type or version (similar to how we encode kernel features). + +## Reference-level explanation [reference-level-explanation]: #reference-level-explanation -## Slate changes +### Payment Proof is a Witnessed Promise + +Since the receiver signature is a promise that payment is proven by +certain on-chain data satisfying certain conditions, we shall call such data a witness, +and let a payment proof consist of a promise paired with a witness. + +### Slate changes -The slate will include the following payment proof related fields: +To accomodate the various proof types, the slate will include the following related fields: * `receiver_address` - An ed25519 public key for the receiver, typically the public key of the user's v3 onion address. * `timestamp` - The time at which the receiver generates the payment proof * `memo` - A string of size at most 32 bytes that may contain additional payment details, or the hash of an arbitrary invoice document -* `receiver_signature` - A signature that validates against the `receiver_address` - over a payment message consisting of the following fields: - - receiver public nonce - - receiver public excess - - `sender_address` - - `timestamp` - - amount - - `memo` +* `promise_signature` - A signature that validates against the `receiver_address` + over a promise message consisting of 1 byte of proof type, followed by type specific data -Note that although included in the signature, the `sender_address` need not be included in the slate, -as both sender and receiver necessarily know it. Slates should only contain the absolute minimum of information +Note that although the sender address is commonly among the signed data, it need not be included in the slate, +as both sender and receiver necessarily know it. Slates should only contain the absolute minimum of information that needs to be relayed to the other party. -## Generating proofs +### Proof type Legacy -When the receiver generates their nonce and excess, they also generate the receiver signature. - -## Witnessing a Payment Proof +These follow the original Payment Proofs RFC in the references. +The signature is over + - proof type `0x00` + - `amount` + - `kernel_commitment` + - `sender_address` -A payment proof witness is a pair (s,i) satisfying s\*G = R + e\*X, where R is the receiver public nonce, X is the receiver public excess, and e is the hash challenge of the on-chain kernel with MMR index i. -A payment proof consists of a receiver signature together with a corresponding witness. +The witness is an on-chain kernel with the given commitment. +The proof type is actually the most significant byte of the amount field, +which is necessarily 0 in the foreseeable future. +The amount field is therefore limited to 7 bytes. -## Verifying Proofs +### Proof type Invoice -This `payment_proof` can be provided by the sender at any time to convince a payee that a payment was made to them. -The proof can be verified as follows: +This will be the type for regular invoices, where receiver specifies the time, amount and purpose of payment. +The signature is over + - proof type `0x01` + - `amount` + - receiver public nonce + - receiver public excess + - `sender_address` + - `timestamp` + - `memo` -1. Ensure that the i'th kernel has sufficiently many confirmations. -2. Verify that s\*G = R + e\*X, where e is the hash challenge of the i'th kernel. -3. Verify that the `receiver_signature` is valid. +For consistency with the old proof type, the amount is again limited to 7 bytes. +The witness is a triple (s,i,C) where i is the MMR index of an on-chain kernel K with commitment C, +satisfying s\*G = R + e\*X, where R is the receiver public nonce, X is the receiver public excess, +and e is the hash challenge of kernel K. +The reason for including the kernel index is that nodes don't maintain +an index of all kernels, and looking for the index of a potentially very old kernel is rather expensive, +and proof verification should not be a DoS vector. +The reason for including the kernel commitment is so that the prover can recompute the index +when necessitated by chain reorgs. -Step 1. benefits from knowing the kernel index rather than the kernel itself, since nodes don't maintain -an index of all kernels, and looking for the index of a potentially very old kernel is rather expensive. +### Proof type SenderNonce -## Storing Proofs +This will be the type for indeterminate invoices, where sender commits by nonce to the time, amount and purpose of payment. +This roughly follows the payment proofs in David Burkett's Eliminate Finalize Step RFC (see References). -When a wallet stores or exports payment proofs, it should store the kernel as well as its index, -in case the chain suffers a large reorg that relocates the kernel to a different index. +The signature is over + - proof type `0x02` + - 7 zero bytes + - receiver public nonce + - receiver public excess + - `sender_address` +The witness is a triple (s,i,C,m) where i is the MMR index of an on-chain kernel K with commitment C, +satisfying s\*G = R + e\*X, where R is the receiver public nonce, X is the receiver public excess, +and e is the hash challenge of kernel K. +Additionally, the sender nonce Rs, computed as the difference between kernel nonce and receiver public nonce, +must be of the form Rs' + H(Rs' | m) \* G, where message m contains the promise fields + - proof type `0x02` + - `amount` + - `timestamp` + - `memo` -## Wallet actions +### Wallet actions -### receiver excess generation +#### receiver excess generation The `receiver_signature` is generated and added to the slate as part of the receive tx-building step. -### sender partial signing +#### sender partial signing Before signing, the sender verifies the receiver signature and checks the payment details. -# Drawbacks +## Drawbacks [drawbacks]: #drawbacks * Addition of timestamp and memo increase the size of tx slates. -# Rationale and alternatives +## Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives -# Prior art +## Prior art [prior-art]: #prior-art * Wallet713 implements payment proofs for grinbox transactions, which our design adapts and builds on to work more seemlessly with onion addresses and with transaction building methods that don't inherently rely on addresses. -# Unresolved questions +## Unresolved questions [unresolved-questions]: #unresolved-questions -# Future possibilities +## Future possibilities [future-possibilities]: #future-possibilities -# References +## References [references]: #references * [Payment Proofs RFC](https://github.com/mimblewimble/grin-rfcs/blob/master/text/0006-payment-proofs.md) * Beam's payment proof model: https://github.com/BeamMW/beam/blob/c9beb0eae55fa6b7fb3084ebe9b5db2850cf83b9/wallet/wallet_db.cpp#L3231-L3236 +* [Eliminate Finalize Step RFC](https://github.com/DavidBurkett/grin-rfcs/blob/eliminate_finalize/text/0000-eliminate-finalize.md) From b9768047ad679ccc42667fa950d39a80f0784e9c Mon Sep 17 00:00:00 2001 From: John Tromp Date: Mon, 12 Oct 2020 23:54:04 +0200 Subject: [PATCH 06/13] small fixes --- text/0000-early-payment-proofs.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index 5ed31fd..1722f52 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -35,6 +35,9 @@ shall prove payment for a specified purpose. This early provision of a payment proof promise enables its use in all possible transaction building flows. +Ta avoid confusion, the invoice flow shall be called receiver-sender-receiver (RSR) flow and +the "regular" flow shall be called sender-receiver-sender (SRS) flow. + The first byte of signed data will be used as payment proof type or version (similar to how we encode kernel features). ## Reference-level explanation @@ -42,7 +45,7 @@ The first byte of signed data will be used as payment proof type or version (sim ### Payment Proof is a Witnessed Promise -Since the receiver signature is a promise that payment is proven by +Since the receiver signature is a promise that payment will be considered proven by certain on-chain data satisfying certain conditions, we shall call such data a witness, and let a payment proof consist of a promise paired with a witness. @@ -73,7 +76,7 @@ The signature is over The witness is an on-chain kernel with the given commitment. The proof type is actually the most significant byte of the amount field, which is necessarily 0 in the foreseeable future. -The amount field is therefore limited to 7 bytes. +The amount field is accordingly limited to 7 bytes. ### Proof type Invoice @@ -86,6 +89,9 @@ The signature is over - `sender_address` - `timestamp` - `memo` +The receiver will sign this data either in the first round of RSR flow, or the second round of SRS flow. +In the latter case, the sender can use the slate fields `amount` and `memo` to set suggested values for +the receiver to use. The `timestamp` should correspong to the time of signature generation. For consistency with the old proof type, the amount is again limited to 7 bytes. The witness is a triple (s,i,C) where i is the MMR index of an on-chain kernel K with commitment C, @@ -108,8 +114,11 @@ The signature is over - receiver public nonce - receiver public excess - `sender_address` +The receiver will sign this data in the first round of RSR flow, leaving the +sender to commit to remaining payment details in their following step. +There is no need for this proof type in SRS flow, as the simpler Invoice type suffices. -The witness is a triple (s,i,C,m) where i is the MMR index of an on-chain kernel K with commitment C, +The witness is a quadruple (s,i,C,m) where i is the MMR index of an on-chain kernel K with commitment C, satisfying s\*G = R + e\*X, where R is the receiver public nonce, X is the receiver public excess, and e is the hash challenge of kernel K. Additionally, the sender nonce Rs, computed as the difference between kernel nonce and receiver public nonce, From e0b8661031b9d2205b3de596bb02e73d62f67c31 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Tue, 13 Oct 2020 00:54:34 +0200 Subject: [PATCH 07/13] add Rs' to witness --- text/0000-early-payment-proofs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index 1722f52..e41c5d5 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -118,7 +118,7 @@ The receiver will sign this data in the first round of RSR flow, leaving the sender to commit to remaining payment details in their following step. There is no need for this proof type in SRS flow, as the simpler Invoice type suffices. -The witness is a quadruple (s,i,C,m) where i is the MMR index of an on-chain kernel K with commitment C, +The witness is a quintuple (s,i,C,Rs',m) where i is the MMR index of an on-chain kernel K with commitment C, satisfying s\*G = R + e\*X, where R is the receiver public nonce, X is the receiver public excess, and e is the hash challenge of kernel K. Additionally, the sender nonce Rs, computed as the difference between kernel nonce and receiver public nonce, From 741a17f1e6c5dc73aa96587aa667d8b96370b62a Mon Sep 17 00:00:00 2001 From: John Tromp Date: Sun, 27 Dec 2020 14:17:32 +0100 Subject: [PATCH 08/13] fix typos --- text/0000-early-payment-proofs.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index e41c5d5..e6c228b 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -35,7 +35,7 @@ shall prove payment for a specified purpose. This early provision of a payment proof promise enables its use in all possible transaction building flows. -Ta avoid confusion, the invoice flow shall be called receiver-sender-receiver (RSR) flow and +To avoid confusion, the invoice flow shall be called receiver-sender-receiver (RSR) flow and the "regular" flow shall be called sender-receiver-sender (SRS) flow. The first byte of signed data will be used as payment proof type or version (similar to how we encode kernel features). @@ -89,9 +89,10 @@ The signature is over - `sender_address` - `timestamp` - `memo` + The receiver will sign this data either in the first round of RSR flow, or the second round of SRS flow. In the latter case, the sender can use the slate fields `amount` and `memo` to set suggested values for -the receiver to use. The `timestamp` should correspong to the time of signature generation. +the receiver to use. The `timestamp` should correspond to the time of signature generation. For consistency with the old proof type, the amount is again limited to 7 bytes. The witness is a triple (s,i,C) where i is the MMR index of an on-chain kernel K with commitment C, @@ -114,6 +115,7 @@ The signature is over - receiver public nonce - receiver public excess - `sender_address` + The receiver will sign this data in the first round of RSR flow, leaving the sender to commit to remaining payment details in their following step. There is no need for this proof type in SRS flow, as the simpler Invoice type suffices. From 9c1f0f60a7e2992fe346ab8a34dfa906daa3f373 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Thu, 21 Jan 2021 18:16:23 +0100 Subject: [PATCH 09/13] minor reformatting --- text/0000-early-payment-proofs.md | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index e6c228b..c07d23d 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -54,15 +54,13 @@ and let a payment proof consist of a promise paired with a witness. To accomodate the various proof types, the slate will include the following related fields: * `receiver_address` - An ed25519 public key for the receiver, typically the public key of the user's v3 onion address. -* `timestamp` - The time at which the receiver generates the payment proof +* `timestamp` - The time at which the receiver generates the payment promise * `memo` - A string of size at most 32 bytes that may contain additional payment details, or the hash of an arbitrary invoice document * `promise_signature` - A signature that validates against the `receiver_address` over a promise message consisting of 1 byte of proof type, followed by type specific data -Note that although the sender address is commonly among the signed data, it need not be included in the slate, -as both sender and receiver necessarily know it. Slates should only contain the absolute minimum of information -that needs to be relayed to the other party. +Note that although the sender address is commonly among the signed data, it need not be included in an slate that's encrypted for the sender, as both sender and receiver necessarily know it. Slates should only contain the absolute minimum of information that needs to be relayed to the other party. ### Proof type Legacy @@ -80,26 +78,20 @@ The amount field is accordingly limited to 7 bytes. ### Proof type Invoice -This will be the type for regular invoices, where receiver specifies the time, amount and purpose of payment. -The signature is over +This will be the type for regular invoices, where receiver specifies the time, amount and purpose of payment. The signature is over - proof type `0x01` - `amount` - - receiver public nonce - - receiver public excess + - `receiver_public_nonce` + - `receiver_public_excess` - `sender_address` - `timestamp` - `memo` -The receiver will sign this data either in the first round of RSR flow, or the second round of SRS flow. -In the latter case, the sender can use the slate fields `amount` and `memo` to set suggested values for -the receiver to use. The `timestamp` should correspond to the time of signature generation. +The receiver will sign this data either in the first round of RSR flow, or the second round of SRS flow. In the latter case, the sender can use the slate fields `amount` and `memo` to set suggested values for the receiver to use. The `timestamp` should correspond to the time of signature generation. For consistency with the old proof type, the amount is again limited to 7 bytes. -The witness is a triple (s,i,C) where i is the MMR index of an on-chain kernel K with commitment C, -satisfying s\*G = R + e\*X, where R is the receiver public nonce, X is the receiver public excess, -and e is the hash challenge of kernel K. -The reason for including the kernel index is that nodes don't maintain -an index of all kernels, and looking for the index of a potentially very old kernel is rather expensive, +The witness is a triple (s,i,C) where i is the MMR index of an on-chain kernel K with commitment C, satisfying s\*G = R + e\*X, where R is the `receiver_public_nonce`, X is the `receiver_public_excess`, and e is the hash challenge of kernel K. +The reason for including the kernel index is that nodes don't maintain an index of all kernels, and looking for the index of a potentially very old kernel is rather expensive, and proof verification should not be a DoS vector. The reason for including the kernel commitment is so that the prover can recompute the index when necessitated by chain reorgs. @@ -112,16 +104,15 @@ This roughly follows the payment proofs in David Burkett's Eliminate Finalize St The signature is over - proof type `0x02` - 7 zero bytes - - receiver public nonce - - receiver public excess + - `receiver_public_nonce` + - `receiver_public_excess` - `sender_address` The receiver will sign this data in the first round of RSR flow, leaving the sender to commit to remaining payment details in their following step. There is no need for this proof type in SRS flow, as the simpler Invoice type suffices. -The witness is a quintuple (s,i,C,Rs',m) where i is the MMR index of an on-chain kernel K with commitment C, -satisfying s\*G = R + e\*X, where R is the receiver public nonce, X is the receiver public excess, +The witness is a quintuple (s,i,C,Rs',m) where i is the MMR index of an on-chain kernel K with commitment C, satisfying s\*G = R + e\*X, where R is the `receiver_public_nonce`, X is the `receiver_public_excess`, and e is the hash challenge of kernel K. and e is the hash challenge of kernel K. Additionally, the sender nonce Rs, computed as the difference between kernel nonce and receiver public nonce, must be of the form Rs' + H(Rs' | m) \* G, where message m contains the promise fields From 9b2700cad6ddd96544c75db3f503dda9876b0772 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Mon, 16 Aug 2021 14:48:51 +0200 Subject: [PATCH 10/13] fix typo and ponder alternative pay/sign-to-contract scheme --- text/0000-early-payment-proofs.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index c07d23d..dabf622 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -93,8 +93,7 @@ For consistency with the old proof type, the amount is again limited to 7 bytes. The witness is a triple (s,i,C) where i is the MMR index of an on-chain kernel K with commitment C, satisfying s\*G = R + e\*X, where R is the `receiver_public_nonce`, X is the `receiver_public_excess`, and e is the hash challenge of kernel K. The reason for including the kernel index is that nodes don't maintain an index of all kernels, and looking for the index of a potentially very old kernel is rather expensive, and proof verification should not be a DoS vector. -The reason for including the kernel commitment is so that the prover can recompute the index -when necessitated by chain reorgs. +The reason for including the kernel commitment is so that the prover can recompute the index when necessitated by chain reorgs. ### Proof type SenderNonce @@ -113,7 +112,6 @@ sender to commit to remaining payment details in their following step. There is no need for this proof type in SRS flow, as the simpler Invoice type suffices. The witness is a quintuple (s,i,C,Rs',m) where i is the MMR index of an on-chain kernel K with commitment C, satisfying s\*G = R + e\*X, where R is the `receiver_public_nonce`, X is the `receiver_public_excess`, and e is the hash challenge of kernel K. -and e is the hash challenge of kernel K. Additionally, the sender nonce Rs, computed as the difference between kernel nonce and receiver public nonce, must be of the form Rs' + H(Rs' | m) \* G, where message m contains the promise fields - proof type `0x02` @@ -121,6 +119,8 @@ must be of the form Rs' + H(Rs' | m) \* G, where message m contains the promise - `timestamp` - `memo` +This is similar to the Sign-to-Contract notion discussed in the last reference. + ### Wallet actions #### receiver excess generation @@ -139,6 +139,15 @@ Before signing, the sender verifies the receiver signature and checks the paymen ## Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives +A possible alternative that more fully embraces Pay/Sign-to-Contract +is to combine a promise and contract in the kernel commitment and/or nonce. +For generality, let's explain the case of using both. In practice, using only one may make more sense or be more secure. + +Let P = P^A + P^B be the sum of the parties' public kernel contributions, let P' = P + H(P|PC) * G be the kernel public key that additionally commits to some data PC. +let R = R^A + R^B be the sum of the parties' nonce, let R' = R + H(R|RC) * G be the kernel public nonce that additionally commits to some data RC. +Let e = H(P' | R' | m) be the kernel hash challenge, s^A = k^A + e * x^A and s^B = k^B + e * x^B be the parties' partial signatures made under agreement with PC and RC, then (s^A + s^B + H(R|RC) + e * H(P|PC), R') is a valid signature for kernel commitment P'. +Now we have various choices of commiting to the receiver promise signature and contract in PC and/or RC. The construction can obviously be simplified when only using one of them. + ## Prior art [prior-art]: #prior-art @@ -156,3 +165,4 @@ Before signing, the sender verifies the receiver signature and checks the paymen * [Payment Proofs RFC](https://github.com/mimblewimble/grin-rfcs/blob/master/text/0006-payment-proofs.md) * Beam's payment proof model: https://github.com/BeamMW/beam/blob/c9beb0eae55fa6b7fb3084ebe9b5db2850cf83b9/wallet/wallet_db.cpp#L3231-L3236 * [Eliminate Finalize Step RFC](https://github.com/DavidBurkett/grin-rfcs/blob/eliminate_finalize/text/0000-eliminate-finalize.md) +* [Pay-to-contract and Sign-to-contract](https://www.reddit.com/r/Bitcoin/comments/d3lffo/technical_paytocontract_and_signtocontract/) From 74b29ff4aa5a85a447f3e0d3f0006a0efbf141f9 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Mon, 16 Aug 2021 16:21:45 +0200 Subject: [PATCH 11/13] retract flawed alternative --- text/0000-early-payment-proofs.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index dabf622..20a1596 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -139,15 +139,6 @@ Before signing, the sender verifies the receiver signature and checks the paymen ## Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives -A possible alternative that more fully embraces Pay/Sign-to-Contract -is to combine a promise and contract in the kernel commitment and/or nonce. -For generality, let's explain the case of using both. In practice, using only one may make more sense or be more secure. - -Let P = P^A + P^B be the sum of the parties' public kernel contributions, let P' = P + H(P|PC) * G be the kernel public key that additionally commits to some data PC. -let R = R^A + R^B be the sum of the parties' nonce, let R' = R + H(R|RC) * G be the kernel public nonce that additionally commits to some data RC. -Let e = H(P' | R' | m) be the kernel hash challenge, s^A = k^A + e * x^A and s^B = k^B + e * x^B be the parties' partial signatures made under agreement with PC and RC, then (s^A + s^B + H(R|RC) + e * H(P|PC), R') is a valid signature for kernel commitment P'. -Now we have various choices of commiting to the receiver promise signature and contract in PC and/or RC. The construction can obviously be simplified when only using one of them. - ## Prior art [prior-art]: #prior-art From cbeea07eecde3b34a521b287a5b5f9227dcabea0 Mon Sep 17 00:00:00 2001 From: John Tromp Date: Mon, 16 Aug 2021 19:07:41 +0200 Subject: [PATCH 12/13] possible tiny simplification --- text/0000-early-payment-proofs.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index 20a1596..66de349 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -139,6 +139,11 @@ Before signing, the sender verifies the receiver signature and checks the paymen ## Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives +In the SenderNonce proof type, instead of requiring the sender nonce to +commit to message m, we can require the kernel nonce to do so, which avoids +the need for a proof verifier to subtract the receiver public nonce from the +kernel nonce. + ## Prior art [prior-art]: #prior-art From 6ecef31abd9f20c4bcb713fe8bd786df7ea01e7d Mon Sep 17 00:00:00 2001 From: John Tromp Date: Wed, 26 Apr 2023 14:11:05 +0200 Subject: [PATCH 13/13] add details for RSR flow with invoice proof type --- text/0000-early-payment-proofs.md | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/text/0000-early-payment-proofs.md b/text/0000-early-payment-proofs.md index 66de349..707e26e 100644 --- a/text/0000-early-payment-proofs.md +++ b/text/0000-early-payment-proofs.md @@ -55,8 +55,9 @@ To accomodate the various proof types, the slate will include the following rela * `receiver_address` - An ed25519 public key for the receiver, typically the public key of the user's v3 onion address. * `timestamp` - The time at which the receiver generates the payment promise -* `memo` - A string of size at most 32 bytes that may contain additional payment details, - or the hash of an arbitrary invoice document +* `memo` - A string of size at most 1024 bytes that contains payment details, + such as a description of the good(s) or service(s) being bought. + `memohash` denotes the 32 byte blake2b hash of this field. * `promise_signature` - A signature that validates against the `receiver_address` over a promise message consisting of 1 byte of proof type, followed by type specific data @@ -85,7 +86,7 @@ This will be the type for regular invoices, where receiver specifies the time, a - `receiver_public_excess` - `sender_address` - `timestamp` - - `memo` + - `memohash` The receiver will sign this data either in the first round of RSR flow, or the second round of SRS flow. In the latter case, the sender can use the slate fields `amount` and `memo` to set suggested values for the receiver to use. The `timestamp` should correspond to the time of signature generation. @@ -95,6 +96,26 @@ The reason for including the kernel index is that nodes don't maintain an index and proof verification should not be a DoS vector. The reason for including the kernel commitment is so that the prover can recompute the index when necessitated by chain reorgs. +The specific steps in RSR flow are + +Receiver fills in memo field and computes memohash. Receiver computes ed25519 signature over the message + 0x01 | amount | `receiver_public_nonce` | `receiver_public_excess` | `sender_address` | `timestamp` | `memohash` +and sets this as slate field `promise_signature`. + +Upon receiving the slate, the Sender composes the same message from the various +slate fields and check the signature against the Receiver public ed25519 key. +The Sender inspects all payment details including the memo and presumably +agrees to proceed with payment. They save the partial signature sS of the +kernel they sign along with the kernel commitment and promise signature, and +send back the slate to the reciever for countersigning. + +When the Sender wants to prove payment, they find the kernel with commitment C +on chain and compute sR = s - sS to recover the receiver partial signature sR +that will satisfy the payment proof condition. + +Sender can convince any 3rd party of the payment to Receiver by providing both +the promise signature (including the memo and all message fields) and the witness. + ### Proof type SenderNonce This will be the type for indeterminate invoices, where sender commits by nonce to the time, amount and purpose of payment. @@ -117,7 +138,7 @@ must be of the form Rs' + H(Rs' | m) \* G, where message m contains the promise - proof type `0x02` - `amount` - `timestamp` - - `memo` + - `memohash` This is similar to the Sign-to-Contract notion discussed in the last reference.