From 1c9adbbc0bbd7c9cb64822847bd42303e9947e4e Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:12:46 +0200 Subject: [PATCH 1/5] nut10: spending conditions --- 10.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 10.md diff --git a/10.md b/10.md new file mode 100644 index 0000000..6832eeb --- /dev/null +++ b/10.md @@ -0,0 +1,68 @@ +NUT-10: Spending conditions +========================== + +`optional` `author: calle` + +--- + +An ordinary ecash token is a set of `Proofs` each with a random string `secret`. To spend such a token in a [split][06] or a [melt][05] operation, wallets include `proofs` in their request each with a unique `secret`. To autorize a transaction, the mint requires that the `secret` has not been seen before. This is the most fundamental spending condition in Cashu, which ensures that a token can't be double-spent. + +In this NUT, we explain how a `secret` can also encode more complex spending conditions that need to be met before the mint authorizes a transaction. + +## Basic components +An ecash transaction, i.e., a [split][06] or a [melt][05] operation, with a spending condition consists of the following components: + +- inputs referring to the `Proofs` being spent +- `Secret` containing the rules for unlocking a `Proof` +- signatures or additional witness data satisfying the unlock conditions +- outputs referring to the `BlindMessages` with new unlock conditions to which the `Proofs` are spent to + +Spending conditions are defined for each individual `Proof` and not on a transaction level that can consist of multiple `Proofs`. Similarly, spending conditions must be satisfied by providing signatures or additional witness data for each `Proof` separately. For a transaction to be valid, all `Proofs` in that transaction must be unlocked successfully. + +New `Secret`s of the outputs to which the inputs are spent to are provided as `BlindMessages` which means that they are blind-signed and not visible to the mint until they are actually spent. + +## Well-known Secret + +Spending conditions are expressed in a well-known secret format that is revealed to the mint when spending (unlocking) a token, not when the token is minted (locked). The mint parses each `Proof`'s `secret`. If it can deserialize it into the following format, and if all `Proofs` have the same `kind`, it executes additional spending conditions that are further specified below. + +The well-known `Secret` stored in `Proof.secret` is a JSON of the format: + +```json +[ +kind , + { + "nonce": , + "data": , + "tags": [[ "key", "value"], ... ], // (optional) + } +] +``` + +- `kind` is the kind of the spending condition, currently: `P2PK` or `P2SH` +- `nonce` is a unique random string +- `data` expresses the spending condition specific to each kind +- `tags` hold additional data committed to and can be used for feature extensions + +... + +[00]: 00.md +[01]: 01.md +[02]: 02.md +[03]: 03.md +[04]: 04.md +[05]: 05.md +[06]: 06.md +[07]: 07.md +[08]: 08.md +[09]: 09.md +[10]: 10.md +[11]: 11.md +[12]: 12.md +[13]: 13.md +[14]: 14.md +[15]: 15.md +[16]: 16.md +[17]: 17.md +[18]: 18.md +[19]: 19.md +[20]: 20.md \ No newline at end of file From 2480fcb197fa94a3b6534839a5eaa638c2df253a Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:31:18 +0200 Subject: [PATCH 2/5] clean up nut-10 --- 10.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/10.md b/10.md index 6832eeb..321673f 100644 --- a/10.md +++ b/10.md @@ -7,15 +7,17 @@ NUT-10: Spending conditions An ordinary ecash token is a set of `Proofs` each with a random string `secret`. To spend such a token in a [split][06] or a [melt][05] operation, wallets include `proofs` in their request each with a unique `secret`. To autorize a transaction, the mint requires that the `secret` has not been seen before. This is the most fundamental spending condition in Cashu, which ensures that a token can't be double-spent. -In this NUT, we explain how a `secret` can also encode more complex spending conditions that need to be met before the mint authorizes a transaction. +In this NUT, we define a well-known format of `secret` that can be used to express more complex spending conditions. These conditions need to be met before the mint authorizes a transaction. Note that the specific type of spending condition is not part of this document but will be explained in other documents. Here, we describe the structure of `secret` which is expressed as a JSON `Secret` with a specific format. + +Spending conditions are enfored by the mint which means that, upon encountering a `Proof` where `Proof.secret` can be parsed into the well-known format, the mint can require additional conditions to be met. ## Basic components An ecash transaction, i.e., a [split][06] or a [melt][05] operation, with a spending condition consists of the following components: -- inputs referring to the `Proofs` being spent +- Inputs referring to the `Proofs` being spent - `Secret` containing the rules for unlocking a `Proof` -- signatures or additional witness data satisfying the unlock conditions -- outputs referring to the `BlindMessages` with new unlock conditions to which the `Proofs` are spent to +- Signatures or additional witness data satisfying the unlock conditions +- Outputs referring to the `BlindMessages` with new unlock conditions to which the `Proofs` are spent to Spending conditions are defined for each individual `Proof` and not on a transaction level that can consist of multiple `Proofs`. Similarly, spending conditions must be satisfied by providing signatures or additional witness data for each `Proof` separately. For a transaction to be valid, all `Proofs` in that transaction must be unlocked successfully. @@ -33,17 +35,21 @@ kind , { "nonce": , "data": , - "tags": [[ "key", "value"], ... ], // (optional) + "tags": [[ "key", "value1", "value2", ...], ... ], // (optional) } ] ``` -- `kind` is the kind of the spending condition, currently: `P2PK` or `P2SH` +- `kind` is the kind of the spending condition - `nonce` is a unique random string - `data` expresses the spending condition specific to each kind - `tags` hold additional data committed to and can be used for feature extensions -... +## Examples + +Example use cases of this secret format are + +- [NUT-11][11]: Pay-to-Public-Key (P2PK) [00]: 00.md [01]: 01.md From dd3b7960d02401681e1544bac3e95e32118d3502 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 13 Oct 2023 21:14:28 +0200 Subject: [PATCH 3/5] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e0662d..b77b236 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio | [07][07] | Token state check | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns] | [Nutshell][py], [Feni][feni], [LNbits] | [08][08] | Overpaid Lightning fees | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns] | [Nutshell][py], [LNbits] | [09][09] | Mint info | - | [Nutshell][py] -| TBD | Multimint support | [Nutshell][py], [Cashu.Me][cashume], [Nutstash][ns] | N/A +| [10][10] | Spending conditions | [Nutshell][py] | [Nutshell][py] | TBD | DLEQ proofs | - | - | TBD | Bitcoin script | [Nutshell][py] | [Nutshell][py] | TBD | Token version prefixes | - | N/A From 9ac7322b758401b4f3462a5f9dc68cfdfc24bcbe Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 13 Oct 2023 21:17:23 +0200 Subject: [PATCH 4/5] update readme --- README.md | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b77b236..9aab6c2 100644 --- a/README.md +++ b/README.md @@ -12,28 +12,23 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio ### Mandatory | # | Description | Wallets | Mints | |--- | --- | --- | --- | -| [00][00] | Cryptography and Models | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns], [JS][js] | [Nutshell][py], [Feni][feni], [LNbits] -| [01][01] | Mint public keys | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns], [JS][js] | [Nutshell][py], [Feni][feni], [LNbits] -| [02][02] | Keysets and keyset IDs | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns], [JS][js] | [Nutshell][py], [Feni][feni], [LNbits] -| [03][03] | Request minting | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns], [JS][js] | [Nutshell][py], [Feni][feni], [LNbits] -| [04][04] | Minting tokens | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns], [JS][js] | [Nutshell][py], [Feni][feni], [LNbits] -| [05][05] | Melting tokens | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns], [JS][js] | [Nutshell][py], [Feni][feni], [LNbits] -| [06][06] | Splitting tokens | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns], [JS][js] | [Nutshell][py], [Feni][feni], [LNbits] +| [00][00] | Cryptography and Models | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns], [cashu-ts][ts] | [Nutshell][py], [Feni][feni], [LNbits], [Moksha][cashume] +| [01][01] | Mint public keys | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns], [cashu-ts][ts] | [Nutshell][py], [Feni][feni], [LNbits], [Moksha][cashume] +| [02][02] | Keysets and keyset IDs | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns], [cashu-ts][ts] | [Nutshell][py], [Feni][feni], [LNbits], [Moksha][cashume] +| [03][03] | Request minting | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns], [cashu-ts][ts] | [Nutshell][py], [Feni][feni], [LNbits], [Moksha][cashume] +| [04][04] | Minting tokens | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns], [cashu-ts][ts] | [Nutshell][py], [Feni][feni], [LNbits], [Moksha][cashume] +| [05][05] | Melting tokens | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns], [cashu-ts][ts] | [Nutshell][py], [Feni][feni], [LNbits], [Moksha][cashume] +| [06][06] | Splitting tokens | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns], [cashu-ts][ts] | [Nutshell][py], [Feni][feni], [LNbits], [Moksha][cashume] ### Optional | # | Description | Wallets | Mints |--- | --- | --- | --- | -| [07][07] | Token state check | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns] | [Nutshell][py], [Feni][feni], [LNbits] -| [08][08] | Overpaid Lightning fees | [Nutshell][py], [Feni][feni], [Cashu.Me][cashume], [Nutstash][ns] | [Nutshell][py], [LNbits] +| [07][07] | Token state check | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns] | [Nutshell][py], [Feni][feni], [LNbits], [Moksha][cashume] +| [08][08] | Overpaid Lightning fees | [Nutshell][py], [Feni][feni], [Moksha][cashume], [Nutstash][ns], [cashu-ts][ts] | [Nutshell][py], [LNbits], [Moksha][cashume] | [09][09] | Mint info | - | [Nutshell][py] | [10][10] | Spending conditions | [Nutshell][py] | [Nutshell][py] | TBD | DLEQ proofs | - | - -| TBD | Bitcoin script | [Nutshell][py] | [Nutshell][py] -| TBD | Token version prefixes | - | N/A -| TBD | Cashu URI | - | N/A -| TBD | Mint LN swap | [Cashu.Me][cashume], [Nutstash][ns] | N/A -| TBD | Token comment | - | N/A -| TBD | Token sender information | - | N/A + [py]: https://github.com/cashubtc/cashu @@ -41,7 +36,7 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio [lnbits]: https://github.com/lnbits/cashu [cashume]: https://cashu.me [ns]: https://nutstash.app/ -[js]: https://github.com/cashubtc/cashu-js +[ts]: https://github.com/cashubtc/cashu-ts [00]: 00.md [01]: 01.md From a78d8b2242bc30ed885aba1a1d32e6d291cf8d6f Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 13 Oct 2023 21:23:38 +0200 Subject: [PATCH 5/5] clearify --- 10.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/10.md b/10.md index 321673f..57da575 100644 --- a/10.md +++ b/10.md @@ -16,7 +16,7 @@ An ecash transaction, i.e., a [split][06] or a [melt][05] operation, with a spen - Inputs referring to the `Proofs` being spent - `Secret` containing the rules for unlocking a `Proof` -- Signatures or additional witness data satisfying the unlock conditions +- Additional witness data satisfying the unlock conditions such as signatures - Outputs referring to the `BlindMessages` with new unlock conditions to which the `Proofs` are spent to Spending conditions are defined for each individual `Proof` and not on a transaction level that can consist of multiple `Proofs`. Similarly, spending conditions must be satisfied by providing signatures or additional witness data for each `Proof` separately. For a transaction to be valid, all `Proofs` in that transaction must be unlocked successfully. @@ -25,7 +25,7 @@ New `Secret`s of the outputs to which the inputs are spent to are provided as `B ## Well-known Secret -Spending conditions are expressed in a well-known secret format that is revealed to the mint when spending (unlocking) a token, not when the token is minted (locked). The mint parses each `Proof`'s `secret`. If it can deserialize it into the following format, and if all `Proofs` have the same `kind`, it executes additional spending conditions that are further specified below. +Spending conditions are expressed in a well-known secret format that is revealed to the mint when spending (unlocking) a token, not when the token is minted (locked). The mint parses each `Proof`'s `secret`. If it can deserialize it into the following format it executes additional spending conditions that are further specified in additional NUTs. The well-known `Secret` stored in `Proof.secret` is a JSON of the format: