From f52ba1e657be1b4b70db10ce3ccba2ea63a178e6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 29 Aug 2024 17:08:53 +0200 Subject: [PATCH 01/27] README: add minibits, fix nutshell link (#154) --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 910b52a4..14c64ac9 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio - [cdk][cdk] - [cashu-ts][ts] - [eNuts][enuts] + - [Minibits][minibits] - [Moksha][moksha] - [Nutstash][ns] - [Cashu.me][cashume] @@ -54,12 +55,13 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio - [Nutmix][nutmix] -[py]: https://github.com/cashubtc/cashu +[py]: https://github.com/cashubtc/nutshell [lnbits]: https://github.com/lnbits/cashu [cashume]: https://cashu.me [ns]: https://nutstash.app/ [ts]: https://github.com/cashubtc/cashu-ts [enuts]: https://github.com/cashubtc/eNuts +[minibits]: https://github.com/minibits-cash/minibits_wallet [moksha]: https://github.com/ngutech21/moksha [cdk]: https://github.com/cashubtc/cdk [cashu-rs-mint]: https://github.com/thesimplekid/cashu-rs-mint From 2276462075573e26f223e8c8d575bc68d9188b39 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Thu, 29 Aug 2024 16:09:10 +0100 Subject: [PATCH 02/27] update cdk mint (#152) --- README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 14c64ac9..0099500e 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,14 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio | # | Description | Wallets | Mints | | --- | --- | --- | --- | -| [07][07] | Token state check | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk] | [Nutshell][py], [Moksha][moksha], [cashu-rs-mint][cashu-rs-mint] | -| [08][08] | Overpaid Lightning fees | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk] | [Nutshell][py], [Moksha][moksha], [cashu-rs-mint][cashu-rs-mint] | -| [09][09] | Signature restore | [Nutshell][py], [cdk], [cashu-ts][ts], [gonuts] | [Nutshell][py], [cashu-rs-mint][cashu-rs-mint] -| [10][10] | Spending conditions | [Nutshell][py], [cdk], [cashu-ts][ts] | [Nutshell][py], [cashu-rs-mint], [nutmix] | -| [11][11] | Pay-To-Pubkey (P2PK) | [Nutshell][py], [cdk], [cashu-ts][ts] | [Nutshell][py], [cashu-rs-mint], [nutmix] | -| [12][12] | DLEQ proofs | [Nutshell][py], [cdk] | [Nutshell][py], [cashu-rs-mint] | -| [13][13] | Deterministic secrets | [Nutshell][py], [Moksha][moksha], [cashu-ts][ts], [cdk], [gonuts] | - | -| [14][14] | Hashed Timelock Contracts (HTLCs) | [Nutshell][py], [cdk] | [Nutshell][py], [cashu-rs-mint] | +| [07][07] | Token state check | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd] | +| [08][08] | Overpaid Lightning fees | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd] | +| [09][09] | Signature restore | [Nutshell][py], [cdk-cli], [cashu-ts][ts], [gonuts] | [Nutshell][py], [cdk-mintd] +| [10][10] | Spending conditions | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [11][11] | Pay-To-Pubkey (P2PK) | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [12][12] | DLEQ proofs | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd] | +| [13][13] | Deterministic secrets | [Nutshell][py], [Moksha][moksha], [cashu-ts][ts], [cdk-cli], [gonuts] | - | +| [14][14] | Hashed Timelock Contracts (HTLCs) | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd] | | [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py] | | [16][16] | Animated QR codes | [Cashu.me][cashume] | - | | [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] | @@ -36,7 +36,7 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio #### Wallets: - [Nutshell][py] - - [cdk][cdk] + - [cdk-cli][cdk-cli] - [cashu-ts][ts] - [eNuts][enuts] - [Minibits][minibits] @@ -51,7 +51,7 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio - [Nutshell][py] - [Gonuts][gonuts] - [Moksha][moksha] - - [cashu-rs-mint][cashu-rs-mint] + - [cdk-mintd][cdk-mintd] - [Nutmix][nutmix] @@ -64,7 +64,8 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio [minibits]: https://github.com/minibits-cash/minibits_wallet [moksha]: https://github.com/ngutech21/moksha [cdk]: https://github.com/cashubtc/cdk -[cashu-rs-mint]: https://github.com/thesimplekid/cashu-rs-mint +[cdk-cli]: https://github.com/cashubtc/cdk/tree/main/crates/cdk-cli +[cdk-mintd]: https://github.com/cashubtc/cdk/tree/main/crates/cdk-mintd [gonuts]: https://github.com/elnosh/gonuts [nutmix]: https://github.com/lescuer97/nutmix [bwc]: https://github.com/MakePrisms/boardwalkcash From 78ed24c9cc121595b91632b8fe2b9c8acd1a88f2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 2 Sep 2024 11:05:10 +0200 Subject: [PATCH 03/27] chore: run prettier on all files (#156) * chore: run prettier on all files * ci: add prettier check --- .github/workflows/prettier.yml | 22 +++++++++ 00.md | 39 ++++++++-------- 01.md | 9 ++-- 02.md | 5 +- 03.md | 12 ++--- 04.md | 53 ++++++++++++---------- 05.md | 28 +++++++----- 06.md | 15 +++--- 07.md | 23 +++++----- 08.md | 15 +++--- 09.md | 7 ++- 10.md | 10 ++-- 11.md | 56 ++++++++++------------- 12.md | 17 ++++--- 13.md | 31 +++++++------ 14.md | 14 +++--- 15.md | 8 ++-- 16.md | 10 ++-- 17.md | 67 +++++++++++++++++++++------ README.md | 79 ++++++++++++++++---------------- tests/00-tests.md | 16 ++++++- tests/01-tests.md | 83 ++++++++++++++++++++++++++++++++-- tests/02-tests.md | 72 ++++++++++++++++++++++++++++- tests/11-test.md | 54 +++++++++++++++++++--- tests/12-tests.md | 1 + tests/13-tests.md | 42 ++++++++--------- tests/README.md | 1 + 27 files changed, 529 insertions(+), 260 deletions(-) create mode 100644 .github/workflows/prettier.yml diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml new file mode 100644 index 00000000..27656ffd --- /dev/null +++ b/.github/workflows/prettier.yml @@ -0,0 +1,22 @@ +name: prettier + +on: [push, pull_request] + +jobs: + prettier: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install dependencies + run: npm install -g prettier + + - name: Run Prettier check + run: npx prettier --check . diff --git a/00.md b/00.md index 6c38c531..c4d714bd 100644 --- a/00.md +++ b/00.md @@ -1,5 +1,4 @@ -NUT-00: Notation, Utilization, and Terminology -========================== +# NUT-00: Notation, Utilization, and Terminology `mandatory` @@ -11,8 +10,6 @@ This document details the notation and models used throughout the specification - Receiving user: `Carol` - Mint: `Bob` - - # Blind Diffie-Hellmann key exchange (BDHKE) ## Variables @@ -37,6 +34,7 @@ This document details the notation and models used throughout the specification Deterministically maps a message to a public key point on the secp256k1 curve, utilizing a domain separator to ensure uniqueness. `Y = PublicKey('02' || SHA256(msg_hash || counter))` where `msg_hash` is `SHA256(DOMAIN_SEPARATOR || x)` + - `Y` derived public key - `DOMAIN_SEPARATOR` constant byte string `b"Secp256k1_HashToCurve_Cashu_"` - `x` message to hash @@ -44,13 +42,13 @@ Deterministically maps a message to a public key point on the secp256k1 curve, u ## Protocol -- Mint `Bob` publishes public key `K = kG` +- Mint `Bob` publishes public key `K = kG` - `Alice` picks secret `x` and computes `Y = hash_to_curve(x)` - `Alice` sends to `Bob`: `B_ = Y + rG` with `r` being a random blinding factor (**blinding**) - `Bob` sends back to `Alice` blinded key: `C_ = kB_` (these two steps are the DH key exchange) (**signing**) - `Alice` can calculate the unblinded key as `C_ - rK = kY + krG - krG = kY = C` (**unblinding**) - Alice can take the pair `(x, C)` as a token and can send it to `Carol`. -- `Carol` can send `(x, C)` to `Bob` who then checks that `k*hash_to_curve(x) == C` (**verification**), and if so treats it as a valid spend of a token, adding `x` to the list of spent secrets. +- `Carol` can send `(x, C)` to `Bob` who then checks that `k*hash_to_curve(x) == C` (**verification**), and if so treats it as a valid spend of a token, adding `x` to the list of spent secrets. ## 0.1 - Models @@ -66,7 +64,7 @@ An encrypted ("blinded") secret and an amount is sent from `Alice` to `Bob` for } ``` - `amount` is the value for the requested `BlindSignature`, `id` is the requested keyset ID from which we expect a signature, and `B_` is the blinded secret message generated by `Alice`. An array `[BlindedMessage]` is also referred to as `BlindedMessages`. +`amount` is the value for the requested `BlindSignature`, `id` is the requested keyset ID from which we expect a signature, and `B_` is the blinded secret message generated by `Alice`. An array `[BlindedMessage]` is also referred to as `BlindedMessages`. ### `BlindSignature` @@ -84,11 +82,11 @@ A `BlindSignature` is sent from `Bob` to `Alice` after [minting tokens][04] or a ### `Proof` -A `Proof` is also called an input and is generated by `Alice` from a `BlindSignature` it received. An array `[Proof]` is called `Proofs`. `Alice` sends `Proofs` to `Bob` for [melting tokens][05]. [Serialized](#serialization-of-tokens) `Proofs` can also be sent from `Alice` to `Carol`. Upon receiving the token, `Carol` deserializes it and requests a [swap][03] from `Bob` to receive new `Proofs`. +A `Proof` is also called an input and is generated by `Alice` from a `BlindSignature` it received. An array `[Proof]` is called `Proofs`. `Alice` sends `Proofs` to `Bob` for [melting tokens][05]. [Serialized](#serialization-of-tokens) `Proofs` can also be sent from `Alice` to `Carol`. Upon receiving the token, `Carol` deserializes it and requests a [swap][03] from `Bob` to receive new `Proofs`. ```json { - "amount": int, + "amount": int, "id": hex_str, "secret": str, "C": hex_str, @@ -100,6 +98,7 @@ A `Proof` is also called an input and is generated by `Alice` from a `BlindSigna ## 0.2 - Protocol ### Errors + In case of an error, mints respond with the HTTP status code `400` and include the following data in their response: ```json @@ -108,6 +107,7 @@ In case of an error, mints respond with the HTTP status code `400` and include t "code": 1337 } ``` + Here, `detail` is the error message, and `code` is the error code. Error codes are to be defined in the documents concerning the use of a certain API endpoint. ## 0.3 - Methods @@ -134,9 +134,10 @@ cashu:cashuAeyJwcm9vZn... ### V3 tokens -> *V3 tokens are deprecated and the use of the more space-efficient V4 tokens is encouraged.* +> _V3 tokens are deprecated and the use of the more space-efficient V4 tokens is encouraged._ ##### Version + This token format has the `[version]` value `A`. ##### Format @@ -166,12 +167,12 @@ The deserialized `base64_token_json` is "memo": str } ``` -`mint` is the mint URL. The mint URL must be stripped of any trailing slashes (`/`). `Proofs` is an array of `Proof` objects. The next two elements are only for displaying the receiving user appropriate information: `unit` is the currency unit of the token keysets (see [Keysets][01] for supported units), and `memo` is an optional text memo from the sender. +`mint` is the mint URL. The mint URL must be stripped of any trailing slashes (`/`). `Proofs` is an array of `Proof` objects. The next two elements are only for displaying the receiving user appropriate information: `unit` is the currency unit of the token keysets (see [Keysets][01] for supported units), and `memo` is an optional text memo from the sender. ##### Example -Below is a TokenV3 JSON before `base64_urlsafe` serialization. +Below is a TokenV3 JSON before `base64_urlsafe` serialization. ```json { @@ -200,15 +201,17 @@ Below is a TokenV3 JSON before `base64_urlsafe` serialization. ``` When serialized, this becomes: + ``` cashuAeyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vODMzMy5zcGFjZTozMzM4IiwicHJvb2ZzIjpbeyJhbW91bnQiOjIsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6IjQwNzkxNWJjMjEyYmU2MWE3N2UzZTZkMmFlYjRjNzI3OTgwYmRhNTFjZDA2YTZhZmMyOWUyODYxNzY4YTc4MzciLCJDIjoiMDJiYzkwOTc5OTdkODFhZmIyY2M3MzQ2YjVlNDM0NWE5MzQ2YmQyYTUwNmViNzk1ODU5OGE3MmYwY2Y4NTE2M2VhIn0seyJhbW91bnQiOjgsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6ImZlMTUxMDkzMTRlNjFkNzc1NmIwZjhlZTBmMjNhNjI0YWNhYTNmNGUwNDJmNjE0MzNjNzI4YzcwNTdiOTMxYmUiLCJDIjoiMDI5ZThlNTA1MGI4OTBhN2Q2YzA5NjhkYjE2YmMxZDVkNWZhMDQwZWExZGUyODRmNmVjNjlkNjEyOTlmNjcxMDU5In1dfV0sInVuaXQiOiJzYXQiLCJtZW1vIjoiVGhhbmsgeW91LiJ9 ``` ### V4 tokens -V4 tokens are a space-efficient way of serializing tokens using the CBOR binary format. All field are single characters and hex strings are encoded in binary. V4 tokens can only hold proofs from a single mint. +V4 tokens are a space-efficient way of serializing tokens using the CBOR binary format. All field are single characters and hex strings are encoded in binary. V4 tokens can only hold proofs from a single mint. ##### Version + This token format has the `[version]` value `B`. ##### Format @@ -227,7 +230,7 @@ The deserialized `base64_token_cbor` is a JSON of the same form as a TokenV4 but { "m": str, // mint URL "u": str, // unit - "d": str , // memo + "d": str , // memo "t": [ { "i": bytes, // keyset ID @@ -250,15 +253,16 @@ The deserialized `base64_token_cbor` is a JSON of the same form as a TokenV4 but ], } ``` -`m` is the mint URL. The mint URL must be stripped of any trailing slashes (`/`). `u` is the currency unit of the token keysets (see [Keysets][01] for supported units), and `d` is an optional text memo from the sender. + +`m` is the mint URL. The mint URL must be stripped of any trailing slashes (`/`). `u` is the currency unit of the token keysets (see [Keysets][01] for supported units), and `d` is an optional text memo from the sender. `i` is the keyset ID of the profs in `p`, which is an array of `Proof` objects without the `id` field. We extracted the keyset ID `id` from each proof and grouped all proofs by their keyset ID `i` one level above (in `p`). -Note that all fields of the `bytes` type encode hex strings in the original representation of `Proof`'s. +Note that all fields of the `bytes` type encode hex strings in the original representation of `Proof`'s. ##### Example -Below is a TokenV4 JSON before CBOR and `base64_urlsafe` serialization. +Below is a TokenV4 JSON before CBOR and `base64_urlsafe` serialization. ```json { @@ -302,7 +306,6 @@ We serialize this JSON using CBOR which can be seen [here](https://cbor.nemo157. cashuBo2F0gqJhaUgA_9SLj17PgGFwgaNhYQFhc3hAYWNjMTI0MzVlN2I4NDg0YzNjZjE4NTAxNDkyMThhZjkwZjcxNmE1MmJmNGE1ZWQzNDdlNDhlY2MxM2Y3NzM4OGFjWCECRFODGd5IXVW-07KaZCvuWHk3WrnnpiDhHki6SCQh88-iYWlIAK0mjE0fWCZhcIKjYWECYXN4QDEzMjNkM2Q0NzA3YTU4YWQyZTIzYWRhNGU5ZjFmNDlmNWE1YjRhYzdiNzA4ZWIwZDYxZjczOGY0ODMwN2U4ZWVhY1ghAjRWqhENhLSsdHrr2Cw7AFrKUL9Ffr1XN6RBT6w659lNo2FhAWFzeEA1NmJjYmNiYjdjYzY0MDZiM2ZhNWQ1N2QyMTc0ZjRlZmY4YjQ0MDJiMTc2OTI2ZDNhNTdkM2MzZGNiYjU5ZDU3YWNYIQJzEpxXGeWZN5qXSmJjY8MzxWyvwObQGr5G1YCCgHicY2FtdWh0dHA6Ly9sb2NhbGhvc3Q6MzMzOGF1Y3NhdA ``` - [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/01.md b/01.md index 364f5cbe..526831dc 100644 --- a/01.md +++ b/01.md @@ -1,7 +1,6 @@ -NUT-01: Mint public key exchange -========================== +# NUT-01: Mint public key exchange -`mandatory` +`mandatory` --- @@ -9,13 +8,12 @@ This document outlines the exchange of the public keys of the mint `Bob` with th ## Description -Wallet user `Alice` receives public keys from mint `Bob` via `GET /v1/keys`. The set of all public keys for a set of amounts is called a *keyset*. +Wallet user `Alice` receives public keys from mint `Bob` via `GET /v1/keys`. The set of all public keys for a set of amounts is called a _keyset_. The mint responds only with its `active` keysets. Keyset are `active` if the mint will sign promises with it. The mint will accept tokens from inactive keysets as inputs but will not sign with them for new outputs. The `active` keysets can change over time, for example due to key rotation. A list of all keysets, active and inactive, can be requested separately (see [NUT-02][02]). Note that a mint can support multiple keysets at the same time but will only respond with the active keysets on the endpoint `GET /v1/keys`. A wallet can ask for the keys of a specific (active or inactive) keyset via the endpoint `GET /v1/keys/{keyset_id}` (see [NUT-02][02]). - ## Keyset generation Keysets are generated by the mint. The mint is free to use any key generation method they like. Each keyset is identified by its keyset `id` which can be computed by anyone from its public keys (see [NUT-02][02]). @@ -54,6 +52,7 @@ Response `GetKeysResponse` of `Bob`: ``` ## Example response + ```json { "keysets": [ diff --git a/02.md b/02.md index b4673078..64d726a1 100644 --- a/02.md +++ b/02.md @@ -49,10 +49,10 @@ def fees(inputs: List[Proof]) -> int: sum_fees += keysets[proof.id].input_fee_ppk return (sum_fees + 999) // 1000 ``` -Here, the `//` operator in `(sum_fees + 999) // 1000` denotes an integer division operator (aka floor division operator) that rounds down `sum_fees + 999` to the next lower integer. Alternatively, we could round up the sum using a floating point division with `ceil(sum_fees / 1000)` although it is not recommended to do so due to the non-deterministic behavior of floating point division. -Notice that since transactions can spend inputs from different keysets, the sum considers the fee for each `Proof` indexed by the keyset ID individually. +Here, the `//` operator in `(sum_fees + 999) // 1000` denotes an integer division operator (aka floor division operator) that rounds down `sum_fees + 999` to the next lower integer. Alternatively, we could round up the sum using a floating point division with `ceil(sum_fees / 1000)` although it is not recommended to do so due to the non-deterministic behavior of floating point division. +Notice that since transactions can spend inputs from different keysets, the sum considers the fee for each `Proof` indexed by the keyset ID individually. ### Deriving the keyset ID @@ -140,7 +140,6 @@ Here, `id` is the keyset ID, `unit` is the unit string (e.g. "sat") of the keyse } ``` - ## Requesting public keys for a specific keyset To receive the public keys of a specific keyset, a wallet can call the `GET /v1/keys/{keyset_id}` endpoint where `keyset_id` is the keyset ID. diff --git a/03.md b/03.md index c4b14778..946e33e6 100644 --- a/03.md +++ b/03.md @@ -1,5 +1,4 @@ -NUT-03: Swap tokens -========================== +# NUT-03: Swap tokens `mandatory` @@ -7,7 +6,7 @@ NUT-03: Swap tokens The swap operation is the most important component of the Cashu system. A swap operation consists of multiple inputs (`Proofs`) and outputs (`BlindedMessages`). Mints verify and invalidate the inputs and issue new promises (`BlindSignatures`). These are then used by the wallet to generate new `Proofs` (see [NUT-00][00]). -The swap operation can serve multiple use cases. The first use case is that `Alice` can use it to split her tokens to a target amount she needs to send to `Carol`, if she does not have the necessary amounts to compose the target amount in her wallet already. The second one is that `Carols`'s wallet can use it to receive tokens from `Alice` by sending them as inputs to the mint and receive new outputs in return. +The swap operation can serve multiple use cases. The first use case is that `Alice` can use it to split her tokens to a target amount she needs to send to `Carol`, if she does not have the necessary amounts to compose the target amount in her wallet already. The second one is that `Carols`'s wallet can use it to receive tokens from `Alice` by sending them as inputs to the mint and receive new outputs in return. ## Swap to send @@ -17,7 +16,6 @@ To make this more clear, we present an example of a typical case of sending toke Note: In order to preserve privacy around the amount that a client might want to send to another user and keep the rest as change, the client **SHOULD** ensure that the list requested outputs is ordered by amount in ascending order. As an example of what to avoid, a request for outputs expressed like so: `[16, 8, 2, 64, 8]` might imply the client is preparing a payment for 26 sat; the client should instead order the list like so: `[2, 8, 8, 16, 64]` to mitigate this privacy leak to the mint. - ## Swap to receive Another useful case for the swap operation follows up the example above where `Alice` has swapped her `Proofs` ready to be sent to `Carol`. `Carol` can receive these `Proofs` using the same operation by using them as inputs to invalidate them and request new outputs from `Bob`. Only if `Carol` has redeemed new outputs, `Alice` can't double-spend the `Proofs` anymore and the transaction is settled. To continue our example, `Carol` requests a swap with input `Proofs` worth `[32, 8]` to receive new outputs (of an arbitrary distribution) with the same total amount. @@ -44,7 +42,7 @@ With curl: ```bash curl -X POST https://mint.host:3338/v1/swap -d \ { - "inputs": + "inputs": [ { "amount": 2, @@ -59,7 +57,7 @@ curl -X POST https://mint.host:3338/v1/swap -d \ "outputs": [ { - "amount": 2, + "amount": 2, "id": "009a1f293253e41e", "B_": "02634a2c2b34bec9e8a4aba4361f6bf202d7fa2365379b0840afe249a7a9d71239" }, @@ -70,7 +68,7 @@ curl -X POST https://mint.host:3338/v1/swap -d \ } ``` -If successful, `Bob` will respond with a `PostSwapResponse` +If successful, `Bob` will respond with a `PostSwapResponse` ```json { diff --git a/04.md b/04.md index 892eeec4..edaf9044 100644 --- a/04.md +++ b/04.md @@ -1,19 +1,18 @@ -NUT-04: Mint tokens -========================== +# NUT-04: Mint tokens `mandatory` --- -Minting tokens is a two-step process: requesting a mint quote and minting new tokens. Here, we describe both steps. +Minting tokens is a two-step process: requesting a mint quote and minting new tokens. Here, we describe both steps. In the first request the wallet asks the mint for a quote for a specific `amount` and `unit` to mint, and the payment `method` to pay. The mint responds with a quote that includes a `quote` id and a payment `request`. The user pays the `request` and, if successful, requests minting of new tokens with the mint in a second request. The wallet includes the `quote` id and new `outputs` in the second request. -We limit this document to mint quotes of `unit="sat"` and `method="bolt11"` which requests a bolt11 Lightning invoice (typically generated by the mint to add Bitcoin to its reserves) to mint ecash denominated in Satoshis. +We limit this document to mint quotes of `unit="sat"` and `method="bolt11"` which requests a bolt11 Lightning invoice (typically generated by the mint to add Bitcoin to its reserves) to mint ecash denominated in Satoshis. # Mint quote -To request a mint quote, the wallet of `Alice` makes a `POST /v1/mint/quote/{method}` request where `method` is the payment method requested (here `bolt11`). +To request a mint quote, the wallet of `Alice` makes a `POST /v1/mint/quote/{method}` request where `method` is the payment method requested (here `bolt11`). ```http POST https://mint.host:3338/v1/mint/quote/bolt11 @@ -27,9 +26,10 @@ The wallet of `Alice` includes the following `PostMintQuoteBolt11Request` data i "unit": } ``` - with the requested `amount` and the `unit`. - - The mint `Bob` then responds with a `PostMintQuoteBolt11Response`: + +with the requested `amount` and the `unit`. + +The mint `Bob` then responds with a `PostMintQuoteBolt11Response`: ```json { @@ -40,14 +40,14 @@ The wallet of `Alice` includes the following `PostMintQuoteBolt11Request` data i } ``` -Where `quote` is the quote ID and `request` is the payment request to fulfill. `expiry` is the Unix timestamp until which the mint quote is valid. +Where `quote` is the quote ID and `request` is the payment request to fulfill. `expiry` is the Unix timestamp until which the mint quote is valid. `state` is an enum string field with possible values `"UNPAID"`, `"PAID"`, `"ISSUED"`: + - `"UNPAID"` means that the quote's request has not been paid yet. - `"PAID"` means that the request has been paid. - `"ISSUED"` means that the quote has already been issued. - Note: `quote` is a **unique and random** id generated by the mint to internally look up the payment state. `quote` **MUST** remain a secret between user and mint and **MUST NOT** be derivable from the payment request. A third party who knows the `quote` ID can front-run and steal the tokens that this operation mints. ## Example @@ -103,9 +103,10 @@ The wallet `Alice` includes the following `PostMintBolt11Request` data in its re "outputs": } ``` - with the `quote` being the quote ID from the previous step and `outputs` being `BlindedMessages` (see [NUT-00][00]) that the wallet requests signatures on whose sum is `amount` as requested in the quote. - - The mint `Bob` then responds with a `PostMintBolt11Response`: + +with the `quote` being the quote ID from the previous step and `outputs` being `BlindedMessages` (see [NUT-00][00]) that the wallet requests signatures on whose sum is `amount` as requested in the quote. + +The mint `Bob` then responds with a `PostMintBolt11Response`: ```json { @@ -138,7 +139,7 @@ curl -X POST https://mint.host:3338/v1/mint/bolt11 -H "Content-Type: application }' ``` -Response of `Bob`: +Response of `Bob`: ```json { @@ -166,22 +167,24 @@ Upon receiving the `BlindSignatures` from the mint `Bob`, the wallet of `Alice` ```json [ { - "id": "009a1f293253e41e", - "amount": 2, - "secret": "407915bc212be61a77e3e6d2aeb4c727980bda51cd06a6afc29e2861768a7837", - "C": "02bc9097997d81afb2cc7346b5e4345a9346bd2a506eb7958598a72f0cf85163ea" + "id": "009a1f293253e41e", + "amount": 2, + "secret": "407915bc212be61a77e3e6d2aeb4c727980bda51cd06a6afc29e2861768a7837", + "C": "02bc9097997d81afb2cc7346b5e4345a9346bd2a506eb7958598a72f0cf85163ea" }, { - "id": "009a1f293253e41e", - "amount": 8, - "secret": "fe15109314e61d7756b0f8ee0f23a624acaa3f4e042f61433c728c7057b931be", - "C": "029e8e5050b890a7d6c0968db16bc1d5d5fa040ea1de284f6ec69d61299f671059" + "id": "009a1f293253e41e", + "amount": 8, + "secret": "fe15109314e61d7756b0f8ee0f23a624acaa3f4e042f61433c728c7057b931be", + "C": "029e8e5050b890a7d6c0968db16bc1d5d5fa040ea1de284f6ec69d61299f671059" } ] ``` ## Settings -The settings for this nut indicate the supported method-unit pairs for minting and whether minting is disabled or not. They are part of the info response of the mint ([NUT-06][06]) which in this case reads + +The settings for this nut indicate the supported method-unit pairs for minting and whether minting is disabled or not. They are part of the info response of the mint ([NUT-06][06]) which in this case reads + ```json { "4": { @@ -197,6 +200,7 @@ The settings for this nut indicate the supported method-unit pairs for minting a `MintMethodSetting` indicates supported `method` and `unit` pairs and additional settings of the mint. `disabled` indicates whether this minting is disabled. `MintMethodSetting` is of the form: + ```json { "method": , @@ -205,6 +209,7 @@ The settings for this nut indicate the supported method-unit pairs for minting a "max_amount": } ``` + `min_amount` and `max_amount` indicate the minimum and maximum amount for an operation of this method-unit pair. Example `MintMethodSetting`: @@ -214,7 +219,7 @@ Example `MintMethodSetting`: "method": "bolt11", "unit": "sat", "min_amount": 0, - "max_amount": 10000 + "max_amount": 10000 } ``` diff --git a/05.md b/05.md index a14befc4..be55a414 100644 --- a/05.md +++ b/05.md @@ -1,22 +1,20 @@ -NUT-05: Melting tokens -========================== +# NUT-05: Melting tokens `mandatory` --- -Melting tokens is the opposite of minting tokens (see [NUT-04][04]). Like minting tokens, melting is a two-step process: requesting a melt quote and melting tokens. Here, we describe both steps. +Melting tokens is the opposite of minting tokens (see [NUT-04][04]). Like minting tokens, melting is a two-step process: requesting a melt quote and melting tokens. Here, we describe both steps. In the first request the wallet asks the mint for a quote for a `request` it wants paid by the mint and the `unit` the wallet would like to spend as inputs. The mint responds with a quote that includes a `quote` id and an `amount` the mint demands in the requested unit. For the method `bolt11`, the mint includes a `fee_reserve` field indicating the reserve fee for a Lightning payment. In the second request, the wallet includes the `quote` id and provides `inputs` that sum up to `amount+fee_reserve` in the first response. For the method `bolt11`, the wallet can also include `outputs` in order for the mint to return overpaid Lightning fees (see [NUT-08][08]). The mint responds with a payment status `paid` and a `proof` of payment. If the request included `outputs`, the mint may respond with `change` for the overpaid fees (see [NUT-08][08]). -We limit this document to mint quotes of `unit="sat"` and `method="bolt11"` which requests a bolt11 Lightning payment (typically paid by the mint from its Bitcoin reserves) using ecash denominated in Satoshis. - +We limit this document to mint quotes of `unit="sat"` and `method="bolt11"` which requests a bolt11 Lightning payment (typically paid by the mint from its Bitcoin reserves) using ecash denominated in Satoshis. # Melt quote -To request a melt quote, the wallet of `Alice` makes a `POST /v1/melt/quote/{method}` request where `method` is the payment method requested (here `bolt11`). +To request a melt quote, the wallet of `Alice` makes a `POST /v1/melt/quote/{method}` request where `method` is the payment method requested (here `bolt11`). ```http POST https://mint.host:3338/v1/melt/quote/bolt11 @@ -33,7 +31,7 @@ The wallet `Alice` includes the following `PostMeltQuoteBolt11Request` data in i Here, `request` is the bolt11 Lightning invoice to be paid and `unit` is the unit the wallet would like to pay with. - The mint `Bob` then responds with a `PostMeltQuoteBolt11Response`: +The mint `Bob` then responds with a `PostMeltQuoteBolt11Response`: ```json { @@ -45,9 +43,11 @@ Here, `request` is the bolt11 Lightning invoice to be paid and `unit` is the uni "payment_preimage": } ``` -Where `quote` is the quote ID, `amount` the amount that needs to be provided, and `fee_reserve` the additional fee reserve that is required. The mint expects `Alice` to include `Proofs` of *at least* `total_amount = amount + fee_reserve`. `expiry` is the Unix timestamp until which the melt quote is valid. `payment_preimage` is the bolt11 payment preimage in case of a successful payment. + +Where `quote` is the quote ID, `amount` the amount that needs to be provided, and `fee_reserve` the additional fee reserve that is required. The mint expects `Alice` to include `Proofs` of _at least_ `total_amount = amount + fee_reserve`. `expiry` is the Unix timestamp until which the melt quote is valid. `payment_preimage` is the bolt11 payment preimage in case of a successful payment. `state` is an enum string field with possible values `"UNPAID"`, `"PENDING"`, `"PAID"`: + - `"UNPAID"` means that the request has not been paid yet. - `"PENDING"` means that the request is currently being paid. - `"PAID"` means that the request has been paid successfully. @@ -72,7 +72,7 @@ Response of `Bob`: "amount": 10, "fee_reserve": 2, "state": "UNPAID", - "expiry": 1701704757, + "expiry": 1701704757 } ``` @@ -142,7 +142,7 @@ curl -X POST https://mint.host:3338/v1/melt/bolt11 -d \ }' ``` -Response `PostMeltQuoteBolt11Response` of `Bob`: +Response `PostMeltQuoteBolt11Response` of `Bob`: ```json { @@ -156,7 +156,9 @@ Response `PostMeltQuoteBolt11Response` of `Bob`: ``` ## Settings -The mint's settings for this nut indicate the supported method-unit pairs for melting. They are part of the info response of the mint ([NUT-06][06]) which in this case reads + +The mint's settings for this nut indicate the supported method-unit pairs for melting. They are part of the info response of the mint ([NUT-06][06]) which in this case reads + ```json { "5": { @@ -172,6 +174,7 @@ The mint's settings for this nut indicate the supported method-unit pairs for me `MeltMethodSetting` indicates supported `method` and `unit` pairs and additional settings of the mint. `disabled` indicates whether melting is disabled. `MeltMethodSetting` is of the form: + ```json { "method": , @@ -180,6 +183,7 @@ The mint's settings for this nut indicate the supported method-unit pairs for me "max_amount": } ``` + `min_amount` and `max_amount` indicate the minimum and maximum amount for an operation of this method-unit pair. Example `MeltMethodSetting`: @@ -189,7 +193,7 @@ Example `MeltMethodSetting`: "method": "bolt11", "unit": "sat", "min_amount": 100, - "max_amount": 10000 + "max_amount": 10000 } ``` diff --git a/06.md b/06.md index d48f8727..16ba1d6e 100644 --- a/06.md +++ b/06.md @@ -1,5 +1,4 @@ -NUT-06: Mint information -========================== +# NUT-06: Mint information `mandatory` @@ -81,15 +80,14 @@ With the mint's response being of the form `GetInfoResponse`: } ``` -- `name` is the name of the mint and should be recognizable. +- `name` is the name of the mint and should be recognizable. - `pubkey` is the hex pubkey of the mint. -- `version` is the implementation name and the version of the software running on this mint separated with a slash "/", -- `description` is a short description of the mint that can be shown in the wallet next to the mint's name. +- `version` is the implementation name and the version of the software running on this mint separated with a slash "/", +- `description` is a short description of the mint that can be shown in the wallet next to the mint's name. - `description_long` is a long description that can be shown in an additional field. - `contact` is an array of contact objects to reach the mint operator. A contact object consists of two fields. The `method` field denotes the contact method (like "email"), the `info` field denotes the identifier (like "contact@me.com"). -- `modt` is the message of the day that the wallet must display to the user. It should only be used to display important announcements to users, such as scheduled maintenances. -- `nuts` indicates each NUT specification that the mint supports and its settings. The settings are defined in each NUT separately. - +- `modt` is the message of the day that the wallet must display to the user. It should only be used to display important announcements to users, such as scheduled maintenances. +- `nuts` indicates each NUT specification that the mint supports and its settings. The settings are defined in each NUT separately. With curl: @@ -97,7 +95,6 @@ With curl: curl -X GET https://mint.host:3338/v1/info ``` - [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/07.md b/07.md index 47cc329a..c2ef4440 100644 --- a/07.md +++ b/07.md @@ -1,5 +1,4 @@ -NUT-07: Token state check -========================== +# NUT-07: Token state check `optional` @@ -7,9 +6,10 @@ NUT-07: Token state check With the token state check, wallets can ask the mint whether a specific proof is already spent and whether it is in-flight in a transaction. Wallets can also request the witness data that was used to spend a proof. -### Token states +### Token states A proof can be in one of the following states + - A proof is `UNSPENT` if it has not been spent yet - A proof is `PENDING` if it is being processed in a transaction (in an ongoing payment). A `PENDING` proof cannot be used in another transaction until it is `live` again. - A proof is `SPENT` if it has been redeemed and its secret is in the list of spent secrets of the mint. @@ -20,11 +20,13 @@ A proof can be in one of the following states ## Use cases -#### Example 1: Ecash transaction -When `Alice` prepares a token to be sent to `Carol`, she can mark these tokens in her database as *pending*. She can then, periodically or upon user input, check with the mint if the token is `UNSPENT` or whether it has been redeemed by `Carol` already, i.e., is `SPENT`. If the proof is not spendable anymore (and, thus, has been redeemed by `Carol`), she can safely delete the proof from her database. +#### Example 1: Ecash transaction + +When `Alice` prepares a token to be sent to `Carol`, she can mark these tokens in her database as _pending_. She can then, periodically or upon user input, check with the mint if the token is `UNSPENT` or whether it has been redeemed by `Carol` already, i.e., is `SPENT`. If the proof is not spendable anymore (and, thus, has been redeemed by `Carol`), she can safely delete the proof from her database. -#### Example 2: Lightning payments -If `Alice`'s melt operation takes a long time to complete (for example if she requests a very slow Lightning payment) and she closes her wallet in the meantime, the next time she comes online, she can check all proofs marked as *pending* in her database to determine whether the payment is still in flight (mint returns `PENDING`), it has succeeded (mint returns `SPENT`), or it has failed (mint returns `UNSPENT`). +#### Example 2: Lightning payments + +If `Alice`'s melt operation takes a long time to complete (for example if she requests a very slow Lightning payment) and she closes her wallet in the meantime, the next time she comes online, she can check all proofs marked as _pending_ in her database to determine whether the payment is still in flight (mint returns `PENDING`), it has succeeded (mint returns `SPENT`), or it has failed (mint returns `UNSPENT`). ## Example @@ -46,7 +48,7 @@ Where the elements of the array in `Ys` are the hexadecimal representation of th **Response** of `Bob`: -`Bob` will respond with a `PostCheckStateResponse` +`Bob` will respond with a `PostCheckStateResponse` ```json { @@ -61,7 +63,7 @@ Where the elements of the array in `Ys` are the hexadecimal representation of th } ``` -- `Y` corresponds to the `Proof` checked in the request. +- `Y` corresponds to the `Proof` checked in the request. - `state` is an enum string field with possible values `"UNSPENT"`, `"PENDING"`, `"SPENT"` - `witness` is the serialized witness data that was used to spend the `Proof` if the token required it such as in the case of P2PK (see [NUT-11][11]). @@ -91,8 +93,7 @@ curl -X POST https://mint.host:3338/v1/checkstate -H 'Content-Type: application/ } ``` - -Where `Y` belongs to the provided `Proof` to check in the request, `state` indicates its state, and `witness` is the witness data that was potentially provided in a previous spend operation (can be empty). +Where `Y` belongs to the provided `Proof` to check in the request, `state` indicates its state, and `witness` is the witness data that was potentially provided in a previous spend operation (can be empty). [00]: 00.md [01]: 01.md diff --git a/08.md b/08.md index fc3201fc..abb8d0fc 100644 --- a/08.md +++ b/08.md @@ -1,17 +1,16 @@ -NUT-08: Lightning fee return -========================== +# NUT-08: Lightning fee return `optional`, `depends on: NUT-05` --- -This document describes how the overpaid Lightning fees are handled and extends [NUT-05][05] which describes melting tokens (i.e. paying a Lightning invoice). In short, a wallet includes *blank outputs* when paying a Lightning invoice which can be assigned a value by the mint if the user has overpaid Lightning fees. This can be the case due to the unpredictability of Lightning network fees. To solve this issue, we introduce so-called *blank outputs* which are blinded messages with an undetermined value. +This document describes how the overpaid Lightning fees are handled and extends [NUT-05][05] which describes melting tokens (i.e. paying a Lightning invoice). In short, a wallet includes _blank outputs_ when paying a Lightning invoice which can be assigned a value by the mint if the user has overpaid Lightning fees. This can be the case due to the unpredictability of Lightning network fees. To solve this issue, we introduce so-called _blank outputs_ which are blinded messages with an undetermined value. The problem is also described in [this gist](https://gist.github.com/callebtc/a6cc0bd2b6f70e081e478147c40fc578). ## Description -Before requesting a Lightning payment as described in [NUT-05][05], `Alice` produces a number of `BlindedMessage` which are similar to ordinary blinded messages but their value is yet to be determined by the mint `Bob` and are thus called *blank outputs*. The number of necessary blank outputs is `max(ceil(log2(fee_reserve)), 1)` which ensures that there is at least one output if there is any fee. If the `fee_reserve` is `0`, then the number of blank outputs is `0` as well. The blank outputs will contain the overpaid fees that will be returned by the mint to the wallet. +Before requesting a Lightning payment as described in [NUT-05][05], `Alice` produces a number of `BlindedMessage` which are similar to ordinary blinded messages but their value is yet to be determined by the mint `Bob` and are thus called _blank outputs_. The number of necessary blank outputs is `max(ceil(log2(fee_reserve)), 1)` which ensures that there is at least one output if there is any fee. If the `fee_reserve` is `0`, then the number of blank outputs is `0` as well. The blank outputs will contain the overpaid fees that will be returned by the mint to the wallet. This code calculates the number of necessary blank outputs in Python: @@ -28,13 +27,14 @@ def calculate_number_of_blank_outputs(fee_reserve_sat: int) -> int: The wallet wants to pay an invoice with `amount := 100 000 sat` and determines by asking the mint that `fee_reserve` is `1000 sats`. The wallet then provides `101 000 sat` worth of proofs and 10 blank `outputs` to make the payment (since `ceil(log2(1000))=ceil(9.96..)=10`). The mint pays the invoice and determines that the actual fee was `100 sat`, i.e, the overpaid fee to return is `fee_return = 900 sat`. The mint splits the amount `900` into summands of `2^n` which is `4, 128, 256, 512`. The mint inserts these amounts into the blank `outputs` it received form the wallet and generates 4 new promises. The mint then returns these `BlindSignature`s to the wallet together with the successful payment status. ## Wallet flow + The wallet asks the mint for the `fee_reserve` for paying a specific bolt11 invoice of value `amount` by calling `POST /v1/melt/quote` as described in [NUT-05][05]. The wallet then provides a `PostMeltBolt11Request` to `POST /v1/melt/bolt11` that has (1) proofs of the value `amount+fee_reserve`, (2) the bolt11 invoice to be paid, and finally, as a new entry, (3) a field `outputs` that has `n_blank_outputs` blinded messages that are generated before the payment attempt to receive potential overpaid fees back to her. ## Mint flow Here we describe how the mint generates `BlindSignature`s for the overpaid fees. The mint `Bob` returns in `PostMeltQuoteBolt11Response` the field `change` **ONLY IF** `Alice` has previously provided `outputs` for the change **AND** if the Lightning `actual_fees` were smaller than the `fee_reserve`. -If the `overpaid_fees = fee_reserve - actual_fees` is positive, `Bob` decomposes it to values of `2^n` (as in [NUT-00][00]) and then imprints them into the `blank_outputs` provided by `Alice`. +If the `overpaid_fees = fee_reserve - actual_fees` is positive, `Bob` decomposes it to values of `2^n` (as in [NUT-00][00]) and then imprints them into the `blank_outputs` provided by `Alice`. `Bob` then signs these blank outputs (now with the imprinted amounts) and thus generates `BlindSignature`s. `Bob` then returns a payment status to the wallet, and, in addition, all blind signatures it generated for the overpaid fees. @@ -57,6 +57,7 @@ With the data being of the form `PostMeltBolt11Request`: "outputs": <-- New } ``` + where the new `output` field carries the `BlindMessages`. The mint `Bob` then responds with a `PostMeltQuoteBolt11Response`: @@ -72,6 +73,7 @@ The mint `Bob` then responds with a `PostMeltQuoteBolt11Response`: "change": <-- New } ``` + where the new `change` field carries the returned `BlindSignature`s due to overpaid fees. ## Example @@ -120,11 +122,12 @@ If the mint has made a successful payment, it will respond the following. { "id": "009a1f293253e41e", "amount": 2, - "C_": "03c668f551855ddc792e22ea61d32ddfa6a45b1eb659ce66e915bf5127a8657be0", + "C_": "03c668f551855ddc792e22ea61d32ddfa6a45b1eb659ce66e915bf5127a8657be0" } ] } ``` + The field `change` is an array of `BlindSignatures` that account for the overpaid fees. Notice that the amount has been changed by the mint. `Alice` must take these and generate `Proofs` by unblinding them as described in [NUT-00][00] and as she does in [NUT-04][04] when minting new tokens. After generating the `Proofs`, `Alice` stores them in her database. [00]: 00.md diff --git a/09.md b/09.md index f240e888..04c7f4ee 100644 --- a/09.md +++ b/09.md @@ -1,5 +1,4 @@ -NUT-09: Restore signatures -========================== +# NUT-09: Restore signatures `optional` `used in: NUT-13` @@ -23,7 +22,7 @@ With the data being of the form `PostRestoreRequest`: } ``` -**Response** of `Bob`: +**Response** of `Bob`: The mint `Bob` then responds with a `PostRestoreResponse`. @@ -34,7 +33,7 @@ The mint `Bob` then responds with a `PostRestoreResponse`. } ``` -The returned arrays `outputs` and `signatures` are of the same length and for every entry `outputs[i]`, there is a corresponding entry `signatures[i]`. +The returned arrays `outputs` and `signatures` are of the same length and for every entry `outputs[i]`, there is a corresponding entry `signatures[i]`. [00]: 00.md [02]: 02.md diff --git a/10.md b/10.md index 6fecdbd0..99b131e9 100644 --- a/10.md +++ b/10.md @@ -1,11 +1,10 @@ -NUT-10: Spending conditions -========================== +# NUT-10: Spending conditions `optional` --- -An ordinary ecash token is a set of `Proofs` each with a random string `secret`. To spend such a token in a [swap][03] 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. +An ordinary ecash token is a set of `Proofs` each with a random string `secret`. To spend such a token in a [swap][03] 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. @@ -14,6 +13,7 @@ Spending conditions are enforced by the mint which means that, upon encountering Caution: If the mint does not support spending conditions or a specific `kind` of spending condition, proofs may be treated as a regular anyone-can-spend tokens. Applications need to make sure to check whether the mint supports a specific `kind` of spending condition by checking the mint's [info][06] endpoint. ## Basic components + An ecash transaction, i.e., a [swap][03] or a [melt][05] operation, with a spending condition consists of the following components: - Inputs referring to the `Proofs` being spent @@ -33,7 +33,7 @@ The well-known `Secret` stored in `Proof.secret` is a JSON of the format: ```json [ -kind , +kind , { "nonce": , "data": , @@ -46,7 +46,7 @@ kind , - `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 diff --git a/11.md b/11.md index 63584cb9..f6006664 100644 --- a/11.md +++ b/11.md @@ -1,5 +1,4 @@ -NUT-11: Pay to Public Key (P2PK) -========================== +# NUT-11: Pay to Public Key (P2PK) `optional`, `depends on: NUT-10` @@ -13,9 +12,9 @@ Caution: If the mint does not support this type of spending condition, proofs ma [NUT-10][10] Secret `kind: P2PK` -If for a `Proof`, `Proof.secret` is a `Secret` of kind `P2PK`, the proof must be unlocked by providing a witness `Proof.witness` and one or more valid signatures in the array `Proof.witness.signatures`. +If for a `Proof`, `Proof.secret` is a `Secret` of kind `P2PK`, the proof must be unlocked by providing a witness `Proof.witness` and one or more valid signatures in the array `Proof.witness.signatures`. -In the basic case, when spending a locked token, the mint requires one valid Schnorr signature in `Proof.witness.signatures` on `Proof.secret` by the public key in `Proof.Secret.data`. +In the basic case, when spending a locked token, the mint requires one valid Schnorr signature in `Proof.witness.signatures` on `Proof.secret` by the public key in `Proof.Secret.data`. To give a concrete example of the basic case, to mint a locked token we first create a P2PK `Secret` that reads: @@ -25,17 +24,12 @@ To give a concrete example of the basic case, to mint a locked token we first cr { "nonce": "859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f", "data": "0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7", - "tags": [ - [ - "sigflag", - "SIG_INPUTS" - ] - ] + "tags": [["sigflag", "SIG_INPUTS"]] } ] ``` -Here, `Secret.data` is the public key of the recipient of the locked ecash. We serialize this `Secret` to a string in `Proof.secret` and get a blind signature by the mint that is stored in `Proof.C` (see [NUT-03][03]]). +Here, `Secret.data` is the public key of the recipient of the locked ecash. We serialize this `Secret` to a string in `Proof.secret` and get a blind signature by the mint that is stored in `Proof.C` (see [NUT-03][03]]). The recipient who owns the private key of the public key `Secret.data` can spend this proof by providing a signature on the serialized `Proof.secret` string that is then added to `Proof.witness.signatures`: @@ -51,26 +45,27 @@ The recipient who owns the private key of the public key `Secret.data` can spend #### Signature scheme -To spend a token locked with `P2PK`, the spender needs to include signatures in the spent proofs. We use `libsecp256k1`'s serialized 64 byte Schnorr signatures on the SHA256 hash of the message to sign. The message to sign is the field `Proof.secret` in the inputs. If indicated by `Secret.tags.sigflag` in the inputs, outputs might also require signatures on the message `BlindedMessage.B_`. +To spend a token locked with `P2PK`, the spender needs to include signatures in the spent proofs. We use `libsecp256k1`'s serialized 64 byte Schnorr signatures on the SHA256 hash of the message to sign. The message to sign is the field `Proof.secret` in the inputs. If indicated by `Secret.tags.sigflag` in the inputs, outputs might also require signatures on the message `BlindedMessage.B_`. -An ecash spending operation like [swap][03] and [melt][05] can have multiple inputs and outputs. If we have more than one input or output, we provide signatures in each `Proof` and `BlindedMessage` individually. The inputs are the `Proofs` provided in the `inputs` field and the outputs are the `BlindedMessages` in the `outputs` field in the request body (see `PostMeltRequest` in [NUT-05][05] and `PostSwapRequest` in [NUT-03][03]). +An ecash spending operation like [swap][03] and [melt][05] can have multiple inputs and outputs. If we have more than one input or output, we provide signatures in each `Proof` and `BlindedMessage` individually. The inputs are the `Proofs` provided in the `inputs` field and the outputs are the `BlindedMessages` in the `outputs` field in the request body (see `PostMeltRequest` in [NUT-05][05] and `PostSwapRequest` in [NUT-03][03]). ### Tags + More complex spending conditions can be defined in the tags in `Proof.tags`. All tags are optional. Tags are arrays with two or more strings being `["key", "value1", "value2", ...]`. Supported tags are: - `sigflag: ` determines whether outputs have to be signed as well - `n_sigs: ` specifies the minimum number of valid signatures expected -- `pubkeys: ` are additional public keys that can provide signatures (*allows multiple entries*) +- `pubkeys: ` are additional public keys that can provide signatures (_allows multiple entries_) - `locktime: ` is the Unix timestamp of when the lock expires -- `refund: ` are optional refund public keys that can exclusively spend after `locktime` (*allows multiple entries*) +- `refund: ` are optional refund public keys that can exclusively spend after `locktime` (_allows multiple entries_) **Note:** The tag serialization type is `[, , ...]` but some tag values are `int`. Wallets and mints must cast types appropriately for de/serialization. #### Signature flags -Signature flags are defined in the tag `Secret.tags['sigflag']`. Currently, there are two signature flags. +Signature flags are defined in the tag `Secret.tags['sigflag']`. Currently, there are two signature flags. - `SIG_INPUTS` requires valid signatures on all inputs. It is the default signature flag and will be applied even if the `sigflag` tag is absent. - `SIG_ALL` requires valid signatures on all inputs and on all outputs. @@ -82,10 +77,12 @@ The signature flag `SIG_ALL` is enforced if at least one of the `Proofs` have th Signatures must be provided in the field `Proof.witness.signatures` for each `Proof` which is an input. If the signature flag `SIG_ALL` is enforced, signatures must also be provided for every output in its field `BlindedMessage.witness.signatures`. ##### Signed inputs + A `Proof` (an input) with a signature `P2PKWitness.signatures` on `secret` is the JSON (see [NUT-00][00]): + ```json { - "amount": , + "amount": , "secret": , "C": , "id": , @@ -96,6 +93,7 @@ A `Proof` (an input) with a signature `P2PKWitness.signatures` on `secret` is th The `secret` of each input is **signed as a string**. ##### Signed outputs + A `BlindedMessage` (an output) with a signature `P2PKWitness.signatures` on `B_` is the JSON (see [NUT-00][00]): ```json @@ -111,6 +109,7 @@ The `B_` of each output is **signed as bytes** which comes from the original hex ##### Witness format `P2PKWitness` is a serialized JSON string of the form + ```json { "signatures": ]> @@ -120,14 +119,17 @@ The `B_` of each output is **signed as bytes** which comes from the original hex The `signatures` are an array of signatures in hex. ### Multisig + If the tag `n_sigs` is a positive integer, the mint will also consider signatures from public keys specified in the `pubkeys` tag additional to the public key in `Secret.data`. If the number of valid signatures is greater or equal to the number specified in `n_sigs`, the transaction is valid. Expressed as an "n-of-m" scheme, `n = n_sigs` is the number of required signatures and `m = 1 ("data" field) + len(pubkeys tag)` is the number of public keys that could sign. ### Locktime + If the tag `locktime` is the unix time and the mint's local clock is greater than `locktime`, the `Proof` becomes spendable by anyone, except if the following condition is also true. Note: A `Proof` is considered spendable by anyone if it only requires a `secret` and a valid signature `C` to be spent (which is the default case). #### Refund public keys + If the `locktime` is in the past and a tag `refund` is present, the `Proof` is spendable only if a valid signature by one of the the `refund` pubkeys is provided in `Proof.witness.signatures` and, depending on the signature flag, in `BlindedMessage.witness.signatures`. #### Complex Example @@ -141,27 +143,18 @@ This is an example `secret` that locks a `Proof` with a Pay-to-Pubkey (P2PK) con "nonce": "da62796403af76c80cd6ce9153ed3746", "data": "033281c37677ea273eb7183b783067f5244933ef78d8c3f15b1a77cb246099c26e", "tags": [ - [ - "sigflag", - "SIG_ALL" - ], - [ - "n_sigs", - "2" - ], - [ - "locktime", - "1689418329" - ], + ["sigflag", "SIG_ALL"], + ["n_sigs", "2"], + ["locktime", "1689418329"], [ "refund", "033281c37677ea273eb7183b783067f5244933ef78d8c3f15b1a77cb246099c26e" - ], + ], [ "pubkeys", "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", "023192200a0cfd3867e48eb63b03ff599c7e46c8f4e41146b2d281173ca6c50c54" - ], + ] ] } ] @@ -170,6 +163,7 @@ This is an example `secret` that locks a `Proof` with a Pay-to-Pubkey (P2PK) con ## Use cases The following use cases are unlocked using P2PK: + - Publicly post locked ecash that can only be redeemed by the intended receiver - Final offline-receiver payments that can't be double-spent when combined with an offline signature check mechanism like DLEQ proofs - Receiver of locked ecash can defer and batch multiple mint round trips for receiving proofs (requires DLEQ) diff --git a/12.md b/12.md index d5775c7b..a78308b8 100644 --- a/12.md +++ b/12.md @@ -1,16 +1,17 @@ -NUT-12: Offline ecash signature validation -========================== +# NUT-12: Offline ecash signature validation `optional` --- -In this document, we present an extension of Cashu's crypto system to allow a user `Alice` to verify the mint `Bob`'s signature using only `Bob`'s public keys. We explain how another user `Carol` who receives ecash from `Alice` can execute the DLEQ proof as well. This is achieved using a Discrete Log Equality (DLEQ) proof. Previously, `Bob`'s signature could only be checked by himself using his own private keys ([NUT-00](00)). +In this document, we present an extension of Cashu's crypto system to allow a user `Alice` to verify the mint `Bob`'s signature using only `Bob`'s public keys. We explain how another user `Carol` who receives ecash from `Alice` can execute the DLEQ proof as well. This is achieved using a Discrete Log Equality (DLEQ) proof. Previously, `Bob`'s signature could only be checked by himself using his own private keys ([NUT-00](00)). # The DLEQ proof -The purpose of this DLEQ is to prove that the mint has used the same private key `a` for creating its public key `A` ([NUT-01](01)) and for signing the BlindedMessage `B'`. `Bob` returns the DLEQ proof additional to the blind signature `C'` for a mint or swap operation. + +The purpose of this DLEQ is to prove that the mint has used the same private key `a` for creating its public key `A` ([NUT-01](01)) and for signing the BlindedMessage `B'`. `Bob` returns the DLEQ proof additional to the blind signature `C'` for a mint or swap operation. The complete DLEQ proof reads + ``` # DLEQ Proof @@ -64,7 +65,7 @@ The mint produces these DLEQ proofs when returning `BlindSignature`'s in the res ``` -`e` and `s` are the DLEQ proof. +`e` and `s` are the DLEQ proof. ### User to user: DLEQ in `Proof` @@ -83,6 +84,7 @@ In order for `Alice` to communicate the DLEQ to another user `Carol`, we extend } } ``` + `e` and `s` are the challenge and response of the DLEQ proof returned by `Bob`, `r` is the blinding factor of `Alice` that was used to generate the `Proof`. `Alice` serializes these proofs like any other in a token (see [NUT-00][00]) to send it to another user `Carol`. ## Alice (minting user) verifies DLEQ proof @@ -96,6 +98,7 @@ e == hash(R1,R2,A,C') # must be True ``` Here, the variables are + - `A` – the public key `Bob` used to sign this Proof - `(e, s)` – the DLEQ proof returned by `Bob` - `B'` – `Alice`'s `BlindedMessage` @@ -103,7 +106,7 @@ Here, the variables are In order to execute the proof, `Alice` needs `e, s` that are returned in the `BlindSignature` by `Bob`. `Alice` further needs `B'` (the `BlindedMessage` `Alice` created and `Bob` signed) and `C'` (the blind signature in the `BlindSignature` response) from `Bob`, and `A` (the public key of `Bob` with which he signed the BlindedMessage). All these values are available to `Alice` during or after calling the mint and swap operations. -If a DLEQ proof is included in the mint's `BlindSignature` response, wallets **MUST** verify the DLEQ proof. +If a DLEQ proof is included in the mint's `BlindSignature` response, wallets **MUST** verify the DLEQ proof. ## Carol (another user) verifies DLEQ proof @@ -125,7 +128,7 @@ B' = Y + r*G R1 = ... (same as Alice) ``` -If a DLEQ proof is included in a received token, wallets **MUST** verify the proof. +If a DLEQ proof is included in a received token, wallets **MUST** verify the proof. [00]: 00.md [01]: 01.md diff --git a/13.md b/13.md index 7e641773..04655442 100644 --- a/13.md +++ b/13.md @@ -1,17 +1,16 @@ -NUT-13: Deterministic Secrets -========================== +# NUT-13: Deterministic Secrets `optional` `depends on: NUT-09` --- -In this document, we describe the process that allows wallets to recover their ecash balance with the help of the mint using a familiar 12 word seed phrase (mnemonic). This allows us to restore the wallet's previous state in case of a device loss or other loss of access to the wallet. The basic idea is that wallets that generate the ecash deterministically can regenerate the same tokens during a recovery process. For this, they ask the mint to reissue previously generated signatures using [NUT-09][09]. +In this document, we describe the process that allows wallets to recover their ecash balance with the help of the mint using a familiar 12 word seed phrase (mnemonic). This allows us to restore the wallet's previous state in case of a device loss or other loss of access to the wallet. The basic idea is that wallets that generate the ecash deterministically can regenerate the same tokens during a recovery process. For this, they ask the mint to reissue previously generated signatures using [NUT-09][09]. ## Deterministic secret derivation An ecash token, or a `Proof`, consists of a `secret` generated by the wallet, and a signature `C` generated by the wallet and the mint in collaboration. Here, we describe how wallets can deterministically generate the `secrets` and blinding factors `r` necessary to generate the signatures `C`. -The wallet generates a `private_key` derived from a 12-word [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) `mnemonic` seed phrase that the user stores in a secure place. The wallet uses the `private_key`, to derive deterministic values for the `secret` and the blinding factors `r` for every new ecash token that it generates. +The wallet generates a `private_key` derived from a 12-word [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) `mnemonic` seed phrase that the user stores in a secure place. The wallet uses the `private_key`, to derive deterministic values for the `secret` and the blinding factors `r` for every new ecash token that it generates. In order to do this, the wallet keeps track of a `counter_k` for each `keyset_k` it uses. The index `k` indicates that the wallet needs to keep track of a separate counter for each keyset `k` it uses. Typically, the wallet will need to keep track of multiple keysets for every mint it interacts with. `counter_k` is used to generate a [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) derivation path which can then be used to derive `secret` and `r`. @@ -32,7 +31,7 @@ secret_derivation_path = `m/129372'/0'/{keyset_k_int}'/{counter_k}'/0` r_derivation_path = `m/129372'/0'/{keyset_id_k_int}'/{counter_k}'/1` ``` -Here, `{keyset_k_int}` and `{counter_k}` are the only variables that can change. `keyset_id_k_int` is an integer representation (see below) of the keyset ID the token is generated with. This means that the derivation path is unique for each keyset. Note that the coin type is always `0'`, independent of the unit of the ecash. +Here, `{keyset_k_int}` and `{counter_k}` are the only variables that can change. `keyset_id_k_int` is an integer representation (see below) of the keyset ID the token is generated with. This means that the derivation path is unique for each keyset. Note that the coin type is always `0'`, independent of the unit of the ecash. **Note:** For examples, see the [test vectors][tests]. @@ -45,11 +44,13 @@ The wallet starts with `counter_k := 0` upon encountering a new keyset and incre The integer representation `keyset_id_int` of a keyset is calculated from its [hexadecimal ID][02] which has a length of 8 bytes or 16 hex characters. First, we convert the hex string to a big-endian sequence of bytes. This value is then modulo reduced by `2^31 - 1` to arrive at an integer that is a unique identifier `keyset_id_int`. Example in Python: + ```python keyset_id_int = int.from_bytes(bytes.fromhex(keyset_id_hex), "big") % (2**31 - 1) ``` Example in JavaScript: + ```javascript keysetIdInt = BigInt(`0x${keysetIdHex}`) % BigInt(2 ** 31 - 1); ``` @@ -60,12 +61,12 @@ Using deterministic secret derivation, a user's wallet can regenerate the same ` The wallet takes the following steps during recovery: -1) Generate `secret` and `r` from `counter` and `keyset` -2) Generate `BlindedMessage` from `secret` -3) Obtain `BlindSignature` for `secret` from the mint -4) Unblind `BlindSignature` to `C` using `r` -5) Restore `Proof = (secret, C)` -6) Check if `Proof` is already spent +1. Generate `secret` and `r` from `counter` and `keyset` +2. Generate `BlindedMessage` from `secret` +3. Obtain `BlindSignature` for `secret` from the mint +4. Unblind `BlindSignature` to `C` using `r` +5. Restore `Proof = (secret, C)` +6. Check if `Proof` is already spent #### Generate `BlindedMessages` @@ -74,6 +75,7 @@ To generate the `BlindedMessages`, the wallet starts with a `counter := 0` and , ```python secret = bip32.get_privkey_from_path(secret_derivation_path).hex() ``` + The wallet similarly generates a blinding factor `r` from the `r_derivation_path`: ```python @@ -96,14 +98,15 @@ If the wallet used the restore endpoint [NUT-09][09] for regenerating the `Proof ### Restoring batches -Generally, the user won't remember the last state of `counter` when starting the recovery process. Therefore, wallets need to know how far they need to increment the `counter` during the restore process to be confident to have reached the most recent state. +Generally, the user won't remember the last state of `counter` when starting the recovery process. Therefore, wallets need to know how far they need to increment the `counter` during the restore process to be confident to have reached the most recent state. + +In short, following approach is recommended: -In short, following approach is recommended: - Restore `Proofs` in batches of 100 and increment `counter` - Repeat until three consecutive batches are returned empty - Reset `counter` to the value at the last successful restore + 1 -Wallets restore `Proofs` in batches of 100. The wallet starts with a `counter=0` and increments it for every `Proof` it generated during one batch. When the wallet begins restoring the first `Proofs`, it is likely that the first few batches will only contain spent `Proofs`. Eventually, the wallet will reach a `counter` that will result in unspent `Proofs` which it stores in its database. The wallet then continues to restore until *three successive batches are returned empty by the mint*. This is to be confident that the restore process did not miss any `Proofs` that might have been generated with larger gaps in the `counter` by the previous wallet that we are restoring. +Wallets restore `Proofs` in batches of 100. The wallet starts with a `counter=0` and increments it for every `Proof` it generated during one batch. When the wallet begins restoring the first `Proofs`, it is likely that the first few batches will only contain spent `Proofs`. Eventually, the wallet will reach a `counter` that will result in unspent `Proofs` which it stores in its database. The wallet then continues to restore until _three successive batches are returned empty by the mint_. This is to be confident that the restore process did not miss any `Proofs` that might have been generated with larger gaps in the `counter` by the previous wallet that we are restoring. [00]: 00.md [02]: 02.md diff --git a/14.md b/14.md index 9dc4c2f7..f3a07911 100644 --- a/14.md +++ b/14.md @@ -1,5 +1,4 @@ -NUT-14: Hashed Timelock Contracts (HTLCs) -========================== +# NUT-14: Hashed Timelock Contracts (HTLCs) `optional` `depends on: NUT-10` @@ -18,6 +17,7 @@ Caution: If the mint does not support this type of spending condition, proofs ma If for a `Proof`, `Proof.secret` is a `Secret` of kind `HTLC`, the hash of the lock is in `Proof.secret.data`. The preimage for unlocking the HTLC is in the witness `Proof.witness.preimage`. All additional tags from `P2PK` locks are used here as well, allowing us to add a locktime, signature flag, and use multisig (see [NUT-11][11]). Here is a concrete example of a `Secret` of kind `HTLC`: + ```json [ "HTLC", @@ -27,12 +27,9 @@ Here is a concrete example of a `Secret` of kind `HTLC`: "tags": [ [ "pubkeys", - "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904" ], - [ - "locktime", - "1689418329" - ], + ["locktime", "1689418329"], [ "refund", "033281c37677ea273eb7183b783067f5244933ef78d8c3f15b1a77cb246099c26e" @@ -51,6 +48,7 @@ See [NUT-11][11] for a description of the signature scheme, the additional use o ##### Witness format `HTLCWitness` is a serialized JSON string of the form + ```json { "preimage": , @@ -70,4 +68,4 @@ See [NUT-11][11] for a description of the signature scheme, the additional use o [09]: 09.md [10]: 10.md [11]: 11.md -[12]: 12.md \ No newline at end of file +[12]: 12.md diff --git a/15.md b/15.md index 4b3efa7d..8418312c 100644 --- a/15.md +++ b/15.md @@ -1,5 +1,4 @@ -NUT-15: Partial multi-path payments -========================== +# NUT-15: Partial multi-path payments `optional` `depends on: NUT-05` @@ -42,6 +41,7 @@ Here, `request` is the bolt11 Lightning invoice to be paid, `unit` is the unit t The settings returned in the info endpoint ([NUT-06][06]) indicate that a mint supports this NUT. The mint MUST indicate each `method` and `unit` that supports `mpp`. It can indicate this in an array of objects for multiple `method` and `unit` pairs and the boolean flag `mpp` set to `true`. `MultipathPaymentSetting` is of the form: + ```json { [ @@ -49,7 +49,7 @@ The settings returned in the info endpoint ([NUT-06][06]) indicate that a mint s "method": , "unit": , "mpp": - }, + }, ... ] } @@ -70,7 +70,7 @@ Example `MultipathPaymentSetting`: "method": "bolt11", "unit": "usd", "mpp": true - }, + }, ] } } diff --git a/16.md b/16.md index 589ceeb8..366817c9 100644 --- a/16.md +++ b/16.md @@ -1,11 +1,10 @@ -NUT-16: Animated QR codes -========================== +# NUT-16: Animated QR codes `optional` --- -This document outlines how tokens should be displayed as QR codes for sending them between two wallets. +This document outlines how tokens should be displayed as QR codes for sending them between two wallets. ## Introduction @@ -20,7 +19,8 @@ If the serialized token is not too large (i.e. includes less than or equal to 2 If a token is too large to be displayed as a single QR code, we use animated QR codes are based on the [UR](https://developer.blockchaincommons.com/ur/) protocol. The sender produces an animated QR code from a serialized Cashu token. The receiver scans the animated QR code until the UR decoder is able to decode the token. ## Resources -- Blockchain commons [UR](https://developer.blockchaincommons.com/ur/) + +- Blockchain commons [UR](https://developer.blockchaincommons.com/ur/) - Typescript library [bc-ur](https://github.com/gandlafbtc/bc-ur) -[00]: 00.md \ No newline at end of file +[00]: 00.md diff --git a/17.md b/17.md index 7d61b174..37edaa33 100644 --- a/17.md +++ b/17.md @@ -39,6 +39,7 @@ All requests from the wallet to the mint are of the form of a `WsRequest`: "id": } ``` + `WsRequestMethod` is a enum of strings with the supported commands `"subscribe"` and `"unsubscribe"`: ```ts @@ -70,22 +71,21 @@ Here, `subId` is a unique uuid generated by the wallet and allows the client to enum SubscriptionKind { bolt11_melt_quote = "bolt11_melt_quote", bolt11_mint_quote = "bolt11_mint_quote", - proof_state = "proof_state" + proof_state = "proof_state", } ``` -The `filters` are an array of mint quote IDs ([NUT-04][04]), or melt quote IDs ([NUT-05][05]), or `Y`'s ([NUT-07][07]) of the corresponding object to receive updates from. +The `filters` are an array of mint quote IDs ([NUT-04][04]), or melt quote IDs ([NUT-05][05]), or `Y`'s ([NUT-07][07]) of the corresponding object to receive updates from. As an example, `filters` would be of the following form to subscribe for updates of three different mint quote IDs: + ```json -[ - "20385fc7245...", "d06667cda9b...", "e14d8ca96f..." -] +["20385fc7245...", "d06667cda9b...", "e14d8ca96f..."] ``` Note that `id` and `subId` are unrelated. The `subId` is the ID for each subscription, whereas `id` is part of the JSON-RPC spec and is an integer counter that must be incremented for every request sent over the websocket. -**Important:** If the subscription is accepted by the mint, the mint MUST first respond with the *current* state of the subscribed object and continue sending any further updates to it. +**Important:** If the subscription is accepted by the mint, the mint MUST first respond with the _current_ state of the subscribed object and continue sending any further updates to it. For example, if the wallet subscribes to a `Proof.Y` of a `Proof` that has not been spent yet, the mint will first respond with a `ProofState` with `state == "UNSPENT"`. If the wallet then spends this `Proof`, the mint would send a `ProofState` with `state == "PENDING"` and then one with `state == "SPENT"`. In total, the mint would send three notifications to the wallet. @@ -149,29 +149,64 @@ Here, the `id` corresponds to the `id` in the request (as part of the JSON-RPC s ``` ### Example: `ProofState` subscription + To subscribe to the `ProofState` of a `Proof`, the wallet establishes a websocket connection to `https://mint.com/v1/ws` and sends a `WsRequest` with a `filters` chosen to be the a `Proof.Y` value of the `Proof` (see [NUT-00][00]). Note that `filters` is an array meaning multiple subscriptions of the same `kind` can be made in the same request. Wallet: + ```json -{"jsonrpc": "2.0", "id": 0, "method": "subscribe", "params": {"kind": "proof_state", "filters": ["02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d"], "subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T"}} +{ + "jsonrpc": "2.0", + "id": 0, + "method": "subscribe", + "params": { + "kind": "proof_state", + "filters": [ + "02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d" + ], + "subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T" + } +} ``` The mint first responds with a `WsResponse` confirming that the subscription has been added. Mint: + ```json -{"jsonrpc": "2.0", "result": {"status": "OK", "subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T"}, "id": 0} +{ + "jsonrpc": "2.0", + "result": { + "status": "OK", + "subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T" + }, + "id": 0 +} ``` The mint immediately sends the current `ProofState` of the subscription as a `WsNotification`. Mint: + ```json -{"jsonrpc": "2.0", "method": "subscribe", "params": {"subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T", "payload": {"Y": "02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d", "state": "UNSPENT", "witness": null}}} +{ + "jsonrpc": "2.0", + "method": "subscribe", + "params": { + "subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T", + "payload": { + "Y": "02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d", + "state": "UNSPENT", + "witness": null + } + } +} ``` + While leaving the websocket connection open, the wallet then spends the ecash. The mint sends `WsNotification` updating the wallet about state changes of the `ProofState` accordingly: Mint: + ```json {"jsonrpc": "2.0", "method": "subscribe", "params": {"subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T", "payload": {"Y": "02e208f9a78cd523444aadf854a4e91281d20f67a923d345239c37f14e137c7c3d", "state": "PENDING"}}} @@ -181,8 +216,14 @@ Mint: The wallet then unsubscribes. Wallet: + ```json -{"jsonrpc": "2.0", "id": 1, "method": "unsubscribe", "params": {"subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T"}} +{ + "jsonrpc": "2.0", + "id": 1, + "method": "unsubscribe", + "params": { "subId": "Ua_IYvRHoCoF_wsZFlJ1m4gBDB--O0_6_n0zHg2T" } +} ``` ## Signaling Support via NUT-06 @@ -207,6 +248,7 @@ Mints signal websocket support via [NUT-06][06] using the following setting: Here, `commands` is an array of the commands that the mint supports. A mint that supports all commands would return `["bolt11_mint_quote", "bolt11_melt_quote", "proof_state"]`. Supported commands are given for each method-unit pair. Example: + ```json "nuts": { "17": { @@ -215,8 +257,8 @@ Example: "method": "bolt11", "unit": "sat", "commands": [ - "bolt11_mint_quote", - "bolt11_melt_quote", + "bolt11_mint_quote", + "bolt11_melt_quote", "proof_state" ] }, @@ -225,7 +267,6 @@ Example: } ``` - [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/README.md b/README.md index 0099500e..dcf98981 100644 --- a/README.md +++ b/README.md @@ -3,57 +3,57 @@ These documents each specify parts of the Cashu protocol. Read the specifications for the legacy API [here](https://github.com/cashubtc/nuts/tree/74f26b81b6617db710fa1081eebc0c7203711213). ## Specifications + Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optional specs. ### Mandatory -| NUT # | Description | -|----------|-----------------------------------| -| [00][00] | Cryptography and Models | -| [01][01] | Mint public keys | -| [02][02] | Keysets and fees | -| [03][03] | Swapping tokens | -| [04][04] | Minting tokens | -| [05][05] | Melting tokens | -| [06][06] | Mint info | +| NUT # | Description | +| -------- | ----------------------- | +| [00][00] | Cryptography and Models | +| [01][01] | Mint public keys | +| [02][02] | Keysets and fees | +| [03][03] | Swapping tokens | +| [04][04] | Minting tokens | +| [05][05] | Melting tokens | +| [06][06] | Mint info | ### Optional -| # | Description | Wallets | Mints | -| --- | --- | --- | --- | -| [07][07] | Token state check | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd] | -| [08][08] | Overpaid Lightning fees | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd] | -| [09][09] | Signature restore | [Nutshell][py], [cdk-cli], [cashu-ts][ts], [gonuts] | [Nutshell][py], [cdk-mintd] -| [10][10] | Spending conditions | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | -| [11][11] | Pay-To-Pubkey (P2PK) | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | -| [12][12] | DLEQ proofs | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd] | -| [13][13] | Deterministic secrets | [Nutshell][py], [Moksha][moksha], [cashu-ts][ts], [cdk-cli], [gonuts] | - | -| [14][14] | Hashed Timelock Contracts (HTLCs) | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd] | -| [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py] | -| [16][16] | Animated QR codes | [Cashu.me][cashume] | - | -| [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] | +| # | Description | Wallets | Mints | +| -------- | --------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------- | +| [07][07] | Token state check | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd] | +| [08][08] | Overpaid Lightning fees | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd] | +| [09][09] | Signature restore | [Nutshell][py], [cdk-cli], [cashu-ts][ts], [gonuts] | [Nutshell][py], [cdk-mintd] | +| [10][10] | Spending conditions | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [11][11] | Pay-To-Pubkey (P2PK) | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [12][12] | DLEQ proofs | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd] | +| [13][13] | Deterministic secrets | [Nutshell][py], [Moksha][moksha], [cashu-ts][ts], [cdk-cli], [gonuts] | - | +| [14][14] | Hashed Timelock Contracts (HTLCs) | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd] | +| [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py] | +| [16][16] | Animated QR codes | [Cashu.me][cashume] | - | +| [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] | #### Wallets: - - [Nutshell][py] - - [cdk-cli][cdk-cli] - - [cashu-ts][ts] - - [eNuts][enuts] - - [Minibits][minibits] - - [Moksha][moksha] - - [Nutstash][ns] - - [Cashu.me][cashume] - - [Gonuts][gonuts] - - [Boardwalk Cash][bwc] +- [Nutshell][py] +- [cdk-cli][cdk-cli] +- [cashu-ts][ts] +- [eNuts][enuts] +- [Minibits][minibits] +- [Moksha][moksha] +- [Nutstash][ns] +- [Cashu.me][cashume] +- [Gonuts][gonuts] +- [Boardwalk Cash][bwc] #### Mints: - - - [Nutshell][py] - - [Gonuts][gonuts] - - [Moksha][moksha] - - [cdk-mintd][cdk-mintd] - - [Nutmix][nutmix] - + +- [Nutshell][py] +- [Gonuts][gonuts] +- [Moksha][moksha] +- [cdk-mintd][cdk-mintd] +- [Nutmix][nutmix] [py]: https://github.com/cashubtc/nutshell [lnbits]: https://github.com/lnbits/cashu @@ -69,7 +69,6 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio [gonuts]: https://github.com/elnosh/gonuts [nutmix]: https://github.com/lescuer97/nutmix [bwc]: https://github.com/MakePrisms/boardwalkcash - [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/tests/00-tests.md b/tests/00-tests.md index 45717908..d3837730 100644 --- a/tests/00-tests.md +++ b/tests/00-tests.md @@ -3,6 +3,7 @@ ### Hash-to-curve function The hash to curve function takes a message of any length and outputs a valid point on the secp256k1 curve. Note that unless you are using complex spend conditions ([NUT-10]), standardized secrets (random 32-bytes-long byte arrays) should be used in order to prevent wallet fingerprinting. + ```shell # Test 1 (hex encoded) Message: 0000000000000000000000000000000000000000000000000000000000000000 @@ -19,7 +20,9 @@ Point: 026cdbe15362df59cd1dd3c9c11de8aedac2106eca69236ecd9fbe117af897be4f ``` ### Blinded messages + These are test vectors for the the blinded secret (public key) `B_` Alice sends to the mint Bob given a secret `x` and a random blinding factor `r`. + ```shell # Test 1 x: d341ee4871f1f889041e63cf0d3823c713eea6aff01e80f1719f08f9e5be98f6 # hex encoded byte array @@ -49,7 +52,9 @@ C_: 0398bc70ce8184d27ba89834d19f5199c84443c31131e48d3c1214db24247d005d ``` ## Serialization of TokenV3 + The following are JSON-formatted v3 tokens and their serialized counterparts. + ```json { "token": [ @@ -76,7 +81,8 @@ The following are JSON-formatted v3 tokens and their serialized counterparts. } ``` -Serialized: +Serialized: + ``` cashuAeyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vODMzMy5zcGFjZTozMzM4IiwicHJvb2ZzIjpbeyJhbW91bnQiOjIsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6IjQwNzkxNWJjMjEyYmU2MWE3N2UzZTZkMmFlYjRjNzI3OTgwYmRhNTFjZDA2YTZhZmMyOWUyODYxNzY4YTc4MzciLCJDIjoiMDJiYzkwOTc5OTdkODFhZmIyY2M3MzQ2YjVlNDM0NWE5MzQ2YmQyYTUwNmViNzk1ODU5OGE3MmYwY2Y4NTE2M2VhIn0seyJhbW91bnQiOjgsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6ImZlMTUxMDkzMTRlNjFkNzc1NmIwZjhlZTBmMjNhNjI0YWNhYTNmNGUwNDJmNjE0MzNjNzI4YzcwNTdiOTMxYmUiLCJDIjoiMDI5ZThlNTA1MGI4OTBhN2Q2YzA5NjhkYjE2YmMxZDVkNWZhMDQwZWExZGUyODRmNmVjNjlkNjEyOTlmNjcxMDU5In1dfV0sInVuaXQiOiJzYXQiLCJtZW1vIjoiVGhhbmsgeW91LiJ9 ``` @@ -84,6 +90,7 @@ cashuAeyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vODMzMy5zcGFjZTozMzM4IiwicHJvb2ZzIjpbey ## Deserialization of TokenV3 The following are incorrectly formatted serialized v3 tokens. + ```shell # Incorrect prefix (casshuA) casshuAeyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vODMzMy5zcGFjZTozMzM4IiwicHJvb2ZzIjpbeyJhbW91bnQiOjIsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6IjQwNzkxNWJjMjEyYmU2MWE3N2UzZTZkMmFlYjRjNzI3OTgwYmRhNTFjZDA2YTZhZmMyOWUyODYxNzY4YTc4MzciLCJDIjoiMDJiYzkwOTc5OTdkODFhZmIyY2M3MzQ2YjVlNDM0NWE5MzQ2YmQyYTUwNmViNzk1ODU5OGE3MmYwY2Y4NTE2M2VhIn0seyJhbW91bnQiOjgsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6ImZlMTUxMDkzMTRlNjFkNzc1NmIwZjhlZTBmMjNhNjI0YWNhYTNmNGUwNDJmNjE0MzNjNzI4YzcwNTdiOTMxYmUiLCJDIjoiMDI5ZThlNTA1MGI4OTBhN2Q2YzA5NjhkYjE2YmMxZDVkNWZhMDQwZWExZGUyODRmNmVjNjlkNjEyOTlmNjcxMDU5In1dfV0sInVuaXQiOiJzYXQiLCJtZW1vIjoiVGhhbmsgeW91LiJ9 @@ -93,11 +100,13 @@ eyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vODMzMy5zcGFjZTozMzM4IiwicHJvb2ZzIjpbeyJhbW91 ``` The following is a correctly serialized v3 token. + ```shell cashuAeyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vODMzMy5zcGFjZTozMzM4IiwicHJvb2ZzIjpbeyJhbW91bnQiOjIsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6IjQwNzkxNWJjMjEyYmU2MWE3N2UzZTZkMmFlYjRjNzI3OTgwYmRhNTFjZDA2YTZhZmMyOWUyODYxNzY4YTc4MzciLCJDIjoiMDJiYzkwOTc5OTdkODFhZmIyY2M3MzQ2YjVlNDM0NWE5MzQ2YmQyYTUwNmViNzk1ODU5OGE3MmYwY2Y4NTE2M2VhIn0seyJhbW91bnQiOjgsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6ImZlMTUxMDkzMTRlNjFkNzc1NmIwZjhlZTBmMjNhNjI0YWNhYTNmNGUwNDJmNjE0MzNjNzI4YzcwNTdiOTMxYmUiLCJDIjoiMDI5ZThlNTA1MGI4OTBhN2Q2YzA5NjhkYjE2YmMxZDVkNWZhMDQwZWExZGUyODRmNmVjNjlkNjEyOTlmNjcxMDU5In1dfV0sInVuaXQiOiJzYXQiLCJtZW1vIjoiVGhhbmsgeW91LiJ9 ``` Both of the following v3 tokens are valid, one includes padding characters at the end and the other does not. + ```shell # Clients should be able to deserialize both cashuAeyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vODMzMy5zcGFjZTozMzM4IiwicHJvb2ZzIjpbeyJhbW91bnQiOjIsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6IjQwNzkxNWJjMjEyYmU2MWE3N2UzZTZkMmFlYjRjNzI3OTgwYmRhNTFjZDA2YTZhZmMyOWUyODYxNzY4YTc4MzciLCJDIjoiMDJiYzkwOTc5OTdkODFhZmIyY2M3MzQ2YjVlNDM0NWE5MzQ2YmQyYTUwNmViNzk1ODU5OGE3MmYwY2Y4NTE2M2VhIn0seyJhbW91bnQiOjgsImlkIjoiMDA5YTFmMjkzMjUzZTQxZSIsInNlY3JldCI6ImZlMTUxMDkzMTRlNjFkNzc1NmIwZjhlZTBmMjNhNjI0YWNhYTNmNGUwNDJmNjE0MzNjNzI4YzcwNTdiOTMxYmUiLCJDIjoiMDI5ZThlNTA1MGI4OTBhN2Q2YzA5NjhkYjE2YmMxZDVkNWZhMDQwZWExZGUyODRmNmVjNjlkNjEyOTlmNjcxMDU5In1dfV0sInVuaXQiOiJzYXQiLCJtZW1vIjoiVGhhbmsgeW91IHZlcnkgbXVjaC4ifQ== @@ -105,10 +114,13 @@ cashuAeyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vODMzMy5zcGFjZTozMzM4IiwicHJvb2ZzIjpbey ``` ## Serialization of TokenV4 + The following are JSON-formatted v4 tokens and their serialized counterparts. The `h''` values are `bytes` but displayed as hex strings here. ### Single keyset + Token from a single keyset and including a memo. + ```json { "t": [ @@ -136,7 +148,9 @@ cashuBpGF0gaJhaUgArSaMTR9YJmFwgaNhYQFhc3hAOWE2ZGJiODQ3YmQyMzJiYTc2ZGIwZGYxOTcyMT ``` ### Multiple keysets + The token below includes proofs from two different keysets. + ```json { "t": [ diff --git a/tests/01-tests.md b/tests/01-tests.md index 74ec3248..a46927d7 100644 --- a/tests/01-tests.md +++ b/tests/01-tests.md @@ -3,28 +3,103 @@ The following are incorrect keysets that should be rejected by wallets implementing the NUT-01 specification. Key 1 is missing a byte + ```json { - "1":"03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38","2":"03fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de","4":"02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303","8":"02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528" + "1": "03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38", + "2": "03fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de", + "4": "02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303", + "8": "02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528" } ``` Key 2 is a valid key but is not in the compressed format. + ```json { - "1":"03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38bc","2":"04fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de3625246cb2c27dac965cb7200a5986467eee92eb7d496bbf1453b074e223e481","4":"02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303","8":"02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528" + "1": "03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38bc", + "2": "04fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de3625246cb2c27dac965cb7200a5986467eee92eb7d496bbf1453b074e223e481", + "4": "02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303", + "8": "02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528" } ``` The following are correct keysets that should be accepted by wallets implementing the NUT-01 specification. Note that the second (bigger) keyset's biggest amount is `9223372036854775808`, one unit over what can fit into a 64-bit signed integer (often known as a `Long`). To handle this you'll need to use either an unsigned 64-bit integer or a 128-bit signed integer (sometimes known as a `BigInteger`). + ```json { - "1":"03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38bc","2":"03fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de","4":"02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303","8":"02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528" + "1": "03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38bc", + "2": "03fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de", + "4": "02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303", + "8": "02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528" } ``` ```json { - "1":"03ba786a2c0745f8c30e490288acd7a72dd53d65afd292ddefa326a4a3fa14c566","2":"03361cd8bd1329fea797a6add1cf1990ffcf2270ceb9fc81eeee0e8e9c1bd0cdf5","4":"036e378bcf78738ddf68859293c69778035740e41138ab183c94f8fee7572214c7","8":"03909d73beaf28edfb283dbeb8da321afd40651e8902fcf5454ecc7d69788626c0","16":"028a36f0e6638ea7466665fe174d958212723019ec08f9ce6898d897f88e68aa5d","32":"03a97a40e146adee2687ac60c2ba2586a90f970de92a9d0e6cae5a4b9965f54612","64":"03ce86f0c197aab181ddba0cfc5c5576e11dfd5164d9f3d4a3fc3ffbbf2e069664","128":"0284f2c06d938a6f78794814c687560a0aabab19fe5e6f30ede38e113b132a3cb9","256":"03b99f475b68e5b4c0ba809cdecaae64eade2d9787aa123206f91cd61f76c01459","512":"03d4db82ea19a44d35274de51f78af0a710925fe7d9e03620b84e3e9976e3ac2eb","1024":"031fbd4ba801870871d46cf62228a1b748905ebc07d3b210daf48de229e683f2dc","2048":"0276cedb9a3b160db6a158ad4e468d2437f021293204b3cd4bf6247970d8aff54b","4096":"02fc6b89b403ee9eb8a7ed457cd3973638080d6e04ca8af7307c965c166b555ea2","8192":"0320265583e916d3a305f0d2687fcf2cd4e3cd03a16ea8261fda309c3ec5721e21","16384":"036e41de58fdff3cb1d8d713f48c63bc61fa3b3e1631495a444d178363c0d2ed50","32768":"0365438f613f19696264300b069d1dad93f0c60a37536b72a8ab7c7366a5ee6c04","65536":"02408426cfb6fc86341bac79624ba8708a4376b2d92debdf4134813f866eb57a8d","131072":"031063e9f11c94dc778c473e968966eac0e70b7145213fbaff5f7a007e71c65f41","262144":"02f2a3e808f9cd168ec71b7f328258d0c1dda250659c1aced14c7f5cf05aab4328","524288":"038ac10de9f1ff9395903bb73077e94dbf91e9ef98fd77d9a2debc5f74c575bc86","1048576":"0203eaee4db749b0fc7c49870d082024b2c31d889f9bc3b32473d4f1dfa3625788","2097152":"033cdb9d36e1e82ae652b7b6a08e0204569ec7ff9ebf85d80a02786dc7fe00b04c","4194304":"02c8b73f4e3a470ae05e5f2fe39984d41e9f6ae7be9f3b09c9ac31292e403ac512","8388608":"025bbe0cfce8a1f4fbd7f3a0d4a09cb6badd73ef61829dc827aa8a98c270bc25b0","16777216":"037eec3d1651a30a90182d9287a5c51386fe35d4a96839cf7969c6e2a03db1fc21","33554432":"03280576b81a04e6abd7197f305506476f5751356b7643988495ca5c3e14e5c262","67108864":"03268bfb05be1dbb33ab6e7e00e438373ca2c9b9abc018fdb452d0e1a0935e10d3","134217728":"02573b68784ceba9617bbcc7c9487836d296aa7c628c3199173a841e7a19798020","268435456":"0234076b6e70f7fbf755d2227ecc8d8169d662518ee3a1401f729e2a12ccb2b276","536870912":"03015bd88961e2a466a2163bd4248d1d2b42c7c58a157e594785e7eb34d880efc9","1073741824":"02c9b076d08f9020ebee49ac8ba2610b404d4e553a4f800150ceb539e9421aaeee","2147483648":"034d592f4c366afddc919a509600af81b489a03caf4f7517c2b3f4f2b558f9a41a","4294967296":"037c09ecb66da082981e4cbdb1ac65c0eb631fc75d85bed13efb2c6364148879b5","8589934592":"02b4ebb0dda3b9ad83b39e2e31024b777cc0ac205a96b9a6cfab3edea2912ed1b3","17179869184":"026cc4dacdced45e63f6e4f62edbc5779ccd802e7fabb82d5123db879b636176e9","34359738368":"02b2cee01b7d8e90180254459b8f09bbea9aad34c3a2fd98c85517ecfc9805af75","68719476736":"037a0c0d564540fc574b8bfa0253cca987b75466e44b295ed59f6f8bd41aace754","137438953472":"021df6585cae9b9ca431318a713fd73dbb76b3ef5667957e8633bca8aaa7214fb6","274877906944":"02b8f53dde126f8c85fa5bb6061c0be5aca90984ce9b902966941caf963648d53a","549755813888":"029cc8af2840d59f1d8761779b2496623c82c64be8e15f9ab577c657c6dd453785","1099511627776":"03e446fdb84fad492ff3a25fc1046fb9a93a5b262ebcd0151caa442ea28959a38a","2199023255552":"02d6b25bd4ab599dd0818c55f75702fde603c93f259222001246569018842d3258","4398046511104":"03397b522bb4e156ec3952d3f048e5a986c20a00718e5e52cd5718466bf494156a","8796093022208":"02d1fb9e78262b5d7d74028073075b80bb5ab281edcfc3191061962c1346340f1e","17592186044416":"030d3f2ad7a4ca115712ff7f140434f802b19a4c9b2dd1c76f3e8e80c05c6a9310","35184372088832":"03e325b691f292e1dfb151c3fb7cad440b225795583c32e24e10635a80e4221c06","70368744177664":"03bee8f64d88de3dee21d61f89efa32933da51152ddbd67466bef815e9f93f8fd1","140737488355328":"0327244c9019a4892e1f04ba3bf95fe43b327479e2d57c25979446cc508cd379ed","281474976710656":"02fb58522cd662f2f8b042f8161caae6e45de98283f74d4e99f19b0ea85e08a56d","562949953421312":"02adde4b466a9d7e59386b6a701a39717c53f30c4810613c1b55e6b6da43b7bc9a","1125899906842624":"038eeda11f78ce05c774f30e393cda075192b890d68590813ff46362548528dca9","2251799813685248":"02ec13e0058b196db80f7079d329333b330dc30c000dbdd7397cbbc5a37a664c4f","4503599627370496":"02d2d162db63675bd04f7d56df04508840f41e2ad87312a3c93041b494efe80a73","9007199254740992":"0356969d6aef2bb40121dbd07c68b6102339f4ea8e674a9008bb69506795998f49","18014398509481984":"02f4e667567ebb9f4e6e180a4113bb071c48855f657766bb5e9c776a880335d1d6","36028797018963968":"0385b4fe35e41703d7a657d957c67bb536629de57b7e6ee6fe2130728ef0fc90b0","72057594037927936":"02b2bc1968a6fddbcc78fb9903940524824b5f5bed329c6ad48a19b56068c144fd","144115188075855872":"02e0dbb24f1d288a693e8a49bc14264d1276be16972131520cf9e055ae92fba19a","288230376151711744":"03efe75c106f931a525dc2d653ebedddc413a2c7d8cb9da410893ae7d2fa7d19cc","576460752303423488":"02c7ec2bd9508a7fc03f73c7565dc600b30fd86f3d305f8f139c45c404a52d958a","1152921504606846976":"035a6679c6b25e68ff4e29d1c7ef87f21e0a8fc574f6a08c1aa45ff352c1d59f06","2305843009213693952":"033cdc225962c052d485f7cfbf55a5b2367d200fe1fe4373a347deb4cc99e9a099","4611686018427387904":"024a4b806cf413d14b294719090a9da36ba75209c7657135ad09bc65328fba9e6f","9223372036854775808":"0377a6fe114e291a8d8e991627c38001c8305b23b9e98b1c7b1893f5cd0dda6cad" + "1": "03ba786a2c0745f8c30e490288acd7a72dd53d65afd292ddefa326a4a3fa14c566", + "2": "03361cd8bd1329fea797a6add1cf1990ffcf2270ceb9fc81eeee0e8e9c1bd0cdf5", + "4": "036e378bcf78738ddf68859293c69778035740e41138ab183c94f8fee7572214c7", + "8": "03909d73beaf28edfb283dbeb8da321afd40651e8902fcf5454ecc7d69788626c0", + "16": "028a36f0e6638ea7466665fe174d958212723019ec08f9ce6898d897f88e68aa5d", + "32": "03a97a40e146adee2687ac60c2ba2586a90f970de92a9d0e6cae5a4b9965f54612", + "64": "03ce86f0c197aab181ddba0cfc5c5576e11dfd5164d9f3d4a3fc3ffbbf2e069664", + "128": "0284f2c06d938a6f78794814c687560a0aabab19fe5e6f30ede38e113b132a3cb9", + "256": "03b99f475b68e5b4c0ba809cdecaae64eade2d9787aa123206f91cd61f76c01459", + "512": "03d4db82ea19a44d35274de51f78af0a710925fe7d9e03620b84e3e9976e3ac2eb", + "1024": "031fbd4ba801870871d46cf62228a1b748905ebc07d3b210daf48de229e683f2dc", + "2048": "0276cedb9a3b160db6a158ad4e468d2437f021293204b3cd4bf6247970d8aff54b", + "4096": "02fc6b89b403ee9eb8a7ed457cd3973638080d6e04ca8af7307c965c166b555ea2", + "8192": "0320265583e916d3a305f0d2687fcf2cd4e3cd03a16ea8261fda309c3ec5721e21", + "16384": "036e41de58fdff3cb1d8d713f48c63bc61fa3b3e1631495a444d178363c0d2ed50", + "32768": "0365438f613f19696264300b069d1dad93f0c60a37536b72a8ab7c7366a5ee6c04", + "65536": "02408426cfb6fc86341bac79624ba8708a4376b2d92debdf4134813f866eb57a8d", + "131072": "031063e9f11c94dc778c473e968966eac0e70b7145213fbaff5f7a007e71c65f41", + "262144": "02f2a3e808f9cd168ec71b7f328258d0c1dda250659c1aced14c7f5cf05aab4328", + "524288": "038ac10de9f1ff9395903bb73077e94dbf91e9ef98fd77d9a2debc5f74c575bc86", + "1048576": "0203eaee4db749b0fc7c49870d082024b2c31d889f9bc3b32473d4f1dfa3625788", + "2097152": "033cdb9d36e1e82ae652b7b6a08e0204569ec7ff9ebf85d80a02786dc7fe00b04c", + "4194304": "02c8b73f4e3a470ae05e5f2fe39984d41e9f6ae7be9f3b09c9ac31292e403ac512", + "8388608": "025bbe0cfce8a1f4fbd7f3a0d4a09cb6badd73ef61829dc827aa8a98c270bc25b0", + "16777216": "037eec3d1651a30a90182d9287a5c51386fe35d4a96839cf7969c6e2a03db1fc21", + "33554432": "03280576b81a04e6abd7197f305506476f5751356b7643988495ca5c3e14e5c262", + "67108864": "03268bfb05be1dbb33ab6e7e00e438373ca2c9b9abc018fdb452d0e1a0935e10d3", + "134217728": "02573b68784ceba9617bbcc7c9487836d296aa7c628c3199173a841e7a19798020", + "268435456": "0234076b6e70f7fbf755d2227ecc8d8169d662518ee3a1401f729e2a12ccb2b276", + "536870912": "03015bd88961e2a466a2163bd4248d1d2b42c7c58a157e594785e7eb34d880efc9", + "1073741824": "02c9b076d08f9020ebee49ac8ba2610b404d4e553a4f800150ceb539e9421aaeee", + "2147483648": "034d592f4c366afddc919a509600af81b489a03caf4f7517c2b3f4f2b558f9a41a", + "4294967296": "037c09ecb66da082981e4cbdb1ac65c0eb631fc75d85bed13efb2c6364148879b5", + "8589934592": "02b4ebb0dda3b9ad83b39e2e31024b777cc0ac205a96b9a6cfab3edea2912ed1b3", + "17179869184": "026cc4dacdced45e63f6e4f62edbc5779ccd802e7fabb82d5123db879b636176e9", + "34359738368": "02b2cee01b7d8e90180254459b8f09bbea9aad34c3a2fd98c85517ecfc9805af75", + "68719476736": "037a0c0d564540fc574b8bfa0253cca987b75466e44b295ed59f6f8bd41aace754", + "137438953472": "021df6585cae9b9ca431318a713fd73dbb76b3ef5667957e8633bca8aaa7214fb6", + "274877906944": "02b8f53dde126f8c85fa5bb6061c0be5aca90984ce9b902966941caf963648d53a", + "549755813888": "029cc8af2840d59f1d8761779b2496623c82c64be8e15f9ab577c657c6dd453785", + "1099511627776": "03e446fdb84fad492ff3a25fc1046fb9a93a5b262ebcd0151caa442ea28959a38a", + "2199023255552": "02d6b25bd4ab599dd0818c55f75702fde603c93f259222001246569018842d3258", + "4398046511104": "03397b522bb4e156ec3952d3f048e5a986c20a00718e5e52cd5718466bf494156a", + "8796093022208": "02d1fb9e78262b5d7d74028073075b80bb5ab281edcfc3191061962c1346340f1e", + "17592186044416": "030d3f2ad7a4ca115712ff7f140434f802b19a4c9b2dd1c76f3e8e80c05c6a9310", + "35184372088832": "03e325b691f292e1dfb151c3fb7cad440b225795583c32e24e10635a80e4221c06", + "70368744177664": "03bee8f64d88de3dee21d61f89efa32933da51152ddbd67466bef815e9f93f8fd1", + "140737488355328": "0327244c9019a4892e1f04ba3bf95fe43b327479e2d57c25979446cc508cd379ed", + "281474976710656": "02fb58522cd662f2f8b042f8161caae6e45de98283f74d4e99f19b0ea85e08a56d", + "562949953421312": "02adde4b466a9d7e59386b6a701a39717c53f30c4810613c1b55e6b6da43b7bc9a", + "1125899906842624": "038eeda11f78ce05c774f30e393cda075192b890d68590813ff46362548528dca9", + "2251799813685248": "02ec13e0058b196db80f7079d329333b330dc30c000dbdd7397cbbc5a37a664c4f", + "4503599627370496": "02d2d162db63675bd04f7d56df04508840f41e2ad87312a3c93041b494efe80a73", + "9007199254740992": "0356969d6aef2bb40121dbd07c68b6102339f4ea8e674a9008bb69506795998f49", + "18014398509481984": "02f4e667567ebb9f4e6e180a4113bb071c48855f657766bb5e9c776a880335d1d6", + "36028797018963968": "0385b4fe35e41703d7a657d957c67bb536629de57b7e6ee6fe2130728ef0fc90b0", + "72057594037927936": "02b2bc1968a6fddbcc78fb9903940524824b5f5bed329c6ad48a19b56068c144fd", + "144115188075855872": "02e0dbb24f1d288a693e8a49bc14264d1276be16972131520cf9e055ae92fba19a", + "288230376151711744": "03efe75c106f931a525dc2d653ebedddc413a2c7d8cb9da410893ae7d2fa7d19cc", + "576460752303423488": "02c7ec2bd9508a7fc03f73c7565dc600b30fd86f3d305f8f139c45c404a52d958a", + "1152921504606846976": "035a6679c6b25e68ff4e29d1c7ef87f21e0a8fc574f6a08c1aa45ff352c1d59f06", + "2305843009213693952": "033cdc225962c052d485f7cfbf55a5b2367d200fe1fe4373a347deb4cc99e9a099", + "4611686018427387904": "024a4b806cf413d14b294719090a9da36ba75209c7657135ad09bc65328fba9e6f", + "9223372036854775808": "0377a6fe114e291a8d8e991627c38001c8305b23b9e98b1c7b1893f5cd0dda6cad" } ``` diff --git a/tests/02-tests.md b/tests/02-tests.md index 759d15e2..c5a80804 100644 --- a/tests/02-tests.md +++ b/tests/02-tests.md @@ -2,15 +2,83 @@ The following keysets and corresponding keyset IDs are correct: Keyset id: `00456a94ab4e1c46` + ```json { - "1":"03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38bc","2":"03fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de","4":"02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303","8":"02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528" + "1": "03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38bc", + "2": "03fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de", + "4": "02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303", + "8": "02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528" } ``` Keyset id: `000f01df73ea149a` + ```json { - "1":"03ba786a2c0745f8c30e490288acd7a72dd53d65afd292ddefa326a4a3fa14c566","2":"03361cd8bd1329fea797a6add1cf1990ffcf2270ceb9fc81eeee0e8e9c1bd0cdf5","4":"036e378bcf78738ddf68859293c69778035740e41138ab183c94f8fee7572214c7","8":"03909d73beaf28edfb283dbeb8da321afd40651e8902fcf5454ecc7d69788626c0","16":"028a36f0e6638ea7466665fe174d958212723019ec08f9ce6898d897f88e68aa5d","32":"03a97a40e146adee2687ac60c2ba2586a90f970de92a9d0e6cae5a4b9965f54612","64":"03ce86f0c197aab181ddba0cfc5c5576e11dfd5164d9f3d4a3fc3ffbbf2e069664","128":"0284f2c06d938a6f78794814c687560a0aabab19fe5e6f30ede38e113b132a3cb9","256":"03b99f475b68e5b4c0ba809cdecaae64eade2d9787aa123206f91cd61f76c01459","512":"03d4db82ea19a44d35274de51f78af0a710925fe7d9e03620b84e3e9976e3ac2eb","1024":"031fbd4ba801870871d46cf62228a1b748905ebc07d3b210daf48de229e683f2dc","2048":"0276cedb9a3b160db6a158ad4e468d2437f021293204b3cd4bf6247970d8aff54b","4096":"02fc6b89b403ee9eb8a7ed457cd3973638080d6e04ca8af7307c965c166b555ea2","8192":"0320265583e916d3a305f0d2687fcf2cd4e3cd03a16ea8261fda309c3ec5721e21","16384":"036e41de58fdff3cb1d8d713f48c63bc61fa3b3e1631495a444d178363c0d2ed50","32768":"0365438f613f19696264300b069d1dad93f0c60a37536b72a8ab7c7366a5ee6c04","65536":"02408426cfb6fc86341bac79624ba8708a4376b2d92debdf4134813f866eb57a8d","131072":"031063e9f11c94dc778c473e968966eac0e70b7145213fbaff5f7a007e71c65f41","262144":"02f2a3e808f9cd168ec71b7f328258d0c1dda250659c1aced14c7f5cf05aab4328","524288":"038ac10de9f1ff9395903bb73077e94dbf91e9ef98fd77d9a2debc5f74c575bc86","1048576":"0203eaee4db749b0fc7c49870d082024b2c31d889f9bc3b32473d4f1dfa3625788","2097152":"033cdb9d36e1e82ae652b7b6a08e0204569ec7ff9ebf85d80a02786dc7fe00b04c","4194304":"02c8b73f4e3a470ae05e5f2fe39984d41e9f6ae7be9f3b09c9ac31292e403ac512","8388608":"025bbe0cfce8a1f4fbd7f3a0d4a09cb6badd73ef61829dc827aa8a98c270bc25b0","16777216":"037eec3d1651a30a90182d9287a5c51386fe35d4a96839cf7969c6e2a03db1fc21","33554432":"03280576b81a04e6abd7197f305506476f5751356b7643988495ca5c3e14e5c262","67108864":"03268bfb05be1dbb33ab6e7e00e438373ca2c9b9abc018fdb452d0e1a0935e10d3","134217728":"02573b68784ceba9617bbcc7c9487836d296aa7c628c3199173a841e7a19798020","268435456":"0234076b6e70f7fbf755d2227ecc8d8169d662518ee3a1401f729e2a12ccb2b276","536870912":"03015bd88961e2a466a2163bd4248d1d2b42c7c58a157e594785e7eb34d880efc9","1073741824":"02c9b076d08f9020ebee49ac8ba2610b404d4e553a4f800150ceb539e9421aaeee","2147483648":"034d592f4c366afddc919a509600af81b489a03caf4f7517c2b3f4f2b558f9a41a","4294967296":"037c09ecb66da082981e4cbdb1ac65c0eb631fc75d85bed13efb2c6364148879b5","8589934592":"02b4ebb0dda3b9ad83b39e2e31024b777cc0ac205a96b9a6cfab3edea2912ed1b3","17179869184":"026cc4dacdced45e63f6e4f62edbc5779ccd802e7fabb82d5123db879b636176e9","34359738368":"02b2cee01b7d8e90180254459b8f09bbea9aad34c3a2fd98c85517ecfc9805af75","68719476736":"037a0c0d564540fc574b8bfa0253cca987b75466e44b295ed59f6f8bd41aace754","137438953472":"021df6585cae9b9ca431318a713fd73dbb76b3ef5667957e8633bca8aaa7214fb6","274877906944":"02b8f53dde126f8c85fa5bb6061c0be5aca90984ce9b902966941caf963648d53a","549755813888":"029cc8af2840d59f1d8761779b2496623c82c64be8e15f9ab577c657c6dd453785","1099511627776":"03e446fdb84fad492ff3a25fc1046fb9a93a5b262ebcd0151caa442ea28959a38a","2199023255552":"02d6b25bd4ab599dd0818c55f75702fde603c93f259222001246569018842d3258","4398046511104":"03397b522bb4e156ec3952d3f048e5a986c20a00718e5e52cd5718466bf494156a","8796093022208":"02d1fb9e78262b5d7d74028073075b80bb5ab281edcfc3191061962c1346340f1e","17592186044416":"030d3f2ad7a4ca115712ff7f140434f802b19a4c9b2dd1c76f3e8e80c05c6a9310","35184372088832":"03e325b691f292e1dfb151c3fb7cad440b225795583c32e24e10635a80e4221c06","70368744177664":"03bee8f64d88de3dee21d61f89efa32933da51152ddbd67466bef815e9f93f8fd1","140737488355328":"0327244c9019a4892e1f04ba3bf95fe43b327479e2d57c25979446cc508cd379ed","281474976710656":"02fb58522cd662f2f8b042f8161caae6e45de98283f74d4e99f19b0ea85e08a56d","562949953421312":"02adde4b466a9d7e59386b6a701a39717c53f30c4810613c1b55e6b6da43b7bc9a","1125899906842624":"038eeda11f78ce05c774f30e393cda075192b890d68590813ff46362548528dca9","2251799813685248":"02ec13e0058b196db80f7079d329333b330dc30c000dbdd7397cbbc5a37a664c4f","4503599627370496":"02d2d162db63675bd04f7d56df04508840f41e2ad87312a3c93041b494efe80a73","9007199254740992":"0356969d6aef2bb40121dbd07c68b6102339f4ea8e674a9008bb69506795998f49","18014398509481984":"02f4e667567ebb9f4e6e180a4113bb071c48855f657766bb5e9c776a880335d1d6","36028797018963968":"0385b4fe35e41703d7a657d957c67bb536629de57b7e6ee6fe2130728ef0fc90b0","72057594037927936":"02b2bc1968a6fddbcc78fb9903940524824b5f5bed329c6ad48a19b56068c144fd","144115188075855872":"02e0dbb24f1d288a693e8a49bc14264d1276be16972131520cf9e055ae92fba19a","288230376151711744":"03efe75c106f931a525dc2d653ebedddc413a2c7d8cb9da410893ae7d2fa7d19cc","576460752303423488":"02c7ec2bd9508a7fc03f73c7565dc600b30fd86f3d305f8f139c45c404a52d958a","1152921504606846976":"035a6679c6b25e68ff4e29d1c7ef87f21e0a8fc574f6a08c1aa45ff352c1d59f06","2305843009213693952":"033cdc225962c052d485f7cfbf55a5b2367d200fe1fe4373a347deb4cc99e9a099","4611686018427387904":"024a4b806cf413d14b294719090a9da36ba75209c7657135ad09bc65328fba9e6f","9223372036854775808":"0377a6fe114e291a8d8e991627c38001c8305b23b9e98b1c7b1893f5cd0dda6cad" + "1": "03ba786a2c0745f8c30e490288acd7a72dd53d65afd292ddefa326a4a3fa14c566", + "2": "03361cd8bd1329fea797a6add1cf1990ffcf2270ceb9fc81eeee0e8e9c1bd0cdf5", + "4": "036e378bcf78738ddf68859293c69778035740e41138ab183c94f8fee7572214c7", + "8": "03909d73beaf28edfb283dbeb8da321afd40651e8902fcf5454ecc7d69788626c0", + "16": "028a36f0e6638ea7466665fe174d958212723019ec08f9ce6898d897f88e68aa5d", + "32": "03a97a40e146adee2687ac60c2ba2586a90f970de92a9d0e6cae5a4b9965f54612", + "64": "03ce86f0c197aab181ddba0cfc5c5576e11dfd5164d9f3d4a3fc3ffbbf2e069664", + "128": "0284f2c06d938a6f78794814c687560a0aabab19fe5e6f30ede38e113b132a3cb9", + "256": "03b99f475b68e5b4c0ba809cdecaae64eade2d9787aa123206f91cd61f76c01459", + "512": "03d4db82ea19a44d35274de51f78af0a710925fe7d9e03620b84e3e9976e3ac2eb", + "1024": "031fbd4ba801870871d46cf62228a1b748905ebc07d3b210daf48de229e683f2dc", + "2048": "0276cedb9a3b160db6a158ad4e468d2437f021293204b3cd4bf6247970d8aff54b", + "4096": "02fc6b89b403ee9eb8a7ed457cd3973638080d6e04ca8af7307c965c166b555ea2", + "8192": "0320265583e916d3a305f0d2687fcf2cd4e3cd03a16ea8261fda309c3ec5721e21", + "16384": "036e41de58fdff3cb1d8d713f48c63bc61fa3b3e1631495a444d178363c0d2ed50", + "32768": "0365438f613f19696264300b069d1dad93f0c60a37536b72a8ab7c7366a5ee6c04", + "65536": "02408426cfb6fc86341bac79624ba8708a4376b2d92debdf4134813f866eb57a8d", + "131072": "031063e9f11c94dc778c473e968966eac0e70b7145213fbaff5f7a007e71c65f41", + "262144": "02f2a3e808f9cd168ec71b7f328258d0c1dda250659c1aced14c7f5cf05aab4328", + "524288": "038ac10de9f1ff9395903bb73077e94dbf91e9ef98fd77d9a2debc5f74c575bc86", + "1048576": "0203eaee4db749b0fc7c49870d082024b2c31d889f9bc3b32473d4f1dfa3625788", + "2097152": "033cdb9d36e1e82ae652b7b6a08e0204569ec7ff9ebf85d80a02786dc7fe00b04c", + "4194304": "02c8b73f4e3a470ae05e5f2fe39984d41e9f6ae7be9f3b09c9ac31292e403ac512", + "8388608": "025bbe0cfce8a1f4fbd7f3a0d4a09cb6badd73ef61829dc827aa8a98c270bc25b0", + "16777216": "037eec3d1651a30a90182d9287a5c51386fe35d4a96839cf7969c6e2a03db1fc21", + "33554432": "03280576b81a04e6abd7197f305506476f5751356b7643988495ca5c3e14e5c262", + "67108864": "03268bfb05be1dbb33ab6e7e00e438373ca2c9b9abc018fdb452d0e1a0935e10d3", + "134217728": "02573b68784ceba9617bbcc7c9487836d296aa7c628c3199173a841e7a19798020", + "268435456": "0234076b6e70f7fbf755d2227ecc8d8169d662518ee3a1401f729e2a12ccb2b276", + "536870912": "03015bd88961e2a466a2163bd4248d1d2b42c7c58a157e594785e7eb34d880efc9", + "1073741824": "02c9b076d08f9020ebee49ac8ba2610b404d4e553a4f800150ceb539e9421aaeee", + "2147483648": "034d592f4c366afddc919a509600af81b489a03caf4f7517c2b3f4f2b558f9a41a", + "4294967296": "037c09ecb66da082981e4cbdb1ac65c0eb631fc75d85bed13efb2c6364148879b5", + "8589934592": "02b4ebb0dda3b9ad83b39e2e31024b777cc0ac205a96b9a6cfab3edea2912ed1b3", + "17179869184": "026cc4dacdced45e63f6e4f62edbc5779ccd802e7fabb82d5123db879b636176e9", + "34359738368": "02b2cee01b7d8e90180254459b8f09bbea9aad34c3a2fd98c85517ecfc9805af75", + "68719476736": "037a0c0d564540fc574b8bfa0253cca987b75466e44b295ed59f6f8bd41aace754", + "137438953472": "021df6585cae9b9ca431318a713fd73dbb76b3ef5667957e8633bca8aaa7214fb6", + "274877906944": "02b8f53dde126f8c85fa5bb6061c0be5aca90984ce9b902966941caf963648d53a", + "549755813888": "029cc8af2840d59f1d8761779b2496623c82c64be8e15f9ab577c657c6dd453785", + "1099511627776": "03e446fdb84fad492ff3a25fc1046fb9a93a5b262ebcd0151caa442ea28959a38a", + "2199023255552": "02d6b25bd4ab599dd0818c55f75702fde603c93f259222001246569018842d3258", + "4398046511104": "03397b522bb4e156ec3952d3f048e5a986c20a00718e5e52cd5718466bf494156a", + "8796093022208": "02d1fb9e78262b5d7d74028073075b80bb5ab281edcfc3191061962c1346340f1e", + "17592186044416": "030d3f2ad7a4ca115712ff7f140434f802b19a4c9b2dd1c76f3e8e80c05c6a9310", + "35184372088832": "03e325b691f292e1dfb151c3fb7cad440b225795583c32e24e10635a80e4221c06", + "70368744177664": "03bee8f64d88de3dee21d61f89efa32933da51152ddbd67466bef815e9f93f8fd1", + "140737488355328": "0327244c9019a4892e1f04ba3bf95fe43b327479e2d57c25979446cc508cd379ed", + "281474976710656": "02fb58522cd662f2f8b042f8161caae6e45de98283f74d4e99f19b0ea85e08a56d", + "562949953421312": "02adde4b466a9d7e59386b6a701a39717c53f30c4810613c1b55e6b6da43b7bc9a", + "1125899906842624": "038eeda11f78ce05c774f30e393cda075192b890d68590813ff46362548528dca9", + "2251799813685248": "02ec13e0058b196db80f7079d329333b330dc30c000dbdd7397cbbc5a37a664c4f", + "4503599627370496": "02d2d162db63675bd04f7d56df04508840f41e2ad87312a3c93041b494efe80a73", + "9007199254740992": "0356969d6aef2bb40121dbd07c68b6102339f4ea8e674a9008bb69506795998f49", + "18014398509481984": "02f4e667567ebb9f4e6e180a4113bb071c48855f657766bb5e9c776a880335d1d6", + "36028797018963968": "0385b4fe35e41703d7a657d957c67bb536629de57b7e6ee6fe2130728ef0fc90b0", + "72057594037927936": "02b2bc1968a6fddbcc78fb9903940524824b5f5bed329c6ad48a19b56068c144fd", + "144115188075855872": "02e0dbb24f1d288a693e8a49bc14264d1276be16972131520cf9e055ae92fba19a", + "288230376151711744": "03efe75c106f931a525dc2d653ebedddc413a2c7d8cb9da410893ae7d2fa7d19cc", + "576460752303423488": "02c7ec2bd9508a7fc03f73c7565dc600b30fd86f3d305f8f139c45c404a52d958a", + "1152921504606846976": "035a6679c6b25e68ff4e29d1c7ef87f21e0a8fc574f6a08c1aa45ff352c1d59f06", + "2305843009213693952": "033cdc225962c052d485f7cfbf55a5b2367d200fe1fe4373a347deb4cc99e9a099", + "4611686018427387904": "024a4b806cf413d14b294719090a9da36ba75209c7657135ad09bc65328fba9e6f", + "9223372036854775808": "0377a6fe114e291a8d8e991627c38001c8305b23b9e98b1c7b1893f5cd0dda6cad" } ``` diff --git a/tests/11-test.md b/tests/11-test.md index d43f1961..af2922dc 100644 --- a/tests/11-test.md +++ b/tests/11-test.md @@ -3,29 +3,71 @@ The following is a `Proof` with a valid signature. ```json -{"amount":1,"secret":"[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"60f3c9b766770b46caac1d27e1ae6b77c8866ebaeba0b9489fe6a15a837eaa6fcd6eaa825499c72ac342983983fd3ba3a8a41f56677cc99ffd73da68b59e1383\"]}"} +{ + "amount": 1, + "secret": "[\"P2PK\",{\"nonce\":\"859d4935c4907062a6297cf4e663e2835d90d97ecdd510745d32f6816323a41f\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"sigflag\",\"SIG_INPUTS\"]]}]", + "C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "id": "009a1f293253e41e", + "witness": "{\"signatures\":[\"60f3c9b766770b46caac1d27e1ae6b77c8866ebaeba0b9489fe6a15a837eaa6fcd6eaa825499c72ac342983983fd3ba3a8a41f56677cc99ffd73da68b59e1383\"]}" +} ``` The following is a `Proof` with an invalid signature as it is on a different secret. + ```json -{"amount":1,"secret":"[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\"]}"} +{ + "amount": 1, + "secret": "[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]", + "C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "id": "009a1f293253e41e", + "witness": "{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\"]}" +} ``` The following is a `Proof` with 2 signatures required to meet the multi-signature spend condition. + ```json -{"amount":1,"secret":"[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\",\"9a72ca2d4d5075be5b511ee48dbc5e45f259bcf4a4e8bf18587f433098a9cd61ff9737dc6e8022de57c76560214c4568377792d4c2c6432886cc7050487a1f22\"]}"} +{ + "amount": 1, + "secret": "[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]", + "C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "id": "009a1f293253e41e", + "witness": "{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\",\"9a72ca2d4d5075be5b511ee48dbc5e45f259bcf4a4e8bf18587f433098a9cd61ff9737dc6e8022de57c76560214c4568377792d4c2c6432886cc7050487a1f22\"]}" +} ``` The following is a `Proof` with one one signature failing the multi-signature spend condition. + ```json -{"amount":1,"secret":"[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","id":"009a1f293253e41e","witness":"{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\"]}"} +{ + "amount": 1, + "secret": "[\"P2PK\",{\"nonce\":\"0ed3fcb22c649dd7bbbdcca36e0c52d4f0187dd3b6a19efcc2bfbebb5f85b2a1\",\"data\":\"0249098aa8b9d2fbec49ff8598feb17b592b986e62319a4fa488a3dc36387157a7\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"02142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"n_sigs\",\"2\"],[\"sigflag\",\"SIG_INPUTS\"]]}]", + "C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "id": "009a1f293253e41e", + "witness": "{\"signatures\":[\"83564aca48c668f50d022a426ce0ed19d3a9bdcffeeaee0dc1e7ea7e98e9eff1840fcc821724f623468c94f72a8b0a7280fa9ef5a54a1b130ef3055217f467b3\"]}" +} ``` + The following is a `Proof` with a signature from the refund key that is spendable because the locktime is in the past. + ```json -{"amount":1,"id":"009a1f293253e41e","secret":"[\"P2PK\",{\"nonce\":\"902685f492ef3bb2ca35a47ddbba484a3365d143b9776d453947dcbf1ddf9689\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"locktime\",\"21\"],[\"n_sigs\",\"2\"],[\"refund\",\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","witness":"{\"signatures\":[\"710507b4bc202355c91ea3c147c0d0189c75e179d995e566336afd759cb342bcad9a593345f559d9b9e108ac2c9b5bd9f0b4b6a295028a98606a0a2e95eb54f7\"]}"} +{ + "amount": 1, + "id": "009a1f293253e41e", + "secret": "[\"P2PK\",{\"nonce\":\"902685f492ef3bb2ca35a47ddbba484a3365d143b9776d453947dcbf1ddf9689\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"locktime\",\"21\"],[\"n_sigs\",\"2\"],[\"refund\",\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\"],[\"sigflag\",\"SIG_INPUTS\"]]}]", + "C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "witness": "{\"signatures\":[\"710507b4bc202355c91ea3c147c0d0189c75e179d995e566336afd759cb342bcad9a593345f559d9b9e108ac2c9b5bd9f0b4b6a295028a98606a0a2e95eb54f7\"]}" +} ``` The following is a `Proof` with a signature from the refund key that is **not** spendable because the locktime is in the future. + ```json -{"amount":1,"id":"009a1f293253e41e","secret":"[\"P2PK\",{\"nonce\":\"64c46e5d30df27286166814b71b5d69801704f23a7ad626b05688fbdb48dcc98\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"locktime\",\"21\"],[\"n_sigs\",\"2\"],[\"refund\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\"],[\"sigflag\",\"SIG_INPUTS\"]]}]","C":"02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904","witness":"{\"signatures\":[\"f661d3dc046d636d47cb3d06586da42c498f0300373d1c2a4f417a44252cdf3809bce207c8888f934dba0d2b1671f1b8622d526840f2d5883e571b462630c1ff\"]}"} +{ + "amount": 1, + "id": "009a1f293253e41e", + "secret": "[\"P2PK\",{\"nonce\":\"64c46e5d30df27286166814b71b5d69801704f23a7ad626b05688fbdb48dcc98\",\"data\":\"026f6a2b1d709dbca78124a9f30a742985f7eddd894e72f637f7085bf69b997b9a\",\"tags\":[[\"pubkeys\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\",\"03142715675faf8da1ecc4d51e0b9e539fa0d52fdd96ed60dbe99adb15d6b05ad9\"],[\"locktime\",\"21\"],[\"n_sigs\",\"2\"],[\"refund\",\"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798\"],[\"sigflag\",\"SIG_INPUTS\"]]}]", + "C": "02698c4e2b5f9534cd0687d87513c759790cf829aa5739184a3e3735471fbda904", + "witness": "{\"signatures\":[\"f661d3dc046d636d47cb3d06586da42c498f0300373d1c2a4f417a44252cdf3809bce207c8888f934dba0d2b1671f1b8622d526840f2d5883e571b462630c1ff\"]}" +} ``` diff --git a/tests/12-tests.md b/tests/12-tests.md index 8ec314c7..a00518d9 100644 --- a/tests/12-tests.md +++ b/tests/12-tests.md @@ -16,6 +16,7 @@ hash(R1, R2, K, C_): "a4dc034b74338c28c6bc3ea49731f2a24440fc7c4affc08b31a93fc9fb ## DLEQ verification on `BlindSignature` The following is a `BlindSignature` with a **valid** DLEQ proof. + ```shell A: "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" B_: "02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2" diff --git a/tests/13-tests.md b/tests/13-tests.md index 9f35178e..34086884 100644 --- a/tests/13-tests.md +++ b/tests/13-tests.md @@ -5,10 +5,10 @@ The integer representation of a keyset with an ID `009a1f293253e41e` and its corresponding derivation path for a counter of value `{counter}` are ```json -{ - "keyset_id": "009a1f293253e41e", - "keyest_id_int": 864559728, - "derivation_path": "m/129372'/0'/864559728'/{counter}'" +{ + "keyset_id": "009a1f293253e41e", + "keyest_id_int": 864559728, + "derivation_path": "m/129372'/0'/864559728'/{counter}'" } ``` @@ -18,7 +18,7 @@ We derive values starting from the following BIP39 mnemonic. ```json { - "mnemonic": "half depart obvious quality work element tank gorilla view sugar picture humble" + "mnemonic": "half depart obvious quality work element tank gorilla view sugar picture humble" } ``` @@ -26,11 +26,11 @@ The secrets derived for the first five counters from `counter=0` to `counter=4` ```json { - "secret_0": "485875df74771877439ac06339e284c3acfcd9be7abf3bc20b516faeadfe77ae", - "secret_1": "8f2b39e8e594a4056eb1e6dbb4b0c38ef13b1b2c751f64f810ec04ee35b77270", - "secret_2": "bc628c79accd2364fd31511216a0fab62afd4a18ff77a20deded7b858c9860c8", - "secret_3": "59284fd1650ea9fa17db2b3acf59ecd0f2d52ec3261dd4152785813ff27a33bf", - "secret_4": "576c23393a8b31cc8da6688d9c9a96394ec74b40fdaf1f693a6bb84284334ea0" + "secret_0": "485875df74771877439ac06339e284c3acfcd9be7abf3bc20b516faeadfe77ae", + "secret_1": "8f2b39e8e594a4056eb1e6dbb4b0c38ef13b1b2c751f64f810ec04ee35b77270", + "secret_2": "bc628c79accd2364fd31511216a0fab62afd4a18ff77a20deded7b858c9860c8", + "secret_3": "59284fd1650ea9fa17db2b3acf59ecd0f2d52ec3261dd4152785813ff27a33bf", + "secret_4": "576c23393a8b31cc8da6688d9c9a96394ec74b40fdaf1f693a6bb84284334ea0" } ``` @@ -38,11 +38,11 @@ The corresponding blinding factors `r` are ```json { - "r_0": "ad00d431add9c673e843d4c2bf9a778a5f402b985b8da2d5550bf39cda41d679", - "r_1": "967d5232515e10b81ff226ecf5a9e2e2aff92d66ebc3edf0987eb56357fd6248", - "r_2": "b20f47bb6ae083659f3aa986bfa0435c55c6d93f687d51a01f26862d9b9a4899", - "r_3": "fb5fca398eb0b1deb955a2988b5ac77d32956155f1c002a373535211a2dfdc29", - "r_4": "5f09bfbfe27c439a597719321e061e2e40aad4a36768bb2bcc3de547c9644bf9" + "r_0": "ad00d431add9c673e843d4c2bf9a778a5f402b985b8da2d5550bf39cda41d679", + "r_1": "967d5232515e10b81ff226ecf5a9e2e2aff92d66ebc3edf0987eb56357fd6248", + "r_2": "b20f47bb6ae083659f3aa986bfa0435c55c6d93f687d51a01f26862d9b9a4899", + "r_3": "fb5fca398eb0b1deb955a2988b5ac77d32956155f1c002a373535211a2dfdc29", + "r_4": "5f09bfbfe27c439a597719321e061e2e40aad4a36768bb2bcc3de547c9644bf9" } ``` @@ -50,10 +50,10 @@ The corresponding derivation paths are ```json { - "derivation_path_0": "m/129372'/0'/864559728'/0'", - "derivation_path_1": "m/129372'/0'/864559728'/1'", - "derivation_path_2": "m/129372'/0'/864559728'/2'", - "derivation_path_3": "m/129372'/0'/864559728'/3'", - "derivation_path_4": "m/129372'/0'/864559728'/4'" + "derivation_path_0": "m/129372'/0'/864559728'/0'", + "derivation_path_1": "m/129372'/0'/864559728'/1'", + "derivation_path_2": "m/129372'/0'/864559728'/2'", + "derivation_path_3": "m/129372'/0'/864559728'/3'", + "derivation_path_4": "m/129372'/0'/864559728'/4'" } -``` \ No newline at end of file +``` diff --git a/tests/README.md b/tests/README.md index 070b2e39..557ec867 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,2 +1,3 @@ # Test Vectors + The files in this directory contain test vectors for NUTs that warrant them. From b933ead95d677418bd3c459412bb4e22b89a21e4 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Mon, 2 Sep 2024 20:02:21 +0100 Subject: [PATCH 04/27] make nut06 fields optional (#157) --- 06.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/06.md b/06.md index 16ba1d6e..afc7e170 100644 --- a/06.md +++ b/06.md @@ -80,14 +80,14 @@ With the mint's response being of the form `GetInfoResponse`: } ``` -- `name` is the name of the mint and should be recognizable. -- `pubkey` is the hex pubkey of the mint. -- `version` is the implementation name and the version of the software running on this mint separated with a slash "/", -- `description` is a short description of the mint that can be shown in the wallet next to the mint's name. -- `description_long` is a long description that can be shown in an additional field. -- `contact` is an array of contact objects to reach the mint operator. A contact object consists of two fields. The `method` field denotes the contact method (like "email"), the `info` field denotes the identifier (like "contact@me.com"). -- `modt` is the message of the day that the wallet must display to the user. It should only be used to display important announcements to users, such as scheduled maintenances. -- `nuts` indicates each NUT specification that the mint supports and its settings. The settings are defined in each NUT separately. +- (optional) `name` is the name of the mint and should be recognizable. +- (optional) `pubkey` is the hex pubkey of the mint. +- (optional) `version` is the implementation name and the version of the software running on this mint separated with a slash "/". +- (optional) `description` is a short description of the mint that can be shown in the wallet next to the mint's name. +- (optional) `description_long` is a long description that can be shown in an additional field. +- (optional) `contact` is an array of contact objects to reach the mint operator. A contact object consists of two fields. The `method` field denotes the contact method (like "email"), the `info` field denotes the identifier (like "contact@me.com"). +- (optional) `motd` is the message of the day that the wallet must display to the user. It should only be used to display important announcements to users, such as scheduled maintenances. +- (optional) `nuts` indicates each NUT specification that the mint supports and its settings. The settings are defined in each NUT separately. With curl: From 82617273da8cf60107af27e1ad8fef41ecb3bc5a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 3 Sep 2024 17:54:18 +0200 Subject: [PATCH 05/27] NUT-06: add time field (#159) --- 06.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/06.md b/06.md index afc7e170..4458b65b 100644 --- a/06.md +++ b/06.md @@ -38,6 +38,7 @@ With the mint's response being of the form `GetInfoResponse`: } ], "motd": "Message to display to users.", + "time": 1725304480, "nuts": { "4": { "methods": [ @@ -87,6 +88,7 @@ With the mint's response being of the form `GetInfoResponse`: - (optional) `description_long` is a long description that can be shown in an additional field. - (optional) `contact` is an array of contact objects to reach the mint operator. A contact object consists of two fields. The `method` field denotes the contact method (like "email"), the `info` field denotes the identifier (like "contact@me.com"). - (optional) `motd` is the message of the day that the wallet must display to the user. It should only be used to display important announcements to users, such as scheduled maintenances. +- (optional) `time` is the current time set on the server. The value is passed as a Unix timestamp integer. - (optional) `nuts` indicates each NUT specification that the mint supports and its settings. The settings are defined in each NUT separately. With curl: From 69c8e778e0a354aec5a01ed507b808b7808bec2f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 8 Sep 2024 14:58:31 +0200 Subject: [PATCH 06/27] NUT-06: add icon_url field (#160) --------- Co-authored-by: Erik <78821053+swedishfrenchpress@users.noreply.github.com> Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- 06.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/06.md b/06.md index 4458b65b..8c88220b 100644 --- a/06.md +++ b/06.md @@ -38,6 +38,7 @@ With the mint's response being of the form `GetInfoResponse`: } ], "motd": "Message to display to users.", + "icon_url": "https://mint.host/icon.jpg", "time": 1725304480, "nuts": { "4": { @@ -88,6 +89,7 @@ With the mint's response being of the form `GetInfoResponse`: - (optional) `description_long` is a long description that can be shown in an additional field. - (optional) `contact` is an array of contact objects to reach the mint operator. A contact object consists of two fields. The `method` field denotes the contact method (like "email"), the `info` field denotes the identifier (like "contact@me.com"). - (optional) `motd` is the message of the day that the wallet must display to the user. It should only be used to display important announcements to users, such as scheduled maintenances. +- (optional) `icon_url` is the URL pointing to an image to be used as an icon for the mint. Recommended to be squared in shape. - (optional) `time` is the current time set on the server. The value is passed as a Unix timestamp integer. - (optional) `nuts` indicates each NUT specification that the mint supports and its settings. The settings are defined in each NUT separately. From 463cd54ad063bfc22c3fc486369a3f91fdfa6390 Mon Sep 17 00:00:00 2001 From: minibits-cash <138401554+minibits-cash@users.noreply.github.com> Date: Mon, 9 Sep 2024 11:50:48 +0200 Subject: [PATCH 07/27] Add optional description to PostMintQuoteBolt11Request (#144) Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- 04.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/04.md b/04.md index edaf9044..e3f7a28b 100644 --- a/04.md +++ b/04.md @@ -23,11 +23,12 @@ The wallet of `Alice` includes the following `PostMintQuoteBolt11Request` data i ```json { "amount": , - "unit": + "unit": , + "description": } ``` -with the requested `amount` and the `unit`. +with the requested `amount` and the `unit`. An optional `description` can be passed if the mint signals support for it in `MintMethodSetting`. The mint `Bob` then responds with a `PostMintQuoteBolt11Response`: @@ -206,7 +207,8 @@ The settings for this nut indicate the supported method-unit pairs for minting a "method": , "unit": , "min_amount": , - "max_amount": + "max_amount": , + "description": } ``` @@ -219,7 +221,8 @@ Example `MintMethodSetting`: "method": "bolt11", "unit": "sat", "min_amount": 0, - "max_amount": 10000 + "max_amount": 10000, + "description": true } ``` From 82e392b246c2730f6164c6fe73a9af260e8ae484 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Tue, 10 Sep 2024 10:20:59 +0100 Subject: [PATCH 08/27] refactor: one error code file (#161) --- error_codes.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 error_codes.md diff --git a/error_codes.md b/error_codes.md new file mode 100644 index 00000000..6d0a0040 --- /dev/null +++ b/error_codes.md @@ -0,0 +1,32 @@ +# NUT Errors + +| Code | Description | Relevant nuts | +| ----- | ----------------------------------------------- | ---------------------------------------- | +| 10002 | Blinded message of output already signed | [NUT-03][03], [NUT-04][04], [NUT-05][05] | +| 10003 | Token could not be verified | [NUT-03][03], [NUT-05][05] | +| 11001 | Token is already spent | [NUT-03][03], [NUT-05][05] | +| 11002 | Transaction is not balanced (inputs != outputs) | [NUT-02][02], [NUT-03][03], [NUT-05][05] | +| 11005 | Unit in request is not supported | [NUT-04][04], [NUT-05][05] | +| 11006 | Amount outside of limit range | [NUT-04][04], [NUT-06][06] | +| 12001 | Keyset is not known | [NUT-02][02], [NUT-04][04] | +| 12002 | Keyset is inactive, cannot sign messages | [NUT-02][02], [NUT-03][03], [NUT-04][04] | +| 20001 | Quote request is not paid | [NUT-04][04] | +| 20002 | Tokens have already been issued for quote | [NUT-04][04] | +| 20003 | Minting is disabled | [NUT-04][04] | +| 20005 | Quote is pending | [NUT-04][04], [NUT-05][05] | +| 20006 | Invoice already paid | [NUT-05][05] | +| 20007 | Quote is expired | [NUT-04][04], [NUT-05][05] | + +[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 From 8f0c6dedd1d34339f55e3c8b69cff7c7cb1c49fc Mon Sep 17 00:00:00 2001 From: elnosh Date: Tue, 10 Sep 2024 14:03:18 -0500 Subject: [PATCH 09/27] error codes: add nut-05 amount outside of limit code --- error_codes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/error_codes.md b/error_codes.md index 6d0a0040..f3403309 100644 --- a/error_codes.md +++ b/error_codes.md @@ -7,7 +7,7 @@ | 11001 | Token is already spent | [NUT-03][03], [NUT-05][05] | | 11002 | Transaction is not balanced (inputs != outputs) | [NUT-02][02], [NUT-03][03], [NUT-05][05] | | 11005 | Unit in request is not supported | [NUT-04][04], [NUT-05][05] | -| 11006 | Amount outside of limit range | [NUT-04][04], [NUT-06][06] | +| 11006 | Amount outside of limit range | [NUT-04][04], [NUT-05][05] | | 12001 | Keyset is not known | [NUT-02][02], [NUT-04][04] | | 12002 | Keyset is inactive, cannot sign messages | [NUT-02][02], [NUT-03][03], [NUT-04][04] | | 20001 | Quote request is not paid | [NUT-04][04] | From ba0e7a35cb05f215ff8281f8c36dbc6f8faa135e Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:19:17 +0200 Subject: [PATCH 10/27] try: gh-pages (#166) * try: gh-pages * use gh-pages-builder * prettier * only on pushes to main --- .github/workflows/pages.yml | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/pages.yml diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 00000000..c05eb034 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,44 @@ +name: Deploy MkDocs Site to GitHub Pages + +on: + push: + branches: + - main + +permissions: write-all + +jobs: + build-deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: gh-pages-builder + + - name: Copy contents to docs/ + run: | + mkdir docs/ + + - name: Checkout main branch + uses: actions/checkout@v3 + with: + ref: main + path: docs + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + + - name: Install Dependencies + run: pip install -r requirements.txt + + - name: Build the Site + run: mkdocs build --clean + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: ./site From 21e3d55c7adf097989932afd5a73dc17985313a8 Mon Sep 17 00:00:00 2001 From: elnosh Date: Wed, 18 Sep 2024 05:51:25 -0500 Subject: [PATCH 11/27] fix typo in nut-12 tests (#163) --- tests/12-tests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/12-tests.md b/tests/12-tests.md index a00518d9..f38d2027 100644 --- a/tests/12-tests.md +++ b/tests/12-tests.md @@ -36,7 +36,7 @@ B_: "02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2" ## DLEQ verification on `Proof` -The following is a `Prood` with a **valid** DLEQ proof. +The following is a `Proof` with a **valid** DLEQ proof. ```shell A: "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" From 83b682ab85c28e232222989edfb0140e593c3eea Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 18 Sep 2024 12:54:08 +0200 Subject: [PATCH 12/27] small typo refactor of "used in"/"depends on" (#158) --- 05.md | 2 ++ 07.md | 2 ++ 08.md | 4 +++- 09.md | 4 +++- 10.md | 2 ++ 11.md | 4 +++- 13.md | 4 +++- 14.md | 4 +++- 15.md | 4 +++- 17.md | 4 +++- 10 files changed, 27 insertions(+), 7 deletions(-) diff --git a/05.md b/05.md index be55a414..8ec448c0 100644 --- a/05.md +++ b/05.md @@ -2,6 +2,8 @@ `mandatory` +`used in: NUT-08, NUT-15` + --- Melting tokens is the opposite of minting tokens (see [NUT-04][04]). Like minting tokens, melting is a two-step process: requesting a melt quote and melting tokens. Here, we describe both steps. diff --git a/07.md b/07.md index c2ef4440..f0f32469 100644 --- a/07.md +++ b/07.md @@ -2,6 +2,8 @@ `optional` +`used in: NUT-17` + --- With the token state check, wallets can ask the mint whether a specific proof is already spent and whether it is in-flight in a transaction. Wallets can also request the witness data that was used to spend a proof. diff --git a/08.md b/08.md index abb8d0fc..db62531a 100644 --- a/08.md +++ b/08.md @@ -1,6 +1,8 @@ # NUT-08: Lightning fee return -`optional`, `depends on: NUT-05` +`optional` + +`depends on: NUT-05` --- diff --git a/09.md b/09.md index 04c7f4ee..924bb0bd 100644 --- a/09.md +++ b/09.md @@ -1,6 +1,8 @@ # NUT-09: Restore signatures -`optional` `used in: NUT-13` +`optional` + +`used in: NUT-13` --- diff --git a/10.md b/10.md index 99b131e9..18ab303c 100644 --- a/10.md +++ b/10.md @@ -2,6 +2,8 @@ `optional` +`used in: NUT-11, NUT-14` + --- An ordinary ecash token is a set of `Proofs` each with a random string `secret`. To spend such a token in a [swap][03] 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. diff --git a/11.md b/11.md index f6006664..31eb0ae4 100644 --- a/11.md +++ b/11.md @@ -1,6 +1,8 @@ # NUT-11: Pay to Public Key (P2PK) -`optional`, `depends on: NUT-10` +`optional` + +`depends on: NUT-10` --- diff --git a/13.md b/13.md index 04655442..8d4f2ae8 100644 --- a/13.md +++ b/13.md @@ -1,6 +1,8 @@ # NUT-13: Deterministic Secrets -`optional` `depends on: NUT-09` +`optional` + +`depends on: NUT-09` --- diff --git a/14.md b/14.md index f3a07911..7fc8cad9 100644 --- a/14.md +++ b/14.md @@ -1,6 +1,8 @@ # NUT-14: Hashed Timelock Contracts (HTLCs) -`optional` `depends on: NUT-10` +`optional` + +`depends on: NUT-10` --- diff --git a/15.md b/15.md index 8418312c..f898b3d7 100644 --- a/15.md +++ b/15.md @@ -1,6 +1,8 @@ # NUT-15: Partial multi-path payments -`optional` `depends on: NUT-05` +`optional` + +`depends on: NUT-05` --- diff --git a/17.md b/17.md index 37edaa33..127d8156 100644 --- a/17.md +++ b/17.md @@ -1,6 +1,8 @@ # NUT-17: WebSockets -`optional`, `depends on: NUT-07` +`optional` + +`depends on: NUT-07` --- From e5fad20a016a0ca2f4370ab4ae438237de9ab4b9 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:35:14 +0200 Subject: [PATCH 13/27] NUT-05: Remove reference to old `paid` flag and `proof` (#167) * remove reference to old `paid` flag and `proof` * longer --- 05.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/05.md b/05.md index 8ec448c0..5cf215dd 100644 --- a/05.md +++ b/05.md @@ -10,7 +10,7 @@ Melting tokens is the opposite of minting tokens (see [NUT-04][04]). Like mintin In the first request the wallet asks the mint for a quote for a `request` it wants paid by the mint and the `unit` the wallet would like to spend as inputs. The mint responds with a quote that includes a `quote` id and an `amount` the mint demands in the requested unit. For the method `bolt11`, the mint includes a `fee_reserve` field indicating the reserve fee for a Lightning payment. -In the second request, the wallet includes the `quote` id and provides `inputs` that sum up to `amount+fee_reserve` in the first response. For the method `bolt11`, the wallet can also include `outputs` in order for the mint to return overpaid Lightning fees (see [NUT-08][08]). The mint responds with a payment status `paid` and a `proof` of payment. If the request included `outputs`, the mint may respond with `change` for the overpaid fees (see [NUT-08][08]). +In the second request, the wallet includes the `quote` id and provides `inputs` that sum up to `amount+fee_reserve` in the first response. For the method `bolt11`, the wallet can also include `outputs` in order for the mint to return overpaid Lightning fees (see [NUT-08][08]). The mint responds with a payment `state`. If the `state` is `"PAID"` the response includes a `payment_preimage` as a proof of payment. If the request included `outputs`, the mint may respond with `change` for the overpaid fees (see [NUT-08][08]). We limit this document to mint quotes of `unit="sat"` and `method="bolt11"` which requests a bolt11 Lightning payment (typically paid by the mint from its Bitcoin reserves) using ecash denominated in Satoshis. From dc153f350944093c10f8706f5b1f47b68404907f Mon Sep 17 00:00:00 2001 From: findingsov <113792100+findingsov@users.noreply.github.com> Date: Tue, 24 Sep 2024 02:54:17 -0500 Subject: [PATCH 14/27] NUT-09: update to reference NUT-13 (#169) --- 09.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/09.md b/09.md index 924bb0bd..e4b3b32f 100644 --- a/09.md +++ b/09.md @@ -6,7 +6,7 @@ --- -In this document, we describe how wallets can recover blind signatures, and with that their corresponding `Proofs`, by requesting from the mint to reissue the blind signatures. This can be used for a backup recovery of a lost wallet (see [NUT-09][09]) or for recovering the response of an interrupted swap request (see [NUT-03][03]). +In this document, we describe how wallets can recover blind signatures, and with that their corresponding `Proofs`, by requesting from the mint to reissue the blind signatures. This can be used for a backup recovery of a lost wallet (see [NUT-13][13]) or for recovering the response of an interrupted swap request (see [NUT-03][03]). Mints must store the `BlindedMessage` and the corresponding `BlindSignature` in their database every time they issue a `BlindSignature`. Wallets provide the `BlindedMessage` for which they request the `BlindSignature`. Mints only respond with a `BlindSignature`, if they have previously signed the `BlindedMessage`. Each returned `BlindSignature` also contains the `amount` and the keyset `id` (see [NUT-00][00]) which is all the necessary information for a wallet to recover a `Proof`. @@ -43,3 +43,4 @@ The returned arrays `outputs` and `signatures` are of the same length and for ev [07]: 07.md [09]: 09.md [11]: 11.md +[13]: 13.md From 25885cd218e122ff9f8b57fc3b729d8e3c13c891 Mon Sep 17 00:00:00 2001 From: Leonardo Escuer <47948594+lescuer97@users.noreply.github.com> Date: Tue, 15 Oct 2024 20:25:31 +0200 Subject: [PATCH 15/27] README: nutmix update (#177) --------- Co-authored-by: Pavol Rusnak --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index dcf98981..e0ca5195 100644 --- a/README.md +++ b/README.md @@ -20,19 +20,19 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio ### Optional -| # | Description | Wallets | Mints | -| -------- | --------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------- | -| [07][07] | Token state check | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd] | -| [08][08] | Overpaid Lightning fees | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd] | -| [09][09] | Signature restore | [Nutshell][py], [cdk-cli], [cashu-ts][ts], [gonuts] | [Nutshell][py], [cdk-mintd] | -| [10][10] | Spending conditions | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | -| [11][11] | Pay-To-Pubkey (P2PK) | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | -| [12][12] | DLEQ proofs | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd] | -| [13][13] | Deterministic secrets | [Nutshell][py], [Moksha][moksha], [cashu-ts][ts], [cdk-cli], [gonuts] | - | -| [14][14] | Hashed Timelock Contracts (HTLCs) | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd] | -| [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py] | -| [16][16] | Animated QR codes | [Cashu.me][cashume] | - | -| [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] | +| # | Description | Wallets | Mints | +| -------- | --------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------- | +| [07][07] | Token state check | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd], [nutmix] | +| [08][08] | Overpaid Lightning fees | [Nutshell][py], [Moksha][moksha], [Nutstash][ns], [cashu-ts][ts], [cdk-cli] | [Nutshell][py], [Moksha][moksha], [cdk-mintd], [nutmix] | +| [09][09] | Signature restore | [Nutshell][py], [cdk-cli], [cashu-ts][ts], [gonuts] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [10][10] | Spending conditions | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [11][11] | Pay-To-Pubkey (P2PK) | [Nutshell][py], [cdk-cli], [cashu-ts][ts] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [12][12] | DLEQ proofs | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [13][13] | Deterministic secrets | [Nutshell][py], [Moksha][moksha], [cashu-ts][ts], [cdk-cli], [gonuts] | - | +| [14][14] | Hashed Timelock Contracts (HTLCs) | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd], [nutmix] | +| [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py], [nutmix] | +| [16][16] | Animated QR codes | [Cashu.me][cashume] | - | +| [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] | #### Wallets: From ebed5baab0467cd000dfa2cfad28a3cf7a944972 Mon Sep 17 00:00:00 2001 From: Egge <80262989+Egge21M@users.noreply.github.com> Date: Fri, 18 Oct 2024 19:30:13 +0200 Subject: [PATCH 16/27] NUT-18: Payment Requests (#124) * added v1 draft * updated reference implementation * updated referece Impl. + began formatting * formatting * fixed typo & removed ref impl * changed transport + token * suggestions * fix * remove TokenV4 JSON, instead use mint unit proofs * add to readme * fix transport and change tag * change tags to support multiple values * remove NIP-04 * remove TokenV4 JSON, instead use mint unit proofs * add to readme * fix transport and change tag * change tags to support multiple values * remove NIP-04 * readd nutix * prettier * Update 18.md Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com> * remove wrong line * add example * prettier --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> Co-authored-by: gudnuf Co-authored-by: ok300 <106775972+ok300@users.noreply.github.com> --- 18.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 6 ++- 2 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 18.md diff --git a/18.md b/18.md new file mode 100644 index 00000000..7b2b3e93 --- /dev/null +++ b/18.md @@ -0,0 +1,129 @@ +# NUT-18: Payment Requests + +`optional` + +--- + +This NUT introduces a standardised format for payment requests, that supply a sending wallet with all information necessary to complete the transaction. This enables many use-cases where a transaction is better initiated by the receiver (e.g. point of sale). + +## Flow + +1. Receiver creates a payment request, encodes it and displays it to the sender +2. Sender scans the request and constructs a matching token +3. Sender sends the token according to the transport specified in the payment request +4. Receiver receives the token and finalises the transaction + +## Payment Request + +A Payment Request is defined as follows + +```json +{ + "i": str , + "a": int , + "u": str , + "r": bool , + "m": Array[str] , + "d": str , + "t": Array[Transport] +} +``` + +Here, the fields are + +- `i`: Payment id to be included in the payment payload +- `a`: The amount of the requested payment +- `u`: The unit of the requested payment (MUST be set if `a` is set) +- `s`: Whether the payment request is for single use +- `m`: A set of mints from which the payment is requested +- `d`: A human readable description that the sending wallet will display after scanning the request +- `t`: The method of `Transport` chosen to transmit the payment (can be multiple, sorted by preference) + +## Transport + +`Transport` specifies methods for sending the ecash to the receiver. A transport consists of a type and a target. + +```json +{ + "t": str, + "a": str, + "g": Array[Array[str, str]] +} +``` + +- `t`: type of Transport +- `a`: target of Transport +- `g`: optional tags for the Transport + +### Tags + +Tags are an optional array of `[tag, value, value, ...]` tuples that can be used to specify additional features about the transport. A single tag can have multiple values. + +### Transport types + +The supported transport types are described below. + +#### Nostr + +- type: `nostr` +- target: `` +- tags: `[["n", "17"]]` + +The `n` tag specifies the NIPs the receiver supports. At least one tag value MUST be specified. For [NIP-17](https://github.com/nostr-protocol/nips/blob/master/17.md) direct messages, the sender sends a `PaymentRequestPayload` as the message content. + +#### HTTP POST + +- type: `post` +- target: `` + +The execute the payment, the sender makes a `POST` request to the specified endpoint URL with the `PaymentRequestPayload` as the body. + +## Payment payload + +If not specified otherwise, the payload sent to the receiver is a `PaymentRequestPayload` JSON serialized object as follows: + +```json +{ + "id": str , + "memo": str , + "mint": str, + "unit": , + "proofs": Array +} +``` + +Here, `id` is the payment id (corresponding to `i` in request), `memo` is an optional memo to be sent to the receiver with the payment, `mint` is the mint URL from which the ecash is from, `unit` is the unit of the payment, and `proofs` is an array of proofs (see [NUT-00][00], can also include DLEQ proofs). + +## Encoded Request + +The payment request is serialized using CBOR, encoded in `base64_urlsafe`, together with a prefix `creq` and a version `A`: + +`"creq" + "A" + base64(CBOR(PaymentRequest))` + +### Example + +This is an example payment request expressed as JSON: + +```json +{ + "i": "b7a90176", + "a": 10, + "u": "sat", + "m": ["https://nofees.testnut.cashu.space"], + "t": [ + { + "t": "nostr", + "a": "nprofile1qy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9mhwden5te0wfjkccte9curxven9eehqctrv5hszrthwden5te0dehhxtnvdakqqgydaqy7curk439ykptkysv7udhdhu68sucm295akqefdehkf0d495cwunl5", + "g": [["n", "17"]] + } + ] +} +``` + +This payment request serializes to (see [here](https://cbor.nemo157.com/#type=hex&value=a3617482a261694800ffd48b8f5ecf80617081a36161016173784061636331323433356537623834383463336366313835303134393231386166393066373136613532626634613565643334376534386563633133663737333838616358210244538319de485d55bed3b29a642bee5879375ab9e7a620e11e48ba482421f3cfa261694800ad268c4d1f5826617082a3616102617378403133323364336434373037613538616432653233616461346539663166343966356135623461633762373038656230643631663733386634383330376538656561635821023456aa110d84b4ac747aebd82c3b005aca50bf457ebd5737a4414fac3ae7d94da36161016173784035366263626362623763633634303662336661356435376432313734663465666638623434303262313736393236643361353764336333646362623539643537616358210273129c5719e599379a974a626363c333c56cafc0e6d01abe46d5808280789c63616d75687474703a2f2f6c6f63616c686f73743a33333338617563736174)): + +```sh +creqApWF0gaNhdGVub3N0cmFheKlucHJvZmlsZTFxeTI4d3VtbjhnaGo3dW45ZDNzaGp0bnl2OWtoMnVld2Q5aHN6OW1od2RlbjV0ZTB3ZmprY2N0ZTljdXJ4dmVuOWVlaHFjdHJ2NWhzenJ0aHdkZW41dGUwZGVoaHh0bnZkYWtxcWd5ZGFxeTdjdXJrNDM5eWtwdGt5c3Y3dWRoZGh1NjhzdWNtMjk1YWtxZWZkZWhrZjBkNDk1Y3d1bmw1YWeBgmFuYjE3YWloYjdhOTAxNzZhYQphdWNzYXRhbYF4Imh0dHBzOi8vbm9mZWVzLnRlc3RudXQuY2FzaHUuc3BhY2U= +``` + +[00]: 00.md diff --git a/README.md b/README.md index e0ca5195..f0b745f5 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,10 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio | [12][12] | DLEQ proofs | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd], [nutmix] | | [13][13] | Deterministic secrets | [Nutshell][py], [Moksha][moksha], [cashu-ts][ts], [cdk-cli], [gonuts] | - | | [14][14] | Hashed Timelock Contracts (HTLCs) | [Nutshell][py], [cdk-cli] | [Nutshell][py], [cdk-mintd], [nutmix] | -| [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py], [nutmix] | +| [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py] | | [16][16] | Animated QR codes | [Cashu.me][cashume] | - | | [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] | +| [18][18] | Payment requests | [Cashu.me][cashume], [Boardwalk][bwc] | - | #### Wallets: @@ -45,7 +46,7 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio - [Nutstash][ns] - [Cashu.me][cashume] - [Gonuts][gonuts] -- [Boardwalk Cash][bwc] +- [Boardwalk][bwc] #### Mints: @@ -87,3 +88,4 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio [15]: 15.md [16]: 16.md [17]: 17.md +[18]: 18.md From ea8d7d6611f2cda04bb02731c077c19697c2c487 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 18 Oct 2024 21:51:02 +0200 Subject: [PATCH 17/27] NUT-18: fix typo (#178) --- 18.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/18.md b/18.md index 7b2b3e93..e1062a5d 100644 --- a/18.md +++ b/18.md @@ -22,7 +22,7 @@ A Payment Request is defined as follows "i": str , "a": int , "u": str , - "r": bool , + "s": bool , "m": Array[str] , "d": str , "t": Array[Transport] From d69242ff97c6f53849350c724c036c66a8425276 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 30 Oct 2024 00:55:29 +0100 Subject: [PATCH 18/27] NUT-07: explicitly mention order (#181) * mention order * refer to NUT-07 in P2PK and HTLCs * prettier * fix * Ys --- 07.md | 9 ++++++--- 10.md | 1 + 11.md | 2 +- 14.md | 2 ++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/07.md b/07.md index f0f32469..c4caf4eb 100644 --- a/07.md +++ b/07.md @@ -2,7 +2,7 @@ `optional` -`used in: NUT-17` +`used in: NUT-17, NUT-11, NUT-14` --- @@ -50,7 +50,7 @@ Where the elements of the array in `Ys` are the hexadecimal representation of th **Response** of `Bob`: -`Bob` will respond with a `PostCheckStateResponse` +`Bob` responds with a `PostCheckStateResponse`: ```json { @@ -65,9 +65,11 @@ Where the elements of the array in `Ys` are the hexadecimal representation of th } ``` +The elements of the `states` array MUST be returned in the same order as the corresponding `Ys` checked in the request. + - `Y` corresponds to the `Proof` checked in the request. - `state` is an enum string field with possible values `"UNSPENT"`, `"PENDING"`, `"SPENT"` -- `witness` is the serialized witness data that was used to spend the `Proof` if the token required it such as in the case of P2PK (see [NUT-11][11]). +- `witness` is the serialized witness data that was used to spend the `Proof` if the token has a [NUT-10][10] spending condition that requires a witness such as in the case of P2PK ([NUT-11][11]) or HTLCs ([NUT-14][14]). With curl: @@ -110,3 +112,4 @@ Where `Y` belongs to the provided `Proof` to check in the request, `state` indic [10]: 10.md [11]: 11.md [12]: 12.md +[14]: 14.md diff --git a/10.md b/10.md index 18ab303c..70f52e62 100644 --- a/10.md +++ b/10.md @@ -54,6 +54,7 @@ kind , Example use cases of this secret format are - [NUT-11][11]: Pay-to-Public-Key (P2PK) +- [NUT-14][14]: Hashed Timelock Contracts (HTLCs) [00]: 00.md [01]: 01.md diff --git a/11.md b/11.md index 31eb0ae4..b84619ff 100644 --- a/11.md +++ b/11.md @@ -118,7 +118,7 @@ The `B_` of each output is **signed as bytes** which comes from the original hex } ``` -The `signatures` are an array of signatures in hex. +The `signatures` are an array of signatures in hex. The witness for a spent proof can be obtained with a `Proof` state check (see [NUT-07][07]). ### Multisig diff --git a/14.md b/14.md index 7fc8cad9..8dbeac63 100644 --- a/14.md +++ b/14.md @@ -58,6 +58,8 @@ See [NUT-11][11] for a description of the signature scheme, the additional use o } ``` +The witness for a spent proof can be obtained with a `Proof` state check (see [NUT-07][07]). + [00]: 00.md [01]: 01.md [02]: 02.md From be7911bf2e6237587373266fe7eeb09885e81218 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Thu, 31 Oct 2024 15:57:38 +0000 Subject: [PATCH 19/27] Update README.md (#183) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0b745f5..b63ab38d 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio | [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py] | | [16][16] | Animated QR codes | [Cashu.me][cashume] | - | | [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] | -| [18][18] | Payment requests | [Cashu.me][cashume], [Boardwalk][bwc] | - | +| [18][18] | Payment requests | [Cashu.me][cashume], [Boardwalk][bwc], [cdk-cli] | - | #### Wallets: From 96891acff7112e439999432b11583e10a61db4e4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 6 Nov 2024 12:35:59 +0100 Subject: [PATCH 20/27] NUT-06: add urls field (#175) --- 06.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/06.md b/06.md index 8c88220b..00973d0c 100644 --- a/06.md +++ b/06.md @@ -39,6 +39,10 @@ With the mint's response being of the form `GetInfoResponse`: ], "motd": "Message to display to users.", "icon_url": "https://mint.host/icon.jpg", + "urls": [ + "https://mint.host", + "http://mint8gv0sq5ul602uxt2fe0t80e3c2bi9fy0cxedp69v1vat6ruj81wv.onion" + ], "time": 1725304480, "nuts": { "4": { @@ -90,6 +94,7 @@ With the mint's response being of the form `GetInfoResponse`: - (optional) `contact` is an array of contact objects to reach the mint operator. A contact object consists of two fields. The `method` field denotes the contact method (like "email"), the `info` field denotes the identifier (like "contact@me.com"). - (optional) `motd` is the message of the day that the wallet must display to the user. It should only be used to display important announcements to users, such as scheduled maintenances. - (optional) `icon_url` is the URL pointing to an image to be used as an icon for the mint. Recommended to be squared in shape. +- (optional) `urls` is the list of endpoint URLs where the mint is reachable from. - (optional) `time` is the current time set on the server. The value is passed as a Unix timestamp integer. - (optional) `nuts` indicates each NUT specification that the mint supports and its settings. The settings are defined in each NUT separately. From 6e5c264d73c99b94c5e7cc60a99aed2c42aa4b80 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:21:50 +0100 Subject: [PATCH 21/27] Fix: nut-15 methods flag (#190) * fix: nut-15 supported flag * prettier * rename to methods --- 15.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/15.md b/15.md index f898b3d7..ac4a65bd 100644 --- a/15.md +++ b/15.md @@ -62,7 +62,7 @@ Example `MultipathPaymentSetting`: ```json { "15": { - [ + "methods": [ { "method": "bolt11", "unit": "sat", @@ -72,7 +72,7 @@ Example `MultipathPaymentSetting`: "method": "bolt11", "unit": "usd", "mpp": true - }, + } ] } } From 95b276488fb3163319c1a94af948020950f31d7d Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:34:58 +0100 Subject: [PATCH 22/27] add missing NUT-06 settings (#191) --- 07.md | 12 ++++++++++++ 08.md | 12 ++++++++++++ 09.md | 12 ++++++++++++ 10.md | 12 ++++++++++++ 11.md | 12 ++++++++++++ 12.md | 12 ++++++++++++ 14.md | 12 ++++++++++++ 15.md | 2 +- 17.md | 2 +- 9 files changed, 86 insertions(+), 2 deletions(-) diff --git a/07.md b/07.md index c4caf4eb..4589120e 100644 --- a/07.md +++ b/07.md @@ -99,6 +99,18 @@ curl -X POST https://mint.host:3338/v1/checkstate -H 'Content-Type: application/ Where `Y` belongs to the provided `Proof` to check in the request, `state` indicates its state, and `witness` is the witness data that was potentially provided in a previous spend operation (can be empty). +## Mint info setting + +The [NUT-06][06] `MintMethodSetting` indicates support for this feature: + +```json +{ + "7": { + "supported": true + } +} +``` + [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/08.md b/08.md index db62531a..d03ffcda 100644 --- a/08.md +++ b/08.md @@ -132,6 +132,18 @@ If the mint has made a successful payment, it will respond the following. The field `change` is an array of `BlindSignatures` that account for the overpaid fees. Notice that the amount has been changed by the mint. `Alice` must take these and generate `Proofs` by unblinding them as described in [NUT-00][00] and as she does in [NUT-04][04] when minting new tokens. After generating the `Proofs`, `Alice` stores them in her database. +## Mint info setting + +The [NUT-06][06] `MintMethodSetting` indicates support for this feature: + +```json +{ + "8": { + "supported": true + } +} +``` + [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/09.md b/09.md index e4b3b32f..73eee23a 100644 --- a/09.md +++ b/09.md @@ -37,6 +37,18 @@ The mint `Bob` then responds with a `PostRestoreResponse`. The returned arrays `outputs` and `signatures` are of the same length and for every entry `outputs[i]`, there is a corresponding entry `signatures[i]`. +## Mint info setting + +The [NUT-06][06] `MintMethodSetting` indicates support for this feature: + +```json +{ + "9": { + "supported": true + } +} +``` + [00]: 00.md [02]: 02.md [03]: 03.md diff --git a/10.md b/10.md index 70f52e62..c9094645 100644 --- a/10.md +++ b/10.md @@ -56,6 +56,18 @@ Example use cases of this secret format are - [NUT-11][11]: Pay-to-Public-Key (P2PK) - [NUT-14][14]: Hashed Timelock Contracts (HTLCs) +## Mint info setting + +The [NUT-06][06] `MintMethodSetting` indicates support for this feature: + +```json +{ + "10": { + "supported": true + } +} +``` + [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/11.md b/11.md index b84619ff..130f0f85 100644 --- a/11.md +++ b/11.md @@ -172,6 +172,18 @@ The following use cases are unlocked using P2PK: - Ecash that is owned by multiple people via the multisignature abilities - Atomic swaps when used in combination with the locktime feature +## Mint info setting + +The [NUT-06][06] `MintMethodSetting` indicates support for this feature: + +```json +{ + "11": { + "supported": true + } +} +``` + [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/12.md b/12.md index a78308b8..1b23d42e 100644 --- a/12.md +++ b/12.md @@ -130,6 +130,18 @@ R1 = ... (same as Alice) If a DLEQ proof is included in a received token, wallets **MUST** verify the proof. +## Mint info setting + +The [NUT-06][06] `MintMethodSetting` indicates support for this feature: + +```json +{ + "12": { + "supported": true + } +} +``` + [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/14.md b/14.md index 8dbeac63..9b76f0d8 100644 --- a/14.md +++ b/14.md @@ -60,6 +60,18 @@ See [NUT-11][11] for a description of the signature scheme, the additional use o The witness for a spent proof can be obtained with a `Proof` state check (see [NUT-07][07]). +## Mint info setting + +The [NUT-06][06] `MintMethodSetting` indicates support for this feature: + +```json +{ + "14": { + "supported": true + } +} +``` + [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/15.md b/15.md index ac4a65bd..52efe74f 100644 --- a/15.md +++ b/15.md @@ -38,7 +38,7 @@ The wallet `Alice` includes the following `PostMeltQuoteBolt11Request` data in i Here, `request` is the bolt11 Lightning invoice to be paid, `unit` is the unit the wallet would like to pay with, and `amount` is the amount for the requested payment. The wallet then pays the returned melt quote the same way as in [NUT-05][05]. -## Settings +## Mint info setting The settings returned in the info endpoint ([NUT-06][06]) indicate that a mint supports this NUT. The mint MUST indicate each `method` and `unit` that supports `mpp`. It can indicate this in an array of objects for multiple `method` and `unit` pairs and the boolean flag `mpp` set to `true`. diff --git a/17.md b/17.md index 127d8156..5603237e 100644 --- a/17.md +++ b/17.md @@ -228,7 +228,7 @@ Wallet: } ``` -## Signaling Support via NUT-06 +## Mint info setting Mints signal websocket support via [NUT-06][06] using the following setting: From 7b53125caa0c96214129746dc7177fe2abe91fa5 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 15 Nov 2024 17:48:51 +0100 Subject: [PATCH 23/27] remove redundant boolean (#192) --- 15.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/15.md b/15.md index 52efe74f..233786ac 100644 --- a/15.md +++ b/15.md @@ -40,7 +40,7 @@ Here, `request` is the bolt11 Lightning invoice to be paid, `unit` is the unit t ## Mint info setting -The settings returned in the info endpoint ([NUT-06][06]) indicate that a mint supports this NUT. The mint MUST indicate each `method` and `unit` that supports `mpp`. It can indicate this in an array of objects for multiple `method` and `unit` pairs and the boolean flag `mpp` set to `true`. +The settings returned in the info endpoint ([NUT-06][06]) indicate that a mint supports this NUT. The mint MUST indicate each `method` and `unit` that supports mpp. It can indicate this in an array of objects for multiple `method` and `unit` pairs. `MultipathPaymentSetting` is of the form: @@ -49,8 +49,7 @@ The settings returned in the info endpoint ([NUT-06][06]) indicate that a mint s [ { "method": , - "unit": , - "mpp": + "unit": }, ... ] @@ -65,13 +64,11 @@ Example `MultipathPaymentSetting`: "methods": [ { "method": "bolt11", - "unit": "sat", - "mpp": true + "unit": "sat" }, { "method": "bolt11", - "unit": "usd", - "mpp": true + "unit": "usd" } ] } From 598c93943e12d4ab08573bc586e66749a05c0b71 Mon Sep 17 00:00:00 2001 From: lollerfirst Date: Sat, 23 Nov 2024 09:22:54 +0100 Subject: [PATCH 24/27] cached responses --- 03.md | 6 ++++++ 04.md | 6 ++++++ 05.md | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/03.md b/03.md index 946e33e6..0d8953c6 100644 --- a/03.md +++ b/03.md @@ -76,6 +76,12 @@ If successful, `Bob` will respond with a `PostSwapResponse` } ``` +## Cached Responses + +`Bob` **MUST** cache every successful `PostSwapResponse` using `PostSwapRequest` as key. +Each cache entry has a TTL (Time-To-Live) of at least 1800 seconds. +In the event of a network error, `Alice` **CAN** replay the same exact request and get the same response. + [00]: 00.md [01]: 01.md [02]: 02.md diff --git a/04.md b/04.md index e3f7a28b..2e97a4a6 100644 --- a/04.md +++ b/04.md @@ -161,6 +161,12 @@ Response of `Bob`: If the invoice was not paid yet, `Bob` responds with an error. In that case, `Alice` **CAN** repeat the same request until the Lightning invoice is settled. +## Cached Responses + +`Bob` **MUST** cache every successful `PostMintBolt11Response` using `PostMintBolt11Request` as key. +Each cache entry has a TTL (Time-To-Live) of at least 1800 seconds. +In the event of a network error, `Alice` **CAN** replay the same exact request and get the same response. + ## Unblinding signatures Upon receiving the `BlindSignatures` from the mint `Bob`, the wallet of `Alice` unblinds them to generate `Proofs` (using the blinding factor `r` and the mint's public key `K`, see BDHKE [NUT-00][00]). The wallet then stores these `Proofs` in its database: diff --git a/05.md b/05.md index 5cf215dd..4d07c48f 100644 --- a/05.md +++ b/05.md @@ -157,6 +157,12 @@ Response `PostMeltQuoteBolt11Response` of `Bob`: } ``` +## Cached Responses + +`Bob` **MUST** cache every successful `PostMeltBolt11Response` using `PostMeltBolt11Request` as key. +Each cache entry has a TTL (Time-To-Live) of at least 1800 seconds. +In the event of a network error, `Alice` **CAN** replay the same exact request and get the same response. + ## Settings The mint's settings for this nut indicate the supported method-unit pairs for melting. They are part of the info response of the mint ([NUT-06][06]) which in this case reads From 67489f20b4103ae8502c02d53db92efab9623596 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 24 Nov 2024 11:37:13 +0100 Subject: [PATCH 25/27] typo Co-authored-by: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> --- 03.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03.md b/03.md index 0d8953c6..152ec450 100644 --- a/03.md +++ b/03.md @@ -78,7 +78,7 @@ If successful, `Bob` will respond with a `PostSwapResponse` ## Cached Responses -`Bob` **MUST** cache every successful `PostSwapResponse` using `PostSwapRequest` as key. +`Bob` **MUST** cache every successful `PostSwapResponse` using `PostSwapRequest` as the key. Each cache entry has a TTL (Time-To-Live) of at least 1800 seconds. In the event of a network error, `Alice` **CAN** replay the same exact request and get the same response. From 74d9f7a130c1c9e6f5e76107049ba3aafc9bfda4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 24 Nov 2024 11:37:21 +0100 Subject: [PATCH 26/27] typo Co-authored-by: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> --- 04.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04.md b/04.md index 2e97a4a6..d57a1b30 100644 --- a/04.md +++ b/04.md @@ -163,7 +163,7 @@ If the invoice was not paid yet, `Bob` responds with an error. In that case, `Al ## Cached Responses -`Bob` **MUST** cache every successful `PostMintBolt11Response` using `PostMintBolt11Request` as key. +`Bob` **MUST** cache every successful `PostMintBolt11Response` using `PostMintBolt11Request` as the key. Each cache entry has a TTL (Time-To-Live) of at least 1800 seconds. In the event of a network error, `Alice` **CAN** replay the same exact request and get the same response. From e9fd20d7ea9a8bb92aa2506a7773ee2977f1668f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 24 Nov 2024 11:37:29 +0100 Subject: [PATCH 27/27] typo Co-authored-by: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> --- 05.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/05.md b/05.md index 4d07c48f..3a0114d6 100644 --- a/05.md +++ b/05.md @@ -159,7 +159,7 @@ Response `PostMeltQuoteBolt11Response` of `Bob`: ## Cached Responses -`Bob` **MUST** cache every successful `PostMeltBolt11Response` using `PostMeltBolt11Request` as key. +`Bob` **MUST** cache every successful `PostMeltBolt11Response` using `PostMeltBolt11Request` as the key. Each cache entry has a TTL (Time-To-Live) of at least 1800 seconds. In the event of a network error, `Alice` **CAN** replay the same exact request and get the same response.