Diffie-Hellman implementation doesn't work for bigger numbers - javascript

Context
I was looking at this video DHE explained
It talks about how two people can exchange a key without eyedroppers to know much.
The implementation according to the video
// INITIALIZERS (video's values)-------------------------
var prefx = 3
var modulo = 17
// SECRET NUMBERS ---------------------------------------
var alice_secret_number = 19 // replaced 54 since there is a precision loss with it.
var bob_secret_number = 24
// PUBLIC KEYS ------------------------------------------
var public_alice = Math.pow(prefx , alice_secret_number)
var public_bob = Math.pow(prefx , bob_secret_number)
// Check potential overflow -----------------------------
console.log(public_alice , public_bob)
// Apply the modulo -------------------------------------
public_alice %= modulo
public_bob %= modulo
// Check the value again --------------------------------
console.log( public_alice , public_bob )
// Calculate the good number ------------------------------------------
var final_alice = Math.pow( public_bob , alice_secret_number ) % modulo
var final_bob = Math.pow( public_alice , bob_secret_number ) % modulo
console.log( final_alice , final_bob )
Problem
That doesn't always work. First, javascript, for example, loses precision.
So you can try with small numbers only. The speaker talks about big modulos. Even small one won't make it.
I gave you the code, which is not tailored toward performance but readability.
Could someone give me his/her opinion on what I am doing wrong?

All numbers in JavaScript are floats (actually doubles). The corresponding specification is IEEE 754. To represent an integer without loss of precision it must fit into the mantissa which is 53 bit big for 64 bit floats. You can check the maximum integer with Number.MAX_SAFE_INTEGER which is 9007199254740991. Everything beyond that loses precision.
Why is this a problem? (Most of) cryptography must be exact otherwise the secret cannot be learned. What you try to do is exponentiate and then apply the modulus, but since you do this separately, you get a very big number after exponentiation before it can be reduced through the modulus operation.
The solution is to use some kind of BigNumber library (like BigInteger) which handles all those big numbers for you. Note that there is specifically a modPow(exp, mod) function which combines those two steps and calculates the result efficiently.
Note that user secrets should be smaller than the modulus.

Related

What's the biggest BigInt value in js as per spec

It turns out (outer a bit of thought it's more obvious but whatever) that BigInt recently introduced to javascript has a limit:
My question would be - is there a constant similar to Number.MAX_SAFE_INTEGER but for BigInt?
This snippet of code:
let a = 2n, step = 1;
try{while(true) {
console.log(step);
a=a**2n; step++
}} catch(e){ console.log(e)}
Shows that the limit is about (step = 32) - at least in Chrome. But I wonder what it this value as per spec.
It seems like there is no maximum limit to a BigInt as per spec, which makes sense considering BigInts are supposed to be arbitrary-precision integers, whose "digits of precision are limited only by the available memory of the host system".
As for v8 specifically, according to this article on the v8 blog, the precision of BigInts are "arbitrary up to an implementation-defined limit". Unfortunately, I couldn't find any further information on how the limit is determined. Maybe someone else would be able to shed light on this based on these v8 BigInt implementation notes?
That said, based on the aforementioned articles, there doesn't seem to be a specific maximum value/size for a BigInt. Rather, it is likely determined based on the available memory on the system in some way.
The maximum size of a BigInt in webkit is defined as such
// The maximum length that the current implementation supports would be
// maxInt / digitBits. However, we use a lower limit for now, because
// raising it later is easier than lowering it.
// Support up to 1 million bits.
static constexpr unsigned maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
The size of void* is platform dependent, 8 on 64 bit systems.
So there's your answer right? Should be 16384 bits.... (-1 for the sign). But I can't create anywhere near that large a number in console.
The size has arbitrary precision, per 4.3.25BigInt value, though, oddly not mentioned in the 20.2 BigInt Objects section.
Here is a quick test program:
/* global BigInt */
let b = BigInt(10)
let exp = 1;
while (true) {
console.log(`BigInt of 10^${exp} `);
b = b * b;
exp *= 2;
}
output with Node v13.2:
BigInt of 10^1
BigInt of 10^2
BigInt of 10^4
...
BigInt of 10^4194304
BigInt of 10^8388608
BigInt of 10^16777216
Performance really drags after about 10 to the millionth.
While there may be a platform specific maximum in a specific browser, the size requirement to show it would be large. Even 10^10^6 takes over 300K to store. You could extend the spec to add a limit with Tetration, e.g., "limit is about 10^10^10^... 8 times", but, seriously, that would be silly.
It turns out it's 2^30 - 1 bits, or 2^(2^30) - 1. Any more bits and it wouldn't work. (I was unable to get the actual value, since bit shifts can't do that) To put that in comparison, there are more digits in that number than the population in the US (almost 2x)!
(Wolfram Alpha link for the number of digits)
Tested on a modern Chrome browser.

(Novice Programmer) mod(3^146, 293) among others returning the same incorrect values in Matlab and JS

First note that mod(3^146,293)=292. For some reason, inputting mod(3^146,293) in Matlab returns 275. Inputting Math.pow(3,146) % 293 in JS returns 275. This same error occurs (as far as I can tell) every time. This leads me to believe I am missing something obvious but cannot seem to tell what.
Any help is much appreciated.
As discussed in the answers to this related question, MATLAB uses double-precision floating point numbers by default, which have limits on their resolution (i.e. the floating point relative accuracy, eps). For example:
>> a = 3^146
a =
4.567759074507741e+69
>> eps(a)
ans =
7.662477704329444e+53
In this case, 3146 is on the order of 1069 and the relative accuracy is on the order of 1053. With only 16 digits of precision, a double can't store the exact integer representation of an arbitrary 70 digit integer.
An alternative in MATLAB is to use the Symbolic Toolbox to create symbolic numbers with a greater resolution. This gives you the answer you expect:
>> a = sym('3^146')
a =
4567759074507740406477787437675267212178680251724974985372646979033929
>> mod(a, 293)
ans =
292
Math.pow(3, 146) is is larger than the constant Number.MAX_SAFE_INTEGER in JavaScript which represents the upper limit of numbers that can be represented without losing any accuracy. Therefore JavaScript cannot accurately represent Math.pow(3, 146) within the 64 bit limit.
MatLab also has limits on its integer size but can represent a large number with the Symbolic Math Toolbox.
There are also algorithms that you can implement to accomplish this without overflowing.

How to raise to the power of an exponent?

How can I calculate 98 raised to the power of exp(13-5) using JavaScript?
Is this the way?
Math.pow(98,Math.exp(8))
When I need to handle large positive numbers that would overflow standard floating point types then I store the numbers as log of the number instead. So instead of calculating 98 to the power of exp(8), I'd calculate exp(8) * log(98) and work with that. I haven't (yet) come across a situation where even that method was inadequate to store the numbers that I needed. However, I have come across several situations where the right answer involves multiplying very very large numbers by very very small numbers, and in that situation using logs as I described has avoided overflows/underflows which would result in the wrong answer.
Update: I suspect this is some kind of homework question relating to how to get round the problem that 98 ^ exp(8) is too big for standard floating point types. In which case, I think my suggestion to use logs comes in handy. For example, to print out the number in C# you could do the following:
double x = Math.Exp(13 - 5) * Math.Log(98); // the number required is exp(x)
int exponent = (int)Math.Floor(x / Math.Log(10));
double absissae = Math.Exp(x - exponent * Math.Log(10));
System.Diagnostics.Trace.WriteLine(absissae.ToString() + " E " + exponent.ToString());
which produces the output
5.77130918514205 E 5935

Preserving the floating point & addition of a bitwise operation in javascript

I am trying to understand the way to add, subtract, divide, and multiply by operating on the bits.
It is necessary to do some optimizing in my JavaScript program due to many calculations running after an event has happened.
By using the code below for a reference I am able to understand that the carry holds the &ing value. Then by doing the XOr that sets the sum var to the bits that do not match in each n1 / n2 variable.
Here is my question.;) What does shifting the (n1 & n2)<<1 by 1 do? What is the goal by doing this? As with the XOr it is obvious that there is no need to do anything else with those bits because their decimal values are ok as they are in the sum var. I can't picture in my head what is being accomplished by the & shift operation.
function add(n1,n2)
{
var carry, sum;
// Find out which bits will result in a carry.
// Those bits will affect the bits directly to
// the left, so we shall shift one bit.
carry = (n1 & n2) << 1;
// In digital electronics, an XOR gate is also known
// as a quarter adder. Basically an addition is performed
// on each individual bit, and the carry is discarded.
//
// All I'm doing here is applying the same concept.
sum = n1 ^ n2;
// If any bits match in position, then perform the
// addition on the current sum and the results of
// the carry.
if (sum & carry)
{
return add(sum, carry);
}
// Return the sum.
else
{
return sum ^ carry;
};
};
The code above works as expected but it does not return the floating point values. I've got to have the total to be returned along with the floating point value.
Does anyone have a function that I can use with the above that will help me with floating point values? Are a website with a clear explanation of what I am looking for? I've tried searching for the last day are so and cannot find anything to go look over.
I got the code above from this resource.
http://www.dreamincode.net/code/snippet3015.htm
Thanks ahead of time!
After thinking about it doing a left shift to the 1 position is a multiplication by 2.
By &ing like this : carry = (n1 & n2) << 1; the carry var will hold a string of binaries compiled of the matched positions in n1 and n2. So, if n1 is 4 and n2 is 4 they both hold the same value. Therefore, by combing the two and right shifting to the 1 index will multiply 4 x 2 = 8; so carry would now equal 8.
1.) var carry = 00001000 =8
&
00001000 =8
2.) carry = now holds the single value of 00001000 =8
A left shift will multiply 8 x 2 =16, or 8 + 8 = 16
3.)carry = carry <<1 , shift all bits over one position
4.) carry now holds a single value of 00010000 = 16
I still cannot find anything on working with floating point values. If anyone has anything do post a link.
It doesn't work because the code assumes that the floating point numbers are represented as integer numbers, which they aren't. Floating point numbers are represented using the IEEE 754 standard, which breaks the numbers in three parts: a sign bit, a group of bits representing an exponent, and another group representing a number between 1 (inclusive) and 2 (exclusive), the mantissa, and the value is calculated as
(sign is set ? 1 : -1) * (mantissa ^ (exponent - bias))
Where the bias depends on the precision of the floating point number. So the algorithm you use for adding two numbers assumes that the bits represent an integer which is not the case for floating point numbers. Operations such as bitwise-AND and bitwise-OR also don't give the results that you'd expect in an integer world.
Some examples, in double precision, the number 2.3 is represented as (in hex) 4002666666666666, while the number 5.3 is represented as 4015333333333333. OR-ing those two numbers will give you 4017777777777777, which represents (roughly) 5.866666.
There are some good pointers on this format, I found the links at http://www.psc.edu/general/software/packages/ieee/ieee.php, http://babbage.cs.qc.edu/IEEE-754/ and http://www.binaryconvert.com/convert_double.html fairly good for understanding it.
Now, if you still want to implement the bitwise addition for those numbers, you can. But you'll have to break the number down in its parts, then normalize the numbers in the same exponent (otherwise you won't be able to add them), perform the addition on the mantissa, and finally normalize it back to the IEEE754 format. But, as #LukeGT said, you'll likely not get a better performance than the JS engine you're running. And some JS implementations don't even support bitwise operations on floating point numbers, so what usually ends up happening is that they first cast the numbers to integers, then perform the operation, which will make your results incorrect as well.
Floating point values have a complicated bit structure, which is very difficult to manipulate with bit operations. As a result, I doubt you could do any better than the Javascript engine at computing them. Floating point calculations are inherently slow, so you should try to avoid them if you're worried about speed.
Try using integers to represent a decimal number to x amount of digits instead. For example if you were working with currency, you could store things in terms of whole cents as opposed to dollars with fractional values.
Hope that helps.

Precise Financial Calculation in JavaScript. What Are the Gotchas?

In the interest of creating cross-platform code, I'd like to develop a simple financial application in JavaScript. The calculations required involve compound interest and relatively long decimal numbers. I'd like to know what mistakes to avoid when using JavaScript to do this type of math—if it is possible at all!
You should probably scale your decimal values by 100, and represent all the monetary values in whole cents. This is to avoid problems with floating-point logic and arithmetic. There is no decimal data type in JavaScript - the only numeric data type is floating-point. Therefore it is generally recommended to handle money as 2550 cents instead of 25.50 dollars.
Consider that in JavaScript:
var result = 1.0 + 2.0; // (result === 3.0) returns true
But:
var result = 0.1 + 0.2; // (result === 0.3) returns false
The expression 0.1 + 0.2 === 0.3 returns false, but fortunately integer arithmetic in floating-point is exact, so decimal representation errors can be avoided by scaling1.
Note that while the set of real numbers is infinite, only a finite number of them (18,437,736,874,454,810,627 to be exact) can be represented exactly by the JavaScript floating-point format. Therefore the representation of the other numbers will be an approximation of the actual number2.
1 Douglas Crockford: JavaScript: The Good Parts: Appendix A - Awful Parts (page 105).
2 David Flanagan: JavaScript: The Definitive Guide, Fourth Edition: 3.1.3 Floating-Point Literals (page 31).
Scaling every value by 100 is the solution. Doing it by hand is probably useless, since you can find libraries that do that for you. I recommend moneysafe, which offers a functional API well suited for ES6 applications:
const { in$, $ } = require('moneysafe');
console.log(in$($(10.5) + $(.3)); // 10.8
https://github.com/ericelliott/moneysafe
Works both in Node.js and the browser.
There's no such thing as "precise" financial calculation because of just two decimal fraction digits but that's a more general problem.
In JavaScript, you can scale every value by 100 and use Math.round() everytime a fraction can occur.
You could use an object to store the numbers and include the rounding in its prototypes valueOf() method. Like this:
sys = require('sys');
var Money = function(amount) {
this.amount = amount;
}
Money.prototype.valueOf = function() {
return Math.round(this.amount*100)/100;
}
var m = new Money(50.42355446);
var n = new Money(30.342141);
sys.puts(m.amount + n.amount); //80.76569546
sys.puts(m+n); //80.76
That way, everytime you use a Money-object, it will be represented as rounded to two decimals. The unrounded value is still accessible via m.amount.
You can build in your own rounding algorithm into Money.prototype.valueOf(), if you like.
Unfortunately all of the answers so far ignore the fact that not all currencies have 100 sub-units (e.g., the cent is the sub-unit of the US dollar (USD)). Currencies like the Iraqi Dinar (IQD) have 1000 sub-units: an Iraqi Dinar has 1000 fils. The Japanese Yen (JPY) has no sub-units. So "multiply by 100 to do integer arithmetic" isn't always the correct answer.
Additionally for monetary calculations you also need to keep track of the currency. You can't add a US Dollar (USD) to an Indian Rupee (INR) (without first converting one to the other).
There are also limitations on the maximum amount that can be represented by JavaScript's integer data type.
In monetary calculations you also have to keep in mind that money has finite precision (typically 0-3 decimal points) & rounding needs to be done in particular ways (e.g., "normal" rounding vs. banker's rounding). The type of rounding to be performed might also vary by jurisdiction/currency.
How to handle money in javascript has a very good discussion of the relevant points.
In my searches I found the dinero.js library that addresses many of the issues wrt monetary calculations. Haven't used it yet in a production system so can't give an informed opinion on it.
use decimaljs ... It a very good library that solves a harsh part of the problem ...
just use it in all your operation.
https://github.com/MikeMcl/decimal.js/
Your problem stems from inaccuracy in floating point calculations. If you're just using rounding to solve this you'll have greater error when you're multiplying and dividing.
The solution is below, an explanation follows:
You'll need to think about mathematics behind this to understand it. Real numbers like 1/3 cannot be represented in math with decimal values since they're endless (e.g. - .333333333333333 ...). Some numbers in decimal cannot be represented in binary correctly. For example, 0.1 cannot be represented in binary correctly with a limited number of digits.
For more detailed description look here: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Take a look at the solution implementation: http://floating-point-gui.de/languages/javascript/
Due to the binary nature of their encoding, some decimal numbers cannot be represented with perfect accuracy. For example
var money = 600.90;
var price = 200.30;
var total = price * 3;
// Outputs: false
console.log(money >= total);
// Outputs: 600.9000000000001
console.log(total);
If you need to use pure javascript then you have need to think about solution for every calculation. For above code we can convert decimals to whole integers.
var money = 60090;
var price = 20030;
var total = price * 3;
// Outputs: true
console.log(money >= total);
// Outputs: 60090
console.log(total);
Avoiding Problems with Decimal Math in JavaScript
There is a dedicated library for financial calculations with great documentation. Finance.js
Use this code for currency calculation and round numbers in two digits.
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript Variables</h1>
<p id="test1"></p>
<p id="test2"></p>
<p id="test3"></p>
<script>
function setDecimalPoint(num) {
if (isNaN(parseFloat(num)))
return 0;
else {
var Number = parseFloat(num);
var multiplicator = Math.pow(10, 2);
Number = parseFloat((Number * multiplicator).toFixed(2));
return (Math.round(Number) / multiplicator);
}
}
document.getElementById("test1").innerHTML = "Without our method O/P is: " + (655.93 * 9)/100;
document.getElementById("test2").innerHTML = "Calculator O/P: 59.0337, Our value is: " + setDecimalPoint((655.93 * 9)/100);
document.getElementById("test3").innerHTML = "Calculator O/P: 32.888.175, Our value is: " + setDecimalPoint(756.05 * 43.5);
</script>
</body>
</html>

Categories

Resources