transcrypto 1.0.3__tar.gz → 1.1.2__tar.gz
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-1.1.2/PKG-INFO +2257 -0
- transcrypto-1.1.2/README.md +2239 -0
- {transcrypto-1.0.3 → transcrypto-1.1.2}/pyproject.toml +19 -4
- transcrypto-1.1.2/src/transcrypto/aes.py +257 -0
- transcrypto-1.1.2/src/transcrypto/base.py +1018 -0
- transcrypto-1.1.2/src/transcrypto/dsa.py +336 -0
- transcrypto-1.1.2/src/transcrypto/elgamal.py +333 -0
- transcrypto-1.1.2/src/transcrypto/modmath.py +535 -0
- transcrypto-1.1.2/src/transcrypto/rsa.py +416 -0
- transcrypto-1.1.2/src/transcrypto/sss.py +299 -0
- transcrypto-1.1.2/src/transcrypto/transcrypto.py +1385 -0
- transcrypto-1.1.2/src/transcrypto.egg-info/PKG-INFO +2257 -0
- {transcrypto-1.0.3 → transcrypto-1.1.2}/src/transcrypto.egg-info/SOURCES.txt +7 -0
- transcrypto-1.0.3/PKG-INFO +0 -147
- transcrypto-1.0.3/README.md +0 -129
- transcrypto-1.0.3/src/transcrypto/transcrypto.py +0 -1077
- transcrypto-1.0.3/src/transcrypto.egg-info/PKG-INFO +0 -147
- {transcrypto-1.0.3 → transcrypto-1.1.2}/LICENSE +0 -0
- {transcrypto-1.0.3 → transcrypto-1.1.2}/setup.cfg +0 -0
- {transcrypto-1.0.3 → transcrypto-1.1.2}/src/transcrypto/__init__.py +0 -0
- {transcrypto-1.0.3 → transcrypto-1.1.2}/src/transcrypto/py.typed +0 -0
- {transcrypto-1.0.3 → transcrypto-1.1.2}/src/transcrypto.egg-info/dependency_links.txt +0 -0
- {transcrypto-1.0.3 → transcrypto-1.1.2}/src/transcrypto.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,2257 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: transcrypto
|
|
3
|
+
Version: 1.1.2
|
|
4
|
+
Summary: Basic crypto primitives, not intended for actual use, but as a companion to --Criptografia, Métodos e Algoritmos--
|
|
5
|
+
Author-email: Daniel Balparda <balparda@github.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/balparda/transcrypto
|
|
8
|
+
Project-URL: PyPI, https://pypi.org/project/transcrypto/
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: Utilities
|
|
13
|
+
Classifier: Topic :: Security :: Cryptography
|
|
14
|
+
Requires-Python: >=3.13.5
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# TransCrypto
|
|
20
|
+
|
|
21
|
+
Basic cryptography primitives implementation, a companion to *"Criptografia, Métodos e Algoritmos"*.
|
|
22
|
+
|
|
23
|
+
Started in July/2025, by Daniel Balparda. Since version 1.0.2 it is PyPI package:
|
|
24
|
+
|
|
25
|
+
<https://pypi.org/project/transcrypto/>
|
|
26
|
+
|
|
27
|
+
- [TransCrypto](#transcrypto)
|
|
28
|
+
- [License](#license)
|
|
29
|
+
- [Design assumptions / Disclaimers](#design-assumptions--disclaimers)
|
|
30
|
+
- [Install](#install)
|
|
31
|
+
- [Command-Line Interface](#command-line-interface)
|
|
32
|
+
- [Global Options](#global-options)
|
|
33
|
+
- [Top-Level Commands](#top-level-commands)
|
|
34
|
+
- [`random`](#random)
|
|
35
|
+
- [`random bits`](#random-bits)
|
|
36
|
+
- [`random int`](#random-int)
|
|
37
|
+
- [`random bytes`](#random-bytes)
|
|
38
|
+
- [`random prime`](#random-prime)
|
|
39
|
+
- [`isprime`](#isprime)
|
|
40
|
+
- [`primegen`](#primegen)
|
|
41
|
+
- [`mersenne`](#mersenne)
|
|
42
|
+
- [`gcd`](#gcd)
|
|
43
|
+
- [`xgcd`](#xgcd)
|
|
44
|
+
- [`mod`](#mod)
|
|
45
|
+
- [`mod inv`](#mod-inv)
|
|
46
|
+
- [`mod div`](#mod-div)
|
|
47
|
+
- [`mod exp`](#mod-exp)
|
|
48
|
+
- [`mod poly`](#mod-poly)
|
|
49
|
+
- [`mod lagrange`](#mod-lagrange)
|
|
50
|
+
- [`mod crt`](#mod-crt)
|
|
51
|
+
- [`hash`](#hash)
|
|
52
|
+
- [`hash sha256`](#hash-sha256)
|
|
53
|
+
- [`hash sha512`](#hash-sha512)
|
|
54
|
+
- [`hash file`](#hash-file)
|
|
55
|
+
- [`aes`](#aes)
|
|
56
|
+
- [`aes key`](#aes-key)
|
|
57
|
+
- [`aes encrypt`](#aes-encrypt)
|
|
58
|
+
- [`aes decrypt`](#aes-decrypt)
|
|
59
|
+
- [`aes ecb`](#aes-ecb)
|
|
60
|
+
- [`aes ecb encrypt`](#aes-ecb-encrypt)
|
|
61
|
+
- [`aes ecb decrypt`](#aes-ecb-decrypt)
|
|
62
|
+
- [`rsa`](#rsa)
|
|
63
|
+
- [`rsa new`](#rsa-new)
|
|
64
|
+
- [`rsa encrypt`](#rsa-encrypt)
|
|
65
|
+
- [`rsa decrypt`](#rsa-decrypt)
|
|
66
|
+
- [`rsa sign`](#rsa-sign)
|
|
67
|
+
- [`rsa verify`](#rsa-verify)
|
|
68
|
+
- [`elgamal`](#elgamal)
|
|
69
|
+
- [`elgamal shared`](#elgamal-shared)
|
|
70
|
+
- [`elgamal new`](#elgamal-new)
|
|
71
|
+
- [`elgamal encrypt`](#elgamal-encrypt)
|
|
72
|
+
- [`elgamal decrypt`](#elgamal-decrypt)
|
|
73
|
+
- [`elgamal sign`](#elgamal-sign)
|
|
74
|
+
- [`elgamal verify`](#elgamal-verify)
|
|
75
|
+
- [`dsa`](#dsa)
|
|
76
|
+
- [`dsa shared`](#dsa-shared)
|
|
77
|
+
- [`dsa new`](#dsa-new)
|
|
78
|
+
- [`dsa sign`](#dsa-sign)
|
|
79
|
+
- [`dsa verify`](#dsa-verify)
|
|
80
|
+
- [`bid`](#bid)
|
|
81
|
+
- [`bid new`](#bid-new)
|
|
82
|
+
- [`bid verify`](#bid-verify)
|
|
83
|
+
- [`sss`](#sss)
|
|
84
|
+
- [`sss new`](#sss-new)
|
|
85
|
+
- [`sss shares`](#sss-shares)
|
|
86
|
+
- [`sss recover`](#sss-recover)
|
|
87
|
+
- [`sss verify`](#sss-verify)
|
|
88
|
+
- [`doc`](#doc)
|
|
89
|
+
- [`doc md`](#doc-md)
|
|
90
|
+
- [Base Library](#base-library)
|
|
91
|
+
- [Humanized Sizes (IEC binary)](#humanized-sizes-iec-binary)
|
|
92
|
+
- [Humanized Decimal Quantities (SI)](#humanized-decimal-quantities-si)
|
|
93
|
+
- [Humanized Durations](#humanized-durations)
|
|
94
|
+
- [Cryptographically Secure Randomness](#cryptographically-secure-randomness)
|
|
95
|
+
- [Fixed-size random integers](#fixed-size-random-integers)
|
|
96
|
+
- [Uniform random integers in a range](#uniform-random-integers-in-a-range)
|
|
97
|
+
- [In-place secure shuffle](#in-place-secure-shuffle)
|
|
98
|
+
- [Random byte strings](#random-byte-strings)
|
|
99
|
+
- [Computing the Greatest Common Divisor](#computing-the-greatest-common-divisor)
|
|
100
|
+
- [Cryptographic Hashing](#cryptographic-hashing)
|
|
101
|
+
- [SHA-256 hashing](#sha-256-hashing)
|
|
102
|
+
- [SHA-512 hashing](#sha-512-hashing)
|
|
103
|
+
- [File hashing](#file-hashing)
|
|
104
|
+
- [Execution Timing](#execution-timing)
|
|
105
|
+
- [Context manager](#context-manager)
|
|
106
|
+
- [Decorator](#decorator)
|
|
107
|
+
- [Manual use](#manual-use)
|
|
108
|
+
- [Key points](#key-points)
|
|
109
|
+
- [Symmetric Encryption Interface](#symmetric-encryption-interface)
|
|
110
|
+
- [Serialization Pipeline](#serialization-pipeline)
|
|
111
|
+
- [Serialize](#serialize)
|
|
112
|
+
- [DeSerialize](#deserialize)
|
|
113
|
+
- [Crypto Objects General Properties (`CryptoKey`)](#crypto-objects-general-properties-cryptokey)
|
|
114
|
+
- [AES-256 Symmetric Encryption](#aes-256-symmetric-encryption)
|
|
115
|
+
- [Key creation](#key-creation)
|
|
116
|
+
- [AES-256 + GCM (default)](#aes-256--gcm-default)
|
|
117
|
+
- [AES-256 + ECB (unsafe, fixed block only)](#aes-256--ecb-unsafe-fixed-block-only)
|
|
118
|
+
- [Fast Modular Arithmetic](#fast-modular-arithmetic)
|
|
119
|
+
- [Chinese Remainder Theorem (CRT) – Pair](#chinese-remainder-theorem-crt--pair)
|
|
120
|
+
- [Modular Polynomials \& Lagrange Interpolation](#modular-polynomials--lagrange-interpolation)
|
|
121
|
+
- [Primality testing \& Prime generators, Mersenne primes](#primality-testing--prime-generators-mersenne-primes)
|
|
122
|
+
- [RSA (Rivest-Shamir-Adleman) Public Cryptography](#rsa-rivest-shamir-adleman-public-cryptography)
|
|
123
|
+
- [El-Gamal Public-Key Cryptography](#el-gamal-public-key-cryptography)
|
|
124
|
+
- [Shared Public Key](#shared-public-key)
|
|
125
|
+
- [Public Key](#public-key)
|
|
126
|
+
- [Private Key](#private-key)
|
|
127
|
+
- [DSA (Digital Signature Algorithm)](#dsa-digital-signature-algorithm)
|
|
128
|
+
- [Security notes](#security-notes)
|
|
129
|
+
- [Advanced: custom primes generator](#advanced-custom-primes-generator)
|
|
130
|
+
- [Public Bidding](#public-bidding)
|
|
131
|
+
- [SSS (Shamir Shared Secret)](#sss-shamir-shared-secret)
|
|
132
|
+
- [Appendix: Development Instructions](#appendix-development-instructions)
|
|
133
|
+
- [Setup](#setup)
|
|
134
|
+
- [Updating Dependencies](#updating-dependencies)
|
|
135
|
+
- [Creating a New Version](#creating-a-new-version)
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
Copyright 2025 Daniel Balparda <balparda@github.com>
|
|
140
|
+
|
|
141
|
+
Licensed under the ***Apache License, Version 2.0*** (the "License"); you may not use this file except in compliance with the License. You may obtain a [copy of the License here](http://www.apache.org/licenses/LICENSE-2.0).
|
|
142
|
+
|
|
143
|
+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
144
|
+
|
|
145
|
+
## Design assumptions / Disclaimers
|
|
146
|
+
|
|
147
|
+
- The library is built to have reference, reliable, simple implementations of math and crypto primitives.
|
|
148
|
+
- All library methods' `int` are tailored to be efficient with arbitrarily large integers.
|
|
149
|
+
- Everything **should work**, as the library is **extensively tested**, *but not necessarily the most efficient or safe for real-world cryptographic use.* For real-world crypto use *other optimized/safe libraries* that were built to be resistant to malicious attacks.
|
|
150
|
+
- *All operations in this library may be vulnerable to timing attacks.*
|
|
151
|
+
- There is some logging and error messages that were written to be clear but in real-life security applications could leak private secrets. Again, this library is not build to be crypto safe. It was built as a simple tested reference implementation.
|
|
152
|
+
|
|
153
|
+
That being said, all care was taken that this is a good library with a solid implementation. *Have fun!*
|
|
154
|
+
|
|
155
|
+
## Install
|
|
156
|
+
|
|
157
|
+
To use in your project just do:
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
pip3 install transcrypto
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
and then `from transcrypto import rsa` (or other parts of the library) for using it.
|
|
164
|
+
|
|
165
|
+
Known dependencies:
|
|
166
|
+
|
|
167
|
+
- [zstandard](https://pypi.org/project/zstandard/) ([docs](https://python-zstandard.readthedocs.org/))
|
|
168
|
+
- [cryptography](https://pypi.org/project/cryptography/) ([docs](https://cryptography.io/en/latest/))
|
|
169
|
+
|
|
170
|
+
<!-- cspell:disable -->
|
|
171
|
+
|
|
172
|
+
<!-- (auto-generated; do not edit between START/END) -->
|
|
173
|
+
<!-- INCLUDE:CLI.md START -->
|
|
174
|
+
|
|
175
|
+
## Command-Line Interface
|
|
176
|
+
|
|
177
|
+
`transcrypto` is a command-line utility that provides access to all core functionality described in this documentation. It serves as a convenient wrapper over the Python APIs, enabling **cryptographic operations**, **number theory functions**, **secure randomness generation**, **hashing**, **AES**, **RSA**, **El-Gamal**, **DSA**, **bidding**, **SSS**, and other utilities without writing code.
|
|
178
|
+
|
|
179
|
+
Invoke with:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
poetry run transcrypto <command> [sub-command] [options...]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Global Options
|
|
186
|
+
|
|
187
|
+
| Option/Arg | Description |
|
|
188
|
+
|---|---|
|
|
189
|
+
| `-v, --verbose` | Increase verbosity (use -v/-vv/-vvv/-vvvv for ERROR/WARN/INFO/DEBUG) |
|
|
190
|
+
| `--hex` | Treat inputs as hex string (default) |
|
|
191
|
+
| `--b64` | Treat inputs as base64url |
|
|
192
|
+
| `--bin` | Treat inputs as binary (bytes) |
|
|
193
|
+
| `--out-hex` | Outputs as hex (default) |
|
|
194
|
+
| `--out-b64` | Outputs as base64url |
|
|
195
|
+
| `--out-bin` | Outputs as binary (bytes) |
|
|
196
|
+
| `-p, --key-path` | File path to serialized key object, if key is needed for operation [type: str] |
|
|
197
|
+
| `--protect` | Password to encrypt/decrypt key file if using the `-p`/`--key-path` option [type: str] |
|
|
198
|
+
|
|
199
|
+
### Top-Level Commands
|
|
200
|
+
|
|
201
|
+
- **`random`** — `poetry run transcrypto random [-h] {bits,int,bytes,prime} ...`
|
|
202
|
+
- **`isprime`** — `poetry run transcrypto isprime [-h] n`
|
|
203
|
+
- **`primegen`** — `poetry run transcrypto primegen [-h] [-c COUNT] start`
|
|
204
|
+
- **`mersenne`** — `poetry run transcrypto mersenne [-h] [-k MIN_K] [-C CUTOFF_K]`
|
|
205
|
+
- **`gcd`** — `poetry run transcrypto gcd [-h] a b`
|
|
206
|
+
- **`xgcd`** — `poetry run transcrypto xgcd [-h] a b`
|
|
207
|
+
- **`mod`** — `poetry run transcrypto mod [-h] {inv,div,exp,poly,lagrange,crt} ...`
|
|
208
|
+
- **`hash`** — `poetry run transcrypto hash [-h] {sha256,sha512,file} ...`
|
|
209
|
+
- **`aes`** — `poetry run transcrypto aes [-h] {key,encrypt,decrypt,ecb} ...`
|
|
210
|
+
- **`rsa`** — `poetry run transcrypto rsa [-h] {new,encrypt,decrypt,sign,verify} ...`
|
|
211
|
+
- **`elgamal`** — `poetry run transcrypto elgamal [-h]`
|
|
212
|
+
- **`dsa`** — `poetry run transcrypto dsa [-h] {shared,new,sign,verify} ...`
|
|
213
|
+
- **`bid`** — `poetry run transcrypto bid [-h] {new,verify} ...`
|
|
214
|
+
- **`sss`** — `poetry run transcrypto sss [-h] {new,shares,recover,verify} ...`
|
|
215
|
+
- **`doc`** — `poetry run transcrypto doc [-h] {md} ...`
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
Examples:
|
|
219
|
+
|
|
220
|
+
# --- Randomness ---
|
|
221
|
+
poetry run transcrypto random bits 16
|
|
222
|
+
poetry run transcrypto random int 1000 2000
|
|
223
|
+
poetry run transcrypto random bytes 32
|
|
224
|
+
poetry run transcrypto random prime 64
|
|
225
|
+
|
|
226
|
+
# --- Primes ---
|
|
227
|
+
poetry run transcrypto isprime 428568761
|
|
228
|
+
poetry run transcrypto primegen 100 -c 3
|
|
229
|
+
poetry run transcrypto mersenne -k 2 -C 17
|
|
230
|
+
|
|
231
|
+
# --- Integer / Modular Math ---
|
|
232
|
+
poetry run transcrypto gcd 462 1071
|
|
233
|
+
poetry run transcrypto xgcd 127 13
|
|
234
|
+
poetry run transcrypto mod inv 17 97
|
|
235
|
+
poetry run transcrypto mod div 6 127 13
|
|
236
|
+
poetry run transcrypto mod exp 438 234 127
|
|
237
|
+
poetry run transcrypto mod poly 12 17 10 20 30
|
|
238
|
+
poetry run transcrypto mod lagrange 5 13 2:4 6:3 7:1
|
|
239
|
+
poetry run transcrypto mod crt 6 7 127 13
|
|
240
|
+
|
|
241
|
+
# --- Hashing ---
|
|
242
|
+
poetry run transcrypto hash sha256 xyz
|
|
243
|
+
poetry run transcrypto --b64 hash sha512 eHl6
|
|
244
|
+
poetry run transcrypto hash file /etc/passwd --digest sha512
|
|
245
|
+
|
|
246
|
+
# --- AES ---
|
|
247
|
+
poetry run transcrypto --out-b64 aes key "correct horse battery staple"
|
|
248
|
+
poetry run transcrypto --b64 --out-b64 aes encrypt -k "<b64key>" "secret"
|
|
249
|
+
poetry run transcrypto --b64 --out-b64 aes decrypt -k "<b64key>" "<ciphertext>"
|
|
250
|
+
poetry run transcrypto aes ecb -k "<b64key>" encrypt "<128bithexblock>"
|
|
251
|
+
poetry run transcrypto aes ecb -k "<b64key>" decrypt "<128bithexblock>"
|
|
252
|
+
|
|
253
|
+
# --- RSA ---
|
|
254
|
+
poetry run transcrypto -p rsa-key rsa new --bits 2048
|
|
255
|
+
poetry run transcrypto -p rsa-key.pub rsa encrypt <plaintext>
|
|
256
|
+
poetry run transcrypto -p rsa-key.priv rsa decrypt <ciphertext>
|
|
257
|
+
poetry run transcrypto -p rsa-key.priv rsa sign <message>
|
|
258
|
+
poetry run transcrypto -p rsa-key.pub rsa verify <message> <signature>
|
|
259
|
+
|
|
260
|
+
# --- ElGamal ---
|
|
261
|
+
poetry run transcrypto -p eg-key elgamal shared --bits 2048
|
|
262
|
+
poetry run transcrypto -p eg-key elgamal new
|
|
263
|
+
poetry run transcrypto -p eg-key.pub elgamal encrypt <plaintext>
|
|
264
|
+
poetry run transcrypto -p eg-key.priv elgamal decrypt <c1:c2>
|
|
265
|
+
poetry run transcrypto -p eg-key.priv elgamal sign <message>
|
|
266
|
+
poetry run transcrypto-p eg-key.pub elgamal verify <message> <s1:s2>
|
|
267
|
+
|
|
268
|
+
# --- DSA ---
|
|
269
|
+
poetry run transcrypto -p dsa-key dsa shared --p-bits 2048 --q-bits 256
|
|
270
|
+
poetry run transcrypto -p dsa-key dsa new
|
|
271
|
+
poetry run transcrypto -p dsa-key.priv dsa sign <message>
|
|
272
|
+
poetry run transcrypto -p dsa-key.pub dsa verify <message> <s1:s2>
|
|
273
|
+
|
|
274
|
+
# --- Public Bid ---
|
|
275
|
+
poetry run transcrypto --bin bid new "tomorrow it will rain"
|
|
276
|
+
poetry run transcrypto --out-bin bid verify
|
|
277
|
+
|
|
278
|
+
# --- Shamir Secret Sharing (SSS) ---
|
|
279
|
+
poetry run transcrypto -p sss-key sss new 3 --bits 1024
|
|
280
|
+
poetry run transcrypto -p sss-key sss shares <secret> 5
|
|
281
|
+
poetry run transcrypto -p sss-key sss recover
|
|
282
|
+
poetry run transcrypto -p sss-key sss verify <secret>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### `random`
|
|
288
|
+
|
|
289
|
+
Cryptographically secure randomness, from the OS CSPRNG.
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
poetry run transcrypto random [-h] {bits,int,bytes,prime} ...
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
#### `random bits`
|
|
296
|
+
|
|
297
|
+
Random integer with exact bit length = `bits` (MSB will be 1).
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
poetry run transcrypto random bits [-h] bits
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
| Option/Arg | Description |
|
|
304
|
+
|---|---|
|
|
305
|
+
| `bits` | Number of bits, ≥ 8 [type: int] |
|
|
306
|
+
|
|
307
|
+
**Example:**
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
$ poetry run transcrypto random bits 16
|
|
311
|
+
36650
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### `random int`
|
|
315
|
+
|
|
316
|
+
Uniform random integer in `[min, max]` range, inclusive.
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
poetry run transcrypto random int [-h] min max
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
| Option/Arg | Description |
|
|
323
|
+
|---|---|
|
|
324
|
+
| `min` | Minimum, ≥ 0 [type: str] |
|
|
325
|
+
| `max` | Maximum, > `min` [type: str] |
|
|
326
|
+
|
|
327
|
+
**Example:**
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
$ poetry run transcrypto random int 1000 2000
|
|
331
|
+
1628
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
#### `random bytes`
|
|
335
|
+
|
|
336
|
+
Generates `n` cryptographically secure random bytes.
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
poetry run transcrypto random bytes [-h] n
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
| Option/Arg | Description |
|
|
343
|
+
|---|---|
|
|
344
|
+
| `n` | Number of bytes, ≥ 1 [type: int] |
|
|
345
|
+
|
|
346
|
+
**Example:**
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
$ poetry run transcrypto random bytes 32
|
|
350
|
+
6c6f1f88cb93c4323285a2224373d6e59c72a9c2b82e20d1c376df4ffbe9507f
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### `random prime`
|
|
354
|
+
|
|
355
|
+
Generate a random prime with exact bit length = `bits` (MSB will be 1).
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
poetry run transcrypto random prime [-h] bits
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
| Option/Arg | Description |
|
|
362
|
+
|---|---|
|
|
363
|
+
| `bits` | Bit length, ≥ 11 [type: int] |
|
|
364
|
+
|
|
365
|
+
**Example:**
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
$ poetry run transcrypto random prime 32
|
|
369
|
+
2365910551
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### `isprime`
|
|
375
|
+
|
|
376
|
+
Primality test with safe defaults, useful for any integer size.
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
poetry run transcrypto isprime [-h] n
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
| Option/Arg | Description |
|
|
383
|
+
|---|---|
|
|
384
|
+
| `n` | Integer to test, ≥ 1 [type: str] |
|
|
385
|
+
|
|
386
|
+
**Example:**
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
$ poetry run transcrypto isprime 2305843009213693951
|
|
390
|
+
True
|
|
391
|
+
$ poetry run transcrypto isprime 2305843009213693953
|
|
392
|
+
False
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
### `primegen`
|
|
398
|
+
|
|
399
|
+
Generate (stream) primes ≥ `start` (prints a limited `count` by default).
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
poetry run transcrypto primegen [-h] [-c COUNT] start
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
| Option/Arg | Description |
|
|
406
|
+
|---|---|
|
|
407
|
+
| `start` | Starting integer (inclusive) [type: str] |
|
|
408
|
+
| `-c, --count` | How many to print (0 = unlimited) [type: int (default: 10)] |
|
|
409
|
+
|
|
410
|
+
**Example:**
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
$ poetry run transcrypto primegen 100 -c 3
|
|
414
|
+
101
|
|
415
|
+
103
|
|
416
|
+
107
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
### `mersenne`
|
|
422
|
+
|
|
423
|
+
Generate (stream) Mersenne prime exponents `k`, also outputting `2^k-1` (the Mersenne prime, `M`) and `M×2^(k-1)` (the associated perfect number), starting at `min-k` and stopping once `k` > `cutoff-k`.
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
poetry run transcrypto mersenne [-h] [-k MIN_K] [-C CUTOFF_K]
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
| Option/Arg | Description |
|
|
430
|
+
|---|---|
|
|
431
|
+
| `-k, --min-k` | Starting exponent `k`, ≥ 1 [type: int (default: 1)] |
|
|
432
|
+
| `-C, --cutoff-k` | Stop once `k` > `cutoff-k` [type: int (default: 10000)] |
|
|
433
|
+
|
|
434
|
+
**Example:**
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
$ poetry run transcrypto mersenne -k 0 -C 15
|
|
438
|
+
k=2 M=3 perfect=6
|
|
439
|
+
k=3 M=7 perfect=28
|
|
440
|
+
k=5 M=31 perfect=496
|
|
441
|
+
k=7 M=127 perfect=8128
|
|
442
|
+
k=13 M=8191 perfect=33550336
|
|
443
|
+
k=17 M=131071 perfect=8589869056
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
### `gcd`
|
|
449
|
+
|
|
450
|
+
Greatest Common Divisor (GCD) of integers `a` and `b`.
|
|
451
|
+
|
|
452
|
+
```bash
|
|
453
|
+
poetry run transcrypto gcd [-h] a b
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
| Option/Arg | Description |
|
|
457
|
+
|---|---|
|
|
458
|
+
| `a` | Integer, ≥ 0 [type: str] |
|
|
459
|
+
| `b` | Integer, ≥ 0 (can't be both zero) [type: str] |
|
|
460
|
+
|
|
461
|
+
**Example:**
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
$ poetry run transcrypto gcd 462 1071
|
|
465
|
+
21
|
|
466
|
+
$ poetry run transcrypto gcd 0 5
|
|
467
|
+
5
|
|
468
|
+
$ poetry run transcrypto gcd 127 13
|
|
469
|
+
1
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
### `xgcd`
|
|
475
|
+
|
|
476
|
+
Extended Greatest Common Divisor (x-GCD) of integers `a` and `b`, will return `(g, x, y)` where `a×x+b×y==g`.
|
|
477
|
+
|
|
478
|
+
```bash
|
|
479
|
+
poetry run transcrypto xgcd [-h] a b
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
| Option/Arg | Description |
|
|
483
|
+
|---|---|
|
|
484
|
+
| `a` | Integer, ≥ 0 [type: str] |
|
|
485
|
+
| `b` | Integer, ≥ 0 (can't be both zero) [type: str] |
|
|
486
|
+
|
|
487
|
+
**Example:**
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
$ poetry run transcrypto xgcd 462 1071
|
|
491
|
+
(21, 7, -3)
|
|
492
|
+
$ poetry run transcrypto xgcd 0 5
|
|
493
|
+
(5, 0, 1)
|
|
494
|
+
$ poetry run transcrypto xgcd 127 13
|
|
495
|
+
(1, 4, -39)
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
### `mod`
|
|
501
|
+
|
|
502
|
+
Modular arithmetic helpers.
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
poetry run transcrypto mod [-h] {inv,div,exp,poly,lagrange,crt} ...
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### `mod inv`
|
|
509
|
+
|
|
510
|
+
Modular inverse: find integer 0≤`i`<`m` such that `a×i ≡ 1 (mod m)`. Will only work if `gcd(a,m)==1`, else will fail with a message.
|
|
511
|
+
|
|
512
|
+
```bash
|
|
513
|
+
poetry run transcrypto mod inv [-h] a m
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
| Option/Arg | Description |
|
|
517
|
+
|---|---|
|
|
518
|
+
| `a` | Integer to invert [type: str] |
|
|
519
|
+
| `m` | Modulus `m`, ≥ 2 [type: str] |
|
|
520
|
+
|
|
521
|
+
**Example:**
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
$ poetry run transcrypto mod inv 127 13
|
|
525
|
+
4
|
|
526
|
+
$ poetry run transcrypto mod inv 17 3120
|
|
527
|
+
2753
|
|
528
|
+
$ poetry run transcrypto mod inv 462 1071
|
|
529
|
+
<<INVALID>> no modular inverse exists (ModularDivideError)
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
#### `mod div`
|
|
533
|
+
|
|
534
|
+
Modular division: find integer 0≤`z`<`m` such that `z×y ≡ x (mod m)`. Will only work if `gcd(y,m)==1` and `y!=0`, else will fail with a message.
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
poetry run transcrypto mod div [-h] x y m
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
| Option/Arg | Description |
|
|
541
|
+
|---|---|
|
|
542
|
+
| `x` | Integer [type: str] |
|
|
543
|
+
| `y` | Integer, cannot be zero [type: str] |
|
|
544
|
+
| `m` | Modulus `m`, ≥ 2 [type: str] |
|
|
545
|
+
|
|
546
|
+
**Example:**
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
$ poetry run transcrypto mod div 6 127 13
|
|
550
|
+
11
|
|
551
|
+
$ poetry run transcrypto mod div 6 0 13
|
|
552
|
+
<<INVALID>> no modular inverse exists (ModularDivideError)
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
#### `mod exp`
|
|
556
|
+
|
|
557
|
+
Modular exponentiation: `a^e mod m`. Efficient, can handle huge values.
|
|
558
|
+
|
|
559
|
+
```bash
|
|
560
|
+
poetry run transcrypto mod exp [-h] a e m
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
| Option/Arg | Description |
|
|
564
|
+
|---|---|
|
|
565
|
+
| `a` | Integer [type: str] |
|
|
566
|
+
| `e` | Integer, ≥ 0 [type: str] |
|
|
567
|
+
| `m` | Modulus `m`, ≥ 2 [type: str] |
|
|
568
|
+
|
|
569
|
+
**Example:**
|
|
570
|
+
|
|
571
|
+
```bash
|
|
572
|
+
$ poetry run transcrypto mod exp 438 234 127
|
|
573
|
+
32
|
|
574
|
+
$ poetry run transcrypto mod exp 438 234 89854
|
|
575
|
+
60622
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
#### `mod poly`
|
|
579
|
+
|
|
580
|
+
Efficiently evaluate polynomial with `coeff` coefficients at point `x` modulo `m` (`c₀+c₁×x+c₂×x²+…+cₙ×xⁿ mod m`).
|
|
581
|
+
|
|
582
|
+
```bash
|
|
583
|
+
poetry run transcrypto mod poly [-h] x m coeff [coeff ...]
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
| Option/Arg | Description |
|
|
587
|
+
|---|---|
|
|
588
|
+
| `x` | Evaluation point `x` [type: str] |
|
|
589
|
+
| `m` | Modulus `m`, ≥ 2 [type: str] |
|
|
590
|
+
| `coeff` | Coefficients (constant-term first: `c₀+c₁×x+c₂×x²+…+cₙ×xⁿ`) [nargs: +] |
|
|
591
|
+
|
|
592
|
+
**Example:**
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
$ poetry run transcrypto mod poly 12 17 10 20 30
|
|
596
|
+
14 # (10+20×12+30×12² ≡ 14 (mod 17))
|
|
597
|
+
$ poetry run transcrypto mod poly 10 97 3 0 0 1 1
|
|
598
|
+
42 # (3+1×10³+1×10⁴ ≡ 42 (mod 97))
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
#### `mod lagrange`
|
|
602
|
+
|
|
603
|
+
Lagrange interpolation over modulus `m`: find the `f(x)` solution for the given `x` and `zₙ:f(zₙ)` points `pt`. The modulus `m` must be a prime.
|
|
604
|
+
|
|
605
|
+
```bash
|
|
606
|
+
poetry run transcrypto mod lagrange [-h] x m pt [pt ...]
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
| Option/Arg | Description |
|
|
610
|
+
|---|---|
|
|
611
|
+
| `x` | Evaluation point `x` [type: str] |
|
|
612
|
+
| `m` | Modulus `m`, ≥ 2 [type: str] |
|
|
613
|
+
| `pt` | Points `zₙ:f(zₙ)` as `key:value` pairs (e.g., `2:4 5:3 7:1`) [nargs: +] |
|
|
614
|
+
|
|
615
|
+
**Example:**
|
|
616
|
+
|
|
617
|
+
```bash
|
|
618
|
+
$ poetry run transcrypto mod lagrange 5 13 2:4 6:3 7:1
|
|
619
|
+
3 # passes through (2,4), (6,3), (7,1)
|
|
620
|
+
$ poetry run transcrypto mod lagrange 11 97 1:1 2:4 3:9 4:16 5:25
|
|
621
|
+
24 # passes through (1,1), (2,4), (3,9), (4,16), (5,25)
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
#### `mod crt`
|
|
625
|
+
|
|
626
|
+
Solves Chinese Remainder Theorem (CRT) Pair: finds the unique integer 0≤`x`<`(m1×m2)` satisfying both `x ≡ a1 (mod m1)` and `x ≡ a2 (mod m2)`, if `gcd(m1,m2)==1`.
|
|
627
|
+
|
|
628
|
+
```bash
|
|
629
|
+
poetry run transcrypto mod crt [-h] a1 m1 a2 m2
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
| Option/Arg | Description |
|
|
633
|
+
|---|---|
|
|
634
|
+
| `a1` | Integer residue for first congruence [type: str] |
|
|
635
|
+
| `m1` | Modulus `m1`, ≥ 2 and `gcd(m1,m2)==1` [type: str] |
|
|
636
|
+
| `a2` | Integer residue for second congruence [type: str] |
|
|
637
|
+
| `m2` | Modulus `m2`, ≥ 2 and `gcd(m1,m2)==1` [type: str] |
|
|
638
|
+
|
|
639
|
+
**Example:**
|
|
640
|
+
|
|
641
|
+
```bash
|
|
642
|
+
$ poetry run transcrypto mod crt 6 7 127 13
|
|
643
|
+
62
|
|
644
|
+
$ poetry run transcrypto mod crt 12 56 17 19
|
|
645
|
+
796
|
|
646
|
+
$ poetry run transcrypto mod crt 6 7 462 1071
|
|
647
|
+
<<INVALID>> moduli m1/m2 not co-prime (ModularDivideError)
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
### `hash`
|
|
653
|
+
|
|
654
|
+
Cryptographic Hashing (SHA-256 / SHA-512 / file).
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
poetry run transcrypto hash [-h] {sha256,sha512,file} ...
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
#### `hash sha256`
|
|
661
|
+
|
|
662
|
+
SHA-256 of input `data`.
|
|
663
|
+
|
|
664
|
+
```bash
|
|
665
|
+
poetry run transcrypto hash sha256 [-h] data
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
| Option/Arg | Description |
|
|
669
|
+
|---|---|
|
|
670
|
+
| `data` | Input data (raw text; or use --hex/--b64/--bin) [type: str] |
|
|
671
|
+
|
|
672
|
+
**Example:**
|
|
673
|
+
|
|
674
|
+
```bash
|
|
675
|
+
$ poetry run transcrypto --bin hash sha256 xyz
|
|
676
|
+
3608bca1e44ea6c4d268eb6db02260269892c0b42b86bbf1e77a6fa16c3c9282
|
|
677
|
+
$ poetry run transcrypto --b64 hash sha256 eHl6 # "xyz" in base-64
|
|
678
|
+
3608bca1e44ea6c4d268eb6db02260269892c0b42b86bbf1e77a6fa16c3c9282
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
#### `hash sha512`
|
|
682
|
+
|
|
683
|
+
SHA-512 of input `data`.
|
|
684
|
+
|
|
685
|
+
```bash
|
|
686
|
+
poetry run transcrypto hash sha512 [-h] data
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
| Option/Arg | Description |
|
|
690
|
+
|---|---|
|
|
691
|
+
| `data` | Input data (raw text; or use --hex/--b64/--bin) [type: str] |
|
|
692
|
+
|
|
693
|
+
**Example:**
|
|
694
|
+
|
|
695
|
+
```bash
|
|
696
|
+
$ poetry run transcrypto --bin hash sha512 xyz
|
|
697
|
+
4a3ed8147e37876adc8f76328e5abcc1b470e6acfc18efea0135f983604953a58e183c1a6086e91ba3e821d926f5fdeb37761c7ca0328a963f5e92870675b728
|
|
698
|
+
$ poetry run transcrypto --b64 hash sha512 eHl6 # "xyz" in base-64
|
|
699
|
+
4a3ed8147e37876adc8f76328e5abcc1b470e6acfc18efea0135f983604953a58e183c1a6086e91ba3e821d926f5fdeb37761c7ca0328a963f5e92870675b728
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
#### `hash file`
|
|
703
|
+
|
|
704
|
+
SHA-256/512 hash of file contents, defaulting to SHA-256.
|
|
705
|
+
|
|
706
|
+
```bash
|
|
707
|
+
poetry run transcrypto hash file [-h] [--digest {sha256,sha512}] path
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
| Option/Arg | Description |
|
|
711
|
+
|---|---|
|
|
712
|
+
| `path` | Path to existing file [type: str] |
|
|
713
|
+
| `--digest` | Digest type, SHA-256 ("sha256") or SHA-512 ("sha512") [choices: ['sha256', 'sha512'] (default: sha256)] |
|
|
714
|
+
|
|
715
|
+
**Example:**
|
|
716
|
+
|
|
717
|
+
```bash
|
|
718
|
+
$ poetry run transcrypto hash file /etc/passwd --digest sha512
|
|
719
|
+
8966f5953e79f55dfe34d3dc5b160ac4a4a3f9cbd1c36695a54e28d77c7874dff8595502f8a420608911b87d336d9e83c890f0e7ec11a76cb10b03e757f78aea
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
### `aes`
|
|
725
|
+
|
|
726
|
+
AES-256 operations (GCM/ECB) and key derivation. No measures are taken here to prevent timing attacks.
|
|
727
|
+
|
|
728
|
+
```bash
|
|
729
|
+
poetry run transcrypto aes [-h] {key,encrypt,decrypt,ecb} ...
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
#### `aes key`
|
|
733
|
+
|
|
734
|
+
Derive key from a password (PBKDF2-HMAC-SHA256) with custom expensive salt and iterations. Very good/safe for simple password-to-key but not for passwords databases (because of constant salt).
|
|
735
|
+
|
|
736
|
+
```bash
|
|
737
|
+
poetry run transcrypto aes key [-h] password
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
| Option/Arg | Description |
|
|
741
|
+
|---|---|
|
|
742
|
+
| `password` | Password (leading/trailing spaces ignored) [type: str] |
|
|
743
|
+
|
|
744
|
+
**Example:**
|
|
745
|
+
|
|
746
|
+
```bash
|
|
747
|
+
$ poetry run transcrypto --out-b64 aes key "correct horse battery staple"
|
|
748
|
+
DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es=
|
|
749
|
+
$ poetry run transcrypto -p keyfile.out --protect hunter aes key "correct horse battery staple"
|
|
750
|
+
AES key saved to 'keyfile.out'
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
#### `aes encrypt`
|
|
754
|
+
|
|
755
|
+
AES-256-GCM: safely encrypt `plaintext` with `-k`/`--key` or with `-p`/`--key-path` keyfile. All inputs are raw, or you can use `--bin`/`--hex`/`--b64` flags. Attention: if you provide `-a`/`--aad` (associated data, AAD), you will need to provide the same AAD when decrypting and it is NOT included in the `ciphertext`/CT returned by this method!
|
|
756
|
+
|
|
757
|
+
```bash
|
|
758
|
+
poetry run transcrypto aes encrypt [-h] [-k KEY] [-a AAD] plaintext
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
| Option/Arg | Description |
|
|
762
|
+
|---|---|
|
|
763
|
+
| `plaintext` | Input data to encrypt (PT) [type: str] |
|
|
764
|
+
| `-k, --key` | Key if `-p`/`--key-path` wasn't used (32 bytes) [type: str] |
|
|
765
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
766
|
+
|
|
767
|
+
**Example:**
|
|
768
|
+
|
|
769
|
+
```bash
|
|
770
|
+
$ poetry run transcrypto --b64 --out-b64 aes encrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= AAAAAAB4eXo=
|
|
771
|
+
F2_ZLrUw5Y8oDnbTP5t5xCUWX8WtVILLD0teyUi_37_4KHeV-YowVA==
|
|
772
|
+
$ poetry run transcrypto --b64 --out-b64 aes encrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -a eHl6 AAAAAAB4eXo=
|
|
773
|
+
xOlAHPUPpeyZHId-f3VQ_QKKMxjIW0_FBo9WOfIBrzjn0VkVV6xTRA==
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
#### `aes decrypt`
|
|
777
|
+
|
|
778
|
+
AES-256-GCM: safely decrypt `ciphertext` with `-k`/`--key` or with `-p`/`--key-path` keyfile. All inputs are raw, or you can use `--bin`/`--hex`/`--b64` flags. Attention: if you provided `-a`/`--aad` (associated data, AAD) during encryption, you will need to provide the same AAD now!
|
|
779
|
+
|
|
780
|
+
```bash
|
|
781
|
+
poetry run transcrypto aes decrypt [-h] [-k KEY] [-a AAD] ciphertext
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
| Option/Arg | Description |
|
|
785
|
+
|---|---|
|
|
786
|
+
| `ciphertext` | Input data to decrypt (CT) [type: str] |
|
|
787
|
+
| `-k, --key` | Key if `-p`/`--key-path` wasn't used (32 bytes) [type: str] |
|
|
788
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during encryption) [type: str] |
|
|
789
|
+
|
|
790
|
+
**Example:**
|
|
791
|
+
|
|
792
|
+
```bash
|
|
793
|
+
$ poetry run transcrypto --b64 --out-b64 aes decrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= F2_ZLrUw5Y8oDnbTP5t5xCUWX8WtVILLD0teyUi_37_4KHeV-YowVA==
|
|
794
|
+
AAAAAAB4eXo=
|
|
795
|
+
$ poetry run transcrypto --b64 --out-b64 aes decrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -a eHl6 xOlAHPUPpeyZHId-f3VQ_QKKMxjIW0_FBo9WOfIBrzjn0VkVV6xTRA==
|
|
796
|
+
AAAAAAB4eXo=
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
#### `aes ecb`
|
|
800
|
+
|
|
801
|
+
AES-256-ECB: encrypt/decrypt 128 bit (16 bytes) hexadecimal blocks. UNSAFE, except for specifically encrypting hash blocks which are very much expected to look random. ECB mode will have the same output for the same input (no IV/nonce is used).
|
|
802
|
+
|
|
803
|
+
```bash
|
|
804
|
+
poetry run transcrypto aes ecb [-h] [-k KEY] {encrypt,decrypt} ...
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
| Option/Arg | Description |
|
|
808
|
+
|---|---|
|
|
809
|
+
| `-k, --key` | Key if `-p`/`--key-path` wasn't used (32 bytes; raw, or you can use `--bin`/`--hex`/`--b64` flags) [type: str] |
|
|
810
|
+
|
|
811
|
+
#### `aes ecb encrypt`
|
|
812
|
+
|
|
813
|
+
AES-256-ECB: encrypt 16-bytes hex `plaintext` with `-k`/`--key` or with `-p`/`--key-path` keyfile. UNSAFE, except for specifically encrypting hash blocks.
|
|
814
|
+
|
|
815
|
+
```bash
|
|
816
|
+
poetry run transcrypto aes ecb encrypt [-h] plaintext
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
| Option/Arg | Description |
|
|
820
|
+
|---|---|
|
|
821
|
+
| `plaintext` | Plaintext block as 32 hex chars (16-bytes) [type: str] |
|
|
822
|
+
|
|
823
|
+
**Example:**
|
|
824
|
+
|
|
825
|
+
```bash
|
|
826
|
+
$ poetry run transcrypto --b64 aes ecb -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= encrypt 00112233445566778899aabbccddeeff
|
|
827
|
+
54ec742ca3da7b752e527b74e3a798d7
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
#### `aes ecb decrypt`
|
|
831
|
+
|
|
832
|
+
AES-256-ECB: decrypt 16-bytes hex `ciphertext` with `-k`/`--key` or with `-p`/`--key-path` keyfile. UNSAFE, except for specifically encrypting hash blocks.
|
|
833
|
+
|
|
834
|
+
```bash
|
|
835
|
+
poetry run transcrypto aes ecb decrypt [-h] ciphertext
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
| Option/Arg | Description |
|
|
839
|
+
|---|---|
|
|
840
|
+
| `ciphertext` | Ciphertext block as 32 hex chars (16-bytes) [type: str] |
|
|
841
|
+
|
|
842
|
+
**Example:**
|
|
843
|
+
|
|
844
|
+
```bash
|
|
845
|
+
$ poetry run transcrypto --b64 aes ecb -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= decrypt 54ec742ca3da7b752e527b74e3a798d7
|
|
846
|
+
00112233445566778899aabbccddeeff
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
---
|
|
850
|
+
|
|
851
|
+
### `rsa`
|
|
852
|
+
|
|
853
|
+
Raw RSA (Rivest-Shamir-Adleman) asymmetric cryptography over *integers* (BEWARE: no OAEP/PSS padding or validation). These are pedagogical/raw primitives; do not use for new protocols. No measures are taken here to prevent timing attacks. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
854
|
+
|
|
855
|
+
```bash
|
|
856
|
+
poetry run transcrypto rsa [-h] {new,encrypt,decrypt,sign,verify} ...
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
#### `rsa new`
|
|
860
|
+
|
|
861
|
+
Generate RSA private/public key pair with `bits` modulus size (prime sizes will be `bits`/2). Requires `-p`/`--key-path` to set the basename for output files.
|
|
862
|
+
|
|
863
|
+
```bash
|
|
864
|
+
poetry run transcrypto rsa new [-h] [--bits BITS]
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
| Option/Arg | Description |
|
|
868
|
+
|---|---|
|
|
869
|
+
| `--bits` | Modulus size in bits; the default is a safe size [type: int (default: 3332)] |
|
|
870
|
+
|
|
871
|
+
**Example:**
|
|
872
|
+
|
|
873
|
+
```bash
|
|
874
|
+
$ poetry run transcrypto -p rsa-key rsa new --bits 64 # NEVER use such a small key: example only!
|
|
875
|
+
RSA private/public keys saved to 'rsa-key.priv/.pub'
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
#### `rsa encrypt`
|
|
879
|
+
|
|
880
|
+
Encrypt integer `message` with public key.
|
|
881
|
+
|
|
882
|
+
```bash
|
|
883
|
+
poetry run transcrypto rsa encrypt [-h] message
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
| Option/Arg | Description |
|
|
887
|
+
|---|---|
|
|
888
|
+
| `message` | Integer message to encrypt, 1≤`message`<*modulus* [type: str] |
|
|
889
|
+
|
|
890
|
+
**Example:**
|
|
891
|
+
|
|
892
|
+
```bash
|
|
893
|
+
$ poetry run transcrypto -p rsa-key.pub rsa encrypt 999
|
|
894
|
+
6354905961171348600
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
#### `rsa decrypt`
|
|
898
|
+
|
|
899
|
+
Decrypt integer `ciphertext` with private key.
|
|
900
|
+
|
|
901
|
+
```bash
|
|
902
|
+
poetry run transcrypto rsa decrypt [-h] ciphertext
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
| Option/Arg | Description |
|
|
906
|
+
|---|---|
|
|
907
|
+
| `ciphertext` | Integer ciphertext to decrypt, 1≤`ciphertext`<*modulus* [type: str] |
|
|
908
|
+
|
|
909
|
+
**Example:**
|
|
910
|
+
|
|
911
|
+
```bash
|
|
912
|
+
$ poetry run transcrypto -p rsa-key.priv rsa decrypt 6354905961171348600
|
|
913
|
+
999
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
#### `rsa sign`
|
|
917
|
+
|
|
918
|
+
Sign integer `message` with private key.
|
|
919
|
+
|
|
920
|
+
```bash
|
|
921
|
+
poetry run transcrypto rsa sign [-h] message
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
| Option/Arg | Description |
|
|
925
|
+
|---|---|
|
|
926
|
+
| `message` | Integer message to sign, 1≤`message`<*modulus* [type: str] |
|
|
927
|
+
|
|
928
|
+
**Example:**
|
|
929
|
+
|
|
930
|
+
```bash
|
|
931
|
+
$ poetry run transcrypto -p rsa-key.priv rsa sign 999
|
|
932
|
+
7632909108672871784
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
#### `rsa verify`
|
|
936
|
+
|
|
937
|
+
Verify integer `signature` for integer `message` with public key.
|
|
938
|
+
|
|
939
|
+
```bash
|
|
940
|
+
poetry run transcrypto rsa verify [-h] message signature
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
| Option/Arg | Description |
|
|
944
|
+
|---|---|
|
|
945
|
+
| `message` | Integer message that was signed earlier, 1≤`message`<*modulus* [type: str] |
|
|
946
|
+
| `signature` | Integer putative signature for `message`, 1≤`signature`<*modulus* [type: str] |
|
|
947
|
+
|
|
948
|
+
**Example:**
|
|
949
|
+
|
|
950
|
+
```bash
|
|
951
|
+
$ poetry run transcrypto -p rsa-key.pub rsa verify 999 7632909108672871784
|
|
952
|
+
RSA signature: OK
|
|
953
|
+
$ poetry run transcrypto -p rsa-key.pub rsa verify 999 7632909108672871785
|
|
954
|
+
RSA signature: INVALID
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
---
|
|
958
|
+
|
|
959
|
+
### `elgamal`
|
|
960
|
+
|
|
961
|
+
Raw El-Gamal asymmetric cryptography over *integers* (BEWARE: no ECIES-style KEM/DEM padding or validation). These are pedagogical/raw primitives; do not use for new protocols. No measures are taken here to prevent timing attacks. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
962
|
+
|
|
963
|
+
```bash
|
|
964
|
+
poetry run transcrypto elgamal [-h]
|
|
965
|
+
{shared,new,encrypt,decrypt,sign,verify} ...
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
#### `elgamal shared`
|
|
969
|
+
|
|
970
|
+
Generate a shared El-Gamal key with `bits` prime modulus size, which is the first step in key generation. The shared key can safely be used by any number of users to generate their private/public key pairs (with the `new` command). The shared keys are "public". Requires `-p`/`--key-path` to set the basename for output files.
|
|
971
|
+
|
|
972
|
+
```bash
|
|
973
|
+
poetry run transcrypto elgamal shared [-h] [--bits BITS]
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
| Option/Arg | Description |
|
|
977
|
+
|---|---|
|
|
978
|
+
| `--bits` | Prime modulus (`p`) size in bits; the default is a safe size [type: int (default: 3332)] |
|
|
979
|
+
|
|
980
|
+
**Example:**
|
|
981
|
+
|
|
982
|
+
```bash
|
|
983
|
+
$ poetry run transcrypto -p eg-key elgamal shared --bits 64 # NEVER use such a small key: example only!
|
|
984
|
+
El-Gamal shared key saved to 'eg-key.shared'
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
#### `elgamal new`
|
|
988
|
+
|
|
989
|
+
Generate an individual El-Gamal private/public key pair from a shared key.
|
|
990
|
+
|
|
991
|
+
```bash
|
|
992
|
+
poetry run transcrypto elgamal new [-h]
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
**Example:**
|
|
996
|
+
|
|
997
|
+
```bash
|
|
998
|
+
$ poetry run transcrypto -p eg-key elgamal new
|
|
999
|
+
El-Gamal private/public keys saved to 'eg-key.priv/.pub'
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
#### `elgamal encrypt`
|
|
1003
|
+
|
|
1004
|
+
Encrypt integer `message` with public key.
|
|
1005
|
+
|
|
1006
|
+
```bash
|
|
1007
|
+
poetry run transcrypto elgamal encrypt [-h] message
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
| Option/Arg | Description |
|
|
1011
|
+
|---|---|
|
|
1012
|
+
| `message` | Integer message to encrypt, 1≤`message`<*modulus* [type: str] |
|
|
1013
|
+
|
|
1014
|
+
**Example:**
|
|
1015
|
+
|
|
1016
|
+
```bash
|
|
1017
|
+
$ poetry run transcrypto -p eg-key.pub elgamal encrypt 999
|
|
1018
|
+
2948854810728206041:15945988196340032688
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
#### `elgamal decrypt`
|
|
1022
|
+
|
|
1023
|
+
Decrypt integer `ciphertext` with private key.
|
|
1024
|
+
|
|
1025
|
+
```bash
|
|
1026
|
+
poetry run transcrypto elgamal decrypt [-h] ciphertext
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
| Option/Arg | Description |
|
|
1030
|
+
|---|---|
|
|
1031
|
+
| `ciphertext` | Integer ciphertext to decrypt; expects `c1:c2` format with 2 integers, 2≤`c1`,`c2`<*modulus* [type: str] |
|
|
1032
|
+
|
|
1033
|
+
**Example:**
|
|
1034
|
+
|
|
1035
|
+
```bash
|
|
1036
|
+
$ poetry run transcrypto -p eg-key.priv elgamal decrypt 2948854810728206041:15945988196340032688
|
|
1037
|
+
999
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
#### `elgamal sign`
|
|
1041
|
+
|
|
1042
|
+
Sign integer message with private key. Output will 2 integers in a `s1:s2` format.
|
|
1043
|
+
|
|
1044
|
+
```bash
|
|
1045
|
+
poetry run transcrypto elgamal sign [-h] message
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
| Option/Arg | Description |
|
|
1049
|
+
|---|---|
|
|
1050
|
+
| `message` | Integer message to sign, 1≤`message`<*modulus* [type: str] |
|
|
1051
|
+
|
|
1052
|
+
**Example:**
|
|
1053
|
+
|
|
1054
|
+
```bash
|
|
1055
|
+
$ poetry run transcrypto -p eg-key.priv elgamal sign 999
|
|
1056
|
+
4674885853217269088:14532144906178302633
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
#### `elgamal verify`
|
|
1060
|
+
|
|
1061
|
+
Verify integer `signature` for integer `message` with public key.
|
|
1062
|
+
|
|
1063
|
+
```bash
|
|
1064
|
+
poetry run transcrypto elgamal verify [-h] message signature
|
|
1065
|
+
```
|
|
1066
|
+
|
|
1067
|
+
| Option/Arg | Description |
|
|
1068
|
+
|---|---|
|
|
1069
|
+
| `message` | Integer message that was signed earlier, 1≤`message`<*modulus* [type: str] |
|
|
1070
|
+
| `signature` | Integer putative signature for `message`; expects `s1:s2` format with 2 integers, 2≤`s1`,`s2`<*modulus* [type: str] |
|
|
1071
|
+
|
|
1072
|
+
**Example:**
|
|
1073
|
+
|
|
1074
|
+
```bash
|
|
1075
|
+
$ poetry run transcrypto -p eg-key.pub elgamal verify 999 4674885853217269088:14532144906178302633
|
|
1076
|
+
El-Gamal signature: OK
|
|
1077
|
+
$ poetry run transcrypto -p eg-key.pub elgamal verify 999 4674885853217269088:14532144906178302632
|
|
1078
|
+
El-Gamal signature: INVALID
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
---
|
|
1082
|
+
|
|
1083
|
+
### `dsa`
|
|
1084
|
+
|
|
1085
|
+
Raw DSA (Digital Signature Algorithm) asymmetric signing over *integers* (BEWARE: no ECDSA/EdDSA padding or validation). These are pedagogical/raw primitives; do not use for new protocols. No measures are taken here to prevent timing attacks. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
1086
|
+
|
|
1087
|
+
```bash
|
|
1088
|
+
poetry run transcrypto dsa [-h] {shared,new,sign,verify} ...
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
#### `dsa shared`
|
|
1092
|
+
|
|
1093
|
+
Generate a shared DSA key with `p-bits`/`q-bits` prime modulus sizes, which is the first step in key generation. `q-bits` should be larger than the secrets that will be protected and `p-bits` should be much larger than `q-bits` (e.g. 3584/256). The shared key can safely be used by any number of users to generate their private/public key pairs (with the `new` command). The shared keys are "public". Requires `-p`/`--key-path` to set the basename for output files.
|
|
1094
|
+
|
|
1095
|
+
```bash
|
|
1096
|
+
poetry run transcrypto dsa shared [-h] [--p-bits P_BITS]
|
|
1097
|
+
[--q-bits Q_BITS]
|
|
1098
|
+
```
|
|
1099
|
+
|
|
1100
|
+
| Option/Arg | Description |
|
|
1101
|
+
|---|---|
|
|
1102
|
+
| `--p-bits` | Prime modulus (`p`) size in bits; the default is a safe size [type: int (default: 3584)] |
|
|
1103
|
+
| `--q-bits` | Prime modulus (`q`) size in bits; the default is a safe size ***IFF*** you are protecting symmetric keys or regular hashes [type: int (default: 256)] |
|
|
1104
|
+
|
|
1105
|
+
**Example:**
|
|
1106
|
+
|
|
1107
|
+
```bash
|
|
1108
|
+
$ poetry run transcrypto -p dsa-key dsa shared --p-bits 128 --q-bits 32 # NEVER use such a small key: example only!
|
|
1109
|
+
DSA shared key saved to 'dsa-key.shared'
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
#### `dsa new`
|
|
1113
|
+
|
|
1114
|
+
Generate an individual DSA private/public key pair from a shared key.
|
|
1115
|
+
|
|
1116
|
+
```bash
|
|
1117
|
+
poetry run transcrypto dsa new [-h]
|
|
1118
|
+
```
|
|
1119
|
+
|
|
1120
|
+
**Example:**
|
|
1121
|
+
|
|
1122
|
+
```bash
|
|
1123
|
+
$ poetry run transcrypto -p dsa-key dsa new
|
|
1124
|
+
DSA private/public keys saved to 'dsa-key.priv/.pub'
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
#### `dsa sign`
|
|
1128
|
+
|
|
1129
|
+
Sign integer message with private key. Output will 2 integers in a `s1:s2` format.
|
|
1130
|
+
|
|
1131
|
+
```bash
|
|
1132
|
+
poetry run transcrypto dsa sign [-h] message
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
| Option/Arg | Description |
|
|
1136
|
+
|---|---|
|
|
1137
|
+
| `message` | Integer message to sign, 1≤`message`<`q` [type: str] |
|
|
1138
|
+
|
|
1139
|
+
**Example:**
|
|
1140
|
+
|
|
1141
|
+
```bash
|
|
1142
|
+
$ poetry run transcrypto -p dsa-key.priv dsa sign 999
|
|
1143
|
+
2395961484:3435572290
|
|
1144
|
+
```
|
|
1145
|
+
|
|
1146
|
+
#### `dsa verify`
|
|
1147
|
+
|
|
1148
|
+
Verify integer `signature` for integer `message` with public key.
|
|
1149
|
+
|
|
1150
|
+
```bash
|
|
1151
|
+
poetry run transcrypto dsa verify [-h] message signature
|
|
1152
|
+
```
|
|
1153
|
+
|
|
1154
|
+
| Option/Arg | Description |
|
|
1155
|
+
|---|---|
|
|
1156
|
+
| `message` | Integer message that was signed earlier, 1≤`message`<`q` [type: str] |
|
|
1157
|
+
| `signature` | Integer putative signature for `message`; expects `s1:s2` format with 2 integers, 2≤`s1`,`s2`<`q` [type: str] |
|
|
1158
|
+
|
|
1159
|
+
**Example:**
|
|
1160
|
+
|
|
1161
|
+
```bash
|
|
1162
|
+
$ poetry run transcrypto -p dsa-key.pub dsa verify 999 2395961484:3435572290
|
|
1163
|
+
DSA signature: OK
|
|
1164
|
+
$ poetry run transcrypto -p dsa-key.pub dsa verify 999 2395961484:3435572291
|
|
1165
|
+
DSA signature: INVALID
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
---
|
|
1169
|
+
|
|
1170
|
+
### `bid`
|
|
1171
|
+
|
|
1172
|
+
Bidding on a `secret` so that you can cryptographically convince a neutral party that the `secret` that was committed to previously was not changed. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
1173
|
+
|
|
1174
|
+
```bash
|
|
1175
|
+
poetry run transcrypto bid [-h] {new,verify} ...
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
#### `bid new`
|
|
1179
|
+
|
|
1180
|
+
Generate the bid files for `secret`. Requires `-p`/`--key-path` to set the basename for output files.
|
|
1181
|
+
|
|
1182
|
+
```bash
|
|
1183
|
+
poetry run transcrypto bid new [-h] secret
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
| Option/Arg | Description |
|
|
1187
|
+
|---|---|
|
|
1188
|
+
| `secret` | Input data to bid to, the protected "secret" [type: str] |
|
|
1189
|
+
|
|
1190
|
+
**Example:**
|
|
1191
|
+
|
|
1192
|
+
```bash
|
|
1193
|
+
$ poetry run transcrypto --bin -p my-bid bid new "tomorrow it will rain"
|
|
1194
|
+
Bid private/public commitments saved to 'my-bid.priv/.pub'
|
|
1195
|
+
```
|
|
1196
|
+
|
|
1197
|
+
#### `bid verify`
|
|
1198
|
+
|
|
1199
|
+
Verify the bid files for correctness and reveal the `secret`. Requires `-p`/`--key-path` to set the basename for output files.
|
|
1200
|
+
|
|
1201
|
+
```bash
|
|
1202
|
+
poetry run transcrypto bid verify [-h]
|
|
1203
|
+
```
|
|
1204
|
+
|
|
1205
|
+
**Example:**
|
|
1206
|
+
|
|
1207
|
+
```bash
|
|
1208
|
+
$ poetry run transcrypto --out-bin -p my-bid bid verify
|
|
1209
|
+
Bid commitment: OK
|
|
1210
|
+
Bid secret:
|
|
1211
|
+
tomorrow it will rain
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
---
|
|
1215
|
+
|
|
1216
|
+
### `sss`
|
|
1217
|
+
|
|
1218
|
+
Raw SSS (Shamir Shared Secret) secret sharing crypto scheme over *integers* (BEWARE: no modern message wrapping, padding or validation). These are pedagogical/raw primitives; do not use for new protocols. No measures are taken here to prevent timing attacks. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
1219
|
+
|
|
1220
|
+
```bash
|
|
1221
|
+
poetry run transcrypto sss [-h] {new,shares,recover,verify} ...
|
|
1222
|
+
```
|
|
1223
|
+
|
|
1224
|
+
#### `sss new`
|
|
1225
|
+
|
|
1226
|
+
Generate the private keys with `bits` prime modulus size and so that at least a `minimum` number of shares are needed to recover the secret. This key will be used to generate the shares later (with the `shares` command). Requires `-p`/`--key-path` to set the basename for output files.
|
|
1227
|
+
|
|
1228
|
+
```bash
|
|
1229
|
+
poetry run transcrypto sss new [-h] [--bits BITS] minimum
|
|
1230
|
+
```
|
|
1231
|
+
|
|
1232
|
+
| Option/Arg | Description |
|
|
1233
|
+
|---|---|
|
|
1234
|
+
| `minimum` | Minimum number of shares required to recover secret, ≥ 2 [type: int] |
|
|
1235
|
+
| `--bits` | Prime modulus (`p`) size in bits; the default is a safe size ***IFF*** you are protecting symmetric keys; the number of bits should be comfortably larger than the size of the secret you want to protect with this scheme [type: int (default: 1024)] |
|
|
1236
|
+
|
|
1237
|
+
**Example:**
|
|
1238
|
+
|
|
1239
|
+
```bash
|
|
1240
|
+
$ poetry run transcrypto -p sss-key sss new 3 --bits 64 # NEVER use such a small key: example only!
|
|
1241
|
+
SSS private/public keys saved to 'sss-key.priv/.pub'
|
|
1242
|
+
```
|
|
1243
|
+
|
|
1244
|
+
#### `sss shares`
|
|
1245
|
+
|
|
1246
|
+
Issue `count` private shares for an integer `secret`.
|
|
1247
|
+
|
|
1248
|
+
```bash
|
|
1249
|
+
poetry run transcrypto sss shares [-h] secret count
|
|
1250
|
+
```
|
|
1251
|
+
|
|
1252
|
+
| Option/Arg | Description |
|
|
1253
|
+
|---|---|
|
|
1254
|
+
| `secret` | Integer secret to be protected, 1≤`secret`<*modulus* [type: str] |
|
|
1255
|
+
| `count` | How many shares to produce; must be ≥ `minimum` used in `new` command or else the `secret` would become unrecoverable [type: int] |
|
|
1256
|
+
|
|
1257
|
+
**Example:**
|
|
1258
|
+
|
|
1259
|
+
```bash
|
|
1260
|
+
$ poetry run transcrypto -p sss-key sss shares 999 5
|
|
1261
|
+
SSS 5 individual (private) shares saved to 'sss-key.share.1…5'
|
|
1262
|
+
$ rm sss-key.share.2 sss-key.share.4 # this is to simulate only having shares 1,3,5
|
|
1263
|
+
```
|
|
1264
|
+
|
|
1265
|
+
#### `sss recover`
|
|
1266
|
+
|
|
1267
|
+
Recover secret from shares; will use any available shares that were found.
|
|
1268
|
+
|
|
1269
|
+
```bash
|
|
1270
|
+
poetry run transcrypto sss recover [-h]
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
**Example:**
|
|
1274
|
+
|
|
1275
|
+
```bash
|
|
1276
|
+
$ poetry run transcrypto -p sss-key sss recover
|
|
1277
|
+
Loaded SSS share: 'sss-key.share.3'
|
|
1278
|
+
Loaded SSS share: 'sss-key.share.5'
|
|
1279
|
+
Loaded SSS share: 'sss-key.share.1' # using only 3 shares: number 2/4 are missing
|
|
1280
|
+
Secret:
|
|
1281
|
+
999
|
|
1282
|
+
```
|
|
1283
|
+
|
|
1284
|
+
#### `sss verify`
|
|
1285
|
+
|
|
1286
|
+
Verify shares against a secret (private params).
|
|
1287
|
+
|
|
1288
|
+
```bash
|
|
1289
|
+
poetry run transcrypto sss verify [-h] secret
|
|
1290
|
+
```
|
|
1291
|
+
|
|
1292
|
+
| Option/Arg | Description |
|
|
1293
|
+
|---|---|
|
|
1294
|
+
| `secret` | Integer secret used to generate the shares, 1≤`secret`<*modulus* [type: str] |
|
|
1295
|
+
|
|
1296
|
+
**Example:**
|
|
1297
|
+
|
|
1298
|
+
```bash
|
|
1299
|
+
$ poetry run transcrypto -p sss-key sss verify 999
|
|
1300
|
+
SSS share 'sss-key.share.3' verification: OK
|
|
1301
|
+
SSS share 'sss-key.share.5' verification: OK
|
|
1302
|
+
SSS share 'sss-key.share.1' verification: OK
|
|
1303
|
+
$ poetry run transcrypto -p sss-key sss verify 998
|
|
1304
|
+
SSS share 'sss-key.share.3' verification: INVALID
|
|
1305
|
+
SSS share 'sss-key.share.5' verification: INVALID
|
|
1306
|
+
SSS share 'sss-key.share.1' verification: INVALID
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
---
|
|
1310
|
+
|
|
1311
|
+
### `doc`
|
|
1312
|
+
|
|
1313
|
+
Documentation utilities. (Not for regular use: these are developer utils.)
|
|
1314
|
+
|
|
1315
|
+
```bash
|
|
1316
|
+
poetry run transcrypto doc [-h] {md} ...
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
#### `doc md`
|
|
1320
|
+
|
|
1321
|
+
Emit Markdown docs for the CLI (see README.md section "Creating a New Version").
|
|
1322
|
+
|
|
1323
|
+
```bash
|
|
1324
|
+
poetry run transcrypto doc md [-h]
|
|
1325
|
+
```
|
|
1326
|
+
|
|
1327
|
+
**Example:**
|
|
1328
|
+
|
|
1329
|
+
```bash
|
|
1330
|
+
$ poetry run transcrypto doc md > CLI.md
|
|
1331
|
+
$ ./tools/inject_md_includes.py
|
|
1332
|
+
inject: README.md updated with included content
|
|
1333
|
+
```
|
|
1334
|
+
<!-- INCLUDE:CLI.md END -->
|
|
1335
|
+
<!-- (auto-generated; do not edit between START/END) -->
|
|
1336
|
+
|
|
1337
|
+
<!-- cspell:enable -->
|
|
1338
|
+
|
|
1339
|
+
### Base Library
|
|
1340
|
+
|
|
1341
|
+
#### Humanized Sizes (IEC binary)
|
|
1342
|
+
|
|
1343
|
+
```py
|
|
1344
|
+
from transcrypto import utils
|
|
1345
|
+
|
|
1346
|
+
utils.HumanizedBytes(512) # '512 B'
|
|
1347
|
+
utils.HumanizedBytes(2048) # '2.00 KiB'
|
|
1348
|
+
utils.HumanizedBytes(5 * 1024**3) # '5.00 GiB'
|
|
1349
|
+
```
|
|
1350
|
+
|
|
1351
|
+
Converts raw byte counts to binary-prefixed strings (`B`, `KiB`, `MiB`, `GiB`, `TiB`, `PiB`, `EiB`). Values under 1024 bytes are returned as integers with `B`; larger values use two decimals.
|
|
1352
|
+
|
|
1353
|
+
- standard: 1 KiB = 1024 B, 1 MiB = 1024 KiB, …
|
|
1354
|
+
- errors: negative inputs raise `InputError`
|
|
1355
|
+
|
|
1356
|
+
#### Humanized Decimal Quantities (SI)
|
|
1357
|
+
|
|
1358
|
+
```py
|
|
1359
|
+
# Base (unitless)
|
|
1360
|
+
utils.HumanizedDecimal(950) # '950'
|
|
1361
|
+
utils.HumanizedDecimal(1500) # '1.50 k'
|
|
1362
|
+
|
|
1363
|
+
# With a unit (trimmed and attached)
|
|
1364
|
+
utils.HumanizedDecimal(1500, ' Hz ') # '1.50 kHz'
|
|
1365
|
+
utils.HumanizedDecimal(0.123456, 'V') # '0.1235 V'
|
|
1366
|
+
|
|
1367
|
+
# Large magnitudes
|
|
1368
|
+
utils.HumanizedDecimal(3_200_000) # '3.20 M'
|
|
1369
|
+
utils.HumanizedDecimal(7.2e12, 'B/s') # '7.20 TB/s'
|
|
1370
|
+
```
|
|
1371
|
+
|
|
1372
|
+
Scales by powers of 1000 using SI prefixes (`k`, `M`, `G`, `T`, `P`, `E`). For values `<1000`, integers are shown as-is; small floats show four decimals. For scaled values, two decimals are used and the unit (if provided) is attached without a space (e.g., `kHz`).
|
|
1373
|
+
|
|
1374
|
+
- unit handling: `unit` is stripped; `<1000` values include a space before the unit (`'950 Hz'`)
|
|
1375
|
+
- errors: negative or non-finite inputs raise `InputError`
|
|
1376
|
+
|
|
1377
|
+
#### Humanized Durations
|
|
1378
|
+
|
|
1379
|
+
```py
|
|
1380
|
+
utils.HumanizedSeconds(0) # '0.00 s'
|
|
1381
|
+
utils.HumanizedSeconds(0.000004) # '4.000 µs'
|
|
1382
|
+
utils.HumanizedSeconds(0.25) # '250.000 ms'
|
|
1383
|
+
utils.HumanizedSeconds(42) # '42.00 s'
|
|
1384
|
+
utils.HumanizedSeconds(3661) # '1.02 h'
|
|
1385
|
+
utils.HumanizedSeconds(172800) # '2.00 d'
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
Chooses an appropriate time unit based on magnitude and formats with fixed precision:
|
|
1389
|
+
|
|
1390
|
+
- `< 1 ms`: microseconds with three decimals (`µs`)
|
|
1391
|
+
- `< 1 s`: milliseconds with three decimals (`ms`)
|
|
1392
|
+
- `< 60 s`: seconds with two decimals (`s`)
|
|
1393
|
+
- `< 60 min`: minutes with two decimals (`min`)
|
|
1394
|
+
- `< 24 h`: hours with two decimals (`h`)
|
|
1395
|
+
- `≥ 24 h`: days with two decimals (`d`)
|
|
1396
|
+
- special case: `0 → '0.00 s'`
|
|
1397
|
+
- errors: negative or non-finite inputs raise `InputError`
|
|
1398
|
+
|
|
1399
|
+
#### Cryptographically Secure Randomness
|
|
1400
|
+
|
|
1401
|
+
These helpers live in `base` and wrap Python’s `secrets` with additional checks and guarantees for crypto use-cases.
|
|
1402
|
+
|
|
1403
|
+
```py
|
|
1404
|
+
from transcrypto import base
|
|
1405
|
+
```
|
|
1406
|
+
|
|
1407
|
+
##### Fixed-size random integers
|
|
1408
|
+
|
|
1409
|
+
```py
|
|
1410
|
+
# Generate a 256-bit integer (first bit always set)
|
|
1411
|
+
r = base.RandBits(256)
|
|
1412
|
+
assert r.bit_length() == 256
|
|
1413
|
+
```
|
|
1414
|
+
|
|
1415
|
+
Produces a crypto-secure random integer with exactly `n_bits` bits (`≥ 8`). The most significant bit is guaranteed to be `1`, so entropy is \~`n_bits−1` — negligible for large crypto sizes.
|
|
1416
|
+
|
|
1417
|
+
- errors: `n_bits < 8` → `InputError`
|
|
1418
|
+
|
|
1419
|
+
##### Uniform random integers in a range
|
|
1420
|
+
|
|
1421
|
+
```py
|
|
1422
|
+
# Uniform between [10, 20] inclusive
|
|
1423
|
+
n = base.RandInt(10, 20)
|
|
1424
|
+
assert 10 <= n <= 20
|
|
1425
|
+
```
|
|
1426
|
+
|
|
1427
|
+
Returns a crypto-secure integer uniformly distributed over the closed interval `[min_int, max_int]`.
|
|
1428
|
+
|
|
1429
|
+
- constraints: `min_int ≥ 0` and `< max_int`
|
|
1430
|
+
- errors: invalid bounds → `InputError`
|
|
1431
|
+
|
|
1432
|
+
##### In-place secure shuffle
|
|
1433
|
+
|
|
1434
|
+
```py
|
|
1435
|
+
deck = list(range(10))
|
|
1436
|
+
base.RandShuffle(deck)
|
|
1437
|
+
print(deck) # securely shuffled order
|
|
1438
|
+
```
|
|
1439
|
+
|
|
1440
|
+
Performs an in-place Fisher–Yates shuffle using `secrets.randbelow`. Suitable for sensitive data ordering.
|
|
1441
|
+
|
|
1442
|
+
- constraints: sequence length ≥ 2
|
|
1443
|
+
- errors: shorter sequences → `InputError`
|
|
1444
|
+
|
|
1445
|
+
##### Random byte strings
|
|
1446
|
+
|
|
1447
|
+
```py
|
|
1448
|
+
# 32 random bytes
|
|
1449
|
+
b = base.RandBytes(32)
|
|
1450
|
+
assert len(b) == 32
|
|
1451
|
+
```
|
|
1452
|
+
|
|
1453
|
+
Generates `n_bytes` of high-quality crypto-secure random data.
|
|
1454
|
+
|
|
1455
|
+
- constraints: `n_bytes ≥ 1`
|
|
1456
|
+
- errors: smaller values → `InputError`
|
|
1457
|
+
|
|
1458
|
+
#### Computing the Greatest Common Divisor
|
|
1459
|
+
|
|
1460
|
+
```py
|
|
1461
|
+
>>> from transcrypto import base
|
|
1462
|
+
>>> base.GCD(462, 1071)
|
|
1463
|
+
21
|
|
1464
|
+
>>> base.GCD(0, 17)
|
|
1465
|
+
17
|
|
1466
|
+
```
|
|
1467
|
+
|
|
1468
|
+
The function is `O(log(min(a, b)))` and handles arbitrarily large integers. To find Bézout coefficients `(x, y)` such that `ax + by = gcd(a, b)` do:
|
|
1469
|
+
|
|
1470
|
+
```py
|
|
1471
|
+
>>> base.ExtendedGCD(462, 1071)
|
|
1472
|
+
(21, -2, 1)
|
|
1473
|
+
>>> 462 * -2 + 1071 * 1
|
|
1474
|
+
21
|
|
1475
|
+
```
|
|
1476
|
+
|
|
1477
|
+
Use-cases:
|
|
1478
|
+
|
|
1479
|
+
- modular inverses: `inv = x % m` when `gcd(a, m) == 1`
|
|
1480
|
+
- solving linear Diophantine equations
|
|
1481
|
+
- RSA / ECC key generation internals
|
|
1482
|
+
|
|
1483
|
+
#### Cryptographic Hashing
|
|
1484
|
+
|
|
1485
|
+
Simple, fixed-output-size wrappers over Python’s `hashlib` for common digest operations, plus file hashing.
|
|
1486
|
+
|
|
1487
|
+
```py
|
|
1488
|
+
from transcrypto import base
|
|
1489
|
+
```
|
|
1490
|
+
|
|
1491
|
+
##### SHA-256 hashing
|
|
1492
|
+
|
|
1493
|
+
```py
|
|
1494
|
+
h = base.Hash256(b'hello world')
|
|
1495
|
+
assert len(h) == 32 # bytes
|
|
1496
|
+
print(h.hex()) # 64 hex chars
|
|
1497
|
+
```
|
|
1498
|
+
|
|
1499
|
+
Computes the SHA-256 digest of a byte string, returning exactly 32 bytes (256 bits). Suitable for fingerprints, commitments, or internal crypto primitives.
|
|
1500
|
+
|
|
1501
|
+
##### SHA-512 hashing
|
|
1502
|
+
|
|
1503
|
+
```py
|
|
1504
|
+
h = base.Hash512(b'hello world')
|
|
1505
|
+
assert len(h) == 64 # bytes
|
|
1506
|
+
print(h.hex()) # 128 hex chars
|
|
1507
|
+
```
|
|
1508
|
+
|
|
1509
|
+
Computes the SHA-512 digest of a byte string, returning exactly 64 bytes (512 bits). Higher collision resistance and larger output space than SHA-256.
|
|
1510
|
+
|
|
1511
|
+
##### File hashing
|
|
1512
|
+
|
|
1513
|
+
```py
|
|
1514
|
+
# Default SHA-256
|
|
1515
|
+
fh = base.FileHash('/path/to/file')
|
|
1516
|
+
print(fh.hex())
|
|
1517
|
+
|
|
1518
|
+
# SHA-512
|
|
1519
|
+
fh2 = base.FileHash('/path/to/file', digest='sha512')
|
|
1520
|
+
```
|
|
1521
|
+
|
|
1522
|
+
Hashes a file from disk in streaming mode. By default uses SHA-256; `digest='sha512'` switches to SHA-512.
|
|
1523
|
+
|
|
1524
|
+
- constraints:
|
|
1525
|
+
- `digest` must be `'sha256'` or `'sha512'`
|
|
1526
|
+
- `full_path` must exist
|
|
1527
|
+
- errors: invalid digest or missing file → `InputError`
|
|
1528
|
+
|
|
1529
|
+
#### Execution Timing
|
|
1530
|
+
|
|
1531
|
+
A flexible timing utility that works as a **context manager**, **decorator**, or **manual timer object**.
|
|
1532
|
+
|
|
1533
|
+
```py
|
|
1534
|
+
from transcrypto import base
|
|
1535
|
+
import time
|
|
1536
|
+
```
|
|
1537
|
+
|
|
1538
|
+
##### Context manager
|
|
1539
|
+
|
|
1540
|
+
```py
|
|
1541
|
+
with base.Timer('Block timing'):
|
|
1542
|
+
time.sleep(1.2)
|
|
1543
|
+
# → logs: "Block timing: 1.20 s" (default via logging.info)
|
|
1544
|
+
```
|
|
1545
|
+
|
|
1546
|
+
Starts timing on entry, stops on exit, and reports elapsed time automatically.
|
|
1547
|
+
|
|
1548
|
+
##### Decorator
|
|
1549
|
+
|
|
1550
|
+
```py
|
|
1551
|
+
@base.Timer('Function timing')
|
|
1552
|
+
def slow_function():
|
|
1553
|
+
time.sleep(0.8)
|
|
1554
|
+
|
|
1555
|
+
slow_function()
|
|
1556
|
+
# → logs: "Function timing: 0.80 s"
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1559
|
+
Wraps a function so that each call is automatically timed.
|
|
1560
|
+
|
|
1561
|
+
##### Manual use
|
|
1562
|
+
|
|
1563
|
+
```py
|
|
1564
|
+
tm = base.Timer('Inline timing', emit_print=True)
|
|
1565
|
+
tm.Start()
|
|
1566
|
+
time.sleep(0.1)
|
|
1567
|
+
tm.Stop() # prints: "Inline timing: 0.10 s"
|
|
1568
|
+
```
|
|
1569
|
+
|
|
1570
|
+
Manual control over `Start()` and `Stop()` for precise measurement of custom intervals.
|
|
1571
|
+
|
|
1572
|
+
##### Key points
|
|
1573
|
+
|
|
1574
|
+
- **Label**: required, shown in output; empty labels raise `InputError`
|
|
1575
|
+
- **Output**:
|
|
1576
|
+
- `emit_log=True` → `logging.info()` (default)
|
|
1577
|
+
- `emit_print=True` → direct `print()`
|
|
1578
|
+
- Both can be enabled
|
|
1579
|
+
- **Format**: elapsed time is shown using `HumanizedSeconds()`
|
|
1580
|
+
- **Safety**:
|
|
1581
|
+
- Cannot start an already started timer
|
|
1582
|
+
- Cannot stop an unstarted or already stopped timer
|
|
1583
|
+
(raises `Error`)
|
|
1584
|
+
|
|
1585
|
+
#### Symmetric Encryption Interface
|
|
1586
|
+
|
|
1587
|
+
`SymmetricCrypto` is an abstract base class that defines the **byte-in / byte-out** contract for symmetric ciphers.
|
|
1588
|
+
|
|
1589
|
+
- **Metadata handling** — if the algorithm uses a `nonce` or `tag`, the implementation must handle it internally (e.g., append it to ciphertext).
|
|
1590
|
+
- **AEAD modes** — if supported, `associated_data` must be authenticated; otherwise, a non-`None` value should raise `InputError`.
|
|
1591
|
+
|
|
1592
|
+
```py
|
|
1593
|
+
class MyAES(base.SymmetricCrypto):
|
|
1594
|
+
def Encrypt(self, plaintext: bytes, *, associated_data=None) -> bytes:
|
|
1595
|
+
...
|
|
1596
|
+
def Decrypt(self, ciphertext: bytes, *, associated_data=None) -> bytes:
|
|
1597
|
+
...
|
|
1598
|
+
```
|
|
1599
|
+
|
|
1600
|
+
#### Serialization Pipeline
|
|
1601
|
+
|
|
1602
|
+
These helpers turn arbitrary Python objects into compressed and/or encrypted binary blobs, and back again — with detailed timing and size logging.
|
|
1603
|
+
|
|
1604
|
+
```py
|
|
1605
|
+
from transcrypto import base
|
|
1606
|
+
```
|
|
1607
|
+
|
|
1608
|
+
##### Serialize
|
|
1609
|
+
|
|
1610
|
+
```py
|
|
1611
|
+
data = {'x': 42, 'y': 'hello'}
|
|
1612
|
+
|
|
1613
|
+
# Basic serialization
|
|
1614
|
+
blob = base.Serialize(data)
|
|
1615
|
+
|
|
1616
|
+
# With compression and encryption
|
|
1617
|
+
blob = base.Serialize(
|
|
1618
|
+
data,
|
|
1619
|
+
compress=9, # compression level (-22..22, default=3)
|
|
1620
|
+
key=my_symmetric_key # must implement SymmetricCrypto
|
|
1621
|
+
)
|
|
1622
|
+
|
|
1623
|
+
# Save directly to file
|
|
1624
|
+
base.Serialize(data, file_path='/tmp/data.blob')
|
|
1625
|
+
```
|
|
1626
|
+
|
|
1627
|
+
Serialization path:
|
|
1628
|
+
|
|
1629
|
+
```text
|
|
1630
|
+
obj → pickle → (compress) → (encrypt) → (save)
|
|
1631
|
+
```
|
|
1632
|
+
|
|
1633
|
+
At each stage:
|
|
1634
|
+
|
|
1635
|
+
- Data size is measured using `HumanizedBytes`
|
|
1636
|
+
- Duration is timed with `Timer`
|
|
1637
|
+
- Results are logged once at the end
|
|
1638
|
+
|
|
1639
|
+
Compression levels:
|
|
1640
|
+
|
|
1641
|
+
`compress` uses `zstandard`; see table below for speed/ratio trade-offs:
|
|
1642
|
+
|
|
1643
|
+
| Level | Speed | Compression ratio | Typical use case |
|
|
1644
|
+
| -------- | ------------| --------------------------------- | --------------------------------------- |
|
|
1645
|
+
| -5 to -1 | Fastest | Poor (better than no compression) | Real-time or very latency-sensitive |
|
|
1646
|
+
| 0…3 | Very fast | Good ratio | Default CLI choice, safe baseline |
|
|
1647
|
+
| 4…6 | Moderate | Better ratio | Good compromise for general persistence |
|
|
1648
|
+
| 7…10 | Slower | Marginally better ratio | Only if storage space is precious |
|
|
1649
|
+
| 11…15 | Much slower | Slight gains | Large archives, not for runtime use |
|
|
1650
|
+
| 16…22 | Very slow | Tiny gains | Archival-only, multi-GB datasets |
|
|
1651
|
+
|
|
1652
|
+
Errors: invalid compression level is clamped to range; other input errors raise `InputError`.
|
|
1653
|
+
|
|
1654
|
+
##### DeSerialize
|
|
1655
|
+
|
|
1656
|
+
```py
|
|
1657
|
+
# From in-memory blob
|
|
1658
|
+
obj = base.DeSerialize(data=blob)
|
|
1659
|
+
|
|
1660
|
+
# From file
|
|
1661
|
+
obj = base.DeSerialize(file_path='/tmp/data.blob')
|
|
1662
|
+
|
|
1663
|
+
# With decryption
|
|
1664
|
+
obj = base.DeSerialize(data=blob, key=my_symmetric_key)
|
|
1665
|
+
```
|
|
1666
|
+
|
|
1667
|
+
Deserialization path:
|
|
1668
|
+
|
|
1669
|
+
```text
|
|
1670
|
+
data/file → (decrypt) → (decompress if Zstd) → unpickle
|
|
1671
|
+
```
|
|
1672
|
+
|
|
1673
|
+
- Compression is auto-detected via Zstandard magic numbers.
|
|
1674
|
+
- All steps are timed/logged like in `Serialize`.
|
|
1675
|
+
|
|
1676
|
+
**Constraints & errors**:
|
|
1677
|
+
|
|
1678
|
+
- Exactly one of `data` or `file_path` must be provided.
|
|
1679
|
+
- `file_path` must exist; `data` must be at least 4 bytes.
|
|
1680
|
+
- Wrong key or corrupted data can raise `CryptoError`.
|
|
1681
|
+
|
|
1682
|
+
#### Crypto Objects General Properties (`CryptoKey`)
|
|
1683
|
+
|
|
1684
|
+
Cryptographic objects all derive from the `CryptoKey` class and will all have some important characteristics:
|
|
1685
|
+
|
|
1686
|
+
- Will be safe to log and print, i.e., implement safe `__str__()` and `__repr__()` methods (in actuality `repr` will be exactly the same as `str`). The `__str__()` should always fully print the public parts of the object and obfuscate the private ones. This obfuscation allows for some debugging, if needed, but if the secrets are "too short" then it can be defeated by brute force. For usual crypto defaults the obfuscation is fine. The obfuscation is the fist 4 bytes of the SHA-512 for the value followed by an ellipsis (e.g. `c9626f16…`).
|
|
1687
|
+
- It will have a `_DebugDump()` method that **does print secrets** and can be used for **debugging only**.
|
|
1688
|
+
- Can be easily serialized to `bytes` by the `blob` property and to base-64 encoded `str` by the `encoded` property.
|
|
1689
|
+
- Can be serialized encrypted to `bytes` by the `Blob(key=[SymmetricCrypto])` method and to encrypted base-64 encoded `str` by the `Encoded(key=[SymmetricCrypto])` method.
|
|
1690
|
+
- Can be instantiated back as an object from `str` or `bytes` using the `Load(data, key=[SymmetricCrypto] | None)` method. The `Load()` will decide how to build the object and will work universally with all the serialization options discussed above.
|
|
1691
|
+
|
|
1692
|
+
Example:
|
|
1693
|
+
|
|
1694
|
+
<!-- cspell:disable -->
|
|
1695
|
+
```py
|
|
1696
|
+
from transcrypto import base, rsa, aes
|
|
1697
|
+
|
|
1698
|
+
priv = rsa.RSAPrivateKey.New(512) # small key, but good for this example
|
|
1699
|
+
print(str(priv)) # safe, no secrets
|
|
1700
|
+
# ▶ RSAPrivateKey(RSAPublicKey(public_modulus=pQaoxy-QeXSds1k9WsGjJw==, encrypt_exp=AQAB), modulus_p=f18141aa…, modulus_q=67494eb9…, decrypt_exp=c96db24a…)
|
|
1701
|
+
|
|
1702
|
+
print(priv._DebugDump()) # UNSAFE: prints secrets
|
|
1703
|
+
# ▶ RSAPrivateKey(public_modulus=219357196311600536151291741191131996967, encrypt_exp=65537, modulus_p=13221374197986739361, modulus_q=16591104148992527047, decrypt_exp=37805202135275158391322585315542443073, remainder_p=9522084656682089473, remainder_q=8975656462800098363, q_inverse_p=11965562396596149292)
|
|
1704
|
+
|
|
1705
|
+
print(priv.blob)
|
|
1706
|
+
# ▶ b"(\xb5/\xfd \x98\xc1\x04\x00\x80\x04\x95\x8d\x00\x00\x00\x00\x00\x00\x00\x8c\x0ftranscrypto.rsa\x94\x8c\rRSAPrivateKey\x94\x93\x94)\x81\x94]\x94(\x8a\x11'\xa3\xc1Z=Y\xb3\x9dty\x90/\xc7\xa8\x06\xa5\x00J\x01\x00\x01\x00\x8a\t\xa1\xc4\x83\x81\xc8\xc1{\xb7\x00\x8a\t\xc7\x8a5\xf0Qq?\xe6\x00\x8a\x10A$&\x82!\x1cy\x89r\xef\xeb\xa7_\x04q\x1c\x8a\t\x01\xbc\xbb\x8a\x8b=%\x84\x00\x8a\x08;\x94#s\xff\xef\x8f|\x8a\t,\x9c\xe2z\x9a7\x0e\xa6\x00eb."
|
|
1707
|
+
|
|
1708
|
+
print(priv.encoded)
|
|
1709
|
+
# ▶ KLUv_WBwAIELAIAElWUBAAAAAAAAjA90cmFuc2NyeXB0by5yc2GUjA1SU0FQcml2YXRlS2V5lJOUKYGUXZQoikHf1EvsmZedAZve7TrLmobLAwuRIr_77TLG6G_0fsLGThERVJu075be8PLjUQYnLXcacZFQ5Fb1Iy1WtiE985euAEoBAAEAiiFR9ngiXMzkf41o5CRBY3h0D4DJVisDDhLmAWsiaHggzQCKIS_cmQ6MKXCtROtC7c_Mrsi9A-9NM8DksaHaRwvy6uTZAIpB4TVbsLxc41TEc19wIzpxbi9y5dW5gdfTkRQSSiz0ijmb8Xk3pyBfKAv8JbHp8Yv48gNZUfX67qq0J7yhJqeUoACKIbFb2kTNRzSqm3JRtjc2BPS-FnLFdadlFcV4-6IW7eqLAIogFZfzDN39gZLR9uTz4KHSTaqxWrJgP8-YYssjss6FlFKKIIItgCDv7ompNpY8gBs5bibN8XTsr-JOYSntDVT5Fe5vZWIu
|
|
1710
|
+
|
|
1711
|
+
key = aes.AESKey(key256=b'x' * 32)
|
|
1712
|
+
print(key)
|
|
1713
|
+
# ▶ AESKey(key256=86a86df7…)
|
|
1714
|
+
|
|
1715
|
+
encrypted = priv.Blob(key=key)
|
|
1716
|
+
print(priv == rsa.RSAPrivateKey.Load(encrypted, key=key))
|
|
1717
|
+
# ▶ True
|
|
1718
|
+
```
|
|
1719
|
+
<!-- cspell:enable -->
|
|
1720
|
+
|
|
1721
|
+
#### AES-256 Symmetric Encryption
|
|
1722
|
+
|
|
1723
|
+
Implements AES-256 in **GCM mode** for authenticated encryption and decryption, plus an **ECB mode** helper for fixed-size block encoding.
|
|
1724
|
+
Also includes a high-iteration PBKDF2-based key derivation from static passwords.
|
|
1725
|
+
|
|
1726
|
+
##### Key creation
|
|
1727
|
+
|
|
1728
|
+
```py
|
|
1729
|
+
from transcrypto import aes
|
|
1730
|
+
|
|
1731
|
+
# From raw bytes (must be exactly 32 bytes)
|
|
1732
|
+
key = aes.AESKey(key256=b'\x00' * 32)
|
|
1733
|
+
|
|
1734
|
+
# From a static password (slow, high-iteration PBKDF2-SHA256)
|
|
1735
|
+
key = aes.AESKey.FromStaticPassword('correct horse battery staple')
|
|
1736
|
+
print(key.encoded) # URL-safe Base64
|
|
1737
|
+
```
|
|
1738
|
+
|
|
1739
|
+
- **Length**: `key256` must be exactly 32 bytes
|
|
1740
|
+
- `FromStaticPassword()`:
|
|
1741
|
+
- Uses PBKDF2-HMAC-SHA256 with **fixed** salt and \~2 million iterations
|
|
1742
|
+
- Designed for **interactive** password entry, **not** for password databases
|
|
1743
|
+
|
|
1744
|
+
##### AES-256 + GCM (default)
|
|
1745
|
+
|
|
1746
|
+
```py
|
|
1747
|
+
data = b'secret message'
|
|
1748
|
+
aad = b'metadata'
|
|
1749
|
+
|
|
1750
|
+
# Encrypt (returns IV + ciphertext + tag)
|
|
1751
|
+
ct = key.Encrypt(data, associated_data=aad)
|
|
1752
|
+
|
|
1753
|
+
# Decrypt
|
|
1754
|
+
pt = key.Decrypt(ct, associated_data=aad)
|
|
1755
|
+
assert pt == data
|
|
1756
|
+
```
|
|
1757
|
+
|
|
1758
|
+
- **Security**:
|
|
1759
|
+
- Random 128-bit IV (`iv`) per encryption
|
|
1760
|
+
- Authenticated tag (128-bit) ensures integrity
|
|
1761
|
+
- Optional `associated_data` is authenticated but not encrypted
|
|
1762
|
+
- **Errors**:
|
|
1763
|
+
- Tag mismatch or wrong key → `CryptoError`
|
|
1764
|
+
|
|
1765
|
+
##### AES-256 + ECB (unsafe, fixed block only)
|
|
1766
|
+
|
|
1767
|
+
```py
|
|
1768
|
+
# ECB mode is for 16-byte block encoding ONLY
|
|
1769
|
+
ecb = key.ECBEncoder()
|
|
1770
|
+
|
|
1771
|
+
block = b'16-byte string!!'
|
|
1772
|
+
ct_block = ecb.Encrypt(block)
|
|
1773
|
+
pt_block = ecb.Decrypt(ct_block)
|
|
1774
|
+
assert pt_block == block
|
|
1775
|
+
|
|
1776
|
+
# Hex helpers
|
|
1777
|
+
hex_ct = ecb.EncryptHex('00112233445566778899aabbccddeeff')
|
|
1778
|
+
```
|
|
1779
|
+
|
|
1780
|
+
- **ECB mode**:
|
|
1781
|
+
- 16-byte plaintext ↔ 16-byte ciphertext
|
|
1782
|
+
- No padding, no IV, no integrity — **do not use for general encryption**
|
|
1783
|
+
- `associated_data` not supported
|
|
1784
|
+
|
|
1785
|
+
Key points:
|
|
1786
|
+
|
|
1787
|
+
- **GCM mode** is secure for general use; ECB mode is for special low-level operations
|
|
1788
|
+
- **Static password derivation** is intentionally slow to resist brute force
|
|
1789
|
+
- All sizes and parameters are validated with `InputError` on misuse
|
|
1790
|
+
|
|
1791
|
+
#### Fast Modular Arithmetic
|
|
1792
|
+
|
|
1793
|
+
```py
|
|
1794
|
+
from transcrypto import modmath
|
|
1795
|
+
|
|
1796
|
+
m = 2**256 - 189 # a large prime modulus
|
|
1797
|
+
|
|
1798
|
+
# Inverse ──────────────────────────────
|
|
1799
|
+
x = 123456789
|
|
1800
|
+
x_inv = modmath.ModInv(x, m)
|
|
1801
|
+
assert (x * x_inv) % m == 1
|
|
1802
|
+
|
|
1803
|
+
# Division (x / y) mod m ──────────────
|
|
1804
|
+
y = 987654321
|
|
1805
|
+
z = modmath.ModDiv(x, y, m) # solves z·y ≡ x (mod m)
|
|
1806
|
+
assert (z * y) % m == x % m
|
|
1807
|
+
|
|
1808
|
+
# Exponentiation ──────────────────────
|
|
1809
|
+
exp = modmath.ModExp(3, 10**20, m) # ≈ log₂(y) time, handles huge exponents
|
|
1810
|
+
```
|
|
1811
|
+
|
|
1812
|
+
#### Chinese Remainder Theorem (CRT) – Pair
|
|
1813
|
+
|
|
1814
|
+
```py
|
|
1815
|
+
from transcrypto import modmath
|
|
1816
|
+
|
|
1817
|
+
# Solve:
|
|
1818
|
+
# x ≡ 2 (mod 3)
|
|
1819
|
+
# x ≡ 3 (mod 5)
|
|
1820
|
+
x = modmath.CRTPair(2, 3, 3, 5)
|
|
1821
|
+
print(x) # 8
|
|
1822
|
+
assert x % 3 == 2
|
|
1823
|
+
assert x % 5 == 3
|
|
1824
|
+
```
|
|
1825
|
+
|
|
1826
|
+
Solves a system of two simultaneous congruences with **pairwise co-prime** moduli, returning the **least non-negative solution** `x` such that:
|
|
1827
|
+
|
|
1828
|
+
```text
|
|
1829
|
+
x ≡ a1 (mod m1)
|
|
1830
|
+
x ≡ a2 (mod m2)
|
|
1831
|
+
0 ≤ x < m1 * m2
|
|
1832
|
+
```
|
|
1833
|
+
|
|
1834
|
+
- **Requirements**:
|
|
1835
|
+
- `m1 ≥ 2`, `m2 ≥ 2`, `m1 != m2`
|
|
1836
|
+
- `gcd(m1, m2) == 1` (co-prime)
|
|
1837
|
+
- **Errors**:
|
|
1838
|
+
- invalid modulus values → `InputError`
|
|
1839
|
+
- non co-prime moduli → `ModularDivideError`
|
|
1840
|
+
|
|
1841
|
+
This function is a 2-modulus variant; for multiple moduli, apply it iteratively or use a general CRT solver.
|
|
1842
|
+
|
|
1843
|
+
#### Modular Polynomials & Lagrange Interpolation
|
|
1844
|
+
|
|
1845
|
+
```py
|
|
1846
|
+
# f(t) = 7t³ − 3t² + 2t + 5 (coefficients constant-term first)
|
|
1847
|
+
coefficients = [5, 2, -3, 7]
|
|
1848
|
+
print(modmath.ModPolynomial(11, coefficients, 97)) # → 19
|
|
1849
|
+
|
|
1850
|
+
# Given three points build the degree-≤2 polynomial and evaluate it.
|
|
1851
|
+
pts = {2: 4, 5: 3, 7: 1}
|
|
1852
|
+
print(modmath.ModLagrangeInterpolate(9, pts, 11)) # → 2
|
|
1853
|
+
```
|
|
1854
|
+
|
|
1855
|
+
#### Primality testing & Prime generators, Mersenne primes
|
|
1856
|
+
|
|
1857
|
+
```py
|
|
1858
|
+
modmath.IsPrime(2**127 - 1) # True (Mersenne prime)
|
|
1859
|
+
modmath.IsPrime(3825123056546413051) # False (strong pseudo-prime)
|
|
1860
|
+
|
|
1861
|
+
# Direct Miller–Rabin with custom witnesses
|
|
1862
|
+
modmath.MillerRabinIsPrime(961748941, witnesses={2,7,61})
|
|
1863
|
+
|
|
1864
|
+
# Infinite iterator of primes ≥ 10⁶
|
|
1865
|
+
for p in modmath.PrimeGenerator(1_000_000):
|
|
1866
|
+
print(p)
|
|
1867
|
+
if p > 1_000_100:
|
|
1868
|
+
break
|
|
1869
|
+
|
|
1870
|
+
# Secure random 384-bit prime (for RSA/ECC experiments)
|
|
1871
|
+
p384 = modmath.NBitRandomPrime(384)
|
|
1872
|
+
|
|
1873
|
+
for k, m_p, perfect in modmath.MersennePrimesGenerator(0):
|
|
1874
|
+
print(f'p = {k:>8} M = {m_p} perfect = {perfect}')
|
|
1875
|
+
if k > 10000: # stop after a few
|
|
1876
|
+
break
|
|
1877
|
+
```
|
|
1878
|
+
|
|
1879
|
+
#### RSA (Rivest-Shamir-Adleman) Public Cryptography
|
|
1880
|
+
|
|
1881
|
+
<https://en.wikipedia.org/wiki/RSA_cryptosystem>
|
|
1882
|
+
|
|
1883
|
+
This implementation is raw RSA, no OAEP or PSS! It works on the actual integers. For real uses you should look for higher-level implementations.
|
|
1884
|
+
|
|
1885
|
+
By default and deliberate choice the *encryption exponent* will be either 7 or 65537, depending on the size of `phi=(p-1)*(q-1)`. If `phi` allows it the larger one will be chosen to avoid Coppersmith attacks.
|
|
1886
|
+
|
|
1887
|
+
```py
|
|
1888
|
+
from transcrypto import rsa
|
|
1889
|
+
|
|
1890
|
+
# Generate a key pair
|
|
1891
|
+
priv = rsa.RSAPrivateKey.New(2048) # 2048-bit modulus
|
|
1892
|
+
pub = rsa.RSAPublicKey.Copy(priv) # public half
|
|
1893
|
+
print(priv.public_modulus.bit_length()) # 2048
|
|
1894
|
+
|
|
1895
|
+
# Encrypt & decrypt
|
|
1896
|
+
msg = 123456789 # (Zero is forbidden by design; smallest valid message is 1.)
|
|
1897
|
+
cipher = pub.Encrypt(msg)
|
|
1898
|
+
plain = priv.Decrypt(cipher)
|
|
1899
|
+
assert plain == msg
|
|
1900
|
+
|
|
1901
|
+
# Sign & verify
|
|
1902
|
+
signature = priv.Sign(msg)
|
|
1903
|
+
assert pub.VerifySignature(msg, signature)
|
|
1904
|
+
|
|
1905
|
+
# Blind signatures (obfuscation pair) - only works on raw RSA
|
|
1906
|
+
pair = rsa.RSAObfuscationPair.New(pub)
|
|
1907
|
+
|
|
1908
|
+
blind_msg = pair.ObfuscateMessage(msg) # what you send to signer
|
|
1909
|
+
blind_sig = priv.Sign(blind_msg) # signer’s output
|
|
1910
|
+
|
|
1911
|
+
sig = pair.RevealOriginalSignature(msg, blind_sig)
|
|
1912
|
+
assert pub.VerifySignature(msg, sig)
|
|
1913
|
+
```
|
|
1914
|
+
|
|
1915
|
+
#### El-Gamal Public-Key Cryptography
|
|
1916
|
+
|
|
1917
|
+
[https://en.wikipedia.org/wiki/ElGamal\_encryption](https://en.wikipedia.org/wiki/ElGamal_encryption)
|
|
1918
|
+
|
|
1919
|
+
This is **raw El-Gamal** over a prime field — no padding, no hashing — and is **not** DSA.
|
|
1920
|
+
For real-world deployments, use a high-level library with authenticated encryption and proper encoding.
|
|
1921
|
+
|
|
1922
|
+
##### Shared Public Key
|
|
1923
|
+
|
|
1924
|
+
```py
|
|
1925
|
+
from transcrypto import elgamal
|
|
1926
|
+
|
|
1927
|
+
# ➊ Shared parameters (prime modulus, group base) for a group
|
|
1928
|
+
shared = elgamal.ElGamalSharedPublicKey.New(256)
|
|
1929
|
+
print(shared.prime_modulus)
|
|
1930
|
+
print(shared.group_base)
|
|
1931
|
+
```
|
|
1932
|
+
|
|
1933
|
+
- `prime_modulus`: large prime `p ≥ 7`
|
|
1934
|
+
- `group_base`: integer `3 ≤ g < p`
|
|
1935
|
+
- Used to derive individual public/private keys.
|
|
1936
|
+
|
|
1937
|
+
##### Public Key
|
|
1938
|
+
|
|
1939
|
+
```py
|
|
1940
|
+
# ➋ Public key from private
|
|
1941
|
+
priv = elgamal.ElGamalPrivateKey.New(shared)
|
|
1942
|
+
pub = elgamal.ElGamalPublicKey.Copy(priv)
|
|
1943
|
+
|
|
1944
|
+
# Encryption
|
|
1945
|
+
msg = 42
|
|
1946
|
+
cipher = pub.Encrypt(msg)
|
|
1947
|
+
plain = priv.Decrypt(cipher)
|
|
1948
|
+
assert plain == msg
|
|
1949
|
+
|
|
1950
|
+
# Signature verify
|
|
1951
|
+
sig = priv.Sign(msg)
|
|
1952
|
+
assert pub.VerifySignature(msg, sig)
|
|
1953
|
+
```
|
|
1954
|
+
|
|
1955
|
+
- `Encrypt(message)` → `(c1, c2)`, both in `[2, p-1]`
|
|
1956
|
+
- `VerifySignature(message, signature)` → `True` or `False`
|
|
1957
|
+
- `Copy()` extracts public portion from a private key
|
|
1958
|
+
|
|
1959
|
+
##### Private Key
|
|
1960
|
+
|
|
1961
|
+
```py
|
|
1962
|
+
# ➌ Private key generation
|
|
1963
|
+
priv = elgamal.ElGamalPrivateKey.New(shared)
|
|
1964
|
+
|
|
1965
|
+
# Decryption
|
|
1966
|
+
plain = priv.Decrypt(cipher)
|
|
1967
|
+
|
|
1968
|
+
# Signing
|
|
1969
|
+
sig = priv.Sign(msg)
|
|
1970
|
+
assert pub.VerifySignature(msg, sig)
|
|
1971
|
+
```
|
|
1972
|
+
|
|
1973
|
+
- `decrypt_exp`: secret exponent `3 ≤ e < p`
|
|
1974
|
+
- `Decrypt((c1, c2))` recovers `m`
|
|
1975
|
+
- `Sign(m)` returns `(s1, s2)`; both satisfy the modulus constraints
|
|
1976
|
+
|
|
1977
|
+
Key points:
|
|
1978
|
+
|
|
1979
|
+
- **Security parameters**:
|
|
1980
|
+
- Recommended `prime_modulus` bit length ≥ 2048 for real security
|
|
1981
|
+
- Random values from `base.RandBits`
|
|
1982
|
+
- **Ephemeral keys**:
|
|
1983
|
+
- Fresh per encryption/signature
|
|
1984
|
+
- Must satisfy `gcd(k, p-1) == 1`
|
|
1985
|
+
- **Errors**:
|
|
1986
|
+
- Bad ranges → `InputError`
|
|
1987
|
+
- Invalid math relationships → `CryptoError`
|
|
1988
|
+
- **Group sharing**:
|
|
1989
|
+
- Multiple parties can share `(p, g)` but have different `(individual_base, decrypt_exp)`
|
|
1990
|
+
|
|
1991
|
+
#### DSA (Digital Signature Algorithm)
|
|
1992
|
+
|
|
1993
|
+
[https://en.wikipedia.org/wiki/Digital\_Signature\_Algorithm](https://en.wikipedia.org/wiki/Digital_Signature_Algorithm)
|
|
1994
|
+
|
|
1995
|
+
This is **raw DSA** over a prime field — **no hashing or padding**. You sign/verify **integers** modulo `q` (`prime_seed`). For real use, hash the message first (e.g., SHA-256) and then map to an integer `< q`.
|
|
1996
|
+
|
|
1997
|
+
```py
|
|
1998
|
+
from transcrypto import dsa
|
|
1999
|
+
|
|
2000
|
+
# ➊ Shared parameters (p, q, g)
|
|
2001
|
+
shared = dsa.DSASharedPublicKey.New(p_bits=1024, q_bits=160)
|
|
2002
|
+
print(shared.prime_modulus) # p
|
|
2003
|
+
print(shared.prime_seed) # q (q | p-1)
|
|
2004
|
+
print(shared.group_base) # g
|
|
2005
|
+
|
|
2006
|
+
# ➋ Individual key pair
|
|
2007
|
+
priv = dsa.DSAPrivateKey.New(shared)
|
|
2008
|
+
pub = dsa.DSAPublicKey.Copy(priv)
|
|
2009
|
+
|
|
2010
|
+
# ➌ Sign & verify (message must be 1 ≤ m < q)
|
|
2011
|
+
msg = 123456789 % shared.prime_seed
|
|
2012
|
+
sig = priv.Sign(msg)
|
|
2013
|
+
assert pub.VerifySignature(msg, sig)
|
|
2014
|
+
```
|
|
2015
|
+
|
|
2016
|
+
- ranges:
|
|
2017
|
+
- `1 ≤ message < q`
|
|
2018
|
+
- signatures: `(s1, s2)` with `2 ≤ s1, s2 < q`
|
|
2019
|
+
- errors:
|
|
2020
|
+
- invalid ranges → `InputError`
|
|
2021
|
+
- inconsistent parameters → `CryptoError`
|
|
2022
|
+
|
|
2023
|
+
##### Security notes
|
|
2024
|
+
|
|
2025
|
+
- Choose **large** parameters (e.g., `p ≥ 2048 bits`, `q ≥ 224 bits`) for non-toy settings.
|
|
2026
|
+
- In practice, compute `m = int.from_bytes(Hash(message), 'big') % q` before calling `Sign(m)`.
|
|
2027
|
+
|
|
2028
|
+
##### Advanced: custom primes generator
|
|
2029
|
+
|
|
2030
|
+
```py
|
|
2031
|
+
# Generate primes (p, q) with q | (p-1); also returns m = (p-1)//q
|
|
2032
|
+
p, q, m = dsa.NBitRandomDSAPrimes(p_bits=1024, q_bits=160)
|
|
2033
|
+
assert (p - 1) % q == 0
|
|
2034
|
+
```
|
|
2035
|
+
|
|
2036
|
+
Used internally by `DSASharedPublicKey.New()`.
|
|
2037
|
+
Search breadth and retry caps are bounded; repeated failures raise `CryptoError`.
|
|
2038
|
+
|
|
2039
|
+
#### Public Bidding
|
|
2040
|
+
|
|
2041
|
+
This is a way of bidding on some commitment (the `secret`) that can be cryptographically proved later to not have been changed. To do that the secret is combined with 2 nonces (random values, `n1` & `n2`) and a hash of it is taken (`H=SHA-512(n1||n2||secret)`). The hash `H` and one nonce `n1` are public and divulged. The other nonce `n2` and the `secret` are kept private and will be used to show `secret` was not changed since the beginning of the process. The nonces guarantee the `secret` cannot be brute-forced or changed after-the-fact. The whole process is as strong as SHA-512 collisions.
|
|
2042
|
+
|
|
2043
|
+
```py
|
|
2044
|
+
from transcrypto import base
|
|
2045
|
+
|
|
2046
|
+
# Generate the private and public bids
|
|
2047
|
+
bid_priv = base.PrivateBid.New(secret) # this one you keep private
|
|
2048
|
+
bid_pub = base.PublicBid.Copy(bid_priv) # this one you publish
|
|
2049
|
+
|
|
2050
|
+
# Checking that a bid is genuine requires the public bid and knowing the nonce and the secret:
|
|
2051
|
+
print(bid_pub.VerifyBid(private_key, secret_bid)) # these come from a divulged private bid
|
|
2052
|
+
# of course, you want to also make sure the provided private data matches your version of it, e.g.:
|
|
2053
|
+
bid_pub_expected = base.PublicBid.Copy(bid_priv)
|
|
2054
|
+
print(bid_pub == bid_pub_expected)
|
|
2055
|
+
```
|
|
2056
|
+
|
|
2057
|
+
#### SSS (Shamir Shared Secret)
|
|
2058
|
+
|
|
2059
|
+
<https://en.wikipedia.org/wiki/Shamir's_secret_sharing>
|
|
2060
|
+
|
|
2061
|
+
This is the information-theoretic SSS but with no authentication or binding between share and secret. Malicious share injection is possible! Add MAC or digital signature in hostile settings. Use at least 128-bit modulus for non-toy deployments.
|
|
2062
|
+
|
|
2063
|
+
```py
|
|
2064
|
+
from transcrypto import sss
|
|
2065
|
+
|
|
2066
|
+
# ➊ Generate parameters: at least 3 of 5 shares needed,
|
|
2067
|
+
# coefficients & modulus are 128-bit primes
|
|
2068
|
+
priv = sss.ShamirSharedSecretPrivate.New(minimum_shares=3, bit_length=128)
|
|
2069
|
+
pub = sss.ShamirSharedSecretPublic.Copy(priv) # what you publish
|
|
2070
|
+
|
|
2071
|
+
print(f'threshold : {pub.minimum}')
|
|
2072
|
+
print(f'prime mod : {pub.modulus}')
|
|
2073
|
+
print(f'poly coefficients: {priv.polynomial}') # keep these private!
|
|
2074
|
+
|
|
2075
|
+
# Issuing shares
|
|
2076
|
+
|
|
2077
|
+
secret = 0xC0FFEE
|
|
2078
|
+
# Generate an unlimited stream; here we take 5
|
|
2079
|
+
five_shares = list(priv.Shares(secret, max_shares=5))
|
|
2080
|
+
for sh in five_shares:
|
|
2081
|
+
print(f'share {sh.share_key} → {sh.share_value}')
|
|
2082
|
+
```
|
|
2083
|
+
|
|
2084
|
+
A single share object looks like `sss.ShamirSharePrivate(minimum=3, modulus=..., share_key=42, share_value=123456789)`.
|
|
2085
|
+
|
|
2086
|
+
```py
|
|
2087
|
+
# Re-constructing the secret
|
|
2088
|
+
|
|
2089
|
+
subset = five_shares[:3] # any 3 distinct shares
|
|
2090
|
+
recovered = pub.RecoverSecret(subset)
|
|
2091
|
+
assert recovered == secret
|
|
2092
|
+
```
|
|
2093
|
+
|
|
2094
|
+
If you supply fewer than minimum shares you get a `CryptoError`, unless you explicitly override:
|
|
2095
|
+
|
|
2096
|
+
```py
|
|
2097
|
+
try:
|
|
2098
|
+
pub.RecoverSecret(five_shares[:2]) # raises
|
|
2099
|
+
except Exception as e:
|
|
2100
|
+
print(e) # "unrecoverable secret …"
|
|
2101
|
+
|
|
2102
|
+
# Force the interpolation even with 2 points (gives a wrong secret, of course)
|
|
2103
|
+
print(pub.RecoverSecret(five_shares[:2], force_recover=True))
|
|
2104
|
+
|
|
2105
|
+
# Checking that a share is genuine
|
|
2106
|
+
|
|
2107
|
+
share = five_shares[0]
|
|
2108
|
+
ok = priv.VerifyShare(secret, share) # ▶ True
|
|
2109
|
+
tampered = sss.ShamirSharePrivate(
|
|
2110
|
+
minimum=share.minimum,
|
|
2111
|
+
modulus=share.modulus,
|
|
2112
|
+
share_key=share.share_key,
|
|
2113
|
+
share_value=(share.share_value + 1) % share.modulus)
|
|
2114
|
+
print(priv.VerifyShare(secret, tampered)) # ▶ False
|
|
2115
|
+
```
|
|
2116
|
+
|
|
2117
|
+
## Appendix: Development Instructions
|
|
2118
|
+
|
|
2119
|
+
### Setup
|
|
2120
|
+
|
|
2121
|
+
If you want to develop for this project, first install python 3.13 and [Poetry](https://python-poetry.org/docs/cli/), but to get the versions you will need, we suggest you do it like this (*Linux*):
|
|
2122
|
+
|
|
2123
|
+
```sh
|
|
2124
|
+
sudo apt-get update
|
|
2125
|
+
sudo apt-get upgrade
|
|
2126
|
+
sudo apt-get install git python3 python3-pip pipx python3-dev python3-venv build-essential software-properties-common
|
|
2127
|
+
|
|
2128
|
+
sudo add-apt-repository ppa:deadsnakes/ppa # install arbitrary python version
|
|
2129
|
+
sudo apt-get update
|
|
2130
|
+
sudo apt-get install python3.13
|
|
2131
|
+
|
|
2132
|
+
sudo apt-get remove python3-poetry
|
|
2133
|
+
python3.13 -m pipx ensurepath
|
|
2134
|
+
# re-open terminal
|
|
2135
|
+
pipx install poetry
|
|
2136
|
+
poetry --version # should be >=2.1
|
|
2137
|
+
|
|
2138
|
+
poetry config virtualenvs.in-project true # creates .venv inside project directory
|
|
2139
|
+
poetry config pypi-token.pypi <TOKEN> # add your personal PyPI project token, if any
|
|
2140
|
+
```
|
|
2141
|
+
|
|
2142
|
+
or this (*Mac*):
|
|
2143
|
+
|
|
2144
|
+
```sh
|
|
2145
|
+
brew update
|
|
2146
|
+
brew upgrade
|
|
2147
|
+
brew cleanup -s
|
|
2148
|
+
|
|
2149
|
+
brew install git python@3.13 # install arbitrary python version
|
|
2150
|
+
|
|
2151
|
+
brew uninstall poetry
|
|
2152
|
+
python3.13 -m pip install --user pipx
|
|
2153
|
+
python3.13 -m pipx ensurepath
|
|
2154
|
+
# re-open terminal
|
|
2155
|
+
pipx install poetry
|
|
2156
|
+
poetry --version # should be >=2.1
|
|
2157
|
+
|
|
2158
|
+
poetry config virtualenvs.in-project true # creates .venv inside project directory
|
|
2159
|
+
poetry config pypi-token.pypi <TOKEN> # add your personal PyPI project token, if any
|
|
2160
|
+
```
|
|
2161
|
+
|
|
2162
|
+
Now install the project:
|
|
2163
|
+
|
|
2164
|
+
```sh
|
|
2165
|
+
git clone https://github.com/balparda/transcrypto.git transcrypto
|
|
2166
|
+
cd transcrypto
|
|
2167
|
+
|
|
2168
|
+
poetry env use python3.13 # creates the venv
|
|
2169
|
+
poetry install --sync # HONOR the project's poetry.lock file, uninstalls stray packages
|
|
2170
|
+
poetry env info # no-op: just to check
|
|
2171
|
+
|
|
2172
|
+
poetry run pytest -vvv
|
|
2173
|
+
# or any command as:
|
|
2174
|
+
poetry run <any-command>
|
|
2175
|
+
```
|
|
2176
|
+
|
|
2177
|
+
To activate like a regular environment do:
|
|
2178
|
+
|
|
2179
|
+
```sh
|
|
2180
|
+
poetry env activate
|
|
2181
|
+
# will print activation command which you next execute, or you can do:
|
|
2182
|
+
source .env/bin/activate # if .env is local to the project
|
|
2183
|
+
source "$(poetry env info --path)/bin/activate" # for other paths
|
|
2184
|
+
|
|
2185
|
+
pytest # or other commands
|
|
2186
|
+
|
|
2187
|
+
deactivate
|
|
2188
|
+
```
|
|
2189
|
+
|
|
2190
|
+
### Updating Dependencies
|
|
2191
|
+
|
|
2192
|
+
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.
|
|
2193
|
+
|
|
2194
|
+
To add a new dependency you should do:
|
|
2195
|
+
|
|
2196
|
+
```sh
|
|
2197
|
+
poetry add "pkg>=1.2.3" # regenerates lock, updates env (adds dep to prod code)
|
|
2198
|
+
poetry add -G dev "pkg>=1.2.3" # adds dep to dev code ("group" dev)
|
|
2199
|
+
# also remember: "pkg@^1.2.3" = latest 1.* ; "pkg@~1.2.3" = latest 1.2.* ; "pkg@1.2.3" exact
|
|
2200
|
+
```
|
|
2201
|
+
|
|
2202
|
+
If you manually added a dependency to `pyproject.toml` you should ***very carefully*** recreate the environment and files:
|
|
2203
|
+
|
|
2204
|
+
```sh
|
|
2205
|
+
rm -rf .venv .poetry poetry.lock
|
|
2206
|
+
poetry env use python3.13
|
|
2207
|
+
poetry install
|
|
2208
|
+
```
|
|
2209
|
+
|
|
2210
|
+
Remember to check your diffs before submitting (especially `poetry.lock`) to avoid surprises!
|
|
2211
|
+
|
|
2212
|
+
When dependencies change, always regenerate `requirements.txt` by running:
|
|
2213
|
+
|
|
2214
|
+
```sh
|
|
2215
|
+
poetry export --format requirements.txt --without-hashes --output requirements.txt
|
|
2216
|
+
```
|
|
2217
|
+
|
|
2218
|
+
### Creating a New Version
|
|
2219
|
+
|
|
2220
|
+
```sh
|
|
2221
|
+
# bump the version!
|
|
2222
|
+
poetry version minor # updates 1.6 to 1.7, for example
|
|
2223
|
+
# or:
|
|
2224
|
+
poetry version patch # updates 1.6 to 1.6.1
|
|
2225
|
+
# or:
|
|
2226
|
+
poetry version <version-number>
|
|
2227
|
+
# (also updates `pyproject.toml` and `poetry.lock`)
|
|
2228
|
+
|
|
2229
|
+
# publish to GIT, including a TAG
|
|
2230
|
+
git commit -a -m "release version 1.0.2"
|
|
2231
|
+
git tag 1.0.2
|
|
2232
|
+
git push
|
|
2233
|
+
git push --tags
|
|
2234
|
+
|
|
2235
|
+
# prepare package for PyPI
|
|
2236
|
+
poetry build
|
|
2237
|
+
poetry publish
|
|
2238
|
+
```
|
|
2239
|
+
|
|
2240
|
+
If you changed the CLI interface at all run:
|
|
2241
|
+
|
|
2242
|
+
```sh
|
|
2243
|
+
poetry run transcrypto doc md > CLI.md
|
|
2244
|
+
./tools/inject_md_includes.py
|
|
2245
|
+
```
|
|
2246
|
+
|
|
2247
|
+
You can find the 10 top slowest tests by running:
|
|
2248
|
+
|
|
2249
|
+
```sh
|
|
2250
|
+
poetry run pytest -vvv -q --durations=10
|
|
2251
|
+
```
|
|
2252
|
+
|
|
2253
|
+
You can search for flaky tests by running all tests 100 times:
|
|
2254
|
+
|
|
2255
|
+
```sh
|
|
2256
|
+
poetry run pytest --flake-finder --flake-runs=100
|
|
2257
|
+
```
|