Skip to content

chore: update source secp256k1 dependency #379

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let package = Package(
dependencies: [
.package(name: "BigInt", url: "https://github.com/attaswift/BigInt", from: "5.3.0"),
.package(name: "GenericJSON", url: "https://github.com/iwill/generic-json-swift", .upToNextMajor(from: "2.0.0")),
.package(url: "https://github.com/GigaBitcoin/secp256k1.swift.git", .upToNextMajor(from: "0.6.0")),
.package(name: "swift-secp256k1", url: "https://github.com/21-DOT-DEV/swift-secp256k1", from: "0.21.1"),
.package(url: "https://github.com/vapor/websocket-kit.git", from: "2.0.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0")
],
Expand All @@ -29,7 +29,7 @@ let package = Package(
.target(name: "Internal_CryptoSwift_PBDKF2"),
"BigInt",
"GenericJSON",
.product(name: "secp256k1", package: "secp256k1.swift"),
.product(name: "P256K", package: "swift-secp256k1"),
.product(name: "WebSocketKit", package: "websocket-kit"),
.product(name: "Logging", package: "swift-log")
],
Expand Down
4 changes: 2 additions & 2 deletions web3sTests/Account/EthereumKeyStorageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class EthereumKeyStorageTests: XCTestCase {
}

func testEncryptAndStorePrivateKey() {
let randomData = Data.randomOfLength(256)!
let randomData = Data.randomOfLength(32)!
let keyStorage = EthereumKeyLocalStorage() as EthereumSingleKeyStorageProtocol
let password = "myP4ssw0rD"

Expand All @@ -56,7 +56,7 @@ class EthereumKeyStorageTests: XCTestCase {
}

func testEncryptAndStorePrivateKeyMultiple() {
let randomData = Data.randomOfLength(256)!
let randomData = Data.randomOfLength(32)!
let keyStorage = EthereumKeyLocalStorage() as EthereumMultipleKeyStorageProtocol
let password = "myP4ssw0rD"

Expand Down
140 changes: 32 additions & 108 deletions web3swift/src/Utils/KeyUtil.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// Copyright © 2022 Argent Labs Limited. All rights reserved.
//

import P256K
import Logging
import secp256k1
import Foundation

public enum KeyUtilError: Error {
Expand All @@ -26,40 +26,12 @@ public class KeyUtil {
}

public static func generatePublicKey(from privateKey: Data) throws -> Data {
guard let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)) else {
logger.warning("Failed to generate a public key: invalid context.")
throw KeyUtilError.invalidContext
}

defer {
secp256k1_context_destroy(ctx)
}

let privateKeyPtr = (privateKey as NSData).bytes.assumingMemoryBound(to: UInt8.self)
guard secp256k1_ec_seckey_verify(ctx, privateKeyPtr) == 1 else {
logger.warning("Failed to generate a public key: private key is not valid.")
throw KeyUtilError.privateKeyInvalid
}

let publicKeyPtr = UnsafeMutablePointer<secp256k1_pubkey>.allocate(capacity: 1)
defer {
publicKeyPtr.deallocate()
}
guard secp256k1_ec_pubkey_create(ctx, publicKeyPtr, privateKeyPtr) == 1 else {
logger.warning("Failed to generate a public key: public key could not be created.")
throw KeyUtilError.unknownError
}
let privateKey = try P256K.Recovery.PrivateKey(dataRepresentation: privateKey, format: .uncompressed)

var publicKeyLength = 65
let outputPtr = UnsafeMutablePointer<UInt8>.allocate(capacity: publicKeyLength)
defer {
outputPtr.deallocate()
}
secp256k1_ec_pubkey_serialize(ctx, outputPtr, &publicKeyLength, publicKeyPtr, UInt32(SECP256K1_EC_UNCOMPRESSED))

let publicKey = Data(bytes: outputPtr, count: publicKeyLength).subdata(in: 1 ..< publicKeyLength)

return publicKey
let publicKey = privateKey.publicKey.dataRepresentation
let publicKeyLength = publicKey.count
let finalPublicKey = publicKey.subdata(in: 1 ..< publicKeyLength)
return finalPublicKey
}

public static func generateAddress(from publicKey: Data) -> EthereumAddress {
Expand All @@ -69,90 +41,42 @@ public class KeyUtil {
}

public static func sign(message: Data, with privateKey: Data, hashing: Bool) throws -> Data {
guard let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)) else {
logger.warning("Failed to sign message: invalid context.")
throw KeyUtilError.invalidContext
}

defer {
secp256k1_context_destroy(ctx)
}

let privateKey = try P256K.Recovery.PrivateKey(dataRepresentation: privateKey)
let msgData = hashing ? message.web3.keccak256 : message
let msg = (msgData as NSData).bytes.assumingMemoryBound(to: UInt8.self)
let privateKeyPtr = (privateKey as NSData).bytes.assumingMemoryBound(to: UInt8.self)
let signaturePtr = UnsafeMutablePointer<secp256k1_ecdsa_recoverable_signature>.allocate(capacity: 1)
defer {
signaturePtr.deallocate()
}
guard secp256k1_ecdsa_sign_recoverable(ctx, signaturePtr, msg, privateKeyPtr, nil, nil) == 1 else {
logger.warning("Failed to sign message: recoverable ECDSA signature creation failed.")
throw KeyUtilError.signatureFailure
}

let outputPtr = UnsafeMutablePointer<UInt8>.allocate(capacity: 64)
defer {
outputPtr.deallocate()
}
var recid: Int32 = 0
secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, outputPtr, &recid, signaturePtr)
let digest = HashDigest(msgData.bytes)
let signature = try privateKey.signature(for: digest)

let outputWithRecidPtr = UnsafeMutablePointer<UInt8>.allocate(capacity: 65)
defer {
outputWithRecidPtr.deallocate()
}
outputWithRecidPtr.assign(from: outputPtr, count: 64)
outputWithRecidPtr.advanced(by: 64).pointee = UInt8(recid)

let signature = Data(bytes: outputWithRecidPtr, count: 65)
let compactSignature = try signature.compactRepresentation.signature
let recoveryId = try signature.compactRepresentation.recoveryId

return signature
var resultSignature = Data(compactSignature)
let v = UInt8(recoveryId & 0xFF)
resultSignature.append(v)
return resultSignature
}

public static func recoverPublicKey(message: Data, signature: Data) throws -> String {
if signature.count != 65 || message.count != 32 {
throw KeyUtilError.badArguments
}

guard let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)) else {
logger.warning("Failed to sign message: invalid context.")
throw KeyUtilError.invalidContext
}
defer { secp256k1_context_destroy(ctx) }

// get recoverable signature
let signaturePtr = UnsafeMutablePointer<secp256k1_ecdsa_recoverable_signature>.allocate(capacity: 1)
defer { signaturePtr.deallocate() }

let serializedSignature = Data(signature[0 ..< 64])
var v = Int32(signature[64])
if v >= 27, v <= 30 {
v -= 27
} else if v >= 31, v <= 34 {
v -= 31
} else if v >= 35, v <= 38 {
v -= 35
}

try serializedSignature.withUnsafeBytes {
guard secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, signaturePtr, $0.bindMemory(to: UInt8.self).baseAddress!, v) == 1 else {
logger.warning("Failed to parse signature: recoverable ECDSA signature parse failed.")
throw KeyUtilError.signatureParseFailure
}
}
let pubkey = UnsafeMutablePointer<secp256k1_pubkey>.allocate(capacity: 1)
defer { pubkey.deallocate() }

try message.withUnsafeBytes {
guard secp256k1_ecdsa_recover(ctx, pubkey, signaturePtr, $0.bindMemory(to: UInt8.self).baseAddress!) == 1 else {
throw KeyUtilError.signatureFailure
}
}
var size = 65
var rv = Data(count: size)
rv.withUnsafeMutableBytes {
secp256k1_ec_pubkey_serialize(ctx, $0.bindMemory(to: UInt8.self).baseAddress!, &size, pubkey, UInt32(SECP256K1_EC_UNCOMPRESSED))
}
return "0x\(rv[1...].web3.keccak256.web3.hexString.suffix(40))"
var recoveryId = Int32(signature[64])
if recoveryId >= 27, recoveryId <= 30 {
recoveryId -= 27
} else if recoveryId >= 31, recoveryId <= 34 {
recoveryId -= 31
} else if recoveryId >= 35, recoveryId <= 38 {
recoveryId -= 35
}

let digest = HashDigest(message.bytes)
let publicKey = try P256K.Recovery.PublicKey(
digest,
signature: P256K.Recovery.ECDSASignature(compactRepresentation: serializedSignature, recoveryId: recoveryId),
format: .uncompressed
)

return "0x\(publicKey.dataRepresentation[1...].web3.keccak256.web3.hexString.suffix(40))"
}
}
Loading