EllipticCurveKit 1.0.0

EllipticCurveKit 1.0.0

Alexander Cyon 维护。



 
依赖项
BigInt>= 0
CryptoSwift~> 1.0.0
 

⚠️此 SDK 目前不安全/未准备用于生产(!)⚠️

我不是密码学专家,如果您发现错误、不准确或有改进此 README 或源代码的建议,请提交一个 issue

目标

“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的AnyCollectionAnyHashable。我们使用类型擦除包装类AnyKeyGeneratorAnyKeySigner

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库包装的简短列表

其他语言

GoJavaScriptPHPPython 绑定RubyRustScala

比特币 C 绑定(Swift)

Swift 中也存在一些用于比特币-core/secp256k1 的绑定。其中最有前景的是 kishikawakatsumi/BitcoinKit(这里还有一些其他的绑定 Boilertalk/secp256k1.swiftnoxproject/ASKSecp256k1pebble8888/secp256k1swiftskywinder/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)