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

## Example

Request of `Alice`:

```http
GET https://mint.host:3338/keysets
```

With curl:

```bash
curl -X GET https://mint.host:3338/keysets
```

Response of `Bob`:

```json
{
  "keysets": [
    "DSAl9nvvyfva",
    ...
  ]
}
```

## 2.1 - Generating a keyset

A keyset is generated by the mint by a single seed `s` from which the private keys `k_i` are derived, with `i` being the index of the amount value. The derivation for the elements `k_i` goes like this:

```python
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. 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] such that the token can be used to identify which mint or keyset it was generated from. 

### 2.2.1 - Storing the keyset ID in a token

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.

[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
2 - concatenate all (sorted) public keys to one string
3 - HASH_SHA256 the concatenated public keys
4 - take the first 12 characters of the hash
```

An example implementation in Python:

```python
def derive_keyset_id(keys: Dict[int, PublicKey]):
	"""Deterministic derivation keyset_id from set of public keys."""
	sorted_keys = dict(sorted(keys.items()))
	pubkeys_concat = "".join([p.serialize().hex() for _, p in sorted_keys.items()])
	return base64.b64encode(
	hashlib.sha256((pubkeys_concat).encode("utf-8")).digest()
	).decode()[:12]
```

[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