33// Copyright © Argent Labs Limited. All rights reserved.
44//
55
6+ import P256K
67import Logging
78import Foundation
8- import libsecp256k1
99
1010public enum KeyUtilError : Error {
1111 case invalidContext
@@ -26,40 +26,12 @@ public class KeyUtil {
2626 }
2727
2828 public static func generatePublicKey( from privateKey: Data ) throws -> Data {
29- guard let ctx = secp256k1_context_create ( UInt32 ( SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY) ) else {
30- logger. warning ( " Failed to generate a public key: invalid context. " )
31- throw KeyUtilError . invalidContext
32- }
33-
34- defer {
35- secp256k1_context_destroy ( ctx)
36- }
37-
38- let privateKeyPtr = ( privateKey as NSData ) . bytes. assumingMemoryBound ( to: UInt8 . self)
39- guard secp256k1_ec_seckey_verify ( ctx, privateKeyPtr) == 1 else {
40- logger. warning ( " Failed to generate a public key: private key is not valid. " )
41- throw KeyUtilError . privateKeyInvalid
42- }
43-
44- let publicKeyPtr = UnsafeMutablePointer< secp256k1_pubkey> . allocate( capacity: 1 )
45- defer {
46- publicKeyPtr. deallocate ( )
47- }
48- guard secp256k1_ec_pubkey_create ( ctx, publicKeyPtr, privateKeyPtr) == 1 else {
49- logger. warning ( " Failed to generate a public key: public key could not be created. " )
50- throw KeyUtilError . unknownError
51- }
29+ let privateKey = try P256K . Recovery. PrivateKey ( dataRepresentation: privateKey, format: . uncompressed)
5230
53- var publicKeyLength = 65
54- let outputPtr = UnsafeMutablePointer< UInt8> . allocate( capacity: publicKeyLength)
55- defer {
56- outputPtr. deallocate ( )
57- }
58- secp256k1_ec_pubkey_serialize ( ctx, outputPtr, & publicKeyLength, publicKeyPtr, UInt32 ( SECP256K1_EC_UNCOMPRESSED) )
59-
60- let publicKey = Data ( bytes: outputPtr, count: publicKeyLength) . subdata ( in: 1 ..< publicKeyLength)
61-
62- return publicKey
31+ let publicKey = privateKey. publicKey. dataRepresentation
32+ let publicKeyLength = publicKey. count
33+ let finalPublicKey = publicKey. subdata ( in: 1 ..< publicKeyLength)
34+ return finalPublicKey
6335 }
6436
6537 public static func generateAddress( from publicKey: Data ) -> EthereumAddress {
@@ -69,90 +41,42 @@ public class KeyUtil {
6941 }
7042
7143 public static func sign( message: Data , with privateKey: Data , hashing: Bool ) throws -> Data {
72- guard let ctx = secp256k1_context_create ( UInt32 ( SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY) ) else {
73- logger. warning ( " Failed to sign message: invalid context. " )
74- throw KeyUtilError . invalidContext
75- }
76-
77- defer {
78- secp256k1_context_destroy ( ctx)
79- }
80-
44+ let privateKey = try P256K . Recovery. PrivateKey ( dataRepresentation: privateKey)
8145 let msgData = hashing ? message. web3. keccak256 : message
82- let msg = ( msgData as NSData ) . bytes. assumingMemoryBound ( to: UInt8 . self)
83- let privateKeyPtr = ( privateKey as NSData ) . bytes. assumingMemoryBound ( to: UInt8 . self)
84- let signaturePtr = UnsafeMutablePointer< secp256k1_ecdsa_recoverable_signature> . allocate( capacity: 1 )
85- defer {
86- signaturePtr. deallocate ( )
87- }
88- guard secp256k1_ecdsa_sign_recoverable ( ctx, signaturePtr, msg, privateKeyPtr, nil , nil ) == 1 else {
89- logger. warning ( " Failed to sign message: recoverable ECDSA signature creation failed. " )
90- throw KeyUtilError . signatureFailure
91- }
92-
93- let outputPtr = UnsafeMutablePointer< UInt8> . allocate( capacity: 64 )
94- defer {
95- outputPtr. deallocate ( )
96- }
97- var recid : Int32 = 0
98- secp256k1_ecdsa_recoverable_signature_serialize_compact ( ctx, outputPtr, & recid, signaturePtr)
46+ let digest = HashDigest ( msgData. bytes)
47+ let signature = try privateKey. signature ( for: digest)
9948
100- let outputWithRecidPtr = UnsafeMutablePointer< UInt8> . allocate( capacity: 65 )
101- defer {
102- outputWithRecidPtr. deallocate ( )
103- }
104- outputWithRecidPtr. update ( from: outputPtr, count: 64 )
105- outputWithRecidPtr. advanced ( by: 64 ) . pointee = UInt8 ( recid)
106-
107- let signature = Data ( bytes: outputWithRecidPtr, count: 65 )
49+ let compactSignature = try signature. compactRepresentation. signature
50+ let recoveryId = try signature. compactRepresentation. recoveryId
10851
109- return signature
52+ var resultSignature = Data ( compactSignature)
53+ let v = UInt8 ( recoveryId & 0xFF )
54+ resultSignature. append ( v)
55+ return resultSignature
11056 }
11157
11258 public static func recoverPublicKey( message: Data , signature: Data ) throws -> String {
11359 if signature. count != 65 || message. count != 32 {
11460 throw KeyUtilError . badArguments
11561 }
11662
117- guard let ctx = secp256k1_context_create ( UInt32 ( SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY) ) else {
118- logger. warning ( " Failed to sign message: invalid context. " )
119- throw KeyUtilError . invalidContext
120- }
121- defer { secp256k1_context_destroy ( ctx) }
122-
123- // get recoverable signature
124- let signaturePtr = UnsafeMutablePointer< secp256k1_ecdsa_recoverable_signature> . allocate( capacity: 1 )
125- defer { signaturePtr. deallocate ( ) }
126-
12763 let serializedSignature = Data ( signature [ 0 ..< 64 ] )
128- var v = Int32 ( signature [ 64 ] )
129- if v >= 27 , v <= 30 {
130- v -= 27
131- } else if v >= 31 , v <= 34 {
132- v -= 31
133- } else if v >= 35 , v <= 38 {
134- v -= 35
135- }
136-
137- try serializedSignature. withUnsafeBytes {
138- guard secp256k1_ecdsa_recoverable_signature_parse_compact ( ctx, signaturePtr, $0. bindMemory ( to: UInt8 . self) . baseAddress!, v) == 1 else {
139- logger. warning ( " Failed to parse signature: recoverable ECDSA signature parse failed. " )
140- throw KeyUtilError . signatureParseFailure
141- }
142- }
143- let pubkey = UnsafeMutablePointer< secp256k1_pubkey> . allocate( capacity: 1 )
144- defer { pubkey. deallocate ( ) }
145-
146- try message. withUnsafeBytes {
147- guard secp256k1_ecdsa_recover ( ctx, pubkey, signaturePtr, $0. bindMemory ( to: UInt8 . self) . baseAddress!) == 1 else {
148- throw KeyUtilError . signatureFailure
149- }
150- }
151- var size = 65
152- var rv = Data ( count: size)
153- _ = rv. withUnsafeMutableBytes {
154- secp256k1_ec_pubkey_serialize ( ctx, $0. bindMemory ( to: UInt8 . self) . baseAddress!, & size, pubkey, UInt32 ( SECP256K1_EC_UNCOMPRESSED) )
155- }
156- return " 0x \( rv [ 1 ... ] . web3. keccak256. web3. hexString. suffix ( 40 ) ) "
64+ var recoveryId = Int32 ( signature [ 64 ] )
65+ if recoveryId >= 27 , recoveryId <= 30 {
66+ recoveryId -= 27
67+ } else if recoveryId >= 31 , recoveryId <= 34 {
68+ recoveryId -= 31
69+ } else if recoveryId >= 35 , recoveryId <= 38 {
70+ recoveryId -= 35
71+ }
72+
73+ let digest = HashDigest ( message. bytes)
74+ let publicKey = try P256K . Recovery. PublicKey (
75+ digest,
76+ signature: P256K . Recovery. ECDSASignature ( compactRepresentation: serializedSignature, recoveryId: recoveryId) ,
77+ format: . uncompressed
78+ )
79+
80+ return " 0x \( publicKey. dataRepresentation [ 1 ... ] . web3. keccak256. web3. hexString. suffix ( 40 ) ) "
15781 }
15882}
0 commit comments