Coverage Summary for Class: SipHashFunction (com.google.common.hash)
| Class | Method, % | Line, % |
|---|---|---|
| SipHashFunction | 0% (0/7) | 0% (0/16) |
| SipHashFunction$SipHasher | 0% (0/6) | 0% (0/41) |
| Total | 0% (0/13) | 0% (0/57) |
1 /* 2 * Copyright (C) 2012 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 /* 16 * SipHash-c-d was designed by Jean-Philippe Aumasson and Daniel J. Bernstein and is described in 17 * "SipHash: a fast short-input PRF" (available at https://131002.net/siphash/siphash.pdf). 18 */ 19 20 package com.google.common.hash; 21 22 import static com.google.common.base.Preconditions.checkArgument; 23 24 import com.google.errorprone.annotations.Immutable; 25 import java.io.Serializable; 26 import java.nio.ByteBuffer; 27 import javax.annotation.CheckForNull; 28 29 /** 30 * {@link HashFunction} implementation of SipHash-c-d. 31 * 32 * @author Kurt Alfred Kluever 33 * @author Jean-Philippe Aumasson 34 * @author Daniel J. Bernstein 35 */ 36 @Immutable 37 @ElementTypesAreNonnullByDefault 38 final class SipHashFunction extends AbstractHashFunction implements Serializable { 39 static final HashFunction SIP_HASH_24 = 40 new SipHashFunction(2, 4, 0x0706050403020100L, 0x0f0e0d0c0b0a0908L); 41 42 // The number of compression rounds. 43 private final int c; 44 // The number of finalization rounds. 45 private final int d; 46 // Two 64-bit keys (represent a single 128-bit key). 47 private final long k0; 48 private final long k1; 49 50 /** 51 * @param c the number of compression rounds (must be positive) 52 * @param d the number of finalization rounds (must be positive) 53 * @param k0 the first half of the key 54 * @param k1 the second half of the key 55 */ 56 SipHashFunction(int c, int d, long k0, long k1) { 57 checkArgument( 58 c > 0, "The number of SipRound iterations (c=%s) during Compression must be positive.", c); 59 checkArgument( 60 d > 0, "The number of SipRound iterations (d=%s) during Finalization must be positive.", d); 61 this.c = c; 62 this.d = d; 63 this.k0 = k0; 64 this.k1 = k1; 65 } 66 67 @Override 68 public int bits() { 69 return 64; 70 } 71 72 @Override 73 public Hasher newHasher() { 74 return new SipHasher(c, d, k0, k1); 75 } 76 77 // TODO(kak): Implement and benchmark the hashFoo() shortcuts. 78 79 @Override 80 public String toString() { 81 return "Hashing.sipHash" + c + "" + d + "(" + k0 + ", " + k1 + ")"; 82 } 83 84 @Override 85 public boolean equals(@CheckForNull Object object) { 86 if (object instanceof SipHashFunction) { 87 SipHashFunction other = (SipHashFunction) object; 88 return (c == other.c) && (d == other.d) && (k0 == other.k0) && (k1 == other.k1); 89 } 90 return false; 91 } 92 93 @Override 94 public int hashCode() { 95 return (int) (getClass().hashCode() ^ c ^ d ^ k0 ^ k1); 96 } 97 98 private static final class SipHasher extends AbstractStreamingHasher { 99 private static final int CHUNK_SIZE = 8; 100 101 // The number of compression rounds. 102 private final int c; 103 // The number of finalization rounds. 104 private final int d; 105 106 // Four 64-bit words of internal state. 107 // The initial state corresponds to the ASCII string "somepseudorandomlygeneratedbytes", 108 // big-endian encoded. There is nothing special about this value; the only requirement 109 // was some asymmetry so that the initial v0 and v1 differ from v2 and v3. 110 private long v0 = 0x736f6d6570736575L; 111 private long v1 = 0x646f72616e646f6dL; 112 private long v2 = 0x6c7967656e657261L; 113 private long v3 = 0x7465646279746573L; 114 115 // The number of bytes in the input. 116 private long b = 0; 117 118 // The final 64-bit chunk includes the last 0 through 7 bytes of m followed by null bytes 119 // and ending with a byte encoding the positive integer b mod 256. 120 private long finalM = 0; 121 122 SipHasher(int c, int d, long k0, long k1) { 123 super(CHUNK_SIZE); 124 this.c = c; 125 this.d = d; 126 this.v0 ^= k0; 127 this.v1 ^= k1; 128 this.v2 ^= k0; 129 this.v3 ^= k1; 130 } 131 132 @Override 133 protected void process(ByteBuffer buffer) { 134 b += CHUNK_SIZE; 135 processM(buffer.getLong()); 136 } 137 138 @Override 139 protected void processRemaining(ByteBuffer buffer) { 140 b += buffer.remaining(); 141 for (int i = 0; buffer.hasRemaining(); i += 8) { 142 finalM ^= (buffer.get() & 0xFFL) << i; 143 } 144 } 145 146 @Override 147 protected HashCode makeHash() { 148 // End with a byte encoding the positive integer b mod 256. 149 finalM ^= b << 56; 150 processM(finalM); 151 152 // Finalization 153 v2 ^= 0xFFL; 154 sipRound(d); 155 return HashCode.fromLong(v0 ^ v1 ^ v2 ^ v3); 156 } 157 158 private void processM(long m) { 159 v3 ^= m; 160 sipRound(c); 161 v0 ^= m; 162 } 163 164 private void sipRound(int iterations) { 165 for (int i = 0; i < iterations; i++) { 166 v0 += v1; 167 v2 += v3; 168 v1 = Long.rotateLeft(v1, 13); 169 v3 = Long.rotateLeft(v3, 16); 170 v1 ^= v0; 171 v3 ^= v2; 172 v0 = Long.rotateLeft(v0, 32); 173 v2 += v1; 174 v0 += v3; 175 v1 = Long.rotateLeft(v1, 17); 176 v3 = Long.rotateLeft(v3, 21); 177 v1 ^= v2; 178 v3 ^= v0; 179 v2 = Long.rotateLeft(v2, 32); 180 } 181 } 182 } 183 184 private static final long serialVersionUID = 0L; 185 }