-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Subaddresses #2056
Subaddresses #2056
Conversation
Is there a possibility of sweeping all subaddress funds back into my main address? Is that how bitcoin's HD wallet works? Or would that be more like the 'disposable address' scheme...? |
Remember, funds never reside on some address. Fundamentally, all the outputs belong to you because you can recover the individual outputs' private keys and they're not associated with an address. If the sender lost the relevant TX key, nobody can ever prove an output was sent to some address unless you give them the view key. Even if you know from your records you sent x monero to address y in TX z, you can't ever prove it without TX key or view key. If the sender sent to your sub A, and you spend it together with something from sub B, he can't tell that's from a different address because they're never linked to an address (unless he was the one who sent to B, in which case he'd have the TX key in local records). He can't even tell you're spending at all since you're using a ring signature :) So, grouping them into addresses or sub-addresses is kind of arbitrary. |
just registered to ask if we can have a so more something like I like to sweep my current sub-wallets usually more than 1 time before I send them to my main-wallet(s) for privacy reasons. otherwise great pr, will save me some time to create and backup a new wallet every time. |
Good work! What's the impact on performance when rescanning blockchain? Has it been benchmarked? |
Can this error message be improved? Even as a technical user, this would mislead me. Perhaps something like: "Error: No single sub-address contains adequate funds although wallet balance is sufficient. Suggestion: aggregate funds to a fresh address." |
f84bd34
to
b4bd69b
Compare
Thank you guys for your feedback! @xmrgit @knaccc @NanoAkron
Yes, it's possible to sweep all the balance of each subaddress to the main address individually. Alternatively, although not recommended for privacy reasons, it's also possible to sweep all the balances of all the subaddresses to the main address in a single transaction if you switch off the safeguard by doing
Conceptually it's kind of similar to Bitcoin's HD wallet, but the actual problem being addressed here is vastly different because in Monero, wallet addresses never appear in the blockchain as @JollyMort stressed.
I couldn't understand your question...
This is the concern addressed by the "not combining subaddresses" scheme. If Alice sent some funds to two different subaddresses and saw a transaction later that included those two outputs in the input ring signatures, she would guess that the two subaddresses belong to the same person.
It's not recommended (but still possible) to sweep all the funds in all the subaddresses to the main address at once, due to the above reason.
No, it's not benchmarked yet. But my guess is that the additional cost for blockchain scanning will be really small (i.e. 1 hashtable lookup, 1 hash computation, and 1 scalar addition, for each incoming tranfer). Thanks a lot for your suggestion! I changed the error message following your suggestion, please see the updated OP. |
Yup. But I could by chance make a ring signature using some 2 inputs to which Alice sent funds (to someone else, not me) in my ring and she could come to the same (but wrong) conclusion :) Plausible deniability FTW |
The point is that the likelihood of such an event is fairly low considering the enormous number of outputs in the blockchain, and if this happens repeatedly, the plausible deniability starts to diminish pretty quickly. |
would it also make sense to modify the command |
8b10d8c
to
eb6efbe
Compare
Minor note: I think it might help if the command syntax: |
I'm a little concerned that the wallet implementation you've proposed could diverge enormously from the GUI implementation, and lead to confusion. If the GUI were to present just a single wallet to users with a main balance and then a list of subaddresses, then that would match perfectly with what you've implemented. However, if the GUI presents the user with the ability to create different subwallets each with their own main balance, and with the abilitiy to create additional aliases per subwallet, then the terminology and UI will be completely different between the GUI and CLI. Therefore I think that before proceeding, it needs to be decided whether the GUI will actually provide users with just subaddresses, or instead subwallets and aliases. |
@kenshi84 does it make sense to have the and would it make sense if |
139937d
to
70d6b8f
Compare
@knaccc
I'm still unsure about the meaning of those terms: Is an "alias" something different from a subaddress? Is a "subwallet" something like a full wallet whose seed is deterministically generated by some "master" seed? I haven't seen any detailed discussion on their exact definitions and merits. There seems to be a general interest in managing different wallet files, either for the purpose of not revealing your identity through address reuse (which is addressed by this PR) or for the protection against KYC/AML demanding your viewkey (which isn't addressed by this PR). To me, opening different wallet files in GUI each having subtotal balances for their subaddresses doesn't seem too complicated or confusing, as long as we get the terminology right. @xmrgit
The |
I mean, that I don't know any example where Sorry for my bad english. |
@xmrgit
until there's no subaddress with unlocked balance. In general, I designed the CLI such that funds in subaddresses tend to accumulate in the main address (by randomly choosing non-zero index first before index=0), because all the change outputs go to the main address, regardless of whether the destination is a standard address or a subaddress. In other words, my intention was that as an "average" user keeps transferring funds without specifying the Does this make sense? |
@kenshi84 I'm referring to the terms defined in the previous PR in this comment: #1753 (comment) Regardless of what terms are used, the two approaches are: Option 1. The user sees a dropdown selection in the GUI to switch between 'bank accounts', like they would with online banking. Each 'bank account' has its own main balance. You can create alternate receiving addresses for each bank account. I've referred to these 'bank accounts' as subwallets and the 'alternate receiving addresses' as aliases. Both subwallets and aliases are implemented by simply issuing a subaddress per subwallet and a subaddress per subwallet alias. Option 2. The user does NOT see multiple 'bank accounts' or 'subwallets'. They just see one wallet with a main balance, and then additional different receiving addresses for this wallet. This is how you've implemented things for the CLI so far. The advantage of Option 1 is that it is less messy. For example, a user might want to use their wallet for two different purposes: one for personal use (PERSONAL) and another for an eBay like scenario where they are selling things online (SELLING). For both the PERSONAL and SELLING purposes, the user would create multiple receiving addresses for privacy reasons. Under Option 1, the user sees two subwallets each with several receiving addresses (aliases). Under Option 2, the user sees just a big list of different receiving addresses, and unless the user carefully labels them, it will be difficult for them to remember which receiving addresses were used to receive funds for PERSONAL vs SELLING purposes. They may see 20 different receiving addresses, and then have to recall which receiving addresses were given out for PERSONAL vs SELLING. Option 1 allows the user to easily see a different balance for their PERSONAL vs SELLING subwallets. This is possible because the GUI knows which receiving addresses (aliases) were associated with each subwallet. To see the total funds related to PERSONAL vs SELLING, they would have to not only remember which receiving addresses were used for each PERSONAL/SELLING purpose, but also manually add up funds to figure out the total funds for their PERSONAL vs SELLING activity. Edit: I've just thought of an Option 3: On reflection, I like Option 3 since: So, in summary, I think we should choose Option 2 or 3 depending on how important we think it is to let users see subtotals for PERSONAL vs SELLING without having to add it up themselves with a calculator. |
@knaccc I'm still not so convinced by your proposal, and in my opinion, this is where I start to feel that having separate wallet files makes more sense. The sole purpose of this PR is to solve the off-chain metadata linkability problem due to address reuse. I didn't intend to improve the user experience of managing multiple accounts in a way similar to today's online banking.
I think you have one misunderstanding: subtotals in subaddresses are NOT useful for keeping track of balances in a per-purpose basis (e.g. PERSONAL vs SELLING), because whenever you spend funds in those subaddresses, the change always goes to the main address. In other words, you can only keep track of the total incoming transfers to those subaddresses, but not the remaining balances of those subaddresses due to the changes being moved to the main address. Therefore, I'd rather vote for letting users simply open multiple wallet files separately (either in a new window or a new tab), both for the CLI and GUI (and probably MyMonero). |
@moneroexamples |
@kenshi84 |
Have new question. How do I prove change returned to myself using private_tx_key? Let me explain what I mean using example. When A makes tx to regular address of B, he will receiver a private tx key (obtained using get_tx_key in A's wallet). Using the key, A can prove to B (using his public address) that he sent to B what he said. Also, A can use his own public address with the same key and see the change returned to A. Now, when A makes tx to sub-address of B, the second part (i.e., checking the change returned to A using the private tx key) does not seem to work. I know that A can use his regular address + his private viewkey to check the change. But I am curious why it does not work with tx private key when sending to a sub-address of B, but it works when sending to regular address of B. |
This is due to the particular way tx public keys are computed when sending funds to subaddresses. As in the OP, when Alice's wallet
where
where
because |
Thanks. But proving change using tx_private_key(s) works when making tx to multiple addresses/subaddress. It only does not work when sending to a single subaddress. My guess is that when sending to multiple subaddresses/addresses in a single tx, extra tx_public_keys and extra private_tx_keys are generated and saved. This does not happen when sending to a single subaddress. Shouldn't there be some extra tx_private_key or tx_public_key also used in this case? |
Your understanding is correct.
That would make a 2-output tx to a subaddress distinguishable from other typical 2-output txes to standard addresses, so no. |
Thanks. Makes sense for 2-output. But what about a 3-output tx with at least one subaddress? Such txs also stand out, due to the additional tx public keys stored in the extra field, dont they?. |
You're right that transfers to multiple destinations including subaddresses will stand out due to additional tx keys. Between the following two options:
we decided to choose the latter after a thorough discussion (credit to @knaccc), anticipating that the use of subaddresses will be the norm in the future. |
Thanks. Its clear now. One more argument for option 2, would be that multiple-output txs are much less common than 2-outputs one. Also in e.g., 10-output tx, its unclear if there are 1 or 9 subaddress, whereas in 2-output, one would immediately know that you are dealing with a subadddress due to extra keys. |
Just wanted to make my understanding clear,
Thanks :) |
Because we'd like watch-only wallets to be able to recognize incoming transfers to subaddresses.
That would mean only full wallets can see incoming transfers to subaddresses. If that's what you want, sure you can do so by customizing the code yourself. But your idea is unlikely to be adopted because it doesn't seem useful. |
@kenshi84 Ah okay, thanks for the clarification :) |
we need a function to explicit generate a subadress with given i. since whitespaces are allowed in the label i would suggest
|
@kenshi84 Why do we need to add |
@moneroexamples
where The number of the additional tx pubkeys is the same as the number of outs; i.e. the recipient with a standard address is assigned a dummy additional tx pubkey, in order to hide which recipient is of which address type. The standard tx pubkey (which is always included) is used for decoding outputs destined to standard addresses.
So, outputs destined to standard addresses will be recognized without using the additional tx pubkeys. Outputs destined to subaddresses will be recognized only when using the additional tx pubkeys. |
@kenshi84 But for sub-addresses, the corresponding extra keys are not dummies, and they should be used in the decoding procedure. Thanks. |
Regarding Hi. Quick question. If an online service, external wallet, hardware wallet, or anything, wants to import an existing account, each output in each tx needs to be checked against 10'000 (=50 accounts x 200 sub-addresses in each) sub-addresses? For example, if I wanted to add sub-addresses to OpenMonero, the backend would need to scan (for each OM's account) each output in each tx 10'000 times to cover the initial set of potential sub-addresses? |
Most of the crypto costs are amortized per primary account (view key). The computation of the view key/output pair must compared against the list of subaddresses for the primary account. So this usually is faster than having 10000 unique view keys to scan against but still has additional storage/memory/time requirements. The major negative is when more than 3 outputs are used in a subaddress transaction. N-2 (where N is number of outputs) ECDH ops are required instead of a fixed single ECDH op for all outputs. If all transactions did this, subaddresses would be more computation for OpenMonero. |
Thanks.
Yes. For a single user it is not a major drama, but multiply this by 100, 1000, or more concurrent users for which you have to do all these extra calculations, and it can add up to some serious extra loading on a server. Anyway, it will be interesting task to do this. |
Note: This PR replaces #1753. Most importantly, the idea of disposable addresses was dropped, due to its potential danger of being misused by uneducated users which leads to on-chain tx linkability. See the relevant discussion here.
GUI version
1. Motivation
Suppose you publish a Monero wallet address for donation on your Twitter/etc profile page. Furthermore, you have an anonymous identity for some secret project where you also want to receive donation in Monero. Because you don't want people to be able to associate you with that anonymous identity by Googling your address, you'd want to use separate wallet addresses for these two purposes. While you can easily do so by simply creating two wallets separately, you're going to spend twice the time for scanning the blockchain and need twice the storage for the wallet cache. And this cost grows in proportion to the number of additional wallet addresses you'd like to have.
Another relevant scenario is when you want to buy Monero anonymously through ShapeShift. If you used the same Monero address repeatedly for multiple purchases, ShapeShift would know that the same person bought that much of Monero through those purchases (although they don't know your contact info as they don't require account registration). You can anonymize the process by creating a temporary wallet for every purchase and transferring the fund to your real wallet afterwards. This is doable, but clearly tedious.
The scheme proposed in this PR provides an effective solution for such scenarios, where the recipient can create multiple wallet "subaddresses" that appear unrelated to each other to outside observers, and the recipient can recognize all incoming transfers to those subaddresses with almost no additional cost. Note that this scheme only introduces additional procedures for the wallet software to construct and interpret transactions, while not requiring any change in the consensus rule (thus requiring no hard fork).
2. How it works cryptographically
Suppose Bob's wallet address is
(A, B) = (a*G, b*G)
wherea
andb
are his view and spend secret keys, respectively. Likewise, Alice's address is(X, Y) = (x*G, y*G)
. Bob is receiving Monero from Alice, but he wants to do so without using his real address(A, B)
in order to prevent Alice from knowing that the recipient is him. In the above example with ShapeShift, Bob would be you and Alice would be ShapeShift.2.1. Generating a subaddress
Bob generates his
i
-th subaddress(i=1,2,...)
as a pair of public keys(C,D)
where:We call
i
the index of the subaddress. Note that(A,B)
and(C,D)
are unlinkable without the knowledge of the view secret keya
. Bob then registersD
to a hash tableT
stored in his wallet cache (akin to the aggregate addresses scheme):To handle his main address in a unified way, Bob also registers
B
to the hash table:In other words, the index 0 is treated as a special case in this scheme representing the original standard address.
2.2. Sending to a subaddress
When Alice constructs a transaction that transfers some fund to a subaddress
(C, D)
, she first chooses a random scalars
and generates a tx pubkey:Note that the tx secret key
r
such thatR = r*G
is unknown to Alice because she doesn't know the secret key ofD
. She then computes an output pubkey for the destination:She finally computes an output pubkey to herself as her change:
Importantly, without the knowledge of the tx secret key
r
as explained above, Alice can include her change output in the transaction only because she knows her own view secret keyx
.In other words, only single-destination transfers are possible in this scheme, and multi-destination transfers (e.g. pool payouts) require the use of standard addresses.(2017-08-01) Now this scheme supports multi-destination transfers by introducing additional tx keys.Also note that Alice can prove her payment to Bob by using
s
.2.3. Receiving by a subaddress
Bob checks if an output pubkey
P
in a new transaction belongs to him or not by computingand looking for
D'
in the hash table. If the transaction was indeed bound to Bob's subaddress(C,D)
,D'
should equal toD
becauseTherefore, Bob should be able to find
D'
in the hash table:and obtain the private key of
P
:2.4. Grouping subaddresses
When sending funds to Bob's subaddress
(C,D)
, Alice can choose to send the change to heri
-th subaddress(X_i,Y_i)
instead of her main address(X,Y)
by replacingY
withY_i
when deriving the change's output pubkey:Using this scheme, it's now possible to maintain balances of subaddresses separately, making them virtually function as separate wallets. In order to maintain subaddresses in an organized manner, we propose a simple scheme of grouping subaddresses as follows: we define the index of subaddresses as a pair of indices
(i,j)
withi
, the major index, representing a group of subaddresses (called an account) andj
, the minor index, representing a particular subaddress within that account. Incoming transfers to subaddresses belonging to the same account(i,0), (i,1), ...
are summed up to form a single balance, and any spending of those outputs will transfer the change to the base subaddress(i,0)
. The index(0,0)
represents the original standard address.3. How it works in the CLI
3.1. Synopsis
Existing commands with updated syntax:
New commands:
3.2. Managing accounts
Initially, the wallet has only one account corresponding to the major index 0. The account index is indicated as the number after
/
in the command prompt:You can create a new account by using the command
account new
:Note the change of the address. The command
account switch
lets you switch between accounts:The command
account
with no arguments shows the list of all the accounts along with their balances:At any time, the user operates on the currently selected account and specifies the minor index in various commands when necessary via the
index
parameter; i.e. in the following description, we use the term "index" to mean the minor index.3.3. Generating subaddresses
The command
address
shows the "base" address at index=0 (which corresponds to the original standard address when the currently selected account is at index=0). The commandaddress new
lets you create a new address at one index beyond the currently existing highest index associated with this account. You can assign a label to the address if necessary:Note that this command is intended to be used for generating "throwaway" addresses; i.e. when you just want a fresh new address to receive funds to the currently selected account (e.g. when purchasing XMR through ShapeShift). If instead you want to maintain a separate balance associated with a new address, create a new account by the command
account new
.The commands
address all
andaddress <index_min> [<index_max>]
show lists of addresses that have been generated so far:The commandintegrated_address
also takes an optional argument to specify the index:(2017-08-01) The integrated subaddresses format was dropped as subaddresses are expected to be replacing the role of payment IDs
The command
address label
lets you set the label of an address:Note that the label of the base address is treated as the label of the currently selected account. You can change account labels by using either
address label
oraccount label
:3.4. Checking funds and balances
Here the wallet finds a few incoming transfers by some of its subaddresses (indicated by the major-minor index pairs):
The command
balance
shows the total balance of all the funds received by all the addresses belonging to the currently selected account. You can see the details about how much funds are received by which address by providing an optional argumentdetail
:Other commands for showing detailed information about funds have some changes of syntax:
3.5. Transferring funds
The apparently unrelated subaddresses might get statistically linked if funds transferred to different subaddresses are used together as inputs in new transactions. For example, suppose Bob published two subaddresses
(C1,D1)
and(C2,D2)
in different places, and Alice repeatedly transferred funds to these addresses not knowing that they both belong to Bob. If Bob repeatedly used outputs received by these subaddresses together as inputs in new transactions, Alice would notice multiple instances of transactions where each of the input ring signatures contains the output she created for the payments to these subaddresses. The probability of such transactions occurring by chance would be fairly low, so she can confidently guess that these subaddresses belong to the same person.To prevent this kind of potential risk of linkability, the wallet tries its best to avoid using outputs belonging to different subaddresses together as inputs in a new transaction. If there exist any subaddresses with enough unlocked balance for the requested transfer, the wallet chooses one randomly. If there is no such subaddress, the wallet uses the minimal number of subaddresses to cover the required amount while showing a warning message. You can also explicitly tell the wallet from which subaddresses the outputs should be picked by using an optional argument
index=<N1>[,<N2>,...]
:The command
sweep_all
has a similar syntax:If you omit the
index
parameter, one subaddress to be swept is chosen randomly (with index 0 being chosen last). You can useindex=<N>
to specify which subaddress to be swept. You can also either useindex=<N1>,<N2>,...
to sweep balances of multiple or all subaddresses.Note that the change always goes to the base subaddress at index=0:
3.6. Restoring wallet from seed
One slight caveat with this scheme is that when restoring a wallet from the seed, the wallet might miss transfers to subaddresses if they aren't stored in the hashtable yet. To mitigate this issue, for each account, the wallet stores 200 (a constant
SUBADDRESS_LOOKAHEAD_MINOR
defined in wallet2.h) subaddresses of indices beyond the highest index created so far. The wallet also generates 50 (a constantSUBADDRESS_LOOKAHEAD_MAJOR
defined in wallet2.h) accounts beyond the highest index created so far. This means that the wallet restoration process is guaranteed to find incoming transfers to subaddresses as long as the major and minor indices of the used subaddresses differ by less than those predefined numbers. Note that the wallet expands the hashtable by itself as it finds incoming transfers to subaddresses at new higher indices, so normally the user won't need to worry about the management of the hashtable. Even if the differences of indices are bigger than those predifined numbers, you can still make the wallet recognize the incoming transfers by manually expanding the hashtable and rescanning the blockchain.Here's an example: First, we generate 360 new addresses for the 1st account:
Next, we generate 70 accounts and print the base addresses of the 15th and 70th accounts:
Then we send funds to these addresses (at indices of 1/150, 1/360, 15/0, 70/0) from another wallet:
Now we delete the cache of the receiving wallet
9uPkEU
and re-generate it by scanning the blockchain again (which gives the same effect as restoring the wallet from the seed):Note that at this point, the wallet was able to successfully recognize incoming transfers to indices of 1/150 and 15/0, but failed to recognize incoming transfers to 1/360 and 70/0 because
360 > 150 + SUBADDRESS_LOOKAHEAD_MINOR
and70 > 15 + SUBADDRESS_LOOKAHEAD_MAJOR
. You can make the wallet recognize those incoming transfers by manually expanding the hashtable and rescanning the blockchain:4. ToDo
5. Related links
Reddit post mentioning this PR: https://www.reddit.com/r/Monero/comments/6e8f83/proposal_for_subaddresses_by_kenshi84_pull/
Reddit post with some questions and answers: https://www.reddit.com/r/Monero/comments/5vgjs2/subaddresses_and_disposable_addresses/
Question on StackExchange: https://monero.stackexchange.com/questions/3673/what-is-a-sub-address
Community feedback: https://www.reddit.com/r/Monero/comments/67565e/feedback_requested_do_you_want_monero_to_have/
Original post in MRL issue #7
Acknowledgements