I need to generate a cryptographically secure 64-bit unsigned random integer in Javascript. The first problem is that Javascript only allows 64-bit signed integers, so 9223372036854775808 is the biggest supported integer without going into floating point use I think? To fix this I can use a big number library, no problem.
My Method:
var randNum = SHA256( randBigInt(128, 0) ) % 2^64;
Where SHA256() is a secure hash function and randBigInt() is defined below as a non-crypto PRNG, im giving it a 128bit seed so brute force shouldn't be a problem.
randBigInt(n,s) //return an n-bit random BigInt (n>=1). If s=1, then the most significant of those n bits is set to 1.
Is this a secure method to generate a cryptographically secure 64-bit random int? And importantly does taking the 2^64 mod guarantee 100% I have a 64-bit number?
An abstract example, say this number is prime (it isn't i know), I will use it in the Galois Field [2^p], where p must be 64bits so that every possible 1-63bit number is a field element. In this query, my random int must be larger than any 63-bit number. And Im not sure im correct in taking the 2^64 mod of a 256bit hash output.
Thanks (hope that makes sense)
You can't turn a non-crypto-secure PRNG into a secure one simply by hashing the output in this way. You've only got as much entropy as you provided as input to seed the PRNG. Sure, the output looks random, but if the attacker knows your scheme (and you ought to assume they do, taking Kerchoffs' principles as axiomatic) then they can guess and/or brute force the inputs.
Also, you seem a little unclear over what you want by a "64-bit number". Do you want 64 bits of random data - in which case the chance of the highest bit being set should be 50% - or do you want some other property like a number between 2^63 and 2^64-1? What are you trying to do, anyway?
The output of a crypto-secure hash function (careful: I'm not sure that SHA256 on its own is ideal as a PRNG) is supposed to pass statistical tests, so you can be pretty sure that the probability of every individual bit being 1 is (very close to) 50%. This is great for generating symmetric keys, but that's not what you're hinting at here?
(As you go on to say, if you're talking about GF(2^p) you do indeed need a prime of a given size. If that's what you're doing, there are algorithms which generate probably and provably prime numbers, and you should look into those instead.)
All JavaScript numbers are actually IEEE 754 doubles, which means you can only exactly represent integers with magnitude <= 2^53. See this answer. So you will need a bignum library.
Taking the mod (%) gives you a number >= 0 and <= 2^64 - 1. 2^64 - 1 is the largest 63-bit number.
Finally, if you feed non-random input into SHA256, you'll get non-random output. In the extreme, if randBigInt always returns 0, than SHA256 will always return the same thing.
Go to:
http://www.number.com.pt/index.html
And on
PRECISION AND IMPLEMENTATION
Get 1000 decimal pseudorandom numbers and see the code.
Related
I found this snippet online along with this Stackoverflow post which converts it into a TypeScript class.
I basically copy and pasted it verbatim (because I am not qualified to modify this sort of cryptographic code), but I noticed that VS Code has a little underline in the very last function:
/**
* generates a random number on [0,1) with 53-bit resolution
*/
nextNumber53(): number {
let a = this._nextInt32() >>> 5;
let b = this._nextInt32() >>> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
}
Specifically the 9007199254740992.0
VS Code says Numeric literals with absolute values equal to 2^53 or greater are too large to be represented accurately as integers.ts(80008)
I notice that if I subtract that number by one and instead make it 9007199254740991.0, then the warning goes away. But I don't necessarily want to modify the code and break it if this is indeed a significant difference.
Basically, I am unsure, because while my intuition says that having a numerical overflow is bad, my intuition also says that I shouldn't try to fix cryptographic code that was posted in several places, as it is probably correct.
But is it? Or should this number be subtracted by one?
9007199254740992 is the right value to use if you want Uniform values in [0,1), i.e. 0.0 <= x < 1.0.
This is just the automatics going awry, this value can be accurately represented by a JavaScript Number, i.e. a 64bit float. It's just 253 and binary IEEE 754 floats have no trouble with numbers of this form (it would even be represented accurately with a 32bit float).
Using 9007199254740991 would make the range [0,1], i.e. 0.0 <= x <= 1.0. Most libraries generate uniform values in [0,1) and other distributions are derived from that, but you are obviously free to do whatever is best for your application.
Note that the actual chance of getting the maximum value back is 2-53 (~1e-16) so you're unlikely not actually see it in practice.
i just wanted to know javascript number size because i want to send lot of them via network per frame and i must know a measure of how many im gonna send per second.
As i readed:
According to the ECMAScript standard, there is only one number type: the double-precision 64-bit binary format IEEE 754 value (number between -(2^53 -1) and 2^53 -1).
So if im gonna send lot of diferent numbers(example later) if all numbers between -(2^53 -1) and (2^53 -1) use same memory i may just combinate them like 567832332423556 and then locally split them locally when received instead of sending a lot of diferent numbers, because anyway that unique number "567832332423556" sends same information as a separated 5,6,7,8... but in one so its supossed to waste many less if it haves same size as a single 5.
Is this true or just im so confused? pls explain me :(.
var data = Array2d(obj.size); //Size can be between 125 and 200;`
Array2d: function (rows) { //The number of rows and files are same
var arr = [];
for (var i=0;i<rows;i++) arr[i] = [];
return arr;
},
...
if (this.calculate()) {
data[x][y] = 1;
} else {
data[x][y] = 0;
}
and somewhere in the code i change those 1 to any number from 2 to 5 so numbers may be from 0 to 5 depends of the situation.
Example:
[
[0,0,2,1,3,4,5,0,2,3,4,5,4(200 numbers)],
[0,5,2,1,5,1,0,2,3,0,0,0,0(200 numbers)]
...(200 times)
]
*And i really need All numbers, i cant miss even one.
If in therms of size 5 is shame as 34234 so i could just do something like:
[
[0021345023454...(20 numbers 10 times)],
[0021345023454...(20 numbers 10 times)]
...(200 times)
]
and it may use 20 times less because if 5 size is the same as 2^53 i just stack numbers 20 by 20 and they should waste lot less (ofc, 20 numbers less by stacking 20, at least in the network, maybe the local split is a little big but locally i do few things so i can handle that).
Precise limits on numbers are covered in What is JavaScript's highest integer value that a Number can go to without losing precision? - 9007199254740991 for regualr arithmetic operations, 2^32 for bit operations.
But it sounds like you are more interested in network representation than memory usage at run-time. Below is list of options from less to more compact. Make sure to understand your performance goals before moving away from basic JSON solution -as cost and complexity of constructing data rises more compatc representation you pick.
Most basic solution - JSON representation of existing array gives pretty decent ~2 characters per value representation:
[[0,1,5,0,0],[1,1,1,1,1],[0,0,0,0,0]]
Representing all numbers in a row as one big string gives ~1 character number:
["01500","11111","00000"]
Representing same values as concatenated numbers does not bring much savings - "11111" as string is about as long as the same 11111 as number - you add pair of quotes per row for string but one coma pare 16 values when packing as numbers.
You can indeed pack values to number in more compact form since the range is 0-5 using standard 6-ary value you get ~6^20 per on JavaScript number which is not significant savings over 16 values per number which you get with just representing as digits concatenation.
Better packing would be to represent 2 or 3 values as one character - 2 values give 36 combinations (v1 * 6 + v2) which can be written with just [A-Z0-9], 3 - 216 value which mostly fits into regular characters range.
you can go strictly binary representation (3-4 bit per value) and send via WebSockets to avoid cost of converting to text with regular requests.
Whether you go with binary or text representation one more option is compression - basic RLE compression may be fine if your data have long sequences of same value, other compression algorithms may work better on more random data. There are libraries to perform compression in JavaScript too.
In my angular JS application I have three amounts in one object. In Chrome browser debugger i have following:
payment.amountForClosing = payment.amountRemaining - payment.amountReserved;
payment.amountRemaining has a value of 3026.2
payment.amountReserved has a value of 2478.4
after substraction payment.amountForClosing has a value of 547.7999999999997, and 547.8 is displayed.
When user tries to make another payment closing, my validation logic returns an error indicating that there is not enough money to make payment closing because of state presented above.
Those amount values come from C# WebApi 2.0 backend, as System.Decimal types.
When dealing with currency, worst thing that you can do is use floating point numbers, as you can see. Because of way how floats are stored, some operations may provide incorrect results. Only thing that will always be correct is multiplication/division by power of 10.
Best way is to store currency as Integer/BigInteger, or whatever, and save it with e.g. 4 decimal places so 12100 should represent 1.21
Then you can do subtraction/multiplication of integer numbers and at the end divide by power of 10.
My suggestion is that you transform those numbers to integer before any operation then divide it back to float.
Floating point precision in Javascript has been discussed before (eg. here or here). You have the following options:
Convert all your numbers to integers.
Format the result to a fixed number of significant digits using .toFixed(2)
Use a special datatype for decimals like BigDecimal
Out of all of these I agree with #PerunSS that in your case, the best option would be converting the numbers to integers before any operation, and the converting them back.
I have an interesting question, I have been doing some work with javascript and a database ID came out as "3494793310847464221", now this is being entered into javascript as a number yet it is using the number as a different value, both when output to an alert and when being passed to another javascript function.
Here is some example code to show the error to its fullest.
<html><head><script language="javascript">alert( 3494793310847464221);
var rar = 3494793310847464221;
alert(rar);
</script></head></html>
This has completly baffeled me and for once google is not my friend...
btw the number is 179 more then the number there...
Your number is larger than the maximum allowed integer value in javascript (2^53). This has previously been covered by What is JavaScript's highest integer value that a Number can go to without losing precision?
In JavaScript, all numbers (even integral ones) are stored as IEEE-754 floating-point numbers. However, FPs have limited "precision" (see the Wikipedia article for more info), so your number isn't able to be represented exactly.
You will need to either store your number as a string or use some other "bignum" approach (unfortunately, I don't know of any JS bignum libraries off the top of my head).
Edit: After doing a little digging, it doesn't seem as if there's been a lot of work done in the way of JavaScript bignum libraries. In fact, the only bignum implementation of any kind that I was able to find is Edward Martin's JavaScript High Precision Calculator.
Use a string instead.
179 more is one way to look at it. Another way is, after the first 16 digits, any further digit is 0. I don't know the details, but it looks like your variable only stores up to 16 digits.
That number exceeds (2^31)-1, and that's the problem; javascript uses 32-bit signed integers (meaning, a range from –2,147,483,648 to 2,147,483,647). Your best choice is to use strings, and create functions to manipulate the strings as numbers.
I wouldn't be all too surprised, if there already was a library that does what you need.
One possible solution is to use a BigInt library such as: http://www.leemon.com/crypto/BigInt.html
This will allow you to store integers of arbitrary precision, but it will not be as fast as standard arithmetic.
Since it's to big to be stored as int, it's converted to float. In JavaScript ther is no explicit integer and float types, there's only universal Number type.
"Can't increment and decrement a string easily..."
Really?
function incr_num(x) {
var lastdigit=Number(x.charAt(x.length-1));
if (lastdigit!=9) return (x.substring(0,x.length-1))+""+(lastdigit+1);
if (x=="9") return "10";
return incr_num(x.substring(0,x.length-1))+"0";
}
function decr_num(x) {
if(x=="0") return "(error: cannot decrement zero)";
var lastdigit=Number(x.charAt(x.length-1));
if (lastdigit!=0) return (x.substring(0,x.length-1))+""+(lastdigit-1);
if (x=="10") return "9"; // delete this line if you like leading zero
return decr_num(x.substring(0,x.length-1))+"9";
}
Just guessing, but perhaps the number is stored as a floating type, and the difference might be because of some rounding error. If that is the case it might work correctly if you use another interpreter (browser, or whatever you are running it in)
Some of my data are 64-bit integers. I would like to send these to a JavaScript program running on a page.
However, as far as I can tell, integers in most JavaScript implementations are 32-bit signed quantities.
My two options seem to be:
Send the values as strings
Send the values as 64-bit floating point numbers
Option (1) isn't perfect, but option (2) seems far less perfect (loss of data).
How have you handled this situation?
There is in fact a limitation at JavaScript/ECMAScript level of precision to 53-bit for integers (they are stored in the mantissa of a "double-like" 8 bytes memory buffer). So transmitting big numbers as JSON won't be unserialized as expected by the JavaScript client, which would truncate them to its 53-bit resolution.
> parseInt("10765432100123456789")
10765432100123458000
See the Number.MAX_SAFE_INTEGER constant and Number.isSafeInteger() function:
The MAX_SAFE_INTEGER constant has a value of 9007199254740991. The
reasoning behind that number is that JavaScript uses double-precision
floating-point format numbers as specified in IEEE 754 and can only
safely represent numbers between -(2^53 - 1) and 2^53 - 1.
Safe in this context refers to the ability to represent integers
exactly and to correctly compare them. For example,
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 will
evaluate to true, which is mathematically incorrect. See
Number.isSafeInteger() for more information.
Due to the resolution of floats in JavaScript, using "64-bit floating point numbers" as you proposed would suffer from the very same restriction.
IMHO the best option is to transmit such values as text. It would be still perfectly readable JSON content, and would be easy do work with at JavaScript level.
A "pure string" representation is what OData specifies, for its Edm.Int64 or Edm.Decimal types.
What the Twitter API does in this case, is to add a specific ".._str": field in the JSON, as such:
{
"id": 10765432100123456789, // for JSON compliant clients
"id_str": "10765432100123456789", // for JavaScript
...
}
I like this option very much, since it would be still compatible with int64 capable clients. In practice, such duplicated content in the JSON won't hurt much, if it is deflated/gzipped at HTTP level.
Once transmitted as string, you may use libraries like strint – a JavaScript library for string-encoded integers to handle such values.
Update: Newer versions of JavaScript engines include a BigInt object class, which is able to handle more than 53-bit. In fact, it can be used for arbitrarily large integers, so a good fit for 64-bit integer values. But when serializing as JSON, the BigInt value will be serialized as a JSON string - weirdly enough, but for compatibility purposes I guess.
This seems to be less a problem with JSON and more a problem with Javascript itself. What are you planning to do with these numbers? If it's just a magic token that you need to pass back to the website later on, by all means simply use a string containing the value. If you actually have to do arithmetic on the value, you could possibly write your own Javascript routines for 64-bit arithmetic.
One way that you could represent values in Javascript (and hence JSON) would be by splitting the numbers into two 32-bit values, eg.
[ 12345678, 12345678 ]
To split a 64-bit value into two 32-bit values, do something like this:
output_values[0] = (input_value >> 32) & 0xffffffff;
output_values[1] = input_value & 0xffffffff;
Then to recombine two 32-bit values to a 64-bit value:
input_value = ((int64_t) output_values[0]) << 32) | output_values[1];
Javascript's Number type (64 bit IEEE 754) only has about 53 bits of precision.
But, if you don't need to do any addition or multiplication, then you could keep 64-bit value as 4-character strings as JavaScript uses UTF-16.
For example, 1 could be encoded as "\u0000\u0000\u0000\u0001". This has the advantage that value comparison (==, >, <) works on strings as expected. It also seems straightforward to write bit operations:
function and64(a,b) {
var r = "";
for (var i = 0; i < 4; i++)
r += String.fromCharCode(a.charCodeAt(i) & b.charCodeAt(i));
return r;
}
The JS number representation is a standard ieee double, so you can't represent a 64 bit integer. iirc you get maybe 48 bits of actual int precision in a double, but all JS bitops reduce to 32bit precision (that's what the spec requires. yay!) so if you really need a 64bit int in js you'll need to implement your own 64 bit int logic library.
JSON itself doesn't care about implementation limits.
your problem is that JS can't handle your data, not the protocol.
In other words, your JS client code has to use either of those non-perfect options.
This thing happened to me. All hell broke loose when sending large integers via json into JSON.parse. I spent days trying to debug. Problem immediately solved when i transmitted the values as strings.
Use
{ "the_sequence_number": "20200707105904535" }
instead of
{ "the_sequence_number": 20200707105904535 }
To make it worse, it would seem that where every JSON.parse is implemented, is some shared lib between Firefox, Chrome and Opera because they all behaved exactly the same. Opera error messages have Chrome URL references in it, almost like WebKit shared by browsers.
console.log('event_listen[' + global_weird_counter + ']: to be sure, server responded with [' + aresponsetxt + ']');
var response = JSON.parse(aresponsetxt);
console.log('event_listen[' + global_weird_counter + ']: after json parse: ' + JSON.stringify(response));
The behaviour i got was the sort of stuff where pointer math went horribly bad. Ghosts were flying out of my workstation wreaking havoc in my sleep. They are all exorcised now that i switched to string.