1
+ from __future__ import annotations
1
2
from dataclasses import dataclass
2
3
from typing import Optional , Tuple
3
4
6
7
from nacl .public import PrivateKey as ImplPrivateKey
7
8
8
9
from nacl .signing import SigningKey , VerifyKey
9
- from nacl .encoding import HexEncoder
10
+ from nacl .encoding import HexEncoder , Encoder
10
11
from synlink .crypto .exception import (
11
12
CryptoBaseException ,
12
13
SignatureVerificationError ,
13
14
)
14
15
from synlink .crypto .kind import Kind
15
16
from synlink .crypto .typing import PrivateKey as IPrivateKey
16
17
from synlink .crypto .typing import PublicKey as IPublicKey
17
- from synlink .utils import _check_minimum_version
18
-
19
- if _check_minimum_version (3 , 11 , 0 ):
20
- from typing import Self
21
- else :
22
- from typing_extensions import Self
18
+ from synlink .crypto .typing import KeyPair as IKeyPair
23
19
24
20
Message = bytes
25
21
Signiture = bytes
32
28
"create_new_ed25519_key_pair_from_seed" ,
33
29
]
34
30
31
+
35
32
class PublicKey (IPublicKey ):
36
33
"""
37
34
Represents an ED25519 public key, providing methods for verification
@@ -45,26 +42,29 @@ def __init__(self, impl: VerifyKey):
45
42
Args:
46
43
impl: An instance of nacl.signing.VerifyKey.
47
44
"""
48
- super ().__init__ ()
49
45
self ._impl : VerifyKey = impl
50
46
self ._kind = Kind .ED25519
47
+
51
48
def get_kind (self ) -> Kind :
52
49
"""
53
50
Returns the kind of this cryptographic key.
54
51
"""
55
52
return self ._kind
53
+
56
54
def to_bytes (self ) -> bytes :
57
55
"""
58
56
Converts the public key to its raw byte representation.
59
57
"""
60
58
return bytes (self ._impl )
59
+
61
60
def __bytes__ (self ) -> bytes :
62
61
"""
63
62
Allows the PublicKey object to be converted to bytes using bytes().
64
63
"""
65
64
return self .to_bytes ()
65
+
66
66
@classmethod
67
- def from_bytes (cls , data : bytes ) -> Self :
67
+ def from_bytes (cls , data : bytes ) -> "PublicKey" :
68
68
"""
69
69
Creates a PublicKey object from its raw byte representation.
70
70
@@ -75,6 +75,7 @@ def from_bytes(cls, data: bytes) -> Self:
75
75
A new PublicKey instance.
76
76
"""
77
77
return cls (VerifyKey (data ))
78
+
78
79
def try_verify (self , data : bytes , signature : bytes ) -> bool :
79
80
"""
80
81
Attempts to verify the signature against the signed message.
@@ -97,6 +98,7 @@ def try_verify(self, data: bytes, signature: bytes) -> bool:
97
98
raise SignatureVerificationError (f"{ e } " ) from e
98
99
except Exception as e :
99
100
raise CryptoBaseException (f"{ e } " ) from e
101
+
100
102
def verify (self , data : bytes , signature : bytes ) -> bool :
101
103
"""
102
104
Verifies the signature against the signed message.
@@ -114,26 +116,31 @@ def verify(self, data: bytes, signature: bytes) -> bool:
114
116
return True
115
117
except BadSignatureError :
116
118
return False
117
- except Exception as e :
119
+ except Exception :
118
120
# Catch other potential exceptions during verification
119
121
# print(f"An unexpected error occurred during verification: {e}") # For debugging
120
122
return False
123
+
121
124
def __str__ (self ) -> str :
122
125
"""
123
126
Returns a human-readable string representation of the public key.
124
127
"""
125
- output = self ._impl .encode (encoder = HexEncoder ()).decode ("utf-8" )
128
+ encoder : Encoder = HexEncoder
129
+ output = self ._impl .encode (encoder ).decode ("utf-8" )
126
130
return f"PublicKey({ output } )"
131
+
127
132
def __repr__ (self ) -> str :
128
133
"""
129
134
Returns a detailed string representation for debugging.
130
135
"""
131
- output = self ._impl .encode (encoder = HexEncoder ()).decode ("utf-8" )
136
+ encoder : Encoder = HexEncoder
137
+ output = self ._impl .encode (encoder ).decode ("utf-8" )
132
138
# Show a truncated hex representation for brevity in repr
133
139
return (
134
140
f"<synlink.crypto.ed25519.PublicKey { output [:8 ]} ...{ output [- 8 :]} >"
135
141
)
136
142
143
+
137
144
class PrivateKey (IPrivateKey ):
138
145
"""
139
146
Represents an ED25519 private key, providing methods for signing
@@ -147,16 +154,17 @@ def __init__(self, impl: SigningKey):
147
154
Args:
148
155
impl: An instance of nacl.signing.SigningKey.
149
156
"""
150
- super ().__init__ ()
151
157
self ._kind = Kind .ED25519
152
158
self ._impl : SigningKey = impl
159
+
153
160
def get_kind (self ) -> Kind :
154
161
"""
155
162
Returns the kind of this cryptographic key.
156
163
"""
157
164
return self ._kind
165
+
158
166
@classmethod
159
- def generate (cls ) -> Self :
167
+ def generate (cls ) -> "PrivateKey" :
160
168
"""
161
169
Generates a new random ED25519 private key.
162
170
@@ -165,8 +173,9 @@ def generate(cls) -> Self:
165
173
"""
166
174
impl = SigningKey .generate ()
167
175
return cls (impl )
176
+
168
177
@classmethod
169
- def from_seed (cls , seed : Optional [bytes ] = None ) -> Self :
178
+ def from_seed (cls , seed : Optional [bytes ] = None ) -> "PrivateKey" :
170
179
"""
171
180
Generates an ED25519 private key from a 32-byte seed.
172
181
@@ -189,8 +198,9 @@ def from_seed(cls, seed: Optional[bytes] = None) -> Self:
189
198
), "PrivateKey seed must be a 32 bytes long binary sequence"
190
199
impl = ImplPrivateKey .from_seed (seed )
191
200
return cls (SigningKey (bytes (impl )))
201
+
192
202
@classmethod
193
- def from_bytes (cls , data : bytes ) -> Self :
203
+ def from_bytes (cls , data : bytes ) -> "PrivateKey" :
194
204
"""
195
205
Creates an ED25519 private key from its raw byte representation.
196
206
@@ -202,6 +212,7 @@ def from_bytes(cls, data: bytes) -> Self:
202
212
"""
203
213
impl = SigningKey (data )
204
214
return cls (impl )
215
+
205
216
def get_public_key (self ) -> IPublicKey :
206
217
"""
207
218
Returns the public key corresponding to this private key.
@@ -210,6 +221,7 @@ def get_public_key(self) -> IPublicKey:
210
221
raise CryptoBaseException ("Invalid private key implementation." )
211
222
# Return a PublicKey wrapping the VerifyKey derived from this SigningKey
212
223
return PublicKey (self ._impl .verify_key )
224
+
213
225
def sign (self , data : bytes ) -> Tuple [Message , Signiture ]:
214
226
"""
215
227
Signs data with the private key and returns the raw signature.
@@ -225,37 +237,42 @@ def sign(self, data: bytes) -> Tuple[Message, Signiture]:
225
237
# Direct signing using the wrapped SigningKey
226
238
signed_message = self ._impl .sign (data )
227
239
return signed_message .message , signed_message .signature
240
+
228
241
def to_bytes (self ) -> bytes :
229
242
"""
230
243
Converts the private key to its raw byte representation.
231
244
"""
232
245
return bytes (self ._impl )
246
+
233
247
def __bytes__ (self ) -> bytes :
234
248
"""
235
249
Allows the PrivateKey object to be converted to bytes using bytes().
236
250
"""
237
251
return self .to_bytes ()
252
+
238
253
def __str__ (self ) -> str :
239
254
"""
240
255
Returns a human-readable string representation of the private key.
241
256
"""
242
257
# For security, avoid showing private key material in str.
243
258
return "PrivateKey(ED25519)"
259
+
244
260
def __repr__ (self ) -> str :
245
261
"""
246
262
Returns a detailed string representation for debugging.
247
263
"""
248
264
# For security, avoid showing private key material in repr.
249
265
return "<synlink.crypto.ed25519.PrivateKey>"
250
266
267
+
251
268
@dataclass (frozen = True , repr = False )
252
- class KeyPair (object ):
269
+ class KeyPair (IKeyPair ):
253
270
"""
254
271
Represents an ED25519 key pair, containing both a private and public key.
255
272
"""
256
273
257
274
secret : PrivateKey
258
- public : PublicKey
275
+ public : IPublicKey
259
276
260
277
def try_verify (self , message : bytes , signature : bytes ) -> bool :
261
278
"""
@@ -273,6 +290,7 @@ def try_verify(self, message: bytes, signature: bytes) -> bool:
273
290
Exception: base class for all non-exit exceptions.
274
291
"""
275
292
return self .public .try_verify (data = message , signature = signature )
293
+
276
294
def verify (self , message : bytes , signature : bytes ) -> bool :
277
295
"""
278
296
Verifies the signature against the signed message.
@@ -288,6 +306,7 @@ def verify(self, message: bytes, signature: bytes) -> bool:
288
306
return self .public .verify (data = message , signature = signature )
289
307
except BadSignatureError :
290
308
return False
309
+
291
310
def sign (self , message : bytes ) -> Tuple [Message , Signiture ]:
292
311
"""
293
312
Signs data with the private key and returns the raw signature.
@@ -299,18 +318,21 @@ def sign(self, message: bytes) -> Tuple[Message, Signiture]:
299
318
The raw signature bytes.
300
319
"""
301
320
return self .secret .sign (data = message )
321
+
302
322
def __bytes__ (self ) -> bytes :
303
323
"""
304
324
Returns the raw bytes of the secret (private) key.
305
325
"""
306
326
return bytes (self .secret )
327
+
307
328
def __repr__ (self ) -> str :
308
329
"""
309
330
Returns a detailed string representation for debugging.
310
331
"""
311
332
# Include the public key's repr for better context
312
333
return f"<synlink.crypto.ed25519.KeyPair public={ self .public !s} >"
313
334
335
+
314
336
def create_new_ed25519_key_pair () -> KeyPair :
315
337
"""
316
338
Creates a new ED25519 key pair with randomly generated keys.
@@ -320,7 +342,8 @@ def create_new_ed25519_key_pair() -> KeyPair:
320
342
"""
321
343
secret = PrivateKey .generate ()
322
344
public = secret .get_public_key ()
323
- return KeyPair (secret , public )
345
+ return KeyPair (secret = secret , public = public )
346
+
324
347
325
348
def create_new_ed25519_key_pair_from_seed (
326
349
seed : Optional [bytes ] = None ,
@@ -338,4 +361,4 @@ def create_new_ed25519_key_pair_from_seed(
338
361
"""
339
362
secret : PrivateKey = PrivateKey .from_seed (seed )
340
363
public = secret .get_public_key ()
341
- return KeyPair (secret , public )
364
+ return KeyPair (secret = secret , public = public )
0 commit comments