Compare commits

..

10 commits

Author SHA1 Message Date
Christopher Sanborn
219b17a8aa Updated numbering in bsip-1203 to match assigned numbering. 2018-10-17 12:58:47 -04:00
Christopher Sanborn
792c524b2a Work in API Requirements subsection of Specifications 2018-10-10 14:51:35 -04:00
Christopher Sanborn
4772b5a736 Small additions to References and See Also. 2018-10-10 13:46:32 -04:00
Christopher Sanborn
52eafc5a64 Clarity edits in Discussion section. 2018-10-10 13:31:20 -04:00
Christopher Sanborn
43831e0a05 Clarity edits in Specifications section. 2018-10-10 12:53:26 -04:00
Christopher Sanborn
dfb2ca516a Typo 2018-10-08 14:17:26 -04:00
Christopher Sanborn
6b923189cd Clarity edits in Specifications section. 2018-10-08 14:15:10 -04:00
Christopher Sanborn
bd1f839c7f More clarity edits in Rationale section. 2018-10-08 13:47:45 -04:00
Christopher Sanborn
a5d3b0208b More edits for clarity. 2018-10-08 12:05:10 -04:00
Christopher Sanborn
b0b0be9592 bsip1203 minor phrasing fixes 2018-10-05 11:38:11 -04:00

View file

@ -1,4 +1,4 @@
BSIP: 1203 (unassigned) BSIP: 0053
Title: Blockchain scanning for inbound Stealth transactions Title: Blockchain scanning for inbound Stealth transactions
Authors: Christopher J. Sanborn Authors: Christopher J. Sanborn
Status: Draft Status: Draft
@ -13,26 +13,26 @@ The existing Stealth implementation ([BSIP-0008](bsip-0008.md)) requires the sen
## Motivation ## Motivation
"Stealth addresses" are a method of providing _unlinkability_ to blockchain transactions. Unlinkability is a major component of the "Privacy Triad": _unlinkability_, _confidentiality_, and _untraceability_. Using a stealth address, a sending wallet is able to compute a "child" public key that derives from the public key specified in the address, but which cannot be correlated, or "linked", to the address public key except by the sender and the receiver. This child key is what is used for the transaction outputs (TXOs). As such, third party observers cannot link TXOs to addresses, nor even link together TXOs which are "controlled" by the same address. "Stealth addresses" are a method of providing _unlinkability_ to blockchain transactions. Unlinkability is a major component of the Privacy Triad: _unlinkability_, _confidentiality_, and _untraceability_. Using a stealth address, a sending wallet is able to compute a child public key that derives from a public key encoded in the address, but which cannot be correlated, or "linked", to the address public key, unless you are either the sender or the receiver. This child key becomes the authorization key for transaction outputs (TXOs) intended for the receiver. As such, third party observers cannot link TXOs to addresses, nor even link together independent TXOs which are destined to the same address.
Although this is a great benefit to privacy, it complicates the matter of detecting inbound transactions, since a wallet cannot simply scan for transactions which explicitly identify the destination address. Although this is a great benefit to privacy, it complicates the matter of detecting inbound transactions, since a wallet cannot simply scan for transactions which explicitly identify the destination address.
Existing [Stealth Phase I](bsip-0008.md) functionality already includes the use of stealth addresses, but does not include a solution for detection of inbound transactions. As a result of which, user adoption of the Stealth feature has been very minimal. We propose below a solution to inbound transaction detection as well as some additional enhancements to the stealth addressing scheme. Existing [Stealth Phase I](bsip-0008.md) functionality already includes the use of stealth addresses, but does not include a solution for detection of inbound transactions. As a result of which, user adoption of the Stealth feature has been very minimal. We propose below a solution to inbound transaction detection as well as some additional enhancements to the stealth addressing scheme, including a proposed new address format that allows for watch-only wallets.
## Rationale ## Rationale
A confidential transaction (cTX) does not identify the recipient. As such, there is no direct way for a wallet to use only its Stealth address to query the p2p network for inbound transactions. In the current "phase one" implementation of Stealth ([BSIP-0008](bsip-0008.md)), inbound discovery is a manual process requiring the sender to communicate "transaction receipts" to the intended recipients of each transaction output in order to alert each recipient of their incoming balance. Transaction receipts are encrypted data structures that embed the Pedersen commitment of the transaction output and the value and blinding factor that the recipient needs to "open" the commitment. Additionally, the receipt records the one-time public key which the recipient uses to derive the private key offset needed to spend the incoming coin, via a shared-secret procedure between the one-time key and the recipient's address key. The need to communicate transaction receipts is burdensome and introduces substantial risk of lost funds due to failure to communicate or retain receipts. A confidential transaction (cTX) does not identify the recipient. As such, there is no direct way for a wallet to use only its Stealth address to query the p2p network for inbound transactions. In the current "phase one" implementation of Stealth ([BSIP-0008](bsip-0008.md)), inbound discovery is a manual process requiring the sender to communicate "transaction receipts" to the intended recipients of each transaction output in order to alert each recipient of their incoming balance. Transaction receipts are encrypted data structures that embed the Pedersen commitment of the transaction output and the value and blinding factor that the recipient needs to "open" the commitment. Additionally, the receipt records the one-time public key which the recipient must use to derive the private key offset needed to spend the incoming coin, via a shared-secret procedure between the one-time key and the recipient's address key. The need to communicate transaction receipts is burdensome and introduces substantial risk of lost funds due to failure to communicate or retain receipts.
_Keys involved in a cTX output (cTXO):_ _Keys involved in a cTX output (cTXO):_
* **One-time PubKey (OTK)** — The sender generates this key (public and private) from randomness and uses it to generate a shared-secret between the OTK and the recipient's Address PubKey. The OTK PubKey will be clear-text encoded in the Tx receipt and optionally also recorded in the transaction output. * **One-Time Key (OTK)** — The sender generates this key (public and private) from randomness and uses it to generate a shared-secret between the OTK and the recipient's Address ViewKey. The OTK PubKey will be clear-text encoded in the Tx receipt, and optionally also recorded in the transaction output to enable automated discovery.
* **Address PubKey (APK)** — This is a public key encoded in the recipient's stealth address. The goal of a stealth address scheme is to _not_ identify this public key in a transaction output. The APK serves as a base point from which individual Tx output AuthKeys are computed. * **Address Keys (ViewKey and SpendKey)** — These are public keys encoded in the recipient's stealth address. The goal of a stealth address scheme is to _not_ identify these public keys in any transaction output. A long-form address encodes _two_ public keys, referred to as ViewKey and SpendKey. The SpendKey serves as a base point from which individual Tx output AuthKeys are computed as an offset, and the ViewKey is used with the OTK to compute that offset. A short-form address encodes only a single public key, which serves as both the ViewKey and SpendKey.
* **Tx Output Auth Key (AuthKey)** — This public key will be recorded in the confidential transaction output (cTXO) as the key which is authorized to spend the commitment. This key is offset from the APK by a secret offset that only the sender and recipient can calculate (from the shared secret between OTK and APK). The sender knows only the offset between APK and AuthKey, but not the full secret key to the AuthKey. The recipient, knowing the private key behind the APK, can compute the private key to AuthKey and therefore can spend the commitment. * **Tx Output Authorization Key (AuthKey)** — This public key will be recorded in the confidential transaction output (cTXO) as the key which is authorized to spend the commitment. This key is offset from the address SpendKey by a secret offset that only the sender and recipient can calculate (from the shared secret between OTK and ViewKey). The sender can only know the offset, but not the full secret key to the AuthKey. The recipient, knowing the private key behind the SpendKey, can compute the private key to AuthKey and therefore can spend the commitment.
Automated discovery could be enabled if the receipt were embedded within the transaction data structure and if an aspect of that data structure supported a challenge condition which the recipient could recognize. Automated discovery could be enabled if the receipt were embedded within the transaction data structure and if an aspect of that data structure supported a challenge condition which the recipient could recognize.
The current implementation allows for a receipt to be embedded in each Tx output via a `stealth_memo` field which is formatted in the same way as the encrypted memos that may accompany regular (non-Stealth) transfer operations. These memos are composed of a header specifying the OTK PubKey and the "message PubKey" for which the recipient holds the corresponding private key, followed by cipher text which is AES encrypted with a shared-secret key between the OTK and the message PubKey. For the `stealth_memo`, the current behavior of the CLI reference wallet is to use the recipient's Address PubKey (APK) as the message PubKey. Although this is a reasonable choice for encrypting the message text, identifying the recipient's APK in the memo header breaks anonymity and completely negates the unlinkability provided by using a stealth address scheme. For this reason, the CLI reference wallet does _NOT_ actually embed the memo in the Tx ouput but instead Base58 encodes it and prints it to the screen, calling it a "transaction receipt." The sender must manually, and secretly, transmit this to the recipient via a side channel. Current network rules allow for a receipt to be embedded in each Tx output via a `stealth_memo` field which is formatted in a similar way as the encrypted memos that may accompany regular (non-Stealth) transfer operations. These memos are composed of a header specifying the OTK PubKey and the "message PubKey" for which the recipient holds the corresponding private key, followed by cipher text which is AES encrypted with a shared-secret key between the OTK and the message PubKey. For this `stealth_memo` field, the current behavior of the CLI reference wallet is to use the recipient's Address PubKey as the message PubKey. Although this is a reasonable choice for encrypting message text generally, it has the severe downside of identifying the recipient's Address PubKey in the memo header, and therefore breaks anonymity and negates the unlinkability provided by using a stealth address scheme. For this reason, the CLI reference wallet currently does _NOT_ actually embed the memo in the Tx ouput but instead Base58 encodes it and prints it to the screen, calling it a "transaction receipt." The sender must manually, and secretly, transmit this to the recipient via a side channel.
**Stealth Memo structure:** **Stealth Memo structure: (Stealth I)**
<span></span> | <span></span> <span></span> | <span></span>
-----: | :--- -----: | :---
@ -40,9 +40,19 @@ The current implementation allows for a receipt to be embedded in each Tx output
**Message PubKey:** | Public key controlled by recipient. &nbsp; **_(33 bytes)_**<br> **Message PubKey:** | Public key controlled by recipient. &nbsp; **_(33 bytes)_**<br>
**Cipher Text:** | AES encrypted message, using _key &leftarrow; Shared(OTK,MPK)_ **Cipher Text:** | AES encrypted message, using _key &leftarrow; Shared(OTK,MPK)_
_Note: Present behavior is to use the Address PubKey as the message PubKey, which reveals intended recipient!!_ _Current Stealth I behavior is to use the Address PubKey as the message PubKey, which reveals intended recipient!!_
A very simple solution would be to change the behavior of using the APK as the message PubKey, and instead to use the Tx output AuthKey as the message PubKey. Because the recipient is able to derive the private key behind the AuthKey through knowledge of the OTK PubKey and the recipient's APK, the recipient would simply need to test the OTK against each of their APK private keys to see if the resulting AuthKey matches the message PubKey. If it does, then the output is recognized as destined to the recipient, even though the recipient's Address PubKey is not identified in the memo header. The computational cost of this is one Diffie Hellman round, a hash operation, and a child key derivation. A very simple solution would be to change the behavior of embedding the Address PubKey in the message PubKey field, and to instead record the Tx output AuthKey in this slot. Because the recipient is also able to derive this AuthKey through knowledge of her own address private keys (in combination with the OTK recorded in the header), the recipient would simply need to test the OTK against each of their own Address Keys to see if the resulting AuthKey matches the one in the header. If it does, then the output is recognized as destined to the recipient, even though the recipient's Address PubKeys are not identified in the memo header. The computational cost of this is one Diffie Hellman round, a hash operation, and a child key derivation. It should be noted that the AES encryption key should still be computed from the shared secret between the OTK and the address ViewKey, however, as this will allow view-only wallets which cannot compute the private key behind the AuthKey to decrypt the memo and tally the incoming transaction.
**Stealth Memo structure: (Proposed: Stealth II)**
<span></span> | <span></span>
-----: | :---
**One-time PubKey:** | Chosen from randomness by sender &nbsp; **_(33 bytes)_**
**cTXO AuthKey:** | Child public key of the stealth address and the OTK. &nbsp; **_(33 bytes)_**<br>
**Cipher Text:** | AES encrypted message, using _key &leftarrow; Shared(OTK,ViewKey)_
_Proposed Stealth II behavior is to embed the AuthKey in the second slot, while still encrypting the message data with a shared key between the OTK and the Address key (specifically, the ViewKey so that watch-only wallets can read the commitment data)._
To support this strategy, a wallet will need to inspect all cTX activity on the network and test the challenge conditions on each transaction. This could be achieved if API nodes are extended to provide an API call to retrieve `stealth_memo` fields from all cTXOs appearing in a specified block range. The wallet could simply download the memos, test the challenge on each one, and identify and decrypt the ones that are destined to the wallet. No need would remain to manually transmit transaction receipts. The receipts would be embedded, compactly and unlinkably, in the Tx outputs. To support this strategy, a wallet will need to inspect all cTX activity on the network and test the challenge conditions on each transaction. This could be achieved if API nodes are extended to provide an API call to retrieve `stealth_memo` fields from all cTXOs appearing in a specified block range. The wallet could simply download the memos, test the challenge on each one, and identify and decrypt the ones that are destined to the wallet. No need would remain to manually transmit transaction receipts. The receipts would be embedded, compactly and unlinkably, in the Tx outputs.
@ -58,10 +68,10 @@ And in the second subsection, [_API requirements..._](#api-requirements-to-allow
Assumptions: Assumptions:
1. Wallet has access to a set of private keys corresponding to stealth addresses which may own commitments on the blockchain. These private keys are needed to "recognize" incoming transactions. 1. Wallet has access to a set of private keys corresponding to stealth addresses which may own commitments on the blockchain. These private keys are needed to "recognize" incoming transactions. If the wallet is a watch-only wallet for a particular address, then it is assumed to have the private and public ViewKey, but only the public SpendKey.
2. Wallet can query an API node for commitments occurring between specified block heights, to obtain a set to scan for owned commitment. ([See below](#api-requirements-to-allow-detection-of-inbound-commitments) for this process.) 2. Wallet can query an API node for commitments occurring between specified block heights, to obtain sets of embedded receipts to scan for owned commitments. ([See below](#api-requirements-to-allow-detection-of-inbound-commitments) for this process.)
In what follows, we detail procedures for two different stealth address formats: one which encodes a single public key, and one which encodes two public keys. The two formats serve a similar purpose of allowing for unlinkable transactions, but the dual-key format allows for watch-only wallets, whereas the single-key format does not. The single key format is borrowed from Confidential Transactions, whereas the dual-key format is borrowed from CryptoNote-based coins such as Monero. We detail procedures for stealth address formats which encode either a single public key, or two distinct public keys in which one key is the ViewKey and the other the SpendKey. The single-key format is already in use on the BitShares network and is borrowed from the original Confidential Transactions specification. The dual-key format allows for additional wallet features and is borrowed from CryptoNote-based coins such as Monero. No changes to the network nodes are required for wallets to support dual-key address formats. In fact, the single-key format can be thought of as a special case of the dual-key format in which the same key is used as the ViewKey and the SpendKey.
**Address Formats:** **Address Formats:**
@ -82,11 +92,11 @@ Recognizability depends on there being a deterministic relationship between the
We assume that the stealth address encodes public keys corresponding to two purposes: discovery, and expenditure. When an address encodes only one public key, that key is used for both purposes. We refer to the key for discovery as the "view" key, and denote the private, public pair as _(v, ViewKey)_. For spending, we denote the key pair as _(s, SpendKey)_. We assume that the stealth address encodes public keys corresponding to two purposes: discovery, and expenditure. When an address encodes only one public key, that key is used for both purposes. We refer to the key for discovery as the "view" key, and denote the private, public pair as _(v, ViewKey)_. For spending, we denote the key pair as _(s, SpendKey)_.
The AuthKey for a cTXO is an EC point summation of the address's SpendKey and an EC point "offset," which, for present purposes we will denote by the private, public pair _(o, Offset)_, with _Offset = o*G_. The AuthKey for a cTXO is an EC point summation of the address's SpendKey and an EC point "offset," which, for present purposes we will denote by the private, public pair _(o, Offset)_, with _Offset = o*G_, where _G_ is the generator point for the curve.
&nbsp; _AuthKey &nbsp;=&nbsp; SpendKey &nbsp;+&nbsp; Offset_ &nbsp; _AuthKey &nbsp;=&nbsp; SpendKey &nbsp;+&nbsp; Offset_
Anonymity is preserved so long as only the sender and the receiver are able to compute _o_ and _Offset_. The algorithm for computing _Offset_ is a deterministic function of the OTK and ViewKey only, (and not the SpendKey). This allows the the recipient to recover the SpendKey by simple subtraction of _Offset_ from the AuthKey and compare against a list of SpendKeys that the wallet may have used to generate an address family with a common ViewKey. (See _[address-per-invoice](#utility-of-dual-key-addresses)_ below.) Anonymity is preserved so long as only the sender and the receiver are able to compute _o_ and _Offset_. The algorithm for computing _Offset_ is a deterministic function of the OTK and ViewKey only, (and not the SpendKey). This allows the the recipient to recover the SpendKey by simple subtraction of _Offset_ from the AuthKey. The recipient's wallet then compares the computed SpendKey against the address SpendKey. The wallet may even compare against a whole list of SpendKeys that the wallet may have used to generate an address family with a common ViewKey, allowing for differentiable invoices, without sacrificing efficiency of scanning. (See _[address-per-invoice](#utility-of-dual-key-addresses)_ below.)
Algorithm | Description / Specification Algorithm | Description / Specification
:---:|:--------------------------- :---:|:---------------------------
@ -101,10 +111,13 @@ The sender's procedure for computing the offset and generating the AuthKey for t
<li> Compute a "shared secret" between between the sender and receiver: <li> Compute a "shared secret" between between the sender and receiver:
_secret = Shared(otk, ViewKey)_ _secret = Shared(otk, ViewKey)_
</li>
<li> Compute the OffsetKey as a child of the ViewKey, indexed by the shared secret:
_offset = ChildOffset(ViewKey,secret)_<br> The sender must be careful to leak neither the shared shared secret nor the private _otk_ key.
</li>
<li> Compute the OffsetKey as a child of the ViewKey, using a SHA256 hash of the shared secret as a child index:
_childindex = SHA256(secret)_<br>
_offset = ChildOffset(ViewKey,childindex)_<br>
_OffsetKey = offset*G_ _OffsetKey = offset*G_
</li> </li>
<li> Compute the AuthKey by summing SpendKey and OffsetKey: <li> Compute the AuthKey by summing SpendKey and OffsetKey:
@ -122,9 +135,10 @@ The receiver, having acquired a list of cTXO metadata that includes _OTK_ and _A
_secret = Shared(OTK, viewpriv)_ _secret = Shared(OTK, viewpriv)_
</li> </li>
<li> Compute the OffsetKey as a child of the ViewKey, indexed by the shared secret: <li> Compute the OffsetKey as a child of the ViewKey, using a SHA256 hash of the shared secret as a child index:
_offset = ChildOffset(ViewKey,secret)_<br> _childindex = SHA256(secret)_<br>
_offset = ChildOffset(ViewKey,childindex)_<br>
_OffsetKey = offset*G_ _OffsetKey = offset*G_
</li> </li>
<li> Recover the public SpendKey by subtracting OffsetKey from AuthKey: <li> Recover the public SpendKey by subtracting OffsetKey from AuthKey:
@ -142,7 +156,7 @@ Thus, a wallet may undertake to periodically download and scan the metadata for
##### Embedding recognizability data in the transaction ##### Embedding recognizability data in the transaction
For the recipient to have the practical ability to recognize a cTXO as their own, the cTXO, as recorded on the blockchain, must include the following two items: 1.) The one-time PubKey (OTK) that the sender generated for shared-secret generation, and, 2.) the authorization PubKey (AuthKey) of the cTXO. Because the AuthKey is computed deterministically from _Shared(OTK,AddrKey)_, it stands that if the recipient can generate the same AuthKey, and thereby determine that the cTXO belongs to them. For the recipient to have the practical ability to recognize a cTXO as their own, the cTXO, as recorded on the blockchain, must include the following two items: 1.) The one-time PubKey (OTK) that the sender generated for shared-secret generation, and, 2.) the authorization PubKey (AuthKey) of the cTXO. Because the AuthKey is computed deterministically from _Shared(OTK,AddrKey)_, it stands that if the recipient can generate the same AuthKey, then the cTXO belongs to them.
The structure of a cTXO is as follows: The structure of a cTXO is as follows:
@ -153,9 +167,9 @@ _Field_ | _Purpose_
**`owner`:** | BitShares owner structure specifying weighted list of keys or accounts that may spend this commitment. (Typically lists just one public key, the "AuthKey" for the cTXO.) **`owner`:** | BitShares owner structure specifying weighted list of keys or accounts that may spend this commitment. (Typically lists just one public key, the "AuthKey" for the cTXO.)
**`stealth_memo`:** | Also known as the "transaction receipt" when transmitted off-chain.<br><br> **`one_time_key`:** &nbsp; _(EC curve point, 33 bytes)_<br> **`to`:** &nbsp; Use the AuthKey here! _(EC curve point, 33 bytes)_<br> **`encrypted_memo`:** &nbsp; Data that recipient needs to "open" the commitment.<br><br> _The stealth memo is optional as far as the network is concerned, but essential if you want the recipient to be able to detect the incoming transaction without sending a "receipt."_ **`stealth_memo`:** | Also known as the "transaction receipt" when transmitted off-chain.<br><br> **`one_time_key`:** &nbsp; _(EC curve point, 33 bytes)_<br> **`to`:** &nbsp; Use the AuthKey here! _(EC curve point, 33 bytes)_<br> **`encrypted_memo`:** &nbsp; Data that recipient needs to "open" the commitment.<br><br> _The stealth memo is optional as far as the network is concerned, but essential if you want the recipient to be able to detect the incoming transaction without sending a "receipt."_
_(An example transaction showing all these fields can be seen in [block 22157273](https://cryptofresh.com/tx/8182e9d78cbce7df281bc252a9e6d87566ca0622). In this Tx, the stealth_memo '`to`' field names the recipient's address key, rather than the cTXO Auth key, and thus breaks unlinkability.)_ _(An example transaction showing all these fields can be seen in [block 22157273](https://cryptofresh.com/tx/8182e9d78cbce7df281bc252a9e6d87566ca0622). In this Tx, the stealth_memo '`to`' field unwisely names the recipient's address key, rather than the cTXO Auth key, and thus breaks unlinkability.)_
Since the `stealth_memo` field can be used to record both the OTK and the AuthKey, all the wallet needs to do to scan for incoming transactions is to download batches of stealth memos and, for each one, test whether the combination of the OTK and the wallet's Address key yields the AuthKey. If it does, then use then derive the AES decryption key from _Shared(OTK,AuthKey)_ and use that to read the additional data in `encrypted_memo`. Since the `stealth_memo` field can be used to record both the OTK and the AuthKey, all the wallet needs to do to scan for incoming transactions is to download batches of stealth memos and, for each one, test whether the combination of the OTK and the wallet's Address key yields the AuthKey. If it does, then derive the AES decryption key from _Shared(OTK,ViewKey)_ and use that to read the additional data in `encrypted_memo`.
Structure of `encrypted_memo`: Structure of `encrypted_memo`:
@ -172,11 +186,19 @@ _(TODO: How is this serialized? Do omitted fields "take up space"? Can fields b
### API Requirements to Allow Detection of Inbound Commitments ### API Requirements to Allow Detection of Inbound Commitments
(Discuss here a proposed API call for retrieving commitments by block height range) To monitor for incoming transactions to a particular wallet, a wallet need only download sets of `stealth_memo` structures to test for recognition. The full cTXO (including Pedersen commitment, owner structure, range proof, etc.) need not be downloaded. Because the encrypted data inside the memo indicates the Pedersen commitment, the wallet will know which cTXO it has recognized. (Witness nodes index cTXO's by Pedersen commitment.)
(Note: the data returned by this call should also include (or, perhaps this should be a separate call) a list of all commitments that were SPENT in the same block height range. In the case of RingCT this would be a list of key-images used, since with RingCT the network doesn't know which commitments are spent or not.) (Discuss here a proposed API call for retrieving stealth_memos by block height range)
(Discuss also possible optimizations such as batching historical commitment and spend data into ranges of fixed size (say intervals of 2^17 blocks, representing a little over four days) so that these data-balls can be cached and returned efficiently without the node needing to satisfy a unique query every time.) To know whether a cTXO is still unspent (e.g. by another instance of the wallet), a wallet could attempt to retrieve the corresponding commitment object from an API node. An empty result indicates the commitment has been spent. However, this procedure indicates our interest in a specific set of commitments, and the network traffic generated runs the risk of revealing that those commitments are "linked".
To prevent this, we propose instead that, in like manner to the downloading of bulk `stealth_memo` structures, that an API call for downloading bulk lists of consumed commitments be implemented, with the download again being over specified block height ranges. A wallet then needs only to test that its own commitments are not on the list of spent commitments.
In the event that ring signatures are implemented for transaction inputs (see [BSIP-0052](bsip-0052.md)), then instead of downloading a list of consumed commitments, we would instead download a list of used key images, which would serve the same purpose.
Because a wallet downloads `stealth_memo` structures in bulk over block height ranges, the wallet never reveals to the network its interest in any specific cTXOs. Thus network interaction for monitoring purposes does not undermine privacy.
NOTE: It is currently possible to retrieve all needed info to support recognition of incoming transactions via Elastic Search queries. This implies: (1) functional wallet behavior can be implemented right away, even if new API calls take longer to implement, and (2) it may be possible to avoid adding new API calls altogether, if the Elastic Search infrastructure is deemed performant enough to support queries from Stealth wallets. (Although intuitively it seems to me an API method would result in a better user experience).
## Discussion ## Discussion
@ -186,7 +208,7 @@ Utilization of the dual-key address format has numerous interesting use cases, i
* The ability to maintain **watch-only wallets**. By entrusting only the View Key to a view-only node, it is possible for this node to monitor for activity to an address without granting spending access to the same node. This allows for such things as: opt-in transparency; cash register monitoring; organizational internal auditing, etc. * The ability to maintain **watch-only wallets**. By entrusting only the View Key to a view-only node, it is possible for this node to monitor for activity to an address without granting spending access to the same node. This allows for such things as: opt-in transparency; cash register monitoring; organizational internal auditing, etc.
* The ability to use **address-per-invoice** without introducing substantial additional scanning overhead. To use this, one keeps the same viewing PubKey and iterates the Spending PubKey part of the address, generating a distinct address per invoice. When scanning the blockchain, the _Child Offset_ is a function of the shared-secret between OTK and ViewKey, such that _AuthKey = SpendKey + Offset_. To obtain the public SpendKey, a watching wallet can subtract the Offset from the AuthKey to obtain the SpendKey, and simply compare against a list of per-invoice SpendKeys that were used to generate addresses. Adding additional SpendKeys to scan for does not incur any additional EC group operations, merely additional byte-wise comparisons, which are trivial. _(Note that while the invoice addresses generated in this manner are distinct, they are not unlinkably distinct, since they share the viewing component. If a business wants individual invoices to be mutually unlinkable, then this scheme will not be sufficient. However, this is a consideration for a business's off-chain security practices, as the addresses themselves never appear on-chain or in a transaction.)_ * The ability to use **address-per-invoice** without introducing substantial additional scanning overhead. To use this, one keeps the same viewing PubKey and iterates the Spending PubKey part of the address, generating a distinct address per invoice. When scanning the blockchain, the _Child Offset_ is a function of the shared-secret between OTK and ViewKey, such that _AuthKey = SpendKey + Offset_. To obtain the public SpendKey, a watching wallet can subtract the Offset from the AuthKey to obtain the SpendKey, and simply compare against a list of per-invoice SpendKeys that were used to generate addresses. Adding additional SpendKeys to scan for does not incur any additional EC group operations, merely additional byte-wise comparisons, which are trivial. _(Note that while the invoice addresses generated in this manner are distinct, they are not unlinkably distinct, since they share the viewing component. If a business wants individual invoices to be mutually unlinkable, then this scheme will not be sufficient. However, this is a consideration for a business's off-chain security practices, as the addresses themselves never appear on-chain or in a transaction. An alternate solution which allows even the ViewKey to vary, while still allowing for efficient scanning, is presented in [MRL-0006](https://lab.getmonero.org/pubs/MRL-0006.pdf), however this introduces a change in how the deterministic offsets are generated, which would need to be signaled by a flag in the address format and supported by wallets.)_
### Possible future extensions ### Possible future extensions
@ -198,23 +220,29 @@ There may be use cases for additional address formats allowing for more complex
One would be a multi-sig situation in which the address format encodes multiple spending keys and a weighting requirement. Although, this would make the resulting address very lengthy, it would also add an interesting use-case. And, since BitShares authority structures already allow for a vector of authorizing keys and weights, it should be possible to implement the feature on the wallet side, without needing any changes to consensus or API. This idea is not explored further here but merely suggested for future exploration if there is a desire for the feature. One would be a multi-sig situation in which the address format encodes multiple spending keys and a weighting requirement. Although, this would make the resulting address very lengthy, it would also add an interesting use-case. And, since BitShares authority structures already allow for a vector of authorizing keys and weights, it should be possible to implement the feature on the wallet side, without needing any changes to consensus or API. This idea is not explored further here but merely suggested for future exploration if there is a desire for the feature.
Another use case for an extended address format would be... (TODO: Discuss including an "invoice nonce" in the address format for correlating incoming transactions to a particular invoice. C.f. Bitcoin where using an address-per-transaction serves both unlinkability as well as invoicing. With Stealth addresses, there is no need to increment addresses for unlinkability, and doing so to facilitate invoicing only increases the scanning overhead by introducing the need to test against additional private keys. But by including an invoice nonce in the address format, which the spending wallet would carry over into the encrypted part of the `stealth_memo`, the recipient can correlate payments to invoices while using only a single address key (or a single pair of spending/viewing keys in the dual-key case).) Another use case for an extended address format would be... (TODO: Discuss including an "invoice nonce" in the address format for correlating incoming transactions to a particular invoice. C.f. Bitcoin where using an address-per-transaction serves both unlinkability as well as invoicing. With Stealth addresses, there is no need to increment addresses for unlinkability, and doing so to facilitate invoicing only increases the scanning overhead by introducing the need to test against additional private keys. But by including an invoice nonce in the address format, which the spending wallet would carry over into the encrypted part of the `stealth_memo`, the recipient can correlate payments to invoices while using only a single address key. This strategy would be similar to the "Integrated addresses" that can be used on the Monero platform. Note, however, that this scheme is largely obsoleted by the simple ability to iterate the SpendKey through a HD address family while keeping the same ViewKey in a dual-key address format.)
### Pitfalls and Cautions ### Pitfalls and Cautions
#### Specific risks and remedies
##### Sender leaks private _otk_ or private _shared secret_:
TODO: analyze
#### An attack on address key from leak of a transaction private key #### An attack on address key from leak of a transaction private key
A confidential output will have associated with it an "Output PubKey." He who can provide a signature from that PubKey is authorized to spend the commitment. Automated detection of inbound commitments depends on the deterministic computation of an offset between the One-time PubKey and the Address PubKey, which is computed from the shared secret between the sender and receiver. Because only the offset is deterministic, the sender cannot compute the private key to the Output PubKey. Only the receiver can do this (by knowing both the offset and the Address private key). A confidential output will have associated with it an "Output PubKey," or AuthKey. He who can provide a signature from the AuthKey is authorized to spend the commitment. Automated detection of inbound commitments depends on the deterministic computation of an offset between the One-time PubKey (OTK) and the Address SpendKey, which is computed from the shared secret between the sender and receiver. Because only the offset is deterministic, the sender cannot compute the private key to the AuthKey. Only the receiver can do this (by knowing both the offset and the address's private spending key).
Because Output PubKeys are only used once, wallet software designers may be led to believe that the security of the Output PrivKeys are only important up until the commitment is spent. (What would it matter, to leak that private key, when the commitment it authorizes is no longer spendable?) This would be a mistake, however, because anyone who can compute the additive offset can subtract it from the Output PrivKey to reveal the Address PrivKey. Although the general public is not expected to be privy to that offset, the _sender_ of the output is in posession of the offset (and the ability to compute it due to knowing the random _k_ behind the One-time PubKey). This means the sender can compute the Address PrivKey, in the event that the recipient leaks the Output PrivKey. Because AuthKeys are only used once, wallet software designers may be led to believe that the security of the AuthKey private keys are only important up until the commitment is spent. (What would it matter, to leak that private key, when the commitment it authorizes is no longer spendable?) This would be a mistake, however, because anyone who can compute the additive offset can subtract it from the private AuthKey to reveal the address's private spending key. Although the general public is not expected to be privy to that offset, the _sender_ of the output is in possession of the offset (and the ability to compute it due to knowing the random _k_ behind the One-time PubKey). This means the sender would be enabled to compute the address's private key, in the event that the recipient leaks the private AuthKey.
Thus, wallet designers should be advised to treat the Output PrivKeys handled by their wallets with at least as much care as the Address PrivKeys, even long after the commitments they authorize have been spent. A leak of a single commitment's PrivKey is tantamount to a leak of the PrivKey for the entire wallet. Thus, wallet designers should be advised to treat the private TXO AuthKeys handled by their wallets with at least as much care as the address private keys, even long after the commitments they authorize have been spent. A leak of a single commitment's PrivKey is tantamount to a leak of the PrivKey for the entire wallet.
(A similar risk of revealing a parent PrivKey from leak of a child PrivKey and parent XPUB when using non-hardened derivation is noted in the Bitcoin BIP-32 protocol for Hierarchical Deterministic Wallets.) (A similar risk of revealing a parent PrivKey from leak of a child PrivKey and parent XPUB when using non-hardened derivation is noted in the Bitcoin BIP-32 protocol for Hierarchical Deterministic Wallets.)
## Summary for Shareholders ## Summary for Shareholders
Although the goal of this BSIP is to support the long-range vision of [Stealth Phase II](bsip-1200.md), the implementation of this BSIP would provide value _right now_, as it would enable the utilization of even the Phase I _Confidential Transactions_ operations without the reliance on burdensome transaction receipts, which are the primary end-user stumbling block to routine Stealth use. Although the goal of this BSIP is to support the long-range vision of [Stealth Phase II](bsip-0050.md), the implementation of this BSIP would provide value _right now_, as it would enable the utilization of even the Phase I _Confidential Transactions_ operations without the reliance on burdensome transaction receipts, which are the primary end-user stumbling block to routine Stealth use.
We have detailed in this document procedures for producing recipient-recognizable transaction outputs from stealth addresses. Specifically, we have detailed the procedure for _two_ distinct stealth address formats: a single-key address format which is identical to that which is already in use, and a new dual-key address format which separates the duties of monitoring from spending, and thus allows for watch-only Stealth wallets. Support for the dual-key address format would require no network or consensus changes. It requires only wallet support. We have detailed in this document procedures for producing recipient-recognizable transaction outputs from stealth addresses. Specifically, we have detailed the procedure for _two_ distinct stealth address formats: a single-key address format which is identical to that which is already in use, and a new dual-key address format which separates the duties of monitoring from spending, and thus allows for watch-only Stealth wallets. Support for the dual-key address format would require no network or consensus changes. It requires only wallet support.
@ -228,4 +256,9 @@ This document is placed in the public domain.
[vS13] - Nicolas van Saberhagen, _Cryptonote v 2.0_, 2013 - https://cryptonote.org/whitepaper.pdf [vS13] - Nicolas van Saberhagen, _Cryptonote v 2.0_, 2013 - https://cryptonote.org/whitepaper.pdf
[NG17] - Sarang Noether and Brandon Goodell, _An efficient implementation of Monero subaddresses_, 2017 - https://lab.getmonero.org/pubs/MRL-0006.pdf
## See Also ## See Also
* Overview of _Stealth Phase II_ - [BSIP-0052](bsip-0052.md)
* [bitshares-stealth-k](https://github.com/Agorise/bitshares-stealth-k) - A Kotlin library for Stealth support in BitShares (in _very_ early development stage)