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

NUT-10: Spending conditions #50

Merged
merged 5 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
74 changes: 74 additions & 0 deletions 10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
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 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
- `Secret` containing the rules for unlocking a `Proof`
- 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.

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 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:

```json
[
kind <str>,
{
"nonce": <str>,
"data": <str>,
"tags": [[ "key", "value1", "value2", ...], ... ], // (optional)
}
]
```

- `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
[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
29 changes: 12 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,31 @@ 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]
| 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
| 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
[feni]: https://github.com/cashubtc/cashu-feni
[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
Expand Down