Merge branch 'main' into PostMintResponse_and_mypy

This commit is contained in:
callebtc
2023-01-11 02:59:11 +01:00
12 changed files with 127 additions and 52 deletions

View File

@@ -40,7 +40,7 @@ pip install cashu
To update Cashu, use `pip install cashu -U`.
If you have problems running the command above on Ubuntu, run `sudo apt install -y pip pkg-config`. On macOS, you might have to run `pip install wheel` and `brew install pkg-config`.
If you have problems running the command above on Ubuntu, run `sudo apt install -y pip pkg-config` and `pip install wheel`. On macOS, you might have to run `pip install wheel` and `brew install pkg-config`.
You can skip the entire next section about Poetry and jump right to [Using Cashu](#using-cashu).
@@ -51,8 +51,7 @@ These steps help you install Python via pyenv and Poetry. If you already have Po
```bash
# on ubuntu:
sudo apt install -y build-essential pkg-config libffi-dev libpq-dev zlib1g-dev libssl-dev python3-dev libsqlite3-dev
# on mac: brew install postgres
sudo apt install -y build-essential pkg-config libffi-dev libpq-dev zlib1g-dev libssl-dev python3-dev libsqlite3-dev ncurses-dev libbz2-dev libreadline-dev lzma-dev
# install python using pyenv
curl https://pyenv.run | bash
@@ -71,7 +70,7 @@ source ~/.bashrc
#### Poetry: Install Cashu
```bash
# install cashu
git clone https://github.com/callebtc/cashu.git
git clone https://github.com/callebtc/cashu.git --recurse-submodules
cd cashu
pyenv local 3.9.13
poetry install

View File

@@ -3,31 +3,31 @@
"""
Implementation of https://gist.github.com/RubenSomsen/be7a4760dd4596d06963d67baf140406
Alice (Client):
Bob (Mint):
A = a*G
return A
Bob (Mint):
Alice (Client):
Y = hash_to_curve(secret_message)
r = random blinding factor
B'= Y + r*G
return B'
Alice:
Bob:
C' = a*B'
(= a*Y + a*r*G)
return C'
Bob:
Alice:
C = C' - r*A
(= C' - a*r*G)
(= a*Y)
return C, secret_message
Alice:
Bob:
Y = hash_to_curve(secret_message)
C == a*Y
If true, C must have originated from Alice
If true, C must have originated from Bob
"""
import hashlib

View File

@@ -504,7 +504,6 @@ async def burn(ctx, token: str, all: bool, force: bool):
@coro
async def pending(ctx):
wallet: Wallet = ctx.obj["WALLET"]
await wallet.load_mint()
reserved_proofs = await get_reserved_proofs(wallet.db)
if len(reserved_proofs):
print(f"--------------------------\n")

View File

@@ -1,3 +1,5 @@
# NUT-0 - Notation and Models
Sending user: `Alice`
Receiving user: `Carol`
Mint: `Bob`

60
docs/specs/01.md Normal file
View File

@@ -0,0 +1,60 @@
# NUT-1 - Mint public key exchange
This describes the basic exchange of the public mint keys that the wallet user `Alice` uses to unblind `Bob`'s signature.
## Description
Wallet user `Alice` receives public keys from mint `Bob` via `GET /keys` and stores them in a key-value store like a dictionary. The set of all public keys for each supported amount is called a *keyset*.
Mint `Bob` responds with his *active* [keyset][02]. The active keyset is the keyset a mint currently uses to sign promises with. The active keyset can change over time, for example due to key rotation. A mint MAY support older keysets indefinetely. Note that a mint can support multiple keysets at the same time but will only respond with the active keyset on the endpoint `GET /keys`. A wallet can ask for the keys of a specific (non-active) keyset by using the endpint `GET /keys/{keyset_id}` (see #2 [TODO: Link #2]).
See [TODO: Link #2] for how a wallet deals with multiple keysets.
Keysets are received as a JSON of the form `{<amount_1> : <mint_pubkey_1>, <amount_2> : ...}` for each `<amount_i>` of the amounts the mint `Bob` supports and the corresponding public key `<mint_pubkey_1>`, that is `K_i` (see #0 [TODO: Link #0]).
## Example
Request of `Alice`:
```http
GET https://mint.host:3338/keys
```
With curl:
```bash
curl -X GET https://mint.host:3338/keys
```
Response of `Bob`:
```json
{
"1": "03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38bc",
"2": "03fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de",
"4": "02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303",
"8": "02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528",
...
}
```
[00]: 00.md
[01]: 02.md
[03]: 03.md
[04]: 04.md
[05]: 05.md
[06]: 06.md
[07]: 07.md
[08]: 08.md
[09]: 09.md
[10]: 10.md
[11]: 11.md
[12]: 12.md
[13]: 13.md
[14]: 14.md
[15]: 15.md
[16]: 16.md
[17]: 17.md
[18]: 18.md
[19]: 19.md
[20]: 20.md

View File

@@ -1,8 +1,10 @@
# NUT-2 - Keysets and keyset ID
A keyset is a set of public keys that the mint `Bob` generates and shares with its users. It refers to the set of public keys that each correspond to the amount values that the mint supports (e.g. 1, 2, 4, 8, ...) respectively.
## Requesting mint keyset IDs
A mint can have multiple active keysets at the same time but **MUST** have only one active keyset. A wallet can ask the mint for all active keyset IDs via the `GET /keysets` endpoint. A wallet **CAN** request the list of active keysets from the mint upon startup and, if it does so, **MUST** choose only tokens from its database that have a keyset ID supported by the mint to interact with it.
A mint can have multiple keysets at the same time but **MUST** have only one *active* keyset (see #1 [TODO: Link #1]). A wallet can ask the mint for all active keyset IDs via the `GET /keysets` endpoint. A wallet **CAN** request the list of active keyset IDs from the mint upon startup and, if it does so, **MUST** choose only tokens from its database that have a keyset ID supported by the mint to interact with it.
This is useful in the case a wallet interacts with multiple mints. That way, a wallet always knows which tokens it can use with the mint it is currently interacting with.
@@ -40,17 +42,21 @@ for i in range(MAX_ORDER):
k_i = HASH_SHA256(s + D + i)[:32]
```
Here, `MAX_ORDER` refers to the order of the maximum token value that the mint supports, i.e., `2^MAX_ORDER`. Typically, `MAX_ORDER = 64`. `D` refers to a derivation path that is chosen by the mint to rotate keys. `i` is the string representation of the index of the amount value.
Here, `MAX_ORDER` refers to the order of the maximum token value that the mint supports, i.e., `2^MAX_ORDER`. Typically, `MAX_ORDER = 64`. `D` refers to a derivation path that is chosen by the mint. The derivation path can be used to rotate keys over time or to service multiple parallel mints with a single instance. `i` is the string representation of the index of the amount value, i.e., `0`, `1`, and so on.
## 2.2 - Keyset ID
A keyset ID is an identifier for a specific keyset. It can be derived by anyone who knows the set of public keys of a mint. The keyset ID **CAN** be stored in a Cashu token [TODO: Link to definition of token] if it was generated by a mint corresponding to the keyset.
A keyset ID is an identifier for a specific keyset. It can be derived by anyone who knows the set of public keys of a mint. The keyset ID **CAN** be stored in a Cashu token [TODO: Link to definition of token] such that the token can be used to identify which mint or keyset it was generated from.
A wallet can use the keyset ID in a token to recognize a mint it was issued by. For example, a wallet might store the `MINT_URL` together with the `keyset_id` in its database the first time it receives a keyset from that mint. That way, a wallet can know which mint to contact when it receives a token with a `keyset_id` of a mint that it has interacted with before.
### 2.2.1 - Storing the keyset ID in a token
### 2.2.1 - Deriving the keyset ID
A wallet can use the keyset ID in a token to recognize a mint it was issued by. For example, a wallet might store the `MINT_URL` together with the `keyset_id` in its database the first time it receives a keyset from that mint. That way, a wallet can know which mint to contact when it receives a token with a `keyset_id` of a mint that it has interacted with before.
The mint and its users can derive a keyset ID from the keyset of the mint. To derive the keyset ID of a mint, execute the following steps:
[TODO: V2 tokens include the `MINT_URL` to enable the first contact when a wallet recieves a token from a mint it has never met before.]
### 2.2.2 - Deriving the keyset ID
The mint and the wallets of its users can derive a keyset ID from the keyset of the mint. To derive the keyset ID of a keyset, execute the following steps:
```
1 - sort keyset by amount
@@ -71,6 +77,3 @@ def derive_keyset_id(keys: Dict[int, PublicKey]):
).decode()[:12]
```
### 2.2.2 - Storing the keyset ID in a token
A mint **CAN** add the keyset ID to a `BlindedSignature` during the minting process [TODO: link to blinded signature. TODO: link to /mint]. If a wallet receives a `BlindedSignature` with a keyset ID,

View File

@@ -1,3 +1,5 @@
# NUT-3 - Request mint
Minting tokens is a two-step process: requesting a mint and minting the tokens. Here, we describe the first step. A wallet requests the minting of tokens in exchange for paying a bolt11 Lightning invoice (typically generated by the mint to add funds to its reserves, and typically paid with another Lightning wallet).
To request the minting of tokens, a wallet `Alice` sends a `GET /mint&amount=<amount_sat>` request with the requested amount `<amount_sat>` in satoshis. The mint `Bob` then responds with a Lightning invoice.

View File

@@ -1,3 +1,5 @@
# NUT-4 - Mint tokens
After requesting a mint (see #3 [TODO: Link]) and paying the invoice that was returned by the mint, a wallet proceeds with requesting tokens from the mint in return for paying the invoice.
For that, a wallet sends a `POST /mint&payment_hash=<hash>` request with a JSON body to the mint. The body **MUST** include `BlindedMessages` that are worth a maximum of `<amount_sat>` [TODO: Refer to BlindedMessages]. If successful (i.e. the invoice has been previously paid and the `BlindedMessages` are valid), the mint responds with `Promises` [TODO: Link Promises].

View File

@@ -1,3 +1,5 @@
# NUT-5 - Melting tokens
Melting tokens is the opposite of minting them (see #4): the wallet `Alice` sends `Proofs` to the mint `Bob` together with a bolt11 Lightning invoice that `Alice` wants to be paid. To melt tokens, `Alice` sends a `POST /melt` request with a JSON body to the mint. The `Proofs` included in the request will be burned by the mint and the mint will pay the invoice in exchange.
`Alice`'s request **MUST** include a `MeltRequest` ([TODO: Link MeltRequest]) JSON body with `Proofs` that have at least the amount of the invoice to be paid.

View File

@@ -1,3 +1,5 @@
# NUT-6 - Split tokens
The split operation is the most important component of the Cashu system. The wallet `Alice` can use it to redeem tokens (i.e. receive new ones in return) that she received from `Carol`, or she can split her own 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 basic idea is that `Alice` sends `Bob` a set of `Proof`'s and a set of `BlindedMessage`'s with an equal amount. Additionally, she specifies the `amount` at which she would like to have the split.

36
docs/specs/README.md Normal file
View File

@@ -0,0 +1,36 @@
# Cashu NUTs (Notation, Usage, and Terminology)
| Number | Description | Wallets |
|----------|-------------------------------------------------------------|---------|
| [00][00] | Notation and Models | Python-CLI, Feni, LNbits
| [01][01] | Mint public keys | Python-CLI, Feni, LNbits
| [02][02] | Keysets and keyset IDs | Python-CLI, Feni, LNbits
| [03][03] | Requesting a mint | Python-CLI, Feni, LNbits
| [04][04] | Mint tokens | Python-CLI, Feni, LNbits
| [05][05] | Melt tokens | Python-CLI, Feni, LNbits
| [06][06] | Split tokens | Python-CLI, Feni, LNbits
[00]: 00.md
[01]: 01.md
[02]: 02.md
[03]: 03.md
[04]: 04.md
[05]: 05.md
[06]: 06.md
[07]: 07.md
[08]: 08.md
[09]: 09.md
[10]: 10.md
[11]: 11.md
[12]: 12.md
[13]: 13.md
[14]: 14.md
[15]: 15.md
[16]: 16.md
[17]: 17.md
[18]: 18.md
[19]: 19.md
[20]: 20.md

View File

@@ -1,32 +0,0 @@
`Alice` receives public keys from mint `Bob` via `GET /keys` and stores them in a key-value store like a dictionary.
`Bob` responds with his **active** keyset [TODO: Link #2]. Note that a mint can support multiple keysets at the same time but will only respond with the active keyset. See [TODO: Link #2] for how a wallet deals with multiple keysets.
Keysets are received as a JSON of the form `{<amount_1> : <mint_pubkey_1>, <amount_2> : ...}` for each `<amount_i>` of the amounts the mint `Bob` supports and the corresponding public key `<mint_pubkey_1>`, that is `K_i` (see #0).
## Example
Request of `Alice`:
```http
GET https://mint.host:3338/keys
```
With curl:
```bash
curl -X GET https://mint.host:3338/keys
```
Response of `Bob`:
```json
{
"1": "03a40f20667ed53513075dc51e715ff2046cad64eb68960632269ba7f0210e38bc",
"2": "03fd4ce5a16b65576145949e6f99f445f8249fee17c606b688b504a849cdc452de",
"4": "02648eccfa4c026960966276fa5a4cae46ce0fd432211a4f449bf84f13aa5f8303",
"8": "02fdfd6796bfeac490cbee12f778f867f0a2c68f6508d17c649759ea0dc3547528",
...
}
```