From 326e73b906b7e902c7f32fadc2dfa863557d5ab5 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 2 Sep 2020 13:22:42 -0700 Subject: [PATCH] Adding utility module (#16) --- .gitmodules | 3 + Package.swift | 21 ++++++- README.md | 15 ++--- Sources/swift-crypto/swift-crypto | 1 + Tests/secp256k1Tests/secp256k1Tests.swift | 69 +++++++++++++++-------- 5 files changed, 76 insertions(+), 33 deletions(-) create mode 160000 Sources/swift-crypto/swift-crypto diff --git a/.gitmodules b/.gitmodules index dee59d2..30dc04a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Sources/secp256k1/secp256k1"] path = Sources/secp256k1/secp256k1 url = https://github.com/bitcoin-core/secp256k1 +[submodule "Sources/swift-crypto/swift-crypto"] + path = Sources/swift-crypto/swift-crypto + url = https://github.com/apple/swift-crypto diff --git a/Package.swift b/Package.swift index 121227e..de5e5f1 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,10 @@ let package = Package( // WARNING: These APIs should not be considered stable and may change at any time. .library( name: "secp256k1", - targets: ["secp256k1"] + targets: [ + "secp256k1", + "secp256k1_utils" + ] ) ], targets: [ @@ -42,9 +45,23 @@ let package = Package( .define("ECMULT_GEN_PREC_BITS", to: "4", nil) ] ), + // Only include select utility extensions because most of Swift Crypto is not required + .target( + name: "secp256k1_utils", + path: "Sources/swift-crypto", + exclude: [ + "swift-crypto/Sources", + ], + sources: [ + "swift-crypto/Tests/CryptoTests/Utils/BytesUtil.swift" + ] + ), .testTarget( name: "secp256k1Tests", - dependencies: ["secp256k1"] + dependencies: [ + "secp256k1", + "secp256k1_utils" + ] ) ], swiftLanguageVersions: [.v5], diff --git a/README.md b/README.md index a02fe33..01e0bb6 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # 🔐 secp256k1.swift [![Build Status](https://app.bitrise.io/app/ef44aebd8443b33b/status.svg?token=oDGzN3bMEwseXF_5MQUsTg&branch=main)](https://app.bitrise.io/app/ef44aebd8443b33b) -Swift bindings library for ECDSA signatures and secret/public key operations using the [libsecp256k1](https://github.com/bitcoin-core/secp256k1) C library. +Swift bindings library for ECDSA signatures and secret/public key operations using [libsecp256k1](https://github.com/bitcoin-core/secp256k1). # Objective This library aims to be a lightweight dependency for clients and wrapper libraries to include ECDSA functionality. -This package targets the default git branch of secp256k1 and aims to stay up-to-date without using a mirrored repository. +This package is set to the default git branch of secp256k1 and aims to stay up-to-date without using a mirrored repository. An extra module is available for convenience functionality. # Getting Started @@ -12,7 +12,7 @@ In your `Package.swift`: ```swift dependencies: [ - .package(name: "secp256k1", url: "https://github.com/GigaBitcoin/secp256k1.swift.git", from: "0.0.1"), + .package(name: "secp256k1", url: "https://github.com/GigaBitcoin/secp256k1.swift.git", from: "0.0.11"), ] ``` @@ -22,26 +22,27 @@ Currently, this Swift package only provides a single product library built using ```swift import secp256k1 +import secp256k1_utils // Initialize context let context = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY))! // Setup private and public key variables -var pubkeyLen = 65 +var pubkeyLen = 33 var cPubkey = secp256k1_pubkey() var pubkey = [UInt8](repeating: 0, count: pubkeyLen) -let privkey: [UInt8] = [0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,0,0,1,0,0,1,1,0,0,1,0,0,32,0] +let privkey = try! Array(hexString: "14e4a74438858920d8a35fb2d88677580b6a2ee9be4e711ae34ec6b396d87b5c") // 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_UNCOMPRESSED)) == 1 else { + secp256k1_ec_pubkey_serialize(context, &pubkey, &pubkeyLen, &cPubkey, UInt32(SECP256K1_EC_COMPRESSED)) == 1 else { // Destory context after creation secp256k1_context_destroy(context) return } -print(pubkey) // [4,96,104, 212, 128, 165, 213, 207, 134, 132, 22, 247, 38, 114, 82, 108, 77, 43, 6, 56, ... ] +print(pubkey.hexString) // 02734b3511150a60fc8cac329cd5ff804555728740f2f2e98bc4242135ef5d5e4e // Destory context after creation secp256k1_context_destroy(context) diff --git a/Sources/swift-crypto/swift-crypto b/Sources/swift-crypto/swift-crypto new file mode 160000 index 0000000..afe4c9b --- /dev/null +++ b/Sources/swift-crypto/swift-crypto @@ -0,0 +1 @@ +Subproject commit afe4c9b5f65b612a2bd4b1cb5ac70eb5841f278e diff --git a/Tests/secp256k1Tests/secp256k1Tests.swift b/Tests/secp256k1Tests/secp256k1Tests.swift index d47b98a..24dbe9e 100644 --- a/Tests/secp256k1Tests/secp256k1Tests.swift +++ b/Tests/secp256k1Tests/secp256k1Tests.swift @@ -1,47 +1,68 @@ import XCTest @testable import secp256k1 +@testable import secp256k1_utils final class secp256k1Tests: XCTestCase { - /// Basic Keypair test - func testKeypairCreation() { + /// Uncompressed Keypair test + func testUncompressedKeypairCreation() { // Initialize context let context = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY))! // Destory context after execution - defer { - secp256k1_context_destroy(context) - } + defer { secp256k1_context_destroy(context) } // Setup private and public key variables var pubkeyLen = 65 var cPubkey = secp256k1_pubkey() - var pubkey = [UInt8](repeating: 0, count: pubkeyLen) - let privkey: [UInt8] = [0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,0,0,1,0,0,1,1,0,0,1,0,0,32,0] + var publicKey = [UInt8](repeating: 0, count: pubkeyLen) + + let privateKey = try! Array(hexString: "14E4A74438858920D8A35FB2D88677580B6A2EE9BE4E711AE34EC6B396D87B5C".lowercased()) + + // Verify the context and keys are setup correctly + XCTAssertEqual(secp256k1_context_randomize(context, privateKey), 1) + XCTAssertEqual(secp256k1_ec_pubkey_create(context, &cPubkey, privateKey), 1) + XCTAssertEqual(secp256k1_ec_pubkey_serialize(context, &publicKey, &pubkeyLen, &cPubkey, UInt32(SECP256K1_EC_UNCOMPRESSED)), 1) + let hexString = """ + 04734B3511150A60FC8CAC329CD5FF804555728740F2F2E98BC4242135EF5D5E4E6C4918116B0866F50C46614F3015D8667FBFB058471D662A642B8EA2C9C78E8A + """ + + // Define the expected public key + let expectedPublicKey = try! Array(hexString: hexString.lowercased()) + + // Verify the generated public key matches the expected public key + XCTAssertEqual(expectedPublicKey, publicKey) + } + + /// Compressed Keypair test + func testCompressedKeypairCreation() { + // Initialize context + let context = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY))! + + // Destory context after execution + defer { secp256k1_context_destroy(context) } + + // Setup private and public key variables + var pubkeyLen = 33 + var cPubkey = secp256k1_pubkey() + var publicKey = [UInt8](repeating: 0, count: pubkeyLen) + + let privateKey = try! Array(hexString: "B035FCFC6ABF660856C5F3A6F9AC51FCA897BB4E76AD9ACA3EFD40DA6B9C864B".lowercased()) + // Verify the context and keys are setup correctly - XCTAssertEqual(secp256k1_context_randomize(context, privkey), 1) - XCTAssertEqual(secp256k1_ec_pubkey_create(context, &cPubkey, privkey), 1) - XCTAssertEqual(secp256k1_ec_pubkey_serialize(context, &pubkey, &pubkeyLen, &cPubkey, UInt32(SECP256K1_EC_UNCOMPRESSED)), 1) + XCTAssertEqual(secp256k1_context_randomize(context, privateKey), 1) + XCTAssertEqual(secp256k1_ec_pubkey_create(context, &cPubkey, privateKey), 1) + XCTAssertEqual(secp256k1_ec_pubkey_serialize(context, &publicKey, &pubkeyLen, &cPubkey, UInt32(SECP256K1_EC_COMPRESSED)), 1) // Define the expected public key - let expectedPublicKey: [UInt8] = [ - 4,96,104, 212, 128, 165, 213, - 207, 134, 132, 22, 247, 38, - 114, 82, 108, 77, 43, 6, 56, - 80, 113, 12, 11, 119, 7, 240, - 188, 73, 170, 44, 202, 33, 225, - 30, 248, 53, 138, 34, 22, 100, - 96, 31, 76, 64, 125, 71, 127, - 62, 155, 108, 243, 17, 222, 97, - 234, 75, 247, 187, 83, 151, 206, - 27, 38, 228 - ] + let expectedPublicKey = try! Array(hexString: "02EA724B70B48B61FB87E4310871A48C65BF38BF3FDFEFE73C2B90F8F32F9C1794".lowercased()) // Verify the generated public key matches the expected public key - XCTAssertEqual(expectedPublicKey, pubkey) + XCTAssertEqual(expectedPublicKey, publicKey) } static var allTests = [ - ("testKeypairCreation", testKeypairCreation), + ("testUncompressedKeypairCreation", testUncompressedKeypairCreation), + ("testCompressedKeypairCreation", testCompressedKeypairCreation), ] }