0
# EdDSA Digital Signatures
1
2
Edwards-curve Digital Signature Algorithm (EdDSA) implementation providing pure EdDSA signatures using Ed25519 and Ed448 curves. EdDSA offers deterministic signatures, resistance to side-channel attacks, and high performance compared to traditional ECDSA.
3
4
## Capabilities
5
6
### EdDSA Public Key
7
8
Public key class for EdDSA signature verification on Edwards curves.
9
10
```python { .api }
11
class PublicKey:
12
"""Public key for Edwards Digital Signature Algorithm."""
13
14
def __init__(self, generator, public_key, public_point=None):
15
"""
16
Create EdDSA public key.
17
18
Parameters:
19
- generator: PointEdwards, curve generator point
20
- public_key: bytes, encoded public key
21
- public_point: PointEdwards, optional pre-computed point
22
23
Raises:
24
ValueError: if public key length is incorrect
25
"""
26
27
def public_point(self):
28
"""
29
Get public key as Edwards curve point.
30
31
Returns:
32
PointEdwards, public key point on Edwards curve
33
"""
34
35
def public_key(self):
36
"""
37
Get encoded public key bytes.
38
39
Returns:
40
bytes, encoded public key
41
"""
42
43
def verify(self, data, signature):
44
"""
45
Verify EdDSA signature over data.
46
47
Parameters:
48
- data: bytes or str, data that was signed
49
- signature: bytes, EdDSA signature (R || S)
50
51
Returns:
52
bool, True if signature is valid
53
54
Raises:
55
ValueError: if signature length is incorrect
56
"""
57
```
58
59
### EdDSA Private Key
60
61
Private key class for EdDSA signature creation on Edwards curves.
62
63
```python { .api }
64
class PrivateKey:
65
"""Private key for Edwards Digital Signature Algorithm."""
66
67
def __init__(self, generator, private_key):
68
"""
69
Create EdDSA private key.
70
71
Parameters:
72
- generator: PointEdwards, curve generator point
73
- private_key: bytes, raw private key bytes
74
75
Raises:
76
ValueError: if private key length is incorrect
77
"""
78
79
def private_key(self):
80
"""
81
Get raw private key bytes.
82
83
Returns:
84
bytes, raw private key material
85
"""
86
87
def public_key(self):
88
"""
89
Generate corresponding public key.
90
91
Returns:
92
PublicKey, public key derived from this private key
93
"""
94
95
def sign(self, data):
96
"""
97
Create EdDSA signature over data.
98
99
Parameters:
100
- data: bytes or str, data to sign
101
102
Returns:
103
bytes, EdDSA signature (R || S format)
104
"""
105
```
106
107
### Edwards Curve Parameters
108
109
Pre-defined Edwards curve parameters for Ed25519 and Ed448 algorithms.
110
111
```python { .api }
112
# Ed25519 curve and generator (RFC 8032)
113
curve_ed25519: CurveEdTw # Edwards curve y² = -x² + 1 - (121665/121666)x²y²
114
generator_ed25519: PointEdwards # Base point for Ed25519
115
116
# Ed448 curve and generator (RFC 8032)
117
curve_ed448: CurveEdTw # Edwards curve x² + y² = 1 - 39081x²y²
118
generator_ed448: PointEdwards # Base point for Ed448
119
```
120
121
## Usage Examples
122
123
### Ed25519 Signature Operations
124
125
```python
126
from ecdsa.eddsa import PrivateKey, PublicKey, generator_ed25519
127
import os
128
129
# Generate Ed25519 private key (32 bytes for Ed25519)
130
private_key_bytes = os.urandom(32)
131
private_key = PrivateKey(generator_ed25519, private_key_bytes)
132
133
# Get corresponding public key
134
public_key = private_key.public_key()
135
136
print(f"Private key length: {len(private_key.private_key())} bytes")
137
print(f"Public key length: {len(public_key.public_key())} bytes")
138
139
# Sign some data
140
message = b"Hello, EdDSA world!"
141
signature = private_key.sign(message)
142
143
print(f"Signature length: {len(signature)} bytes")
144
print(f"Signature (hex): {signature.hex()}")
145
146
# Verify signature
147
is_valid = public_key.verify(message, signature)
148
print(f"Signature valid: {is_valid}")
149
150
# Test with modified message (should fail)
151
try:
152
modified_message = b"Hello, EdDSA world!!"
153
is_valid_modified = public_key.verify(modified_message, signature)
154
print(f"Modified message signature valid: {is_valid_modified}")
155
except:
156
print("Signature verification failed for modified message")
157
```
158
159
### Ed448 Signature Operations
160
161
```python
162
from ecdsa.eddsa import PrivateKey, PublicKey, generator_ed448
163
import os
164
165
# Generate Ed448 private key (57 bytes for Ed448)
166
private_key_bytes = os.urandom(57)
167
private_key = PrivateKey(generator_ed448, private_key_bytes)
168
169
# Get corresponding public key
170
public_key = private_key.public_key()
171
172
print(f"Ed448 private key length: {len(private_key.private_key())} bytes")
173
print(f"Ed448 public key length: {len(public_key.public_key())} bytes")
174
175
# Sign data with Ed448
176
message = b"Ed448 provides higher security level"
177
signature = private_key.sign(message)
178
179
print(f"Ed448 signature length: {len(signature)} bytes")
180
print(f"Ed448 signature (hex): {signature.hex()}")
181
182
# Verify Ed448 signature
183
is_valid = public_key.verify(message, signature)
184
print(f"Ed448 signature valid: {is_valid}")
185
```
186
187
### Deterministic Signatures Demonstration
188
189
```python
190
from ecdsa.eddsa import PrivateKey, generator_ed25519
191
import os
192
193
# EdDSA signatures are deterministic - same message produces same signature
194
private_key_bytes = os.urandom(32)
195
private_key = PrivateKey(generator_ed25519, private_key_bytes)
196
197
message = b"Deterministic signature test"
198
199
# Sign the same message multiple times
200
sig1 = private_key.sign(message)
201
sig2 = private_key.sign(message)
202
sig3 = private_key.sign(message)
203
204
print(f"Signature 1: {sig1.hex()[:32]}...")
205
print(f"Signature 2: {sig2.hex()[:32]}...")
206
print(f"Signature 3: {sig3.hex()[:32]}...")
207
208
print(f"All signatures identical: {sig1 == sig2 == sig3}")
209
210
# Different messages produce different signatures
211
message2 = b"Different message"
212
sig_different = private_key.sign(message2)
213
print(f"Different message signature: {sig_different.hex()[:32]}...")
214
print(f"Signatures different: {sig1 != sig_different}")
215
```
216
217
### Working with Edwards Curve Points
218
219
```python
220
from ecdsa.eddsa import PrivateKey, generator_ed25519
221
from ecdsa.ellipticcurve import PointEdwards
222
import os
223
224
# Create private key and examine the underlying mathematics
225
private_key_bytes = os.urandom(32)
226
private_key = PrivateKey(generator_ed25519, private_key_bytes)
227
public_key = private_key.public_key()
228
229
# Get the public key point
230
public_point = public_key.public_point()
231
232
print(f"Public key point type: {type(public_point)}")
233
print(f"Point x coordinate: {public_point.x()}")
234
print(f"Point y coordinate: {public_point.y()}")
235
236
# Verify point is on the Edwards curve
237
curve = generator_ed25519.curve()
238
x, y = public_point.x(), public_point.y()
239
on_curve = curve.contains_point(x, y)
240
print(f"Public key point is on curve: {on_curve}")
241
242
# Demonstrate point arithmetic on Edwards curves
243
generator = generator_ed25519
244
scalar = 12345
245
result_point = scalar * generator
246
247
print(f"Scalar multiplication result: ({result_point.x()}, {result_point.y()})")
248
print(f"Result point on curve: {curve.contains_point(result_point.x(), result_point.y())}")
249
```
250
251
### Performance Comparison with ECDSA
252
253
```python
254
from ecdsa import SigningKey, NIST256p
255
from ecdsa.eddsa import PrivateKey, generator_ed25519
256
import time
257
import os
258
259
# Create ECDSA key (for comparison)
260
ecdsa_key = SigningKey.generate(curve=NIST256p)
261
262
# Create EdDSA key
263
eddsa_private_bytes = os.urandom(32)
264
eddsa_key = PrivateKey(generator_ed25519, eddsa_private_bytes)
265
266
message = b"Performance test message" * 10 # 250 bytes
267
268
# Time ECDSA signing
269
start_time = time.time()
270
for _ in range(100):
271
ecdsa_sig = ecdsa_key.sign(message)
272
ecdsa_sign_time = time.time() - start_time
273
274
# Time EdDSA signing
275
start_time = time.time()
276
for _ in range(100):
277
eddsa_sig = eddsa_key.sign(message)
278
eddsa_sign_time = time.time() - start_time
279
280
print(f"ECDSA signing (100 iterations): {ecdsa_sign_time:.4f} seconds")
281
print(f"EdDSA signing (100 iterations): {eddsa_sign_time:.4f} seconds")
282
print(f"EdDSA speedup: {ecdsa_sign_time / eddsa_sign_time:.2f}x")
283
284
# Time verification
285
ecdsa_vk = ecdsa_key.verifying_key
286
eddsa_pk = eddsa_key.public_key()
287
288
start_time = time.time()
289
for _ in range(100):
290
ecdsa_vk.verify(ecdsa_sig, message)
291
ecdsa_verify_time = time.time() - start_time
292
293
start_time = time.time()
294
for _ in range(100):
295
eddsa_pk.verify(message, eddsa_sig)
296
eddsa_verify_time = time.time() - start_time
297
298
print(f"ECDSA verification (100 iterations): {ecdsa_verify_time:.4f} seconds")
299
print(f"EdDSA verification (100 iterations): {eddsa_verify_time:.4f} seconds")
300
print(f"EdDSA verification speedup: {ecdsa_verify_time / eddsa_verify_time:.2f}x")
301
```
302
303
### EdDSA Key Storage and Serialization
304
305
```python
306
from ecdsa.eddsa import PrivateKey, PublicKey, generator_ed25519
307
import os
308
import json
309
import base64
310
311
# Generate key pair
312
private_key_bytes = os.urandom(32)
313
private_key = PrivateKey(generator_ed25519, private_key_bytes)
314
public_key = private_key.public_key()
315
316
# Serialize keys for storage
317
private_key_b64 = base64.b64encode(private_key.private_key()).decode('ascii')
318
public_key_b64 = base64.b64encode(public_key.public_key()).decode('ascii')
319
320
# Create key storage format
321
key_data = {
322
"algorithm": "Ed25519",
323
"private_key": private_key_b64,
324
"public_key": public_key_b64
325
}
326
327
print("Serialized key data:")
328
print(json.dumps(key_data, indent=2))
329
330
# Deserialize keys
331
loaded_private_bytes = base64.b64decode(key_data["private_key"])
332
loaded_public_bytes = base64.b64decode(key_data["public_key"])
333
334
# Reconstruct keys
335
loaded_private_key = PrivateKey(generator_ed25519, loaded_private_bytes)
336
loaded_public_key = PublicKey(generator_ed25519, loaded_public_bytes)
337
338
# Verify keys work correctly
339
test_message = b"Key serialization test"
340
signature = loaded_private_key.sign(test_message)
341
is_valid = loaded_public_key.verify(test_message, signature)
342
343
print(f"Loaded keys work correctly: {is_valid}")
344
print(f"Original and loaded private keys match: {private_key == loaded_private_key}")
345
print(f"Original and loaded public keys match: {public_key == loaded_public_key}")
346
```
347
348
### EdDSA Security Properties
349
350
```python
351
from ecdsa.eddsa import PrivateKey, generator_ed25519, generator_ed448
352
import os
353
354
# Demonstrate EdDSA security properties
355
print("EdDSA Security Properties:")
356
print("=" * 40)
357
358
# 1. Deterministic signatures (no randomness during signing)
359
private_key = PrivateKey(generator_ed25519, os.urandom(32))
360
message = b"Security test message"
361
362
sig1 = private_key.sign(message)
363
sig2 = private_key.sign(message)
364
print(f"1. Deterministic signatures: {sig1 == sig2}")
365
366
# 2. Context separation (different private keys, same message)
367
private_key2 = PrivateKey(generator_ed25519, os.urandom(32))
368
sig_different_key = private_key2.sign(message)
369
print(f"2. Different keys produce different signatures: {sig1 != sig_different_key}")
370
371
# 3. Ed25519 vs Ed448 security levels
372
ed25519_key = PrivateKey(generator_ed25519, os.urandom(32))
373
ed448_key = PrivateKey(generator_ed448, os.urandom(57))
374
375
ed25519_sig = ed25519_key.sign(message)
376
ed448_sig = ed448_key.sign(message)
377
378
print(f"3. Ed25519 signature length: {len(ed25519_sig)} bytes")
379
print(f" Ed448 signature length: {len(ed448_sig)} bytes")
380
print(f" Ed25519 security level: ~128 bits")
381
print(f" Ed448 security level: ~224 bits")
382
383
# 4. Signature malleability resistance
384
print("4. EdDSA signatures are not malleable (unlike some ECDSA implementations)")
385
386
# 5. Side-channel resistance
387
print("5. EdDSA is designed to be resistant to timing attacks")
388
print(" - No secret branches in the signing algorithm")
389
print(" - No secret array indices")
390
print(" - No secret memory access patterns")
391
```
392
393
## Algorithm Details
394
395
EdDSA provides several security and performance advantages over ECDSA:
396
397
### Security Benefits
398
399
1. **Deterministic Signatures**: No random number generation during signing eliminates the risk of nonce reuse attacks
400
2. **Malleability Resistance**: EdDSA signatures cannot be modified while remaining valid
401
3. **Side-Channel Resistance**: Designed to resist timing attacks and other side-channel attacks
402
4. **Complete Addition Formulas**: Edwards curves use complete addition formulas that work for all points
403
404
### Performance Benefits
405
406
1. **Faster Verification**: Edwards curve arithmetic is generally faster than Weierstrass curves
407
2. **Batch Verification**: Multiple signatures can be verified together more efficiently
408
3. **Smaller Signatures**: Ed25519 signatures are 64 bytes vs. 64-72 bytes for ECDSA on P-256
409
410
### Curve Properties
411
412
- **Ed25519**: Based on Curve25519, ~128-bit security level, 32-byte keys, 64-byte signatures
413
- **Ed448**: Based on Curve448, ~224-bit security level, 57-byte keys, 114-byte signatures