Git Product home page Git Product logo

ellipticcurvekit's Introduction

⚠️ THIS SDK IS NOT SAFE/PRODUCTION READY (YET!) ⚠️

I'm no cryptography expert, If you find mistakes, inaccuracies or if you have suggestions for improvements of this README or the source code, please submit an issue!

Goal

"Swifty", safe and fast Elliptic Curve Cryptography SDK in pure Swift (no dependency to a library written in any other language than Swift).

Swifty?

Swift is a very expressible, type safe, and fast programming language having the mottos "Clarity is more important than brevity" and "Clarity at the point of use" which makes it read out as English. The main goal of this Swift SDK is to be Swifty (while also safe and fast). By the way, did you know that Swift is the fastest growing programming language?

Usage

Swift is perfect for Protocol Oriented Programming (POP) and strongly typed language, which allows for these kinds of protocols.

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
}

Since both protocols above require an associatedtype which specify which Curve and Signature to use, we can use type-erased types, similar to Swift Foundation's AnyCollection or AnyHashable. We use type-erased wrappers AnyKeyGenerator and AnyKeySigner below:

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.")
}

The code above takes around 0.5 seconds to execute (using Release optimization flags), which I'm working on optimizing.

The privatekey, signature, and message hex strings above are "Test Vector 2" from the Bitcoin BIP-Schnorr wiki.

Message

As you can see in the code example above, the signer (e.g. AnyKeySigner<Schnorr<Secp256k1>>) has a method for signing func sign(_ message: Message, using... a Message. Which is a container for any data you wanna sign. You should only be signing hashed data. Message contains four initializers, two for unhashed data (resulting in the data being hashed by the provided Hasher (shadowing Swift's Hasher)). Or if you know that you have already hashed the data, you can either pass a hashed hex string representation or the hashed data (to make sure you know what you are doing you are still required to provide info about which Hasher has been used to hash the data. Probably DefaultHasher.sha256).

Alternatives

There are many - production like alternatives to this Swift SDK. The goal of this library is to be rid of dependencies to C (and other programming languages) code. While there is alternative to this Swift SDK that is written in pure swift, it is too slow (read #pure-swift).

Bitcoin C Bindings

The Bitcoin Core's secp256k1 library developed in C seems to be the industry standard library for Elliptic Curve Cryptography. It is proven and robust and has many developers, why many projects in other programming languages just provide and a wrapper around it. Here is a short list of Bitcoin secp256k1 C library wrappers:

Other languages

Go, Javascript, PHP, Python Binding, Ruby, Rust, Scala

Bitcoin C Bindings (Swift)

There are some bindings to bitcoin-core/secp256k1 in Swift too. The most promising seems to be kishikawakatsumi/BitcoinKit (here are some others Boilertalk/secp256k1.swift, noxproject/ASKSecp256k1, pebble8888/secp256k1swift and skywinder/ios-secp256k1.

The SDK kishikawakatsumi/BitcoinKit stands out since it provides additional Swift layers to bitcoin-core/secp256k1. For production purposes, I recommend looking at kishikawakatsumi/BitcoinKit.

Pure Swift

The only Pure Swift Elliptic Curve cryptography SDK I have found so far is hyugit/EllipticCurve. The code is very Swifty and nice indeed, great work by Huang Yu aka hyugit! However, the code runs too slow. Taking over 10 minutes for Key generation. While this SDK takes around 0.1 seconds (using Release optimization flags).

Status

This SDK is in a proof-of-concept stage, but most features are supported, the code is Swifty and fast, but not yet safe to use. I'm working on optimizing the performance first, then making it safe to use.

Status of goal

  • "Swifty"
  • Fast (fastest pure Swift ECC SDK, but 250x slower than Bitcoin C SDK)
  • Safe

Dependencies

This SDK should never require any bridge to some C library (OpenSSL or bitcoin core for example) or even Objective-C. This SDK should be "Swifty" through and through.

Big Numbers

Elliptic Curve Cryptography requires big numbers (256 bits and more), but natively we only have support for 64 bits (on 64-bit platforms) using UInt64. I started on developing my own BigInt code, which I eventually throw away since Apple Developer Karoy Lorentey a.k.a. "lorentey" already created BigInt SDK attaswift/BigInt which works beautifully. I am also keeping an eye on a BigInt implementation from Apple, which is in prototype stage, might switch over to it if ever officially released.

I have also evalutated hyugit/UInt256 which conforms to Swifts FixedWidthInteger protocol, but that won't scale well since we might need 512 and 1024 bit large numbers. I also suspect that arithemtic operations in attaswift/BigInt are faster than hyugit/UInt256 (needs verification). There are also discontinued CryptoCoinSwift/UInt256 which seems inferior to hyugit/UInt256.

Apple Accelerate vBignum

Apple's library Accelerate seems to offer BigNumbers but in a very unswifty way using UnsafePointers here is addition of vbignum's vU256:

func vU256Add(_ a: UnsafePointer<vU256>, 
            _ b: UnsafePointer<vU256>, 
            _ result: UnsafeMutablePointer<vU256>)

However, I should probably investigate it further and measure performance. Perhaps a small struct wrapping it and decorating it with a Swifty API would give greater performance than attaswift/BigInt.

Hash functions

I use the SHA-256 hashing functions provided by krzyzanowskim/CryptoSwift.

Key inspiration

I have used lots of open source projects as inspiration. Bitcoin Improvement Proposal Wiki bip-schnorr by the bitcoin core developer Pieter Wuille a.k.a. "Sipa" has been a priceless inspiration for Schnorr Signature.

Sylvestre Blanc a.k.a. "HurlSly"'s Python Code has also been very helpful.

Roadmap

Signatures

  • ECDSA
  • Schnorr
  • ed25519 (EdDSA)

Key Formats

Private Key

  • Raw
  • WIF Uncompressed
  • WIF Compressed

Public Key

  • Uncompressed
  • Compressed

Public Addresses

  • Bitcoin (mainnet + testnet)
  • Zilliqa (testnet)

Common Curves

It is plan to support most of the common curves listed by running CLI command openssl ecparam -list_curves, but these four are the ones I will be starting with:

  • secp256k1 (Bitcoin, Ethereum, Zilliqa, Radix)
  • secp256r1 (NEO)
  • X25519 - Curve25519 used for ECDH (Nano, Stellar, Cardano)

Donate

This SDK has been developed by the single author Alexander Cyon in his free time. If you find it useful, please consider donating.

Any donation would be much appreciated:

  • ZIL: zil108t2jdgse760d88qjqmffhe9uy0nk4wvzx404t
  • BTC: 3GarsdAzLpEYbhkryYz1WiZxhtTLLaNJwo
  • ETH: 0xAB8F0137295BFE37f50b581F76418518a91ab8DB
  • NEO: AbbnnCLP26ccSnLooDDcwPLDnfXbVL5skH

ellipticcurvekit's People

Contributors

jnordberg avatar sajjon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ellipticcurvekit's Issues

optimization Config?

Hi~
Method processing takes a long time.

It always takes over 3 seconds to run ( restoreKeyPairFrom, verify method )
I would like to know release optimization Config info.

my Xcode build Settings.

  • Complilation Mode : wholemodule
  • SWIFT_OPTIMIZATION_LEVEL (debug) : -Onone
  • append User-Define option
    SWIFT_WHOLE_MODULE_OPTIMIZATION = YES

Do you have any more settings info?

Throws an error when running the sample code

let message = Message(hex: "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"
An error occurred:
Cannot invoke initializer for type 'Message' with an argument list of type '(hex: String)'

Get PublicKey<Secp256k1> from Data

Hi,

I'm currently porting my Android app to iOS and I stumbled across your library which seems to perfectly meet my requirements. I'm not sure if I do something wrong but I'm not able to create a public key from Data. I have created a Unit test to check if the output of some crypto functions is the same as in my Android app. Therefore I use following uncompressed public key. Below the uncompressed public key in hex representation

04F40AF135A4889436CEE52B5C73A33EC5AD0BE0952F57F4F0ED0C80B0BEDA7CA643789393A5947E9FAA3F6795C9AA09A96325DFE850BFC3F1DB62A50ABFB0FFF7

Once converted the hex string to Data I use following function calls

let decodedFromUncompressed = try AffinePoint<Secp256k1>.init(data: publicKeyBytes)
return PublicKey<Secp256k1>.init(point: decodedFromUncompressed)

This leads to an error here

Upon further investigation I saw that the call

let yData = y.as256bitLongData()

returned 0 despite the value is not 0. It seems the as256bitLongData uses internally a function called asHexStringLength64 which returns following strange hex value

0-789393A5947E9FAA3F6795C9AA09A96325DFE850BFC3F1DB62A50ABFB0FFF7

The function fills up the missing values with 0 but seems to ignore the '-' sign. Is this the root cause of the error, did I misunderstand something or is there another way to get a PublicKey from uncompressed Data?

Support for Secp521R1

Hi, I'm still using your library for my project and it works great, the the app which I'm porting from Android to iOS is communicating with a 3rd Party endpoint and in one of the recent updates they switched from Secp256K1 to Secp521R1. Do you have plans to add this curve Algo?

Error with Message initialization

Hello!
Your lib perfectly matches to my goals, but I have trouble with Message from your example:
let message = Message(hex: "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89" An error occurred: Cannot invoke initializer for type 'Message' with an argument list of type '(hex: String)'

How could I init Message with some String?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.