/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.examples.pi.math; /** Montgomery method. * * References: * * [1] Richard Crandall and Carl Pomerance. Prime Numbers: A Computational * Perspective. Springer-Verlag, 2001. * * [2] Peter Montgomery. Modular multiplication without trial division. * Math. Comp., 44:519-521, 1985. */ class Montgomery { protected final Product product = new Product(); protected long N; protected long N_I; // N' protected long R; protected long R_1; // R - 1 protected int s; /** Set the modular and initialize this object. */ Montgomery set(long n) { if (n % 2 != 1) throw new IllegalArgumentException("n % 2 != 1, n=" + n); N = n; R = Long.highestOneBit(n) << 1; N_I = R - Modular.modInverse(N, R); R_1 = R - 1; s = Long.numberOfTrailingZeros(R); return this; } /** Compute 2^y mod N for N odd. */ long mod(final long y) { long p = R - N; long x = p << 1; if (x >= N) x -= N; for(long mask = Long.highestOneBit(y); mask > 0; mask >>>= 1) { p = product.m(p, p); if ((mask & y) != 0) p = product.m(p, x); } return product.m(p, 1); } class Product { private final LongLong x = new LongLong(); private final LongLong xN_I = new LongLong(); private final LongLong aN = new LongLong(); long m(final long c, final long d) { LongLong.multiplication(x, c, d); // a = (x * N')&(R - 1) = ((x & R_1) * N') & R_1 final long a = LongLong.multiplication(xN_I, x.and(R_1), N_I).and(R_1); LongLong.multiplication(aN, a, N); final long z = aN.plusEqual(x).shiftRight(s); return z < N? z: z - N; } } }