Bignum arithmetic notes / 09

Modular exponentiation

Exponentiation is where arithmetic meets side channels: the multiplication routine may be constant-time while the exponent loop leaks the key.

The mathematical task is

\[y=x^e\bmod m.\]

For public exponents, variable-time methods may be acceptable. For secret exponents, the sequence of operations and memory accesses must not reveal exponent bits.

Square-and-multiply

The ordinary left-to-right algorithm scans exponent bits and multiplies only when a bit is 1. This is not constant-time for secret exponents.

/* Variable-time: only for public e. */
for (uint32_t i = bits; i-- > 0;) {
    mont_sqr(acc, acc, m);
    if (bit(e, i)) mont_mul(acc, acc, base, m);
}

Always multiply

A constant-operation-count variant computes both candidates and selects by mask.

for (uint32_t i = bits; i-- > 0;) {
    mont_sqr(sq, acc, m);
    mont_mul(prod, sq, base, m);
    bn_cmov(acc, prod, sq, n, bit(e, i));
}

This still needs fixed-latency mont_mul, fixed loop bounds, and a bit extraction that does not branch on secret-dependent memory length.

Fixed-window exponentiation

A window of width \(w_0\) precomputes odd powers. It reduces multiplications but introduces table lookup risk. Constant-time lookup scans the whole table and conditionally selects each row.

Table selection contract

For secret index \(j\), do not read table[j] directly. Read every table entry and mask-select the desired one. The memory trace must be independent of \(j\).

Montgomery ladder

The ladder maintains two registers, typically \(R_0=x^k\) and \(R_1=x^{k+1}\) for the prefix \(k\). Each bit performs one multiplication and one squaring, with conditional swaps.

Example: RSA public exponent 65537

For encryption or signature verification with \(e=65537=2^{16}+1\), the exponent is public. A short fixed sequence of 16 squarings and one multiplication is appropriate. Constant-time with respect to the exponent is not needed, but base and modulus handling still must be correct.

Example: Diffie-Hellman secret exponent

For finite-field Diffie-Hellman, the exponent is secret. A sliding-window method with direct table indexing leaks. Use a ladder or fixed-window with constant-time table selection.

Proof sketch

For left-to-right binary exponentiation, after processing bits from the top down to position \(i\), the accumulator equals \(x^p\) where \(p\) is the integer represented by the processed prefix. Squaring shifts the prefix left by one bit; multiplying by \(x\) appends a 1 bit.

SageMath vectors

m = 2^127 - 1
for x, e in [(5, 65537), (1234567, 0xdeadbeef), (m-2, 12345)]:
    print(power_mod(x, e, m) == pow(x, e, m))