Skip to content
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

[Obsolete] Sub-addresses and disposable addresses #1753

Closed
wants to merge 1 commit into from

Conversation

Projects
None yet
8 participants
@kenshi84
Copy link
Contributor

commented Feb 21, 2017

(This PR replaces #1345)

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/

Acknowledgements

  • @JollyMort for initial discussions since the very beginning
  • @knaccc for bringing up the concept of sub-addresses with a modified DH key exchange idea
  • @RandomRun for the second generation modified DH key exchange idea that solves the problem of discovery of the main wallet keys
  • @luigi1111 for various suggestions and guidance

Original post in MRL issue #7:

Assumptions & Characteristics

  • Address of the recipient (Bob): (A, B) = (a*G, b*G)
  • Address of the sender (Alice) : (X, Y) = (x*G, y*G)
  • Alice can pay to the same sub-address of Bob any number of times
  • The tx pubkey R is defined as a variant of DH shared secret between Bob & Alice; i.e., neither Alice nor Bob can know the tx private key r
  • The tx can have only two destinations, one to Bob and the other to Alice (as her change). Payments to more than one destinations have to be done using the standard address format.

Generating a sub-address

Bob's j-th sub-address (j=1,2,...) is a pair of EC points (C,D) where:

m = Hs(a || j)
M = m*G
D = B + M
C = a*D

We call j an index of a subaddress. Note that (A,B) and (C,D) are unlinkable. Bob then registers D to a hash table T (akin to the aggregate addresses scheme):

T[D] <-- j

To handle his main address in a unified way, Bob also registers B to the hash table:

T[B] <-- 0

In other words, index=0 is a special case in this scheme corresponding to the original standard address.

Sending to a sub-address

When constructing a transaction, Alice first chooses a random scalar s and generates a tx pubkey:

R = s*D

She then computes an output pubkey to Bob:

P = Hs(s*C)*G + D

She finally computes an output pubkey to herself as her change:

Q = Hs(x*R)*G + Y

Note that Alice can prove her payment to Bob by using s.

Receiving by a sub-address

Bob checks if an output pubkey P in a new transaction belongs to him or not by computing

D' = P - Hs(a*R)*G

and looking for D' in the hash table. If the transaction was indeed bound to Bob's sub-address (C,D), D' should equal to D because

a*R = a*s*D
    = s*a*D
    = s*C

Therefore, Bob should be able to find D' in the hash table:

j <-- T[D']

and obtain the private key of P:

p = { Hs(a*R) + b                   j == 0
    { Hs(a*R) + b + Hs(a || j)      otherwise

Disposable address

Bob can generate a one-time disposable address associated with one of his sub-addresses (C,D) using a 64bit random payment ID k as (C~,D~,k) where

m~ = Hs(a || k)
M~ = m~*G
D~ = D + M~
C~ = a*D~

Note that (C,D) and (C~,D~,k) are unlinkable. To keep the additional overhead in scanning the blockchain very small, the class of k's that can be used for Bob's disposable addresses is limited to those satisfying the following equation:

Hs(a || k) mod 256 == k mod 256                                 (1)

Bob can also generate one-time disposable addresses associated with his main address (A,B) as a special case:

m~ = Hs(a || k)
M~ = m~*G
D~ = B + M~
C~ = a*D~

Sending to a disposable address

Alice's procedure is exactly the same as above: she first generates a tx pubkey:

R = s*D~

and then generates an output pubkey P to Bob:

P = Hs(s*C~)*G + D~

Importantly, she finally attaches the payment ID k to the transaction without encryption.

Receiving by a disposable address

When Bob processes a new transaction, he first computes

D~' = P - Hs(a*R)*G

and looks for D~' in the hash table. If not found, and if the transaction has a payment ID k that satisfies equation (1), Bob then computes

m~ = Hs(a || k)
M~ = m~*G
D' = D~' - M~

and looks for D' in the hash table. If the transaction was indeed bound to Bob's disposable address (C~,D~,k), D~' should equal to D~ because

a*R = a*s*D~
    = s*a*D~
    = s*C~

and D' should be found in the hash table:

j <-- T[D']

Bob can obtain the private key of P as:

p = { Hs(a*R) + b + Hs(a || k)                   j == 0
    { Hs(a*R) + b + Hs(a || k) + Hs(a || j)      otherwise

monero-wallet-cli exmaple

A receiving wallet issuing various addresses:

[wallet 9t7rEA]: address
9t7rEAot149VeyQWWr9BmbTdfcrxnnAD9Dau1wTDEDBAFH7BV3eChMRgYQVAVhby31ddZhrhjyt389wNTxbyeHm6Cyi6nXF

[wallet 9t7rEA]: address 1
AD5g2VqQcB2fntjCoANERv6xmy5418ox3fvZk1TkaRSoWv7naZCkgZb7VBG2257BMcCCDUGvQvKPFfxAgNn4NR3nVXwjrLS

[wallet 9t7rEA]: address 2
AHE9mST2hRBa24TQEaGJAsdxszXefwkEiDK1SSHyX6QKNpAdGraUZTshBUh1kSTwGE35VZyeNnio1MAD6a8FkMBJSj3LUUd

[wallet 9t7rEA]: integrated_address
A3pXEydNcKfVeyQWWr9BmbTdfcrxnnAD9Dau1wTDEDBAFH7BV3eChMRgYQVAVhby31ddZhrhjyt389wNTxbyeHm6JoDe6twKdx53DLjrs3
Integrated payment ID: 6685c4d8b66c5a13

[wallet 9t7rEA]: integrated_address 1
ANnM3JeuDSYfntjCoANERv6xmy5418ox3fvZk1TkaRSoWv7naZCkgZb7VBG2257BMcCCDUGvQvKPFfxAgNn4NR3njFMhE5mtFT38WuLkLQ
Integrated payment ID: 94dc1853fde65642

[wallet 9t7rEA]: integrated_address 2
ASvpnFGXJgha24TQEaGJAsdxszXefwkEiDK1SSHyX6QKNpAdGraUZTshBUh1kSTwGE35VZyeNnio1MAD6a8FkMBJfHV5hrtwiCdB4MQTy2
Integrated payment ID: e2e6cd8386d7a659

[wallet 9t7rEA]: disposable_address
AZ7X4LDLYPsLLxj9TJkbWx6sUaYFKoRhTHdJnH7Gsm9z1a39reax9sxSMJwLJximmJQi6zVbvW6UA6D2fQ8YzbyW3QEKmCtiweECduWhWw
Integrated payment ID: 5a0aaf0e9da17f67

[wallet 9t7rEA]: disposable_address 1
AdicMwZSxJzhSPoomqjGLUJ7mRzLxYbSt7X8gRk62uHLWapAXqPhKwXMuGpmmqUprLD5qPjnJC1fYgqS94c5vzbd3rUUnJawYSUUKPPpLF
Integrated payment ID: 0e943c66479201f2

[wallet 9t7rEA]: disposable_address 2
AYY9kS19g3vJKJgEAgqoUWM3RBBCeoBNzJLkTHZKgRS3BAhdoyD1ESA85QeyYJFjmkQw8wZqLqqiEF8fDwQxqZL5auzyqjjzQywUsGDaZS
Integrated payment ID: c1dd798b455beaf6

Funds transferred from another wallet:

[wallet 9svHk1]: transfer 9t7rEAot149VeyQWWr9BmbTdfcrxnnAD9Dau1wTDEDBAFH7BV3eChMRgYQVAVhby31ddZhrhjyt389wNTxbyeHm6Cyi6nXF 0.1
Money successfully sent, transaction <f403044ca45aacd29100d19ca72e6a89d8b0ffe23872ec19a9a8238d00117238>

[wallet 9svHk1]: transfer AD5g2VqQcB2fntjCoANERv6xmy5418ox3fvZk1TkaRSoWv7naZCkgZb7VBG2257BMcCCDUGvQvKPFfxAgNn4NR3nVXwjrLS 0.2
Money successfully sent, transaction <f0dc11588fcdd9a60a948c8e584dd04de3950166611ee9f91499efa06fc0519e>

[wallet 9svHk1]: transfer AD5g2VqQcB2fntjCoANERv6xmy5418ox3fvZk1TkaRSoWv7naZCkgZb7VBG2257BMcCCDUGvQvKPFfxAgNn4NR3nVXwjrLS 0.3
Money successfully sent, transaction <eb18aab9b7338b1a82634e753e61d8bcae74026935ab92ed7325ea3108bc360f>

[wallet 9svHk1]: transfer AHE9mST2hRBa24TQEaGJAsdxszXefwkEiDK1SSHyX6QKNpAdGraUZTshBUh1kSTwGE35VZyeNnio1MAD6a8FkMBJSj3LUUd 0.4
Money successfully sent, transaction <41bb8c6750ff1aa4eb1e71c9d1ab6fb88bac192c6f9f40c4034398778488b76a>

[wallet 9svHk1]: transfer AHE9mST2hRBa24TQEaGJAsdxszXefwkEiDK1SSHyX6QKNpAdGraUZTshBUh1kSTwGE35VZyeNnio1MAD6a8FkMBJSj3LUUd 0.5
Money successfully sent, transaction <4f14f6006960a1d4d49d42771aaa318d3022af1631940e69d4cf7d83ea491012>

[wallet 9svHk1]: transfer A3pXEydNcKfVeyQWWr9BmbTdfcrxnnAD9Dau1wTDEDBAFH7BV3eChMRgYQVAVhby31ddZhrhjyt389wNTxbyeHm6JoDe6twKdx53DLjrs3 0.6
Money successfully sent, transaction <0c99a9da2222f6ae44e2d17c24485e21de91d50fe3c0ac00aec927903ec4c74f>

[wallet 9svHk1]: transfer ANnM3JeuDSYfntjCoANERv6xmy5418ox3fvZk1TkaRSoWv7naZCkgZb7VBG2257BMcCCDUGvQvKPFfxAgNn4NR3njFMhE5mtFT38WuLkLQ 0.7
Money successfully sent, transaction <e36ee2e40722421274ff44a2315fc710a09c979995963eb792476791bd074ede>

[wallet 9svHk1]: transfer ASvpnFGXJgha24TQEaGJAsdxszXefwkEiDK1SSHyX6QKNpAdGraUZTshBUh1kSTwGE35VZyeNnio1MAD6a8FkMBJfHV5hrtwiCdB4MQTy2 0.8
Money successfully sent, transaction <63f41854983cd5c01f8192095cc3fcbd6a8f6c3a8486f37ece379209a316b2de>

[wallet 9svHk1]: transfer ASvpnFGXJgha24TQEaGJAsdxszXefwkEiDK1SSHyX6QKNpAdGraUZTshBUh1kSTwGE35VZyeNnio1MAD6a8FkMBJfHV5hrtwiCdB4MQTy2 0.9
Money successfully sent, transaction <e3dc68106826f32cd83a0b9a92cd1c5ef36692d2f47d08bf3dd908acb87684de>

[wallet 9svHk1]: transfer AZ7X4LDLYPsLLxj9TJkbWx6sUaYFKoRhTHdJnH7Gsm9z1a39reax9sxSMJwLJximmJQi6zVbvW6UA6D2fQ8YzbyW3QEKmCtiweECduWhWw 1.0
Money successfully sent, transaction <06ac8afa2ad4a80ada7fdfce39cc1457332744e509839705de1b92cbddb5b6c3>

[wallet 9svHk1]: transfer AZ7X4LDLYPsLLxj9TJkbWx6sUaYFKoRhTHdJnH7Gsm9z1a39reax9sxSMJwLJximmJQi6zVbvW6UA6D2fQ8YzbyW3QEKmCtiweECduWhWw 1.1
Error: unknown transfer error: you've already transferred to this disposable address before

[wallet 9svHk1]: transfer AdicMwZSxJzhSPoomqjGLUJ7mRzLxYbSt7X8gRk62uHLWapAXqPhKwXMuGpmmqUprLD5qPjnJC1fYgqS94c5vzbd3rUUnJawYSUUKPPpLF 1.2
Money successfully sent, transaction <fa3c6dfaa8a81a67e4d5c85e1b1357bb3458c3b18dcca3485585bb74c4b4b83c>

[wallet 9svHk1]: transfer AdicMwZSxJzhSPoomqjGLUJ7mRzLxYbSt7X8gRk62uHLWapAXqPhKwXMuGpmmqUprLD5qPjnJC1fYgqS94c5vzbd3rUUnJawYSUUKPPpLF 1.3
Error: unknown transfer error: you've already transferred to this disposable address before

[wallet 9svHk1]: transfer AYY9kS19g3vJKJgEAgqoUWM3RBBCeoBNzJLkTHZKgRS3BAhdoyD1ESA85QeyYJFjmkQw8wZqLqqiEF8fDwQxqZL5auzyqjjzQywUsGDaZS 1.4
Money successfully sent, transaction <03f21186208f194f35ebcd8327460fcf8e42e07c82eb2eb50915e5a862d558d5>

Incoming transfers shown on the receiving wallet:

[wallet 9t7rEA]: show_transfers
  852939     in      09:16:40 AM       0.700000000000 e36ee2e40722421274ff44a2315fc710a09c979995963eb792476791bd074ede 94dc1853fde65642 1   - 
  852939     in      09:16:40 AM       1.000000000000 06ac8afa2ad4a80ada7fdfce39cc1457332744e509839705de1b92cbddb5b6c3 5a0aaf0e9da17f67 0 d - 
  852939     in      09:16:40 AM       1.200000000000 fa3c6dfaa8a81a67e4d5c85e1b1357bb3458c3b18dcca3485585bb74c4b4b83c 0e943c66479201f2 1 d - 
  852939     in      09:16:40 AM       0.900000000000 e3dc68106826f32cd83a0b9a92cd1c5ef36692d2f47d08bf3dd908acb87684de e2e6cd8386d7a659 2   - 
  852939     in      09:16:40 AM       0.800000000000 63f41854983cd5c01f8192095cc3fcbd6a8f6c3a8486f37ece379209a316b2de e2e6cd8386d7a659 2   - 
  852940     in      09:18:41 AM       0.300000000000 eb18aab9b7338b1a82634e753e61d8bcae74026935ab92ed7325ea3108bc360f 0000000000000000 1   - 
  852940     in      09:18:41 AM       0.400000000000 41bb8c6750ff1aa4eb1e71c9d1ab6fb88bac192c6f9f40c4034398778488b76a 0000000000000000 2   - 
  852940     in      09:18:41 AM       0.100000000000 f403044ca45aacd29100d19ca72e6a89d8b0ffe23872ec19a9a8238d00117238 0000000000000000 0   - 
  852941     in      09:22:01 AM       1.400000000000 03f21186208f194f35ebcd8327460fcf8e42e07c82eb2eb50915e5a862d558d5 c1dd798b455beaf6 2 d - 
  852941     in      09:22:01 AM       0.600000000000 0c99a9da2222f6ae44e2d17c24485e21de91d50fe3c0ac00aec927903ec4c74f 6685c4d8b66c5a13 0   - 
  852941     in      09:22:01 AM       0.200000000000 f0dc11588fcdd9a60a948c8e584dd04de3950166611ee9f91499efa06fc0519e 0000000000000000 1   - 
  852941     in      09:22:01 AM       0.500000000000 4f14f6006960a1d4d49d42771aaa318d3022af1631940e69d4cf7d83ea491012 0000000000000000 2   - 
[wallet 9t7rEA]:  show_transfers index=0
  852939     in      09:16:40 AM       1.000000000000 06ac8afa2ad4a80ada7fdfce39cc1457332744e509839705de1b92cbddb5b6c3 5a0aaf0e9da17f67 0 d - 
  852940     in      09:18:41 AM       0.100000000000 f403044ca45aacd29100d19ca72e6a89d8b0ffe23872ec19a9a8238d00117238 0000000000000000 0   - 
  852941     in      09:22:01 AM       0.600000000000 0c99a9da2222f6ae44e2d17c24485e21de91d50fe3c0ac00aec927903ec4c74f 6685c4d8b66c5a13 0   - 
[wallet 9t7rEA]: show_transfers index=1
  852939     in      09:16:40 AM       0.700000000000 e36ee2e40722421274ff44a2315fc710a09c979995963eb792476791bd074ede 94dc1853fde65642 1   - 
  852939     in      09:16:40 AM       1.200000000000 fa3c6dfaa8a81a67e4d5c85e1b1357bb3458c3b18dcca3485585bb74c4b4b83c 0e943c66479201f2 1 d - 
  852940     in      09:18:41 AM       0.300000000000 eb18aab9b7338b1a82634e753e61d8bcae74026935ab92ed7325ea3108bc360f 0000000000000000 1   - 
  852941     in      09:22:01 AM       0.200000000000 f0dc11588fcdd9a60a948c8e584dd04de3950166611ee9f91499efa06fc0519e 0000000000000000 1   - 
[wallet 9t7rEA]: show_transfers index=2
  852939     in      09:16:40 AM       0.900000000000 e3dc68106826f32cd83a0b9a92cd1c5ef36692d2f47d08bf3dd908acb87684de e2e6cd8386d7a659 2   - 
  852939     in      09:16:40 AM       0.800000000000 63f41854983cd5c01f8192095cc3fcbd6a8f6c3a8486f37ece379209a316b2de e2e6cd8386d7a659 2   - 
  852940     in      09:18:41 AM       0.400000000000 41bb8c6750ff1aa4eb1e71c9d1ab6fb88bac192c6f9f40c4034398778488b76a 0000000000000000 2   - 
  852941     in      09:22:01 AM       1.400000000000 03f21186208f194f35ebcd8327460fcf8e42e07c82eb2eb50915e5a862d558d5 c1dd798b455beaf6 2 d - 
  852941     in      09:22:01 AM       0.500000000000 4f14f6006960a1d4d49d42771aaa318d3022af1631940e69d4cf7d83ea491012 0000000000000000 2   - 

If the specified index exceeds the current hashtable size, the wallet throws an error. The hashtable size (set to 10000 by default) can be changed via the set command:

[wallet 9t7rEA]: address 9999
AMoUhePUitn2DnAfiRqWjxBBzbCVxWmbyTMbi9R9LUKLJBKUEQhy4AYA5zRDKD6tAhJnTj2WqpRA8gjjmP4W3VS2G8ybAfp
[wallet 9t7rEA]: address 10000
Error: requested index exceeds the limit! expand the hashtable by 'set subaddresses-size N'
[wallet 9t7rEA]: set subaddresses-size 12000
Wallet password: 
[wallet 9t7rEA]: address 10000
ADktBD7xvTsEmQcgkW5nXdGXeqoZbcum5EkA5MbTS1sXis2bieBgreVWYUvLPkRzRxW2UGmDhjCMDP8dDqXnBgUo94dz8To

The hashtable size can also be set when reconstructing the wallet from the seed or generating a watch-only wallet from the viewkey.

Pros & cons, when to use which?

  Sub-address Disposable address
Suitable for transfer to multiple destinations (e.g. pool payouts)? No No
Suitable for repetitive transfers? Yes No (same payment ID stored in the blockchain without encryption)
Guaranteed to produce different address each time? No (same address from same index) Yes

Case 1: Pool payouts

Use the standard address. Neither sub-addresses nor disposable addresses can be used for transfers to multiple destinations.

Case 2: Putting up donation addresses on your anonymous Twitter etc. accounts

Use sub-addresses. If you used a disposable address, all donations going to that address would share the same payment ID which gets stored in the blockchain without encryption (as opposed to the case with integrated addresses where payment IDs get stored in the blockchain after encryption) and hence the link among those transactions would be immediately clear to everyone.

Case 3: Buying XMR at account-less exchanges (e.g. ShapeShift) anonymously

Use disposable addresses. Sub-addresses could also serve the purpose of generating different addresses, but you need to make sure to use different indices to generate different addresses, or else you'll end up reusing the same address and the exchange will notice it. Disposable addresses are always guaranteed to be new and different every time you issue them.

ToDo

  • Crypto & code reviewing
  • Unit test, performance test, etc
  • GUI integration
  • Update MRL-0006
@NanoAkron

This comment has been minimized.

Copy link
Contributor

commented Feb 21, 2017

So to any outside observer, a payment to an integrated address and to a disposable address would look the same?

@kenshi84

This comment has been minimized.

Copy link
Contributor Author

commented Feb 21, 2017

Yes, they look the same on the blockchain, for example,

Btw, the little 'd' in the show_transfers indicates that the transfer is received by a disposable address.

@kenshi84 kenshi84 force-pushed the kenshi84:subaddress branch 2 times, most recently from be059d5 to e1f343c Feb 21, 2017

@NanoAkron

This comment has been minimized.

Copy link
Contributor

commented Feb 21, 2017

That's excellent

//---------------------------------------------------------------
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys);

This comment has been minimized.

Copy link
@kenshi84

kenshi84 Feb 22, 2017

Author Contributor

This function along with the above two structs are moved into cryptonote_format_utils. Strictly speaking this is not really necessary, but I did so because I wanted to keep cryptonote_tx_utils (which was introduced by my previous PR) to the absolute minimum (that rely on libringct and libblockchain_db). Maybe this change should be in a separate PR?

@kenshi84 kenshi84 force-pushed the kenshi84:subaddress branch 6 times, most recently from c19489e to d3d2e98 Feb 22, 2017

@kenshi84 kenshi84 force-pushed the kenshi84:subaddress branch 2 times, most recently from 99d7f69 to 9a39dec Feb 23, 2017

@NanoAkron

This comment has been minimized.

Copy link
Contributor

commented Feb 24, 2017

Is this a decent place to open a conversation about having subaddresses vs. disposable addresses vs. both?

@kenshi84

This comment has been minimized.

Copy link
Contributor Author

commented Feb 24, 2017

@NanoAkron I think so.

@kenshi84 kenshi84 force-pushed the kenshi84:subaddress branch 2 times, most recently from 033867e to f913702 Feb 24, 2017

@kenshi84 kenshi84 force-pushed the kenshi84:subaddress branch from f913702 to 338e65c Mar 4, 2017

@JollyMort

This comment has been minimized.

Copy link
Contributor

commented Mar 4, 2017

Could this be made to work with multiple sub-addresses as destinations?

R = s * D_1 * D_2 ... D_{i-1} * D_i * D_{i+1} ... * D_n, and

P_i = Hs(s * D_1 * D_2 ... D_{i-1} * C_i * D_{i+1} ... * D_n)*G + D_i?

@kenshi84

This comment has been minimized.

Copy link
Contributor Author

commented Mar 5, 2017

@JollyMort
No, you can't multiply an EC point against another EC point; i.e. given A=a*G and B=b*G, you can't do A*B to obtain a*b*G, the DH shared secret between A and B. It can be computed only as a*B or b*A.

@kenshi84 kenshi84 force-pushed the kenshi84:subaddress branch from 338e65c to 9f33410 Mar 6, 2017

@kenshi84 kenshi84 force-pushed the kenshi84:subaddress branch 4 times, most recently from dbcf654 to 4ed0456 Mar 6, 2017

@RandomRun

This comment has been minimized.

Copy link

commented Apr 25, 2017

@knaccc: Are there logs of that IRC chat? Also, I would like to understand better the method you propose to scan for additional addresses for only a 5% cost increase. Is that part of the IRC discussion, or posted somewhere else?

@kenshi84: As I pointed out in previous comments, using h(a || j) in the construction of the subaddresses may leak B, and also only generates the wallets sequentially, which might be a restriction in certain use cases.

Would there be a problem in simply replacing h(a || j) by a generic secret s in the specification of subaddresses? This way, s could be h(a || j), if that's what the user's wallet was set out to do; or perhaps h(b || j); or even as I suggested before, we could use an existing HD wallet scheme (with a seed derived from the private keys already backed up by the mnemonic seed, like seed = h(a+b)), and have s be the keys generated on that tree; etc.

Each one of these schemes have pros and cons for different use cases, so it would be great to leave the door open for experimentation, should someone like to implement them in the future using your work on subaddresses. (I am thinking mostly about using subaddresses in phone or light wallets, and being able to organize and separate accounts, like in Mycelium, while keeping a reasonable amount of privacy with respect to the third parties involved.)

My question is: the way you are building things, will this kind of tweaking still be possible, or will there be any protocol or consensus changes in how subaddresses are recognized that would make that hard? My guess is that even if you go for the h(a || j) implementation, it should still be possible for someone to use any secret s by just modifying wallet code, but I have been away from the discussion for a while, so I am asking just to be sure.

@knaccc

This comment has been minimized.

Copy link

commented Apr 25, 2017

@RandomRun It was a discovery I made from using a Java SUPERCOP ref10 implementation.

As I'm sure you know, EC multiplication in general is performed by doubling and adding as necessary.

Prior to performing a scalar multiplication to determine aR, the library requires R to be precomputed. This means finding multiples of R for all powers of 2. This precomputation is then used when adding together the precomputed power of 2 multiples of R as necessary to perform the scalar multiplication with a.

In my tests in Java, I discovered that the most time consuming part of the process is the precomputation rather than the actual scalar multiplication operation following the precomputation. Therefore once R is precomputed, scalar multiplication for many different values of a is much faster.

It could well be the case that this degree of speedup is peculiar to the Java SUPERCOP ref10 implementation and that the C implementation may not experience such a dramatic speedup. This idea therefore needs to be tested and validated by someone with C experience.

The IRC chat was in #monero-dev - I think you can see it all if you look at the Slack history.

@knaccc

This comment has been minimized.

Copy link

commented Apr 26, 2017

@RandomRun That's interesting. What if instead of m = Hs(a || j), it was m = Hs( Hs(bH) || j), where H is an alternative base point to G that is a global constant in Monero.

The advantage of this is that the auditor can be only told how to examine one particular subaddress, but if the auditor needed to know about all subaddresses you would not need to share b or a very large list of Hs(a || j), you could just share Hs(bH) instead to allow the auditor to examine all possible subaddresses forever.

@knaccc

This comment has been minimized.

Copy link

commented Apr 26, 2017

Option 1 2 3 4 5
Subwallet implementation (user sees multiple "accounts" with different balances) None R precomp Subaddr Subaddr Subaddr
Alias implementation (extra addresses per sender that contribute to the same wallet balance) Subaddr Subaddr Subaddr Disp None
Subwallet address suitable for transfer to multiple destinations (e.g. pool payouts)? No Yes No No No
Alias address suitable for transfer to multiple destinations (e.g. pool payouts)? No No No No N/A
Subwallet address suitable for repetitive transfers Yes Yes Yes Yes Yes
Alias address suitable for repetitive transfers Yes Yes Yes No Yes
60MB of block hashes required per subwallet Yes No No No No
Blockchain scan time impact Severe Moderate Minimal Minimal Minimal
One-time lookup table generation impact High, required per independent wallet High, required per subwallet Once Once Once
Convenience for users to use different addresses per sender to help wallet isolate funds per sender for privacy purposes Low High High High Low
User creates messy wallet because subwallets are used when the user really wanted reusable aliases No No No Yes Yes

(edit: my personal preference is for option 3 above)

@knaccc

This comment has been minimized.

Copy link

commented Apr 28, 2017

@RandomRun I just realized there is a possible attack if the scheme is changed to attempt to give out auditor access to just a single subaddress.

An ecdhinfo amount n is supplied in each transaction for each output. The real value of each received output is derived using the function real output amount = n - Hs(Hs(Hs(aR || i))).

Therefore if you knew a for one subaddress and therefore knew a for all subaddresses, you'd be able to check every output on the blockchain to see if the decoded output amount using the formula above falls into the relatively narrow range of probable XMR amounts that users would specify in transactions. This would allow the attacker to determine outputs that are very highly probable to be owned by other subaddresses within the same wallet.

This is a possible reason to preserve @kenshi84's original scheme instead of modifying it to allow auditor access to only specific subaddresses.

@RandomRun

This comment has been minimized.

Copy link

commented Apr 28, 2017

@knaccc: Thanks for the clarification regarding EC computation. That was a nice discovery!

About using m = Hs( Hs(bH) || j), I agree that that is better than using b directly, as it would allow the user to let the auditor to generate the whole sequence, if he so desires.

Whether the auditor will be able to derive the whole sub-tree (if we are going for HD wallets eventually), I am not sure this specific scheme would allow for that. I believe BIP0032 contains some good ideas on how to build our keys to preserve the tree structure, though.

About the possible attack:

An ecdhinfo amount n is supplied in each transaction for each output. The real value of each received output is derived using the function real output amount = n - Hs(Hs(Hs(aR || i))).

I didn't know that that was how the auditor recovered the real output amount from a ringCT transaction. Could you point me to a reference so I can learn more on that? (I thought that the "ecdhInfo" field of a transaction only stored the points, xG and aH ("mask" and "amount", respectively) of the Pedersen commitment. But I was looking here, and that could be outdated...)

Since the traditional address view key is (a, B), I was expecting that B would also be required to view the amounts involved, but apparently that is not so. In this case, would it be possible it change real output amount to something involving B, like n - Hs(Hs(Hs(aR+B || i))), so as to eliminate the attack you mentioned?

@knaccc

This comment has been minimized.

Copy link

commented Apr 28, 2017

@RandomRun Haha yes the decoding of RingCT amounts was a difficult discovery that involved going through the source code with a lot of patience. This is the function

void ecdhDecode(ecdhTuple & masked, const key & sharedSec) {

I also tested the function n - Hs(Hs(Hs(aR || i))) against outputs I own on the blockchain, so I'm sure that's the correct function.

Your Hs(aR+B || i) idea seems like it might work, although I don't have a thorough understanding of the full extent of the side effects of this change.

The main issue that comes to mind is that this would involve scalar multiplication of G with both Hs(aR || i) and Hs(aR+B || i) for each output in order to support both existing and new transaction types, which increases blockchain scanning time. This may not be a problem if the precomputation of G means that there is only a 5% extra blockchain scanning cost for this, but as I mentioned someone with a good knowledge of C needs to verify this for the C implementation. Edit: Actually, this may not be a problem if there is a new transaction version number issued, and only Hs(aR+B || i) is used in newer transaction types.

Another thought is whether there is an attack if a huge list of publicly listed monero address public spend keys (e.g. because they appear in search engine results) could be used to test against each output to discover any subaddresses with a shared view key.

@RandomRun

This comment has been minimized.

Copy link

commented Apr 28, 2017

@knaccc:

This may not be a problem if the precomputation of G means that there is only a 5% extra blockchain scanning cost for this[...]

Indeed, that is a good observation. When I first made a suggestion to modify subaddresses, I was thinking about replacing the transaction key R for an output key, but at the time @kenshi84 referred to a private conversation with @luigi1111 in which they concluded that:

[...] the computational cost due to additional key derivation processes for per-output tx pubkeys would be unacceptably high.

And added later in that thread:

Doubling the scanning cost is already way more than unacceptable. In addition, it'll be more than double since some transactions are multi-destination transfers, e.g. transfer to 4 or 5 recipients. This is most common for pool payouts which is not the majority of all transactions. Imposing such an immense additional cost to all users merely to enable multi-destination transfer with subaddresses, would be inappropriate.

So if your time complexity reduction from doubling to just 5% increase works, hopefully that might not be a problem anymore?

@knaccc

This comment has been minimized.

Copy link

commented Apr 29, 2017

So if your time complexity reduction from doubling to just 5% increase works, hopefully that might not be a problem anymore?

If there were a different R per output, then a single R could not be precomputed once per transaction. So it would be the full 100% extra per R.

Time savings only occur when for the same user, you scalar multiply with a particular group element more than once.

@RandomRun

This comment has been minimized.

Copy link

commented May 1, 2017

@knaccc: I see, your improvement actually makes having a single transaction key even more attractive.

BTW thanks for the code reference and taking the time to find that decoding function!

@vtnerd

This comment has been minimized.

Copy link
Contributor

commented May 2, 2017

@knaccc I would like some clarification on your thoughts on the "precomputation" for the subaddresses. Your description seems to indicate that there is a way to reuse a precomputed table for scalar multiplication but I do not see where this can occur. The receiver is still doing two scalar multiplications for every output. It should be possible to remove one of the scalar mulitplications in your scheme since an additional restriction was added - there can only be two outputs going to different addresses.

EDIT: Misspoke, you cannot remove a scalar multiplication. The signature must be with respect to G.

Each transaction has a unique R that the receiver must mulitply against - it is an ECDH operation exactly like our current transactions. The primary speedup I see is the ability to scan against multiple payment addresses simultaneously. Couldn't the same thing be achieved by making the wallet aware of multiple addresses at a time? The sender would have to nothing new. On the receiver side you could create new keypairs (X, Y) = (x*G, y*G) -> (X1, Y1) = (H(x || 1)*G, H(y || 1)*G). The security audit is easier too.

@JollyMort

This comment has been minimized.

Copy link
Contributor

commented May 2, 2017

What does it mean precompute R? I mean, it's already there in the TX, so what's there to compute? Do I understand well that the "precompute R" trick would be in the following:

Suppose that we have a multi-wallet with privView keys a_1, a_2 ... a_n and pubSpend B_1, B_2 ... B_n. The TX has the R computed by the sender and the recipient must, for each output in the TX (with an index j), compute:

P'_i = H_s(a_i*R || j)*G + B_i, where j is the index of an output in the TX. I understand this is the current scheme, although appending the index is omitted in the CN whitepaper.

Now, what can we precompute? We can sort the keys by privView. Then, we prepare a multi-wallet specific table with a calculated offset chain for each privView, like this:

privView privViewHelper
a_0 x_0 = 0
a_i x_i = a_i - a_{i-1}

Now, with this table, for each TX we can do:
temp. value | output suspect | test if matching j-th output in the TX
--- | --- | ---
S_0 = a_0*R | P'_0 = H_s(S_0 || j)*G + B_0 | P_j == P'_0 ?
S_i = S_{i-1} + x_i*R | P'_i = H_s(S_i || j)*G + B_i | P_j == P'_i ?

Is this right? Would it be faster? We multiply R with a "big" number only once, and later it's addition of R multiplied with some smaller number (only the difference), which ought to be faster, no? We can also re-use everything before || j for other outputs in the TX.

@knaccc

This comment has been minimized.

Copy link

commented May 2, 2017

@JollyMort Precompute only means generating power of 2 tables for R, which means when it's time to do multiplication of a scalar with R, the powers of 2 required already exist. My comment explaining it is here: #1753 (comment)

@knaccc

This comment has been minimized.

Copy link

commented May 2, 2017

By the way, this concept of precomputation isn't some new invention of mine, it's literally a method called precomputeForScalarMultiplication in the Java SUPERCOP library I'm using, that is required to be called prior to any scalar multiplication I do. Here is working code:

R = new Ed25519EncodedGroupElement(extra.txPubKey).decode();
R.precomputeForScalarMultiplication();
Ed25519GroupElement aR = mul8(R.scalarMultiply(new Ed25519EncodedFieldElement(privateViewKeyBytes)));
byte[] HsaRi = CryptoUtil.hashToScalar(ByteUtil.concat(aR.encode().getRaw(), outputIndex));
Ed25519GroupElement HsaRiG = G.scalarMultiply(new Ed25519EncodedFieldElement(HsaRi));
@vtnerd

This comment has been minimized.

Copy link
Contributor

commented May 2, 2017

I posted this in IRC -> https://github.com/monero-project/monero/blob/master/src/crypto/crypto-ops.c#L1963 is where R is precomputed currently. This was the confusion from my prior post you can "batch" multiple wallets by computing that table once for each tx pub key already. It still requires scalar multiplication for each wallet, which requires the other tweaks to collapse into one.

@vtnerd
Copy link
Contributor

left a comment

Reviewed only portions of this PR.

if (index >= m_subaddresses_size)
throw std::runtime_error("requested index exceeds the limit! expand the hashtable by 'set subaddresses-size N'");
const crypto::secret_key a = m_account.get_keys().m_view_secret_key;
for (int i = 0; i < 100000; ++i)

This comment has been minimized.

Copy link
@vtnerd

vtnerd May 4, 2017

Contributor

After reading the description for disposable addresses my first thought was how to generate one (because it seemed like brute force was necessary). And here it is. How often does this fail? How long does it take on average? Or even better, has anyone calculated the probability of finding such a value?

Edit: ... this only requires a 1 byte match, so it should find it with high probability actually ... kind of fired this off quickly.

This comment has been minimized.

Copy link
@kenshi84

kenshi84 May 9, 2017

Author Contributor

Yes, it's quite unimaginable for this loop to not terminate after a few hundred rounds.

for (int i = 0; i < 100000; ++i)
{
crypto::hash8 k = crypto::rand<crypto::hash8>();
char data[HASH_SIZE + 8];

This comment has been minimized.

Copy link
@vtnerd

vtnerd May 4, 2017

Contributor

This is using HASH_SIZE again.

This comment has been minimized.

Copy link
@kenshi84

kenshi84 May 9, 2017

Author Contributor

thanks

{
crypto::hash8 k = crypto::rand<crypto::hash8>();
char data[HASH_SIZE + 8];
memcpy(data , &a, HASH_SIZE);

This comment has been minimized.

Copy link
@vtnerd

vtnerd May 4, 2017

Contributor

Pop this up before the loop. This should require deep LTO to be optimized by the compiler.

This comment has been minimized.

Copy link
@kenshi84

kenshi84 May 9, 2017

Author Contributor

Good point, thanks

crypto::hash_to_scalar(data, HASH_SIZE + 8, m2);
// check if the following equation holds: (H(viewkey, pID) - pID) mod 256 == 0
if (k.data[0] != m2.data[0])
continue;

This comment has been minimized.

Copy link
@vtnerd

vtnerd May 4, 2017

Contributor

This is purely style but I think something like this is more readable:

for (int i = 0; true; ++i) {
    if (i >= 100000) throw exception{....};
    crypto::hash8 k = crypto::rand<crypto::hash8>();
    memcpy(data + HASH_SIZE, &k, 8);
    crypto::secret_key m2;
    crypto::hash_to_scalar(data, HASH_SIZE + 8, m2);
    if (k._data[0] == m2.data[0]) break;
}

Primarily because I like to keep loops more compact. The desired stopping condition is less obvious in the current version IMO.

This comment has been minimized.

Copy link
@kenshi84

kenshi84 May 9, 2017

Author Contributor

Agreed, thanks

crypto::secret_key disposable_seckey;
crypto::hash_to_scalar(data, HASH_SIZE + 8, disposable_seckey);
// check if the following equation holds: (H(viewkey, pID) - pID) mod 256 == 0
if (src_entr.payment_id8.data[0] == disposable_seckey.data[0])

This comment has been minimized.

Copy link
@vtnerd

vtnerd May 4, 2017

Contributor

I don't see any discussion about how is this leaking 1 byte from the secret key to the world. Something worth discussing.

This comment has been minimized.

Copy link
@kenshi84

kenshi84 May 9, 2017

Author Contributor

I'm not sure what your concern is. Do you see a potential privacy leak here?

This comment has been minimized.

Copy link
@vtnerd

vtnerd May 12, 2017

Contributor

The lower 8-bits of the secret key used to "hide" the association between public subaddress and public disposable address is published via the public payment id k. So this is leaking some private information; there is a smaller search space to associate public (sub)address <-> disposable public address than public (sub)address <-> public tx output address. Wanted to discuss any potential impact - identifying the relationship should still be difficult.

This comment has been minimized.

Copy link
@kenshi84

kenshi84 May 12, 2017

Author Contributor

Thanks, I was missing that point.

I chose the number 8 rather arbitrarily, and the potential (theoretical?) "leakage" you described would decrease as this number is lowered, at the cost of increased wallet scanning time. The extreme in the other end would be to use all the 64 bits, which still leaves the search space of 256-64=192 bits for the secret scalar m~. We can try to come up with a better choice of this number hitting the "right" balance, but it seems difficult to me to assess the potential privacy leak quantitatively (or to judge whether it's a real problem or not in the first place).

boost::optional<keypair> disposable_key;
{
char data[HASH_SIZE + 8];
memcpy(data, &sender_account_keys.m_view_secret_key, HASH_SIZE);

This comment has been minimized.

Copy link
@vtnerd

vtnerd May 4, 2017

Contributor

HASH_SIZE and sizeof(m_view_key_secret_key) are identical, but its probably better if sizeof is used for the calculations.

This comment has been minimized.

Copy link
@kenshi84

kenshi84 May 9, 2017

Author Contributor

ok

@kenshi84 kenshi84 force-pushed the kenshi84:subaddress branch from b0e4733 to dfdf9b8 May 9, 2017

@kenshi84

This comment has been minimized.

Copy link
Contributor Author

commented May 10, 2017

@RandomRun

Sorry for my long silence.

The idea of "per-subaddress selective auditing" that you and @knaccc have been discussing is somewhat interesting, but IMHO I'm quite skeptical about it. Let me rephrase your proposed idea in my own words: the original equation for the j-th sub-address

m_j = Hs(a || j)

is now replaced by

s   = Hs(b)
m_j = Hs(s || j)

The wallet owner gives the sub-address (C_j, D_j) where

D_j = B + m_j*G
C_j = a*D_j

along with a to the auditor. The auditor, not knowing the secret s, cannot generate all other sub-addresses from a alone. The wallet owner can create a view-only wallet for cold storage containing a and s but not b, which can recognize incoming transfers to all sub-addresses.

Maybe possibly this approach might be useful, but I'm skeptical because the auditor can easily find links among many sub-addresses (C1,D1), (C2,D2), ... belonging to the same owner, by detecting the common relation

C1 == a*D1
C2 == a*D2
...

The auditor can simply add those detected D1, D2, ... to his wallet's hashtable, and identify incoming transfers to those sub-addresses by checking

P ?= Hs(a*R)*G + D1
P ?= Hs(a*R)*G + D2
...

In my original intent, sub-addresses are meant to be passed to people and very often made publicly known (or forcibly made so by leaks), so the auditor will have access to all those found sub-addresses anyway. So I don't really see a privacy improvement in this approach.

The fundamental reason that makes this "selective auditing" idea difficult to realize I think is the fact that the same a must be passed to the auditor. I thought about some possible ideas of passing different "per-subaddress" view secret key a_j to the auditor, but so far my take is that it's unworkable.

@RandomRun

This comment has been minimized.

Copy link

commented May 12, 2017

@kenshi84: What you are suggesting requires that the auditor knows the sub-address itself. If he is just looking at blockchain data, he won't find the (C_j, D_j) to do the check C_j == a*D_j to begin with. But I agree with you that if the auditor ever comes across the address, then it will be linked, and that is not good.

Your observation, together with @knaccc's observation about decoding transactions amounts using a alone, seem to indicate that indeed the user can't expect unlinkability from sub-addresses if a is ever shared.

I wonder if selective auditing could be achieved by using more keys, like some stealth address generalization that would involve say (a, b, c) instead of just (a, b), because as it stands a lot is depending on a.

@knaccc

This comment has been minimized.

Copy link

commented May 13, 2017

I hacked together some C to test the pre-computed scalar multiplication issue. The speedup in C is 2.68x, which is dramatically lower than the Java 20x speedup. Therefore the "Option 2" "R precomp" looks like it's off the table. I suspect the Java situation is complicated by object creation overhead that does not affect the C implementation.

@kenshi84

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2017

A conversation took place on IRC today:

<knaccc:> moneromooo sorry, i couldn't make it to a terminal for the meeting. For subaddresses/disposable addresses, you'll remember I created a table and indicated a preference for option 3, which means dropping disposable addresses, and using subaddresses for both subwallets and aliases. I'm not sure if kenshi84 agrees or not that disposable addresses should be dropped or if he concurs with option 3. @RandomRun at
<knaccc:> the end of the thread was looking for a way to allow specific subaddresses to be audited without exposing information about other subaddresses, but neither I nor kenshi84 think that has legs, and I personally think it overcomplicates things. I think the main thing holding this back from completion is input from other stakeholders about whether they agree with option 3, and agree with the idea of having
<knaccc:> subwallets and aliases.
<knaccc:> the table of options is here: #1753 (comment)
<luigi1114:> I agree with option 3
<knaccc:> luigi1114 awesome. Who else needs to give consideration.approval?
<luigi1114:> I don't really know
<luigi1114:> whoever thinks they are important :)
<knaccc:> hehe I think there is the question of whether the GUI peeps are willing to implement both aliases and subwallets. I suspect the implementation of these things may be different in the CLI vs GUI
<knaccc:> from a UX perspective
<kenshi84:> knaccc: i still don't understand the role of aliases. how is that useful? also i'm not entirely convinced that disposable addresses should be dropped
<knaccc:> kenshi84 On disposable addresses, I think there is the issue of the use case. They're clearly technically superior in certain circumstances, but not in others
<kenshi84:> my first use case is shapeshift
<kenshi84:> @iamsmooth says it's too narrow, which i don't quite agree
<knaccc:> kenshi84 the only problem is that it takes education to get people to not re-use their disposable addresses, whereas if aliases were used there would be no problem with accidental/uninformed re-use
<knaccc:> Maybe i need to explain aliases
<knaccc:> The idea is this:
<knaccc:> You have subwallets, which feel to the user like different bank accounts
<knaccc:> Then you have aliases, which are mulitple incoming addresses per bank account
<knaccc:> Underneath, it's all just implemented using the subaddress scheme
<knaccc:> So when I create my first subwallet, i use subaddress 1
<knaccc:> and then if i create 3 aliases, I use subaddresses 2,3,4
<knaccc:> then if i create another subwallet, that's subaddress 5
<knaccc:> so the GUI wallet keeps track of what looks to the user like a subwallet, and what looks to the user like an alias address for the same wallet
<knaccc:> So normally, users will create a subwallet, then give out an alias for incoming funds each time they use shapeshift
<knaccc:> and because the wallet is treating those subaddresses as aliases, they all appear under the same balance, instead of as entirely different subwallets
<kenshi84:> that's no different from using a new subaddress for each xmr purchase at shapeshift
<kenshi84:> which is inefficient storage-wise
<kenshi84:> disposable address is better for that
<knaccc:> that's the point, both subwallets and aliases both use the subaddress scheme as the underlying mechanism, which allows multiple payouts to alias addresses without linkability
<knaccc:> so if you used the disposable address scheme as the underlying implementation for an alias, you'd have to educate people about reuse
<kenshi84:> but you don't want to reuse the same subaddress with shapeshift
<kenshi84:> that's the point of disposable address
<knaccc:> kenshi84 i agree disposable addresses could be used for that instead of subaddresses, and that's what i was originally thinking in the thread, but then there is the issue of educating the user about not being able to reuse addresses
<kenshi84:> ok. then the disposable address feature may be made optional or hidden
<kenshi84:> by supplying some command-line flag or something
<knaccc:> i really like dispoable addresses, I just think for the use case of 'aliases' for the user giving out different addresses to shapeshift each time, it'd be simpler for that use case to be handled with reusable subaddresses
<kenshi84:> but that increases the size of the hashtable without good reason
<knaccc:> if no one objects, i think it'd be nice to have disposable addresses in at least the CLI too
<luigi1114:> getting an actual figure of the cost would be helpful to me
<luigi1114:> hashtable costs almost nothing unless you go nuts
<knaccc:> it's a one time hashtable generation cost, and I think it'd be in the order of 1 second per 3000 disposable addresses right?
<luigi1114:> not disposable?
<knaccc:> disposable addresses have no setup costs
<luigi1114:> you said disposable
<luigi1114:> I think you meant sub
<knaccc:> oh sorry
<knaccc:> yes i did mean subaddresses
<luigi1114:> right that one time is negligible
<luigi1114:> I mean the additional hashing time on wallet refresh
<luigi1114:> for disposable
<knaccc:> i think disposable addreses only add something like 1-2% wallet refresh overhead
<luigi1114:> I'd rather have more than "i think" :)
<knaccc:> fair enough :)
<luigi1114:> I doubt it's much, but I'm sensitive to increasing the scan time
<kenshi84:> for generating 10k (set by default) subaddress hashtable on my 2.8GHz i7 MacBookPro, it takes about <10 seconds and <400kb
<kenshi84:> so yes, if you mean "nuts" by those needing much more than 10k addresses, then the cost is negligible for "normal" users
<knaccc:> conceptually I think disposable addresses are brilliant in that they are unlimited, but a massive problem when it comes to having to explain to the user what addresses can and can't be reused
<luigi1114:> 10k is quite a lot of addresses
<luigi1114:> buying some xmr on shapeshift every day would take 27 years to exhaust
<kenshi84:> for disposable addresses, the additional cost would arise when the given tx has a short 64bit payment ID
<kenshi84:> and the additional processing involves computing a hash m~ =Hs(a || k), generating its pubkey M~=m~*G and subtracting it from the examined spend pubkey D = D~ - M~
<knaccc:> and that's only done in 1/256 = 0.039% of cases where there is a payment ID
<kenshi84:> which happens once in 256 times due to filtering using the equation (i.e. checking the match of the lowest byte of the pID and m~)
<luigi1114:> unless they become common
<knaccc:> oops i meant to say 0.39%
<luigi1114:> I'm don't personally think there is enough differentiation to support both schemes, two new address formats, etc
<luigi1114:> I think some extension of the mnemonic might be helpful in some holistic thingymabopper
<luigi1114:> need to channel more gingeropolous
<knaccc:> the question is: if disposable addresses are implemented, are the only people that have great enough transaction volume to use them people that don't mind waiting 1 second for each few thousand they need to generate
<luigi1114:> do you mean subaddresses again?
<knaccc:> i'll rephrase:
<knaccc:> the question is: if disposable addresses are implemented, are the only people that have great enough transaction volume to use them people that don't mind waiting 1 second per thousand if they were forced to use subaddresses instead
<kenshi84:> i see your point
<luigi1114:> oh ok
<kenshi84:> maybe i'm being too paranoid about the hashtable size issue
<kenshi84:> in practice a few tens of thousands would be big enough for most
<kenshi84:> and that'd cost only a few tens of seconds or minutes and a few megabytes at most
<kenshi84:> one caveat is that you need to remember how big your hashtable was when restoring your wallet from seed
<knaccc:> kenshi84 i always thought a huge strength of disposable addresses are for scenarios where you don't want multiple front end servers to need to communicate with each other about what subaddresses have already been given out and therefore what the next address is they can present to a user. Also, to alllow checkout pages that are 'wasteful' and immediately present users with an address to send to at an
<knaccc:> early stage in the funnel where 99.9% of people will not actually make a purchase
<knaccc:> since luigi is watching, s/are/is :)
<luigi1114:> trollolol
<luigi1114:> knaccc in most cases an integrated address would work for payment, no?
<kenshi84:> ok, i'm persuaded and fine with dropping the disposable address scheme
<kenshi84:> and i see the point of aliases now
<kenshi84:> but then we need to make quite some changes to the code to reflect that idea
<kenshi84:> it's an issue of interface design
<knaccc:> luigi1114 i guess so, unless there is a scenario i've not yet imagined there the addresses cannot all have the same observable underlying address
<kenshi84:> how subaddresses should be organized / managed
<knaccc:> kenshi84 right yes for the CLI, I'd imagine it'd probably just be done the way it already is, with a simple sequence
<knaccc:> it's only the GUI that needs to allow for naming subwallets, and remembering that certain IDs were used for aliases vs subwallets
<kenshi84:> but aliases represent some kind of grouping over subaddresses, which is not implemented yet
<luigi1114:> just dump it on @Jaqueeee (eks dee)
<kenshi84:> CLI also needs some work
<luigi1114:> btw thanks for all your work on this
<luigi1114:> both of you
<knaccc:> kenshi84 basically the GUI just needs to remember that certain subaddresses are supposed to be aliases for an existing subaddress, and then simply display combined balances
<knaccc:> luigi1114 no problem, kenshi84 did all the really hard work :)
<kenshi84:> the wallet also needs to memorize which subaddress was already used or not
<knaccc:> kenshi84 right yes
<kenshi84:> if the user wants to avoid reusing, like with shapeshift
<knaccc:> yes absolutely
<kenshi84:> luigi1114: hehe i'm excited about being able to contribute to Monero :)
<knaccc:> i think it'd be a good time for the GUI to think more about how to save things like notes on transactions, as well as which subaddresses have been created, in a form the user can easily back up
<luigi1114:> you're like the energizer bunny: 1. wow new idea; 2. code code code code; 3. pr; 4. "hmm, we should do it this way"; 5. "good idea" revert code code code
<luigi1114:> :)
<kenshi84:> ok bottom line: drop disposable address idea & replace it with subaddress+alias
<kenshi84:> i'll try to come up with a reasonable interface design
<knaccc:> yeah kenshi84 you really ran with this, very impressive :)
<kenshi84:> and make yet another pr :)
<luigi1114:> good luck on that :D
<knaccc:> kenshi84 for the GUI or CLI?
<luigi1114:> (interface)
<kenshi84:> CLI for sure
<kenshi84:> but i'll have GUI in mind
<kenshi84:> so that @Jaqueeee won't have too much trouble integrating it to GUI
<knaccc:> very nice
<kenshi84:> thanks for all your ideas knaccc
<kenshi84:> and your advice luigi1114 :)
<knaccc:> kenshi84 It's been a pleasure, both of you!
<luigi1114:> \o/
<luigi1114:> grouphug
<knaccc:> if we keep this up, soon Monero will be as good as Bytecoin!
<kenshi84:> lol
<luigi1114:> literally
<luigi1114:> laughed out loud
<knaccc:> :)
<nanoakron:> I think we may still need your ‘one-time address’ scheme at some point in the future though when a use case becomes evident
<redlion_:> I agree. I think it would be a very useful function long-term.

which led to a conclusion that we drop the disposable address idea for now (with a possibility to revisit it in the future), and we design the alias idea (both for general and one-time uses) on top of the sub-address scheme, eliminating the potential risk of txes being linked due to reuse of disposable addresses by uneducated users.

This PR will be closed in favor of a new PR that will be created soon^TM.

@kenshi84 kenshi84 changed the title Sub-addresses and disposable addresses [Obsolete] Sub-addresses and disposable addresses May 22, 2017

@moneromooo-monero

This comment has been minimized.

Copy link
Contributor

commented May 22, 2017

Or you can keep this PR number for those updates ? There is valuable discussion on this page.

@kenshi84

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2017

@moneromooo-monero But there'll be substantial changes to the code. Should I just wipe this existing code by git push --force? I thought it'd be good to keep the obsolete code for referencing purposes.

@moneromooo-monero

This comment has been minimized.

Copy link
Contributor

commented May 22, 2017

Alright, fair enough.

@kenshi84 kenshi84 referenced this pull request May 30, 2017

Merged

Subaddresses #2056

@kenshi84

This comment has been minimized.

Copy link
Contributor Author

commented May 30, 2017

Closing in favor of #2056.

@kenshi84 kenshi84 closed this May 30, 2017

@kenshi84 kenshi84 deleted the kenshi84:subaddress branch Oct 16, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.