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/dsa.py CHANGED
@@ -1,7 +1,5 @@
1
- #!/usr/bin/env python3
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 DSA (Digital Signature Algorithm) library.
6
4
 
7
5
  <https://en.wikipedia.org/wiki/Digital_Signature_Algorithm>
@@ -17,18 +15,12 @@ import dataclasses
17
15
  import logging
18
16
  import multiprocessing
19
17
  import os
20
- # import pdb
21
18
  from typing import Self
22
19
 
23
- import gmpy2 # type:ignore
20
+ import gmpy2
24
21
 
25
22
  from . import base, constants, modmath
26
23
 
27
- __author__ = 'balparda@github.com'
28
- __version__: str = base.__version__ # version comes from base!
29
- __version_tuple__: tuple[int, ...] = base.__version_tuple__
30
-
31
-
32
24
  _MAX_KEY_GENERATION_FAILURES = 15
33
25
 
34
26
  # fixed prefixes: do NOT ever change! will break all encryption and signature schemes
@@ -36,8 +28,9 @@ _DSA_SIGNATURE_HASH_PREFIX = b'transcrypto.DSA.Signature.1.0\x00'
36
28
 
37
29
 
38
30
  def NBitRandomDSAPrimes(
39
- p_bits: int, q_bits: int, /, *, serial: bool = True) -> tuple[int, int, int]:
40
- """Generates 2 random DSA primes p & q with `x_bits` size and (p-1)%q==0.
31
+ p_bits: int, q_bits: int, /, *, serial: bool = True
32
+ ) -> tuple[int, int, int]:
33
+ """Generate 2 random DSA primes p & q with `x_bits` size and (p-1)%q==0.
41
34
 
42
35
  Uses an aggressive small-prime wheel sieve:
43
36
  Before any Miller-Rabin we reject p = m·q + 1 if it is divisible by a small prime.
@@ -76,9 +69,11 @@ def NBitRandomDSAPrimes(
76
69
 
77
70
  Raises:
78
71
  InputError: invalid inputs
72
+ Error: prime search failed
73
+
79
74
  """
80
75
  # test inputs
81
- if q_bits < 11:
76
+ if q_bits < 11: # noqa: PLR2004
82
77
  raise base.InputError(f'invalid q_bits length: {q_bits=}')
83
78
  if p_bits < q_bits + 11:
84
79
  raise base.InputError(f'invalid p_bits length: {p_bits=}')
@@ -88,7 +83,7 @@ def NBitRandomDSAPrimes(
88
83
  n_workers: int = min(4, os.cpu_count() or 1)
89
84
  pr: int | None = None
90
85
  m: int | None = None
91
- if serial or n_workers <= 1 or p_bits < 200:
86
+ if serial or n_workers <= 1 or p_bits < 200: # noqa: PLR2004
92
87
  # do one worker
93
88
  while pr is None or m is None or pr.bit_length() != p_bits:
94
89
  pr, m = _PrimePSearchShard(q, p_bits)
@@ -97,10 +92,12 @@ def NBitRandomDSAPrimes(
97
92
  multiprocessing.set_start_method('fork', force=True)
98
93
  with concurrent.futures.ProcessPoolExecutor(max_workers=n_workers) as pool:
99
94
  workers: set[concurrent.futures.Future[tuple[int | None, int | None]]] = {
100
- pool.submit(_PrimePSearchShard, q, p_bits) for _ in range(n_workers)}
95
+ pool.submit(_PrimePSearchShard, q, p_bits) for _ in range(n_workers)
96
+ }
101
97
  while workers:
102
98
  done: set[concurrent.futures.Future[tuple[int | None, int | None]]] = concurrent.futures.wait(
103
- workers, return_when=concurrent.futures.FIRST_COMPLETED)[0]
99
+ workers, return_when=concurrent.futures.FIRST_COMPLETED
100
+ )[0]
104
101
  for worker in done:
105
102
  workers.remove(worker)
106
103
  pr, m = worker.result()
@@ -113,7 +110,7 @@ def NBitRandomDSAPrimes(
113
110
 
114
111
 
115
112
  def _PrimePSearchShard(q: int, p_bits: int) -> tuple[int | None, int | None]:
116
- """Search for a `p_bits` random prime, starting from a random point, for ~ expected prime gap.
113
+ """Search for a `p_bits` random prime, starting from a random point, for ~6x expected prime gap.
117
114
 
118
115
  Args:
119
116
  q (int): Prime `q` for DSA
@@ -121,27 +118,26 @@ def _PrimePSearchShard(q: int, p_bits: int) -> tuple[int | None, int | None]:
121
118
 
122
119
  Returns:
123
120
  tuple[int | None, int | None]: either the prime `p` and multiple `m` or None if no prime found
121
+
124
122
  """
125
123
  q_bits: int = q.bit_length()
126
- shard_len: int = max(2000, 6 * int(0.693 * p_bits)) # ~ expected prime gap ~2^k (≈ 0.693*k)
124
+ shard_len: int = max(2000, 6 * int(0.693 * p_bits)) # ~6x expected prime gap ~2^k (≈ 0.693*k)
127
125
  # find range of multiples to use
128
126
  min_p: int = 2 ** (p_bits - 1)
129
- max_p: int = 2 ** p_bits - 1
127
+ max_p: int = 2**p_bits - 1
130
128
  min_m: int = min_p // q + 2
131
129
  max_m: int = max_p // q - 2
132
- assert max_m - min_m > 1000 # make sure we'll have options!
130
+ assert max_m - min_m > 1000 # make sure we'll have options! # noqa: PLR2004, S101
133
131
  # make list of small primes to use for sieving
134
132
  approx_q_root: int = 1 << (q_bits // 2)
135
133
  pr: int
136
134
  forbidden: dict[int, int] = { # (modulus: forbidden residue)
137
- pr: ((-modmath.ModInv(q % pr, pr)) % pr)
138
- for pr in constants.FIRST_5K_PRIMES_SORTED[1:min(1000, approx_q_root)]} # skip pr==2
135
+ pr: ((-modmath.ModInv(q % pr, pr)) % pr)
136
+ for pr in constants.FIRST_5K_PRIMES_SORTED[1 : min(1000, approx_q_root)]
137
+ } # skip pr==2
139
138
 
140
139
  def _PassesSieve(m: int) -> bool:
141
- for r, f in forbidden.items():
142
- if m % r == f:
143
- return False
144
- return True
140
+ return all(m % r != f for r, f in forbidden.items())
145
141
 
146
142
  # try searching starting here
147
143
  m: int = base.RandInt(min_m, max_m)
@@ -154,9 +150,8 @@ def _PrimePSearchShard(q: int, p_bits: int) -> tuple[int | None, int | None]:
154
150
  if pr > max_p:
155
151
  break
156
152
  # first do a quick sieve test
157
- if _PassesSieve(m):
158
- if modmath.IsPrime(pr): # passed sieve, do full test
159
- return (pr, m) # found a suitable prime set!
153
+ if _PassesSieve(m) and modmath.IsPrime(pr): # passed sieve, do full test
154
+ return (pr, m) # found a suitable prime set!
160
155
  count += 1
161
156
  m += 2 # next even number
162
157
  return (None, None)
@@ -172,6 +167,7 @@ class DSASharedPublicKey(base.CryptoKey):
172
167
  prime_modulus (int): prime modulus (p), > prime_seed
173
168
  prime_seed (int): prime seed (q), ≥ 7
174
169
  group_base (int): shared encryption group public base, 3 ≤ g < prime_modulus
170
+
175
171
  """
176
172
 
177
173
  prime_modulus: int
@@ -183,16 +179,17 @@ class DSASharedPublicKey(base.CryptoKey):
183
179
 
184
180
  Raises:
185
181
  InputError: invalid inputs
182
+
186
183
  """
187
- super(DSASharedPublicKey, self).__post_init__() # pylint: disable=super-with-arguments # needed here b/c: dataclass
188
- if self.prime_seed < 7 or not modmath.IsPrime(self.prime_seed):
184
+ if self.prime_seed < 7 or not modmath.IsPrime(self.prime_seed): # noqa: PLR2004
189
185
  raise base.InputError(f'invalid prime_seed: {self}')
190
- if (self.prime_modulus <= self.prime_seed or
191
- self.prime_modulus % self.prime_seed != 1 or
192
- not modmath.IsPrime(self.prime_modulus)):
186
+ if (
187
+ self.prime_modulus <= self.prime_seed
188
+ or self.prime_modulus % self.prime_seed != 1
189
+ or not modmath.IsPrime(self.prime_modulus)
190
+ ):
193
191
  raise base.InputError(f'invalid prime_modulus: {self}')
194
- if (not 2 < self.group_base < self.prime_modulus or
195
- self.group_base == self.prime_seed):
192
+ if not 2 < self.group_base < self.prime_modulus or self.group_base == self.prime_seed: # noqa: PLR2004
196
193
  raise base.InputError(f'invalid group_base: {self}')
197
194
 
198
195
  def __str__(self) -> str:
@@ -200,21 +197,24 @@ class DSASharedPublicKey(base.CryptoKey):
200
197
 
201
198
  Returns:
202
199
  string representation of DSASharedPublicKey
200
+
203
201
  """
204
- return ('DSASharedPublicKey('
205
- f'bits=[{self.prime_modulus.bit_length()}, {self.prime_seed.bit_length()}], '
206
- f'prime_modulus={base.IntToEncoded(self.prime_modulus)}, '
207
- f'prime_seed={base.IntToEncoded(self.prime_seed)}, '
208
- f'group_base={base.IntToEncoded(self.group_base)})')
202
+ return (
203
+ 'DSASharedPublicKey('
204
+ f'bits=[{self.prime_modulus.bit_length()}, {self.prime_seed.bit_length()}], '
205
+ f'prime_modulus={base.IntToEncoded(self.prime_modulus)}, '
206
+ f'prime_seed={base.IntToEncoded(self.prime_seed)}, '
207
+ f'group_base={base.IntToEncoded(self.group_base)})'
208
+ )
209
209
 
210
210
  @property
211
211
  def modulus_size(self) -> tuple[int, int]:
212
212
  """Modulus size in bytes. The number of bytes used in Sign/Verify."""
213
- return ((self.prime_modulus.bit_length() + 7) // 8,
214
- (self.prime_seed.bit_length() + 7) // 8)
213
+ return ((self.prime_modulus.bit_length() + 7) // 8, (self.prime_seed.bit_length() + 7) // 8)
215
214
 
216
215
  def _DomainSeparatedHash(
217
- self, message: bytes, associated_data: bytes | None, salt: bytes, /) -> int:
216
+ self, message: bytes, associated_data: bytes | None, salt: bytes, /
217
+ ) -> int:
218
218
  """Compute the domain-separated hash for signing and verifying.
219
219
 
220
220
  Args:
@@ -228,12 +228,12 @@ class DSASharedPublicKey(base.CryptoKey):
228
228
 
229
229
  Raises:
230
230
  CryptoError: hash output is out of range
231
+
231
232
  """
232
233
  aad: bytes = b'' if associated_data is None else associated_data
233
234
  la: bytes = base.IntToFixedBytes(len(aad), 8)
234
- assert len(salt) == 64, 'should never happen: salt should be exactly 64 bytes'
235
- y: int = base.BytesToInt(
236
- base.Hash512(_DSA_SIGNATURE_HASH_PREFIX + la + aad + message + salt))
235
+ assert len(salt) == 64, 'should never happen: salt should be exactly 64 bytes' # noqa: PLR2004, S101
236
+ y: int = base.BytesToInt(base.Hash512(_DSA_SIGNATURE_HASH_PREFIX + la + aad + message + salt))
237
237
  if not 1 < y < self.prime_seed - 1:
238
238
  # will only reasonably happen if prime seed is small
239
239
  raise base.CryptoError(f'hash output {y} is out of range/invalid {self.prime_seed}')
@@ -251,16 +251,14 @@ class DSASharedPublicKey(base.CryptoKey):
251
251
  Returns:
252
252
  DSASharedPublicKey object ready for use
253
253
 
254
- Raises:
255
- InputError: invalid inputs
256
254
  """
257
255
  # test inputs and generate primes
258
256
  p, q, m = NBitRandomDSAPrimes(p_bits, q_bits)
259
257
  # generate random number, create object (should never fail)
260
258
  g: int = 0
261
- while g < 2:
259
+ while g < 3: # noqa: PLR2004
262
260
  h: int = base.RandBits(p_bits - 1)
263
- g = int(gmpy2.powmod(h, m, p)) # type:ignore # pylint:disable=no-member
261
+ g = int(gmpy2.powmod(h, m, p))
264
262
  return cls(prime_modulus=p, prime_seed=q, group_base=g)
265
263
 
266
264
 
@@ -272,6 +270,7 @@ class DSAPublicKey(DSASharedPublicKey, base.Verifier):
272
270
 
273
271
  Attributes:
274
272
  individual_base (int): individual encryption public base, 3 ≤ i < prime_modulus
273
+
275
274
  """
276
275
 
277
276
  individual_base: int
@@ -281,10 +280,13 @@ class DSAPublicKey(DSASharedPublicKey, base.Verifier):
281
280
 
282
281
  Raises:
283
282
  InputError: invalid inputs
283
+
284
284
  """
285
- super(DSAPublicKey, self).__post_init__() # pylint: disable=super-with-arguments # needed here b/c: dataclass
286
- if (not 2 < self.individual_base < self.prime_modulus or
287
- self.individual_base in (self.group_base, self.prime_seed)):
285
+ super(DSAPublicKey, self).__post_init__()
286
+ if not 2 < self.individual_base < self.prime_modulus or self.individual_base in { # noqa: PLR2004
287
+ self.group_base,
288
+ self.prime_seed,
289
+ }:
288
290
  raise base.InputError(f'invalid individual_base: {self}')
289
291
 
290
292
  def __str__(self) -> str:
@@ -292,21 +294,27 @@ class DSAPublicKey(DSASharedPublicKey, base.Verifier):
292
294
 
293
295
  Returns:
294
296
  string representation of DSAPublicKey
297
+
295
298
  """
296
- return ('DSAPublicKey('
297
- f'{super(DSAPublicKey, self).__str__()}, ' # pylint: disable=super-with-arguments
298
- f'individual_base={base.IntToEncoded(self.individual_base)})')
299
+ return (
300
+ 'DSAPublicKey('
301
+ f'{super(DSAPublicKey, self).__str__()}, '
302
+ f'individual_base={base.IntToEncoded(self.individual_base)})'
303
+ )
299
304
 
300
305
  def _MakeEphemeralKey(self) -> tuple[int, int]:
301
306
  """Make an ephemeral key adequate to be used with DSA.
302
307
 
303
308
  Returns:
304
309
  (key, key_inverse), where 3 ≤ k < p_seed and (k*i) % p_seed == 1
310
+
305
311
  """
306
312
  ephemeral_key: int = 0
307
313
  bit_length: int = self.prime_seed.bit_length()
308
- while (not 2 < ephemeral_key < self.prime_seed or
309
- ephemeral_key in (self.group_base, self.individual_base)):
314
+ while not 2 < ephemeral_key < self.prime_seed or ephemeral_key in { # noqa: PLR2004
315
+ self.group_base,
316
+ self.individual_base,
317
+ }:
310
318
  ephemeral_key = base.RandBits(bit_length - 1)
311
319
  return (ephemeral_key, modmath.ModInv(ephemeral_key, self.prime_seed))
312
320
 
@@ -326,23 +334,26 @@ class DSAPublicKey(DSASharedPublicKey, base.Verifier):
326
334
 
327
335
  Raises:
328
336
  InputError: invalid inputs
337
+
329
338
  """
330
339
  # test inputs
331
340
  if not 0 < message < self.prime_seed:
332
341
  raise base.InputError(f'invalid message: {message=}')
333
- if (not 2 <= signature[0] < self.prime_seed or
334
- not 2 <= signature[1] < self.prime_seed):
342
+ if not 2 <= signature[0] < self.prime_seed or not 2 <= signature[1] < self.prime_seed: # noqa: PLR2004
335
343
  raise base.InputError(f'invalid signature: {signature=}')
336
344
  # verify
337
345
  inv: int = modmath.ModInv(signature[1], self.prime_seed)
338
- a: int = int(gmpy2.powmod( # type:ignore # pylint:disable=no-member
339
- self.group_base, (message * inv) % self.prime_seed, self.prime_modulus))
340
- b: int = int(gmpy2.powmod( # type:ignore # pylint:disable=no-member
341
- self.individual_base, (signature[0] * inv) % self.prime_seed, self.prime_modulus))
346
+ a: int = int(
347
+ gmpy2.powmod(self.group_base, (message * inv) % self.prime_seed, self.prime_modulus)
348
+ )
349
+ b: int = int(
350
+ gmpy2.powmod(self.individual_base, (signature[0] * inv) % self.prime_seed, self.prime_modulus)
351
+ )
342
352
  return ((a * b) % self.prime_modulus) % self.prime_seed == signature[0]
343
353
 
344
354
  def Verify(
345
- self, message: bytes, signature: bytes, /, *, associated_data: bytes | None = None) -> bool:
355
+ self, message: bytes, signature: bytes, /, *, associated_data: bytes | None = None
356
+ ) -> bool:
346
357
  """Verify a `signature` for `message`. True if OK; False if failed verification.
347
358
 
348
359
  • Let k = ceil(log2(n))/8 be the modulus size in bytes.
@@ -361,40 +372,51 @@ class DSAPublicKey(DSASharedPublicKey, base.Verifier):
361
372
 
362
373
  Raises:
363
374
  InputError: invalid inputs
364
- CryptoError: internal crypto failures, authentication failure, key mismatch, etc
375
+
365
376
  """
366
377
  k: int = self.modulus_size[1] # use prime_seed size
367
- if k <= 64:
378
+ if k <= 64: # noqa: PLR2004
368
379
  raise base.InputError(f'modulus/seed too small for signing operations: {k} bytes')
369
380
  if len(signature) != (64 + k + k):
370
381
  logging.info(f'invalid signature length: {len(signature)} ; expected {64 + k + k}')
371
382
  return False
372
383
  try:
373
384
  return self.RawVerify(
374
- self._DomainSeparatedHash(message, associated_data, signature[:64]),
375
- (base.BytesToInt(signature[64:64 + k]), base.BytesToInt(signature[64 + k:])))
385
+ self._DomainSeparatedHash(message, associated_data, signature[:64]),
386
+ (base.BytesToInt(signature[64 : 64 + k]), base.BytesToInt(signature[64 + k :])),
387
+ )
376
388
  except base.InputError as err:
377
389
  logging.info(err)
378
390
  return False
379
391
 
380
392
  @classmethod
381
393
  def Copy(cls, other: DSAPublicKey, /) -> Self:
382
- """Initialize a public key by taking the public parts of a public/private key."""
394
+ """Initialize a public key by taking the public parts of a public/private key.
395
+
396
+ Args:
397
+ other (DSAPublicKey): object to copy from
398
+
399
+ Returns:
400
+ Self: a new DSAPublicKey
401
+
402
+ """
383
403
  return cls(
384
- prime_modulus=other.prime_modulus,
385
- prime_seed=other.prime_seed,
386
- group_base=other.group_base,
387
- individual_base=other.individual_base)
404
+ prime_modulus=other.prime_modulus,
405
+ prime_seed=other.prime_seed,
406
+ group_base=other.group_base,
407
+ individual_base=other.individual_base,
408
+ )
388
409
 
389
410
 
390
411
  @dataclasses.dataclass(kw_only=True, slots=True, frozen=True, repr=False)
391
- class DSAPrivateKey(DSAPublicKey, base.Signer): # pylint: disable=too-many-ancestors
412
+ class DSAPrivateKey(DSAPublicKey, base.Signer):
392
413
  """DSA private key.
393
414
 
394
415
  No measures are taken here to prevent timing attacks.
395
416
 
396
417
  Attributes:
397
- decrypt_exp (int): individual decryption exponent, 3 ≤ i < prime_modulus
418
+ decrypt_exp (int): individual decryption exponent, 3 ≤ i < prime_seed
419
+
398
420
  """
399
421
 
400
422
  decrypt_exp: int
@@ -405,12 +427,15 @@ class DSAPrivateKey(DSAPublicKey, base.Signer): # pylint: disable=too-many-ance
405
427
  Raises:
406
428
  InputError: invalid inputs
407
429
  CryptoError: modulus math is inconsistent with values
430
+
408
431
  """
409
- super(DSAPrivateKey, self).__post_init__() # pylint: disable=super-with-arguments # needed here b/c: dataclass
410
- if (not 2 < self.decrypt_exp < self.prime_seed or
411
- self.decrypt_exp in (self.group_base, self.individual_base)):
432
+ super(DSAPrivateKey, self).__post_init__()
433
+ if not 2 < self.decrypt_exp < self.prime_seed or self.decrypt_exp in { # noqa: PLR2004
434
+ self.group_base,
435
+ self.individual_base,
436
+ }:
412
437
  raise base.InputError(f'invalid decrypt_exp: {self}')
413
- if gmpy2.powmod(self.group_base, self.decrypt_exp, self.prime_modulus) != self.individual_base: # type:ignore # pylint:disable=no-member
438
+ if gmpy2.powmod(self.group_base, self.decrypt_exp, self.prime_modulus) != self.individual_base:
414
439
  raise base.CryptoError(f'inconsistent g**d % p == i: {self}')
415
440
 
416
441
  def __str__(self) -> str:
@@ -418,10 +443,13 @@ class DSAPrivateKey(DSAPublicKey, base.Signer): # pylint: disable=too-many-ance
418
443
 
419
444
  Returns:
420
445
  string representation of DSAPrivateKey without leaking secrets
446
+
421
447
  """
422
- return ('DSAPrivateKey('
423
- f'{super(DSAPrivateKey, self).__str__()}, ' # pylint: disable=super-with-arguments
424
- f'decrypt_exp={base.ObfuscateSecret(self.decrypt_exp)})')
448
+ return (
449
+ 'DSAPrivateKey('
450
+ f'{super(DSAPrivateKey, self).__str__()}, '
451
+ f'decrypt_exp={base.ObfuscateSecret(self.decrypt_exp)})'
452
+ )
425
453
 
426
454
  def RawSign(self, message: int, /) -> tuple[int, int]:
427
455
  """Sign `message` with this private key.
@@ -438,6 +466,7 @@ class DSAPrivateKey(DSAPublicKey, base.Signer): # pylint: disable=too-many-ance
438
466
 
439
467
  Raises:
440
468
  InputError: invalid inputs
469
+
441
470
  """
442
471
  # test inputs
443
472
  if not 0 < message < self.prime_seed:
@@ -445,9 +474,9 @@ class DSAPrivateKey(DSAPublicKey, base.Signer): # pylint: disable=too-many-ance
445
474
  # sign
446
475
  a: int = 0
447
476
  b: int = 0
448
- while a < 2 or b < 2:
477
+ while a < 2 or b < 2: # noqa: PLR2004
449
478
  ephemeral_key, ephemeral_inv = self._MakeEphemeralKey()
450
- a = int(gmpy2.powmod(self.group_base, ephemeral_key, self.prime_modulus) % self.prime_seed) # type:ignore # pylint:disable=no-member
479
+ a = int(gmpy2.powmod(self.group_base, ephemeral_key, self.prime_modulus) % self.prime_seed)
451
480
  b = (ephemeral_inv * ((message + a * self.decrypt_exp) % self.prime_seed)) % self.prime_seed
452
481
  return (a, b)
453
482
 
@@ -474,15 +503,15 @@ class DSAPrivateKey(DSAPublicKey, base.Signer): # pylint: disable=too-many-ance
474
503
 
475
504
  Raises:
476
505
  InputError: invalid inputs
477
- CryptoError: internal crypto failures
506
+
478
507
  """
479
508
  k: int = self.modulus_size[1] # use prime_seed size
480
- if k <= 64:
509
+ if k <= 64: # noqa: PLR2004
481
510
  raise base.InputError(f'modulus/seed too small for signing operations: {k} bytes')
482
511
  salt: bytes = base.RandBytes(64)
483
512
  s_int: tuple[int, int] = self.RawSign(self._DomainSeparatedHash(message, associated_data, salt))
484
513
  s_bytes: bytes = base.IntToFixedBytes(s_int[0], k) + base.IntToFixedBytes(s_int[1], k)
485
- assert len(s_bytes) == 2 * k, 'should never happen: s_bytes should be exactly 2k bytes'
514
+ assert len(s_bytes) == 2 * k, 'should never happen: s_bytes should be exactly 2k bytes' # noqa: S101
486
515
  return salt + s_bytes
487
516
 
488
517
  @classmethod
@@ -498,10 +527,11 @@ class DSAPrivateKey(DSAPublicKey, base.Signer): # pylint: disable=too-many-ance
498
527
  Raises:
499
528
  InputError: invalid inputs
500
529
  CryptoError: failed generation
530
+
501
531
  """
502
532
  # test inputs
503
533
  bit_length: int = shared_key.prime_seed.bit_length()
504
- if bit_length < 11:
534
+ if bit_length < 11: # noqa: PLR2004
505
535
  raise base.InputError(f'invalid q_bit length: {bit_length=}')
506
536
  # loop until we have an object
507
537
  failures: int = 0
@@ -509,17 +539,20 @@ class DSAPrivateKey(DSAPublicKey, base.Signer): # pylint: disable=too-many-ance
509
539
  try:
510
540
  # generate private key differing from group_base
511
541
  decrypt_exp: int = 0
512
- while (not 2 < decrypt_exp < shared_key.prime_seed - 1 or
513
- decrypt_exp == shared_key.group_base):
542
+ while (
543
+ not 2 < decrypt_exp < shared_key.prime_seed or decrypt_exp == shared_key.group_base # noqa: PLR2004
544
+ ):
514
545
  decrypt_exp = base.RandBits(bit_length - 1)
515
546
  # make the object
516
547
  return cls(
517
- prime_modulus=shared_key.prime_modulus,
518
- prime_seed=shared_key.prime_seed,
519
- group_base=shared_key.group_base,
520
- individual_base=int(gmpy2.powmod( # type:ignore # pylint:disable=no-member
521
- shared_key.group_base, decrypt_exp, shared_key.prime_modulus)),
522
- decrypt_exp=decrypt_exp)
548
+ prime_modulus=shared_key.prime_modulus,
549
+ prime_seed=shared_key.prime_seed,
550
+ group_base=shared_key.group_base,
551
+ individual_base=int(
552
+ gmpy2.powmod(shared_key.group_base, decrypt_exp, shared_key.prime_modulus)
553
+ ),
554
+ decrypt_exp=decrypt_exp,
555
+ )
523
556
  except base.InputError as err:
524
557
  failures += 1
525
558
  if failures >= _MAX_KEY_GENERATION_FAILURES: