| ... | ... | @@ -68,18 +68,20 @@ pub const Wyhash = struct { |
| 68 | 68 | if (self.total_len <= 16) { |
| 69 | 69 | newSelf.smallKey(input); |
| 70 | 70 | } else { |
| 71 | var offset: usize = 0; |
| 71 | 72 | if (self.buf_len < 16) { |
| 72 | 73 | var scratch: [16]u8 = undefined; |
| 73 | 74 | const rem = 16 - self.buf_len; |
| 74 | 75 | @memcpy(scratch[0..rem], self.buf[self.buf.len - rem ..][0..rem]); |
| 75 | 76 | @memcpy(scratch[rem..][0..self.buf_len], self.buf[0..self.buf_len]); |
| 76 | 77 | |
| 77 | | // Same as input with lookbehind to pad to 16-bytes |
| 78 | | input = scratch[rem..]; |
| 78 | // Same as input but with additional bytes preceeding start in case of a short buffer |
| 79 | input = &scratch; |
| 80 | offset = rem; |
| 79 | 81 | } |
| 80 | 82 | |
| 81 | 83 | newSelf.final0(); |
| 82 | | newSelf.final1(input); |
| 84 | newSelf.final1(input, offset); |
| 83 | 85 | } |
| 84 | 86 | |
| 85 | 87 | return newSelf.final2(); |
| ... | ... | @@ -145,19 +147,21 @@ pub const Wyhash = struct { |
| 145 | 147 | self.state[0] ^= self.state[1] ^ self.state[2]; |
| 146 | 148 | } |
| 147 | 149 | |
| 148 | | // Input must reside in a 16-byte buffer. The input slice passed be offset into it in which |
| 149 | | // case this function will index in front of the slice. |
| 150 | | inline fn final1(self: *Wyhash, input: []const u8) void { |
| 151 | | std.debug.assert(input.len <= 48); |
| 150 | // input_lb must be at least 16-bytes long (in shorter key cases the smallKey function will be |
| 151 | // used instead). We use an index into a slice to for comptime processing as opposed to if we |
| 152 | // used pointers. |
| 153 | inline fn final1(self: *Wyhash, input_lb: []const u8, start_pos: usize) void { |
| 154 | std.debug.assert(input_lb.len >= 16); |
| 155 | std.debug.assert(input_lb.len - start_pos <= 48); |
| 156 | const input = input_lb[start_pos..]; |
| 152 | 157 | |
| 153 | 158 | var i: usize = 0; |
| 154 | 159 | while (i + 16 < input.len) : (i += 16) { |
| 155 | 160 | self.state[0] = mix(read(8, input[i..]) ^ secret[1], read(8, input[i + 8 ..]) ^ self.state[0]); |
| 156 | 161 | } |
| 157 | 162 | |
| 158 | | // Possible lookbehind past pointer start. |
| 159 | | self.a = read(8, (input.ptr + input.len - 16)[0..8]); |
| 160 | | self.b = read(8, (input.ptr + input.len - 8)[0..8]); |
| 163 | self.a = read(8, input_lb[input_lb.len - 16 ..][0..8]); |
| 164 | self.b = read(8, input_lb[input_lb.len - 8 ..][0..8]); |
| 161 | 165 | } |
| 162 | 166 | |
| 163 | 167 | inline fn final2(self: *Wyhash) u64 { |
| ... | ... | @@ -180,7 +184,7 @@ pub const Wyhash = struct { |
| 180 | 184 | } |
| 181 | 185 | self.final0(); |
| 182 | 186 | } |
| 183 | | self.final1(input[i..]); |
| 187 | self.final1(input, i); |
| 184 | 188 | } |
| 185 | 189 | |
| 186 | 190 | self.total_len = input.len; |
| ... | ... | @@ -213,6 +217,14 @@ test "test vectors" { |
| 213 | 217 | } |
| 214 | 218 | } |
| 215 | 219 | |
| 220 | test "test vectors at comptime" { |
| 221 | comptime { |
| 222 | inline for (vectors) |e| { |
| 223 | try expectEqual(e.expected, Wyhash.hash(e.seed, e.input)); |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 216 | 228 | test "test vectors streaming" { |
| 217 | 229 | const step = 5; |
| 218 | 230 | |