001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.codec.digest; 019 020import org.apache.commons.codec.binary.StringUtils; 021 022/** 023 * Implements the MurmurHash2 32-bit and 64-bit hash functions. 024 * 025 * <p> 026 * MurmurHash is a non-cryptographic hash function suitable for general 027 * hash-based lookup. The name comes from two basic operations, multiply (MU) 028 * and rotate (R), used in its inner loop. Unlike cryptographic hash functions, 029 * it is not specifically designed to be difficult to reverse by an adversary, 030 * making it unsuitable for cryptographic purposes. 031 * </p> 032 * 033 * <p> 034 * This contains a Java port of the 32-bit hash function {@code MurmurHash2} 035 * and the 64-bit hash function {@code MurmurHash64A} from Austin Appleby's 036 * original {@code c++} code in SMHasher. 037 * </p> 038 * 039 * <p> 040 * This is a re-implementation of the original C code plus some additional 041 * features. 042 * </p> 043 * 044 * <p> 045 * This is public domain code with no copyrights. From home page of 046 * <a href="https://github.com/aappleby/smhasher">SMHasher</a>: 047 * </p> 048 * 049 * <blockquote> 050 * "All MurmurHash versions are public domain software, and the author 051 * disclaims all copyright to their code." 052 * </blockquote> 053 * 054 * @see <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a> 055 * @see <a href="https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp"> 056 * Original MurmurHash2 c++ code</a> 057 * @since 1.13 058 */ 059public final class MurmurHash2 { 060 061 // Constants for 32-bit variant 062 private static final int M32 = 0x5bd1e995; 063 private static final int R32 = 24; 064 065 // Constants for 64-bit variant 066 private static final long M64 = 0xc6a4a7935bd1e995L; 067 private static final int R64 = 47; 068 069 /** 070 * Generates a 32-bit hash from byte array with the given length and a default seed value. 071 * This is a helper method that will produce the same result as: 072 * 073 * <pre> 074 * int seed = 0x9747b28c; 075 * int hash = MurmurHash2.hash32(data, length, seed); 076 * </pre> 077 * 078 * @param data The input byte array. 079 * @param length The length of the array. 080 * @return The 32-bit hash. 081 * @see #hash32(byte[], int, int) 082 */ 083 public static int hash32(final byte[] data, final int length) { 084 return hash32(data, length, 0x9747b28c); 085 } 086 087 /** 088 * Generates a 32-bit hash from byte array with the given length and seed. 089 * 090 * @param data The input byte array. 091 * @param length The length of the array. 092 * @param seed The initial seed value. 093 * @return The 32-bit hash. 094 */ 095 public static int hash32(final byte[] data, final int length, final int seed) { 096 // Initialize the hash to a random value 097 int h = seed ^ length; 098 // Mix 4 bytes at a time into the hash 099 final int nblocks = length >> 2; 100 // body 101 for (int i = 0; i < nblocks; i++) { 102 final int index = i << 2; 103 int k = MurmurHash.getLittleEndianInt(data, index); 104 k *= M32; 105 k ^= k >>> R32; 106 k *= M32; 107 h *= M32; 108 h ^= k; 109 } 110 // Handle the last few bytes of the input array 111 final int index = nblocks << 2; 112 switch (length - index) { 113 case 3: 114 h ^= (data[index + 2] & 0xff) << 16; 115 // falls-through 116 case 2: 117 h ^= (data[index + 1] & 0xff) << 8; 118 // falls-through 119 case 1: 120 h ^= data[index] & 0xff; 121 h *= M32; 122 } 123 // Do a few final mixes of the hash to ensure the last few 124 // bytes are well-incorporated. 125 h ^= h >>> 13; 126 h *= M32; 127 h ^= h >>> 15; 128 return h; 129 } 130 131 /** 132 * Generates a 32-bit hash from a string with a default seed. 133 * <p> 134 * Before 1.14 the string was converted using default encoding. 135 * Since 1.14 the string is converted to bytes using UTF-8 encoding. 136 * </p> 137 * This is a helper method that will produce the same result as: 138 * 139 * <pre> 140 * int seed = 0x9747b28c; 141 * byte[] bytes = data.getBytes(StandardCharsets.UTF_8); 142 * int hash = MurmurHash2.hash32(bytes, bytes.length, seed); 143 * </pre> 144 * 145 * @param text The input string. 146 * @return The 32-bit hash. 147 * @see #hash32(byte[], int, int) 148 */ 149 public static int hash32(final String text) { 150 final byte[] bytes = StringUtils.getBytesUtf8(text); 151 return hash32(bytes, bytes.length); 152 } 153 154 /** 155 * Generates a 32-bit hash from a substring with a default seed value. 156 * The string is converted to bytes using the default encoding. 157 * This is a helper method that will produce the same result as: 158 * 159 * <pre> 160 * int seed = 0x9747b28c; 161 * byte[] bytes = text.substring(from, from + length).getBytes(StandardCharsets.UTF_8); 162 * int hash = MurmurHash2.hash32(bytes, bytes.length, seed); 163 * </pre> 164 * 165 * @param text The input string. 166 * @param from The starting index. 167 * @param length The length of the substring. 168 * @return The 32-bit hash. 169 * @see #hash32(byte[], int, int) 170 */ 171 public static int hash32(final String text, final int from, final int length) { 172 return hash32(text.substring(from, from + length)); 173 } 174 175 /** 176 * Generates a 64-bit hash from byte array with given length and a default seed value. 177 * This is a helper method that will produce the same result as: 178 * 179 * <pre> 180 * int seed = 0xe17a1465; 181 * int hash = MurmurHash2.hash64(data, length, seed); 182 * </pre> 183 * 184 * @param data The input byte array. 185 * @param length The length of the array. 186 * @return The 64-bit hash. 187 * @see #hash64(byte[], int, int) 188 */ 189 public static long hash64(final byte[] data, final int length) { 190 return hash64(data, length, 0xe17a1465); 191 } 192 193 /** 194 * Generates a 64-bit hash from byte array of the given length and seed. 195 * 196 * @param data The input byte array. 197 * @param length The length of the array. 198 * @param seed The initial seed value. 199 * @return The 64-bit hash of the given array. 200 */ 201 public static long hash64(final byte[] data, final int length, final int seed) { 202 long h = seed & 0xffffffffL ^ length * M64; 203 final int nblocks = length >> 3; 204 // body 205 for (int i = 0; i < nblocks; i++) { 206 final int index = i << 3; 207 long k = MurmurHash.getLittleEndianLong(data, index); 208 209 k *= M64; 210 k ^= k >>> R64; 211 k *= M64; 212 213 h ^= k; 214 h *= M64; 215 } 216 final int index = nblocks << 3; 217 switch (length - index) { 218 case 7: 219 h ^= ((long) data[index + 6] & 0xff) << 48; 220 // falls-through 221 case 6: 222 h ^= ((long) data[index + 5] & 0xff) << 40; 223 // falls-through 224 case 5: 225 h ^= ((long) data[index + 4] & 0xff) << 32; 226 // falls-through 227 case 4: 228 h ^= ((long) data[index + 3] & 0xff) << 24; 229 // falls-through 230 case 3: 231 h ^= ((long) data[index + 2] & 0xff) << 16; 232 // falls-through 233 case 2: 234 h ^= ((long) data[index + 1] & 0xff) << 8; 235 // falls-through 236 case 1: 237 h ^= (long) data[index] & 0xff; 238 h *= M64; 239 } 240 h ^= h >>> R64; 241 h *= M64; 242 h ^= h >>> R64; 243 return h; 244 } 245 246 /** 247 * Generates a 64-bit hash from a string with a default seed. 248 * <p> 249 * Before 1.14 the string was converted using default encoding. 250 * Since 1.14 the string is converted to bytes using UTF-8 encoding. 251 * </p> 252 * <p> 253 * This is a helper method that will produce the same result as: 254 * </p> 255 * 256 * <pre> 257 * int seed = 0xe17a1465; 258 * byte[] bytes = data.getBytes(StandardCharsets.UTF_8); 259 * int hash = MurmurHash2.hash64(bytes, bytes.length, seed); 260 * </pre> 261 * 262 * @param text The input string. 263 * @return The 64-bit hash. 264 * @see #hash64(byte[], int, int) 265 */ 266 public static long hash64(final String text) { 267 final byte[] bytes = StringUtils.getBytesUtf8(text); 268 return hash64(bytes, bytes.length); 269 } 270 271 /** 272 * Generates a 64-bit hash from a substring with a default seed value. 273 * The string is converted to bytes using the default encoding. 274 * This is a helper method that will produce the same result as: 275 * 276 * <pre> 277 * int seed = 0xe17a1465; 278 * byte[] bytes = text.substring(from, from + length).getBytes(StandardCharsets.UTF_8); 279 * int hash = MurmurHash2.hash64(bytes, bytes.length, seed); 280 * </pre> 281 * 282 * @param text The input string. 283 * @param from The starting index. 284 * @param length The length of the substring. 285 * @return The 64-bit hash. 286 * @see #hash64(byte[], int, int) 287 */ 288 public static long hash64(final String text, final int from, final int length) { 289 return hash64(text.substring(from, from + length)); 290 } 291 292 /** No instance methods. */ 293 private MurmurHash2() { 294 } 295}