transcrypto 1.6.0__py3-none-any.whl → 1.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- transcrypto/__init__.py +7 -0
- transcrypto/aes.py +150 -44
- transcrypto/base.py +384 -520
- transcrypto/cli/__init__.py +3 -0
- transcrypto/cli/aeshash.py +368 -0
- transcrypto/cli/bidsecret.py +334 -0
- transcrypto/cli/clibase.py +303 -0
- transcrypto/cli/intmath.py +427 -0
- transcrypto/cli/publicalgos.py +877 -0
- transcrypto/constants.py +20070 -1906
- transcrypto/dsa.py +132 -99
- transcrypto/elgamal.py +116 -84
- transcrypto/modmath.py +88 -78
- transcrypto/profiler.py +228 -175
- transcrypto/rsa.py +126 -90
- transcrypto/sss.py +122 -70
- transcrypto/transcrypto.py +419 -1423
- {transcrypto-1.6.0.dist-info → transcrypto-1.8.0.dist-info}/METADATA +88 -66
- transcrypto-1.8.0.dist-info/RECORD +23 -0
- {transcrypto-1.6.0.dist-info → transcrypto-1.8.0.dist-info}/WHEEL +1 -2
- transcrypto-1.8.0.dist-info/entry_points.txt +4 -0
- transcrypto/safetrans.py +0 -1228
- transcrypto-1.6.0.dist-info/RECORD +0 -18
- transcrypto-1.6.0.dist-info/top_level.txt +0 -1
- {transcrypto-1.6.0.dist-info → transcrypto-1.8.0.dist-info}/licenses/LICENSE +0 -0
transcrypto/sss.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
#
|
|
3
|
-
# Copyright 2025 Daniel Balparda (balparda@github.com) - Apache-2.0 license
|
|
4
|
-
#
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright 2026 Daniel Balparda <balparda@github.com>
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
5
3
|
"""Balparda's TransCrypto Shamir Shared Secret (SSS) library.
|
|
6
4
|
|
|
7
5
|
<https://en.wikipedia.org/wiki/Shamir's_secret_sharing>
|
|
@@ -11,15 +9,10 @@ from __future__ import annotations
|
|
|
11
9
|
|
|
12
10
|
import dataclasses
|
|
13
11
|
import logging
|
|
14
|
-
|
|
15
|
-
from typing import
|
|
16
|
-
|
|
17
|
-
from . import base, modmath, aes
|
|
18
|
-
|
|
19
|
-
__author__ = 'balparda@github.com'
|
|
20
|
-
__version__: str = base.__version__ # version comes from base!
|
|
21
|
-
__version_tuple__: tuple[int, ...] = base.__version_tuple__
|
|
12
|
+
from collections import abc
|
|
13
|
+
from typing import Self
|
|
22
14
|
|
|
15
|
+
from . import aes, base, modmath
|
|
23
16
|
|
|
24
17
|
# fixed prefixes: do NOT ever change! will break all encryption and signature schemes
|
|
25
18
|
_SSS_ENCRYPTION_AAD_PREFIX = b'transcrypto.SSS.Sharing.1.0\x00'
|
|
@@ -35,6 +28,7 @@ class ShamirSharedSecretPublic(base.CryptoKey):
|
|
|
35
28
|
Attributes:
|
|
36
29
|
minimum (int): minimum shares needed for recovery, ≥ 2
|
|
37
30
|
modulus (int): prime modulus used for share generation, prime, ≥ 2
|
|
31
|
+
|
|
38
32
|
"""
|
|
39
33
|
|
|
40
34
|
minimum: int
|
|
@@ -45,11 +39,9 @@ class ShamirSharedSecretPublic(base.CryptoKey):
|
|
|
45
39
|
|
|
46
40
|
Raises:
|
|
47
41
|
InputError: invalid inputs
|
|
42
|
+
|
|
48
43
|
"""
|
|
49
|
-
|
|
50
|
-
if (self.modulus < 2 or
|
|
51
|
-
not modmath.IsPrime(self.modulus) or
|
|
52
|
-
self.minimum < 2):
|
|
44
|
+
if self.modulus < 2 or not modmath.IsPrime(self.modulus) or self.minimum < 2: # noqa: PLR2004
|
|
53
45
|
raise base.InputError(f'invalid modulus or minimum: {self}')
|
|
54
46
|
|
|
55
47
|
def __str__(self) -> str:
|
|
@@ -57,11 +49,14 @@ class ShamirSharedSecretPublic(base.CryptoKey):
|
|
|
57
49
|
|
|
58
50
|
Returns:
|
|
59
51
|
string representation of ShamirSharedSecretPublic
|
|
52
|
+
|
|
60
53
|
"""
|
|
61
|
-
return (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
return (
|
|
55
|
+
'ShamirSharedSecretPublic('
|
|
56
|
+
f'bits={self.modulus.bit_length()}, '
|
|
57
|
+
f'minimum={self.minimum}, '
|
|
58
|
+
f'modulus={base.IntToEncoded(self.modulus)})'
|
|
59
|
+
)
|
|
65
60
|
|
|
66
61
|
@property
|
|
67
62
|
def modulus_size(self) -> int:
|
|
@@ -69,7 +64,8 @@ class ShamirSharedSecretPublic(base.CryptoKey):
|
|
|
69
64
|
return (self.modulus.bit_length() + 7) // 8
|
|
70
65
|
|
|
71
66
|
def RawRecoverSecret(
|
|
72
|
-
|
|
67
|
+
self, shares: abc.Collection[ShamirSharePrivate], /, *, force_recover: bool = False
|
|
68
|
+
) -> int:
|
|
73
69
|
"""Recover the secret from ShamirSharePrivate objects.
|
|
74
70
|
|
|
75
71
|
BEWARE: This is raw SSS, no modern message wrapping, padding or validation!
|
|
@@ -88,6 +84,7 @@ class ShamirSharedSecretPublic(base.CryptoKey):
|
|
|
88
84
|
Raises:
|
|
89
85
|
InputError: invalid inputs
|
|
90
86
|
CryptoError: secret cannot be recovered (number of shares < `minimum`)
|
|
87
|
+
|
|
91
88
|
"""
|
|
92
89
|
# check that we have enough shares by de-duping them first
|
|
93
90
|
share_points: dict[int, int] = {}
|
|
@@ -98,7 +95,8 @@ class ShamirSharedSecretPublic(base.CryptoKey):
|
|
|
98
95
|
if k in share_points:
|
|
99
96
|
if v != share_points[k]:
|
|
100
97
|
raise base.InputError(
|
|
101
|
-
|
|
98
|
+
f'{share} key/value {k}/{v} duplicated with conflicting value in {share_dict[k]}'
|
|
99
|
+
)
|
|
102
100
|
logging.warning(f'{share} key/value {k}/{v} is a duplicate of {share_dict[k]}: DISCARDED')
|
|
103
101
|
continue
|
|
104
102
|
share_points[k] = v
|
|
@@ -115,7 +113,15 @@ class ShamirSharedSecretPublic(base.CryptoKey):
|
|
|
115
113
|
|
|
116
114
|
@classmethod
|
|
117
115
|
def Copy(cls, other: ShamirSharedSecretPublic, /) -> Self:
|
|
118
|
-
"""Initialize a public key by taking the public parts of a public/private key.
|
|
116
|
+
"""Initialize a public key by taking the public parts of a public/private key.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
other (ShamirSharedSecretPublic): object to copy from
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Self: a new ShamirSharedSecretPublic
|
|
123
|
+
|
|
124
|
+
"""
|
|
119
125
|
return cls(minimum=other.minimum, modulus=other.modulus)
|
|
120
126
|
|
|
121
127
|
|
|
@@ -132,6 +138,7 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
132
138
|
|
|
133
139
|
Attributes:
|
|
134
140
|
polynomial (list[int]): prime coefficients for generation poly., each modulus.bit_length() size
|
|
141
|
+
|
|
135
142
|
"""
|
|
136
143
|
|
|
137
144
|
polynomial: list[int]
|
|
@@ -141,13 +148,18 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
141
148
|
|
|
142
149
|
Raises:
|
|
143
150
|
InputError: invalid inputs
|
|
151
|
+
|
|
144
152
|
"""
|
|
145
|
-
super(ShamirSharedSecretPrivate, self).__post_init__()
|
|
146
|
-
if (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
153
|
+
super(ShamirSharedSecretPrivate, self).__post_init__()
|
|
154
|
+
if (
|
|
155
|
+
len(self.polynomial) != self.minimum - 1 # exactly this size
|
|
156
|
+
or len(set(self.polynomial)) != self.minimum - 1 # no duplicate
|
|
157
|
+
or self.modulus in self.polynomial # different from modulus
|
|
158
|
+
or any(
|
|
159
|
+
not modmath.IsPrime(p) or p.bit_length() != self.modulus.bit_length()
|
|
160
|
+
for p in self.polynomial
|
|
161
|
+
)
|
|
162
|
+
): # all primes and the right size
|
|
151
163
|
raise base.InputError(f'invalid polynomial: {self}')
|
|
152
164
|
|
|
153
165
|
def __str__(self) -> str:
|
|
@@ -155,10 +167,13 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
155
167
|
|
|
156
168
|
Returns:
|
|
157
169
|
string representation of ShamirSharedSecretPrivate without leaking secrets
|
|
170
|
+
|
|
158
171
|
"""
|
|
159
|
-
return (
|
|
160
|
-
|
|
161
|
-
|
|
172
|
+
return (
|
|
173
|
+
'ShamirSharedSecretPrivate('
|
|
174
|
+
f'{super(ShamirSharedSecretPrivate, self).__str__()}, '
|
|
175
|
+
f'polynomial=[{", ".join(base.ObfuscateSecret(i) for i in self.polynomial)}])'
|
|
176
|
+
)
|
|
162
177
|
|
|
163
178
|
def RawShare(self, secret: int, /, *, share_key: int = 0) -> ShamirSharePrivate:
|
|
164
179
|
"""Make a new ShamirSharePrivate for the `secret`.
|
|
@@ -178,6 +193,7 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
178
193
|
|
|
179
194
|
Raises:
|
|
180
195
|
InputError: invalid inputs
|
|
196
|
+
|
|
181
197
|
"""
|
|
182
198
|
# test inputs
|
|
183
199
|
if not 0 <= secret < self.modulus:
|
|
@@ -185,18 +201,19 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
185
201
|
if not 1 <= share_key < self.modulus:
|
|
186
202
|
if not share_key: # default is zero, and that means we generate it here
|
|
187
203
|
share_key = 0
|
|
188
|
-
while not share_key or share_key in self.polynomial:
|
|
204
|
+
while not share_key or share_key in self.polynomial or share_key >= self.modulus:
|
|
189
205
|
share_key = base.RandBits(self.modulus.bit_length() - 1)
|
|
190
206
|
else:
|
|
191
207
|
raise base.InputError(f'invalid share_key: {share_key=}')
|
|
192
208
|
# build object
|
|
193
209
|
return ShamirSharePrivate(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
210
|
+
minimum=self.minimum,
|
|
211
|
+
modulus=self.modulus,
|
|
212
|
+
share_key=share_key,
|
|
213
|
+
share_value=modmath.ModPolynomial(share_key, [secret, *self.polynomial], self.modulus),
|
|
214
|
+
)
|
|
197
215
|
|
|
198
|
-
def RawShares(
|
|
199
|
-
self, secret: int, /, *, max_shares: int = 0) -> Generator[ShamirSharePrivate, None, None]:
|
|
216
|
+
def RawShares(self, secret: int, /, *, max_shares: int = 0) -> abc.Generator[ShamirSharePrivate]:
|
|
200
217
|
"""Make any number of ShamirSharePrivate for the `secret`.
|
|
201
218
|
|
|
202
219
|
BEWARE: This is raw SSS, no modern message wrapping, padding or validation!
|
|
@@ -213,6 +230,7 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
213
230
|
|
|
214
231
|
Raises:
|
|
215
232
|
InputError: invalid inputs
|
|
233
|
+
|
|
216
234
|
"""
|
|
217
235
|
# test inputs
|
|
218
236
|
if max_shares and max_shares < self.minimum:
|
|
@@ -222,7 +240,12 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
222
240
|
used_keys: set[int] = set()
|
|
223
241
|
while not max_shares or count < max_shares:
|
|
224
242
|
share_key: int = 0
|
|
225
|
-
while
|
|
243
|
+
while (
|
|
244
|
+
not share_key
|
|
245
|
+
or share_key in self.polynomial
|
|
246
|
+
or share_key in used_keys
|
|
247
|
+
or share_key >= self.modulus
|
|
248
|
+
):
|
|
226
249
|
share_key = base.RandBits(self.modulus.bit_length() - 1)
|
|
227
250
|
try:
|
|
228
251
|
yield self.RawShare(secret, share_key=share_key)
|
|
@@ -251,28 +274,34 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
251
274
|
|
|
252
275
|
Raises:
|
|
253
276
|
InputError: invalid inputs
|
|
254
|
-
|
|
277
|
+
|
|
255
278
|
"""
|
|
256
279
|
if total_shares < self.minimum:
|
|
257
280
|
raise base.InputError(f'invalid total_shares: {total_shares=} < {self.minimum=}')
|
|
258
281
|
k: int = self.modulus_size
|
|
259
|
-
if k <= 32:
|
|
282
|
+
if k <= 32: # noqa: PLR2004
|
|
260
283
|
raise base.InputError(f'modulus too small for key operations: {k} bytes')
|
|
261
284
|
key256: bytes = base.RandBytes(32)
|
|
262
285
|
shares: list[ShamirSharePrivate] = list(
|
|
263
|
-
|
|
286
|
+
self.RawShares(base.BytesToInt(key256), max_shares=total_shares)
|
|
287
|
+
)
|
|
264
288
|
aad: bytes = (
|
|
265
|
-
|
|
266
|
-
|
|
289
|
+
_SSS_ENCRYPTION_AAD_PREFIX
|
|
290
|
+
+ base.IntToFixedBytes(self.minimum, 8)
|
|
291
|
+
+ base.IntToFixedBytes(self.modulus, k)
|
|
292
|
+
)
|
|
267
293
|
aead_key: bytes = base.Hash512(_SSS_ENCRYPTION_AAD_PREFIX + key256)
|
|
268
294
|
ct: bytes = aes.AESKey(key256=aead_key[32:]).Encrypt(secret, associated_data=aad)
|
|
269
|
-
return [
|
|
295
|
+
return [
|
|
296
|
+
ShamirShareData(
|
|
270
297
|
minimum=s.minimum,
|
|
271
298
|
modulus=s.modulus,
|
|
272
299
|
share_key=s.share_key,
|
|
273
300
|
share_value=s.share_value,
|
|
274
301
|
encrypted_data=ct,
|
|
275
|
-
|
|
302
|
+
)
|
|
303
|
+
for s in shares
|
|
304
|
+
]
|
|
276
305
|
|
|
277
306
|
def RawVerifyShare(self, secret: int, share: ShamirSharePrivate, /) -> bool:
|
|
278
307
|
"""Verify a ShamirSharePrivate object for the `secret`.
|
|
@@ -289,14 +318,12 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
289
318
|
Returns:
|
|
290
319
|
True if share is valid; False otherwise
|
|
291
320
|
|
|
292
|
-
Raises:
|
|
293
|
-
InputError: invalid inputs
|
|
294
321
|
"""
|
|
295
322
|
return share == self.RawShare(secret, share_key=share.share_key)
|
|
296
323
|
|
|
297
324
|
@classmethod
|
|
298
325
|
def New(cls, minimum_shares: int, bit_length: int, /) -> Self:
|
|
299
|
-
"""
|
|
326
|
+
"""Make a new private SSS object of `bit_length` bits prime modulus and coefficients.
|
|
300
327
|
|
|
301
328
|
Args:
|
|
302
329
|
minimum_shares (int): minimum shares needed for recovery, ≥ 2
|
|
@@ -307,11 +334,12 @@ class ShamirSharedSecretPrivate(ShamirSharedSecretPublic):
|
|
|
307
334
|
|
|
308
335
|
Raises:
|
|
309
336
|
InputError: invalid inputs
|
|
337
|
+
|
|
310
338
|
"""
|
|
311
339
|
# test inputs
|
|
312
|
-
if minimum_shares < 2:
|
|
340
|
+
if minimum_shares < 2: # noqa: PLR2004
|
|
313
341
|
raise base.InputError(f'at least 2 shares are needed: {minimum_shares=}')
|
|
314
|
-
if bit_length < 10:
|
|
342
|
+
if bit_length < 10: # noqa: PLR2004
|
|
315
343
|
raise base.InputError(f'invalid bit length: {bit_length=}')
|
|
316
344
|
# make the primes
|
|
317
345
|
unique_primes: set[int] = modmath.NBitRandomPrimes(bit_length, n_primes=minimum_shares)
|
|
@@ -335,6 +363,7 @@ class ShamirSharePrivate(ShamirSharedSecretPublic):
|
|
|
335
363
|
Attributes:
|
|
336
364
|
share_key (int): share secret key; a randomly picked value, 1 ≤ k < modulus
|
|
337
365
|
share_value (int): share secret value, 1 ≤ v < modulus; (k, v) is a "point" of f(k)=v
|
|
366
|
+
|
|
338
367
|
"""
|
|
339
368
|
|
|
340
369
|
share_key: int
|
|
@@ -345,10 +374,10 @@ class ShamirSharePrivate(ShamirSharedSecretPublic):
|
|
|
345
374
|
|
|
346
375
|
Raises:
|
|
347
376
|
InputError: invalid inputs
|
|
377
|
+
|
|
348
378
|
"""
|
|
349
|
-
super(ShamirSharePrivate, self).__post_init__()
|
|
350
|
-
if
|
|
351
|
-
not 0 < self.share_value < self.modulus):
|
|
379
|
+
super(ShamirSharePrivate, self).__post_init__()
|
|
380
|
+
if not 0 < self.share_key < self.modulus or not 0 < self.share_value < self.modulus:
|
|
352
381
|
raise base.InputError(f'invalid share: {self}')
|
|
353
382
|
|
|
354
383
|
def __str__(self) -> str:
|
|
@@ -356,18 +385,32 @@ class ShamirSharePrivate(ShamirSharedSecretPublic):
|
|
|
356
385
|
|
|
357
386
|
Returns:
|
|
358
387
|
string representation of ShamirSharePrivate without leaking secrets
|
|
388
|
+
|
|
359
389
|
"""
|
|
360
|
-
return (
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
390
|
+
return (
|
|
391
|
+
'ShamirSharePrivate('
|
|
392
|
+
f'{super(ShamirSharePrivate, self).__str__()}, '
|
|
393
|
+
f'share_key={base.ObfuscateSecret(self.share_key)}, '
|
|
394
|
+
f'share_value={base.ObfuscateSecret(self.share_value)})'
|
|
395
|
+
)
|
|
364
396
|
|
|
365
397
|
@classmethod
|
|
366
398
|
def CopyShare(cls, other: ShamirSharePrivate, /) -> Self:
|
|
367
|
-
"""Initialize a share taking the parts of another share.
|
|
399
|
+
"""Initialize a share taking the parts of another share.
|
|
400
|
+
|
|
401
|
+
Args:
|
|
402
|
+
other (ShamirSharePrivate): object to copy from
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
Self: a new ShamirSharePrivate
|
|
406
|
+
|
|
407
|
+
"""
|
|
368
408
|
return cls(
|
|
369
|
-
|
|
370
|
-
|
|
409
|
+
minimum=other.minimum,
|
|
410
|
+
modulus=other.modulus,
|
|
411
|
+
share_key=other.share_key,
|
|
412
|
+
share_value=other.share_value,
|
|
413
|
+
)
|
|
371
414
|
|
|
372
415
|
|
|
373
416
|
@dataclasses.dataclass(kw_only=True, slots=True, frozen=True, repr=False)
|
|
@@ -380,6 +423,8 @@ class ShamirShareData(ShamirSharePrivate):
|
|
|
380
423
|
Attributes:
|
|
381
424
|
share_key (int): share secret key; a randomly picked value, 1 ≤ k < modulus
|
|
382
425
|
share_value (int): share secret value, 1 ≤ v < modulus; (k, v) is a "point" of f(k)=v
|
|
426
|
+
encrypted_data (bytes): AES-256-GCM encrypted secret data with IV and tag
|
|
427
|
+
|
|
383
428
|
"""
|
|
384
429
|
|
|
385
430
|
encrypted_data: bytes
|
|
@@ -389,9 +434,10 @@ class ShamirShareData(ShamirSharePrivate):
|
|
|
389
434
|
|
|
390
435
|
Raises:
|
|
391
436
|
InputError: invalid inputs
|
|
437
|
+
|
|
392
438
|
"""
|
|
393
|
-
super(ShamirShareData, self).__post_init__()
|
|
394
|
-
if len(self.encrypted_data) < 32:
|
|
439
|
+
super(ShamirShareData, self).__post_init__()
|
|
440
|
+
if len(self.encrypted_data) < 32: # noqa: PLR2004
|
|
395
441
|
raise base.InputError(f'AES256+GCM SSS should have ≥32 bytes IV/CT/tag: {self}')
|
|
396
442
|
|
|
397
443
|
def __str__(self) -> str:
|
|
@@ -399,10 +445,13 @@ class ShamirShareData(ShamirSharePrivate):
|
|
|
399
445
|
|
|
400
446
|
Returns:
|
|
401
447
|
string representation of ShamirShareData without leaking secrets
|
|
448
|
+
|
|
402
449
|
"""
|
|
403
|
-
return (
|
|
404
|
-
|
|
405
|
-
|
|
450
|
+
return (
|
|
451
|
+
'ShamirShareData('
|
|
452
|
+
f'{super(ShamirShareData, self).__str__()}, '
|
|
453
|
+
f'encrypted_data={base.ObfuscateSecret(self.encrypted_data)})'
|
|
454
|
+
)
|
|
406
455
|
|
|
407
456
|
def RecoverData(self, other_shares: list[ShamirSharePrivate]) -> bytes:
|
|
408
457
|
"""Recover the encrypted data from ShamirSharePrivate objects.
|
|
@@ -420,17 +469,20 @@ class ShamirShareData(ShamirSharePrivate):
|
|
|
420
469
|
Raises:
|
|
421
470
|
InputError: invalid inputs
|
|
422
471
|
CryptoError: internal crypto failures, authentication failure, key mismatch, etc
|
|
472
|
+
|
|
423
473
|
"""
|
|
424
474
|
k: int = self.modulus_size
|
|
425
|
-
if k <= 32:
|
|
475
|
+
if k <= 32: # noqa: PLR2004
|
|
426
476
|
raise base.InputError(f'modulus too small for key operations: {k} bytes')
|
|
427
477
|
# recover secret; raise if shares are invalid
|
|
428
|
-
secret: int = self.RawRecoverSecret([self
|
|
478
|
+
secret: int = self.RawRecoverSecret([self, *other_shares])
|
|
429
479
|
if not 0 <= secret < (1 << 256):
|
|
430
480
|
raise base.CryptoError('recovered key out of range for 256-bit key')
|
|
431
481
|
key256: bytes = base.IntToFixedBytes(secret, 32)
|
|
432
482
|
aad: bytes = (
|
|
433
|
-
|
|
434
|
-
|
|
483
|
+
_SSS_ENCRYPTION_AAD_PREFIX
|
|
484
|
+
+ base.IntToFixedBytes(self.minimum, 8)
|
|
485
|
+
+ base.IntToFixedBytes(self.modulus, k)
|
|
486
|
+
)
|
|
435
487
|
aead_key: bytes = base.Hash512(_SSS_ENCRYPTION_AAD_PREFIX + key256)
|
|
436
488
|
return aes.AESKey(key256=aead_key[32:]).Decrypt(self.encrypted_data, associated_data=aad)
|