📄 uhash32.java
字号:
if (K.length != 24) { throw new ExceptionInInitializerError("K length is not 24"); } // Extract keys and restrict to special key-sets // Mask64 = uint2str(0x01FFFFFF01FFFFFF, 8); // Mask128 = uint2str(0x01FFFFFF01FFFFFF01FFFFFF01FFFFFF, 16); // k64 = str2uint(K[1..8] and Mask64); // k128 = str2uint(K[9..24] and Mask128); int i = 0; k64 = new BigInteger(1, new byte[] { (byte) (K[i++] & 0x01), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0x01), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF) }); k128 = new BigInteger(1, new byte[] { (byte) (K[i++] & 0x01), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0x01), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0x01), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0x01), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF), (byte) (K[i++] & 0xFF) }); y = BigInteger.ONE; highBound = false; bytesSoFar = 0L; } private L2Hash32(L2Hash32 that) { super(); this.k64 = that.k64; this.k128 = that.k128; this.y = that.y; this.highBound = that.highBound; this.bytesSoFar = that.bytesSoFar; if (that.buffer != null) { byte[] thatbuffer = that.buffer.toByteArray(); this.buffer = new ByteArrayOutputStream(); this.buffer.write(thatbuffer, 0, thatbuffer.length); } } // Class methods // ---------------------------------------------------------------------- // Instance methods // ---------------------------------------------------------------------- // java.lang.Cloneable interface implementation ------------------------- public Object clone() { return new L2Hash32(this); } // other instance methods ----------------------------------------------- // this is called with either 8-bytes or 16-bytes void update(byte[] b, int offset, int len) { if (len == 0) { return; } if (!highBound) { // do the first (only?) 8-bytes poly(64, LOWER_RANGE, k64, b, offset, 8); bytesSoFar += 8L; highBound = (bytesSoFar > BOUNDARY); if (highBound) { // if we just crossed the limit then process y poly(128, UPPER_RANGE, k128, yTo16bytes(), 0, 16); buffer = new ByteArrayOutputStream(); } // do the rest if any update(b, offset + 8, len - 8); } else { // we're already beyond the 2**17 bytes size limit // process in chuncks of 16 buffer.write(b, offset, len); if (buffer.size() > 16) { byte[] bb = buffer.toByteArray(); poly(128, UPPER_RANGE, k128, bb, 0, 16); if (bb.length > 16) { buffer.write(bb, 16, bb.length - 16); } } } } byte[] digest() { // If M no more than 2^17 bytes, hash under 64-bit prime, // otherwise, hash first 2^17 bytes under 64-bit prime and // remainder under 128-bit prime. if (!highBound) { // y is up-to-date // do nothing } else { // we may have some bytes in buffer byte[] bb = buffer.toByteArray(); byte[] lastBlock = new byte[16]; System.arraycopy(bb, 0, lastBlock, 0, bb.length); lastBlock[bb.length] = (byte) 0x80; poly(128, UPPER_RANGE, k128, lastBlock, 0, 16); } byte[] result = yTo16bytes(); reset(); return result; } void reset() { y = BigInteger.ONE; highBound = false; bytesSoFar = 0L; if (buffer != null) { buffer.reset(); } } // helper methods ------------------------------------------------------- private byte[] yTo16bytes() { byte[] yy = y.toByteArray(); byte[] result = new byte[16]; if (yy.length > 16) { System.arraycopy(yy, yy.length - 16, result, 0, 16); } else { System.arraycopy(yy, 0, result, 16 - yy.length, yy.length); } return result; } /** * 5.3 POLY: Polynomial hash * Function Name: POLY * * @param wordbits positive integer divisible by 8: called with 64 or 128. * @param maxwordrange positive integer less than 2**wordbits. * @param k integer in the range 0 .. prime(wordbits) - 1. * @param M string with length divisible by (wordbits / 8) bytes. * return y, integer in the range 0 .. prime(wordbits) - 1. */ private void poly(int wordbits, BigInteger maxwordrange, BigInteger k, byte[] M, int off, int len) { byte[] mag = new byte[len]; System.arraycopy(M, off, mag, 0, len); // Define constants used for fixing out-of-range words // int wordbytes = wordbits / 8; BigInteger p = prime(wordbits); BigInteger offset = TWO.pow(wordbits).subtract(p); // 2^wordbits - p; BigInteger marker = p.subtract(BigInteger.ONE); // Break M into chunks of length wordbytes bytes // long n = M.length / wordbytes; // Let M_1, M_2, ..., M_n be strings of length wordbytes bytes // so that M = M_1 || M_2 || .. || M_n // For each input word, compare it with maxwordrange. If larger // then hash the words 'marker' and (m - offset), both in range. // for (int i = 0; i < n; i++) { BigInteger m = new BigInteger(1, mag); if (m.compareTo(maxwordrange) >= 0) { // m >= maxwordrange y = y.multiply(k).add(marker).mod(p); // (k * y + marker) % p; y = y.multiply(k).add(m.subtract(offset)).mod(p); // (k * y + (m - offset)) % p; } else { y = y.multiply(k).add(m).mod(p); // (k * y + m) % p; } // } // return y; } } // ========================================================================= /** * Third hash stage of the UHash32 algorithm. * * Input: * K1 string of length 64 bytes. * K2 string of length 4 bytes. * M string of length 16 bytes. * Returns: * Y, string of length 4 bytes. */ class L3Hash32 implements Cloneable { // Constants and variables // ---------------------------------------------------------------------- private static final long PRIME_36 = 0x0000000FFFFFFFFBL; private int[] k = new int[9]; // Constructor(s) // ---------------------------------------------------------------------- /** * * @param K1 string of length 64 bytes. * @param K2 string of length 4 bytes. */ L3Hash32(byte[] K1, byte[] K2) { super(); // pre-conditions if (K1.length != 64) { throw new ExceptionInInitializerError("K1 length is not 64"); } if (K2.length != 4) { throw new ExceptionInInitializerError("K2 length is not 4"); } // Break K1 into 8 chunks and convert to integers // int i = 0; // for (int j = 0; i < 8; ) { for (int i = 0, j = 0; i < 8; i++) { long kk = (K1[j++] & 0xFFL) << 56 | (K1[j++] & 0xFFL) << 48 | (K1[j++] & 0xFFL) << 40 | (K1[j++] & 0xFFL) << 32 | (K1[j++] & 0xFFL) << 24 | (K1[j++] & 0xFFL) << 16 | (K1[j++] & 0xFFL) << 8 | (K1[j++] & 0xFFL); // k[i++] = (int)(kk % PRIME_36); k[i] = (int) (kk % PRIME_36); } // k[i] = K2[0] << 24 | (K2[1] & 0xFF) << 16 | (K2[2] & 0xFF) << 8 | (K2[3] & 0xFF); k[8] = K2[0] << 24 | (K2[1] & 0xFF) << 16 | (K2[2] & 0xFF) << 8 | (K2[3] & 0xFF); } private L3Hash32(int[] k) { super(); this.k = k; } // Class methods // ---------------------------------------------------------------------- // Instance methods // ---------------------------------------------------------------------- // java.lang.Cloneable interface implementation ------------------------- public Object clone() { return new L3Hash32((int[]) k.clone()); } // other instance methods ----------------------------------------------- /** * @param M string of length 16 bytes. * @return Y, string of length 4 bytes. */ byte[] digest(byte[] M) { if (M.length != 16) { throw new IllegalArgumentException("M length is not 16"); } long m, y = 0L; for (int i = 0, j = 0; i < 8; i++) { // Break M into 8 chunks and convert to integers m = (M[j++] & 0xFFL) << 8 | (M[j++] & 0xFFL); // Inner-product hash, extract last 32 bits and affine-translate // y = (m_1 * k_1 + ... + m_8 * k_8) mod prime(36); // y = y mod 2^32; y += (m * (k[i] & 0xFFFFFFFFL)) % PRIME_36; } int Y = ((int) y) ^ k[8]; return new byte[] { (byte) (Y >>> 24), (byte) (Y >>> 16), (byte) (Y >>> 8), (byte) Y }; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -