transcrypto 1.4.0__py3-none-any.whl → 1.6.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/base.py CHANGED
@@ -11,7 +11,7 @@ import argparse
11
11
  import base64
12
12
  import codecs
13
13
  import dataclasses
14
- # import datetime
14
+ import datetime
15
15
  import enum
16
16
  import functools
17
17
  import hashlib
@@ -24,19 +24,21 @@ import pickle
24
24
  import secrets
25
25
  import sys
26
26
  import time
27
+ import threading
27
28
  from typing import Any, Callable, final, MutableSequence, Protocol, runtime_checkable
28
29
  from typing import Sequence, Self, TypeVar
29
30
 
30
31
  import numpy as np
32
+ from rich import console as rich_console
33
+ from rich import logging as rich_logging
31
34
  from scipy import stats # type:ignore
32
35
  import zstandard
33
36
 
34
37
  __author__ = 'balparda@github.com'
35
- __version__ = '1.4.0' # 2026-01-13, Tue
38
+ __version__ = '1.6.0' # 2026-01-15, Thu
36
39
  __version_tuple__: tuple[int, ...] = tuple(int(v) for v in __version__.split('.'))
37
40
 
38
- # MIN_TM = int( # minimum allowed timestamp
39
- # datetime.datetime(2000, 1, 1, 0, 0, 0).replace(tzinfo=datetime.timezone.utc).timestamp())
41
+ # Data conversion utils
40
42
 
41
43
  BytesToHex: Callable[[bytes], str] = lambda b: b.hex()
42
44
  BytesToInt: Callable[[bytes], int] = lambda b: int.from_bytes(b, 'big', signed=False)
@@ -50,6 +52,28 @@ EncodedToBytes: Callable[[str], bytes] = lambda e: base64.urlsafe_b64decode(e.en
50
52
 
51
53
  PadBytesTo: Callable[[bytes, int], bytes] = lambda b, i: b.rjust((i + 7) // 8, b'\x00')
52
54
 
55
+ # Time utils
56
+
57
+ MIN_TM = int(
58
+ datetime.datetime(2000, 1, 1, 0, 0, 0).replace(tzinfo=datetime.timezone.utc).timestamp())
59
+ TIME_FORMAT = '%Y/%b/%d-%H:%M:%S-UTC'
60
+ TimeStr: Callable[[int | float | None], str] = lambda tm: (
61
+ time.strftime(TIME_FORMAT, time.gmtime(tm)) if tm else '-')
62
+ Now: Callable[[], int] = lambda: int(time.time())
63
+ StrNow: Callable[[], str] = lambda: TimeStr(Now())
64
+
65
+ # Logging
66
+ _LOG_FORMAT_NO_PROCESS: str = '%(funcName)s: %(message)s'
67
+ _LOG_FORMAT_WITH_PROCESS: str = '%(processName)s/' + _LOG_FORMAT_NO_PROCESS
68
+ _LOG_FORMAT_DATETIME: str = '[%Y%m%d-%H:%M:%S]' # e.g., [20240131-13:45:30]
69
+ _LOG_LEVELS: list[int] = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG]
70
+ _LOG_COMMON_PROVIDERS: set[str] = {
71
+ 'werkzeug',
72
+ 'gunicorn.error', 'gunicorn.access',
73
+ 'uvicorn', 'uvicorn.error', 'uvicorn.access',
74
+ 'django.server',
75
+ }
76
+
53
77
  # SI prefix table, powers of 1000
54
78
  _SI_PREFIXES: dict[int, str] = {
55
79
  -6: 'a', # atto
@@ -106,6 +130,75 @@ class ImplementationError(Error, NotImplementedError):
106
130
  """This feature is not implemented yet (TransCrypto)."""
107
131
 
108
132
 
133
+ __console_lock = threading.RLock()
134
+ __console_singleton: rich_console.Console | None = None
135
+
136
+
137
+ def Console() -> rich_console.Console:
138
+ """Get the global console instance.
139
+
140
+ Returns:
141
+ rich.console.Console: The global console instance.
142
+ """
143
+ with __console_lock:
144
+ if __console_singleton is None:
145
+ return rich_console.Console() # fallback console if InitLogging hasn't been called yet
146
+ return __console_singleton
147
+
148
+
149
+ def ResetConsole() -> None:
150
+ """Reset the global console instance."""
151
+ global __console_singleton # pylint: disable=global-statement
152
+ with __console_lock:
153
+ __console_singleton = None
154
+
155
+
156
+ def InitLogging(
157
+ verbosity: int, /, *,
158
+ include_process: bool = False, soft_wrap: bool = False) -> rich_console.Console:
159
+ """Initialize logger (with RichHandler).
160
+
161
+ If you have a CLI app that uses this, its pytests should call `ResetConsole()` in a fixture, like:
162
+
163
+ from transcrypto import base
164
+ @pytest.fixture(autouse=True)
165
+ def _reset_base_logging():
166
+ base.ResetConsole()
167
+ yield
168
+
169
+ Args:
170
+ verbosity (int): Logging verbosity level.
171
+ include_process (bool, optional): Whether to include process name in log output.
172
+ soft_wrap (bool, optional): Whether to enable soft wrapping in the console.
173
+ Default is False, and it means rich will hard-wrap long lines (by adding '\n' chars).
174
+
175
+ Returns:
176
+ rich.console.Console: The initialized console instance.
177
+ """
178
+ global __console_singleton # pylint: disable=global-statement
179
+ with __console_lock:
180
+ if __console_singleton is not None:
181
+ return __console_singleton
182
+ logging_level: int = _LOG_LEVELS[max(0, min(verbosity, len(_LOG_LEVELS) - 1))]
183
+ console = rich_console.Console(soft_wrap=soft_wrap)
184
+ logging.basicConfig(
185
+ level=logging_level,
186
+ format=_LOG_FORMAT_WITH_PROCESS if include_process else _LOG_FORMAT_NO_PROCESS,
187
+ datefmt=_LOG_FORMAT_DATETIME,
188
+ handlers=[rich_logging.RichHandler( # we show name/line, but want time & level
189
+ console=console, rich_tracebacks=True, show_time=True, show_level=True, show_path=True)],
190
+ force=True) # force=True to override any previous logging config
191
+ logging.captureWarnings(True)
192
+ for name in _LOG_COMMON_PROVIDERS:
193
+ log: logging.Logger = logging.getLogger(name)
194
+ log.handlers.clear()
195
+ log.propagate = True
196
+ log.setLevel(logging_level)
197
+ __console_singleton = console # need a global statement to re-bind this one
198
+ logging.info(f'Logging initialized at level {logging.getLevelName(logging_level)}')
199
+ return console
200
+
201
+
109
202
  def HumanizedBytes(inp_sz: int | float, /) -> str: # pylint: disable=too-many-return-statements
110
203
  """Convert a byte count into a human-readable string using binary prefixes (powers of 1024).
111
204
 
@@ -460,7 +553,7 @@ class Timer:
460
553
  if self.emit_log:
461
554
  logging.info(message)
462
555
  if self.emit_print:
463
- print(message)
556
+ Console().print(message)
464
557
 
465
558
  def __exit__(
466
559
  self, unused_exc_type: type[BaseException] | None,
transcrypto/profiler.py CHANGED
@@ -16,11 +16,12 @@ doc md
16
16
  from __future__ import annotations
17
17
 
18
18
  import argparse
19
- import logging
20
19
  # import pdb
21
20
  import sys
22
21
  from typing import Callable
23
22
 
23
+ from rich import console as rich_console
24
+
24
25
  from . import base, modmath, dsa
25
26
 
26
27
  __author__ = 'balparda@github.com'
@@ -107,7 +108,8 @@ def _BuildParser() -> argparse.ArgumentParser: # pylint: disable=too-many-state
107
108
 
108
109
  def _PrimeProfiler(
109
110
  prime_callable: Callable[[int], int],
110
- repeats: int, n_bits_range: tuple[int, int, int], confidence: float, /) -> None:
111
+ repeats: int, n_bits_range: tuple[int, int, int], confidence: float,
112
+ console: rich_console.Console, /) -> None:
111
113
  primes: dict[int, list[float]] = {}
112
114
  for n_bits in range(*n_bits_range):
113
115
  # investigate for size n_bits
@@ -120,7 +122,7 @@ def _PrimeProfiler(
120
122
  # finished collecting n_bits-sized primes
121
123
  measurements: str = base.HumanizedMeasurements(
122
124
  primes[n_bits], parser=base.HumanizedSeconds, confidence=confidence)
123
- print(f'{n_bits} → {measurements}')
125
+ console.print(f'{n_bits} → {measurements}')
124
126
 
125
127
 
126
128
  def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-name,too-many-locals,too-many-branches,too-many-statements
@@ -129,11 +131,7 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
129
131
  parser: argparse.ArgumentParser = _BuildParser()
130
132
  args: argparse.Namespace = parser.parse_args(argv)
131
133
  # take care of global options
132
- levels: list[int] = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG]
133
- logging.basicConfig(
134
- level=levels[min(args.verbose, len(levels) - 1)], # type: ignore
135
- format=getattr(base, 'LOG_FORMAT', '%(levelname)s:%(message)s'))
136
- logging.captureWarnings(True)
134
+ console: rich_console.Console = base.InitLogging(args.verbose)
137
135
 
138
136
  try:
139
137
  # get the command, do basic checks and switch
@@ -149,16 +147,16 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
149
147
  match command:
150
148
  # -------- Primes ----------
151
149
  case 'primes':
152
- print(f'Starting {"SERIAL" if args.serial else "PARALLEL"} regular primes test')
150
+ console.print(f'Starting {"SERIAL" if args.serial else "PARALLEL"} regular primes test')
153
151
  _PrimeProfiler(
154
152
  lambda n: modmath.NBitRandomPrimes(n, serial=args.serial, n_primes=1).pop(),
155
- repeats, bits, confidence / 100.0)
153
+ repeats, bits, confidence / 100.0, console)
156
154
 
157
155
  case 'dsa':
158
- print(f'Starting {"SERIAL" if args.serial else "PARALLEL"} DSA primes test')
156
+ console.print(f'Starting {"SERIAL" if args.serial else "PARALLEL"} DSA primes test')
159
157
  _PrimeProfiler(
160
158
  lambda n: dsa.NBitRandomDSAPrimes(n, n // 2, serial=args.serial)[0],
161
- repeats, bits, confidence / 100.0)
159
+ repeats, bits, confidence / 100.0, console)
162
160
 
163
161
  # -------- Documentation ----------
164
162
  case 'doc':
@@ -166,7 +164,7 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
166
164
  args.doc_command.lower().strip() if getattr(args, 'doc_command', '') else '')
167
165
  match doc_command:
168
166
  case 'md':
169
- print(base.GenerateCLIMarkdown(
167
+ console.print(base.GenerateCLIMarkdown(
170
168
  'profiler', _BuildParser(), description=(
171
169
  '`profiler` is a command-line utility that provides stats on TransCrypto '
172
170
  'performance.')))
@@ -177,12 +175,12 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
177
175
  parser.print_help()
178
176
 
179
177
  if command not in ('doc',):
180
- print(f'Finished in {tmr}')
178
+ console.print(f'Finished in {tmr}')
181
179
 
182
180
  except NotImplementedError as err:
183
- print(f'Invalid command: {err}')
181
+ console.print(f'Invalid command: {err}')
184
182
  except (base.Error, ValueError) as err:
185
- print(str(err))
183
+ console.print(str(err))
186
184
 
187
185
  return 0
188
186
 
transcrypto/safetrans.py CHANGED
@@ -693,10 +693,11 @@ If you want, I can fill in concrete implementations next (e.g., Miller–Rabin f
693
693
  from __future__ import annotations
694
694
 
695
695
  import argparse
696
- import logging
697
696
  # import pdb
698
697
  import sys
699
698
 
699
+ from rich import console as rich_console
700
+
700
701
  from . import base
701
702
 
702
703
  __author__ = 'balparda@github.com'
@@ -1185,11 +1186,7 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1185
1186
  parser: argparse.ArgumentParser = _BuildParser()
1186
1187
  args: argparse.Namespace = parser.parse_args(argv)
1187
1188
  # take care of global options
1188
- levels: list[int] = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG]
1189
- logging.basicConfig(
1190
- level=levels[min(args.verbose, len(levels) - 1)], # type: ignore
1191
- format=getattr(base, 'LOG_FORMAT', '%(levelname)s:%(message)s'))
1192
- logging.captureWarnings(True)
1189
+ console: rich_console.Console = base.InitLogging(args.verbose, soft_wrap=True)
1193
1190
 
1194
1191
  try:
1195
1192
  # get the command, do basic checks and switch
@@ -1205,7 +1202,7 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1205
1202
  args.doc_command.lower().strip() if getattr(args, 'doc_command', '') else '')
1206
1203
  match doc_command:
1207
1204
  case 'md':
1208
- print(base.GenerateCLIMarkdown(
1205
+ console.print(base.GenerateCLIMarkdown(
1209
1206
  'safetrans', _BuildParser(), description=(
1210
1207
  '`safetrans` is a command-line utility that provides ***safe*** crypto '
1211
1208
  'primitives. It serves as a convenient wrapper over the Python APIs, '
@@ -1220,9 +1217,9 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1220
1217
  parser.print_help()
1221
1218
 
1222
1219
  except NotImplementedError as err:
1223
- print(f'Invalid command: {err}')
1220
+ console.print(f'Invalid command: {err}')
1224
1221
  except (base.Error, ValueError) as err:
1225
- print(str(err))
1222
+ console.print(str(err))
1226
1223
 
1227
1224
  return 0
1228
1225
 
@@ -31,6 +31,8 @@ import logging
31
31
  import sys
32
32
  from typing import Any, Iterable
33
33
 
34
+ from rich import console as rich_console
35
+
34
36
  from . import base, modmath, rsa, sss, elgamal, dsa, aes
35
37
 
36
38
  __author__ = 'balparda@github.com'
@@ -944,7 +946,8 @@ def _BuildParser() -> argparse.ArgumentParser: # pylint: disable=too-many-state
944
946
 
945
947
 
946
948
  def AESCommand(
947
- args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType, /) -> None:
949
+ args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType,
950
+ console: rich_console.Console, /) -> None:
948
951
  """Execute `aes` command."""
949
952
  pt: bytes
950
953
  ct: bytes
@@ -965,26 +968,26 @@ def AESCommand(
965
968
  aes_key = aes.AESKey.FromStaticPassword(args.password)
966
969
  if args.key_path:
967
970
  _SaveObj(aes_key, args.key_path, args.protect or None)
968
- print(f'AES key saved to {args.key_path!r}')
971
+ console.print(f'AES key saved to {args.key_path!r}')
969
972
  else:
970
- print(_BytesToText(aes_key.key256, out_format))
973
+ console.print(_BytesToText(aes_key.key256, out_format))
971
974
  case 'encrypt':
972
975
  pt = _BytesFromText(args.plaintext, in_format)
973
976
  ct = aes_key.Encrypt(pt, associated_data=aad)
974
- print(_BytesToText(ct, out_format))
977
+ console.print(_BytesToText(ct, out_format))
975
978
  case 'decrypt':
976
979
  ct = _BytesFromText(args.ciphertext, in_format)
977
980
  pt = aes_key.Decrypt(ct, associated_data=aad)
978
- print(_BytesToText(pt, out_format))
981
+ console.print(_BytesToText(pt, out_format))
979
982
  case 'ecb':
980
983
  ecb_cmd: str = args.aes_ecb_command.lower().strip() if args.aes_ecb_command else ''
981
984
  match ecb_cmd:
982
985
  case 'encrypt':
983
986
  ecb: aes.AESKey.ECBEncoderClass = aes_key.ECBEncoder()
984
- print(ecb.EncryptHex(args.plaintext))
987
+ console.print(ecb.EncryptHex(args.plaintext))
985
988
  case 'decrypt':
986
989
  ecb = aes_key.ECBEncoder()
987
- print(ecb.DecryptHex(args.ciphertext))
990
+ console.print(ecb.DecryptHex(args.ciphertext))
988
991
  case _:
989
992
  raise NotImplementedError()
990
993
  case _:
@@ -992,7 +995,8 @@ def AESCommand(
992
995
 
993
996
 
994
997
  def RSACommand(
995
- args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType, /) -> None:
998
+ args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType,
999
+ console: rich_console.Console, /) -> None:
996
1000
  """Execute `rsa` command."""
997
1001
  c: int
998
1002
  m: int
@@ -1010,53 +1014,54 @@ def RSACommand(
1010
1014
  rsa_pub = rsa.RSAPublicKey.Copy(rsa_priv)
1011
1015
  _SaveObj(rsa_priv, args.key_path + '.priv', args.protect or None)
1012
1016
  _SaveObj(rsa_pub, args.key_path + '.pub', args.protect or None)
1013
- print(f'RSA private/public keys saved to {args.key_path + ".priv/.pub"!r}')
1017
+ console.print(f'RSA private/public keys saved to {args.key_path + ".priv/.pub"!r}')
1014
1018
  case 'rawencrypt':
1015
1019
  rsa_pub = rsa.RSAPublicKey.Copy(
1016
1020
  _LoadObj(args.key_path, args.protect or None, rsa.RSAPublicKey))
1017
1021
  m = _ParseInt(args.message)
1018
- print(rsa_pub.RawEncrypt(m))
1022
+ console.print(rsa_pub.RawEncrypt(m))
1019
1023
  case 'rawdecrypt':
1020
1024
  rsa_priv = _LoadObj(args.key_path, args.protect or None, rsa.RSAPrivateKey)
1021
1025
  c = _ParseInt(args.ciphertext)
1022
- print(rsa_priv.RawDecrypt(c))
1026
+ console.print(rsa_priv.RawDecrypt(c))
1023
1027
  case 'rawsign':
1024
1028
  rsa_priv = _LoadObj(args.key_path, args.protect or None, rsa.RSAPrivateKey)
1025
1029
  m = _ParseInt(args.message)
1026
- print(rsa_priv.RawSign(m))
1030
+ console.print(rsa_priv.RawSign(m))
1027
1031
  case 'rawverify':
1028
1032
  rsa_pub = rsa.RSAPublicKey.Copy(
1029
1033
  _LoadObj(args.key_path, args.protect or None, rsa.RSAPublicKey))
1030
1034
  m = _ParseInt(args.message)
1031
1035
  sig: int = _ParseInt(args.signature)
1032
- print('RSA signature: ' + ('OK' if rsa_pub.RawVerify(m, sig) else 'INVALID'))
1036
+ console.print('RSA signature: ' + ('OK' if rsa_pub.RawVerify(m, sig) else 'INVALID'))
1033
1037
  case 'encrypt':
1034
1038
  rsa_pub = _LoadObj(args.key_path, args.protect or None, rsa.RSAPublicKey)
1035
1039
  pt = _BytesFromText(args.plaintext, in_format)
1036
1040
  ct = rsa_pub.Encrypt(pt, associated_data=aad)
1037
- print(_BytesToText(ct, out_format))
1041
+ console.print(_BytesToText(ct, out_format))
1038
1042
  case 'decrypt':
1039
1043
  rsa_priv = _LoadObj(args.key_path, args.protect or None, rsa.RSAPrivateKey)
1040
1044
  ct = _BytesFromText(args.ciphertext, in_format)
1041
1045
  pt = rsa_priv.Decrypt(ct, associated_data=aad)
1042
- print(_BytesToText(pt, out_format))
1046
+ console.print(_BytesToText(pt, out_format))
1043
1047
  case 'sign':
1044
1048
  rsa_priv = _LoadObj(args.key_path, args.protect or None, rsa.RSAPrivateKey)
1045
1049
  pt = _BytesFromText(args.message, in_format)
1046
1050
  ct = rsa_priv.Sign(pt, associated_data=aad)
1047
- print(_BytesToText(ct, out_format))
1051
+ console.print(_BytesToText(ct, out_format))
1048
1052
  case 'verify':
1049
1053
  rsa_pub = _LoadObj(args.key_path, args.protect or None, rsa.RSAPublicKey)
1050
1054
  pt = _BytesFromText(args.message, in_format)
1051
1055
  ct = _BytesFromText(args.signature, in_format)
1052
- print('RSA signature: ' +
1053
- ('OK' if rsa_pub.Verify(pt, ct, associated_data=aad) else 'INVALID'))
1056
+ console.print(
1057
+ 'RSA signature: ' + ('OK' if rsa_pub.Verify(pt, ct, associated_data=aad) else 'INVALID'))
1054
1058
  case _:
1055
1059
  raise NotImplementedError()
1056
1060
 
1057
1061
 
1058
1062
  def ElGamalCommand( # pylint: disable=too-many-statements
1059
- args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType, /) -> None:
1063
+ args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType,
1064
+ console: rich_console.Console, /) -> None:
1060
1065
  """Execute `elgamal` command."""
1061
1066
  c1: str
1062
1067
  c2: str
@@ -1075,64 +1080,66 @@ def ElGamalCommand( # pylint: disable=too-many-statements
1075
1080
  shared_eg: elgamal.ElGamalSharedPublicKey = elgamal.ElGamalSharedPublicKey.NewShared(
1076
1081
  args.bits)
1077
1082
  _SaveObj(shared_eg, args.key_path + '.shared', args.protect or None)
1078
- print(f'El-Gamal shared key saved to {args.key_path + ".shared"!r}')
1083
+ console.print(f'El-Gamal shared key saved to {args.key_path + ".shared"!r}')
1079
1084
  case 'new':
1080
1085
  eg_priv = elgamal.ElGamalPrivateKey.New(
1081
1086
  _LoadObj(args.key_path + '.shared', args.protect or None, elgamal.ElGamalSharedPublicKey))
1082
1087
  eg_pub = elgamal.ElGamalPublicKey.Copy(eg_priv)
1083
1088
  _SaveObj(eg_priv, args.key_path + '.priv', args.protect or None)
1084
1089
  _SaveObj(eg_pub, args.key_path + '.pub', args.protect or None)
1085
- print(f'El-Gamal private/public keys saved to {args.key_path + ".priv/.pub"!r}')
1090
+ console.print(f'El-Gamal private/public keys saved to {args.key_path + ".priv/.pub"!r}')
1086
1091
  case 'rawencrypt':
1087
1092
  eg_pub = elgamal.ElGamalPublicKey.Copy(
1088
1093
  _LoadObj(args.key_path, args.protect or None, elgamal.ElGamalPublicKey))
1089
1094
  m = _ParseInt(args.message)
1090
1095
  ss = eg_pub.RawEncrypt(m)
1091
- print(f'{ss[0]}:{ss[1]}')
1096
+ console.print(f'{ss[0]}:{ss[1]}')
1092
1097
  case 'rawdecrypt':
1093
1098
  eg_priv = _LoadObj(args.key_path, args.protect or None, elgamal.ElGamalPrivateKey)
1094
1099
  c1, c2 = args.ciphertext.split(':')
1095
1100
  ss = (_ParseInt(c1), _ParseInt(c2))
1096
- print(eg_priv.RawDecrypt(ss))
1101
+ console.print(eg_priv.RawDecrypt(ss))
1097
1102
  case 'rawsign':
1098
1103
  eg_priv = _LoadObj(args.key_path, args.protect or None, elgamal.ElGamalPrivateKey)
1099
1104
  m = _ParseInt(args.message)
1100
1105
  ss = eg_priv.RawSign(m)
1101
- print(f'{ss[0]}:{ss[1]}')
1106
+ console.print(f'{ss[0]}:{ss[1]}')
1102
1107
  case 'rawverify':
1103
1108
  eg_pub = elgamal.ElGamalPublicKey.Copy(
1104
1109
  _LoadObj(args.key_path, args.protect or None, elgamal.ElGamalPublicKey))
1105
1110
  m = _ParseInt(args.message)
1106
1111
  c1, c2 = args.signature.split(':')
1107
1112
  ss = (_ParseInt(c1), _ParseInt(c2))
1108
- print('El-Gamal signature: ' + ('OK' if eg_pub.RawVerify(m, ss) else 'INVALID'))
1113
+ console.print('El-Gamal signature: ' + ('OK' if eg_pub.RawVerify(m, ss) else 'INVALID'))
1109
1114
  case 'encrypt':
1110
1115
  eg_pub = _LoadObj(args.key_path, args.protect or None, elgamal.ElGamalPublicKey)
1111
1116
  pt = _BytesFromText(args.plaintext, in_format)
1112
1117
  ct = eg_pub.Encrypt(pt, associated_data=aad)
1113
- print(_BytesToText(ct, out_format))
1118
+ console.print(_BytesToText(ct, out_format))
1114
1119
  case 'decrypt':
1115
1120
  eg_priv = _LoadObj(args.key_path, args.protect or None, elgamal.ElGamalPrivateKey)
1116
1121
  ct = _BytesFromText(args.ciphertext, in_format)
1117
1122
  pt = eg_priv.Decrypt(ct, associated_data=aad)
1118
- print(_BytesToText(pt, out_format))
1123
+ console.print(_BytesToText(pt, out_format))
1119
1124
  case 'sign':
1120
1125
  eg_priv = _LoadObj(args.key_path, args.protect or None, elgamal.ElGamalPrivateKey)
1121
1126
  pt = _BytesFromText(args.message, in_format)
1122
1127
  ct = eg_priv.Sign(pt, associated_data=aad)
1123
- print(_BytesToText(ct, out_format))
1128
+ console.print(_BytesToText(ct, out_format))
1124
1129
  case 'verify':
1125
1130
  eg_pub = _LoadObj(args.key_path, args.protect or None, elgamal.ElGamalPublicKey)
1126
1131
  pt = _BytesFromText(args.message, in_format)
1127
1132
  ct = _BytesFromText(args.signature, in_format)
1128
- print('El-Gamal signature: ' +
1129
- ('OK' if eg_pub.Verify(pt, ct, associated_data=aad) else 'INVALID'))
1133
+ console.print(
1134
+ 'El-Gamal signature: ' + ('OK' if eg_pub.Verify(pt, ct, associated_data=aad)
1135
+ else 'INVALID'))
1130
1136
  case _:
1131
1137
  raise NotImplementedError()
1132
1138
 
1133
1139
 
1134
1140
  def DSACommand(
1135
- args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType, /) -> None:
1141
+ args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType,
1142
+ console: rich_console.Console, /) -> None:
1136
1143
  """Execute `dsa` command."""
1137
1144
  c1: str
1138
1145
  c2: str
@@ -1151,43 +1158,44 @@ def DSACommand(
1151
1158
  dsa_shared: dsa.DSASharedPublicKey = dsa.DSASharedPublicKey.NewShared(
1152
1159
  args.p_bits, args.q_bits)
1153
1160
  _SaveObj(dsa_shared, args.key_path + '.shared', args.protect or None)
1154
- print(f'DSA shared key saved to {args.key_path + ".shared"!r}')
1161
+ console.print(f'DSA shared key saved to {args.key_path + ".shared"!r}')
1155
1162
  case 'new':
1156
1163
  dsa_priv = dsa.DSAPrivateKey.New(
1157
1164
  _LoadObj(args.key_path + '.shared', args.protect or None, dsa.DSASharedPublicKey))
1158
1165
  dsa_pub = dsa.DSAPublicKey.Copy(dsa_priv)
1159
1166
  _SaveObj(dsa_priv, args.key_path + '.priv', args.protect or None)
1160
1167
  _SaveObj(dsa_pub, args.key_path + '.pub', args.protect or None)
1161
- print(f'DSA private/public keys saved to {args.key_path + ".priv/.pub"!r}')
1168
+ console.print(f'DSA private/public keys saved to {args.key_path + ".priv/.pub"!r}')
1162
1169
  case 'rawsign':
1163
1170
  dsa_priv = _LoadObj(args.key_path, args.protect or None, dsa.DSAPrivateKey)
1164
1171
  m = _ParseInt(args.message) % dsa_priv.prime_seed
1165
1172
  ss = dsa_priv.RawSign(m)
1166
- print(f'{ss[0]}:{ss[1]}')
1173
+ console.print(f'{ss[0]}:{ss[1]}')
1167
1174
  case 'rawverify':
1168
1175
  dsa_pub = dsa.DSAPublicKey.Copy(
1169
1176
  _LoadObj(args.key_path, args.protect or None, dsa.DSAPublicKey))
1170
1177
  m = _ParseInt(args.message) % dsa_pub.prime_seed
1171
1178
  c1, c2 = args.signature.split(':')
1172
1179
  ss = (_ParseInt(c1), _ParseInt(c2))
1173
- print('DSA signature: ' + ('OK' if dsa_pub.RawVerify(m, ss) else 'INVALID'))
1180
+ console.print('DSA signature: ' + ('OK' if dsa_pub.RawVerify(m, ss) else 'INVALID'))
1174
1181
  case 'sign':
1175
1182
  dsa_priv = _LoadObj(args.key_path, args.protect or None, dsa.DSAPrivateKey)
1176
1183
  pt = _BytesFromText(args.message, in_format)
1177
1184
  ct = dsa_priv.Sign(pt, associated_data=aad)
1178
- print(_BytesToText(ct, out_format))
1185
+ console.print(_BytesToText(ct, out_format))
1179
1186
  case 'verify':
1180
1187
  dsa_pub = _LoadObj(args.key_path, args.protect or None, dsa.DSAPublicKey)
1181
1188
  pt = _BytesFromText(args.message, in_format)
1182
1189
  ct = _BytesFromText(args.signature, in_format)
1183
- print('DSA signature: ' +
1184
- ('OK' if dsa_pub.Verify(pt, ct, associated_data=aad) else 'INVALID'))
1190
+ console.print(
1191
+ 'DSA signature: ' + ('OK' if dsa_pub.Verify(pt, ct, associated_data=aad) else 'INVALID'))
1185
1192
  case _:
1186
1193
  raise NotImplementedError()
1187
1194
 
1188
1195
 
1189
1196
  def BidCommand(
1190
- args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType, /) -> None:
1197
+ args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType,
1198
+ console: rich_console.Console, /) -> None:
1191
1199
  """Execute `bid` command."""
1192
1200
  bid_cmd: str = args.bid_command.lower().strip() if args.bid_command else ''
1193
1201
  match bid_cmd:
@@ -1197,22 +1205,23 @@ def BidCommand(
1197
1205
  bid_pub: base.PublicBid512 = base.PublicBid512.Copy(bid_priv)
1198
1206
  _SaveObj(bid_priv, args.key_path + '.priv', args.protect or None)
1199
1207
  _SaveObj(bid_pub, args.key_path + '.pub', args.protect or None)
1200
- print(f'Bid private/public commitments saved to {args.key_path + ".priv/.pub"!r}')
1208
+ console.print(f'Bid private/public commitments saved to {args.key_path + ".priv/.pub"!r}')
1201
1209
  case 'verify':
1202
1210
  bid_priv = _LoadObj(args.key_path + '.priv', args.protect or None, base.PrivateBid512)
1203
1211
  bid_pub = _LoadObj(args.key_path + '.pub', args.protect or None, base.PublicBid512)
1204
1212
  bid_pub_expect: base.PublicBid512 = base.PublicBid512.Copy(bid_priv)
1205
- print('Bid commitment: ' + (
1213
+ console.print('Bid commitment: ' + (
1206
1214
  'OK' if (bid_pub.VerifyBid(bid_priv.private_key, bid_priv.secret_bid) and
1207
1215
  bid_pub == bid_pub_expect) else 'INVALID'))
1208
- print('Bid secret:')
1209
- print(_BytesToText(bid_priv.secret_bid, out_format))
1216
+ console.print('Bid secret:')
1217
+ console.print(_BytesToText(bid_priv.secret_bid, out_format))
1210
1218
  case _:
1211
1219
  raise NotImplementedError()
1212
1220
 
1213
1221
 
1214
1222
  def SSSCommand(
1215
- args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType, /) -> None:
1223
+ args: argparse.Namespace, in_format: _StrBytesType, out_format: _StrBytesType,
1224
+ console: rich_console.Console, /) -> None:
1216
1225
  """Execute `sss` command."""
1217
1226
  pt: bytes
1218
1227
  sss_share: sss.ShamirSharePrivate
@@ -1226,40 +1235,43 @@ def SSSCommand(
1226
1235
  sss_pub: sss.ShamirSharedSecretPublic = sss.ShamirSharedSecretPublic.Copy(sss_priv)
1227
1236
  _SaveObj(sss_priv, args.key_path + '.priv', args.protect or None)
1228
1237
  _SaveObj(sss_pub, args.key_path + '.pub', args.protect or None)
1229
- print(f'SSS private/public keys saved to {args.key_path + ".priv/.pub"!r}')
1238
+ console.print(f'SSS private/public keys saved to {args.key_path + ".priv/.pub"!r}')
1230
1239
  case 'rawshares':
1231
1240
  sss_priv = _LoadObj(
1232
1241
  args.key_path + '.priv', args.protect or None, sss.ShamirSharedSecretPrivate)
1233
1242
  secret: int = _ParseInt(args.secret)
1234
1243
  for i, sss_share in enumerate(sss_priv.RawShares(secret, max_shares=args.count)):
1235
1244
  _SaveObj(sss_share, f'{args.key_path}.share.{i + 1}', args.protect or None)
1236
- print(f'SSS {args.count} individual (private) shares saved to '
1237
- f'{args.key_path + ".share.1…" + str(args.count)!r}')
1245
+ console.print(
1246
+ f'SSS {args.count} individual (private) shares saved to '
1247
+ f'{args.key_path + ".share.1…" + str(args.count)!r}')
1238
1248
  case 'rawrecover':
1239
1249
  sss_pub = _LoadObj(args.key_path + '.pub', args.protect or None, sss.ShamirSharedSecretPublic)
1240
1250
  subset = []
1241
1251
  for fname in glob.glob(args.key_path + '.share.*'):
1242
1252
  sss_share = _LoadObj(fname, args.protect or None, sss.ShamirSharePrivate)
1243
1253
  subset.append(sss_share)
1244
- print(f'Loaded SSS share: {fname!r}')
1245
- print('Secret:')
1246
- print(sss_pub.RawRecoverSecret(subset))
1254
+ console.print(f'Loaded SSS share: {fname!r}')
1255
+ console.print('Secret:')
1256
+ console.print(sss_pub.RawRecoverSecret(subset))
1247
1257
  case 'rawverify':
1248
1258
  sss_priv = _LoadObj(
1249
1259
  args.key_path + '.priv', args.protect or None, sss.ShamirSharedSecretPrivate)
1250
1260
  secret = _ParseInt(args.secret)
1251
1261
  for fname in glob.glob(args.key_path + '.share.*'):
1252
1262
  sss_share = _LoadObj(fname, args.protect or None, sss.ShamirSharePrivate)
1253
- print(f'SSS share {fname!r} verification: '
1254
- f'{"OK" if sss_priv.RawVerifyShare(secret, sss_share) else "INVALID"}')
1263
+ console.print(
1264
+ f'SSS share {fname!r} verification: '
1265
+ f'{"OK" if sss_priv.RawVerifyShare(secret, sss_share) else "INVALID"}')
1255
1266
  case 'shares':
1256
1267
  sss_priv = _LoadObj(
1257
1268
  args.key_path + '.priv', args.protect or None, sss.ShamirSharedSecretPrivate)
1258
1269
  pt = _BytesFromText(args.secret, in_format)
1259
1270
  for i, data_share in enumerate(sss_priv.MakeDataShares(pt, args.count)):
1260
1271
  _SaveObj(data_share, f'{args.key_path}.share.{i + 1}', args.protect or None)
1261
- print(f'SSS {args.count} individual (private) shares saved to '
1262
- f'{args.key_path + ".share.1…" + str(args.count)!r}')
1272
+ console.print(
1273
+ f'SSS {args.count} individual (private) shares saved to '
1274
+ f'{args.key_path + ".share.1…" + str(args.count)!r}')
1263
1275
  case 'recover':
1264
1276
  sss_pub = _LoadObj(args.key_path + '.pub', args.protect or None, sss.ShamirSharedSecretPublic)
1265
1277
  subset, data_share = [], None
@@ -1268,12 +1280,12 @@ def SSSCommand(
1268
1280
  subset.append(sss_share)
1269
1281
  if isinstance(sss_share, sss.ShamirShareData):
1270
1282
  data_share = sss_share
1271
- print(f'Loaded SSS share: {fname!r}')
1283
+ console.print(f'Loaded SSS share: {fname!r}')
1272
1284
  if data_share is None:
1273
1285
  raise base.InputError('no data share found among the available shares')
1274
1286
  pt = data_share.RecoverData(subset)
1275
- print('Secret:')
1276
- print(_BytesToText(pt, out_format))
1287
+ console.print('Secret:')
1288
+ console.print(_BytesToText(pt, out_format))
1277
1289
  case _:
1278
1290
  raise NotImplementedError()
1279
1291
 
@@ -1284,11 +1296,7 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1284
1296
  parser: argparse.ArgumentParser = _BuildParser()
1285
1297
  args: argparse.Namespace = parser.parse_args(argv)
1286
1298
  # take care of global options
1287
- levels: list[int] = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG]
1288
- logging.basicConfig(
1289
- level=levels[min(args.verbose, len(levels) - 1)], # type: ignore
1290
- format=getattr(base, 'LOG_FORMAT', '%(levelname)s:%(message)s'))
1291
- logging.captureWarnings(True)
1299
+ console: rich_console.Console = base.InitLogging(args.verbose, soft_wrap=True)
1292
1300
  in_format: _StrBytesType = _StrBytesType.FromFlags(args.hex, args.b64, args.bin)
1293
1301
  out_format: _StrBytesType = _StrBytesType.FromFlags(args.out_hex, args.out_b64, args.out_bin)
1294
1302
 
@@ -1311,51 +1319,51 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1311
1319
  # -------- primes ----------
1312
1320
  case 'isprime':
1313
1321
  n = _ParseInt(args.n)
1314
- print(modmath.IsPrime(n))
1322
+ console.print(modmath.IsPrime(n))
1315
1323
  case 'primegen':
1316
1324
  start: int = _ParseInt(args.start)
1317
1325
  count: int = args.count
1318
1326
  i = 0
1319
1327
  for p in modmath.PrimeGenerator(start):
1320
- print(p)
1328
+ console.print(p)
1321
1329
  i += 1
1322
1330
  if count and i >= count:
1323
1331
  break
1324
1332
  case 'mersenne':
1325
1333
  for k, m_p, perfect in modmath.MersennePrimesGenerator(args.min_k):
1326
- print(f'k={k} M={m_p} perfect={perfect}')
1334
+ console.print(f'k={k} M={m_p} perfect={perfect}')
1327
1335
  if k > args.cutoff_k:
1328
1336
  break
1329
1337
 
1330
1338
  # -------- integer / modular ----------
1331
1339
  case 'gcd':
1332
1340
  a, b = _ParseInt(args.a), _ParseInt(args.b)
1333
- print(base.GCD(a, b))
1341
+ console.print(base.GCD(a, b))
1334
1342
  case 'xgcd':
1335
1343
  a, b = _ParseInt(args.a), _ParseInt(args.b)
1336
- print(base.ExtendedGCD(a, b))
1344
+ console.print(base.ExtendedGCD(a, b))
1337
1345
  case 'mod':
1338
1346
  mod_command: str = args.mod_command.lower().strip() if args.mod_command else ''
1339
1347
  match mod_command:
1340
1348
  case 'inv':
1341
1349
  a, m = _ParseInt(args.a), _ParseInt(args.m)
1342
1350
  try:
1343
- print(modmath.ModInv(a, m))
1351
+ console.print(modmath.ModInv(a, m))
1344
1352
  except modmath.ModularDivideError:
1345
- print('<<INVALID>> no modular inverse exists (ModularDivideError)')
1353
+ console.print('<<INVALID>> no modular inverse exists (ModularDivideError)')
1346
1354
  case 'div':
1347
1355
  x, y, m = _ParseInt(args.x), _ParseInt(args.y), _ParseInt(args.m)
1348
1356
  try:
1349
- print(modmath.ModDiv(x, y, m))
1357
+ console.print(modmath.ModDiv(x, y, m))
1350
1358
  except modmath.ModularDivideError:
1351
- print('<<INVALID>> no modular inverse exists (ModularDivideError)')
1359
+ console.print('<<INVALID>> no modular inverse exists (ModularDivideError)')
1352
1360
  case 'exp':
1353
1361
  a, e, m = _ParseInt(args.a), _ParseInt(args.e), _ParseInt(args.m)
1354
- print(modmath.ModExp(a, e, m))
1362
+ console.print(modmath.ModExp(a, e, m))
1355
1363
  case 'poly':
1356
1364
  x, m = _ParseInt(args.x), _ParseInt(args.m)
1357
1365
  coeffs: list[int] = _ParseIntList(args.coeff)
1358
- print(modmath.ModPolynomial(x, coeffs, m))
1366
+ console.print(modmath.ModPolynomial(x, coeffs, m))
1359
1367
  case 'lagrange':
1360
1368
  x, m = _ParseInt(args.x), _ParseInt(args.m)
1361
1369
  pts: dict[int, int] = {}
@@ -1364,14 +1372,14 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1364
1372
  for kv in args.pt:
1365
1373
  k_s, v_s = kv.split(':', 1)
1366
1374
  pts[_ParseInt(k_s)] = _ParseInt(v_s)
1367
- print(modmath.ModLagrangeInterpolate(x, pts, m))
1375
+ console.print(modmath.ModLagrangeInterpolate(x, pts, m))
1368
1376
  case 'crt':
1369
1377
  crt_tuple: tuple[int, int, int, int] = (
1370
1378
  _ParseInt(args.a1), _ParseInt(args.m1), _ParseInt(args.a2), _ParseInt(args.m2))
1371
1379
  try:
1372
- print(modmath.CRTPair(*crt_tuple))
1380
+ console.print(modmath.CRTPair(*crt_tuple))
1373
1381
  except modmath.ModularDivideError:
1374
- print('<<INVALID>> moduli m1/m2 not co-prime (ModularDivideError)')
1382
+ console.print('<<INVALID>> moduli m1/m2 not co-prime (ModularDivideError)')
1375
1383
  case _:
1376
1384
  raise NotImplementedError()
1377
1385
 
@@ -1380,13 +1388,13 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1380
1388
  rand_cmd: str = args.rand_command.lower().strip() if args.rand_command else ''
1381
1389
  match rand_cmd:
1382
1390
  case 'bits':
1383
- print(base.RandBits(args.bits))
1391
+ console.print(base.RandBits(args.bits))
1384
1392
  case 'int':
1385
- print(base.RandInt(_ParseInt(args.min), _ParseInt(args.max)))
1393
+ console.print(base.RandInt(_ParseInt(args.min), _ParseInt(args.max)))
1386
1394
  case 'bytes':
1387
- print(base.BytesToHex(base.RandBytes(args.n)))
1395
+ console.print(base.BytesToHex(base.RandBytes(args.n)))
1388
1396
  case 'prime':
1389
- print(modmath.NBitRandomPrimes(args.bits).pop())
1397
+ console.print(modmath.NBitRandomPrimes(args.bits).pop())
1390
1398
  case _:
1391
1399
  raise NotImplementedError()
1392
1400
  case 'hash':
@@ -1395,35 +1403,35 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1395
1403
  case 'sha256':
1396
1404
  bt = _BytesFromText(args.data, in_format)
1397
1405
  digest: bytes = base.Hash256(bt)
1398
- print(_BytesToText(digest, out_format))
1406
+ console.print(_BytesToText(digest, out_format))
1399
1407
  case 'sha512':
1400
1408
  bt = _BytesFromText(args.data, in_format)
1401
1409
  digest = base.Hash512(bt)
1402
- print(_BytesToText(digest, out_format))
1410
+ console.print(_BytesToText(digest, out_format))
1403
1411
  case 'file':
1404
1412
  digest = base.FileHash(args.path, digest=args.digest)
1405
- print(_BytesToText(digest, out_format))
1413
+ console.print(_BytesToText(digest, out_format))
1406
1414
  case _:
1407
1415
  raise NotImplementedError()
1408
1416
 
1409
1417
  # -------- AES / RSA / El-Gamal / DSA / SSS ----------
1410
1418
  case 'aes':
1411
- AESCommand(args, in_format, out_format)
1419
+ AESCommand(args, in_format, out_format, console)
1412
1420
 
1413
1421
  case 'rsa':
1414
- RSACommand(args, in_format, out_format)
1422
+ RSACommand(args, in_format, out_format, console)
1415
1423
 
1416
1424
  case 'elgamal':
1417
- ElGamalCommand(args, in_format, out_format)
1425
+ ElGamalCommand(args, in_format, out_format, console)
1418
1426
 
1419
1427
  case 'dsa':
1420
- DSACommand(args, in_format, out_format)
1428
+ DSACommand(args, in_format, out_format, console)
1421
1429
 
1422
1430
  case 'bid':
1423
- BidCommand(args, in_format, out_format)
1431
+ BidCommand(args, in_format, out_format, console)
1424
1432
 
1425
1433
  case 'sss':
1426
- SSSCommand(args, in_format, out_format)
1434
+ SSSCommand(args, in_format, out_format, console)
1427
1435
 
1428
1436
  # -------- Documentation ----------
1429
1437
  case 'doc':
@@ -1431,7 +1439,7 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1431
1439
  args.doc_command.lower().strip() if getattr(args, 'doc_command', '') else '')
1432
1440
  match doc_command:
1433
1441
  case 'md':
1434
- print(base.GenerateCLIMarkdown(
1442
+ console.print(base.GenerateCLIMarkdown(
1435
1443
  'transcrypto', _BuildParser(), description=(
1436
1444
  '`transcrypto` is a command-line utility that provides access to all core '
1437
1445
  'functionality described in this documentation. It serves as a convenient '
@@ -1446,9 +1454,9 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1446
1454
  parser.print_help()
1447
1455
 
1448
1456
  except NotImplementedError as err:
1449
- print(f'Invalid command: {err}')
1457
+ console.print(f'Invalid command: {err}')
1450
1458
  except (base.Error, ValueError) as err:
1451
- print(str(err))
1459
+ console.print(str(err))
1452
1460
 
1453
1461
  return 0
1454
1462
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: transcrypto
3
- Version: 1.4.0
3
+ Version: 1.6.0
4
4
  Summary: Basic crypto primitives, not intended for actual use, but as a companion to --Criptografia, Métodos e Algoritmos--
5
5
  Author-email: Daniel Balparda <balparda@github.com>
6
6
  License-Expression: Apache-2.0
@@ -984,7 +984,7 @@ deactivate
984
984
 
985
985
  ### Updating Dependencies
986
986
 
987
- To update `poetry.lock` file to more current versions do `poetry update`, it will ignore the current lock, update, and rewrite the `poetry.lock` file.
987
+ To update `poetry.lock` file to more current versions do `poetry update`, it will ignore the current lock, update, and rewrite the `poetry.lock` file. If you have cache problems `poetry cache clear PyPI --all` will clean it.
988
988
 
989
989
  To add a new dependency you should do:
990
990
 
@@ -1,18 +1,18 @@
1
1
  transcrypto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  transcrypto/aes.py,sha256=TRiON5hvtJoZFz1BaTlWtHOOnq_xK8iW13ajLsBPJ2M,11935
3
- transcrypto/base.py,sha256=yqRdt7QLZyAiIA2SlvCa8btWbwMuOKTF7SLepJiDHiI,60336
3
+ transcrypto/base.py,sha256=HTuKgl_qz5gFLx62G0wTGLO5mW4YA5YlstuCusr9G74,63767
4
4
  transcrypto/constants.py,sha256=rt7g7H3ga3r_U59YhewwtuFDzVLkB-Uzc9fEq91epX4,158419
5
5
  transcrypto/dsa.py,sha256=dc6__0YS2B_xbN4UnhX120GMyWid6qg6iopEimTnoxs,20505
6
6
  transcrypto/elgamal.py,sha256=uR0bJ7A13UrAZynW6QRWJZhe86ZvoozaO5U9rDpam_I,21350
7
7
  transcrypto/modmath.py,sha256=RVwszAQA5kdMe5k1Fb3bQiO3NK0kujYeQHo76CVuWqc,21266
8
- transcrypto/profiler.py,sha256=fhoEs__UY8wuq5Zdam4AALS4sL00eCL5MG_jUlEUchI,7709
8
+ transcrypto/profiler.py,sha256=nJRQzb_aSBtjKOO7naJS2EQim7dnWBJLtDihlhJvAG8,7628
9
9
  transcrypto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  transcrypto/rsa.py,sha256=3SYUEGOdHn_8UbezzocyQA8bkytL7d_d9rudsv4Zx9A,24926
11
- transcrypto/safetrans.py,sha256=ftrkAPiuha4K73fyzN_aF3kbXOft8KLr6QdOAOVwlnA,57161
11
+ transcrypto/safetrans.py,sha256=JNeTeldkxdmB5Ca1t8ZKP5wrYkJ1jAal8AOKjy9H9vc,57011
12
12
  transcrypto/sss.py,sha256=Jl7pa1fleNQ-1kvneaeO-B2PfM0ilNKTYw4vVJ5WGwc,17100
13
- transcrypto/transcrypto.py,sha256=NGkQS9L_umnsy3MsiQvAbC6eM0vjRV4OF7daxM3mx9M,71386
14
- transcrypto-1.4.0.dist-info/licenses/LICENSE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174
15
- transcrypto-1.4.0.dist-info/METADATA,sha256=iKeon-sdEf8Ej3XqHj_-2obHJrJGUNLCJl7iOIDEOGI,37895
16
- transcrypto-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- transcrypto-1.4.0.dist-info/top_level.txt,sha256=9IfB0nGtVzQbYok5QIYNOy3coDv2UKX2OZtlFyxFDDQ,12
18
- transcrypto-1.4.0.dist-info/RECORD,,
13
+ transcrypto/transcrypto.py,sha256=gQpFGzqTwEy2unct3ettopbdokzjyfTaW6BWy838XKc,72105
14
+ transcrypto-1.6.0.dist-info/licenses/LICENSE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174
15
+ transcrypto-1.6.0.dist-info/METADATA,sha256=5N1FL_NtQwHypHw65QeTjTDkWktZecuqbZzAGGCt2tg,37969
16
+ transcrypto-1.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ transcrypto-1.6.0.dist-info/top_level.txt,sha256=9IfB0nGtVzQbYok5QIYNOy3coDv2UKX2OZtlFyxFDDQ,12
18
+ transcrypto-1.6.0.dist-info/RECORD,,