joepie91 / node-random-number-csprng

A cryptographically secure generator for random numbers in a range.
83 stars 9 forks source link

calculateParameters seems to be broken on node #4

Open adrian-gierakowski opened 6 years ago

adrian-gierakowski commented 6 years ago

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

almic commented 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.)

PROger4ever commented 5 years ago

Can we fix it anyway? I don't know, maybe replace bitwise operators with dividing/subtracting or something like that?