Skip to content

Commit

Permalink
Merge branch 'main' into requests
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Oct 15, 2024
2 parents 0c57a0d + dc153f3 commit 183d2bb
Show file tree
Hide file tree
Showing 29 changed files with 1,247 additions and 362 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -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
22 changes: 22 additions & 0 deletions .github/workflows/prettier.yml
Original file line number Diff line number Diff line change
@@ -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 .
146 changes: 128 additions & 18 deletions 00.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
NUT-00: Notation, Utilization, and Terminology
==========================
# NUT-00: Notation, Utilization, and Terminology

`mandatory`

Expand All @@ -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
Expand All @@ -37,20 +34,21 @@ 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
- `counter` uint32 counter(byte order little endian) incremented from 0 until a point is found that lies on the curve

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

Expand All @@ -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`

Expand All @@ -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,
Expand All @@ -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
Expand All @@ -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
Expand All @@ -122,27 +122,34 @@ We use the following format for token serialization:
cashu[version][token]
```

#### V3 tokens
`cashu` is the Cashu token prefix. `[version]` is a single `base64_urlsafe` character to denote the token format version.

##### URI tags

Wallets serialize tokens in a `base64_urlsafe` format (base64 encoding with `/` replaced by `_` and `+` by `-`).
To make Cashu tokens clickable on the web, we use the URI scheme `cashu:`. An example of a serialized token with URI tag is

```sh
cashu[version][base64_token_json]
cashu:cashuAeyJwcm9vZn...
```

`cashu` is the Cashu token prefix. `[version]` is a single `base64_urlsafe` character to denote the token format version (starting with `A` for the present token format). `[base64_token_json]` is the token JSON serialized in `base64_urlsafe`. A `[base64_token_json]` should be cleared of any whitespace before serializing.
### V3 tokens

> _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`.

##### URI tags
##### Format

To make Cashu tokens clickable on the web, we use the URI scheme `cashu:`. A serialized token with URI tag becomes
V3 tokens are base64-encoded JSON objects. The token format supports tokens from multiple mints. The JSON is serialized with a `base64_urlsafe` (base64 encoding with `/` replaced by `_` and `+` by `-`). `base64_urlsafe` strings may have padding characters (usually `=`) at the end which can be omitted. Clients need to be able to decode both cases.

```sh
cashu:cashuAeyJwcm9vZn...
cashuA[base64_token_json]
```

`[base64_token_json]` is the token JSON serialized in `base64_urlsafe`. `[base64_token_json]` should be cleared of any whitespace before serializing.

##### Token format

The deserialized `base64_token_json` is
Expand All @@ -160,10 +167,12 @@ The deserialized `base64_token_json` is
"memo": str <optional>
}
```
`mint` is the mint URL, `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

##### Example JSON
Below is a TokenV3 JSON before `base64_urlsafe` serialization.

```json
{
Expand Down Expand Up @@ -192,10 +201,111 @@ The deserialized `base64_token_json` is
```

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.

##### Version

This token format has the `[version]` value `B`.

##### Format

Wallets serialize tokens in a `base64_urlsafe` format (base64 encoding with `/` replaced by `_` and `+` by `-`). `base64_urlsafe` strings may have padding characters (usually `=`) at the end which can be omitted. Clients need to be able to decode both cases.

```sh
cashuB[base64_token_cbor]
```

##### Token format

The deserialized `base64_token_cbor` is a JSON of the same form as a TokenV4 but with shorter keys and data represented as binary data (`bytes`) instead of hex strings (`hex_str`). Note that we have expanded what is called `Proofs` in TokenV3 (called `p` here with TokenV4) showing that its values are also different from the TokenV3 serialization.

```json
{
"m": str, // mint URL
"u": str, // unit
"d": str <optional>, // memo
"t": [
{
"i": bytes, // keyset ID
"p": [ // proofs with this keyset ID
{
"a": int, // amount
"s": str, // secret
"c": bytes, // signature
"d": { <optional> // DLEQ proof
"e": bytes,
"s": bytes,
"r": bytes
},
"w": str <optional> // witness
},
...
]
},
...
],
}
```

`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.

##### Example

Below is a TokenV4 JSON before CBOR and `base64_urlsafe` serialization.

```json
{
"t": [
{
"i": h'00ffd48b8f5ecf80',
"p": [
{
"a": 1,
"s": "acc12435e7b8484c3cf1850149218af90f716a52bf4a5ed347e48ecc13f77388",
"c": h'0244538319de485d55bed3b29a642bee5879375ab9e7a620e11e48ba482421f3cf',
},
],
},
{
"i": h'00ad268c4d1f5826',
"p": [
{
"a": 2,
"s": "1323d3d4707a58ad2e23ada4e9f1f49f5a5b4ac7b708eb0d61f738f48307e8ee",
"c": h'023456aa110d84b4ac747aebd82c3b005aca50bf457ebd5737a4414fac3ae7d94d',
},
{
"a": 1,
"s": "56bcbcbb7cc6406b3fa5d57d2174f4eff8b4402b176926d3a57d3c3dcbb59d57",
"c": h'0273129c5719e599379a974a626363c333c56cafc0e6d01abe46d5808280789c63',
},
],
},
],
"m": "http://localhost:3338",
"u": "sat",
}
```

The `h''` values are `bytes` but displayed as hex strings here.

We serialize this JSON using CBOR which can be seen [here](https://cbor.nemo157.com/#type=hex&value=a3617482a261694800ffd48b8f5ecf80617081a36161016173784061636331323433356537623834383463336366313835303134393231386166393066373136613532626634613565643334376534386563633133663737333838616358210244538319de485d55bed3b29a642bee5879375ab9e7a620e11e48ba482421f3cfa261694800ad268c4d1f5826617082a3616102617378403133323364336434373037613538616432653233616461346539663166343966356135623461633762373038656230643631663733386634383330376538656561635821023456aa110d84b4ac747aebd82c3b005aca50bf457ebd5737a4414fac3ae7d94da36161016173784035366263626362623763633634303662336661356435376432313734663465666638623434303262313736393236643361353764336333646362623539643537616358210273129c5719e599379a974a626363c333c56cafc0e6d01abe46d5808280789c63616d75687474703a2f2f6c6f63616c686f73743a33333338617563736174). The resulting bytes are then serialized to a string using `base64_urlsafe` and the prefix `cashuB` is added. This leaves us with the following serialized TokenV4:

```
cashuBo2F0gqJhaUgA_9SLj17PgGFwgaNhYQFhc3hAYWNjMTI0MzVlN2I4NDg0YzNjZjE4NTAxNDkyMThhZjkwZjcxNmE1MmJmNGE1ZWQzNDdlNDhlY2MxM2Y3NzM4OGFjWCECRFODGd5IXVW-07KaZCvuWHk3WrnnpiDhHki6SCQh88-iYWlIAK0mjE0fWCZhcIKjYWECYXN4QDEzMjNkM2Q0NzA3YTU4YWQyZTIzYWRhNGU5ZjFmNDlmNWE1YjRhYzdiNzA4ZWIwZDYxZjczOGY0ODMwN2U4ZWVhY1ghAjRWqhENhLSsdHrr2Cw7AFrKUL9Ffr1XN6RBT6w659lNo2FhAWFzeEA1NmJjYmNiYjdjYzY0MDZiM2ZhNWQ1N2QyMTc0ZjRlZmY4YjQ0MDJiMTc2OTI2ZDNhNTdkM2MzZGNiYjU5ZDU3YWNYIQJzEpxXGeWZN5qXSmJjY8MzxWyvwObQGr5G1YCCgHicY2FtdWh0dHA6Ly9sb2NhbGhvc3Q6MzMzOGF1Y3NhdA
```

[00]: 00.md
[01]: 01.md
[02]: 02.md
Expand Down
9 changes: 4 additions & 5 deletions 01.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
NUT-01: Mint public key exchange
==========================
# NUT-01: Mint public key exchange

`mandatory`
`mandatory`

---

This document outlines the exchange of the public keys of the mint `Bob` with the wallet user `Alice`. `Alice` uses the keys to unblind `Bob`'s blind signatures (see [NUT-00][00]).

## 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]).
Expand Down Expand Up @@ -54,6 +52,7 @@ Response `GetKeysResponse` of `Bob`:
```

## Example response

```json
{
"keysets": [
Expand Down
Loading

0 comments on commit 183d2bb

Please sign in to comment.