Skip to content

Commit

Permalink
Adding ECDSA (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
csjones authored Mar 13, 2021
1 parent d1052cb commit cdf449c
Show file tree
Hide file tree
Showing 16 changed files with 564 additions and 77 deletions.
22 changes: 16 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,21 @@ let package = Package(
cSettings: [
.headerSearchPath("secp256k1"),
// Basic config values that are universal and require no dependencies.
// https://github.com/bitcoin-core/secp256k1/blob/master/src/basic-config.h#L27-L31
// https://github.com/bitcoin-core/secp256k1/blob/master/src/basic-config.h#L26-L30
.define("ECMULT_WINDOW_SIZE", to: "15", nil),
.define("USE_NUM_NONE"),
.define("USE_FIELD_INV_BUILTIN"),
.define("USE_SCALAR_INV_BUILTIN"),
.define("USE_WIDEMUL_64"),
// Mirroring default value of `ECMULT_GEN_PREC_BITS` to 4 bits.
.define("ECMULT_GEN_PREC_BITS", to: "4", nil),
// Enabling additional secp256k1 modules.
.define("SECP256K1_ECDH_H"),
.define("SECP256K1_MODULE_ECDH_MAIN_H"),
.define("SECP256K1_EXTRAKEYS_H"),
.define("SECP256K1_MODULE_EXTRAKEYS_MAIN_H"),
.define("SECP256K1_SCHNORRSIG_H"),
.define("SECP256K1_MODULE_SCHNORRSIG_MAIN_H"),
.define("USE_NUM_NONE"),
.define("USE_FIELD_INV_BUILTIN"),
.define("USE_SCALAR_INV_BUILTIN"),
.define("USE_WIDEMUL_64")
]
),
// Only include select utility extensions because most of Swift Crypto is not required
Expand All @@ -66,11 +68,19 @@ let package = Package(
"swift-crypto/Sources/Crypto/Util/SecureBytes.swift",
"swift-crypto/Sources/Crypto/Util/BoringSSL/RNG_boring.swift",
"swift-crypto/Sources/Crypto/Util/BoringSSL/SafeCompare_boring.swift",
"swift-crypto/Sources/Crypto/Signatures/Signature.swift",
"swift-crypto/Sources/Crypto/Digests/Digest.swift",
"swift-crypto/Sources/Crypto/CryptoKitErrors.swift",
"Zeroization.swift",
"SHA256.swift",
"String.swift",
"secp256k1.swift",
"ECDSA.swift",
"SafeCompare.swift",
"NISTCurvesKeys.swift"
"NISTCurvesKeys.swift",
"PrettyBytes.swift",
"EdDSA.swift",
"Digests.swift"
]
),
.testTarget(
Expand Down
65 changes: 22 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,68 +1,47 @@
[![Build Status](https://app.bitrise.io/app/ef44aebd8443b33b/status.svg?token=oDGzN3bMEwseXF_5MQUsTg&branch=main)](https://app.bitrise.io/app/ef44aebd8443b33b) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FGigaBitcoin%2Fsecp256k1.swift%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/GigaBitcoin/secp256k1.swift) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FGigaBitcoin%2Fsecp256k1.swift%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/GigaBitcoin/secp256k1.swift)

# 🔐 secp256k1.swift
Swift library and bindings for ECDSA signatures and secret/public key operations using [libsecp256k1](https://github.com/bitcoin-core/secp256k1).
Swift library plus bindings for ECDSA signatures and secret/public key operations using [libsecp256k1](https://github.com/bitcoin-core/secp256k1).


# Objective
This library aims to be a lightweight wrapper for clients to include ECDSA functionality in Swift. The package aims to stay up-to-date and uses a submodule set to the default git branch of secp256k1.
# Objectives

Long-term goals are:
- Lightweight ECDSA functionality
- APIs modeled after [Swift Crypto](https://github.com/apple/swift-crypto)
- Up-to-date with future versions of Swift and libsecp256k1
- Consistent across multiple platforms

# Getting Started

In your `Package.swift`:

```swift
dependencies: [
.package(
name: "secp256k1",
url: "https://github.com/GigaBitcoin/secp256k1.swift.git",
from: "0.2.0"
),
]
```


# Basic Usage
# Usage

```swift
import secp256k1

let privateKeyBytes = try! "14E4A74438858920D8A35FB2D88677580B6A2EE9BE4E711AE34EC6B396D87B5C".byteArray()
let privatekey = try! secp256k1.Signing.PrivateKey(rawRepresentation: privateKeyBytes)


print(String(byteArray: privatekey.publicKey.rawRepresentation)) // 02734b3511150a60fc8cac329cd5ff804555728740f2f2e98bc4242135ef5d5e4e
```

let messageData = "Hello World!".data(using: .utf8)!
let signature = try! privateKey.signature(for: messageData)

# Advance Usage

```swift
import secp256k1

// Initialize context
let context = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY))!
print(try! signature.derRepresentation().base64EncodedString()) // MEUCID8JELjY/ua6MSRKh/VtO7q2YAgpPOfqlwi05Lj/gC1jAiEAiJ1r82jIVc9G/2kooLnzIbg04ky/leocdLn9XE1LvwI=
```

// Setup private and public key variables
var pubkeyLen = 33
var cPubkey = secp256k1_pubkey()
var pubkey = [UInt8](repeating: 0, count: pubkeyLen)
let privkey = try! "14E4A74438858920D8A35FB2D88677580B6A2EE9BE4E711AE34EC6B396D87B5C".byteArray()

// Verify the context and keys are setup correctly
guard secp256k1_context_randomize(context, privkey) == 1,
secp256k1_ec_pubkey_create(context, &cPubkey, privkey) == 1,
secp256k1_ec_pubkey_serialize(context, &pubkey, &pubkeyLen, &cPubkey, UInt32(SECP256K1_EC_COMPRESSED)) == 1 else {
// Destory context after creation
secp256k1_context_destroy(context)
return
}
# Getting Started

print(String(byteArray: pubKey)) // 02734b3511150a60fc8cac329cd5ff804555728740f2f2e98bc4242135ef5d5e4e
In your `Package.swift`:

// Destory context after creation
secp256k1_context_destroy(context)
```swift
dependencies: [
.package(
name: "secp256k1",
url: "https://github.com/GigaBitcoin/secp256k1.swift.git",
from: "0.3.0"
),
]
```


Expand Down
18 changes: 18 additions & 0 deletions Sources/bindings/include/SHA256.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// SHA256.h
// GigaBitcoin/secp256k1.swift
//
// Copyright (c) 2021 GigaBitcoin LLC
// Distributed under the MIT software license
//
// See the accompanying file LICENSE for information
//

#include "../secp256k1/src/hash.h"
#include "../secp256k1/include/secp256k1.h"

/// Exposes secp256k1 SHA256 implementation to the bindings target
/// @param output pointer to an array to be filled by the function
/// @param input a pointer to the data to be hashed
/// @param len the length of the data to be hashed
void secp256k1_swift_sha256(unsigned char *output, const unsigned char *input, size_t len);
2 changes: 1 addition & 1 deletion Sources/bindings/include/secp256k1.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
#include "../secp256k1/include/secp256k1_preallocated.h"
#include "../secp256k1/include/secp256k1_recovery.h"
#include "../secp256k1/include/secp256k1_schnorrsig.h"
#include "../secp256k1/include/secp256k1.h"
#include "../secp256k1/include/secp256k1.h"
23 changes: 23 additions & 0 deletions Sources/bindings/src/SHA256.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// SHA256.c
// GigaBitcoin/secp256k1.swift
//
// Copyright (c) 2021 GigaBitcoin LLC
// Distributed under the MIT software license
//
// See the accompanying file LICENSE for information
//

#include "SHA256.h"
#include "../secp256k1/src/hash_impl.h"

/// Exposes secp256k1 SHA256 implementation to the bindings target
/// @param output pointer to an array to be filled by the function
/// @param input a pointer to the data to be hashed
/// @param len the length of the data to be hashed
void secp256k1_swift_sha256(unsigned char *output, const unsigned char *input, size_t len) {
secp256k1_sha256 hasher;
secp256k1_sha256_initialize(&hasher);
secp256k1_sha256_write(&hasher, input, len);
secp256k1_sha256_finalize(&hasher, output);
}
69 changes: 69 additions & 0 deletions Sources/implementation/Digests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// Digests.swift
// GigaBitcoin/secp256k1.swift
//
// Modifications Copyright (c) 2021 GigaBitcoin LLC
// Distributed under the MIT software license
//
// See the accompanying file LICENSE for information
//
//
// NOTICE: THIS FILE HAS BEEN MODIFIED BY GigaBitcoin LLC
// UNDER COMPLIANCE WITH THE APACHE 2.0 LICENSE FROM THE
// ORIGINAL WORK OF THE COMPANY Apple Inc.
//
// THE FOLLOWING IS THE COPYRIGHT OF THE ORIGINAL DOCUMENT:
//
//
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCrypto open source project
//
// Copyright (c) 2019-2020 Apple Inc. and the SwiftCrypto project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.md for the list of SwiftCrypto project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import Foundation

// MARK: - SHA256Digest + DigestPrivate

public struct SHA256Digest: Digest {
let bytes: (UInt64, UInt64, UInt64, UInt64)

public static var byteCount: Int {
get { return 32 }

set { fatalError("Cannot set SHA256.byteCount") }
}

public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
return try Swift.withUnsafeBytes(of: bytes) {
let boundsCheckedPtr = UnsafeRawBufferPointer(start: $0.baseAddress,
count: Self.byteCount)
return try body(boundsCheckedPtr)
}
}

private func toArray() -> ArraySlice<UInt8> {
var array = [UInt8]()
array.appendByte(bytes.0)
array.appendByte(bytes.1)
array.appendByte(bytes.2)
array.appendByte(bytes.3)
return array.prefix(upTo: SHA256Digest.byteCount)
}

public var description: String {
return "\("SHA256") digest: \(toArray().hexString)"
}

public func hash(into hasher: inout Hasher) {
self.withUnsafeBytes { hasher.combine(bytes: $0) }
}
}
Loading

0 comments on commit cdf449c

Please sign in to comment.