Open adrian-gierakowski opened 6 years ago
This looks like a limitation of how Javascript implements numbers, and the bitwise operators in javascript, which convert the signed 64 bit floating point numbers to 32 bit integers before operating on them. Why they made it like that, I have no clue. Compatibility? Maybe just oversight?
From https://www.w3schools.com/js/js_bitwise.asp on 2/15/2018
JavaScript Uses 32 bits Bitwise Operands
JavaScript stores numbers as 64 bits floating point numbers, but all bitwise operations are performed on 32 bits binary numbers.
Before a bitwise operation is performed, JavaScript converts numbers to 32 bits signed integers. After the bitwise operation is performed, the result is converted back to 64 bits JavaScript numbers.
The examples above uses 4 bits unsigned binary numbers. Because of this ~ 5 returns 10. Since JavaScript uses 32 bits signed integers, it will not return 10. It will return -6.
00000000000000000000000000000101 (5) 11111111111111111111111111111010 (~5 = -6)
A signed integer uses the leftmost bit as the minus sign.
This seems to be exactly what's happening here. For now, just don't use ranges any bigger than 2^32 - 1
, or 4,294,97,295. As long as the range is smaller than 2^32, the numbers won't overflow. Use numbers as big as MAX_SAFE_INTEGER, but the range can't be bigger than 2^32.
Then again, if you are trying to generate numbers that big, then going through the effort of making it slightly more secure with all this fluff is trumped by sheer size of possible options.
(Not exactly a professional, but I'm sure there's a number library for bitwise operations on large numbers. Implementing it yourself and making a pull request should take a few minutes if you really need ranges that big.)
Can we fix it anyway? I don't know, maybe replace bitwise operators with dividing/subtracting or something like that?
calculateParameters(Math.pow( 2, 31 )) => { bitsNeeded: 32, bytesNeeded: 4, mask: -1 } calculateParameters(Math.pow( 2, 32 )) => { bitsNeeded: 1, bytesNeeded: 1, mask: 3 } calculateParameters(Number.MAX_SAFE_INTEGER) => { bitsNeeded: 32, bytesNeeded: 4, mask: -1 }
tested with node 6 and 7 see: https://repl.it/repls/SuperUpbeatNandoo