mirror of
https://github.com/Such-Software/smirk-backend-core.git
synced 2026-10-17 15:31:38 +02:00
feat(keys): give an encryption subkey its own row
A targeted XMR or WOW tip has to be sealed to a key that is not the spend
key. That scalar is the spend authority and an ed25519 signing oracle the
dapp bridge already exposes, and as a raw reduced scalar it does not pair
with age's SHA512(seed)[0..32] derivation anyway.
Grin got its second row for free, because a slatepack address is bech32 and
a signing key is hex, so the value alone says which row it belongs in. An
encryption subkey has no such tell: it is 32 opaque bytes that look exactly
like the identity key, so it needs an explicit key_type or the upsert on
(user_id, asset, key_type) overwrites the key sign-in verifies against.
So RegisterKeyRequest gains an optional key_type. Omitted, every shipped
wallet keeps the value-based routing it relies on today. Supplied, it must
name one of primary, enc or slatepack; anything else is a 400 rather than a
row nothing will ever read. One invariant outranks the request: a bech32
Grin address is still refused from the primary row, which is the outage
ddbba30 fixed.
The lookup response gains tip_keys alongside public_keys, applying the
per-asset target server-side. For BTC, LTC and Grin the two maps agree. For
XMR and WOW tip_keys carries the enc row or nothing at all, so a wallet too
old to have published one has no tip target, which is the right answer
rather than a fallback to the spend key.
This commit is contained in:
@@ -3885,6 +3885,17 @@
|
||||
"type": "boolean",
|
||||
"description": "Whether a user owns this username."
|
||||
},
|
||||
"tip_keys": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/PublicKeysInfo",
|
||||
"description": "Per-asset key a sender encrypts a TARGETED tip to, if registered.\n\nSeparate from `public_keys` because for XMR and WOW the two differ: the\npublic key that identifies a Cryptonote wallet is its spend key, and\nencrypting to that is not an option (see `key_type_for_tip`). An asset\nwhose owner has published no usable target is `null` here, which the\nsender reads as \"targeted tip unavailable\", never as \"fall back to the\nidentity key\"."
|
||||
}
|
||||
]
|
||||
},
|
||||
"user_id": {
|
||||
"type": [
|
||||
"string",
|
||||
@@ -4611,6 +4622,13 @@
|
||||
"type": "string",
|
||||
"description": "Asset the key is for (`btc`, `ltc`, `xmr`, `wow`, `grin`)."
|
||||
},
|
||||
"key_type": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "Which row this key belongs in (`primary`, `enc`, `slatepack`).\n\nOmitted by every shipped wallet, and by anything registering the key a\nsignature is verified against. Required for a key whose role cannot be\nread off its own value: an `enc` key is 32 opaque bytes that look exactly\nlike a `primary` one, so without this it would silently overwrite the\nidentity key on `(user_id, asset, key_type)`."
|
||||
},
|
||||
"public_key": {
|
||||
"type": "string",
|
||||
"description": "The public key (format depends on the asset)."
|
||||
|
||||
Reference in New Issue
Block a user