{"id":"884ece447ab65f960542ab69614ba92575d0a9d625ceff37673b9d0719823781","pubkey":"d1678e7ef965374bbea308a1215609a78376dc158277a7d657680f9d5efd5c38","created_at":1768125400,"kind":30817,"tags":[["d","nut-01"],["title","NUT-01: Mint public key exchange"],["summary","How a wallet fetches a mint's active public keys, one per amount, and what a keyset is."],["s","mandatory"],["t","cashu"],["t","ecash"],["t","nut"],["alt","A specification: NUT-01: Mint public key exchange"],["client","openspecs-import"],["published_at","1674849737"],["proxy","https://github.com/cashubtc/nuts/blob/a845dfc998abae501fc3419592d53dc995d34b12/01.md","web"],["x","1c6070287b82d910e57d7c445806f2012d7deef9a12d50c393b55081fea3ca7f"]],"content":"# NUT-01: Mint public key exchange\n\n`mandatory`\n\n---\n\nThis 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]).\n\n## Description\n\nWallet 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_.\n\nThe mint responds only with its `active` keysets. Keysets are `active` if the mint will sign outputs 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]).\n\nNote 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]).\n\n## Supported Currency Units\n\nA mint may support any currency unit(s) they can mint ([NUT-04][04]) and melt([NUT-05][05]), either directly or indirectly, including:\n\n- `btc`: Bitcoin (Minor Unit: 8) - though use of the `sat` unit is generally preferred\n- `sat`: Bitcoin's Minor Unit (ie: `100,000,000 sat = 1 bitcoin`)\n- `msat`: defined as 1/1000th of a `sat` (ie: `1,000 msat = 1 sat`)\n- `auth`: reserved for Blind Authentication (see [NUT-22][22]).\n- [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html) currency codes (eg: `usd`, `eur`, `gbp`)\n- Stablecoin currency codes (eg: `usdt`, `usdc`, `eurc`, `gyen`)\n\n> [!IMPORTANT]\n> For Bitcoin, ISO 4217 currencies (and stablecoins pegged to those currencies), Keyset amount values **MUST** represent an amount in the Minor Unit of that currency. Where the Minor Unit of a currency is \"`0`\", amounts represent whole units. For example:\n>\n> - `usd` (Minor Unit: 2) `<amount_1> = 1 cent (0.01 USD)`\n> - `jpy` (Minor Unit: 0) `<amount_1> = 1 JPY`\n> - `bhd` (Minor Unit: 3) `<amount_1> = 1 fils (0.001 BHD)`\n> - `btc` (Minor Unit: 8) `<amount_1> = 1 sat (0.00000001 BTC)`\n> - `eurc` (Pegged to EUR, so Minor Unit: 2) `<amount_1> = 1 cent (0.01 EURC)`\n> - `gyen` (Pegged to JPY, so Minor Unit: 0) `<amount_1> = 1 GYEN`\n\n## Keyset generation\n\nKeysets 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]).\n\nKeys in Keysets are maps of the form `{<amount_1> : <mint_pubkey_1>, <amount_2> : <mint_pubkey_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 [NUT-00][00]). The mint **MUST** use the [compressed Secp256k1 public key format](https://learnmeabitcoin.com/technical/public-key#public-key-format) to represent its public keys.\n\n## Example\n\nRequest of `Alice`:\n\n```http\nGET https://mint.host:3338/v1/keys\n```\n\nWith curl:\n\n```bash\ncurl -X GET https://mint.host:3338/v1/keys\n```\n\nResponse `GetKeysResponse` of `Bob`:\n\n```json\n{\n  \"keysets\": [\n    {\n      \"id\": <keyset_id_hex_str>,\n      \"unit\": <currency_unit_str>,\n      \"active\": <bool>,\n      \"input_fee_ppk\": <int|null>,\n      \"final_expiry\": <unix_timestamp_int|null>\n      \"keys\": {\n        <amount_int>: <public_key_str>,\n        ...\n      }\n    }\n  ]\n}\n```\n\nHere, `active` indicates whether the mint will sign new outputs with this keyset, and `input_fee_ppk` is the fee in parts per thousand (ppk) per input spent from this keyset (see [NUT-02][02]).\n\n## Example response\n\n```json\n{\n  \"keysets\": [\n    {\n      \"id\": \"009a1f293253e41e\",\n      \"unit\": \"sat\",\n      \"active\": true,\n      \"input_fee_ppk\": 100,\n      \"final_expiry\": 1896187313,\n      \"keys\": {\n          \"1\": \"02194603ffa36356f4a56b7df9371fc3192472351453ec7398b8da8117e7c3e104\",\n          \"2\": \"03b0f36d6d47ce14df8a7be9137712c42bcdd960b19dd02f1d4a9703b1f31d7513\",\n          \"4\": \"0366be6e026e42852498efb82014ca91e89da2e7a5bd3761bdad699fa2aec9fe09\",\n          \"8\": \"0253de5237f189606f29d8a690ea719f74d65f617bb1cb6fbea34f2bc4f930016d\",\n          ...\n      }\n    }\n  ]\n}\n```\n\nNote that for a keyset in an ISO 4217 currency, the key amounts represent values in the Minor Unit of that currency (keys truncated and comments added for clarity):\n\n```json\n{\n  \"keysets\": [\n    {\n      \"id\": \"00a2f293253e41f9\",\n      \"unit\": \"usd\",\n      \"active\": true,\n      \"input_fee_ppk\": 100,\n      \"final_expiry\": 1896187313,\n      \"keys\": {\n          \"1\": \"0229...e101\", // 1 cent (0.01 USD)\n          \"2\": \"03c0...7512\", // 2 cents (0.02 USD)\n          \"4\": \"0376...fe00\", // 4 cents (0.04 USD)\n          \"8\": \"0263...016e\", // 8 cents (0.08 USD)\n          ...\n      }\n    }\n  ]\n}\n```\n\n[00]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crqqpd6d9\n[01]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crznyve7g\n[02]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cry0t0uzl\n[03]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crxuwwl3j\n[04]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crg74fknc\n[05]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cr2dsg4q4\n[06]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crv3ltsuz\n[07]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crwz62n00\n[08]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crs4q9zck\n[09]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crjx9yptm\n[10]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cnqx5tye7\n[11]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cnz43282n\n[12]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cnyf7fzky\n[22]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595erydfxtm8\n","sig":"990d9995333e169f1d1d41e028b5faff498d25196b3bd291c780dfa10ff2536001b3752a982d566d04d602f17f3876538cb9e9767906897aa3cfce90303a221e"}