-
Notifications
You must be signed in to change notification settings - Fork 71
NUT-XX - Mint Remote signer standard #250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lescuer97
wants to merge
35
commits into
cashubtc:main
Choose a base branch
from
lescuer97:remote-signer-nut
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+317
−0
Open
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
2490ff2
remote signer nut
lescuer97 d9b2d8f
fix: improved compromise of remote signer
lescuer97 195e120
fix: change of derivation
lescuer97 8e9fd16
standard consolidation
lescuer97 40bb2ba
change integer type
lescuer97 5e65d02
change name to service
lescuer97 b8d31c7
run pretty
lescuer97 c049e08
auth section
lescuer97 58a0363
Update nut-xx.md
lescuer97 0674129
Update nut-xx.md
lescuer97 4b33469
fix spec
lescuer97 d0006f9
Merge branch 'remote-signer-nut' of github.com:lescuer97/nuts into re…
lescuer97 30b4f11
prettier fix
lescuer97 0c051de
test vector
lescuer97 ae8429c
fix: remove oneOf
lescuer97 734332d
add metadata fields
lescuer97 36b043d
fix: protobuf styling
lescuer97 465bf8e
fix: remove proof witness
lescuer97 59c3404
remove unnedded text
lescuer97 a8401f7
fix: bytes for id
lescuer97 f6e41b9
remove amounts
lescuer97 2f0e728
fix: ids as bytes
lescuer97 2add6e5
chore: add version of keyset
lescuer97 5abce61
feat: final_expiry
lescuer97 99e9f8e
add optional to final_expiry
lescuer97 6cdccbf
cleanup file
pokemongogouy f45fddd
fix range of integer
pokemongogouy 4e54ead
prettier
pokemongogouy 2dc81e4
change to use different notation
pokemongogouy fc48eb0
auth test
pokemongogouy 43f2543
check version type
pokemongogouy 01fa60a
add seedphrase constraint and unit string serialization
lescuer97 f4558d4
add comparison table
lescuer97 192e235
change to use uppercase
lescuer97 a91269f
change unit reference warning
lescuer97 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| # NUT-XX: Remote signer communications | ||
|
|
||
| `optional` | ||
|
|
||
| --- | ||
|
|
||
| This NUT define a standard way for Mints to communicate with a remote signer. The mint can protect its private key by isolating it to a service. | ||
|
|
||
| Mints will connect to the signer and ask for validation of proofs as well signing blinded messages. This NUT does not specify the transport method needed to communicate with the mint. | ||
|
|
||
| ## Protocol | ||
|
|
||
| The signer MUST speak the same language using the GRPC protobuf defined in `remote-signer.proto` inside the repository. | ||
|
|
||
| ### Authentication | ||
|
|
||
| The signer and the mint can communicate with each other over different transports. | ||
| The signer MUST NOT accept any request if authentication has not occurred. | ||
|
|
||
| #### Over the Network | ||
|
|
||
| The Mint and the Signer MUST authenticate with each other using mTLS. | ||
|
|
||
| ## Seedphrase usage | ||
|
|
||
| [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic seedphrase must be used for generation | ||
| of the keysets. | ||
|
|
||
| Example: `legal winner thank year wave sausage worth useful legal winner thank yellow` | ||
|
|
||
| ### Canonical unit reference parsing | ||
|
|
||
| Implementations **MUST** accept currency unit labels case-insensitively and ignore leading or trailing ASCII whitespace. When serializing a unit into JSON (e.g., as part of a keyset description in NUT-01 responses), implementations **SHOULD** emit the uppercase representation of the unit so that mints and wallets display consistent labels. | ||
|
|
||
| Before deriving an index, the input label **MUST** be transformed as follows: | ||
|
|
||
| 1. Remove leading and trailing ASCII whitespace characters (space, tab, carriage return, line feed). | ||
| 2. Apply Unicode Normalization Form C (NFC). | ||
| 3. Convert the normalized string to uppercase using Unicode-aware semantics. | ||
|
|
||
| | Input unit | Canonical form | Index | | ||
| | ------------ | -------------- | ------------ | | ||
| | `sat` | `SAT` | `1967237907` | | ||
| | `SAT` | `SAT` | `1967237907` | | ||
| | `nuts` | `NUTS` | `1502388627` | | ||
| | `USD` | `USD` | `577560378` | | ||
| | `usD` | `USD` | `577560378` | | ||
| | `café` | `CAFÉ` | `642348965` | | ||
| | `cafe\u0301` | `CAFÉ` | `642348965` | | ||
| | `eurc` | `EURC` | `1321886550` | | ||
|
|
||
| NOTE: Mints **MUST** make sure that the unit_reference integer has not been repeated before for a different normalized | ||
| unit string. | ||
|
|
||
| ## Generating keys for the signer. | ||
|
|
||
| For compatibility reasons all signers SHOULD implement the following BIP32 derivation path. | ||
|
|
||
| - m = master key | ||
| - 129372' (UTF-8 for 🥜) | ||
| - unit_reference = Big endian encoded integer of the first 4 bytes of the sha256 hash of the canonical unit string reference modulo by 2^31. We modulo because we want to stay inside the `2^31 - 1` range. | ||
| ex: sha256sum('auth')[:4] = bdf49c3c = 3186924604 | ||
| 3186924604 % 2^31 = 1039440956. | ||
| - version: uint32 | ||
| - index_of_amount = index of and the amounts of the keyset as if the where laid in an array. ex: [1, 2, 4, 8, 16, ...] | ||
|
|
||
| `m / 129372' / unit_reference' / version' / index_of_amount'` | ||
|
|
||
| ## Configuration | ||
|
|
||
| The Signer can also be configured to have some rate limiting features. Limiting the amount of minting that can happen by | ||
| time or single action. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| syntax = "proto3"; | ||
|
|
||
| package signatory; | ||
|
|
||
| service Signatory { | ||
| rpc BlindSign(BlindedMessages) returns (BlindSignResponse); | ||
| rpc VerifyProofs(Proofs) returns (BooleanResponse); | ||
| // returns all the keysets for the mint | ||
| rpc Keysets(EmptyRequest) returns (KeysResponse); | ||
| // rotates the keysets | ||
| rpc RotateKeyset(RotationRequest) returns (KeyRotationResponse); | ||
| } | ||
|
|
||
| enum Operation { | ||
| OPERATION_UNSPECIFIED = 0; | ||
| OPERATION_MINT = 1; | ||
| OPERATION_MELT = 2; | ||
| OPERATION_SWAP = 3; | ||
| } | ||
|
|
||
| message BlindSignResponse { | ||
| Error error = 1; | ||
thesimplekid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| BlindSignatures sigs = 2; | ||
| } | ||
|
|
||
| message BlindedMessages { | ||
lescuer97 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| repeated BlindedMessage blinded_messages = 1; | ||
| Operation operation = 2; | ||
| string correlation_id = 3; | ||
| } | ||
|
|
||
| // Represents a blinded message | ||
| message BlindedMessage { | ||
| uint64 amount = 1; | ||
| bytes keyset_id = 2; | ||
| bytes blinded_secret = 3; | ||
| } | ||
|
|
||
| message BooleanResponse { | ||
| Error error = 1; | ||
| bool success = 2; | ||
| } | ||
|
|
||
| message KeyRotationResponse { | ||
| Error error = 1; | ||
| KeySet keyset = 2; | ||
| } | ||
|
|
||
| message KeysResponse { | ||
| Error error = 1; | ||
| SignatoryKeysets keysets = 2; | ||
| } | ||
|
|
||
| message SignatoryKeysets { | ||
| bytes pubkey = 1; | ||
| repeated KeySet keysets = 2; | ||
| } | ||
|
|
||
| message KeySet { | ||
| bytes id = 1; | ||
| CurrencyUnit unit = 2; | ||
| bool active = 3; | ||
| uint64 input_fee_ppk = 4; | ||
| Keys keys = 5; | ||
| uint32 version = 6; | ||
| optional uint64 final_expiry = 7; | ||
| } | ||
|
|
||
| message Keys { | ||
| map<uint64, bytes> keys = 1; | ||
| } | ||
|
|
||
| message RotationRequest { | ||
| CurrencyUnit unit = 1; | ||
| uint64 input_fee_ppk = 2; | ||
| repeated uint64 amounts = 3; | ||
| // unix timestamp for expiration | ||
| optional uint64 final_expiry = 4; | ||
| } | ||
|
|
||
| enum CurrencyUnitType { | ||
| CURRENCY_UNIT_TYPE_UNSPECIFIED = 0; | ||
| CURRENCY_UNIT_TYPE_SAT = 1; | ||
| CURRENCY_UNIT_TYPE_MSAT = 2; | ||
| CURRENCY_UNIT_TYPE_USD = 3; | ||
| CURRENCY_UNIT_TYPE_EUR = 4; | ||
| CURRENCY_UNIT_TYPE_AUTH = 5; | ||
| } | ||
|
|
||
| message CurrencyUnit { | ||
| oneof currency_unit { | ||
| CurrencyUnitType unit = 1; | ||
| string custom_unit = 2; | ||
| } | ||
| } | ||
|
|
||
| message Proofs { | ||
| repeated Proof proof = 1; | ||
| Operation operation = 3; | ||
| string correlation_id = 4; | ||
| } | ||
|
|
||
| message Proof { | ||
| uint64 amount = 1; | ||
| bytes keyset_id = 2; | ||
| bytes secret = 3; | ||
| bytes c = 4; | ||
| } | ||
|
|
||
| message BlindSignatures { | ||
| repeated BlindSignature blind_signatures = 1; | ||
| } | ||
|
|
||
| message BlindSignature { | ||
| uint64 amount = 1; | ||
| bytes keyset_id = 2; | ||
| bytes blinded_secret = 3; | ||
| optional BlindSignatureDLEQ dleq = 4; | ||
| } | ||
|
|
||
| message BlindSignatureDLEQ { | ||
| bytes e = 1; | ||
| bytes s = 2; | ||
| } | ||
|
|
||
| enum ErrorCode { | ||
| ERROR_CODE_UNSPECIFIED = 0; | ||
| ERROR_CODE_AMOUNT_OUTSIDE_LIMIT = 1; | ||
| ERROR_CODE_DUPLICATE_INPUTS_PROVIDED = 2; | ||
| ERROR_CODE_DUPLICATE_OUTPUTS_PROVIDED = 3; | ||
| ERROR_CODE_KEYSET_NOT_KNOWN = 4; | ||
| ERROR_CODE_KEYSET_INACTIVE = 5; | ||
| ERROR_CODE_MINTING_DISABLED = 6; | ||
| ERROR_CODE_COULD_NOT_ROTATE_KEYSET = 7; | ||
| ERROR_CODE_INVALID_PROOF = 8; | ||
| ERROR_CODE_INVALID_BLIND_MESSAGE = 9; | ||
| ERROR_CODE_UNIT_NOT_SUPPORTED = 10; | ||
| } | ||
|
|
||
| message Error { | ||
| ErrorCode code = 1; | ||
| string detail = 2; | ||
| } | ||
|
|
||
| message EmptyRequest {} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| # NUT-XX Test Vectors | ||
|
|
||
| The following are keysets corresponding to the id: `00b5a0580f75cc2f`. | ||
|
|
||
| - `version` = 1 | ||
| - `unit` = sat | ||
|
|
||
| ```json | ||
| { | ||
| "1": "0233501d047ff4058007722d5d24e10a8ff5c723a677be411fff46a3cee9a92cc0", | ||
| "2": "03a09803ce40118b8917fafa08409dbe6e8bb36d76c55f4c58400cd720abaf54cb", | ||
| "4": "02dac058df2e8611098286ef87ee9698f555548784ab4b1a860c79338073ad8c49", | ||
| "8": "025b66b937d65544981817aa9a053a762a7d72a7543c66a54370ea68aa53170a10", | ||
| "16": "027cf2ad5fa02b99ea37b305048562828453d89dfa7defcda1c10f6746f25f7541", | ||
| "32": "0336033cbbc044737bced1fd40b7f0cb0ce08a83aedaa882ed1ced875a1f517879", | ||
| "64": "035be95ecaadbfe67b14f07205d13bbcab5da58bb595c57dfb9b61c5e3e7e4de0e", | ||
| "128": "0232c757957a8f5a14e93a9bbe8852c273b985ad238ce9b4d5a16885d8a761462b", | ||
| "256": "02cbd889df7d38e95dca2ee0e09bc22e3ae57e95975043854a5560a464f970ac1f", | ||
| "512": "02c99a0b72ba8f01c5da765c534e75ae3e5f51e4931bfced18a91df4b9233b168f", | ||
| "1024": "0320527abb6ae3dd6db9da5041ca941be679e953b446614843af7a4393e9ac96bc", | ||
| "2048": "033f9276b0c5f73fbeb0130eab5705a8e878f4191fe251a18cbd918cda3c9e2d5e", | ||
| "4096": "03cf69ed2939be4ac35308560d4423e1a0d96cacf9fe33267c7e6a047bf438e53e", | ||
| "8192": "027c8bfff71352766c3870e9f5f577830bbb44eadfb757fdff9a8cd209c4b22d76", | ||
| "16384": "02ea21bd310828b9e46746eba2ae985626b3a2efc2468db66ae480715dc6deec8a", | ||
| "32768": "027ae7179192282d5b44ac55bff82c13e1ea916ae1edefa33ea64100be7408e015", | ||
| "65536": "028f333c1beada3445cb62108e35d72199925a055c1e7c102c742e1761770f6c62", | ||
| "131072": "03de95cae3614499a3df2d412e91aa09ddef8b8d49e8d652e3798419da86958139", | ||
| "262144": "03c7817c19b4b107eb2ccf2f32b60f9c22a59a1d4a93e492ad01f1505097a654b7", | ||
| "524288": "028aad03886b6ec6b9f628090e9c151a73f025aa949a9686dac1f0b32995a4e8df", | ||
| "1048576": "034bf50a5916d9f112b8fbfe82a5ac914b5bec792b107cf25922c9866f002473e8", | ||
| "2097152": "03d2894e1b1b7ab7497ff69e16d280b630f60ba34fe00edd7c748ae5ee73bc0d1a", | ||
| "4194304": "0285ba0ee2960927de958610b13d63fc29019407eb32c477d9a2d016fda3062a37", | ||
| "8388608": "03d7a4b4b1b8d6b9f2b5966e380a62f8efd53f79d1965e076a716d2fb75e9774a1", | ||
| "16777216": "037a033e2f1df992523df83bcb9aa02cefdadd59882d7949f4500f5493d89fa2fd", | ||
| "33554432": "03014de7af4809599cabc6d6b30e5121b4a88153eb38a7b66dd8e50e3166215ab0", | ||
| "67108864": "0240162a1d2eb1841450de53a6244a625922b14006153d5219dad0fcf0c369c497", | ||
| "134217728": "03f8c6f7b0ee71f66940a33c746c3bf8b1cba793a498dd2fdeb6857552415a4d5d", | ||
| "268435456": "02dc9de15fa1332f5a2c8f85045ea127cbc3407fb8a844b453f38e1c9cdce9ef87", | ||
| "536870912": "0291bdcb1719b5bf447b2885efc84061d1de30b9d1f583d25034059457a2fd739e", | ||
| "1073741824": "02f8a96485e3fa791f57d7f4ef279dd3617b873efbdf673815c49dbf9ce7422b0d", | ||
| "2147483648": "02ff8cf3e3de985bb2f286c98e335a175b2b53a0e0d7fa1f53d642c95a372329a2", | ||
| "4294967296": "02d96196cc54e7506bfe9fdb4a0d691eed2948ecb9b8e81d28d27225287ad5debc", | ||
| "8589934592": "03e64e5664f7ab843f41aaf4c0534d698b3318d140c23cbd2fcc33eece53400dac", | ||
| "17179869184": "034c9a4bf7b4cb8fac6ace994624e5250ddac5ac84541b6c8bd12b71d22719bb2d", | ||
| "34359738368": "0313027c2b106c7dcdee0d806c3343026260276c6793d4d1dfdf79aae30875be31", | ||
| "68719476736": "03081adca96d42cb2ac4ac94e0ea2aac4d9412265ae55ed377e3c0357aa1157253", | ||
| "137438953472": "02fdc4118761739425220ba87dee5ea9fdc1d581abfcb506fb5afabf76e172b798", | ||
| "274877906944": "031dd7cd25f761c8f80828b487bab1cef730f68e8d6f2026b443cc7223862f6c73", | ||
| "549755813888": "02da505eab15744a6fd3fa6b3257bced520d4d294ea94444528fd30d7f90948629", | ||
| "1099511627776": "02bfc54369099958275376ab030f2a085532c8a00ae4d1bbfa5031c64b42d58a47", | ||
| "2199023255552": "032241a5d4d1e988b8ae85f68a381df0e40065ae8c81b1c4f7ea31c87eab2c0d81", | ||
| "4398046511104": "03a681e41990d350cdedd30840f26ad970b4015dd6e6b5c03f7cc99b384bee8762", | ||
| "8796093022208": "033d5293a33cda29d65058d6d3a4b821472574e92414fa052c79f8bdc1cd72faba", | ||
| "17592186044416": "033ddfec40622aaf62d672f43fd05ddb396afd7ad9f00daede45102c890d3a012b", | ||
| "35184372088832": "02564bbdcbed18a8e2d79b2fdad6e5e8a9fe92e853ab23170934d84015cc4b96b0", | ||
| "70368744177664": "02170950642b94d0ed232370d5dd3630b5eb7e73791447fb961b12d8139de975de", | ||
| "140737488355328": "02b2add5a6eb5dc06f706e9dba190ba412c2c7ba240284b336b66ef38a39e51f1c", | ||
| "281474976710656": "03e3e584a4bc1d0a6399f5b6b9355bd67a10ad9f46c8a4283de96854e47eb4357c", | ||
| "562949953421312": "033821262e6a78f29dad81d3133845883a7632a47f51ab1d99a0eae4a5354eef45", | ||
| "1125899906842624": "038db672a61c70dc66b504152ea39b607527f2f59e8ebfdf8d955c38e914661534", | ||
| "2251799813685248": "03dafb9683eac036a422266ddc85b675bf13aeafe0658cad2ec1555c28f4049b28", | ||
| "4503599627370496": "0351733345d4bb491e27bdb221e382d00f2248f2ee7f04dc6f3faab2692fbd296c", | ||
| "9007199254740992": "03f930c1e6c154ca169370adbec7691fd9c11245867a37ae086f7547f5c9e8386f", | ||
| "18014398509481984": "02d700dc30d3cd6be292bddbd5f74c09df784862c785cd763ad6c829be59c21bed", | ||
| "36028797018963968": "03444b9c312900fffbd478e390aa6fdf9d3ffe230239141ecadf0bcee25e379512", | ||
| "72057594037927936": "03af7acedfcfcaf83cfdb7d171ef64723286bd6e0ab90f3629e627e77955917776", | ||
| "144115188075855872": "02e35aef647a881e8c318879fb81b6261df73e385dfbc5ff3fc0ab40f13f5ed560", | ||
| "288230376151711744": "024558ed8e986901e05839c34d17c261c8d93b8cabb5dee83ab805bb5028e5e463", | ||
| "576460752303423488": "024f60a89ba055e009d84a90a13a7860a909fb486a8ffb4315c2f59aff6fbfd929", | ||
| "1152921504606846976": "0311b2a5b91dfaebab4fb125338fd38dab72ec5671e6db5f468cb1477970ea3876", | ||
| "2305843009213693952": "02aeaa116d930767b5143cac922511c0e093beee5a2850f67490f5a5bb44a8af76", | ||
| "4611686018427387904": "02bf7003847bc8e7ad35ea5c8975e3fdde8d1c43ef540d250cf2dc75792c733647", | ||
| "9223372036854775808": "0376b06a13092fbb679f6e7a90ce877c37d5a20714a65567177a91a0479b3e86a9" | ||
| } | ||
| ``` | ||
|
|
||
| Keyset id: `00e1cf6079abb988`. | ||
|
|
||
| - `version` = 1 | ||
| - `unit` = auth | ||
|
|
||
| ```json | ||
| { | ||
| "1": "025b6c1ca8bb741a6f2321c953266df7bf3f3f2c3be8c54c0a6e41bb00976046a4" | ||
| } | ||
| ``` | ||
|
|
||
| This are the expected integer for unit strings: | ||
|
|
||
| ```json | ||
| { | ||
| "sat" = 866057899 | ||
| "msat" = 1980671987 | ||
| "auth" = 1039440956 | ||
| "eur" = 975082952 | ||
| "usd" = 1443872135 | ||
| "SAT" = 866057899 | ||
| "cafe\u0301" = 84901316 | ||
| } | ||
| ``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you say 'index' here, do you mean 'unit reference'? This is essentially the first mention of 'index' in this doc, and I don't know what it is.
(I see many others have commented already. Apologies in advance if I now ask a few questions that have already been answered 😀)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hi! it just talks about the actual index number that is going to be used later on the derivation path
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hi! it just talks about the actual index number that is going to be used later on the derivation path.
Should probably use better naming