blob: 3aa81d4db5d0bccd58aa7c27bc059ac1d8b74ca3 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
/// This file implements SipHash-2-4 and SipHash-1-3
/// (https://131002.net/siphash/).
///
/// This file is based on the reference C implementation, which was released
/// to public domain by:
///
/// * Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
/// * Daniel J. Bernstein <djb@cr.yp.to>
//===----------------------------------------------------------------------===//
extension Hasher {
// FIXME: Remove @usableFromInline and @_fixed_layout once Hasher is resilient.
// rdar://problem/38549901
@usableFromInline @_fixed_layout
internal struct _State {
// "somepseudorandomlygeneratedbytes"
private var v0: UInt64 = 0x736f6d6570736575
private var v1: UInt64 = 0x646f72616e646f6d
private var v2: UInt64 = 0x6c7967656e657261
private var v3: UInt64 = 0x7465646279746573
// The fields below are reserved for future use. They aren't currently used.
private var v4: UInt64 = 0
private var v5: UInt64 = 0
private var v6: UInt64 = 0
private var v7: UInt64 = 0
@inline(__always)
internal init(rawSeed: (UInt64, UInt64)) {
v3 ^= rawSeed.1
v2 ^= rawSeed.0
v1 ^= rawSeed.1
v0 ^= rawSeed.0
}
}
}
extension Hasher._State {
@inline(__always)
private static func _rotateLeft(_ x: UInt64, by amount: UInt64) -> UInt64 {
return (x &<< amount) | (x &>> (64 - amount))
}
@inline(__always)
private mutating func _round() {
v0 = v0 &+ v1
v1 = Hasher._State._rotateLeft(v1, by: 13)
v1 ^= v0
v0 = Hasher._State._rotateLeft(v0, by: 32)
v2 = v2 &+ v3
v3 = Hasher._State._rotateLeft(v3, by: 16)
v3 ^= v2
v0 = v0 &+ v3
v3 = Hasher._State._rotateLeft(v3, by: 21)
v3 ^= v0
v2 = v2 &+ v1
v1 = Hasher._State._rotateLeft(v1, by: 17)
v1 ^= v2
v2 = Hasher._State._rotateLeft(v2, by: 32)
}
@inline(__always)
private func _extract() -> UInt64 {
return v0 ^ v1 ^ v2 ^ v3
}
}
extension Hasher._State {
@inline(__always)
internal mutating func compress(_ m: UInt64) {
v3 ^= m
_round()
v0 ^= m
}
@inline(__always)
internal mutating func finalize(tailAndByteCount: UInt64) -> UInt64 {
compress(tailAndByteCount)
v2 ^= 0xff
for _ in 0..<3 {
_round()
}
return _extract()
}
}
extension Hasher._State {
@inline(__always)
internal init() {
self.init(rawSeed: Hasher._executionSeed)
}
@inline(__always)
internal init(seed: Int) {
let executionSeed = Hasher._executionSeed
// Prevent sign-extending the supplied seed; this makes testing slightly
// easier.
let seed = UInt(bitPattern: seed)
self.init(rawSeed: (
executionSeed.0 ^ UInt64(truncatingIfNeeded: seed),
executionSeed.1))
}
}