1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import annotations
6
7import abc
8
9from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
10from cryptography.hazmat.bindings._rust import openssl as rust_openssl
11from cryptography.hazmat.primitives import _serialization
12from cryptography.utils import Buffer
13
14
15class MLDSA44PublicKey(metaclass=abc.ABCMeta):
16 @classmethod
17 def from_public_bytes(cls, data: bytes) -> MLDSA44PublicKey:
18 from cryptography.hazmat.backends.openssl.backend import backend
19
20 if not backend.mldsa_supported():
21 raise UnsupportedAlgorithm(
22 "ML-DSA-44 is not supported by this backend.",
23 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
24 )
25
26 return rust_openssl.mldsa.from_mldsa44_public_bytes(data)
27
28 @abc.abstractmethod
29 def public_bytes(
30 self,
31 encoding: _serialization.Encoding,
32 format: _serialization.PublicFormat,
33 ) -> bytes:
34 """
35 The serialized bytes of the public key.
36 """
37
38 @abc.abstractmethod
39 def public_bytes_raw(self) -> bytes:
40 """
41 The raw bytes of the public key.
42 Equivalent to public_bytes(Raw, Raw).
43
44 The public key is 1,312 bytes for MLDSA-44.
45 """
46
47 @abc.abstractmethod
48 def verify(
49 self,
50 signature: Buffer,
51 data: Buffer,
52 context: Buffer | None = None,
53 ) -> None:
54 """
55 Verify the signature.
56 """
57
58 @abc.abstractmethod
59 def __eq__(self, other: object) -> bool:
60 """
61 Checks equality.
62 """
63
64 @abc.abstractmethod
65 def __copy__(self) -> MLDSA44PublicKey:
66 """
67 Returns a copy.
68 """
69
70 @abc.abstractmethod
71 def __deepcopy__(self, memo: dict) -> MLDSA44PublicKey:
72 """
73 Returns a deep copy.
74 """
75
76
77if hasattr(rust_openssl, "mldsa"):
78 MLDSA44PublicKey.register(rust_openssl.mldsa.MLDSA44PublicKey)
79
80
81class MLDSA44PrivateKey(metaclass=abc.ABCMeta):
82 @classmethod
83 def generate(cls) -> MLDSA44PrivateKey:
84 from cryptography.hazmat.backends.openssl.backend import backend
85
86 if not backend.mldsa_supported():
87 raise UnsupportedAlgorithm(
88 "ML-DSA-44 is not supported by this backend.",
89 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
90 )
91
92 return rust_openssl.mldsa.generate_mldsa44_key()
93
94 @classmethod
95 def from_seed_bytes(cls, data: Buffer) -> MLDSA44PrivateKey:
96 from cryptography.hazmat.backends.openssl.backend import backend
97
98 if not backend.mldsa_supported():
99 raise UnsupportedAlgorithm(
100 "ML-DSA-44 is not supported by this backend.",
101 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
102 )
103
104 return rust_openssl.mldsa.from_mldsa44_seed_bytes(data)
105
106 @abc.abstractmethod
107 def public_key(self) -> MLDSA44PublicKey:
108 """
109 The MLDSA44PublicKey derived from the private key.
110 """
111
112 @abc.abstractmethod
113 def private_bytes(
114 self,
115 encoding: _serialization.Encoding,
116 format: _serialization.PrivateFormat,
117 encryption_algorithm: _serialization.KeySerializationEncryption,
118 ) -> bytes:
119 """
120 The serialized bytes of the private key.
121
122 This method only returns the serialization of the seed form of the
123 private key, never the expanded one.
124 """
125
126 @abc.abstractmethod
127 def private_bytes_raw(self) -> bytes:
128 """
129 The raw bytes of the private key.
130 Equivalent to private_bytes(Raw, Raw, NoEncryption()).
131
132 This method only returns the seed form of the private key (32 bytes).
133 """
134
135 @abc.abstractmethod
136 def sign(self, data: Buffer, context: Buffer | None = None) -> bytes:
137 """
138 Signs the data.
139 """
140
141 @abc.abstractmethod
142 def __copy__(self) -> MLDSA44PrivateKey:
143 """
144 Returns a copy.
145 """
146
147 @abc.abstractmethod
148 def __deepcopy__(self, memo: dict) -> MLDSA44PrivateKey:
149 """
150 Returns a deep copy.
151 """
152
153
154if hasattr(rust_openssl, "mldsa"):
155 MLDSA44PrivateKey.register(rust_openssl.mldsa.MLDSA44PrivateKey)
156
157
158class MLDSA65PublicKey(metaclass=abc.ABCMeta):
159 @classmethod
160 def from_public_bytes(cls, data: bytes) -> MLDSA65PublicKey:
161 from cryptography.hazmat.backends.openssl.backend import backend
162
163 if not backend.mldsa_supported():
164 raise UnsupportedAlgorithm(
165 "ML-DSA-65 is not supported by this backend.",
166 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
167 )
168
169 return rust_openssl.mldsa.from_mldsa65_public_bytes(data)
170
171 @abc.abstractmethod
172 def public_bytes(
173 self,
174 encoding: _serialization.Encoding,
175 format: _serialization.PublicFormat,
176 ) -> bytes:
177 """
178 The serialized bytes of the public key.
179 """
180
181 @abc.abstractmethod
182 def public_bytes_raw(self) -> bytes:
183 """
184 The raw bytes of the public key.
185 Equivalent to public_bytes(Raw, Raw).
186
187 The public key is 1,952 bytes for MLDSA-65.
188 """
189
190 @abc.abstractmethod
191 def verify(
192 self,
193 signature: Buffer,
194 data: Buffer,
195 context: Buffer | None = None,
196 ) -> None:
197 """
198 Verify the signature.
199 """
200
201 @abc.abstractmethod
202 def __eq__(self, other: object) -> bool:
203 """
204 Checks equality.
205 """
206
207 @abc.abstractmethod
208 def __copy__(self) -> MLDSA65PublicKey:
209 """
210 Returns a copy.
211 """
212
213 @abc.abstractmethod
214 def __deepcopy__(self, memo: dict) -> MLDSA65PublicKey:
215 """
216 Returns a deep copy.
217 """
218
219
220if hasattr(rust_openssl, "mldsa"):
221 MLDSA65PublicKey.register(rust_openssl.mldsa.MLDSA65PublicKey)
222
223
224class MLDSA65PrivateKey(metaclass=abc.ABCMeta):
225 @classmethod
226 def generate(cls) -> MLDSA65PrivateKey:
227 from cryptography.hazmat.backends.openssl.backend import backend
228
229 if not backend.mldsa_supported():
230 raise UnsupportedAlgorithm(
231 "ML-DSA-65 is not supported by this backend.",
232 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
233 )
234
235 return rust_openssl.mldsa.generate_mldsa65_key()
236
237 @classmethod
238 def from_seed_bytes(cls, data: Buffer) -> MLDSA65PrivateKey:
239 from cryptography.hazmat.backends.openssl.backend import backend
240
241 if not backend.mldsa_supported():
242 raise UnsupportedAlgorithm(
243 "ML-DSA-65 is not supported by this backend.",
244 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
245 )
246
247 return rust_openssl.mldsa.from_mldsa65_seed_bytes(data)
248
249 @abc.abstractmethod
250 def public_key(self) -> MLDSA65PublicKey:
251 """
252 The MLDSA65PublicKey derived from the private key.
253 """
254
255 @abc.abstractmethod
256 def private_bytes(
257 self,
258 encoding: _serialization.Encoding,
259 format: _serialization.PrivateFormat,
260 encryption_algorithm: _serialization.KeySerializationEncryption,
261 ) -> bytes:
262 """
263 The serialized bytes of the private key.
264
265 This method only returns the serialization of the seed form of the
266 private key, never the expanded one.
267 """
268
269 @abc.abstractmethod
270 def private_bytes_raw(self) -> bytes:
271 """
272 The raw bytes of the private key.
273 Equivalent to private_bytes(Raw, Raw, NoEncryption()).
274
275 This method only returns the seed form of the private key (32 bytes).
276 """
277
278 @abc.abstractmethod
279 def sign(self, data: Buffer, context: Buffer | None = None) -> bytes:
280 """
281 Signs the data.
282 """
283
284 @abc.abstractmethod
285 def __copy__(self) -> MLDSA65PrivateKey:
286 """
287 Returns a copy.
288 """
289
290 @abc.abstractmethod
291 def __deepcopy__(self, memo: dict) -> MLDSA65PrivateKey:
292 """
293 Returns a deep copy.
294 """
295
296
297if hasattr(rust_openssl, "mldsa"):
298 MLDSA65PrivateKey.register(rust_openssl.mldsa.MLDSA65PrivateKey)
299
300
301class MLDSA87PublicKey(metaclass=abc.ABCMeta):
302 @classmethod
303 def from_public_bytes(cls, data: bytes) -> MLDSA87PublicKey:
304 from cryptography.hazmat.backends.openssl.backend import backend
305
306 if not backend.mldsa_supported():
307 raise UnsupportedAlgorithm(
308 "ML-DSA-87 is not supported by this backend.",
309 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
310 )
311
312 return rust_openssl.mldsa.from_mldsa87_public_bytes(data)
313
314 @abc.abstractmethod
315 def public_bytes(
316 self,
317 encoding: _serialization.Encoding,
318 format: _serialization.PublicFormat,
319 ) -> bytes:
320 """
321 The serialized bytes of the public key.
322 """
323
324 @abc.abstractmethod
325 def public_bytes_raw(self) -> bytes:
326 """
327 The raw bytes of the public key.
328 Equivalent to public_bytes(Raw, Raw).
329
330 The public key is 2,592 bytes for MLDSA-87.
331 """
332
333 @abc.abstractmethod
334 def verify(
335 self,
336 signature: Buffer,
337 data: Buffer,
338 context: Buffer | None = None,
339 ) -> None:
340 """
341 Verify the signature.
342 """
343
344 @abc.abstractmethod
345 def __eq__(self, other: object) -> bool:
346 """
347 Checks equality.
348 """
349
350 @abc.abstractmethod
351 def __copy__(self) -> MLDSA87PublicKey:
352 """
353 Returns a copy.
354 """
355
356 @abc.abstractmethod
357 def __deepcopy__(self, memo: dict) -> MLDSA87PublicKey:
358 """
359 Returns a deep copy.
360 """
361
362
363if hasattr(rust_openssl, "mldsa"):
364 MLDSA87PublicKey.register(rust_openssl.mldsa.MLDSA87PublicKey)
365
366
367class MLDSA87PrivateKey(metaclass=abc.ABCMeta):
368 @classmethod
369 def generate(cls) -> MLDSA87PrivateKey:
370 from cryptography.hazmat.backends.openssl.backend import backend
371
372 if not backend.mldsa_supported():
373 raise UnsupportedAlgorithm(
374 "ML-DSA-87 is not supported by this backend.",
375 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
376 )
377
378 return rust_openssl.mldsa.generate_mldsa87_key()
379
380 @classmethod
381 def from_seed_bytes(cls, data: Buffer) -> MLDSA87PrivateKey:
382 from cryptography.hazmat.backends.openssl.backend import backend
383
384 if not backend.mldsa_supported():
385 raise UnsupportedAlgorithm(
386 "ML-DSA-87 is not supported by this backend.",
387 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
388 )
389
390 return rust_openssl.mldsa.from_mldsa87_seed_bytes(data)
391
392 @abc.abstractmethod
393 def public_key(self) -> MLDSA87PublicKey:
394 """
395 The MLDSA87PublicKey derived from the private key.
396 """
397
398 @abc.abstractmethod
399 def private_bytes(
400 self,
401 encoding: _serialization.Encoding,
402 format: _serialization.PrivateFormat,
403 encryption_algorithm: _serialization.KeySerializationEncryption,
404 ) -> bytes:
405 """
406 The serialized bytes of the private key.
407
408 This method only returns the serialization of the seed form of the
409 private key, never the expanded one.
410 """
411
412 @abc.abstractmethod
413 def private_bytes_raw(self) -> bytes:
414 """
415 The raw bytes of the private key.
416 Equivalent to private_bytes(Raw, Raw, NoEncryption()).
417
418 This method only returns the seed form of the private key (32 bytes).
419 """
420
421 @abc.abstractmethod
422 def sign(self, data: Buffer, context: Buffer | None = None) -> bytes:
423 """
424 Signs the data.
425 """
426
427 @abc.abstractmethod
428 def __copy__(self) -> MLDSA87PrivateKey:
429 """
430 Returns a copy.
431 """
432
433 @abc.abstractmethod
434 def __deepcopy__(self, memo: dict) -> MLDSA87PrivateKey:
435 """
436 Returns a deep copy.
437 """
438
439
440if hasattr(rust_openssl, "mldsa"):
441 MLDSA87PrivateKey.register(rust_openssl.mldsa.MLDSA87PrivateKey)