|
---|
此软件包已被 Swift 4.2 中引入的 Hasher 类型和 Hashable.hash(into:) 要求 所取代。不建议在现代 Swift 代码中使用此软件包;相反,只需实现标准的 Hashable 即可。(SE-0206 中引入的标准库更改有点像此软件包的第 2 版。) |
SipHash
是 SipHash 哈希算法的纯 Swift 实现,该算法由 Jean-Philippe Aumasson 和 Daniel J. Bernstein 于 2012 年设计。
SipHash 是一系列伪随机函数(又名键控哈希函数),针对短消息的速度进行了优化。
目标应用包括网络流量身份验证和防御哈希泛洪 DoS 攻击。
SipHash 安全、快速且简单(真的)
- SipHash 比以前的加密算法(例如基于通用哈希的 MAC)更简单、更快
- SipHash 在性能上与不安全的非加密算法(例如 MurmurHash)具有竞争力
-- 131002.net
SipHash 有多种变体;此软件包实现了名为 SipHash-2-4 的变体。
请注意,Swift 标准库 已经包含 SipHash-2-4 和 SipHash-1-3 的实现;但是,这些 API 目前是私有的,不能在 stdlib 之外使用。此软件包提供了一个独立的实现,可用于第三方代码。
当前的 SipHash 版本需要 Swift 4。
import SipHash
// `SipHashable` is like `Hashable`, but simpler.
struct Book: SipHashable {
let title: String
let pageCount: Int
// You need to implement this method instead of `hashValue`.
func appendHashes(to hasher: inout SipHasher) {
// Simply append the fields you want to include in the hash.
hasher.append(title)
hasher.append(pageCount)
}
static func ==(left: Book, right: Book) -> Bool {
return left.title == right.title && left.pageCount == right.pageCount
}
}
// You can now use Books in sets or as dictionary keys.
let book = Book(title: "The Colour of Magic", pageCount: 206)
let books: Set<Book> = [book]
// If you prefer to do so, you may also create & use hashers directly.
var hasher = SipHasher()
hasher.add(book)
hasher.add(42)
// Finalizing the hasher extracts the hash value and invalidates it.
let hash = hasher.finalize()
除非您面向的是旧版本的 Swift(<4.2),否则不应使用 SipHash
。此软件包已过时;它仅为了历史原因和兼容性而保留在此处。不要将其导入到新的代码中。
以下是原始文档,将 SipHashable
与原始的(现在已弃用的)Hashable.hashValue
协议要求进行对比。
再次强调:不要将此软件包导入到新编写的代码中。
编写一个好的 hashValue
实现非常困难,即使我们只需要组合几个字段的值。我们需要想出一个确定性函数,它可以很好地混合字段值,产生一个固定宽度的结果,并且在典型输入上不会产生太多的冲突。但是多少冲突才算“太多”?我们甚至知道我们的“典型输入”是什么样的吗?对我来说,这两个问题的答案通常是“我完全不知道”,我打赌你也有同样的问题。
因此,验证我们的 hashValue
实现是否运行良好是一项令人沮丧的任务。
我们需要通过查看哈希函数在各种输入下的行为来以某种方式检查其属性。为相等的值具有相等的 hashValues
的要求编写测试非常容易。但是,验证哈希是否几乎没有冲突需要对“典型”输入的统计属性做出一些假设——即使我们对这样做有足够的信心,编写代码来做这件事也太复杂了。
与其推出您自己的临时哈希函数,不如直接使用专门设计用于将数据混合到哈希中的算法?使用标准化算法意味着我们不再需要担心冲突行为:如果算法设计良好,我们将始终获得良好的结果。
SipHash 算法是哈希处理的特别好的选择。它实现了一个 64 位加密消息身份验证码 (MAC),具有一个 256 位内部状态,该状态从一个 128 位密钥初始化,该密钥(通常)为二进制文件的每次执行随机生成。SipHash 旨在防止哈希冲突攻击,同时保持易用性和快速性。Perl、Python、Ruby、Rust 甚至 Swift 本身已经在使用它——这就是为什么 Hashable
的文档明确警告 hashValue
返回的值在不同执行中可能不同。
标准库已经实现了 SipHash,但该实现是私有的。(从技术上讲,它是可以使用的,但它并非 stdlib API 的正式组成部分,并且甚至可能在小版本更新中被更改/删除。)我希望重构版本的 stdlib 的 SipHash 将在未来的 Swift 版本中作为公共 API 提供。但在我们等待的同时,此软件包提供了一个今天可用的替代实现。
毫无疑问。请报告您发现的所有错误!
该软件包具有 100% 的单元测试覆盖率。不幸的是,这并没有告诉你它在实践中的可靠性。
测试套件验证该软件包生成的值与 SipHash 原始作者提供的测试向量匹配,这让我相当有信心该软件包正确实现了 SipHash。显然,你的结果可能会有所不同。
如果您使用 CocoaPods,您可以通过将其作为依赖项包含在您的 Podfile
中来开始使用 SipHash
pod 'SipHash', '~> 1.2'
对于 Carthage,将以下行添加到您的 Cartfile
github "attaswift/SipHash" ~> 1.2
对于 Swift Package Manager,将 SipHash
添加到您的 Package.swift
文件中的依赖项列表中
import PackageDescription
let package = Package(
name: "MyPackage",
dependencies: [
.Package(url: "https://github.com/attaswift/SipHash.git", from: "1.2.1")
]
)
如果您不使用依赖项管理器,您需要将此 repo 克隆到您项目附近的某个位置,并将对 SipHash.xcodeproj
的引用添加到您项目的 xcworkspace
中。您可以将 SipHash 的克隆放置在磁盘上的任何位置,但最好将其设置为应用程序顶级 Git 存储库的子模块。
要将您的应用程序二进制文件与 SipHash 链接,只需将 SipHash 项目中的 SipHash.framework
添加到 Xcode 中应用程序目标“通用”页面的“嵌入式二进制文件”部分。只要 SipHash 项目文件在您的工作区中被引用,此框架就会在您单击目标“嵌入式二进制文件”列表的“+”按钮时打开的“选择要添加的项目”表中列出。
除了将框架目标添加到“嵌入式二进制文件”之外,无需进行任何其他设置。