Task: Montgomery reduction

C: #include <stdio.h>
#include <stdlib.h>

typedef unsigned long long ulong;

const int BASE = 2;

struct Montgomery {
    ulong m;
    ulong rrm;
    int n;
};

int bitLength(ulong v) {
    int result = 0;
    while (v > 0) {
        v >>= 1;
        result++;
    }
    return result;
}

ulong modPow(ulong b, ulong e, ulong n) {
    ulong result = 1;

    if (n == 1) {
        return 0;
    }

    b = b % n;
    while (e > 0) {
        if (e % 2 == 1) {
            result = (result * b) % n;
        }
        e >>= 1;
        b = (b * b) % n;
    }

    return result;
}

struct Montgomery makeMontgomery(ulong m) {
    struct Montgomery result;

    if (m == 0 || (m & 1) == 0) {
        fprintf(stderr, "m must be greater than zero and odd");
        exit(1);
    }

    result.m = m;
    result.n = bitLength(m);
    result.rrm = (1ULL << (result.n * 2)) % m;

    return result;
}

ulong reduce(struct Montgomery mont, ulong t) {
    ulong a = t;
    int i;

    for (i = 0; i < mont.n; i++) {
        if ((a & 1) == 1) {
            a += mont.m;
        }
        a = a >> 1;
    }

    if (a >= mont.m) {
        a -= mont.m;
    }
    return a;
}

void check(ulong x1, ulong x2, ulong m) {
    struct Montgomery mont = makeMontgomery(m);
    ulong t1 = x1 * mont.rrm;
    ulong t2 = x2 * mont.rrm;

    ulong r1 = reduce(mont, t1);
    ulong r2 = reduce(mont, t2);
    ulong r = 1ULL << mont.n;

    printf("b :  %d\n", BASE);
    printf("n :  %d\n", mont.n);
    printf("r :  %llu\n", r);
    printf("m :  %llu\n", mont.m);
    printf("t1:  %llu\n", t1);
    printf("t2:  %llu\n", t2);
    printf("r1:  %llu\n", r1);
    printf("r2:  %llu\n", r2);
    printf("\n");
    printf("Original x1       : %llu\n", x1);
    printf("Recovered from r1 : %llu\n", reduce(mont, r1));
    printf("Original x2       : %llu\n", x2);
    printf("Recovered from r2 : %llu\n", reduce(mont, r2));

    printf("\nMontgomery computation of x1 ^ x2 mod m :\n");
    ulong prod = reduce(mont, mont.rrm);
    ulong base = reduce(mont, x1 * mont.rrm);
    ulong exp = x2;
    while (bitLength(exp) > 0) {
        if ((exp & 1) == 1) {
            prod = reduce(mont, prod * base);
        }
        exp >>= 1;
        base = reduce(mont, base * base);
    }
    printf("%llu\n", reduce(mont, prod));
    printf("\nAlternate computation of x1 ^ x2 mod m :\n");
    printf("%llu\n", modPow(x1, x2, m));
}

int main() {
    check(41, 11, 1549);

    return 0;
}





Java: import java.math.BigInteger;

public class MontgomeryReduction {
    private static final BigInteger ZERO = BigInteger.ZERO;
    private static final BigInteger ONE = BigInteger.ONE;
    private static final BigInteger TWO = BigInteger.valueOf(2);

    public static class Montgomery {
        public static final int BASE = 2;

        BigInteger m;
        BigInteger rrm;
        int n;

        public Montgomery(BigInteger m) {
            if (m.compareTo(BigInteger.ZERO) <= 0 || !m.testBit(0)) {
                throw new IllegalArgumentException();
            }
            this.m = m;
            this.n = m.bitLength();
            this.rrm = ONE.shiftLeft(n * 2).mod(m);
        }

        public BigInteger reduce(BigInteger t) {
            BigInteger a = t;
            for (int i = 0; i < n; i++) {
                if (a.testBit(0)) a = a.add(this.m);
                a = a.shiftRight(1);
            }
            if (a.compareTo(m) >= 0) a = a.subtract(this.m);
            return a;
        }
    }

    public static void main(String[] args) {
        BigInteger m  = new BigInteger("750791094644726559640638407699");
        BigInteger x1 = new BigInteger("540019781128412936473322405310");
        BigInteger x2 = new BigInteger("515692107665463680305819378593");

        Montgomery mont = new Montgomery(m);
        BigInteger t1 = x1.multiply(mont.rrm);
        BigInteger t2 = x2.multiply(mont.rrm);

        BigInteger r1 = mont.reduce(t1);
        BigInteger r2 = mont.reduce(t2);
        BigInteger r = ONE.shiftLeft(mont.n);

        System.out.printf("b :  %s\n", Montgomery.BASE);
        System.out.printf("n :  %s\n", mont.n);
        System.out.printf("r :  %s\n", r);
        System.out.printf("m :  %s\n", mont.m);
        System.out.printf("t1:  %s\n", t1);
        System.out.printf("t2:  %s\n", t2);
        System.out.printf("r1:  %s\n", r1);
        System.out.printf("r2:  %s\n", r2);
        System.out.println();
        System.out.printf("Original x1       :  %s\n", x1);
        System.out.printf("Recovered from r1 :  %s\n", mont.reduce(r1));
        System.out.printf("Original x2       :  %s\n", x2);
        System.out.printf("Recovered from r2 :  %s\n", mont.reduce(r2));

        System.out.println();
        System.out.println("Montgomery computation of x1 ^ x2 mod m :");
        BigInteger prod = mont.reduce(mont.rrm);
        BigInteger base = mont.reduce(x1.multiply(mont.rrm));
        BigInteger exp = x2;
        while (exp.bitLength()>0) {
            if (exp.testBit(0)) prod=mont.reduce(prod.multiply(base));
            exp = exp.shiftRight(1);
            base = mont.reduce(base.multiply(base));
        }
        System.out.println(mont.reduce(prod));

        System.out.println();
        System.out.println("Library-based computation of x1 ^ x2 mod m :");
        System.out.println(x1.modPow(x2, m));
    }
}