Problem Statement
Shielding is the process of locking an amount of a public token to acquire the same amount of the corresponding private token inside the Incognito network. It is the mechanism for users who want to achieve the Incognito privacy level for their public tokens. Since the introduction of Privacy V2, Incognito users have been experiencing a fairly higher level of privacy, with the ability to hide transaction amounts, senders, recipients, as well as asset types. However, at the moment, shielding encounters a problem of address re-using. That is, the locking address for all shielding requests from the same user is the same. This is undesirable because it is easy to determine whether two shielding requests belong to the same user or not. Fortunately, this problem can be addressed by employing one-time addresses.
Before we get into the details of the solution, letâs take a look at the properties that each Incognito transaction type achieves, and then see how employing one-time addresses might increase the shielding processâs privacy.
Table. A summary of each transaction type in Incognito
(*
depends on the interacting network)
Property | Transfer | Trade | Shield | Unshield |
---|---|---|---|---|
Hide amount | YES | NO | NO | NO |
Hide sender | YES | YES | YES/NO* | YES |
Hide receiver | YES | YES | NO | YES/NO* |
Hide asset type | YES | NO | NO | NO |
From the table, one can easily observe the following.
- A normal transfer satisfies all of these properties, so we are good to go.
- A trade cannot be processed unless the trading amount and trading assets are known. As a result, these values must be transparent. Therefore, hiding amounts and assets is not possible at the moment for a trade.
- Unshielding (i.e., sending assets out of Incognito) necessitates knowledge of the destination blockchain, as well as knowledge of the asset type. Hiding receivers differs depending on whether the destination blockchain is public (e.g., BTC, ETH) or private (e.g., XMR). Unshielding also requires burning corresponding amounts inside the Incognito network. So, hiding amounts is impossible. Therefore, at this time, we can say that unshielding transactions achieve the highest level of privacy.
- Whatâs left to be improved is the shielding process. Like unshielding, hiding amounts and asset types is not possible. Hiding senders depends on the interacting blockchain. So nothing we can do about these three properties. However, because the receivers are part of the Incognito network, we can improve this by employing one-time addresses.
Current Design
Next, we will quickly recap the current design. To shield a token from a Public Chain into Incognito, a User must proceed with the following steps.
- Generate the depositing address (
depositAddr
, a multisig address) using his payment address (incAddr
). EachincAddr
will have a uniquely corresponding depositAddr. Details of this can be found in this post. - Send an amount of the public token to the generated depositing address.
- Query the Public Chain to get the
depositProof
. - Send the
depositProof
to Incognito. -
Incognito mints the corresponding amount for User using his
incAddr
.
Figure 1. Current shielding design.
As we can see in Step 1, the incAddr
is used every time the User wants to shield an asset. Therefore, for two separate shielding requests, the same depositAddr
is generated. Therefore, one can tell that these requests belong to the same User.
To address this problem, we take advantage of one-time addresses to generate newly depositAddr
every time the User wants to perform a shield. In the next section, we explain in detail the solution.
Improvement
The idea is simple: let the User generate a one-time depositing address each time he deposits money into the Incognito network. The new flow is described in Figure 2 with the following steps.
Figure 2. New shielding flow. Colored in red indicates differences from the old design.
- Generate a one-time key pair (
OTPrivKey, OTPubKey
) to initiate the shielding request. - Generate a one-time Incognito address (
otaReceiver
) for receiving the corresponding token. - Sign this
otaReceiver
using the generatedOTPrivKey
in Step 1. This step is needed to ensure the authenticity of the shield (explained below). - Generate a depositing address using the
OTPubKey
instead of his payment addressincAddr
. - Send an amount of the public token to the generated depositing address.
- Query the Public Chain to get the
depositProof
. - Send the
depositProof
and corresponding data (OTPubKey, otaReceiver, sig
) to Incognito. -
Incognito mints the corresponding amount for User via the
otaReceiver
.
In this new design, we introduce the following new terms:
-
OTPrivKey, OTPubKey
. A one-time key pair for the shield request.- The
OTPubKey
is used to replace the currentincAddr
. As a newOTPubKey
is generated every time the User wants to shield, the correspondingdepositAddr
is also newly generated. Note that the User can re-use theOTPubKey
in other shielding requests. However, this is NOT RECOMMENDED because it will lower the privacy level and allow an observer to link his shields. - The
OTPrivKey
is used to sign the shielding request on data including theotaReceiver
.
- The
-
otaReceiver
. A one-time Incognito address that is used to receive the minted token. Unlike the previous design whereincAddr
is used and the Incognito knows how to mint the corresponding token for this address, thisotaReceiver
is needed as the payment address is not supplied. -
sig
. The signature for this shield request, which is signed on data includingotaReceiver
. This signature is needed to validate the authenticity of the shield request to make sure an attacker cannot use thedepositAddr
to shield the token to the address that he favors.
Effective Key Management
The replacement of the incAddr
results in a problem of key management. Since a fresh (OTPrivKey, OTPubKey
) pair is generated for each shield, we need a wise method for generating, managing, and checking if the key pair has been used. Randomly generating this pair is not a good solution, because we do not have an effective way to retrieve which pairs we have used, and thus cannot rebuild the shielding history.
To address this problem, we can employ the idea of HD Wallets or the BIP32 proposal, in which we have the pairs generated using a master key (mKey
) and an increasing index. The mKey
can be dependent on or independent of the private key, the latter is a better choice in terms of key management. For example, mKey
can be generated as follows (details will be updated soon):
mKey = Hash(privateKey, âonetimedepositingmasterkeyâ)
Figure 3. One-time key generation.
Starting at index = 0
, we try to create a child key pair and check if this pair has been used. If yes, we increase the index
by 1.
Conclusion
With this design, Incognito is now becoming more and more robust. Please tell us what you think about this design. Comments and recommendations are wholeheartedly welcomed.