4
4
//
5
5
6
6
import Logging
7
- import secp256k1
7
+ import P256K
8
8
import Foundation
9
9
10
10
public enum KeyUtilError : Error {
@@ -26,40 +26,12 @@ public class KeyUtil {
26
26
}
27
27
28
28
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
- }
52
-
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
29
+ let privateKey = try P256K . Recovery. PrivateKey ( dataRepresentation: privateKey, format: . uncompressed)
30
+
31
+ let publicKey = privateKey. publicKey. dataRepresentation
32
+ let publicKeyLength = publicKey. count
33
+ let finalPublicKey = publicKey. subdata ( in: 1 ..< publicKeyLength)
34
+ return finalPublicKey
63
35
}
64
36
65
37
public static func generateAddress( from publicKey: Data ) -> EthereumAddress {
@@ -69,90 +41,42 @@ public class KeyUtil {
69
41
}
70
42
71
43
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)
81
45
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)
99
48
100
- let outputWithRecidPtr = UnsafeMutablePointer< UInt8> . allocate( capacity: 65 )
101
- defer {
102
- outputWithRecidPtr. deallocate ( )
103
- }
104
- outputWithRecidPtr. assign ( 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
108
51
109
- return signature
52
+ var resultSignature = Data ( compactSignature)
53
+ let v = UInt8 ( recoveryId & 0xFF )
54
+ resultSignature. append ( v)
55
+ return resultSignature
110
56
}
111
57
112
58
public static func recoverPublicKey( message: Data , signature: Data ) throws -> String {
113
59
if signature. count != 65 || message. count != 32 {
114
60
throw KeyUtilError . badArguments
115
61
}
116
-
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
-
62
+
127
63
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 ) ) "
157
81
}
158
82
}
0 commit comments