Pages:
Author

Topic: How to detect the change output? (Read 7282 times)

donator
Activity: 2772
Merit: 1019
February 01, 2013, 10:12:03 AM
#33
bitcoin-qt tries to randomize the position of the change output, but I believe the code has a flaw:

// Insert change txn at random position:
vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));

The problem is that size() is one in the common case of one payee, so GetRandInt will always return 0.The change ends up in the first output.

I think it should be size()+1.

Exploiting this bug I made a chart showing transaction volume of output #1 only: [CHART] Bitcoin Actual Transaction Volume? (using "change is never last" bug)

Electrum had the opposite behaviour though - it always sent the change as the last output (and as currently exists can only do single-destination transactions, so the change was always the second output if there was change).  So guessing change still means guessing what the client used to send the transaction was, which helps anonymity a bit from the date electrum was released.

So I can't agree with you that your results are meaningful.

The most recent 1.6.2 release of Electrum randomizes the change output.

Also, I know some people deliberately send transactions with excess precision to the real output to make the change output have less precision and look like it isn't change.

I really think it's near-impossible to reliably guess the change output if it's not a 0.01xxx amount.

Thanks for pointing out the electrum behavior.

There could be many useful heuristics which, especially when taken together, might yield good results. I'm not going to attempt any such thing and just agree with you that it can't reliably be done.
donator
Activity: 668
Merit: 500
February 01, 2013, 09:02:05 AM
#32
bitcoin-qt tries to randomize the position of the change output, but I believe the code has a flaw:

// Insert change txn at random position:
vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));

The problem is that size() is one in the common case of one payee, so GetRandInt will always return 0.The change ends up in the first output.

I think it should be size()+1.

Exploiting this bug I made a chart showing transaction volume of output #1 only: [CHART] Bitcoin Actual Transaction Volume? (using "change is never last" bug)

Electrum had the opposite behaviour though - it always sent the change as the last output (and as currently exists can only do single-destination transactions, so the change was always the second output if there was change).  So guessing change still means guessing what the client used to send the transaction was, which helps anonymity a bit from the date electrum was released.

So I can't agree with you that your results are meaningful.

The most recent 1.6.2 release of Electrum randomizes the change output.

Also, I know some people deliberately send transactions with excess precision to the real output to make the change output have less precision and look like it isn't change.

I really think it's near-impossible to reliably guess the change output if it's not a 0.01xxx amount.
donator
Activity: 2772
Merit: 1019
January 13, 2013, 12:20:41 PM
#31
bitcoin-qt tries to randomize the position of the change output, but I believe the code has a flaw:

// Insert change txn at random position:
vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));

The problem is that size() is one in the common case of one payee, so GetRandInt will always return 0.The change ends up in the first output.

I think it should be size()+1.

Exploiting this bug I made a chart showing transaction volume of output #1 only: [CHART] Bitcoin Actual Transaction Volume? (using "change is never last" bug)
hero member
Activity: 900
Merit: 1014
advocate of a cryptographic attack on the globe
December 21, 2012, 11:10:01 AM
#30
I'm proud of myself  Smiley  because I see this kind of bug coming. I posted this line on November 6, 2012 in my blog (bitslog):

"The (pseudo) anonymization property of Bitcoin is the easiest property to be lost while modifying the code, since the related code is not encapsulated in a certain class or file, but spread all over the code."


Good call Sergio Smiley
hero member
Activity: 555
Merit: 654
December 21, 2012, 10:11:02 AM
#29
I'm proud of myself  Smiley  because I saw this kind of bug coming. I posted this line on November 6, 2012 in my blog (bitslog):

"The (pseudo) anonymization property of Bitcoin is the easiest property to be lost while modifying the code, since the related code is not encapsulated in a certain class or file, but spread all over the code."

Hal
vip
Activity: 314
Merit: 4276
December 14, 2012, 10:46:46 PM
#28
I felt bad about losing that donation address, particularly after elux very generously donated a whole bitcoin. I found a wallet on a backup that had the key, and so I was able to retrieve the funds. Again, thanks very much!
legendary
Activity: 1120
Merit: 1152
December 14, 2012, 07:22:34 PM
#27
Yes, I saw that project, I'm curious to try it out myself, although I'll have to upgrade my computer first.

It's interesting that you found this bug by looking at the code. I mean, the results of it have been sitting in plain sight for, well, anyone to see. Heck, I'm kicking myself for not realizing it, let alone how Gavin and the other devs must feel. It's remarkable that Meni was the first person to notice and bring it to the attention of the forum after all this time, and even then it took your post for what he actually said to sink in.

Re: donations, I sent both you and the OP a BTC after applying your patch. Fortunately for Meni it took two tries for it to be obvious that the patch worked...
Hal
vip
Activity: 314
Merit: 4276
December 14, 2012, 07:06:44 PM
#26
Actually the OP observed that the software always puts the change first. I was working on a separate project suggested by Mike Hearn, using the new secure "trusted computing" modes on modern cpus to enforce spending limits even when infested with malware. I'm using Jon McCune's flicker software from sourceforge. The secure mode signs transactions and enforces limits on spends, but to know the transaction amount it has to know which is the change output.So I was just looking at this code yesterday and scratching my head (figuratively). I'll post more on this project when it's further along.

As far as my donation address, I created that years ago using Gavin's original vanitygen patch. I don't even know if I still have the key. It might be on a computer I don't use any more. I've substituted one of my offline savings wallet addresses. I shouldn't lose that.I'm not hurting for bitcoins; I started running the first day (and gave up after a few weeks because of the fan noise). Still, it's the thought that counts - thanks!
legendary
Activity: 1120
Merit: 1152
December 14, 2012, 06:43:47 PM
#25
I think Hal's donation wallet address has a flaw. The problem is that balance() returned 0.

I added one bitcoin, but balance()+1 doesn't seem like enough.

Details here: http://blockchain.info/address/1HALookLvrqrn2kxHhXCnwDgknD3RXifhH

From Hal's sig:

Quote
Hal 157i5gK7iN4bNAN39Ahuoiq6Tx5TaQukTE

So Hal, which one is your current Bitcoin address?


Also, it's funny how every tx to 1HALook is obviously affected by this bug.
hero member
Activity: 784
Merit: 1009
firstbits:1MinerQ
December 14, 2012, 06:18:41 PM
#24
I think it's also worthwhile pointing out that now there is a "known" history of change/payment values. It should be easier to develop algorithms that can select future change values even after the bug is fixed, which a much higher confidence level.
legendary
Activity: 1400
Merit: 1005
December 14, 2012, 06:03:04 PM
#23
When will we have a fix for this?

you could just add "+1" after "size()" and recompile. maybe do some testing before using it productively.
I don't compile. Did it once, never planning to do it again. Biggest headache I've ever experienced.  So, I am asking about a general installer release.

Personally, I don't really care about this anonymous side of things and hiding my true balance or associated addresses.  I don't have anything to hide with regards to my transactions.  But I know a lot of people do care about it, so I am sort of asking on everyone's behalf when we can expect an updated client to be released.
donator
Activity: 2772
Merit: 1019
December 14, 2012, 05:57:42 PM
#22
When will we have a fix for this?

you could just add "+1" after "size()" and recompile. maybe do some testing before using it productively.
full member
Activity: 151
Merit: 100
December 14, 2012, 03:46:26 PM
#21
bitcoin-qt tries to randomize the position of the change output, but I believe the code has a flaw:

// Insert change txn at random position:
vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));

The problem is that size() is one in the common case of one payee, so GetRandInt will always return 0.The change ends up in the first output.

I think it should be size()+1.

long live the open source!
legendary
Activity: 1680
Merit: 1035
December 14, 2012, 01:31:24 PM
#20
bitcoin-qt tries to randomize the position of the change output, but I believe the code has a flaw...
Ay carumba, how did we not notice that for over two years?


Because we're still in Beta  Grin
legendary
Activity: 1400
Merit: 1005
December 14, 2012, 11:34:02 AM
#19
When will we have a fix for this?
hero member
Activity: 555
Merit: 654
December 14, 2012, 08:35:58 AM
#18
bitcoin-qt tries to randomize the position of the change output, but I believe the code has a flaw:

// Insert change txn at random position:
vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));

The problem is that size() is one in the common case of one payee, so GetRandInt will always return 0.The change ends up in the first output.

I think it should be size()+1.

Excellent catch Hal!!!!.
It's clear that is very important that programmers/researchers of the community, apart from the core developers, review the code.

Some time ago I added to the Weaknesses page of the Bitcoin wiki a section "Security Vulnerabilities and bugs" (https://en.bitcoin.it/wiki/Weaknesses#Security_Vulnerabilities_and_bugs) regarding the impact of bugs. I will update to reflect this one.

staff
Activity: 4284
Merit: 8808
December 14, 2012, 06:51:26 AM
#17
Maybe because all this time nobody made an analysis of the Bitcoin transaction graph which prompted an investigation into ways to determine common ownership of addresses Smiley. So you can thank Adi and Dorit for that.
More like: the fact that their analysis didn't turn that up further confirms how shallow and ineffective the research was.  If only there were real research happening it might have been discovered more quickly!  (Of course, many other people did do things with the transaction graph without noticing this too— see for example blockchain.info's taint tracking service. So they were hardly alone in not noticing it)
donator
Activity: 2772
Merit: 1019
December 14, 2012, 06:44:52 AM
#16
bitcoin-qt tries to randomize the position of the change output, but I believe the code has a flaw:

// Insert change txn at random position:
vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));

The problem is that size() is one in the common case of one payee, so GetRandInt will always return 0.The change ends up in the first output.

I think it should be size()+1.

Holy moly! That means we can get a much better approximation of transaction volume Wink
legendary
Activity: 1458
Merit: 1006
December 14, 2012, 06:07:56 AM
#15
I think Hal's donation wallet address has a flaw. The problem is that balance() returned 0.

I added one bitcoin, but balance()+1 doesn't seem like enough.

Details here:
http://blockchain.info/address/1HALookLvrqrn2kxHhXCnwDgknD3RXifhH
http://blockchain.info/address/157i5gK7iN4bNAN39Ahuoiq6Tx5TaQukTE

I think it should be size()+1.

Seeing this made me really happy.
donator
Activity: 2058
Merit: 1054
December 14, 2012, 03:52:12 AM
#14
bitcoin-qt tries to randomize the position of the change output, but I believe the code has a flaw...
Ay carumba, how did we not notice that for over two years?
Maybe because all this time nobody made an analysis of the Bitcoin transaction graph which prompted an investigation into ways to determine common ownership of addresses Smiley. So you can thank Adi and Dorit for that.

Also: http://dilbert.com/strips/comic/2001-10-25/. Many of us have looked at transactions in Blockexplorer, assuming change should be in a random location, but without paying special attention to this, there's hardly any smoking gun saying "This isn't random".
Pages:
Jump to: