transcrypto 1.3.0__py3-none-any.whl → 1.5.1__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/aes.py +10 -2
- transcrypto/base.py +720 -103
- transcrypto/constants.py +1921 -0
- transcrypto/dsa.py +16 -2
- transcrypto/modmath.py +37 -419
- transcrypto/profiler.py +191 -0
- transcrypto/safetrans.py +1231 -0
- transcrypto/transcrypto.py +14 -180
- transcrypto-1.5.1.dist-info/METADATA +1071 -0
- transcrypto-1.5.1.dist-info/RECORD +18 -0
- transcrypto-1.3.0.dist-info/METADATA +0 -2562
- transcrypto-1.3.0.dist-info/RECORD +0 -15
- {transcrypto-1.3.0.dist-info → transcrypto-1.5.1.dist-info}/WHEEL +0 -0
- {transcrypto-1.3.0.dist-info → transcrypto-1.5.1.dist-info}/licenses/LICENSE +0 -0
- {transcrypto-1.3.0.dist-info → transcrypto-1.5.1.dist-info}/top_level.txt +0 -0
transcrypto/transcrypto.py
CHANGED
|
@@ -10,13 +10,15 @@ Notes on the layout (quick mental model):
|
|
|
10
10
|
|
|
11
11
|
isprime, primegen, mersenne
|
|
12
12
|
gcd, xgcd, and grouped mod inv|div|exp|poly|lagrange|crt
|
|
13
|
-
random bits|int|bytes|prime
|
|
13
|
+
random bits|int|bytes|prime
|
|
14
|
+
hash sha256|sha512|file
|
|
14
15
|
aes key frompass, aes encrypt|decrypt (GCM), aes ecb encrypt|decrypt
|
|
15
16
|
rsa new|encrypt|decrypt|sign|verify|rawencrypt|rawdecrypt|rawsign|rawverify
|
|
16
17
|
elgamal shared|new|encrypt|decrypt|sign|verify|rawencrypt|rawdecrypt|rawsign|rawverify
|
|
17
18
|
dsa shared|new|sign|verify|rawsign|rawverify
|
|
18
19
|
bid new|verify
|
|
19
20
|
sss new|shares|recover|rawshares|rawrecover|rawverify
|
|
21
|
+
doc md
|
|
20
22
|
"""
|
|
21
23
|
|
|
22
24
|
from __future__ import annotations
|
|
@@ -27,7 +29,7 @@ import glob
|
|
|
27
29
|
import logging
|
|
28
30
|
# import pdb
|
|
29
31
|
import sys
|
|
30
|
-
from typing import Any, Iterable
|
|
32
|
+
from typing import Any, Iterable
|
|
31
33
|
|
|
32
34
|
from . import base, modmath, rsa, sss, elgamal, dsa, aes
|
|
33
35
|
|
|
@@ -119,179 +121,6 @@ def _LoadObj(path: str, password: str | None, expect: type, /) -> Any:
|
|
|
119
121
|
return obj
|
|
120
122
|
|
|
121
123
|
|
|
122
|
-
def _FlagNames(a: argparse.Action, /) -> list[str]:
|
|
123
|
-
# Positional args have empty 'option_strings'; otherwise use them (e.g., ['-v','--verbose'])
|
|
124
|
-
if a.option_strings:
|
|
125
|
-
return list(a.option_strings)
|
|
126
|
-
if a.nargs:
|
|
127
|
-
if isinstance(a.metavar, str) and a.metavar:
|
|
128
|
-
# e.g., nargs=2, metavar='FILE'
|
|
129
|
-
return [a.metavar]
|
|
130
|
-
if isinstance(a.metavar, tuple):
|
|
131
|
-
# e.g., nargs=2, metavar=('FILE1', 'FILE2')
|
|
132
|
-
return list(a.metavar)
|
|
133
|
-
# Otherwise, it’s a positional arg with no flags, so return the destination name
|
|
134
|
-
return [a.dest]
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def _ActionIsSubparser(a: argparse.Action, /) -> bool:
|
|
138
|
-
return isinstance(a, argparse._SubParsersAction) # type: ignore[attr-defined] # pylint: disable=protected-access
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def _FormatDefault(a: argparse.Action, /) -> str:
|
|
142
|
-
if a.default is argparse.SUPPRESS:
|
|
143
|
-
return ''
|
|
144
|
-
if isinstance(a.default, bool):
|
|
145
|
-
return ' (default: on)' if a.default else ''
|
|
146
|
-
if a.default in (None, '', 0, False):
|
|
147
|
-
return ''
|
|
148
|
-
return f' (default: {a.default})'
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def _FormatChoices(a: argparse.Action, /) -> str:
|
|
152
|
-
return f' choices: {list(a.choices)}' if getattr(a, 'choices', None) else '' # type:ignore
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def _FormatType(a: argparse.Action, /) -> str:
|
|
156
|
-
t: Any | None = getattr(a, 'type', None)
|
|
157
|
-
if t is None:
|
|
158
|
-
return ''
|
|
159
|
-
# Show clean type names (int, str, float); for callables, just say 'custom'
|
|
160
|
-
return f' type: {t.__name__ if hasattr(t, "__name__") else "custom"}'
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def _FormatNArgs(a: argparse.Action, /) -> str:
|
|
164
|
-
return f' nargs: {a.nargs}' if getattr(a, 'nargs', None) not in (None, 0) else ''
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def _RowsForActions(actions: Sequence[argparse.Action], /) -> list[tuple[str, str]]:
|
|
168
|
-
rows: list[tuple[str, str]] = []
|
|
169
|
-
for a in actions:
|
|
170
|
-
if _ActionIsSubparser(a):
|
|
171
|
-
continue
|
|
172
|
-
# skip the built-in help action; it’s implied
|
|
173
|
-
if getattr(a, 'help', '') == argparse.SUPPRESS or isinstance(a, argparse._HelpAction): # type: ignore[attr-defined] # pylint: disable=protected-access
|
|
174
|
-
continue
|
|
175
|
-
flags: str = ', '.join(_FlagNames(a))
|
|
176
|
-
meta: str = ''.join(
|
|
177
|
-
(_FormatType(a), _FormatNArgs(a), _FormatChoices(a), _FormatDefault(a))).strip()
|
|
178
|
-
desc: str = (a.help or '').strip()
|
|
179
|
-
if meta:
|
|
180
|
-
desc = f'{desc} [{meta}]' if desc else f'[{meta}]'
|
|
181
|
-
rows.append((flags, desc))
|
|
182
|
-
return rows
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def _MarkdownTable(
|
|
186
|
-
rows: Sequence[tuple[str, str]],
|
|
187
|
-
headers: tuple[str, str] = ('Option/Arg', 'Description'), /) -> str:
|
|
188
|
-
if not rows:
|
|
189
|
-
return ''
|
|
190
|
-
out: list[str] = ['| ' + headers[0] + ' | ' + headers[1] + ' |', '|---|---|']
|
|
191
|
-
for left, right in rows:
|
|
192
|
-
out.append(f'| `{left}` | {right} |')
|
|
193
|
-
return '\n'.join(out)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def _WalkSubcommands(
|
|
197
|
-
parser: argparse.ArgumentParser, path: list[str] | None = None, /) -> list[
|
|
198
|
-
tuple[list[str], argparse.ArgumentParser, Any]]:
|
|
199
|
-
path = path or []
|
|
200
|
-
items: list[tuple[list[str], argparse.ArgumentParser, Any]] = []
|
|
201
|
-
# sub_action = None
|
|
202
|
-
name: str
|
|
203
|
-
sp: argparse.ArgumentParser
|
|
204
|
-
for action in parser._actions: # type: ignore[attr-defined] # pylint: disable=protected-access
|
|
205
|
-
if _ActionIsSubparser(action):
|
|
206
|
-
# sub_action = a # type: ignore[assignment]
|
|
207
|
-
for name, sp in action.choices.items(): # type:ignore
|
|
208
|
-
items.append((path + [name], sp, action)) # type:ignore
|
|
209
|
-
items.extend(_WalkSubcommands(sp, path + [name])) # type:ignore
|
|
210
|
-
return items
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def _HelpText(sub_parser: argparse.ArgumentParser, parent_sub_action: Any, /) -> str:
|
|
214
|
-
if parent_sub_action is not None:
|
|
215
|
-
for choice_action in parent_sub_action._choices_actions: # type: ignore # pylint: disable=protected-access
|
|
216
|
-
if choice_action.dest == sub_parser.prog.split()[-1]:
|
|
217
|
-
return choice_action.help or ''
|
|
218
|
-
return ''
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def _GenerateCLIMarkdown() -> str: # pylint: disable=too-many-locals
|
|
222
|
-
"""Return a Markdown doc section that reflects the current _BuildParser() tree.
|
|
223
|
-
|
|
224
|
-
Will treat epilog strings as examples, splitting on '$$' to get multiple examples.
|
|
225
|
-
"""
|
|
226
|
-
parser: argparse.ArgumentParser = _BuildParser()
|
|
227
|
-
assert parser.prog == 'poetry run transcrypto', 'should never happen: module name changed?'
|
|
228
|
-
prog: str = 'transcrypto' # no '.py' needed because poetry run has an alias
|
|
229
|
-
lines: list[str] = ['']
|
|
230
|
-
# Header + global flags
|
|
231
|
-
lines.append('## Command-Line Interface\n')
|
|
232
|
-
lines.append(
|
|
233
|
-
f'`{prog}` is a command-line utility that provides access to all core functionality '
|
|
234
|
-
'described in this documentation. It serves as a convenient wrapper over the Python APIs, '
|
|
235
|
-
'enabling **cryptographic operations**, **number theory functions**, **secure randomness '
|
|
236
|
-
'generation**, **hashing**, **AES**, **RSA**, **El-Gamal**, **DSA**, **bidding**, **SSS**, '
|
|
237
|
-
'and other utilities without writing code.\n')
|
|
238
|
-
lines.append('Invoke with:\n')
|
|
239
|
-
lines.append('```bash')
|
|
240
|
-
lines.append(f'poetry run {prog} <command> [sub-command] [options...]')
|
|
241
|
-
lines.append('```\n')
|
|
242
|
-
# Global options table
|
|
243
|
-
global_rows: list[tuple[str, str]] = _RowsForActions(parser._actions) # type: ignore[attr-defined] # pylint: disable=protected-access
|
|
244
|
-
if global_rows:
|
|
245
|
-
lines.append('### Global Options\n')
|
|
246
|
-
lines.append(_MarkdownTable(global_rows))
|
|
247
|
-
lines.append('')
|
|
248
|
-
# Top-level commands summary
|
|
249
|
-
lines.append('### Top-Level Commands\n')
|
|
250
|
-
# Find top-level subparsers to list available commands
|
|
251
|
-
top_subs: list[argparse.Action] = [a for a in parser._actions if _ActionIsSubparser(a)] # type: ignore[attr-defined] # pylint: disable=protected-access
|
|
252
|
-
for action in top_subs:
|
|
253
|
-
for name, sp in action.choices.items(): # type: ignore[union-attr]
|
|
254
|
-
help_text: str = (sp.description or ' '.join(i.strip() for i in sp.format_usage().splitlines())).strip() # type:ignore
|
|
255
|
-
short: str = (sp.help if hasattr(sp, 'help') else '') or '' # type:ignore
|
|
256
|
-
help_text = short or help_text # type:ignore
|
|
257
|
-
help_text = help_text.replace('usage: ', '').strip() # type:ignore
|
|
258
|
-
lines.append(f'- **`{name}`** — `{help_text}`')
|
|
259
|
-
lines.append('')
|
|
260
|
-
if parser.epilog:
|
|
261
|
-
lines.append('```bash')
|
|
262
|
-
lines.append(parser.epilog)
|
|
263
|
-
lines.append('```\n')
|
|
264
|
-
# Detailed sections per (sub)command
|
|
265
|
-
for path, sub_parser, parent_sub_action in _WalkSubcommands(parser):
|
|
266
|
-
if len(path) == 1:
|
|
267
|
-
lines.append('---\n') # horizontal rule between top-level commands
|
|
268
|
-
header: str = ' '.join(path)
|
|
269
|
-
lines.append(f'###{"" if len(path) == 1 else "#"} `{header}`') # (header level 3 or 4)
|
|
270
|
-
# Usage block
|
|
271
|
-
help_text = _HelpText(sub_parser, parent_sub_action)
|
|
272
|
-
if help_text:
|
|
273
|
-
lines.append(f'\n{help_text}')
|
|
274
|
-
usage: str = sub_parser.format_usage().replace('usage: ', '').strip()
|
|
275
|
-
lines.append('\n```bash')
|
|
276
|
-
lines.append(str(usage))
|
|
277
|
-
lines.append('```\n')
|
|
278
|
-
# Options/args table
|
|
279
|
-
rows: list[tuple[str, str]] = _RowsForActions(sub_parser._actions) # type: ignore[attr-defined] # pylint: disable=protected-access
|
|
280
|
-
if rows:
|
|
281
|
-
lines.append(_MarkdownTable(rows))
|
|
282
|
-
lines.append('')
|
|
283
|
-
# Examples (if any) - stored in epilog argument
|
|
284
|
-
epilog: str = sub_parser.epilog.strip() if sub_parser.epilog else ''
|
|
285
|
-
if epilog:
|
|
286
|
-
lines.append('**Example:**\n')
|
|
287
|
-
lines.append('```bash')
|
|
288
|
-
for epilog_line in epilog.split('$$'):
|
|
289
|
-
lines.append(f'$ poetry run {prog} {epilog_line.strip()}')
|
|
290
|
-
lines.append('```\n')
|
|
291
|
-
# join all lines as the markdown string
|
|
292
|
-
return '\n'.join(lines)
|
|
293
|
-
|
|
294
|
-
|
|
295
124
|
def _BuildParser() -> argparse.ArgumentParser: # pylint: disable=too-many-statements,too-many-locals
|
|
296
125
|
"""Construct the CLI argument parser (kept in sync with the docs)."""
|
|
297
126
|
# ========================= main parser ==========================================================
|
|
@@ -740,7 +569,7 @@ def _BuildParser() -> argparse.ArgumentParser: # pylint: disable=too-many-state
|
|
|
740
569
|
'decrypt',
|
|
741
570
|
help='Decrypt `ciphertext` with private key.',
|
|
742
571
|
epilog=('--b64 --out-bin -p rsa-key.priv rsa decrypt -a eHl6 -- '
|
|
743
|
-
'AO6knI6xwq6TGR…Qy22jiFhXi1eQ
|
|
572
|
+
'AO6knI6xwq6TGR…Qy22jiFhXi1eQ==\nabcde'))
|
|
744
573
|
p_rsa_dec_safe.add_argument('ciphertext', type=str, help='Ciphertext to decrypt')
|
|
745
574
|
p_rsa_dec_safe.add_argument(
|
|
746
575
|
'-a', '--aad', type=str, default='',
|
|
@@ -1109,9 +938,7 @@ def _BuildParser() -> argparse.ArgumentParser: # pylint: disable=too-many-state
|
|
|
1109
938
|
doc_sub.add_parser(
|
|
1110
939
|
'md',
|
|
1111
940
|
help='Emit Markdown docs for the CLI (see README.md section "Creating a New Version").',
|
|
1112
|
-
epilog=
|
|
1113
|
-
'$ ./tools/inject_md_includes.py\n'
|
|
1114
|
-
'inject: README.md updated with included content'))
|
|
941
|
+
epilog='doc md > transcrypto.md\n<<saves file>>')
|
|
1115
942
|
|
|
1116
943
|
return parser
|
|
1117
944
|
|
|
@@ -1604,7 +1431,14 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
|
|
|
1604
1431
|
args.doc_command.lower().strip() if getattr(args, 'doc_command', '') else '')
|
|
1605
1432
|
match doc_command:
|
|
1606
1433
|
case 'md':
|
|
1607
|
-
print(
|
|
1434
|
+
print(base.GenerateCLIMarkdown(
|
|
1435
|
+
'transcrypto', _BuildParser(), description=(
|
|
1436
|
+
'`transcrypto` is a command-line utility that provides access to all core '
|
|
1437
|
+
'functionality described in this documentation. It serves as a convenient '
|
|
1438
|
+
'wrapper over the Python APIs, enabling **cryptographic operations**, '
|
|
1439
|
+
'**number theory functions**, **secure randomness generation**, **hashing**, '
|
|
1440
|
+
'**AES**, **RSA**, **El-Gamal**, **DSA**, **bidding**, **SSS**, '
|
|
1441
|
+
'and other utilities without writing code.')))
|
|
1608
1442
|
case _:
|
|
1609
1443
|
raise NotImplementedError()
|
|
1610
1444
|
|