⚠️ 此 SDK 目前不安全/未准备用于生产(!)⚠️
提交一个 issue!
我不是密码学专家,如果您发现错误、不准确或有改进此 README 或源代码的建议,请目标
“Swifty”,纯 Swift 的安全快速椭圆曲线加密 SDK(没有其他语言库的依赖)。
Swifty?
Swift 是一种非常易读、类型安全且快速的编程语言,其座右铭为“清晰度比简洁性更重要”和“使用时的清晰度”,这使得其代码更类似英语。此 Swift SDK 的主要目标是成为 Swifty(同时保持安全且快速)。顺便问一下,您知道Swift 是增长最快的编程语言吗?
用法
Swift非常适合协议导向编程(POP)和强类型语言,这允许使用这些类型的协议。
public protocol EllipticCurveCryptographyKeyGeneration {
/// Elliptic Curve used, e.g. `secp256k1`
associatedtype CurveType: EllipticCurve
/// Generates a new key pair (PrivateKey and PublicKey)
static func generateNewKeyPair() -> KeyPair<CurveType>
/// Support Wallet Import Format (a.k.a. WIF)
static func restoreKeyPairFrom(privateKey: PrivateKey<CurveType>) -> KeyPair<CurveType>
/// A `Wallet` is a `KeyPair` and with `PublicAddresses` derived (compressed/uncompressed)
static func createWallet(using keyPair: KeyPair<CurveType>) -> Wallet<CurveType>
}
public protocol EllipticCurveCryptographySigning {
/// Which method to use for signing, e.g. `Schnorr`
associatedtype SigningMethodUsed: Signing
typealias CurveType = SigningMethodUsed.CurveType
/// Signs `message` using `keyPair`
static func sign(_ message: Message, using keyPair: KeyPair<CurveType>) -> SignatureType
/// Checks if `signature` is valid for `message` or not.
static func verify(_ message: Message, wasSignedBy signature: SignatureType, publicKey: PublicKey<CurveType>) -> Bool
}
上述两个协议都需要一个associatedtype
来指定要使用的曲线和签名,因此我们可以使用类型擦除类型,类似于Swift Foundation的AnyCollection或AnyHashable。我们使用类型擦除包装类AnyKeyGenerator
和AnyKeySigner
。
let privateKey = PrivateKey<Secp256k1>(hex: "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF")!
let keyPair = AnyKeyGenerator<Secp256k1>.restoreKeyPairFrom(privateKey: privateKey)
let message = Message(hex: "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
let signature = AnyKeySigner<Schnorr<Secp256k1>>.sign(message, using: keyPair)
let expectedSignature = Signature<Secp256k1>(hex: "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD")!
if signature == expectedSignature {
print("Correct signature!")
}
if AnyKeySigner<Schnorr<Secp256k1>>.verify(message, wasSignedBy: signature, publicKey: keyPair.publicKey) {
print("Yes, message was indeed signed by public key and prodouced that signature.")
}
上述代码的执行时间大约为0.5秒(使用Release
优化标志),我正在尝试优化它。
上述私钥、签名和消息十六进制字符串是比特币BIP-Schnorr wiki中的“测试向量2”。
替代方案
有许多类似于这个Swift SDK的生产级替代品。这个库的目标是摆脱对C(和其他编程语言)代码的依赖。虽然还有纯Swift编写的这个Swift SDK的替代品,但运行速度太慢(阅读#pure-swift)。
比特币C绑定
在C语言中开发的Bitcoin Core的secp256k1库似乎是椭圆曲线密码学的行业标准库。它经过验证,稳健,有众多开发者,这就是为什么其他编程语言中的许多项目只是提供围绕它的包装。以下是Bitcoin secp256k1 C库包装的简短列表
其他语言
比特币 C 绑定(Swift)
Swift 中也存在一些用于比特币-core/secp256k1 的绑定。其中最有前景的是 kishikawakatsumi/BitcoinKit(这里还有一些其他的绑定 Boilertalk/secp256k1.swift、noxproject/ASKSecp256k1、pebble8888/secp256k1swift 和 skywinder/ios-secp256k1)。
SDK kishikawakatsumi/BitcoinKit 突出之处在于它为 bitcoin-core/secp256k1 提供了额外的 Swift 层。对于生产用途,我推荐查看 kishikawakatsumi/BitcoinKit。
纯 Swift
到目前为止,我找到的唯一纯 Swift 的椭圆曲线密码学 SDK 是 hyugit/EllipticCurve。代码非常符合 Swift 风格,确实不错,作者 Huang Yu,也称 hyugit 做了出色的工作!然而,代码运行速度太慢了。密钥生成需要超过 10 分钟。而此 SDK 使用 Release
优化选项仅需 0.1 秒钟。
状态
此 SDK 处于概念验证阶段,但已支持大多数功能,代码风格 swwifty 且运行速度快,但尚未安全使用。我正在先优化性能,然后再使其安全使用。
目标状态
- "Swift风格"
- 快速(最快纯 Swift ECC SDK,但比比特币 C SDK 慢 250 倍)
- 安全
依赖项
此SDK不应该需要任何C库(例如OpenSSL或bitcoin核心)的桥梁,甚至不应该使用Objective-C。此SDK应该是彻头彻尾的“Swifty”。
大数字
椭圆曲线密码学需要大数(至少256位),但我们原生只支持64位(在64位平台上)使用UInt64
。我开始开发自己的Big Int代码,但最终放弃了,因为Apple开发者Karoy Lorentey(又名"lorentey")已经创建了BigInt SDKattaswift/BigInt,它运行得非常好。我还在关注苹果的一个BigInt实现(处于原型阶段),如果它正式发布,可能会切换到它。
我还评估了hyugit/UInt256,它符合Swift的FixedWidthInteger协议,但是由于我们可能需要512位和1024位的大数,它的可扩展性不好。我还怀疑attaswift/BigInt中的算术运算速度比hyugit/UInt256(需要验证)快。同时还有废弃的CryptoCoinSwift/UInt256,它似乎比hyugit/UInt256低级。
Apple Accelerate vBignum
Apple的库Accelerate似乎提供了大数,但使用UnsafePointer
的方式非常不Swifty,这里是通过vbignum的vU256来添加。
func vU256Add(_ a: UnsafePointer<vU256>,
_ b: UnsafePointer<vU256>,
_ result: UnsafeMutablePointer<vU256>)
不过,我可能需要更深入地调查它并测量性能。也许一个小结构体包裹它并用Swifty API装饰它会给attaswift/BigInt带来更高的性能。
哈希函数
我使用krzyzanowskim/CryptoSwift提供的SHA-256哈希函数。
关键灵感
我受到了许多开源项目的启发。比特币改进提案Wiki bip-schnorr 由比特币核心开发者 Pieter Wuille(又名 "Sipa") 提出,对于 Schnorr 签名来说是无价之宝。
Sylvestre Blanc(又名 "HurlSly") 的 Python 代码 也非常有帮助。
路线图
签名
- ECDSA
- Schnorr
- ed25519 (EdDSA)
密钥格式
私钥
- 原始格式
- 未压缩WIF
- 压缩WIF
公钥
- 未压缩
- 压缩
公钥地址
- 比特币(主网 + 测试网)
- Zilliqa(测试网)
常见曲线
计划通过运行CLI命令 openssl ecparam -list_curves
来支持大多数常见曲线,但以下四个是我的起点
- secp256k1(比特币、以太坊、Zilliqa、Radix)
- secp256r1(NEO)
- X25519 - 用于ECDH的Curve25519(Nano、Stellar、Cardano)