0
# Core Keys & Signatures
1
2
Primary ECDSA/EdDSA functionality for creating and verifying digital signatures. This module provides the main interface for elliptic curve cryptographic operations including key generation, deterministic signing, and signature verification with support for multiple curves and hash functions.
3
4
## Capabilities
5
6
### SigningKey Class
7
8
The SigningKey class represents a private key for creating digital signatures using ECDSA or EdDSA algorithms.
9
10
#### Key Generation and Loading
11
12
```python { .api }
13
class SigningKey:
14
@classmethod
15
def generate(cls, curve=NIST192p, entropy=None, hashfunc=sha1):
16
"""
17
Generate a new random signing key.
18
19
Parameters:
20
- curve: Curve object (default NIST192p)
21
- entropy: callable returning random bytes, or None for os.urandom
22
- hashfunc: hash function for signatures (default sha1)
23
24
Returns:
25
SigningKey object
26
"""
27
28
@classmethod
29
def from_secret_exponent(cls, secexp, curve=NIST192p, hashfunc=sha1):
30
"""
31
Create SigningKey from integer secret exponent.
32
33
Parameters:
34
- secexp: int, secret exponent (private key value)
35
- curve: Curve object (default NIST192p)
36
- hashfunc: hash function for signatures (default sha1)
37
38
Returns:
39
SigningKey object
40
"""
41
42
@classmethod
43
def from_string(cls, string, curve=NIST192p, hashfunc=sha1):
44
"""
45
Create SigningKey from raw byte string.
46
47
Parameters:
48
- string: bytes, raw private key bytes
49
- curve: Curve object (default NIST192p)
50
- hashfunc: hash function for signatures (default sha1)
51
52
Returns:
53
SigningKey object
54
"""
55
56
@classmethod
57
def from_pem(cls, string, hashfunc=sha1, valid_curve_encodings=None):
58
"""
59
Create SigningKey from PEM-encoded private key.
60
61
Parameters:
62
- string: str or bytes, PEM-encoded private key
63
- hashfunc: hash function for signatures (default sha1)
64
- valid_curve_encodings: list of acceptable curve encodings or None
65
66
Returns:
67
SigningKey object
68
"""
69
70
@classmethod
71
def from_der(cls, string, hashfunc=sha1, valid_curve_encodings=None):
72
"""
73
Create SigningKey from DER-encoded private key.
74
75
Parameters:
76
- string: bytes, DER-encoded private key
77
- hashfunc: hash function for signatures (default sha1)
78
- valid_curve_encodings: list of acceptable curve encodings or None
79
80
Returns:
81
SigningKey object
82
"""
83
```
84
85
#### Signing Operations
86
87
```python { .api }
88
def sign(self, data, entropy=None, hashfunc=None, sigencode=sigencode_string, k=None, allow_truncate=True):
89
"""
90
Sign data using ECDSA/EdDSA.
91
92
Parameters:
93
- data: bytes, data to sign
94
- entropy: callable returning random bytes, or None for default
95
- hashfunc: hash function, or None for default
96
- sigencode: signature encoding function (default sigencode_string)
97
- k: int, specific k value for signature (for testing only)
98
- allow_truncate: bool, allow hash truncation for curve compatibility
99
100
Returns:
101
bytes, encoded signature
102
"""
103
104
def sign_deterministic(self, data, hashfunc=None, sigencode=sigencode_string, extra_entropy=b""):
105
"""
106
Sign data using RFC 6979 deterministic ECDSA.
107
108
Parameters:
109
- data: bytes, data to sign
110
- hashfunc: hash function, or None for default
111
- sigencode: signature encoding function (default sigencode_string)
112
- extra_entropy: bytes, additional entropy for deterministic generation
113
114
Returns:
115
bytes, encoded signature
116
"""
117
118
def sign_digest(self, digest, entropy=None, sigencode=sigencode_string, k=None, allow_truncate=False):
119
"""
120
Sign a pre-computed hash digest.
121
122
Parameters:
123
- digest: bytes, hash digest to sign
124
- entropy: callable returning random bytes, or None for default
125
- sigencode: signature encoding function (default sigencode_string)
126
- k: int, specific k value for signature (for testing only)
127
- allow_truncate: bool, allow hash truncation for curve compatibility
128
129
Returns:
130
bytes, encoded signature
131
"""
132
133
def sign_digest_deterministic(self, digest, hashfunc=None, sigencode=sigencode_string, extra_entropy=b"", allow_truncate=False):
134
"""
135
Sign a pre-computed hash digest using RFC 6979 deterministic ECDSA.
136
137
Parameters:
138
- digest: bytes, hash digest to sign
139
- hashfunc: hash function used to create digest (required for RFC 6979)
140
- sigencode: signature encoding function (default sigencode_string)
141
- extra_entropy: bytes, additional entropy for deterministic generation
142
- allow_truncate: bool, allow hash truncation for curve compatibility
143
144
Returns:
145
bytes, encoded signature
146
"""
147
148
def sign_number(self, number, entropy=None, k=None):
149
"""
150
Sign a number directly (low-level interface).
151
152
Parameters:
153
- number: int, number to sign
154
- entropy: callable returning random bytes, or None for default
155
- k: int, specific k value for signature (for testing only)
156
157
Returns:
158
tuple[int, int], (r, s) signature pair
159
"""
160
```
161
162
#### Key Access and Export
163
164
```python { .api }
165
def get_verifying_key(self):
166
"""
167
Get the corresponding public key.
168
169
Returns:
170
VerifyingKey object
171
"""
172
173
def to_string(self):
174
"""
175
Export private key as raw bytes.
176
177
Returns:
178
bytes, raw private key
179
"""
180
181
def to_pem(self, point_encoding="uncompressed", format="ssleay", curve_parameters_encoding=None):
182
"""
183
Export private key in PEM format.
184
185
Parameters:
186
- point_encoding: str, point encoding format ("uncompressed", "compressed", "hybrid")
187
- format: str, PEM format variant ("ssleay", "pkcs8")
188
- curve_parameters_encoding: str or None, curve parameter encoding
189
190
Returns:
191
bytes, PEM-encoded private key
192
"""
193
194
def to_der(self, point_encoding="uncompressed", format="ssleay", curve_parameters_encoding=None):
195
"""
196
Export private key in DER format.
197
198
Parameters:
199
- point_encoding: str, point encoding format ("uncompressed", "compressed", "hybrid")
200
- format: str, DER format variant ("ssleay", "pkcs8")
201
- curve_parameters_encoding: str or None, curve parameter encoding
202
203
Returns:
204
bytes, DER-encoded private key
205
"""
206
207
def to_ssh(self):
208
"""
209
Export private key in SSH format.
210
211
Returns:
212
bytes, SSH-encoded private key
213
"""
214
```
215
216
#### Key Attributes
217
218
```python { .api }
219
curve: Curve # The elliptic curve object
220
default_hashfunc: callable # Default hash function
221
baselen: int # Length of raw key encoding in bytes
222
verifying_key: VerifyingKey # Associated public key
223
```
224
225
### VerifyingKey Class
226
227
The VerifyingKey class represents a public key for verifying digital signatures created with ECDSA or EdDSA algorithms.
228
229
#### Key Loading and Creation
230
231
```python { .api }
232
class VerifyingKey:
233
@classmethod
234
def from_public_point(cls, point, curve=NIST192p, hashfunc=sha1, validate_point=True):
235
"""
236
Create VerifyingKey from elliptic curve point.
237
238
Parameters:
239
- point: Point object, public key point on curve
240
- curve: Curve object (default NIST192p)
241
- hashfunc: hash function for signatures (default sha1)
242
- validate_point: bool, validate point is on curve
243
244
Returns:
245
VerifyingKey object
246
"""
247
248
@classmethod
249
def from_string(cls, string, curve=NIST192p, hashfunc=sha1, validate_point=True, valid_encodings=None):
250
"""
251
Create VerifyingKey from raw byte string.
252
253
Parameters:
254
- string: bytes, raw public key bytes
255
- curve: Curve object (default NIST192p)
256
- hashfunc: hash function for signatures (default sha1)
257
- validate_point: bool, validate point is on curve
258
- valid_encodings: list of acceptable point encodings or None
259
260
Returns:
261
VerifyingKey object
262
"""
263
264
@classmethod
265
def from_pem(cls, string, hashfunc=sha1, valid_encodings=None, valid_curve_encodings=None):
266
"""
267
Create VerifyingKey from PEM-encoded public key.
268
269
Parameters:
270
- string: str or bytes, PEM-encoded public key
271
- hashfunc: hash function for signatures (default sha1)
272
- valid_encodings: list of acceptable point encodings or None
273
- valid_curve_encodings: list of acceptable curve encodings or None
274
275
Returns:
276
VerifyingKey object
277
"""
278
279
@classmethod
280
def from_der(cls, string, hashfunc=sha1, valid_encodings=None, valid_curve_encodings=None):
281
"""
282
Create VerifyingKey from DER-encoded public key.
283
284
Parameters:
285
- string: bytes, DER-encoded public key
286
- hashfunc: hash function for signatures (default sha1)
287
- valid_encodings: list of acceptable point encodings or None
288
- valid_curve_encodings: list of acceptable curve encodings or None
289
290
Returns:
291
VerifyingKey object
292
"""
293
294
@classmethod
295
def from_public_key_recovery(cls, signature, data, curve, hashfunc=sha1, sigdecode=sigdecode_string, allow_truncate=True):
296
"""
297
Recover public key(s) from signature and original data.
298
299
Parameters:
300
- signature: bytes, encoded signature
301
- data: bytes, original signed data
302
- curve: Curve object
303
- hashfunc: hash function used for signing (default sha1)
304
- sigdecode: signature decoding function (default sigdecode_string)
305
- allow_truncate: bool, allow hash truncation for curve compatibility
306
307
Returns:
308
list[VerifyingKey], possible public keys (usually 2 or 4 options)
309
"""
310
311
@classmethod
312
def from_public_key_recovery_with_digest(cls, signature, digest, curve, hashfunc=sha1, sigdecode=sigdecode_string, allow_truncate=False):
313
"""
314
Recover public key(s) from signature and pre-computed digest.
315
316
Parameters:
317
- signature: bytes, encoded signature
318
- digest: bytes, hash digest of original data
319
- curve: Curve object
320
- hashfunc: hash function used to create digest (default sha1)
321
- sigdecode: signature decoding function (default sigdecode_string)
322
- allow_truncate: bool, allow hash truncation for curve compatibility
323
324
Returns:
325
list[VerifyingKey], possible public keys (usually 2 or 4 options)
326
"""
327
```
328
329
#### Signature Verification
330
331
```python { .api }
332
def verify(self, signature, data, hashfunc=None, sigdecode=sigdecode_string, allow_truncate=True):
333
"""
334
Verify signature against data.
335
336
Parameters:
337
- signature: bytes, encoded signature to verify
338
- data: bytes, original data that was signed
339
- hashfunc: hash function, or None for default
340
- sigdecode: signature decoding function (default sigdecode_string)
341
- allow_truncate: bool, allow hash truncation for curve compatibility
342
343
Returns:
344
bool, True if signature is valid
345
346
Raises:
347
BadSignatureError: if signature is invalid
348
"""
349
350
def verify_digest(self, signature, digest, sigdecode=sigdecode_string, allow_truncate=False):
351
"""
352
Verify signature against pre-computed hash digest.
353
354
Parameters:
355
- signature: bytes, encoded signature to verify
356
- digest: bytes, hash digest of original data
357
- sigdecode: signature decoding function (default sigdecode_string)
358
- allow_truncate: bool, allow hash truncation for curve compatibility
359
360
Returns:
361
bool, True if signature is valid
362
363
Raises:
364
BadSignatureError: if signature is invalid
365
"""
366
```
367
368
#### Key Export and Optimization
369
370
```python { .api }
371
def precompute(self, lazy=False):
372
"""
373
Precompute values for faster signature verification.
374
375
Parameters:
376
- lazy: bool, compute values lazily on first use
377
"""
378
379
def to_string(self, encoding="raw"):
380
"""
381
Export public key as raw bytes.
382
383
Parameters:
384
- encoding: str, point encoding format ("raw", "uncompressed", "compressed", "hybrid")
385
386
Returns:
387
bytes, encoded public key
388
"""
389
390
def to_pem(self, point_encoding="uncompressed", curve_parameters_encoding=None):
391
"""
392
Export public key in PEM format.
393
394
Parameters:
395
- point_encoding: str, point encoding format ("uncompressed", "compressed", "hybrid")
396
- curve_parameters_encoding: str or None, curve parameter encoding
397
398
Returns:
399
bytes, PEM-encoded public key
400
"""
401
402
def to_der(self, point_encoding="uncompressed", curve_parameters_encoding=None):
403
"""
404
Export public key in DER format.
405
406
Parameters:
407
- point_encoding: str, point encoding format ("uncompressed", "compressed", "hybrid")
408
- curve_parameters_encoding: str or None, curve parameter encoding
409
410
Returns:
411
bytes, DER-encoded public key
412
"""
413
414
def to_ssh(self):
415
"""
416
Export public key in SSH format.
417
418
Returns:
419
bytes, SSH-encoded public key
420
"""
421
```
422
423
#### Key Attributes
424
425
```python { .api }
426
curve: Curve # The elliptic curve object
427
default_hashfunc: callable # Default hash function
428
pubkey: object # Internal public key object
429
```
430
431
## Exception Classes
432
433
```python { .api }
434
class BadSignatureError(Exception):
435
"""Raised when signature verification fails."""
436
437
class BadDigestError(Exception):
438
"""Raised when hash digest is too large for the curve."""
439
440
class MalformedPointError(Exception):
441
"""Raised when point encoding is invalid or point is not on curve."""
442
```
443
444
## Usage Examples
445
446
### Basic Key Generation and Signing
447
448
```python
449
from ecdsa import SigningKey, NIST256p
450
import hashlib
451
452
# Generate a new signing key
453
sk = SigningKey.generate(curve=NIST256p)
454
vk = sk.verifying_key
455
456
# Sign some data
457
message = b"Hello, cryptographic world!"
458
signature = sk.sign(message, hashfunc=hashlib.sha256)
459
460
# Verify the signature
461
try:
462
vk.verify(signature, message, hashfunc=hashlib.sha256)
463
print("Signature verified successfully!")
464
except BadSignatureError:
465
print("Signature verification failed!")
466
```
467
468
### Deterministic Signatures (RFC 6979)
469
470
```python
471
from ecdsa import SigningKey, NIST256p
472
import hashlib
473
474
sk = SigningKey.generate(curve=NIST256p)
475
message = b"Deterministic signing example"
476
477
# Create deterministic signature (same signature every time)
478
sig1 = sk.sign_deterministic(message, hashfunc=hashlib.sha256)
479
sig2 = sk.sign_deterministic(message, hashfunc=hashlib.sha256)
480
assert sig1 == sig2 # Signatures are identical
481
482
# Verify deterministic signature
483
vk = sk.verifying_key
484
vk.verify(sig1, message, hashfunc=hashlib.sha256)
485
```
486
487
### Key Serialization and Loading
488
489
```python
490
from ecdsa import SigningKey, VerifyingKey, NIST256p
491
492
# Generate key pair
493
sk = SigningKey.generate(curve=NIST256p)
494
vk = sk.verifying_key
495
496
# Export keys in various formats
497
private_pem = sk.to_pem()
498
public_pem = vk.to_pem()
499
private_der = sk.to_der()
500
public_der = vk.to_der()
501
502
# Load keys from serialized formats
503
loaded_sk = SigningKey.from_pem(private_pem)
504
loaded_vk = VerifyingKey.from_pem(public_pem)
505
loaded_sk_der = SigningKey.from_der(private_der)
506
loaded_vk_der = VerifyingKey.from_der(public_der)
507
508
# Verify they work the same
509
message = b"Test message"
510
original_sig = sk.sign(message)
511
loaded_sig = loaded_sk.sign(message)
512
513
# Both signatures should verify with both public keys
514
vk.verify(original_sig, message)
515
loaded_vk.verify(loaded_sig, message)
516
```
517
518
### Multiple Signature Encodings
519
520
```python
521
from ecdsa import SigningKey, NIST256p
522
from ecdsa.util import sigencode_der, sigdecode_der, sigencode_string, sigdecode_string
523
524
sk = SigningKey.generate(curve=NIST256p)
525
vk = sk.verifying_key
526
message = b"Encoding example"
527
528
# Sign with different encodings
529
sig_raw = sk.sign(message, sigencode=sigencode_string)
530
sig_der = sk.sign(message, sigencode=sigencode_der)
531
532
# Verify with corresponding decodings
533
vk.verify(sig_raw, message, sigdecode=sigdecode_string)
534
vk.verify(sig_der, message, sigdecode=sigdecode_der)
535
```