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/elgamal.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 El-Gamal library.
6
4
 
7
5
  <https://en.wikipedia.org/wiki/ElGamal_encryption>
@@ -20,17 +18,11 @@ from __future__ import annotations
20
18
 
21
19
  import dataclasses
22
20
  import logging
23
- # import pdb
24
21
  from typing import Self
25
22
 
26
- import gmpy2 # type:ignore
27
-
28
- from . import base, modmath, aes
29
-
30
- __author__ = 'balparda@github.com'
31
- __version__: str = base.__version__ # version comes from base!
32
- __version_tuple__: tuple[int, ...] = base.__version_tuple__
23
+ import gmpy2
33
24
 
25
+ from . import aes, base, modmath
34
26
 
35
27
  _MAX_KEY_GENERATION_FAILURES = 15
36
28
 
@@ -48,6 +40,7 @@ class ElGamalSharedPublicKey(base.CryptoKey):
48
40
  Attributes:
49
41
  prime_modulus (int): prime modulus, ≥ 7
50
42
  group_base (int): shared encryption group public base, 3 ≤ g < prime_modulus
43
+
51
44
  """
52
45
 
53
46
  prime_modulus: int
@@ -58,11 +51,11 @@ class ElGamalSharedPublicKey(base.CryptoKey):
58
51
 
59
52
  Raises:
60
53
  InputError: invalid inputs
54
+
61
55
  """
62
- super(ElGamalSharedPublicKey, self).__post_init__() # pylint: disable=super-with-arguments # needed here b/c: dataclass
63
- if self.prime_modulus < 7 or not modmath.IsPrime(self.prime_modulus):
56
+ if self.prime_modulus < 7 or not modmath.IsPrime(self.prime_modulus): # noqa: PLR2004
64
57
  raise base.InputError(f'invalid prime_modulus: {self}')
65
- if not 2 < self.group_base < self.prime_modulus - 1:
58
+ if not 2 < self.group_base < self.prime_modulus - 1: # noqa: PLR2004
66
59
  raise base.InputError(f'invalid group_base: {self}')
67
60
 
68
61
  def __str__(self) -> str:
@@ -70,11 +63,14 @@ class ElGamalSharedPublicKey(base.CryptoKey):
70
63
 
71
64
  Returns:
72
65
  string representation of ElGamalSharedPublicKey
66
+
73
67
  """
74
- return ('ElGamalSharedPublicKey('
75
- f'bits={self.prime_modulus.bit_length()}, '
76
- f'prime_modulus={base.IntToEncoded(self.prime_modulus)}, '
77
- f'group_base={base.IntToEncoded(self.group_base)})')
68
+ return (
69
+ 'ElGamalSharedPublicKey('
70
+ f'bits={self.prime_modulus.bit_length()}, '
71
+ f'prime_modulus={base.IntToEncoded(self.prime_modulus)}, '
72
+ f'group_base={base.IntToEncoded(self.group_base)})'
73
+ )
78
74
 
79
75
  @property
80
76
  def modulus_size(self) -> int:
@@ -82,7 +78,8 @@ class ElGamalSharedPublicKey(base.CryptoKey):
82
78
  return (self.prime_modulus.bit_length() + 7) // 8
83
79
 
84
80
  def _DomainSeparatedHash(
85
- self, message: bytes, associated_data: bytes | None, salt: bytes, /) -> int:
81
+ self, message: bytes, associated_data: bytes | None, salt: bytes, /
82
+ ) -> int:
86
83
  """Compute the domain-separated hash for signing and verifying.
87
84
 
88
85
  Args:
@@ -96,12 +93,14 @@ class ElGamalSharedPublicKey(base.CryptoKey):
96
93
 
97
94
  Raises:
98
95
  CryptoError: hash output is out of range
96
+
99
97
  """
100
98
  aad: bytes = b'' if associated_data is None else associated_data
101
99
  la: bytes = base.IntToFixedBytes(len(aad), 8)
102
- assert len(salt) == 64, 'should never happen: salt should be exactly 64 bytes'
100
+ assert len(salt) == 64, 'should never happen: salt should be exactly 64 bytes' # noqa: PLR2004, S101
103
101
  y: int = base.BytesToInt(
104
- base.Hash512(_ELGAMAL_SIGNATURE_HASH_PREFIX + la + aad + message + salt))
102
+ base.Hash512(_ELGAMAL_SIGNATURE_HASH_PREFIX + la + aad + message + salt)
103
+ )
105
104
  if not 1 < y < self.prime_modulus:
106
105
  # will only reasonably happen if modulus is small
107
106
  raise base.CryptoError(f'hash output {y} is out of range/invalid {self.prime_modulus}')
@@ -119,14 +118,15 @@ class ElGamalSharedPublicKey(base.CryptoKey):
119
118
 
120
119
  Raises:
121
120
  InputError: invalid inputs
121
+
122
122
  """
123
123
  # test inputs
124
- if bit_length < 11:
124
+ if bit_length < 11: # noqa: PLR2004
125
125
  raise base.InputError(f'invalid bit length: {bit_length=}')
126
126
  # generate random prime and number, create object (should never fail)
127
127
  p: int = modmath.NBitRandomPrimes(bit_length).pop()
128
128
  g: int = 0
129
- while not 2 < g < p - 1:
129
+ while not 2 < g < p: # noqa: PLR2004
130
130
  g = base.RandBits(bit_length)
131
131
  return cls(prime_modulus=p, group_base=g)
132
132
 
@@ -139,6 +139,7 @@ class ElGamalPublicKey(ElGamalSharedPublicKey, base.Encryptor, base.Verifier):
139
139
 
140
140
  Attributes:
141
141
  individual_base (int): individual encryption public base, 3 ≤ i < prime_modulus
142
+
142
143
  """
143
144
 
144
145
  individual_base: int
@@ -148,10 +149,13 @@ class ElGamalPublicKey(ElGamalSharedPublicKey, base.Encryptor, base.Verifier):
148
149
 
149
150
  Raises:
150
151
  InputError: invalid inputs
152
+
151
153
  """
152
- super(ElGamalPublicKey, self).__post_init__() # pylint: disable=super-with-arguments # needed here b/c: dataclass
153
- if (not 2 < self.individual_base < self.prime_modulus - 1 or
154
- self.individual_base == self.group_base):
154
+ super(ElGamalPublicKey, self).__post_init__()
155
+ if (
156
+ not 2 < self.individual_base < self.prime_modulus - 1 # noqa: PLR2004
157
+ or self.individual_base == self.group_base
158
+ ):
155
159
  raise base.InputError(f'invalid individual_base: {self}')
156
160
 
157
161
  def __str__(self) -> str:
@@ -159,23 +163,29 @@ class ElGamalPublicKey(ElGamalSharedPublicKey, base.Encryptor, base.Verifier):
159
163
 
160
164
  Returns:
161
165
  string representation of ElGamalPublicKey
166
+
162
167
  """
163
- return ('ElGamalPublicKey('
164
- f'{super(ElGamalPublicKey, self).__str__()}, ' # pylint: disable=super-with-arguments
165
- f'individual_base={base.IntToEncoded(self.individual_base)})')
168
+ return (
169
+ 'ElGamalPublicKey('
170
+ f'{super(ElGamalPublicKey, self).__str__()}, '
171
+ f'individual_base={base.IntToEncoded(self.individual_base)})'
172
+ )
166
173
 
167
174
  def _MakeEphemeralKey(self) -> tuple[int, int]:
168
175
  """Make an ephemeral key adequate to be used with El-Gamal.
169
176
 
170
177
  Returns:
171
- (key, key_inverse), where 2 ≤ k < modulus - 1 and
178
+ (key, key_inverse), where 2 ≤ k < modulus and
172
179
  GCD(k, modulus - 1) == 1 and (k*i) % (p-1) == 1
180
+
173
181
  """
174
182
  ephemeral_key: int = 0
175
183
  p_1: int = self.prime_modulus - 1
176
184
  bit_length: int = self.prime_modulus.bit_length()
177
- while (not 1 < ephemeral_key < p_1 or
178
- ephemeral_key in (self.group_base, self.individual_base)):
185
+ while not 1 < ephemeral_key < self.prime_modulus or ephemeral_key in {
186
+ self.group_base,
187
+ self.individual_base,
188
+ }:
179
189
  ephemeral_key = base.RandBits(bit_length)
180
190
  if base.GCD(ephemeral_key, p_1) != 1:
181
191
  ephemeral_key = 0 # we have to try again
@@ -196,6 +206,7 @@ class ElGamalPublicKey(ElGamalSharedPublicKey, base.Encryptor, base.Verifier):
196
206
 
197
207
  Raises:
198
208
  InputError: invalid inputs
209
+
199
210
  """
200
211
  # test inputs
201
212
  if not 0 < message < self.prime_modulus:
@@ -203,10 +214,10 @@ class ElGamalPublicKey(ElGamalSharedPublicKey, base.Encryptor, base.Verifier):
203
214
  # encrypt
204
215
  a: int = 0
205
216
  b: int = 0
206
- while a < 2 or b < 2:
217
+ while a < 2 or b < 2: # noqa: PLR2004
207
218
  ephemeral_key: int = self._MakeEphemeralKey()[0]
208
- a = int(gmpy2.powmod(self.group_base, ephemeral_key, self.prime_modulus)) # type:ignore # pylint:disable=no-member
209
- s: int = int(gmpy2.powmod(self.individual_base, ephemeral_key, self.prime_modulus)) # type:ignore # pylint:disable=no-member
219
+ a = int(gmpy2.powmod(self.group_base, ephemeral_key, self.prime_modulus))
220
+ s: int = int(gmpy2.powmod(self.individual_base, ephemeral_key, self.prime_modulus))
210
221
  b = (message * s) % self.prime_modulus
211
222
  return (a, b)
212
223
 
@@ -237,23 +248,19 @@ class ElGamalPublicKey(ElGamalSharedPublicKey, base.Encryptor, base.Verifier):
237
248
  associated_data="prefix" + len(aad) + aad +
238
249
  Padded(ct1, k) + Padded(ct2, k))
239
250
 
240
- Raises:
241
- InputError: invalid inputs
242
- CryptoError: internal crypto failures
243
251
  """
244
252
  # generate random r and encrypt it
245
253
  r: int = 0
246
- while not 1 < r < self.prime_modulus - 1:
254
+ while not 1 < r < self.prime_modulus:
247
255
  r = base.RandBits(self.prime_modulus.bit_length())
248
256
  k: int = self.modulus_size
249
257
  i_ct: tuple[int, int] = self.RawEncrypt(r)
250
258
  ct: bytes = base.IntToFixedBytes(i_ct[0], k) + base.IntToFixedBytes(i_ct[1], k)
251
- assert len(ct) == 2 * k, 'should never happen: c_kem should be exactly 2k bytes'
259
+ assert len(ct) == 2 * k, 'should never happen: c_kem should be exactly 2k bytes' # noqa: S101
252
260
  # encrypt plaintext with AES-256-GCM using SHA512(r)[32:] as key; return ct || Encrypt(...)
253
261
  ss: bytes = base.Hash512(base.IntToFixedBytes(r, k))
254
262
  aad: bytes = b'' if associated_data is None else associated_data
255
- aad_prime: bytes = (
256
- _ELGAMAL_ENCRYPTION_AAD_PREFIX + base.IntToFixedBytes(len(aad), 8) + aad + ct)
263
+ aad_prime: bytes = _ELGAMAL_ENCRYPTION_AAD_PREFIX + base.IntToFixedBytes(len(aad), 8) + aad + ct
257
264
  return ct + aes.AESKey(key256=ss[32:]).Encrypt(plaintext, associated_data=aad_prime)
258
265
 
259
266
  def RawVerify(self, message: int, signature: tuple[int, int], /) -> bool:
@@ -272,21 +279,22 @@ class ElGamalPublicKey(ElGamalSharedPublicKey, base.Encryptor, base.Verifier):
272
279
 
273
280
  Raises:
274
281
  InputError: invalid inputs
282
+
275
283
  """
276
284
  # test inputs
277
285
  if not 0 < message < self.prime_modulus:
278
286
  raise base.InputError(f'invalid message: {message=}')
279
- if (not 2 <= signature[0] < self.prime_modulus or
280
- not 2 <= signature[1] < self.prime_modulus - 1):
287
+ if not 2 <= signature[0] < self.prime_modulus or not 2 <= signature[1] < self.prime_modulus - 1: # noqa: PLR2004
281
288
  raise base.InputError(f'invalid signature: {signature=}')
282
289
  # verify
283
- a: int = int(gmpy2.powmod(self.group_base, message, self.prime_modulus)) # type:ignore # pylint:disable=no-member
284
- b: int = int(gmpy2.powmod(signature[0], signature[1], self.prime_modulus)) # type:ignore # pylint:disable=no-member
285
- c: int = int(gmpy2.powmod(self.individual_base, signature[0], self.prime_modulus)) # type:ignore # pylint:disable=no-member
290
+ a: int = int(gmpy2.powmod(self.group_base, message, self.prime_modulus))
291
+ b: int = int(gmpy2.powmod(signature[0], signature[1], self.prime_modulus))
292
+ c: int = int(gmpy2.powmod(self.individual_base, signature[0], self.prime_modulus))
286
293
  return a == (b * c) % self.prime_modulus
287
294
 
288
295
  def Verify(
289
- self, message: bytes, signature: bytes, /, *, associated_data: bytes | None = None) -> bool:
296
+ self, message: bytes, signature: bytes, /, *, associated_data: bytes | None = None
297
+ ) -> bool:
290
298
  """Verify a `signature` for `message`. True if OK; False if failed verification.
291
299
 
292
300
  • Let k = ceil(log2(n))/8 be the modulus size in bytes.
@@ -305,39 +313,50 @@ class ElGamalPublicKey(ElGamalSharedPublicKey, base.Encryptor, base.Verifier):
305
313
 
306
314
  Raises:
307
315
  InputError: invalid inputs
308
- CryptoError: internal crypto failures, authentication failure, key mismatch, etc
316
+
309
317
  """
310
318
  k: int = self.modulus_size
311
- if k <= 64:
319
+ if k <= 64: # noqa: PLR2004
312
320
  raise base.InputError(f'modulus too small for signing operations: {k} bytes')
313
321
  if len(signature) != (64 + k + k):
314
322
  logging.info(f'invalid signature length: {len(signature)} ; expected {64 + k + k}')
315
323
  return False
316
324
  try:
317
325
  return self.RawVerify(
318
- self._DomainSeparatedHash(message, associated_data, signature[:64]),
319
- (base.BytesToInt(signature[64:64 + k]), base.BytesToInt(signature[64 + k:])))
326
+ self._DomainSeparatedHash(message, associated_data, signature[:64]),
327
+ (base.BytesToInt(signature[64 : 64 + k]), base.BytesToInt(signature[64 + k :])),
328
+ )
320
329
  except base.InputError as err:
321
330
  logging.info(err)
322
331
  return False
323
332
 
324
333
  @classmethod
325
334
  def Copy(cls, other: ElGamalPublicKey, /) -> Self:
326
- """Initialize a public key by taking the public parts of a public/private key."""
335
+ """Initialize a public key by taking the public parts of a public/private key.
336
+
337
+ Args:
338
+ other (ElGamalPublicKey): object to copy from
339
+
340
+ Returns:
341
+ Self: a new ElGamalPublicKey
342
+
343
+ """
327
344
  return cls(
328
- prime_modulus=other.prime_modulus,
329
- group_base=other.group_base,
330
- individual_base=other.individual_base)
345
+ prime_modulus=other.prime_modulus,
346
+ group_base=other.group_base,
347
+ individual_base=other.individual_base,
348
+ )
331
349
 
332
350
 
333
351
  @dataclasses.dataclass(kw_only=True, slots=True, frozen=True, repr=False)
334
- class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylint: disable=too-many-ancestors
352
+ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer):
335
353
  """El-Gamal private key.
336
354
 
337
355
  BEWARE: This is **NOT** DSA! No measures are taken here to prevent timing attacks.
338
356
 
339
357
  Attributes:
340
358
  decrypt_exp (int): individual decryption exponent, 3 ≤ i < prime_modulus
359
+
341
360
  """
342
361
 
343
362
  decrypt_exp: int
@@ -348,12 +367,15 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
348
367
  Raises:
349
368
  InputError: invalid inputs
350
369
  CryptoError: modulus math is inconsistent with values
370
+
351
371
  """
352
- super(ElGamalPrivateKey, self).__post_init__() # pylint: disable=super-with-arguments # needed here b/c: dataclass
353
- if (not 2 < self.decrypt_exp < self.prime_modulus - 1 or
354
- self.decrypt_exp in (self.group_base, self.individual_base)):
372
+ super(ElGamalPrivateKey, self).__post_init__()
373
+ if not 2 < self.decrypt_exp < self.prime_modulus - 1 or self.decrypt_exp in { # noqa: PLR2004
374
+ self.group_base,
375
+ self.individual_base,
376
+ }:
355
377
  raise base.InputError(f'invalid decrypt_exp: {self}')
356
- if gmpy2.powmod(self.group_base, self.decrypt_exp, self.prime_modulus) != self.individual_base: # type:ignore # pylint:disable=no-member
378
+ if gmpy2.powmod(self.group_base, self.decrypt_exp, self.prime_modulus) != self.individual_base:
357
379
  raise base.CryptoError(f'inconsistent g**e % p == i: {self}')
358
380
 
359
381
  def __str__(self) -> str:
@@ -361,10 +383,13 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
361
383
 
362
384
  Returns:
363
385
  string representation of ElGamalPrivateKey without leaking secrets
386
+
364
387
  """
365
- return ('ElGamalPrivateKey('
366
- f'{super(ElGamalPrivateKey, self).__str__()}, ' # pylint: disable=super-with-arguments
367
- f'decrypt_exp={base.ObfuscateSecret(self.decrypt_exp)})')
388
+ return (
389
+ 'ElGamalPrivateKey('
390
+ f'{super(ElGamalPrivateKey, self).__str__()}, '
391
+ f'decrypt_exp={base.ObfuscateSecret(self.decrypt_exp)})'
392
+ )
368
393
 
369
394
  def RawDecrypt(self, ciphertext: tuple[int, int], /) -> int:
370
395
  """Decrypt `ciphertext` tuple with this private key.
@@ -380,14 +405,15 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
380
405
 
381
406
  Raises:
382
407
  InputError: invalid inputs
408
+
383
409
  """
384
410
  # test inputs
385
- if (not 2 <= ciphertext[0] < self.prime_modulus or
386
- not 2 <= ciphertext[1] < self.prime_modulus):
411
+ if not 2 <= ciphertext[0] < self.prime_modulus or not 2 <= ciphertext[1] < self.prime_modulus: # noqa: PLR2004
387
412
  raise base.InputError(f'invalid message: {ciphertext=}')
388
413
  # decrypt
389
414
  csi: int = int(
390
- gmpy2.powmod(ciphertext[0], self.prime_modulus - 1 - self.decrypt_exp, self.prime_modulus)) # type:ignore # pylint:disable=no-member
415
+ gmpy2.powmod(ciphertext[0], self.prime_modulus - 1 - self.decrypt_exp, self.prime_modulus)
416
+ )
391
417
  return (ciphertext[1] * csi) % self.prime_modulus
392
418
 
393
419
  def Decrypt(self, ciphertext: bytes, /, *, associated_data: bytes | None = None) -> bytes:
@@ -412,18 +438,19 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
412
438
 
413
439
  Raises:
414
440
  InputError: invalid inputs
415
- CryptoError: internal crypto failures, authentication failure, key mismatch, etc
441
+
416
442
  """
417
443
  k: int = self.modulus_size
418
444
  if len(ciphertext) < (k + k + 32):
419
445
  raise base.InputError(f'invalid ciphertext length: {len(ciphertext)} ; {k=}')
420
446
  # split ciphertext in 3 parts: the first 2k bytes is ct, the rest is AES-256-GCM
421
- ct1, ct2, aes_ct = ciphertext[:k], ciphertext[k:2 * k], ciphertext[2 * k:]
447
+ ct1, ct2, aes_ct = ciphertext[:k], ciphertext[k : 2 * k], ciphertext[2 * k :]
422
448
  r: int = self.RawDecrypt((base.BytesToInt(ct1), base.BytesToInt(ct2)))
423
449
  ss: bytes = base.Hash512(base.IntToFixedBytes(r, k))
424
450
  aad: bytes = b'' if associated_data is None else associated_data
425
451
  aad_prime: bytes = (
426
- _ELGAMAL_ENCRYPTION_AAD_PREFIX + base.IntToFixedBytes(len(aad), 8) + aad + ct1 + ct2)
452
+ _ELGAMAL_ENCRYPTION_AAD_PREFIX + base.IntToFixedBytes(len(aad), 8) + aad + ct1 + ct2
453
+ )
427
454
  return aes.AESKey(key256=ss[32:]).Decrypt(aes_ct, associated_data=aad_prime)
428
455
 
429
456
  def RawSign(self, message: int, /) -> tuple[int, int]:
@@ -441,6 +468,7 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
441
468
 
442
469
  Raises:
443
470
  InputError: invalid inputs
471
+
444
472
  """
445
473
  # test inputs
446
474
  if not 0 < message < self.prime_modulus:
@@ -449,9 +477,9 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
449
477
  a: int = 0
450
478
  b: int = 0
451
479
  p_1: int = self.prime_modulus - 1
452
- while a < 2 or b < 2:
480
+ while a < 2 or b < 2: # noqa: PLR2004
453
481
  ephemeral_key, ephemeral_inv = self._MakeEphemeralKey()
454
- a = int(gmpy2.powmod(self.group_base, ephemeral_key, self.prime_modulus)) # type:ignore # pylint:disable=no-member
482
+ a = int(gmpy2.powmod(self.group_base, ephemeral_key, self.prime_modulus))
455
483
  b = (ephemeral_inv * ((message - a * self.decrypt_exp) % p_1)) % p_1
456
484
  return (a, b)
457
485
 
@@ -478,15 +506,15 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
478
506
 
479
507
  Raises:
480
508
  InputError: invalid inputs
481
- CryptoError: internal crypto failures
509
+
482
510
  """
483
511
  k: int = self.modulus_size
484
- if k <= 64:
512
+ if k <= 64: # noqa: PLR2004
485
513
  raise base.InputError(f'modulus too small for signing operations: {k} bytes')
486
514
  salt: bytes = base.RandBytes(64)
487
515
  s_int: tuple[int, int] = self.RawSign(self._DomainSeparatedHash(message, associated_data, salt))
488
516
  s_bytes: bytes = base.IntToFixedBytes(s_int[0], k) + base.IntToFixedBytes(s_int[1], k)
489
- assert len(s_bytes) == 2 * k, 'should never happen: s_bytes should be exactly 2k bytes'
517
+ assert len(s_bytes) == 2 * k, 'should never happen: s_bytes should be exactly 2k bytes' # noqa: S101
490
518
  return salt + s_bytes
491
519
 
492
520
  @classmethod
@@ -502,10 +530,11 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
502
530
  Raises:
503
531
  InputError: invalid inputs
504
532
  CryptoError: failed generation
533
+
505
534
  """
506
535
  # test inputs
507
536
  bit_length: int = shared_key.prime_modulus.bit_length()
508
- if bit_length < 11:
537
+ if bit_length < 11: # noqa: PLR2004
509
538
  raise base.InputError(f'invalid bit length: {bit_length=}')
510
539
  # loop until we have an object
511
540
  failures: int = 0
@@ -513,16 +542,19 @@ class ElGamalPrivateKey(ElGamalPublicKey, base.Decryptor, base.Signer): # pylin
513
542
  try:
514
543
  # generate private key differing from group_base
515
544
  decrypt_exp: int = 0
516
- while (not 2 < decrypt_exp < shared_key.prime_modulus - 1 or
517
- decrypt_exp == shared_key.group_base):
545
+ while (
546
+ not 2 < decrypt_exp < shared_key.prime_modulus or decrypt_exp == shared_key.group_base # noqa: PLR2004
547
+ ):
518
548
  decrypt_exp = base.RandBits(bit_length)
519
549
  # make the object
520
550
  return cls(
521
- prime_modulus=shared_key.prime_modulus,
522
- group_base=shared_key.group_base,
523
- individual_base=int(gmpy2.powmod( # type:ignore # pylint:disable=no-member
524
- shared_key.group_base, decrypt_exp, shared_key.prime_modulus)),
525
- decrypt_exp=decrypt_exp)
551
+ prime_modulus=shared_key.prime_modulus,
552
+ group_base=shared_key.group_base,
553
+ individual_base=int(
554
+ gmpy2.powmod(shared_key.group_base, decrypt_exp, shared_key.prime_modulus)
555
+ ),
556
+ decrypt_exp=decrypt_exp,
557
+ )
526
558
  except base.InputError as err:
527
559
  failures += 1
528
560
  if failures >= _MAX_KEY_GENERATION_FAILURES: