diff --git a/dip-pasta-masternode-shares.md b/dip-pasta-masternode-shares.md
new file mode 100644
index 00000000..3f405f01
--- /dev/null
+++ b/dip-pasta-masternode-shares.md
@@ -0,0 +1,456 @@
+
+ DIP: pasta-masternode-shares
+ Title: Masternode Reward Shares
+ Author(s): Pasta
+ Special-Thanks:
+ Comments-Summary: No comments yet.
+ Status: Draft
+ Type: Standard
+ Created: 2026-06-05
+ License: MIT License
+
+
+## Table of Contents
+
+1. [Abstract](#abstract)
+2. [Motivation](#motivation)
+3. [Prior Work](#prior-work)
+4. [Specification](#specification)
+ 1. [Terminology](#terminology)
+ 2. [Provider Transaction Version](#provider-transaction-version)
+ 3. [Masternode Payout Share](#masternode-payout-share)
+ 4. [Registering a Masternode](#registering-a-masternode)
+ 5. [Updating Masternode Payout Shares](#updating-masternode-payout-shares)
+ 6. [Masternode List State](#masternode-list-state)
+ 7. [Masternode Reward Payments](#masternode-reward-payments)
+ 8. [Validation Rules](#validation-rules)
+ 9. [RPC and JSON Interfaces](#rpc-and-json-interfaces)
+ 10. [Special Transaction Filtering](#special-transaction-filtering)
+5. [Deployment and Compatibility](#deployment-and-compatibility)
+6. [Rationale](#rationale)
+7. [Test Cases](#test-cases)
+8. [Security Considerations](#security-considerations)
+9. [Copyright](#copyright)
+
+## Abstract
+
+This DIP extends [DIP-0003: Deterministic Masternode Lists](dip-0003.md) by
+allowing the owner-controlled portion of a masternode reward to be split across
+multiple payout scripts. A masternode may specify between 1 and 8 distinct owner
+payout entries, each with a basis-point reward share. A masternode with one
+owner uses the same structure as a masternode with multiple owners: one payout
+entry with a reward value of 10000.
+
+The existing operator reward mechanism is preserved. If a non-zero operator
+reward was configured and an operator payout script is set, the operator reward
+is subtracted from the masternode reward first. The remaining owner reward is
+then split across the configured owner payout entries.
+
+## Motivation
+
+Dash masternodes currently support at most two automatic reward recipients: the
+owner payout address and the operator payout address. This is useful when an
+owner delegates operation to a hosting provider, but it does not support direct,
+protocol-enforced reward distribution among multiple masternode share owners.
+
+Without protocol support, shared masternode ownership requires an off-chain
+agreement. One participant receives the masternode reward and then distributes
+funds manually or through an external service. This introduces custodial risk,
+operational delay, accounting complexity, and disputes when the receiving party
+fails to distribute payments correctly.
+
+This DIP allows the blockchain itself to enforce automatic reward distribution
+for the owner-controlled portion of masternode rewards. The registrar owner key
+continues to control masternode registration metadata, including the payout
+split, so this proposal provides protocol-enforced automatic payouts while
+preserving the existing owner-update model from DIP-0003.
+
+## Prior Work
+
+* [DIP-0002: Special Transactions](dip-0002.md)
+* [DIP-0003: Deterministic Masternode Lists](dip-0003.md)
+* [DIP-0004: Simplified Verification of Deterministic Masternode Lists](dip-0004.md)
+
+## Specification
+
+### Terminology
+
+This DIP uses the following terms:
+
+| Term | Definition |
+| --- | --- |
+| Owner reward | The masternode reward amount remaining after subtracting any operator reward. |
+| Payout entry | One owner payout script and its reward share. |
+| Payout list | The ordered list of owner payout entries for a masternode. |
+| Reward share | A `uint16_t` basis-point value. A value of 10000 represents 100 percent. |
+
+### Provider Transaction Version
+
+This DIP defines a new provider transaction payload version:
+
+| Name | Value | Description |
+| --- | --- | --- |
+| `MultiPayout` | 4 | Provider transaction payload version with a unified owner payout list. |
+
+Version 4 provider registration and registrar update transactions replace the
+single `scriptPayout` field with a unified `payouts` field. The unified field is
+used for all owner payout configurations, including the single-owner case.
+
+Version 4 applies to the following special transactions:
+
+| Transaction | Special transaction type | Version 4 change |
+| --- | --- | --- |
+| ProRegTx | 1 | Replaces `scriptPayout` with `payouts`. |
+| ProUpRegTx | 3 | Replaces `scriptPayout` with `payouts`. |
+
+This DIP does not change the existing ProUpServTx operator payout field. The
+operator payout remains a separate operator-controlled service update field.
+
+### Masternode Payout Share
+
+Each owner payout entry has the following structure:
+
+| Field | Type | Size | Description |
+| --- | --- | --- | --- |
+| reward | uint16_t | 2 | Basis-point share of the owner reward. |
+| scriptPayoutSize | compactSize uint | 1-9 | Size of the payout script. |
+| scriptPayout | Script | Variable | Owner payout script. |
+
+The `reward` field is expressed in basis points. Implementations must interpret
+10000 as 100 percent, 5000 as 50 percent, and 100 as 1 percent.
+
+The payout list has the following structure:
+
+| Field | Type | Size | Description |
+| --- | --- | --- | --- |
+| payoutsCount | uint8_t | 1 | Number of payout entries. Must be from 1 to 8. |
+| payouts | MasternodePayoutShare[] | Variable | Ordered owner payout entries. |
+
+The ordering of payout entries is consensus-significant for reward rounding.
+The last payout entry receives the rounding remainder as specified in
+[Masternode Reward Payments](#masternode-reward-payments).
+
+### Registering a Masternode
+
+For version 4 ProRegTx payloads, the ProRegTx structure defined in DIP-0003 is
+modified by replacing `scriptPayout` with `payouts`.
+
+| Field | Type | Size | Description |
+| --- | --- | --- | --- |
+| version | uint16_t | 2 | Provider transaction version number. Set to 4 for this DIP. |
+| type | uint16_t | 2 | Masternode type. |
+| mode | uint16_t | 2 | Masternode mode. |
+| collateralOutpoint | COutpoint | 36 | The collateral outpoint. |
+| netInfo | NetInfo | Variable | Masternode service addressing information. |
+| KeyIdOwner | CKeyID | 20 | The public key hash used for owner-related signing. |
+| PubKeyOperator | BLSPubKey | 48 | The public key used for operator-related signing. |
+| KeyIdVoting | CKeyID | 20 | The public key hash used for voting. |
+| operatorReward | uint16_t | 2 | Operator reward in basis points, from 0 to 10000. |
+| payoutsCount | uint8_t | 1 | Number of owner payout entries. |
+| payouts | MasternodePayoutShare[] | Variable | Owner payout entries. |
+| inputsHash | uint256 | 32 | The SHA256 hash of all transaction input outpoints. |
+| platformNodeID | uint160 | 20 | Node ID derived from the Platform P2P public key. Present only for Evo masternodes. |
+| payloadSigSize | compactSize uint | 1-9 | Size of the signature. |
+| payloadSig | unsigned char[] | Variable | Signature required for external collateral ownership proof. |
+
+For a masternode with one owner, the payout list contains exactly one entry with
+`reward = 10000`.
+
+For version 4 Evo masternode registrations, Platform P2P and HTTPS addressing
+data is encoded in `netInfo` using the extended-address provider transaction
+format. Separate `platformP2PPort` and `platformHTTPPort` fields are not
+serialized in version 4 payloads.
+
+For external collaterals, the collateral ownership sign string must include the
+new payout list representation instead of the previous single payout string. The
+payout list string is produced by concatenating each payout entry in serialized
+order as:
+
+```text
+:
+```
+
+Entries are joined with commas. `` is the Dash address corresponding
+to the entry's `scriptPayout` when the script is a standard address script, or
+the hex representation of the script otherwise. The ProRegTx sign string
+therefore becomes:
+
+```text
+||||
+```
+
+### Updating Masternode Payout Shares
+
+For version 4 ProUpRegTx payloads, the ProUpRegTx structure defined in DIP-0003
+is modified by replacing `scriptPayout` with `payouts`.
+
+| Field | Type | Size | Description |
+| --- | --- | --- | --- |
+| version | uint16_t | 2 | Provider update registrar transaction version number. Set to 4 for this DIP. |
+| proTXHash | uint256 | 32 | The hash of the initial ProRegTx. |
+| mode | uint16_t | 2 | Masternode mode. |
+| PubKeyOperator | BLSPubKey | 48 | The public key used for operator-related signing. |
+| KeyIdVoting | CKeyID | 20 | The public key hash used for voting. |
+| payoutsCount | uint8_t | 1 | Number of owner payout entries. |
+| payouts | MasternodePayoutShare[] | Variable | Owner payout entries. |
+| inputsHash | uint256 | 32 | The SHA256 hash of all transaction input outpoints. |
+| payloadSigSize | compactSize uint | 1-9 | Size of the signature. |
+| payloadSig | unsigned char[] | Variable | Signature of the ProUpRegTx fields, signed by the owner. |
+
+The masternode owner may update the payout list through ProUpRegTx. A payout
+list update does not revive a PoSe-banned masternode, matching existing
+ProUpRegTx behavior.
+
+### Masternode List State
+
+Deterministic masternode state must store the owner payout list for version 4
+masternodes. The previous single `scriptPayout` state field is replaced by the
+unified `payouts` field for version 4 state.
+
+State diffs must report payout-list changes as a single logical field. A
+version 4 state diff that changes any payout entry, payout order, payout script,
+or reward share must include the full replacement payout list.
+
+For compatibility with pre-version-4 masternodes, implementations may internally
+represent legacy `scriptPayout` as a one-entry payout list with `reward = 10000`.
+This compatibility representation must not change the serialization of legacy
+provider transaction payloads or legacy deterministic masternode state.
+
+### Masternode Reward Payments
+
+Masternode reward payment construction proceeds in the following order:
+
+1. Calculate the block's masternode reward using the existing rules.
+2. Apply any Platform credit pool reallocation using the existing rules.
+3. If the selected masternode has a non-zero `operatorReward` and a non-empty
+ operator payout script, calculate:
+
+```text
+operatorAmount = floor(masternodeReward * operatorReward / 10000)
+```
+
+4. Subtract `operatorAmount` from `masternodeReward`. The result is the owner
+ reward.
+5. For each owner payout entry except the last, calculate:
+
+```text
+entryAmount = floor(ownerReward * reward / 10000)
+```
+
+6. The last owner payout entry receives:
+
+```text
+ownerReward - sum(previous owner payout entry amounts)
+```
+
+7. Create one coinbase output for each owner payout entry with a non-zero
+ calculated amount.
+8. If `operatorAmount` is non-zero, create the operator payout output using
+ the existing operator payout script.
+
+The final owner payout entry receives the remainder to guarantee that the total
+owner reward is paid exactly even when integer division truncates earlier
+entries.
+
+Coinbase validation must require every expected masternode payout output by
+amount and script. As with the current masternode payment implementation, the
+relative order of outputs in the coinbase transaction is not consensus
+significant.
+
+### Validation Rules
+
+A version 4 payout list is invalid if any of the following conditions are true:
+
+1. `payoutsCount` is less than 1.
+2. `payoutsCount` is greater than 8.
+3. Any payout entry has `reward` less than 100.
+4. Any payout entry has `reward` greater than 10000.
+5. The sum of all `reward` fields is not exactly 10000.
+6. Any `scriptPayout` is not a P2PKH or P2SH script.
+7. The same payout script appears more than once in the payout list.
+8. A P2PKH payout destination equals the owner key ID.
+9. A P2PKH payout destination equals the voting key ID.
+10. A P2PKH payout destination equals the collateral key ID when the collateral
+ output destination can be extracted as a P2PKH destination.
+
+The 100-basis-point minimum is a consensus anti-dust bound. It prevents
+intentionally tiny micro-owner entries from creating nuisance coinbase outputs.
+It is not a guarantee that every possible future block reward will remain above
+policy dust thresholds forever as the block reward declines.
+
+All existing ProRegTx and ProUpRegTx validation rules from DIP-0003 continue to
+apply unless explicitly replaced by this DIP.
+
+### RPC and JSON Interfaces
+
+RPCs that create ProRegTx or ProUpRegTx transactions must accept a unified
+`payouts` array for version 4 transactions. Each entry contains an address and
+a basis-point reward:
+
+```json
+[
+ {
+ "address": "X...",
+ "reward": 10000
+ }
+]
+```
+
+```json
+[
+ {
+ "address": "X...",
+ "reward": 7000
+ },
+ {
+ "address": "X...",
+ "reward": 3000
+ }
+]
+```
+
+JSON output for version 4 masternodes and provider transaction payloads must
+expose owner payouts through a `payouts` array. This applies to at least:
+
+* Raw transaction JSON for ProRegTx and ProUpRegTx.
+* `protx info`.
+* `protx diff`.
+* `protx listdiff`.
+* Extended Simplified Masternode List JSON.
+
+The `payoutAddress` field is not part of the normative JSON shape for version 4
+masternodes. A single-owner version 4 masternode still reports a one-entry
+`payouts` array with `reward = 10000`.
+
+RPCs that report required or actual masternode payments must expose every
+generated masternode payout output. This applies to at least:
+
+* `masternode winners`.
+* `masternode payments`.
+* `getblocktemplate`.
+
+The existing operator payout reporting remains separate when an operator payout
+output is generated.
+
+### Special Transaction Filtering
+
+Special transaction filters and bloom filters must include every script in a
+version 4 payout list. A filter that matches any owner payout script in the list
+must match the containing ProRegTx or ProUpRegTx in the same manner that a match
+on the current single `scriptPayout` field does.
+
+## Deployment and Compatibility
+
+This DIP is intended to deploy with Dash Core's v24 network upgrade
+(`DEPLOYMENT_V24`). Version 4 ProRegTx and ProUpRegTx payloads are only valid
+after v24 activates.
+
+Before v24 activation:
+
+* Provider transaction versions greater than the current maximum valid version
+ remain invalid.
+* Legacy ProRegTx and ProUpRegTx payload serialization is unchanged.
+* Legacy masternode reward payment behavior is unchanged.
+
+After v24 activation:
+
+* New version 4 registrations may use 1 to 8 owner payout entries.
+* Version 4 registrar updates may change the payout list.
+* Existing legacy masternodes remain valid and continue to use their existing
+ single owner payout script.
+* Existing operator reward behavior remains unchanged.
+
+Implementations should treat legacy single-payout masternodes and version 4
+one-entry payout-list masternodes as equivalent for reward payment purposes, but
+must preserve their distinct serialized provider transaction payloads.
+
+## Rationale
+
+### Unified payout list
+
+Using a payout list for both single-owner and multi-owner masternodes avoids a
+special case where one payout is represented differently from several payouts.
+This makes the new version's semantics clear: every owner reward recipient is a
+payout entry.
+
+### Maximum of 8 owner payout entries
+
+A maximum of 8 owner payout entries provides enough room for common shared
+masternode arrangements while limiting the number of additional coinbase
+outputs, deterministic masternode state size, and Simplified Masternode List
+metadata. Larger limits would support finer ownership fragmentation, but would
+increase worst-case coinbase and state growth for every paid block involving a
+highly fragmented masternode.
+
+### Basis-point reward shares
+
+Basis points match the existing `operatorReward` precision and allow the payout
+list to reuse a familiar representation. Requiring the shares to sum to exactly
+10000 avoids ambiguous normalization rules.
+
+### Minimum reward share
+
+The minimum owner payout share of 100 basis points prevents registrations that
+would intentionally create very small recurring coinbase outputs. This limit
+also follows from the maximum payout count: if all 8 entries are used, each
+entry must represent a meaningful owner share.
+
+### Operator reward remains separate
+
+The operator reward serves a different role from owner payout shares. It is
+configured by the owner as a maximum operator percentage, while the operator
+sets the actual operator payout script through ProUpServTx. Keeping this
+mechanism separate preserves hosting-provider delegation without making the
+operator payout script part of the owner payout list.
+
+## Test Cases
+
+Implementations should include tests for the following cases:
+
+1. A version 4 ProRegTx with one payout entry and `reward = 10000` is valid.
+2. A version 4 ProRegTx with 8 distinct payout entries whose rewards sum to
+ 10000 is valid.
+3. A version 4 ProRegTx with 0 payout entries is invalid.
+4. A version 4 ProRegTx with 9 payout entries is invalid.
+5. A payout entry with `reward = 99` is invalid.
+6. A payout list whose rewards sum to 9999 or 10001 is invalid.
+7. A payout list containing duplicate scripts is invalid.
+8. A payout list containing a non-P2PKH and non-P2SH script is invalid.
+9. A payout script that reuses the owner, voting, or collateral key is invalid
+ where the corresponding key comparison is possible.
+10. A ProUpRegTx can replace the payout list without reviving a PoSe-banned
+ masternode.
+11. A masternode with an operator payout first subtracts the operator reward and
+ then splits the owner reward across the payout list.
+12. Integer rounding pays the remainder to the last owner payout entry.
+13. Coinbase validation rejects a block missing any expected owner payout output.
+14. Coinbase validation rejects a block paying an expected payout script the
+ wrong amount.
+15. `protx info`, `protx diff`, `protx listdiff`, raw transaction JSON, and
+ extended SML JSON expose the unified `payouts` array.
+16. `masternode payments`, `masternode winners`, and `getblocktemplate` expose
+ all generated masternode payout outputs.
+17. Legacy single-payout masternodes continue to pay exactly as before.
+
+## Security Considerations
+
+This DIP removes the need for an off-chain distributor to manually forward the
+owner portion of masternode rewards to multiple share owners. It does not remove
+the registrar owner's authority to update masternode registration metadata. A
+share arrangement that requires immutable payout rights must use additional
+contractual, wallet, or protocol mechanisms outside the scope of this DIP.
+
+Payout scripts must not reuse owner, voting, or collateral keys for the same
+reason that DIP-0003 restricts current payout key reuse: payout keys may be used
+in less secure wallet environments, while owner, voting, and collateral keys
+control higher-value masternode functions.
+
+The payout count and minimum share limits reduce the risk of using masternode
+registrations to create large numbers of tiny recurring coinbase outputs.
+However, the block reward declines over time, so no fixed basis-point minimum
+can permanently guarantee that every future payout output will remain above all
+policy dust thresholds.
+
+## Copyright
+
+Copyright (c) 2026 Dash Core Group, Inc. [Licensed under the MIT License](https://opensource.org/licenses/MIT)
diff --git a/dip-pasta-yappr.md b/dip-pasta-yappr.md
new file mode 100644
index 00000000..f8480b87
--- /dev/null
+++ b/dip-pasta-yappr.md
@@ -0,0 +1,563 @@
+
+ DIP: pasta-yappr
+ Title: Dash Platform Application Key Exchange and State Transition Signing
+ Author(s): Pasta
+ Special-Thanks:
+ Comments-Summary: No comments yet.
+ Status: Draft
+ Type: Applications
+ Created: 2026-03-10
+ License: MIT License
+
+
+# Table of Contents
+
+1. [Abstract](#abstract)
+1. [Motivation](#motivation)
+1. [Prior Work](#prior-work)
+1. [Terminology](#terminology)
+1. [Overview](#overview)
+1. [Key Exchange Protocol](#key-exchange-protocol)
+ * [dash-key: URI Format](#dash-key-uri-format)
+ * [Binary Payload Layout](#binary-payload-layout)
+ * [Network Identifiers](#network-identifiers)
+ * [URI Validation Rules](#uri-validation-rules)
+ * [Cryptographic Flow](#cryptographic-flow)
+ * [Login Key Derivation](#login-key-derivation)
+ * [Shared Secret Derivation](#shared-secret-derivation)
+ * [Login Key Encryption](#login-key-encryption)
+ * [Application-Side Key Derivation](#application-side-key-derivation)
+1. [Key Exchange Contract](#key-exchange-contract)
+ * [Document Schema](#document-schema)
+ * [Indices](#indices)
+ * [Polling](#polling)
+1. [State Transition Signing Protocol](#state-transition-signing-protocol)
+ * [dash-st: URI Format](#dash-st-uri-format)
+ * [Query Parameters](#query-parameters)
+ * [Supported Encodings](#supported-encodings)
+ * [Wallet Validation and Signing](#wallet-validation-and-signing)
+1. [First-Time Login Key Registration](#first-time-login-key-registration)
+1. [Security Considerations](#security-considerations)
+1. [Copyright](#copyright)
+
+# Abstract
+
+This DIP defines two complementary URI-based protocols that enable secure interaction between Dash
+Platform applications and wallet software. The **Key Exchange Protocol** (`dash-key:`) allows web
+applications to obtain deterministic login keys from a wallet via QR code scanning, using ECDH key
+agreement and AES-256-GCM encryption with Dash Platform as the communication channel. The **State
+Transition Signing Protocol** (`dash-st:`) allows applications to request that a wallet sign and
+broadcast unsigned state transitions. Together, these protocols enable wallet-based authentication
+for Platform applications without requiring users to manually handle private keys.
+
+# Motivation
+
+Dash Platform applications require users to authenticate with cryptographic keys tied to their
+Platform identity. Current authentication methods require users to manually enter or manage private
+keys, which is both error-prone and a poor user experience. Users accustomed to modern login flows
+(e.g., scanning a QR code with a mobile device) expect a simpler mechanism.
+
+This DIP addresses the following problems:
+
+1. **Key management burden**: Users should not need to copy, paste, or store raw private keys to use
+ Platform applications.
+2. **Deterministic authentication**: A wallet should derive the same login key for a given
+ application every time, enabling stateless re-authentication across devices and sessions.
+3. **Per-application isolation**: Each application should receive a unique key, so compromise of one
+ application's key does not affect others.
+4. **First-time onboarding**: New users need a way to register application-specific keys on their
+ identity without manually constructing state transitions.
+5. **Decentralized communication**: The protocol should not rely on any centralized server; Dash
+ Platform itself serves as the communication channel between the application and the wallet.
+
+# Prior Work
+
+* [BIP-0032: Hierarchical Deterministic
+ Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
+* [BIP-0044: Multi-Account Hierarchy for Deterministic
+ Wallets](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
+* [DIP-0009: Coin Specific Feature Derivation
+ Paths](https://github.com/dashpay/dips/blob/master/dip-0009.md)
+* [DIP-0011: Identities](https://github.com/dashpay/dips/blob/master/dip-0011.md)
+* [DIP-0013: Identities in Hierarchical Deterministic
+ Wallets](https://github.com/dashpay/dips/blob/master/dip-0013.md)
+* [DIP-0015: DashPay](https://github.com/dashpay/dips/blob/master/dip-0015.md)
+
+# Terminology
+
+| Term | Definition |
+| ---- | ---------- |
+| Application | A Dash Platform application (e.g., a web app) that needs to authenticate a user via their Platform identity |
+| Wallet | Software that holds the user's HD wallet seed and Platform identity keys (e.g., Dash Evo Tool) |
+| Login Key | A 32-byte deterministic key derived by the wallet for a specific application and identity |
+| Ephemeral Keypair | A temporary secp256k1 keypair generated for a single key exchange session |
+| Key Exchange Contract | A Dash Platform data contract that stores `loginKeyResponse` documents |
+| Hash160 | The composition RIPEMD-160(SHA-256(data)), producing a 20-byte hash |
+
+# Overview
+
+The protocol operates in two phases. In the first phase, the application generates an ephemeral
+keypair and encodes a key exchange request as a `dash-key:` URI, typically displayed as a QR code.
+The user scans this with their wallet, which derives a deterministic login key, encrypts it using
+ECDH-derived shared secret, and publishes the encrypted response to Dash Platform. The application
+polls Platform for the response, decrypts the login key, and derives authentication and encryption
+keys from it.
+
+If the user's identity does not yet have the necessary application keys registered, the application
+enters a second phase: it constructs an unsigned `IdentityUpdateTransition` that adds the required
+keys, encodes it as a `dash-st:` URI, and displays it as a QR code. The wallet signs and broadcasts
+the transition to complete key registration.
+
+```text
+APPLICATION DASH PLATFORM WALLET
+═══════════ ═════════════ ══════
+
+ 1. Generate ephemeral keypair
+ (app_priv, app_pub)
+ 2. Encode app_pub + contractId
+ + label into dash-key: URI
+ 3. Display URI as QR code
+ 4. Scan QR / paste URI
+ Parse and validate payload
+ 5. User selects identity and
+ approves the request
+ 6. Derive login key from wallet
+ seed (BIP32 path + HKDF with
+ identity, contract, key index)
+ 7. Generate wallet ephemeral
+ keypair (wallet_priv, wallet_pub)
+ 8. Compute shared secret:
+ ECDH(wallet_priv, app_pub) → HKDF
+ 9. Encrypt login key with shared
+ secret using AES-256-GCM
+ 10. Create loginKeyResponse document
+ with wallet_pub + encrypted payload
+ ◄───────────────────
+ 11. Document stored
+ on Platform
+12. Poll Platform for document
+ matching contractId +
+ Hash160(app_pub)
+13. Document found; extract
+ wallet_pub and encrypted payload
+14. Compute same shared secret:
+ ECDH(app_priv, wallet_pub) → HKDF
+15. Decrypt login key using
+ shared secret and AES-256-GCM
+16. Derive auth key and encryption
+ key from login key via HKDF
+17. Check if derived keys are
+ registered on the identity
+ ├─ YES: Login complete
+ └─ NO: First-time login;
+ continue to key registration
+
+18. Build unsigned IdentityUpdate
+ transition adding auth +
+ encryption keys
+19. Encode as dash-st: URI
+ and display QR code
+ 20. Scan dash-st: QR
+ Review transition details
+ 21. User approves; wallet signs
+ with existing auth key
+ 22. Broadcast signed transition
+ ◄───────────────────
+ 23. Identity updated
+ on Platform
+24. Poll identity for new keys
+25. Keys found; login complete
+```
+
+# Key Exchange Protocol
+
+## dash-key: URI Format
+
+A key exchange request is encoded as a URI with the following structure:
+
+```text
+dash-key:?n=&v=
+```
+
+| Component | Description |
+| --------- | ----------- |
+| `dash-key:` | URI scheme prefix |
+| `` | Base58-encoded binary payload (see below) |
+| `n` | Network identifier (required) |
+| `v` | Protocol version (optional). When present, the wallet MUST verify it matches the version byte in the payload. The current protocol version is `1`. |
+
+### Binary Payload Layout
+
+The Base58-decoded payload has the following structure:
+
+| Offset | Size (bytes) | Field | Description |
+| ------ | ------------ | ----- | ----------- |
+| 0 | 1 | version | Protocol version; must be `0x01` |
+| 1 | 33 | appEphemeralPubKey | Compressed secp256k1 public key (prefix `0x02` or `0x03`) |
+| 34 | 32 | contractId | Dash Platform data contract identifier for the application |
+| 66 | 1 | labelLength | Length of the label field in bytes (0–64) |
+| 67 | 0–64 | label | UTF-8 encoded application label |
+
+Minimum payload size: 67 bytes (no label). Maximum payload size: 131 bytes (64-byte label).
+
+### Network Identifiers
+
+| Value | Network |
+| ----- | ------- |
+| `m`, `mainnet`, `dash` | Mainnet |
+| `t`, `testnet` | Testnet |
+| `d`, `devnet` | Devnet |
+| `r`, `regtest` | Regtest (local) |
+
+## URI Validation Rules
+
+A wallet implementation MUST validate the following before processing a `dash-key:` URI:
+
+1. The URI begins with the `dash-key:` prefix.
+2. The Base58 payload decodes successfully.
+3. The payload is at least 67 bytes.
+4. The version byte at offset 0 equals `0x01`. Any other version MUST be rejected.
+5. The ephemeral public key at offset 1 is a valid compressed secp256k1 point (first byte is `0x02`
+ or `0x03`).
+6. The label length byte at offset 66 does not exceed 64.
+7. The total payload length equals `67 + labelLength`.
+8. The label bytes (if any) are valid UTF-8.
+9. If the query parameter `v` is present, it matches the version byte in the payload.
+10. The network parameter `n` matches the wallet's active network.
+
+## Cryptographic Flow
+
+### Login Key Derivation
+
+The wallet derives a deterministic login key from its HD seed for a given identity, contract, and
+key index. The derivation proceeds in two stages.
+
+#### Stage 1: BIP32 Base Key Derivation
+
+Derive a private key at the following HD path:
+
+```text
+m / 9' / coin_type' / 21' / account'
+```
+
+| Path Level | Value |
+| ---------- | ----- |
+| 9' | Feature purpose (per [DIP-0009](https://github.com/dashpay/dips/blob/master/dip-0009.md)) |
+| coin_type' | `5` (mainnet) or `1` (testnet/devnet/regtest) per [BIP-0044](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) |
+| 21' | Key exchange feature index |
+| account' | Wallet account index for the selected identity (default `0`) |
+
+#### Stage 2: HKDF Key Derivation
+
+Apply HKDF-SHA256 ([RFC 5869](https://www.rfc-editor.org/rfc/rfc5869)) to the BIP32-derived private
+key:
+
+| Parameter | Value |
+| --------- | ----- |
+| Hash | SHA-256 |
+| IKM | 32-byte private key from Stage 1 |
+| Salt | 32-byte identity identifier |
+| Info | `contractId (32 bytes) ‖ keyIndex (4 bytes, little-endian)` |
+| Output length | 32 bytes |
+
+The `keyIndex` is determined by querying Platform for an existing `loginKeyResponse` document owned
+by this identity for the target contract. If a document exists, its stored `keyIndex` is reused. If
+no document exists, `keyIndex` is `0`. This ensures the same login key is derived on every
+authentication for the same identity and contract.
+
+### Shared Secret Derivation
+
+Both the application and the wallet independently derive the same shared secret using ECDH:
+
+1. Perform ECDH multiplication on secp256k1: multiply the local ephemeral private key by the
+ remote ephemeral public key.
+2. Extract the x-coordinate of the resulting point (32 bytes).
+3. Apply HKDF-SHA256:
+
+| Parameter | Value |
+| --------- | ----- |
+| Hash | SHA-256 |
+| IKM | 32-byte x-coordinate from ECDH |
+| Salt | `dash:key-exchange:v1` (UTF-8, 20 bytes) |
+| Info | empty |
+| Output length | 32 bytes |
+
+The output is the 32-byte symmetric key used for AES-256-GCM encryption.
+
+### Login Key Encryption
+
+After deriving the login key and the shared secret, the wallet encrypts the login key so it can be
+safely published to Platform. Only the application — which holds the other half of the ECDH
+ephemeral keypair — can decrypt it.
+
+The wallet generates a random 12-byte nonce and encrypts the 32-byte login key using AES-256-GCM
+with the shared secret as the symmetric key. No associated data is used.
+
+The resulting encrypted payload is serialized as a single byte sequence:
+
+| Offset | Size (bytes) | Field | Description |
+| ------ | ------------ | ----- | ----------- |
+| 0 | 12 | nonce | Random nonce used for AES-256-GCM |
+| 12 | 32 | ciphertext | Encrypted login key |
+| 44 | 16 | tag | Message authentication code produced by AES-GCM; used during decryption to verify the ciphertext has not been modified |
+
+Total encrypted payload size: 60 bytes. This byte sequence is stored in the `encryptedPayload`
+field of the `loginKeyResponse` document published to Platform.
+
+To decrypt, the application extracts the nonce from the first 12 bytes, uses its own copy of the
+shared secret as the AES-256-GCM key, and decrypts the remaining 48 bytes (ciphertext + tag) to
+recover the 32-byte login key.
+
+### Application-Side Key Derivation
+
+After decrypting the login key, the application derives two keys using HKDF-SHA256:
+
+**Authentication key:**
+
+| Parameter | Value |
+| --------- | ----- |
+| IKM | 32-byte login key |
+| Salt | 32-byte identity identifier |
+| Info | `auth` (UTF-8, 4 bytes) |
+| Output length | 32 bytes |
+
+**Encryption key:**
+
+| Parameter | Value |
+| --------- | ----- |
+| IKM | 32-byte login key |
+| Salt | 32-byte identity identifier |
+| Info | `encryption` (UTF-8, 10 bytes) |
+| Output length | 32 bytes |
+
+These derived keys are deterministic: the same login key and identity always produce the same
+authentication and encryption keys.
+
+# Key Exchange Contract
+
+The key exchange protocol uses a Dash Platform data contract to communicate responses from the
+wallet to the application. This contract is deployed once and shared by all applications using the
+protocol.
+
+## Document Schema
+
+The contract defines a single document type: `loginKeyResponse`.
+
+| Field | Type | Size (bytes) | Description |
+| ----- | ---- | ------------ | ----------- |
+| contractId | Identifier | 32 | The target application's data contract identifier |
+| appEphemeralPubKeyHash | Bytes | 20 | Hash160 of the application's ephemeral public key |
+| walletEphemeralPubKey | Bytes | 33 | Wallet's compressed secp256k1 ephemeral public key |
+| encryptedPayload | Bytes | 1–4096 | Encrypted login key (nonce ‖ ciphertext ‖ tag; typically 60 bytes) |
+| keyIndex | Integer | 4 | The key index used in login key derivation |
+
+All fields are required.
+
+## Indices
+
+The contract defines two unique indices:
+
+### Index 1: byOwnerAndContract
+
+| Property | Order |
+| -------- | ----- |
+| $ownerId | ascending |
+| contractId | ascending |
+
+This index ensures a wallet identity can have at most one response per target contract. Subsequent
+key exchanges for the same identity and contract update the existing document.
+
+### Index 2: byContractAndEphemeralKey
+
+| Property | Order |
+| -------- | ----- |
+| contractId | ascending |
+| appEphemeralPubKeyHash | ascending |
+
+This index enables the application to poll for a response using its ephemeral public key hash,
+without needing to know the wallet's identity in advance.
+
+## Polling
+
+The application polls for a response by querying the key exchange contract with the following
+conditions:
+
+* `contractId` equals the application's own contract identifier
+* `appEphemeralPubKeyHash` equals Hash160 of the application's ephemeral public key
+
+The recommended polling interval is 3 seconds with a 120-second timeout. When a matching document is
+found, the application extracts `walletEphemeralPubKey` and `encryptedPayload` to complete the
+decryption. The wallet identity is discovered from the document's `$ownerId` field.
+
+## Document Lifecycle
+
+When a wallet processes a key exchange request:
+
+1. Query for an existing `loginKeyResponse` document matching `($ownerId, contractId)`.
+2. If a document exists, update it with the new ephemeral key hash, wallet ephemeral public key,
+ encrypted payload, and key index. Bump the document revision.
+3. If no document exists, create a new one with all required fields.
+4. On revision conflict during update, retry up to 3 times with a 500ms delay between attempts,
+ re-querying the document on each attempt.
+
+# State Transition Signing Protocol
+
+The `dash-st:` protocol allows an application to request that a wallet sign and broadcast an
+unsigned state transition. While general-purpose, its primary use in the key exchange flow is for
+first-time key registration.
+
+## dash-st: URI Format
+
+```text
+dash-st:?n=&v=[&id=][&k=][&l=