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

Random coin sort is slightly biased #907

Open
emilbayes opened this issue Nov 12, 2019 · 5 comments
Open

Random coin sort is slightly biased #907

emilbayes opened this issue Nov 12, 2019 · 5 comments
Labels
wallet Wallet related

Comments

@emilbayes
Copy link

Random sorting of coins during coin selection uses Math.random(), which outputs in the interval [0, 1[. Splitting this interval in two equal intervals yields [0, 0.5[ and [0.5, 1[. This means the current sort is slightly biased as it considers the intervals [0, 0.5] and ]0.5, 1[. In large this probably doesn't matter, but it is a slight logic bug. It can easily be fixed by changing to either < or >=

return Math.random() > 0.5 ? 1 : -1;

@pinheadmz
Copy link
Member

Interesting, good eye!

Looks to me like the default for initializing the coin selection in init() is by value anyway (not random) and there is a good deal of processing that follows in the coin selector anyway, so this bug will very rarely have a noticeable effect.

But I think you are right, if the random initialization is selected, there will be a tiny bias towards coins that occur later in the passed coins array. How tiny? I'm curious.

Well, Math.random() returns a 64-bit float with 52 bits of "entropy" like 0.22262904318293097. Since this is only a bug in the case that Math.random() returns exactly 0.5 the sorting function will select the "b" value an extra 1/2^52 times 😁 (Check my math?)

Were you noticing nay other bugs? Out of curiosity, What brings you own to this part of the code base? Thank you for your observation!

@emilbayes
Copy link
Author

Floats are not uniformly distributed in that range, so I don't think the probability is that simple. But like I mentioned above, I don't think "bug" is of any consequence :)

@tynes
Copy link
Member

tynes commented Nov 13, 2019

Maybe bcrypto.random.randomRange would be a better source of randomness?
It uses "openssl/rand.h" and "random.h"

https://github.com/bcoin-org/bcrypto/blob/master/src/random/random.c
https://github.com/bcoin-org/bcrypto/blob/master/lib/js/random.js#L89

@emilbayes
Copy link
Author

emilbayes commented Nov 13, 2019

If you want to go that route, then a random bitflip is probably better, eg. bcrypto.random.randomInt() which will give interval [0, 2**32[, split it and you get [0, 2**16[, [2**16, 2**32[ and you can then check randInt =< 0xffff

@emilbayes
Copy link
Author

emilbayes commented Nov 14, 2019

@tynes Actually that function you linked doesn't allow you to generate the full uint32 range, because the max is exclusive but also asserted to be a valid 32 bit uint itself. Don't know if this is on purpose :)
https://github.com/bcoin-org/bcrypto/blob/b812f35db315b0272790202ca386a3cbbfc20d87/lib/js/random.js#L91

@pinheadmz pinheadmz added the wallet Wallet related label Nov 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wallet Wallet related
Projects
None yet
Development

No branches or pull requests

3 participants