Skip to content

Commit cdf449c

Browse files
authored
Adding ECDSA (#71)
1 parent d1052cb commit cdf449c

File tree

16 files changed

+564
-77
lines changed

16 files changed

+564
-77
lines changed

Package.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,21 @@ let package = Package(
3939
cSettings: [
4040
.headerSearchPath("secp256k1"),
4141
// Basic config values that are universal and require no dependencies.
42-
// https://github.com/bitcoin-core/secp256k1/blob/master/src/basic-config.h#L27-L31
42+
// https://github.com/bitcoin-core/secp256k1/blob/master/src/basic-config.h#L26-L30
4343
.define("ECMULT_WINDOW_SIZE", to: "15", nil),
44+
.define("USE_NUM_NONE"),
45+
.define("USE_FIELD_INV_BUILTIN"),
46+
.define("USE_SCALAR_INV_BUILTIN"),
47+
.define("USE_WIDEMUL_64"),
48+
// Mirroring default value of `ECMULT_GEN_PREC_BITS` to 4 bits.
4449
.define("ECMULT_GEN_PREC_BITS", to: "4", nil),
50+
// Enabling additional secp256k1 modules.
4551
.define("SECP256K1_ECDH_H"),
4652
.define("SECP256K1_MODULE_ECDH_MAIN_H"),
4753
.define("SECP256K1_EXTRAKEYS_H"),
4854
.define("SECP256K1_MODULE_EXTRAKEYS_MAIN_H"),
4955
.define("SECP256K1_SCHNORRSIG_H"),
5056
.define("SECP256K1_MODULE_SCHNORRSIG_MAIN_H"),
51-
.define("USE_NUM_NONE"),
52-
.define("USE_FIELD_INV_BUILTIN"),
53-
.define("USE_SCALAR_INV_BUILTIN"),
54-
.define("USE_WIDEMUL_64")
5557
]
5658
),
5759
// Only include select utility extensions because most of Swift Crypto is not required
@@ -66,11 +68,19 @@ let package = Package(
6668
"swift-crypto/Sources/Crypto/Util/SecureBytes.swift",
6769
"swift-crypto/Sources/Crypto/Util/BoringSSL/RNG_boring.swift",
6870
"swift-crypto/Sources/Crypto/Util/BoringSSL/SafeCompare_boring.swift",
71+
"swift-crypto/Sources/Crypto/Signatures/Signature.swift",
72+
"swift-crypto/Sources/Crypto/Digests/Digest.swift",
73+
"swift-crypto/Sources/Crypto/CryptoKitErrors.swift",
6974
"Zeroization.swift",
75+
"SHA256.swift",
7076
"String.swift",
7177
"secp256k1.swift",
78+
"ECDSA.swift",
7279
"SafeCompare.swift",
73-
"NISTCurvesKeys.swift"
80+
"NISTCurvesKeys.swift",
81+
"PrettyBytes.swift",
82+
"EdDSA.swift",
83+
"Digests.swift"
7484
]
7585
),
7686
.testTarget(

README.md

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,47 @@
11
[![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)
22

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

66

7-
# Objective
8-
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.
7+
# Objectives
98

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

11-
# Getting Started
1215

13-
In your `Package.swift`:
14-
15-
```swift
16-
dependencies: [
17-
.package(
18-
name: "secp256k1",
19-
url: "https://github.com/GigaBitcoin/secp256k1.swift.git",
20-
from: "0.2.0"
21-
),
22-
]
23-
```
24-
25-
26-
# Basic Usage
16+
# Usage
2717

2818
```swift
2919
import secp256k1
3020

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

34-
3524
print(String(byteArray: privatekey.publicKey.rawRepresentation)) // 02734b3511150a60fc8cac329cd5ff804555728740f2f2e98bc4242135ef5d5e4e
36-
```
3725

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

39-
# Advance Usage
40-
41-
```swift
42-
import secp256k1
43-
44-
// Initialize context
45-
let context = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY))!
29+
print(try! signature.derRepresentation().base64EncodedString()) // MEUCID8JELjY/ua6MSRKh/VtO7q2YAgpPOfqlwi05Lj/gC1jAiEAiJ1r82jIVc9G/2kooLnzIbg04ky/leocdLn9XE1LvwI=
30+
```
4631

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

53-
// Verify the context and keys are setup correctly
54-
guard secp256k1_context_randomize(context, privkey) == 1,
55-
secp256k1_ec_pubkey_create(context, &cPubkey, privkey) == 1,
56-
secp256k1_ec_pubkey_serialize(context, &pubkey, &pubkeyLen, &cPubkey, UInt32(SECP256K1_EC_COMPRESSED)) == 1 else {
57-
// Destory context after creation
58-
secp256k1_context_destroy(context)
59-
return
60-
}
33+
# Getting Started
6134

62-
print(String(byteArray: pubKey)) // 02734b3511150a60fc8cac329cd5ff804555728740f2f2e98bc4242135ef5d5e4e
35+
In your `Package.swift`:
6336

64-
// Destory context after creation
65-
secp256k1_context_destroy(context)
37+
```swift
38+
dependencies: [
39+
.package(
40+
name: "secp256k1",
41+
url: "https://github.com/GigaBitcoin/secp256k1.swift.git",
42+
from: "0.3.0"
43+
),
44+
]
6645
```
6746

6847

Sources/bindings/include/SHA256.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// SHA256.h
3+
// GigaBitcoin/secp256k1.swift
4+
//
5+
// Copyright (c) 2021 GigaBitcoin LLC
6+
// Distributed under the MIT software license
7+
//
8+
// See the accompanying file LICENSE for information
9+
//
10+
11+
#include "../secp256k1/src/hash.h"
12+
#include "../secp256k1/include/secp256k1.h"
13+
14+
/// Exposes secp256k1 SHA256 implementation to the bindings target
15+
/// @param output pointer to an array to be filled by the function
16+
/// @param input a pointer to the data to be hashed
17+
/// @param len the length of the data to be hashed
18+
void secp256k1_swift_sha256(unsigned char *output, const unsigned char *input, size_t len);

Sources/bindings/include/secp256k1.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
#include "../secp256k1/include/secp256k1_preallocated.h"
44
#include "../secp256k1/include/secp256k1_recovery.h"
55
#include "../secp256k1/include/secp256k1_schnorrsig.h"
6-
#include "../secp256k1/include/secp256k1.h"
6+
#include "../secp256k1/include/secp256k1.h"

Sources/bindings/src/SHA256.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// SHA256.c
3+
// GigaBitcoin/secp256k1.swift
4+
//
5+
// Copyright (c) 2021 GigaBitcoin LLC
6+
// Distributed under the MIT software license
7+
//
8+
// See the accompanying file LICENSE for information
9+
//
10+
11+
#include "SHA256.h"
12+
#include "../secp256k1/src/hash_impl.h"
13+
14+
/// Exposes secp256k1 SHA256 implementation to the bindings target
15+
/// @param output pointer to an array to be filled by the function
16+
/// @param input a pointer to the data to be hashed
17+
/// @param len the length of the data to be hashed
18+
void secp256k1_swift_sha256(unsigned char *output, const unsigned char *input, size_t len) {
19+
secp256k1_sha256 hasher;
20+
secp256k1_sha256_initialize(&hasher);
21+
secp256k1_sha256_write(&hasher, input, len);
22+
secp256k1_sha256_finalize(&hasher, output);
23+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//
2+
// Digests.swift
3+
// GigaBitcoin/secp256k1.swift
4+
//
5+
// Modifications Copyright (c) 2021 GigaBitcoin LLC
6+
// Distributed under the MIT software license
7+
//
8+
// See the accompanying file LICENSE for information
9+
//
10+
//
11+
// NOTICE: THIS FILE HAS BEEN MODIFIED BY GigaBitcoin LLC
12+
// UNDER COMPLIANCE WITH THE APACHE 2.0 LICENSE FROM THE
13+
// ORIGINAL WORK OF THE COMPANY Apple Inc.
14+
//
15+
// THE FOLLOWING IS THE COPYRIGHT OF THE ORIGINAL DOCUMENT:
16+
//
17+
//
18+
//===----------------------------------------------------------------------===//
19+
//
20+
// This source file is part of the SwiftCrypto open source project
21+
//
22+
// Copyright (c) 2019-2020 Apple Inc. and the SwiftCrypto project authors
23+
// Licensed under Apache License v2.0
24+
//
25+
// See LICENSE.txt for license information
26+
// See CONTRIBUTORS.md for the list of SwiftCrypto project authors
27+
//
28+
// SPDX-License-Identifier: Apache-2.0
29+
//
30+
//===----------------------------------------------------------------------===//
31+
32+
import Foundation
33+
34+
// MARK: - SHA256Digest + DigestPrivate
35+
36+
public struct SHA256Digest: Digest {
37+
let bytes: (UInt64, UInt64, UInt64, UInt64)
38+
39+
public static var byteCount: Int {
40+
get { return 32 }
41+
42+
set { fatalError("Cannot set SHA256.byteCount") }
43+
}
44+
45+
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
46+
return try Swift.withUnsafeBytes(of: bytes) {
47+
let boundsCheckedPtr = UnsafeRawBufferPointer(start: $0.baseAddress,
48+
count: Self.byteCount)
49+
return try body(boundsCheckedPtr)
50+
}
51+
}
52+
53+
private func toArray() -> ArraySlice<UInt8> {
54+
var array = [UInt8]()
55+
array.appendByte(bytes.0)
56+
array.appendByte(bytes.1)
57+
array.appendByte(bytes.2)
58+
array.appendByte(bytes.3)
59+
return array.prefix(upTo: SHA256Digest.byteCount)
60+
}
61+
62+
public var description: String {
63+
return "\("SHA256") digest: \(toArray().hexString)"
64+
}
65+
66+
public func hash(into hasher: inout Hasher) {
67+
self.withUnsafeBytes { hasher.combine(bytes: $0) }
68+
}
69+
}

0 commit comments

Comments
 (0)