Algorithm for calculating powers of extremely large numbers

Problem

As we all know the expression: \(x^n \mod m; (\forall x,n,m \in \mathbb N)\) is the building block of most of the cryptographic techniques. A simple implementation of it would be:

// calculate x^n
function power(x, n, m) {    
    let result = 1;
    for (let i = 0; i < n; i++) {
        result = (result * n) % m;
    }
    return result;
}

However, the above function wouldn't work with the extremely large number (> 1 bil) since it requires huge execution time.

The algorithm

Knowing that:

$$a^p \times a^q = a^{p+q}$$

and

$$a^{p+q} \mod m = (a^p\mod m)(a^q \mod m)$$

We convert the power value into a sum of series of the powers of two:

$$n = \sum(b_i \times 2^i); \text{for } b_i \text{ either 0 or 1}$$

for example: \(n = 11 = 1\times2^0+1\times2^1+0\times2^2+1\times2^3\). It could be seen that \(n=\overline{b_0b_1\dots b_n}\) is the binary representation of \(n\). For an arbitrary value of \(n\), we break the \(a^n\) into smaller pieces like below:

$$\begin{align*} a^n \mod m &= a^{\sum(b_i \times 2^i)} \mod m\\ &= a^{b_0\times2^0 + b_1\times2^1+...} \mod m \\ &= (a^{b_0\times2^0} \mod m)\times (a^{b_1 \times 2^1} \mod m) \ times \dots \end{align*}$$

Knowing that\((a^{2^k})^2 \mod m= a^{2^{k+1}} \mod m\); it means that once we have calculated \(a^{2^k}\) we can easily calculate \(a^{2^{k+1}} \mod m\) by just squaring it. Now, using a for loop, and a temporary variable to store \(a^{2^k}\) at the step \(k^{th}\). At the next of the for loop, square it up to calculate \(a^{2^{k+1}}\). The complexity of the algorithm is \( O(\log n)\).

// calculate a^n mod m for big n
function quick_pow(a, n, m) {
    if (n === 0) return 1;
    let temp = a;
    let result = 1;
    while (n>0) {
        const b_i = n & 1; // calculate b_i by extracting the right most bit
        if (b_i === 1) {
            result = (result * temp) % m; // calculate the result
        }
        n = n >> 1; // shift right n by 1 bit        
        temp = (temp * temp) % m; // square the temporary value
    }
    return result;
}