/** * Copyright 2014 Sunny Gleason and original author or authors * * Licensed 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 io.kazuki.v0.internal.hash; import java.math.BigInteger; /** * Utility methods for nifty hash implementations. */ public class LongHashMethods { public static final long LONG_LO_MASK = 0x00000000FFFFFFFFL; /** rotate a long by the specified number of bits */ public static final long rotateLong(long val, int bits) { return (val >> bits) | (val << (64 - bits)); } /** rotate a long by the specified number of bits */ public static final int rotateInt(int val, int bits) { return (val >> bits) | (val << (32 - bits)); } /** take a bunch of random bytes and turn them into a single long */ public static final long condenseBytesIntoLong(byte[] representation) { long seed = 0L; int pos = 0; for (byte b : representation) { long bLong = ((long) b) << (pos * 8); seed ^= bLong; pos = (pos + 1) % 8; } return seed; } /** take a bunch of random bytes and turn them into a single int */ public static final int condenseBytesIntoInt(byte[] representation) { int seed = 0; int pos = 0; for (byte b : representation) { long bLong = ((long) b) << (pos * 8); seed ^= bLong; pos = (pos + 1) % 4; } return seed; } /** gather a long from the specified index into the byte array */ public static final long gatherLongLE(byte[] data, int index) { int i1 = gatherIntLE(data, index); long l2 = gatherIntLE(data, index + 4); return uintToLong(i1) | (l2 << 32); } /** * gather a partial long from the specified index using the specified number * of bytes into the byte array */ public static final long gatherPartialLongLE(byte[] data, int index, int available) { if (available >= 4) { int i = gatherIntLE(data, index); long l = uintToLong(i); available -= 4; if (available == 0) { return l; } int i2 = gatherPartialIntLE(data, index + 4, available); l <<= (available << 3); l |= (long) i2; return l; } return (long) gatherPartialIntLE(data, index, available); } /** perform unsigned extension of int to long */ public static final long uintToLong(int i) { long l = (long) i; return (l << 32) >>> 32; } /** gather an int from the specified index into the byte array */ public static final int gatherIntLE(byte[] data, int index) { int i = data[index] & 0xFF; i |= (data[++index] & 0xFF) << 8; i |= (data[++index] & 0xFF) << 16; i |= (data[++index] << 24); return i; } /** * gather a partial int from the specified index using the specified number * of bytes into the byte array */ public static final int gatherPartialIntLE(byte[] data, int index, int available) { int i = data[index] & 0xFF; if (available > 1) { i |= (data[++index] & 0xFF) << 8; if (available > 2) { i |= (data[++index] & 0xFF) << 16; } } return i; } /** * Multiply a 128-bit value by a long. FIXME: need to verify! */ public static final void multiply128_optimized(long a, long b, long[] dest) { long aH = a >> 32; long aL = a & LONG_LO_MASK; long bH = b >> 32; long bL = b & LONG_LO_MASK; long r1, r2, r3, rML; r1 = aL * bL; r2 = aH * bL; r3 = aL * bH; rML = (r1 >>> 32) + (r2 & LONG_LO_MASK) + (r3 & LONG_LO_MASK); dest[0] = (r1 & LONG_LO_MASK) + ((rML & LONG_LO_MASK) << 32); dest[1] = (aH * bH) + (rML >>> 32); } /** * Multiply a 128-bit value by a long. */ public static final void multiply128(long a, long b, long[] dest) { BigInteger a1 = BigInteger.valueOf(a); BigInteger b1 = BigInteger.valueOf(b); BigInteger product = a1.multiply(b1); dest[0] = product.longValue(); dest[1] = product.shiftRight(64).longValue(); } }