Basic crypto primitives, not intended for actual use, but as a companion to --Criptografia, Métodos e Algoritmos--
Project description
TransCrypto
Basic cryptography primitives implementation, a companion to "Criptografia, Métodos e Algoritmos".
Started in July/2025, by Daniel Balparda. Since version 1.0.2 it is PyPI package:
https://pypi.org/project/transcrypto/
- TransCrypto
- License
- Design assumptions / Disclaimers
- Install
- Command-Line Interface
- Global Options
- Top-Level Commands
randomisprimeprimegenmersennegcdxgcdmodhashaesrsaelgamaldsabidsssdoc- Base Library
- Humanized Sizes (IEC binary)
- Humanized Decimal Quantities (SI)
- Humanized Durations
- Execution Timing
- Serialization Pipeline
- Cryptographically Secure Randomness
- Computing the Greatest Common Divisor
- Fast Modular Arithmetic
- Primality testing & Prime generators, Mersenne primes
- Cryptographic Hashing
- Symmetric Encryption Interface
- Crypto Objects General Properties (
CryptoKey) - AES-256 Symmetric Encryption
- RSA (Rivest-Shamir-Adleman) Public Cryptography
- El-Gamal Public-Key Cryptography
- DSA (Digital Signature Algorithm)
- Public Bidding
- SSS (Shamir Shared Secret)
- Appendix: Development Instructions
License
Copyright 2025 Daniel Balparda balparda@github.com
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.
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.
Design assumptions / Disclaimers
- The library is built to have reference, reliable, simple implementations of math and crypto primitives (e.g.
RawEncrypt()/RawSign()and friends plus all the low-level primality and modular arithmetic). The issue is not that the library is unsafe, it is that the library is full of places that allow you to shoot yourself in the foot if you don't know what you are doing. - The library also has advanced top-level methods that are cryptographically safe and might be used in real-world scenarios (e.g.
Encrypt()/Sign()and friends). - All library methods'
intare tailored to be efficient with arbitrarily large integers. - 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 you might consider other optimized/safe libraries that were built to be resistant to malicious attacks.
- All operations in this library may be vulnerable to timing attacks. This may be a problem to your use-case or not depending on the situation.
All that being said, extreme care was taken that this is a good library with a solid safe implementation. Have fun!
Install
To use in your project just do:
pip3 install transcrypto
and then from transcrypto import rsa (or other parts of the library) for using it.
Known dependencies:
Command-Line Interface
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.
Invoke with:
poetry run transcrypto <command> [sub-command] [options...]
Global Options
| Option/Arg | Description |
|---|---|
-v, --verbose |
Increase verbosity (use -v/-vv/-vvv/-vvvv for ERROR/WARN/INFO/DEBUG) |
--hex |
Treat inputs as hex string (default) |
--b64 |
Treat inputs as base64url |
--bin |
Treat inputs as binary (bytes) |
--out-hex |
Outputs as hex (default) |
--out-b64 |
Outputs as base64url |
--out-bin |
Outputs as binary (bytes) |
-p, --key-path |
File path to serialized key object, if key is needed for operation [type: str] |
--protect |
Password to encrypt/decrypt key file if using the -p/--key-path option [type: str] |
Top-Level Commands
random—poetry run transcrypto random [-h] {bits,int,bytes,prime} ...isprime—poetry run transcrypto isprime [-h] nprimegen—poetry run transcrypto primegen [-h] [-c COUNT] startmersenne—poetry run transcrypto mersenne [-h] [-k MIN_K] [-C CUTOFF_K]gcd—poetry run transcrypto gcd [-h] a bxgcd—poetry run transcrypto xgcd [-h] a bmod—poetry run transcrypto mod [-h] {inv,div,exp,poly,lagrange,crt} ...hash—poetry run transcrypto hash [-h] {sha256,sha512,file} ...aes—poetry run transcrypto aes [-h] {key,encrypt,decrypt,ecb} ...rsa—poetry run transcrypto rsa [-h] {new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...elgamal—poetry run transcrypto elgamal [-h] {shared,new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...dsa—poetry run transcrypto dsa [-h] {shared,new,rawsign,sign,rawverify,verify} ...bid—poetry run transcrypto bid [-h] {new,verify} ...sss—poetry run transcrypto sss [-h] {new,rawshares,shares,rawrecover,recover,rawverify} ...doc—poetry run transcrypto doc [-h] {md} ...
Examples:
# --- Randomness ---
poetry run transcrypto random bits 16
poetry run transcrypto random int 1000 2000
poetry run transcrypto random bytes 32
poetry run transcrypto random prime 64
# --- Primes ---
poetry run transcrypto isprime 428568761
poetry run transcrypto primegen 100 -c 3
poetry run transcrypto mersenne -k 2 -C 17
# --- Integer / Modular Math ---
poetry run transcrypto gcd 462 1071
poetry run transcrypto xgcd 127 13
poetry run transcrypto mod inv 17 97
poetry run transcrypto mod div 6 127 13
poetry run transcrypto mod exp 438 234 127
poetry run transcrypto mod poly 12 17 10 20 30
poetry run transcrypto mod lagrange 5 13 2:4 6:3 7:1
poetry run transcrypto mod crt 6 7 127 13
# --- Hashing ---
poetry run transcrypto hash sha256 xyz
poetry run transcrypto --b64 hash sha512 eHl6
poetry run transcrypto hash file /etc/passwd --digest sha512
# --- AES ---
poetry run transcrypto --out-b64 aes key "correct horse battery staple"
poetry run transcrypto --b64 --out-b64 aes encrypt -k "<b64key>" "secret"
poetry run transcrypto --b64 --out-b64 aes decrypt -k "<b64key>" "<ciphertext>"
poetry run transcrypto aes ecb -k "<b64key>" encrypt "<128bithexblock>"
poetry run transcrypto aes ecb -k "<b64key>" decrypt "<128bithexblock>"
# --- RSA ---
poetry run transcrypto -p rsa-key rsa new --bits 2048
poetry run transcrypto -p rsa-key.pub rsa rawencrypt <plaintext>
poetry run transcrypto -p rsa-key.priv rsa rawdecrypt <ciphertext>
poetry run transcrypto -p rsa-key.priv rsa rawsign <message>
poetry run transcrypto -p rsa-key.pub rsa rawverify <message> <signature>
# --- ElGamal ---
poetry run transcrypto -p eg-key elgamal shared --bits 2048
poetry run transcrypto -p eg-key elgamal new
poetry run transcrypto -p eg-key.pub elgamal rawencrypt <plaintext>
poetry run transcrypto -p eg-key.priv elgamal rawdecrypt <c1:c2>
poetry run transcrypto -p eg-key.priv elgamal rawsign <message>
poetry run transcrypto-p eg-key.pub elgamal rawverify <message> <s1:s2>
# --- DSA ---
poetry run transcrypto -p dsa-key dsa shared --p-bits 2048 --q-bits 256
poetry run transcrypto -p dsa-key dsa new
poetry run transcrypto -p dsa-key.priv dsa rawsign <message>
poetry run transcrypto -p dsa-key.pub dsa rawverify <message> <s1:s2>
# --- Public Bid ---
poetry run transcrypto --bin bid new "tomorrow it will rain"
poetry run transcrypto --out-bin bid verify
# --- Shamir Secret Sharing (SSS) ---
poetry run transcrypto -p sss-key sss new 3 --bits 1024
poetry run transcrypto -p sss-key sss rawshares <secret> 5
poetry run transcrypto -p sss-key sss rawrecover
poetry run transcrypto -p sss-key sss rawverify <secret>
random
Cryptographically secure randomness, from the OS CSPRNG.
poetry run transcrypto random [-h] {bits,int,bytes,prime} ...
random bits
Random integer with exact bit length = bits (MSB will be 1).
poetry run transcrypto random bits [-h] bits
| Option/Arg | Description |
|---|---|
bits |
Number of bits, ≥ 8 [type: int] |
Example:
$ poetry run transcrypto random bits 16
36650
random int
Uniform random integer in [min, max] range, inclusive.
poetry run transcrypto random int [-h] min max
| Option/Arg | Description |
|---|---|
min |
Minimum, ≥ 0 [type: str] |
max |
Maximum, > min [type: str] |
Example:
$ poetry run transcrypto random int 1000 2000
1628
random bytes
Generates n cryptographically secure random bytes.
poetry run transcrypto random bytes [-h] n
| Option/Arg | Description |
|---|---|
n |
Number of bytes, ≥ 1 [type: int] |
Example:
$ poetry run transcrypto random bytes 32
6c6f1f88cb93c4323285a2224373d6e59c72a9c2b82e20d1c376df4ffbe9507f
random prime
Generate a random prime with exact bit length = bits (MSB will be 1).
poetry run transcrypto random prime [-h] bits
| Option/Arg | Description |
|---|---|
bits |
Bit length, ≥ 11 [type: int] |
Example:
$ poetry run transcrypto random prime 32
2365910551
isprime
Primality test with safe defaults, useful for any integer size.
poetry run transcrypto isprime [-h] n
| Option/Arg | Description |
|---|---|
n |
Integer to test, ≥ 1 [type: str] |
Example:
$ poetry run transcrypto isprime 2305843009213693951
True
$ poetry run transcrypto isprime 2305843009213693953
False
primegen
Generate (stream) primes ≥ start (prints a limited count by default).
poetry run transcrypto primegen [-h] [-c COUNT] start
| Option/Arg | Description |
|---|---|
start |
Starting integer (inclusive) [type: str] |
-c, --count |
How many to print (0 = unlimited) [type: int (default: 10)] |
Example:
$ poetry run transcrypto primegen 100 -c 3
101
103
107
mersenne
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.
poetry run transcrypto mersenne [-h] [-k MIN_K] [-C CUTOFF_K]
| Option/Arg | Description |
|---|---|
-k, --min-k |
Starting exponent k, ≥ 1 [type: int (default: 1)] |
-C, --cutoff-k |
Stop once k > cutoff-k [type: int (default: 10000)] |
Example:
$ poetry run transcrypto mersenne -k 0 -C 15
k=2 M=3 perfect=6
k=3 M=7 perfect=28
k=5 M=31 perfect=496
k=7 M=127 perfect=8128
k=13 M=8191 perfect=33550336
k=17 M=131071 perfect=8589869056
gcd
Greatest Common Divisor (GCD) of integers a and b.
poetry run transcrypto gcd [-h] a b
| Option/Arg | Description |
|---|---|
a |
Integer, ≥ 0 [type: str] |
b |
Integer, ≥ 0 (can't be both zero) [type: str] |
Example:
$ poetry run transcrypto gcd 462 1071
21
$ poetry run transcrypto gcd 0 5
5
$ poetry run transcrypto gcd 127 13
1
xgcd
Extended Greatest Common Divisor (x-GCD) of integers a and b, will return (g, x, y) where a×x+b×y==g.
poetry run transcrypto xgcd [-h] a b
| Option/Arg | Description |
|---|---|
a |
Integer, ≥ 0 [type: str] |
b |
Integer, ≥ 0 (can't be both zero) [type: str] |
Example:
$ poetry run transcrypto xgcd 462 1071
(21, 7, -3)
$ poetry run transcrypto xgcd 0 5
(5, 0, 1)
$ poetry run transcrypto xgcd 127 13
(1, 4, -39)
mod
Modular arithmetic helpers.
poetry run transcrypto mod [-h] {inv,div,exp,poly,lagrange,crt} ...
mod inv
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.
poetry run transcrypto mod inv [-h] a m
| Option/Arg | Description |
|---|---|
a |
Integer to invert [type: str] |
m |
Modulus m, ≥ 2 [type: str] |
Example:
$ poetry run transcrypto mod inv 127 13
4
$ poetry run transcrypto mod inv 17 3120
2753
$ poetry run transcrypto mod inv 462 1071
<<INVALID>> no modular inverse exists (ModularDivideError)
mod div
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.
poetry run transcrypto mod div [-h] x y m
| Option/Arg | Description |
|---|---|
x |
Integer [type: str] |
y |
Integer, cannot be zero [type: str] |
m |
Modulus m, ≥ 2 [type: str] |
Example:
$ poetry run transcrypto mod div 6 127 13
11
$ poetry run transcrypto mod div 6 0 13
<<INVALID>> no modular inverse exists (ModularDivideError)
mod exp
Modular exponentiation: a^e mod m. Efficient, can handle huge values.
poetry run transcrypto mod exp [-h] a e m
| Option/Arg | Description |
|---|---|
a |
Integer [type: str] |
e |
Integer, ≥ 0 [type: str] |
m |
Modulus m, ≥ 2 [type: str] |
Example:
$ poetry run transcrypto mod exp 438 234 127
32
$ poetry run transcrypto mod exp 438 234 89854
60622
mod poly
Efficiently evaluate polynomial with coeff coefficients at point x modulo m (c₀+c₁×x+c₂×x²+…+cₙ×xⁿ mod m).
poetry run transcrypto mod poly [-h] x m coeff [coeff ...]
| Option/Arg | Description |
|---|---|
x |
Evaluation point x [type: str] |
m |
Modulus m, ≥ 2 [type: str] |
coeff |
Coefficients (constant-term first: c₀+c₁×x+c₂×x²+…+cₙ×xⁿ) [nargs: +] |
Example:
$ poetry run transcrypto mod poly 12 17 10 20 30
14 # (10+20×12+30×12² ≡ 14 (mod 17))
$ poetry run transcrypto mod poly 10 97 3 0 0 1 1
42 # (3+1×10³+1×10⁴ ≡ 42 (mod 97))
mod lagrange
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.
poetry run transcrypto mod lagrange [-h] x m pt [pt ...]
| Option/Arg | Description |
|---|---|
x |
Evaluation point x [type: str] |
m |
Modulus m, ≥ 2 [type: str] |
pt |
Points zₙ:f(zₙ) as key:value pairs (e.g., 2:4 5:3 7:1) [nargs: +] |
Example:
$ poetry run transcrypto mod lagrange 5 13 2:4 6:3 7:1
3 # passes through (2,4), (6,3), (7,1)
$ poetry run transcrypto mod lagrange 11 97 1:1 2:4 3:9 4:16 5:25
24 # passes through (1,1), (2,4), (3,9), (4,16), (5,25)
mod crt
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.
poetry run transcrypto mod crt [-h] a1 m1 a2 m2
| Option/Arg | Description |
|---|---|
a1 |
Integer residue for first congruence [type: str] |
m1 |
Modulus m1, ≥ 2 and gcd(m1,m2)==1 [type: str] |
a2 |
Integer residue for second congruence [type: str] |
m2 |
Modulus m2, ≥ 2 and gcd(m1,m2)==1 [type: str] |
Example:
$ poetry run transcrypto mod crt 6 7 127 13
62
$ poetry run transcrypto mod crt 12 56 17 19
796
$ poetry run transcrypto mod crt 6 7 462 1071
<<INVALID>> moduli m1/m2 not co-prime (ModularDivideError)
hash
Cryptographic Hashing (SHA-256 / SHA-512 / file).
poetry run transcrypto hash [-h] {sha256,sha512,file} ...
hash sha256
SHA-256 of input data.
poetry run transcrypto hash sha256 [-h] data
| Option/Arg | Description |
|---|---|
data |
Input data (raw text; or use --hex/--b64/--bin) [type: str] |
Example:
$ poetry run transcrypto --bin hash sha256 xyz
3608bca1e44ea6c4d268eb6db02260269892c0b42b86bbf1e77a6fa16c3c9282
$ poetry run transcrypto --b64 hash sha256 eHl6 # "xyz" in base-64
3608bca1e44ea6c4d268eb6db02260269892c0b42b86bbf1e77a6fa16c3c9282
hash sha512
SHA-512 of input data.
poetry run transcrypto hash sha512 [-h] data
| Option/Arg | Description |
|---|---|
data |
Input data (raw text; or use --hex/--b64/--bin) [type: str] |
Example:
$ poetry run transcrypto --bin hash sha512 xyz
4a3ed8147e37876adc8f76328e5abcc1b470e6acfc18efea0135f983604953a58e183c1a6086e91ba3e821d926f5fdeb37761c7ca0328a963f5e92870675b728
$ poetry run transcrypto --b64 hash sha512 eHl6 # "xyz" in base-64
4a3ed8147e37876adc8f76328e5abcc1b470e6acfc18efea0135f983604953a58e183c1a6086e91ba3e821d926f5fdeb37761c7ca0328a963f5e92870675b728
hash file
SHA-256/512 hash of file contents, defaulting to SHA-256.
poetry run transcrypto hash file [-h] [--digest {sha256,sha512}] path
| Option/Arg | Description |
|---|---|
path |
Path to existing file [type: str] |
--digest |
Digest type, SHA-256 ("sha256") or SHA-512 ("sha512") [choices: ['sha256', 'sha512'] (default: sha256)] |
Example:
$ poetry run transcrypto hash file /etc/passwd --digest sha512
8966f5953e79f55dfe34d3dc5b160ac4a4a3f9cbd1c36695a54e28d77c7874dff8595502f8a420608911b87d336d9e83c890f0e7ec11a76cb10b03e757f78aea
aes
AES-256 operations (GCM/ECB) and key derivation. No measures are taken here to prevent timing attacks.
poetry run transcrypto aes [-h] {key,encrypt,decrypt,ecb} ...
aes key
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).
poetry run transcrypto aes key [-h] password
| Option/Arg | Description |
|---|---|
password |
Password (leading/trailing spaces ignored) [type: str] |
Example:
$ poetry run transcrypto --out-b64 aes key "correct horse battery staple"
DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es=
$ poetry run transcrypto -p keyfile.out --protect hunter aes key "correct horse battery staple"
AES key saved to 'keyfile.out'
aes encrypt
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!
poetry run transcrypto aes encrypt [-h] [-k KEY] [-a AAD] plaintext
| Option/Arg | Description |
|---|---|
plaintext |
Input data to encrypt (PT) [type: str] |
-k, --key |
Key if -p/--key-path wasn't used (32 bytes) [type: str] |
-a, --aad |
Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
Example:
$ poetry run transcrypto --b64 --out-b64 aes encrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= AAAAAAB4eXo=
F2_ZLrUw5Y8oDnbTP5t5xCUWX8WtVILLD0teyUi_37_4KHeV-YowVA==
$ poetry run transcrypto --b64 --out-b64 aes encrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -a eHl6 AAAAAAB4eXo=
xOlAHPUPpeyZHId-f3VQ_QKKMxjIW0_FBo9WOfIBrzjn0VkVV6xTRA==
aes decrypt
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!
poetry run transcrypto aes decrypt [-h] [-k KEY] [-a AAD] ciphertext
| Option/Arg | Description |
|---|---|
ciphertext |
Input data to decrypt (CT) [type: str] |
-k, --key |
Key if -p/--key-path wasn't used (32 bytes) [type: str] |
-a, --aad |
Associated data (optional; has to be exactly the same as used during encryption) [type: str] |
Example:
$ poetry run transcrypto --b64 --out-b64 aes decrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= F2_ZLrUw5Y8oDnbTP5t5xCUWX8WtVILLD0teyUi_37_4KHeV-YowVA==
AAAAAAB4eXo=
$ poetry run transcrypto --b64 --out-b64 aes decrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -a eHl6 xOlAHPUPpeyZHId-f3VQ_QKKMxjIW0_FBo9WOfIBrzjn0VkVV6xTRA==
AAAAAAB4eXo=
aes ecb
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).
poetry run transcrypto aes ecb [-h] [-k KEY] {encrypt,decrypt} ...
| Option/Arg | Description |
|---|---|
-k, --key |
Key if -p/--key-path wasn't used (32 bytes; raw, or you can use --bin/--hex/--b64 flags) [type: str] |
aes ecb encrypt
AES-256-ECB: encrypt 16-bytes hex plaintext with -k/--key or with -p/--key-path keyfile. UNSAFE, except for specifically encrypting hash blocks.
poetry run transcrypto aes ecb encrypt [-h] plaintext
| Option/Arg | Description |
|---|---|
plaintext |
Plaintext block as 32 hex chars (16-bytes) [type: str] |
Example:
$ poetry run transcrypto --b64 aes ecb -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= encrypt 00112233445566778899aabbccddeeff
54ec742ca3da7b752e527b74e3a798d7
aes ecb decrypt
AES-256-ECB: decrypt 16-bytes hex ciphertext with -k/--key or with -p/--key-path keyfile. UNSAFE, except for specifically encrypting hash blocks.
poetry run transcrypto aes ecb decrypt [-h] ciphertext
| Option/Arg | Description |
|---|---|
ciphertext |
Ciphertext block as 32 hex chars (16-bytes) [type: str] |
Example:
$ poetry run transcrypto --b64 aes ecb -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= decrypt 54ec742ca3da7b752e527b74e3a798d7
00112233445566778899aabbccddeeff
rsa
RSA (Rivest-Shamir-Adleman) asymmetric cryptography. No measures are taken here to prevent timing attacks. All methods require file key(s) as -p/--key-path (see provided examples).
poetry run transcrypto rsa [-h]
{new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...
rsa new
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.
poetry run transcrypto rsa new [-h] [--bits BITS]
| Option/Arg | Description |
|---|---|
--bits |
Modulus size in bits; the default is a safe size [type: int (default: 3332)] |
Example:
$ poetry run transcrypto -p rsa-key rsa new --bits 64 # NEVER use such a small key: example only!
RSA private/public keys saved to 'rsa-key.priv/.pub'
rsa rawencrypt
Raw encrypt integer message with public key (BEWARE: no OAEP/PSS padding or validation).
poetry run transcrypto rsa rawencrypt [-h] message
| Option/Arg | Description |
|---|---|
message |
Integer message to encrypt, 1≤message<modulus [type: str] |
Example:
$ poetry run transcrypto -p rsa-key.pub rsa rawencrypt 999
6354905961171348600
rsa encrypt
Encrypt message with public key.
poetry run transcrypto rsa encrypt [-h] [-a AAD] plaintext
| Option/Arg | Description |
|---|---|
plaintext |
Message to encrypt [type: str] |
-a, --aad |
Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
Example:
$ poetry run transcrypto --bin --out-b64 -p rsa-key.pub rsa encrypt "abcde" -a "xyz"
AO6knI6xwq6TGR…Qy22jiFhXi1eQ==
rsa rawdecrypt
Raw decrypt integer ciphertext with private key (BEWARE: no OAEP/PSS padding or validation).
poetry run transcrypto rsa rawdecrypt [-h] ciphertext
| Option/Arg | Description |
|---|---|
ciphertext |
Integer ciphertext to decrypt, 1≤ciphertext<modulus [type: str] |
Example:
$ poetry run transcrypto -p rsa-key.priv rsa rawdecrypt 6354905961171348600
999
rsa decrypt
Decrypt ciphertext with private key.
poetry run transcrypto rsa decrypt [-h] [-a AAD] ciphertext
| Option/Arg | Description |
|---|---|
ciphertext |
Ciphertext to decrypt [type: str] |
-a, --aad |
Associated data (optional; has to be exactly the same as used during encryption) [type: str] |
Example:
$ poetry run transcrypto --b64 --out-bin -p rsa-key.priv rsa decrypt "AO6knI6xwq6TGR…Qy22jiFhXi1eQ==" -a "eHl6"
abcde
rsa rawsign
Raw sign integer message with private key (BEWARE: no OAEP/PSS padding or validation).
poetry run transcrypto rsa rawsign [-h] message
| Option/Arg | Description |
|---|---|
message |
Integer message to sign, 1≤message<modulus [type: str] |
Example:
$ poetry run transcrypto -p rsa-key.priv rsa rawsign 999
7632909108672871784
rsa sign
Sign message with private key.
poetry run transcrypto rsa sign [-h] [-a AAD] message
| Option/Arg | Description |
|---|---|
message |
Message to sign [type: str] |
-a, --aad |
Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
Example:
$ poetry run transcrypto --bin --out-b64 -p rsa-key.priv rsa sign "xyz"
91TS7gC6LORiL…6RD23Aejsfxlw==
rsa rawverify
Raw verify integer signature for integer message with public key (BEWARE: no OAEP/PSS padding or validation).
poetry run transcrypto rsa rawverify [-h] message signature
| Option/Arg | Description |
|---|---|
message |
Integer message that was signed earlier, 1≤message<modulus [type: str] |
signature |
Integer putative signature for message, 1≤signature<modulus [type: str] |
Example:
$ poetry run transcrypto -p rsa-key.pub rsa rawverify 999 7632909108672871784
RSA signature: OK
$ poetry run transcrypto -p rsa-key.pub rsa rawverify 999 7632909108672871785
RSA signature: INVALID
rsa verify
Verify signature for message with public key.
poetry run transcrypto rsa verify [-h] [-a AAD] message signature
| Option/Arg | Description |
|---|---|
message |
Message that was signed earlier [type: str] |
signature |
Putative signature for message [type: str] |
-a, --aad |
Associated data (optional; has to be exactly the same as used during signing) [type: str] |
Example:
$ poetry run transcrypto --b64 -p rsa-key.pub rsa verify "eHl6" "91TS7gC6LORiL…6RD23Aejsfxlw=="
RSA signature: OK
$ poetry run transcrypto --b64 -p rsa-key.pub rsa verify "eLl6" "91TS7gC6LORiL…6RD23Aejsfxlw=="
RSA signature: INVALID
elgamal
El-Gamal asymmetric cryptography. No measures are taken here to prevent timing attacks. All methods require file key(s) as -p/--key-path (see provided examples).
poetry run transcrypto elgamal [-h]
{shared,new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...
elgamal shared
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.
poetry run transcrypto elgamal shared [-h] [--bits BITS]
| Option/Arg | Description |
|---|---|
--bits |
Prime modulus (p) size in bits; the default is a safe size [type: int (default: 3332)] |
Example:
$ poetry run transcrypto -p eg-key elgamal shared --bits 64 # NEVER use such a small key: example only!
El-Gamal shared key saved to 'eg-key.shared'
elgamal new
Generate an individual El-Gamal private/public key pair from a shared key.
poetry run transcrypto elgamal new [-h]
Example:
$ poetry run transcrypto -p eg-key elgamal new
El-Gamal private/public keys saved to 'eg-key.priv/.pub'
elgamal rawencrypt
Raw encrypt integer message with public key (BEWARE: no ECIES-style KEM/DEM padding or validation).
poetry run transcrypto elgamal rawencrypt [-h] message
| Option/Arg | Description |
|---|---|
message |
Integer message to encrypt, 1≤message<modulus [type: str] |
Example:
$ poetry run transcrypto -p eg-key.pub elgamal rawencrypt 999
2948854810728206041:15945988196340032688
elgamal encrypt
Encrypt message with public key.
poetry run transcrypto elgamal encrypt [-h] [-a AAD] plaintext
| Option/Arg | Description |
|---|---|
plaintext |
Message to encrypt [type: str] |
-a, --aad |
Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
Example:
$ poetry run transcrypto --bin --out-b64 -p eg-key.pub elgamal encrypt "abcde" -a "xyz"
CdFvoQ_IIPFPZLua…kqjhcUTspISxURg==
elgamal rawdecrypt
Raw decrypt integer ciphertext with private key (BEWARE: no ECIES-style KEM/DEM padding or validation).
poetry run transcrypto elgamal rawdecrypt [-h] ciphertext
| Option/Arg | Description |
|---|---|
ciphertext |
Integer ciphertext to decrypt; expects c1:c2 format with 2 integers, 2≤c1,c2<modulus [type: str] |
Example:
$ poetry run transcrypto -p eg-key.priv elgamal rawdecrypt 2948854810728206041:15945988196340032688
999
elgamal decrypt
Decrypt ciphertext with private key.
poetry run transcrypto elgamal decrypt [-h] [-a AAD] ciphertext
| Option/Arg | Description |
|---|---|
ciphertext |
Ciphertext to decrypt [type: str] |
-a, --aad |
Associated data (optional; has to be exactly the same as used during encryption) [type: str] |
Example:
$ poetry run transcrypto --b64 --out-bin -p eg-key.priv elgamal decrypt "CdFvoQ_IIPFPZLua…kqjhcUTspISxURg==" -a "eHl6"
abcde
elgamal rawsign
Raw sign integer message with private key (BEWARE: no ECIES-style KEM/DEM padding or validation). Output will 2 integers in a s1:s2 format.
poetry run transcrypto elgamal rawsign [-h] message
| Option/Arg | Description |
|---|---|
message |
Integer message to sign, 1≤message<modulus [type: str] |
Example:
$ poetry run transcrypto -p eg-key.priv elgamal rawsign 999
4674885853217269088:14532144906178302633
elgamal sign
Sign message with private key.
poetry run transcrypto elgamal sign [-h] [-a AAD] message
| Option/Arg | Description |
|---|---|
message |
Message to sign [type: str] |
-a, --aad |
Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
Example:
$ poetry run transcrypto --bin --out-b64 -p eg-key.priv elgamal sign "xyz"
Xl4hlYK8SHVGw…0fCKJE1XVzA==
elgamal rawverify
Raw verify integer signature for integer message with public key (BEWARE: no ECIES-style KEM/DEM padding or validation).
poetry run transcrypto elgamal rawverify [-h] message signature
| Option/Arg | Description |
|---|---|
message |
Integer message that was signed earlier, 1≤message<modulus [type: str] |
signature |
Integer putative signature for message; expects s1:s2 format with 2 integers, 2≤s1,s2<modulus [type: str] |
Example:
$ poetry run transcrypto -p eg-key.pub elgamal rawverify 999 4674885853217269088:14532144906178302633
El-Gamal signature: OK
$ poetry run transcrypto -p eg-key.pub elgamal rawverify 999 4674885853217269088:14532144906178302632
El-Gamal signature: INVALID
elgamal verify
Verify signature for message with public key.
poetry run transcrypto elgamal verify [-h] [-a AAD] message signature
| Option/Arg | Description |
|---|---|
message |
Message that was signed earlier [type: str] |
signature |
Putative signature for message [type: str] |
-a, --aad |
Associated data (optional; has to be exactly the same as used during signing) [type: str] |
Example:
$ poetry run transcrypto --b64 -p eg-key.pub elgamal verify "eHl6" "Xl4hlYK8SHVGw…0fCKJE1XVzA=="
El-Gamal signature: OK
$ poetry run transcrypto --b64 -p eg-key.pub elgamal verify "eLl6" "Xl4hlYK8SHVGw…0fCKJE1XVzA=="
El-Gamal signature: INVALID
dsa
DSA (Digital Signature Algorithm) asymmetric signing/verifying. No measures are taken here to prevent timing attacks. All methods require file key(s) as -p/--key-path (see provided examples).
poetry run transcrypto dsa [-h]
{shared,new,rawsign,sign,rawverify,verify} ...
dsa shared
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. 4096/544). 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.
poetry run transcrypto dsa shared [-h] [--p-bits P_BITS]
[--q-bits Q_BITS]
| Option/Arg | Description |
|---|---|
--p-bits |
Prime modulus (p) size in bits; the default is a safe size [type: int (default: 4096)] |
--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: 544)] |
Example:
$ poetry run transcrypto -p dsa-key dsa shared --p-bits 128 --q-bits 32 # NEVER use such a small key: example only!
DSA shared key saved to 'dsa-key.shared'
dsa new
Generate an individual DSA private/public key pair from a shared key.
poetry run transcrypto dsa new [-h]
Example:
$ poetry run transcrypto -p dsa-key dsa new
DSA private/public keys saved to 'dsa-key.priv/.pub'
dsa rawsign
Raw sign integer message with private key (BEWARE: no ECDSA/EdDSA padding or validation). Output will 2 integers in a s1:s2 format.
poetry run transcrypto dsa rawsign [-h] message
| Option/Arg | Description |
|---|---|
message |
Integer message to sign, 1≤message<q [type: str] |
Example:
$ poetry run transcrypto -p dsa-key.priv dsa rawsign 999
2395961484:3435572290
dsa sign
Sign message with private key.
poetry run transcrypto dsa sign [-h] [-a AAD] message
| Option/Arg | Description |
|---|---|
message |
Message to sign [type: str] |
-a, --aad |
Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
Example:
$ poetry run transcrypto --bin --out-b64 -p dsa-key.priv dsa sign "xyz"
yq8InJVpViXh9…BD4par2XuA=
dsa rawverify
Raw verify integer signature for integer message with public key (BEWARE: no ECDSA/EdDSA padding or validation).
poetry run transcrypto dsa rawverify [-h] message signature
| Option/Arg | Description |
|---|---|
message |
Integer message that was signed earlier, 1≤message<q [type: str] |
signature |
Integer putative signature for message; expects s1:s2 format with 2 integers, 2≤s1,s2<q [type: str] |
Example:
$ poetry run transcrypto -p dsa-key.pub dsa rawverify 999 2395961484:3435572290
DSA signature: OK
$ poetry run transcrypto -p dsa-key.pub dsa rawverify 999 2395961484:3435572291
DSA signature: INVALID
dsa verify
Verify signature for message with public key.
poetry run transcrypto dsa verify [-h] [-a AAD] message signature
| Option/Arg | Description |
|---|---|
message |
Message that was signed earlier [type: str] |
signature |
Putative signature for message [type: str] |
-a, --aad |
Associated data (optional; has to be exactly the same as used during signing) [type: str] |
Example:
$ poetry run transcrypto --b64 -p dsa-key.pub dsa verify "eHl6" "yq8InJVpViXh9…BD4par2XuA="
DSA signature: OK
$ poetry run transcrypto --b64 -p dsa-key.pub dsa verify "eLl6" "yq8InJVpViXh9…BD4par2XuA="
DSA signature: INVALID
bid
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).
poetry run transcrypto bid [-h] {new,verify} ...
bid new
Generate the bid files for secret. Requires -p/--key-path to set the basename for output files.
poetry run transcrypto bid new [-h] secret
| Option/Arg | Description |
|---|---|
secret |
Input data to bid to, the protected "secret" [type: str] |
Example:
$ poetry run transcrypto --bin -p my-bid bid new "tomorrow it will rain"
Bid private/public commitments saved to 'my-bid.priv/.pub'
bid verify
Verify the bid files for correctness and reveal the secret. Requires -p/--key-path to set the basename for output files.
poetry run transcrypto bid verify [-h]
Example:
$ poetry run transcrypto --out-bin -p my-bid bid verify
Bid commitment: OK
Bid secret:
tomorrow it will rain
sss
SSS (Shamir Shared Secret) secret sharing crypto scheme. No measures are taken here to prevent timing attacks. All methods require file key(s) as -p/--key-path (see provided examples).
poetry run transcrypto sss [-h]
{new,rawshares,shares,rawrecover,recover,rawverify} ...
sss new
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.
poetry run transcrypto sss new [-h] [--bits BITS] minimum
| Option/Arg | Description |
|---|---|
minimum |
Minimum number of shares required to recover secret, ≥ 2 [type: int] |
--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)] |
Example:
$ poetry run transcrypto -p sss-key sss new 3 --bits 64 # NEVER use such a small key: example only!
SSS private/public keys saved to 'sss-key.priv/.pub'
sss rawshares
Raw shares: Issue count private shares for an integer secret (BEWARE: no modern message wrapping, padding or validation).
poetry run transcrypto sss rawshares [-h] secret count
| Option/Arg | Description |
|---|---|
secret |
Integer secret to be protected, 1≤secret<modulus [type: str] |
count |
How many shares to produce; must be ≥ minimum used in new command or else the secret would become unrecoverable [type: int] |
Example:
$ poetry run transcrypto -p sss-key sss rawshares 999 5
SSS 5 individual (private) shares saved to 'sss-key.share.1…5'
$ rm sss-key.share.2 sss-key.share.4 # this is to simulate only having shares 1,3,5
sss shares
Shares: Issue count private shares for a secret.
poetry run transcrypto sss shares [-h] secret count
| Option/Arg | Description |
|---|---|
secret |
Secret to be protected [type: str] |
count |
How many shares to produce; must be ≥ minimum used in new command or else the secret would become unrecoverable [type: int] |
Example:
$ poetry run transcrypto --bin -p sss-key sss shares "abcde" 5
SSS 5 individual (private) shares saved to 'sss-key.share.1…5'
$ rm sss-key.share.2 sss-key.share.4 # this is to simulate only having shares 1,3,5
sss rawrecover
Raw recover integer secret from shares; will use any available shares that were found (BEWARE: no modern message wrapping, padding or validation).
poetry run transcrypto sss rawrecover [-h]
Example:
$ poetry run transcrypto -p sss-key sss rawrecover
Loaded SSS share: 'sss-key.share.3'
Loaded SSS share: 'sss-key.share.5'
Loaded SSS share: 'sss-key.share.1' # using only 3 shares: number 2/4 are missing
Secret:
999
sss recover
Recover secret from shares; will use any available shares that were found.
poetry run transcrypto sss recover [-h]
Example:
$ poetry run transcrypto --out-bin -p sss-key sss recover
Loaded SSS share: 'sss-key.share.3'
Loaded SSS share: 'sss-key.share.5'
Loaded SSS share: 'sss-key.share.1' # using only 3 shares: number 2/4 are missing
Secret:
abcde
sss rawverify
Raw verify shares against a secret (private params; BEWARE: no modern message wrapping, padding or validation).
poetry run transcrypto sss rawverify [-h] secret
| Option/Arg | Description |
|---|---|
secret |
Integer secret used to generate the shares [type: str] |
Example:
$ poetry run transcrypto -p sss-key sss rawverify 999
SSS share 'sss-key.share.3' verification: OK
SSS share 'sss-key.share.5' verification: OK
SSS share 'sss-key.share.1' verification: OK
$ poetry run transcrypto -p sss-key sss rawverify 998
SSS share 'sss-key.share.3' verification: INVALID
SSS share 'sss-key.share.5' verification: INVALID
SSS share 'sss-key.share.1' verification: INVALID
doc
Documentation utilities. (Not for regular use: these are developer utils.)
poetry run transcrypto doc [-h] {md} ...
doc md
Emit Markdown docs for the CLI (see README.md section "Creating a New Version").
poetry run transcrypto doc md [-h]
Example:
$ poetry run transcrypto doc md > CLI.md
$ ./tools/inject_md_includes.py
inject: README.md updated with included content
Base Library
Humanized Sizes (IEC binary)
from transcrypto import utils
utils.HumanizedBytes(512) # '512 B'
utils.HumanizedBytes(2048) # '2.00 KiB'
utils.HumanizedBytes(5 * 1024**3) # '5.00 GiB'
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.
- standard: 1 KiB = 1024 B, 1 MiB = 1024 KiB, …
- errors: negative inputs raise
InputError
Humanized Decimal Quantities (SI)
# Base (unitless)
utils.HumanizedDecimal(950) # '950'
utils.HumanizedDecimal(1500) # '1.50 k'
# With a unit (trimmed and attached)
utils.HumanizedDecimal(1500, ' Hz ') # '1.50 kHz'
utils.HumanizedDecimal(0.123456, 'V') # '0.1235 V'
# Large magnitudes
utils.HumanizedDecimal(3_200_000) # '3.20 M'
utils.HumanizedDecimal(7.2e12, 'B/s') # '7.20 TB/s'
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).
- unit handling:
unitis stripped;<1000values include a space before the unit ('950 Hz') - errors: negative or non-finite inputs raise
InputError
Humanized Durations
utils.HumanizedSeconds(0) # '0.00 s'
utils.HumanizedSeconds(0.000004) # '4.000 µs'
utils.HumanizedSeconds(0.25) # '250.000 ms'
utils.HumanizedSeconds(42) # '42.00 s'
utils.HumanizedSeconds(3661) # '1.02 h'
utils.HumanizedSeconds(172800) # '2.00 d'
Chooses an appropriate time unit based on magnitude and formats with fixed precision:
< 1 ms: microseconds with three decimals (µs)< 1 s: milliseconds with three decimals (ms)< 60 s: seconds with two decimals (s)< 60 min: minutes with two decimals (min)< 24 h: hours with two decimals (h)≥ 24 h: days with two decimals (d)- special case:
0 → '0.00 s' - errors: negative or non-finite inputs raise
InputError
Execution Timing
A flexible timing utility that works as a context manager, decorator, or manual timer object.
from transcrypto import base
import time
Context manager
with base.Timer('Block timing'):
time.sleep(1.2)
# → logs: "Block timing: 1.20 s" (default via logging.info)
Starts timing on entry, stops on exit, and reports elapsed time automatically.
Decorator
@base.Timer('Function timing')
def slow_function():
time.sleep(0.8)
slow_function()
# → logs: "Function timing: 0.80 s"
Wraps a function so that each call is automatically timed.
Manual use
tm = base.Timer('Inline timing', emit_print=True)
tm.Start()
time.sleep(0.1)
tm.Stop() # prints: "Inline timing: 0.10 s"
Manual control over Start() and Stop() for precise measurement of custom intervals.
Key points
- Label: required, shown in output; empty labels raise
InputError - Output:
emit_log=True→logging.info()(default)emit_print=True→ directprint()- Both can be enabled
- Format: elapsed time is shown using
HumanizedSeconds() - Safety:
- Cannot start an already started timer
- Cannot stop an unstarted or already stopped timer
(raises
Error)
Serialization Pipeline
These helpers turn arbitrary Python objects into compressed and/or encrypted binary blobs, and back again — with detailed timing and size logging.
from transcrypto import base
Serialize
data = {'x': 42, 'y': 'hello'}
# Basic serialization
blob = base.Serialize(data)
# With compression and encryption
blob = base.Serialize(
data,
compress=9, # compression level (-22..22, default=3)
key=my_symmetric_key # must implement SymmetricCrypto
)
# Save directly to file
base.Serialize(data, file_path='/tmp/data.blob')
Serialization path:
obj → pickle → (compress) → (encrypt) → (save)
At each stage:
- Data size is measured using
HumanizedBytes - Duration is timed with
Timer - Results are logged once at the end
Compression levels:
compress uses zstandard; see table below for speed/ratio trade-offs:
| Level | Speed | Compression ratio | Typical use case |
|---|---|---|---|
| -5 to -1 | Fastest | Poor (better than no compression) | Real-time or very latency-sensitive |
| 0…3 | Very fast | Good ratio | Default CLI choice, safe baseline |
| 4…6 | Moderate | Better ratio | Good compromise for general persistence |
| 7…10 | Slower | Marginally better ratio | Only if storage space is precious |
| 11…15 | Much slower | Slight gains | Large archives, not for runtime use |
| 16…22 | Very slow | Tiny gains | Archival-only, multi-GB datasets |
Errors: invalid compression level is clamped to range; other input errors raise InputError.
DeSerialize
# From in-memory blob
obj = base.DeSerialize(data=blob)
# From file
obj = base.DeSerialize(file_path='/tmp/data.blob')
# With decryption
obj = base.DeSerialize(data=blob, key=my_symmetric_key)
Deserialization path:
data/file → (decrypt) → (decompress if Zstd) → unpickle
- Compression is auto-detected via Zstandard magic numbers.
- All steps are timed/logged like in
Serialize.
Constraints & errors:
- Exactly one of
dataorfile_pathmust be provided. file_pathmust exist;datamust be at least 4 bytes.- Wrong key or corrupted data can raise
CryptoError.
Cryptographically Secure Randomness
These helpers live in base and wrap Python’s secrets with additional checks and guarantees for crypto use-cases.
from transcrypto import base
Fixed-size random integers
# Generate a 256-bit integer (first bit always set)
r = base.RandBits(256)
assert r.bit_length() == 256
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.
- errors:
n_bits < 8→InputError
Uniform random integers in a range
# Uniform between [10, 20] inclusive
n = base.RandInt(10, 20)
assert 10 <= n <= 20
Returns a crypto-secure integer uniformly distributed over the closed interval [min_int, max_int].
- constraints:
min_int ≥ 0and< max_int - errors: invalid bounds →
InputError
In-place secure shuffle
deck = list(range(10))
base.RandShuffle(deck)
print(deck) # securely shuffled order
Performs an in-place Fisher–Yates shuffle using secrets.randbelow. Suitable for sensitive data ordering.
- constraints: sequence length ≥ 2
- errors: shorter sequences →
InputError
Random byte strings
# 32 random bytes
b = base.RandBytes(32)
assert len(b) == 32
Generates n_bytes of high-quality crypto-secure random data.
- constraints:
n_bytes ≥ 1 - errors: smaller values →
InputError
Computing the Greatest Common Divisor
>>> from transcrypto import base
>>> base.GCD(462, 1071)
21
>>> base.GCD(0, 17)
17
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:
>>> base.ExtendedGCD(462, 1071)
(21, -2, 1)
>>> 462 * -2 + 1071 * 1
21
Use-cases:
- modular inverses:
inv = x % mwhengcd(a, m) == 1 - solving linear Diophantine equations
- RSA / ECC key generation internals
Fast Modular Arithmetic
from transcrypto import modmath
m = 2**256 - 189 # a large prime modulus
# Inverse ──────────────────────────────
x = 123456789
x_inv = modmath.ModInv(x, m)
assert (x * x_inv) % m == 1
# Division (x / y) mod m ──────────────
y = 987654321
z = modmath.ModDiv(x, y, m) # solves z·y ≡ x (mod m)
assert (z * y) % m == x % m
# Exponentiation ──────────────────────
exp = modmath.ModExp(3, 10**20, m) # ≈ log₂(y) time, handles huge exponents
Chinese Remainder Theorem (CRT) – Pair
from transcrypto import modmath
# Solve:
# x ≡ 2 (mod 3)
# x ≡ 3 (mod 5)
x = modmath.CRTPair(2, 3, 3, 5)
print(x) # 8
assert x % 3 == 2
assert x % 5 == 3
Solves a system of two simultaneous congruences with pairwise co-prime moduli, returning the least non-negative solution x such that:
x ≡ a1 (mod m1)
x ≡ a2 (mod m2)
0 ≤ x < m1 * m2
- Requirements:
m1 ≥ 2,m2 ≥ 2,m1 != m2gcd(m1, m2) == 1(co-prime)
- Errors:
- invalid modulus values →
InputError - non co-prime moduli →
ModularDivideError
- invalid modulus values →
This function is a 2-modulus variant; for multiple moduli, apply it iteratively or use a general CRT solver.
Modular Polynomials & Lagrange Interpolation
# f(t) = 7t³ − 3t² + 2t + 5 (coefficients constant-term first)
coefficients = [5, 2, -3, 7]
print(modmath.ModPolynomial(11, coefficients, 97)) # → 19
# Given three points build the degree-≤2 polynomial and evaluate it.
pts = {2: 4, 5: 3, 7: 1}
print(modmath.ModLagrangeInterpolate(9, pts, 11)) # → 2
Primality testing & Prime generators, Mersenne primes
modmath.IsPrime(2**127 - 1) # True (Mersenne prime)
modmath.IsPrime(3825123056546413051) # False (strong pseudo-prime)
# Direct Miller–Rabin with custom witnesses
modmath.MillerRabinIsPrime(961748941, witnesses={2,7,61})
# Infinite iterator of primes ≥ 10⁶
for p in modmath.PrimeGenerator(1_000_000):
print(p)
if p > 1_000_100:
break
# Secure random 384-bit prime (for RSA/ECC experiments)
p384 = modmath.NBitRandomPrime(384)
for k, m_p, perfect in modmath.MersennePrimesGenerator(0):
print(f'p = {k:>8} M = {m_p} perfect = {perfect}')
if k > 10000: # stop after a few
break
Cryptographic Hashing
Simple, fixed-output-size wrappers over Python’s hashlib for common digest operations, plus file hashing.
from transcrypto import base
SHA-256 hashing
h = base.Hash256(b'hello world')
assert len(h) == 32 # bytes
print(h.hex()) # 64 hex chars
Computes the SHA-256 digest of a byte string, returning exactly 32 bytes (256 bits). Suitable for fingerprints, commitments, or internal crypto primitives.
SHA-512 hashing
h = base.Hash512(b'hello world')
assert len(h) == 64 # bytes
print(h.hex()) # 128 hex chars
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.
File hashing
# Default SHA-256
fh = base.FileHash('/path/to/file')
print(fh.hex())
# SHA-512
fh2 = base.FileHash('/path/to/file', digest='sha512')
Hashes a file from disk in streaming mode. By default uses SHA-256; digest='sha512' switches to SHA-512.
- constraints:
digestmust be'sha256'or'sha512'full_pathmust exist
- errors: invalid digest or missing file →
InputError
Symmetric Encryption Interface
SymmetricCrypto is an abstract base class that defines the byte-in / byte-out contract for symmetric ciphers.
- Metadata handling — if the algorithm uses a
nonceortag, the implementation must handle it internally (e.g., append it to ciphertext). - AEAD modes — if supported,
associated_datamust be authenticated; otherwise, a non-Nonevalue should raiseInputError.
class MyAES(base.SymmetricCrypto):
def Encrypt(self, plaintext: bytes, *, associated_data=None) -> bytes:
...
def Decrypt(self, ciphertext: bytes, *, associated_data=None) -> bytes:
...
Crypto Objects General Properties (CryptoKey)
Cryptographic objects all derive from the CryptoKey class and will all have some important characteristics:
- Will be safe to log and print, i.e., implement safe
__str__()and__repr__()methods (in actualityreprwill be exactly the same asstr). 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…). - It will have a
_DebugDump()method that does print secrets and can be used for debugging only. - Can be easily serialized to
bytesby theblobproperty and to base-64 encodedstrby theencodedproperty. - Can be serialized encrypted to
bytesby theBlob(key=[SymmetricCrypto])method and to encrypted base-64 encodedstrby theEncoded(key=[SymmetricCrypto])method. - Can be instantiated back as an object from
strorbytesusing theLoad(data, key=[SymmetricCrypto] | None)method. TheLoad()will decide how to build the object and will work universally with all the serialization options discussed above.
Example:
from transcrypto import base, rsa, aes
priv = rsa.RSAPrivateKey.New(512) # small key, but good for this example
print(str(priv)) # safe, no secrets
# ▶ RSAPrivateKey(RSAPublicKey(public_modulus=pQaoxy-QeXSds1k9WsGjJw==, encrypt_exp=AQAB), modulus_p=f18141aa…, modulus_q=67494eb9…, decrypt_exp=c96db24a…)
print(priv._DebugDump()) # UNSAFE: prints secrets
# ▶ 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)
print(priv.blob)
# ▶ 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."
print(priv.encoded)
# ▶ KLUv_WBwAIELAIAElWUBAAAAAAAAjA90cmFuc2NyeXB0by5yc2GUjA1SU0FQcml2YXRlS2V5lJOUKYGUXZQoikHf1EvsmZedAZve7TrLmobLAwuRIr_77TLG6G_0fsLGThERVJu075be8PLjUQYnLXcacZFQ5Fb1Iy1WtiE985euAEoBAAEAiiFR9ngiXMzkf41o5CRBY3h0D4DJVisDDhLmAWsiaHggzQCKIS_cmQ6MKXCtROtC7c_Mrsi9A-9NM8DksaHaRwvy6uTZAIpB4TVbsLxc41TEc19wIzpxbi9y5dW5gdfTkRQSSiz0ijmb8Xk3pyBfKAv8JbHp8Yv48gNZUfX67qq0J7yhJqeUoACKIbFb2kTNRzSqm3JRtjc2BPS-FnLFdadlFcV4-6IW7eqLAIogFZfzDN39gZLR9uTz4KHSTaqxWrJgP8-YYssjss6FlFKKIIItgCDv7ompNpY8gBs5bibN8XTsr-JOYSntDVT5Fe5vZWIu
key = aes.AESKey(key256=b'x' * 32)
print(key)
# ▶ AESKey(key256=86a86df7…)
encrypted = priv.Blob(key=key)
print(priv == rsa.RSAPrivateKey.Load(encrypted, key=key))
# ▶ True
AES-256 Symmetric Encryption
Implements AES-256 in GCM mode for authenticated encryption and decryption, plus an ECB mode helper for fixed-size block encoding. Also includes a high-iteration PBKDF2-based key derivation from static passwords.
Key creation
from transcrypto import aes
# From raw bytes (must be exactly 32 bytes)
key = aes.AESKey(key256=b'\x00' * 32)
# From a static password (slow, high-iteration PBKDF2-SHA256)
key = aes.AESKey.FromStaticPassword('correct horse battery staple')
print(key.encoded) # URL-safe Base64
- Length:
key256must be exactly 32 bytes FromStaticPassword():- Uses PBKDF2-HMAC-SHA256 with fixed salt and ~2 million iterations
- Designed for interactive password entry, not for password databases
AES-256 + GCM (default)
data = b'secret message'
aad = b'metadata'
# Encrypt (returns IV + ciphertext + tag)
ct = key.Encrypt(data, associated_data=aad)
# Decrypt
pt = key.Decrypt(ct, associated_data=aad)
assert pt == data
- Security:
- Random 128-bit IV (
iv) per encryption - Authenticated tag (128-bit) ensures integrity
- Optional
associated_datais authenticated but not encrypted
- Random 128-bit IV (
- Errors:
- Tag mismatch or wrong key →
CryptoError
- Tag mismatch or wrong key →
AES-256 + ECB (unsafe, fixed block only)
# ECB mode is for 16-byte block encoding ONLY
ecb = key.ECBEncoder()
block = b'16-byte string!!'
ct_block = ecb.Encrypt(block)
pt_block = ecb.Decrypt(ct_block)
assert pt_block == block
# Hex helpers
hex_ct = ecb.EncryptHex('00112233445566778899aabbccddeeff')
- ECB mode:
- 16-byte plaintext ↔ 16-byte ciphertext
- No padding, no IV, no integrity — do not use for general encryption
associated_datanot supported
Key points:
- GCM mode is secure for general use; ECB mode is for special low-level operations
- Static password derivation is intentionally slow to resist brute force
- All sizes and parameters are validated with
InputErroron misuse
RSA (Rivest-Shamir-Adleman) Public Cryptography
https://en.wikipedia.org/wiki/RSA_cryptosystem
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.
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.
from transcrypto import rsa
# Generate a key pair
priv = rsa.RSAPrivateKey.New(2048) # 2048-bit modulus
pub = rsa.RSAPublicKey.Copy(priv) # public half
print(priv.public_modulus.bit_length()) # 2048
# Safe Encrypt & decrypt
msg = b'xyz'
cipher = pub.Encrypt(msg, associated_data=b'aad')
plain = priv.Decrypt(cipher, associated_data=b'aad')
assert plain == msg
# Safe Sign & verify
signature = priv.Sign(msg) # can also have associated_data, optionally
assert pub.Verify(msg, signature)
# Raw Encrypt & decrypt
msg = 123456789 # (Zero is forbidden by design; smallest valid message is 1.)
cipher = pub.RawEncrypt(msg)
plain = priv.RawDecrypt(cipher)
assert plain == msg
# Raw Sign & verify
signature = priv.RawSign(msg)
assert pub.RawVerify(msg, signature)
# Blind signatures (obfuscation pair) - only works on raw RSA
pair = rsa.RSAObfuscationPair.New(pub)
blind_msg = pair.ObfuscateMessage(msg) # what you send to signer
blind_sig = priv.RawSign(blind_msg) # signer’s output
sig = pair.RevealOriginalSignature(msg, blind_sig)
assert pub.RawVerify(msg, sig)
El-Gamal Public-Key Cryptography
https://en.wikipedia.org/wiki/ElGamal_encryption
This is raw El-Gamal over a prime field — no padding, no hashing — and is not DSA. For real-world deployments, use a high-level library with authenticated encryption and proper encoding.
from transcrypto import elgamal
# Shared parameters (prime modulus, group base) for a group
shared = elgamal.ElGamalSharedPublicKey.New(256)
print(shared.prime_modulus)
print(shared.group_base)
# Public key from private
priv = elgamal.ElGamalPrivateKey.New(shared)
pub = elgamal.ElGamalPublicKey.Copy(priv)
# Safe Encrypt & decrypt
msg = b'xyz'
cipher = pub.Encrypt(msg, associated_data=b'aad')
plain = priv.Decrypt(cipher, associated_data=b'aad')
assert plain == msg
# Safe Sign & verify
signature = priv.Sign(msg) # can also have associated_data, optionally
assert pub.Verify(msg, signature)
# Raw Encryption
msg = 42
cipher = pub.RawEncrypt(msg)
plain = priv.RawDecrypt(cipher)
assert plain == msg
# Raw Signature verify
sig = priv.RawSign(msg)
assert pub.RawVerify(msg, sig)
Key points:
- Security parameters:
- Recommended
prime_modulusbit length ≥ 2048 for real security - Random values from
base.RandBits
- Recommended
- Ephemeral keys:
- Fresh per encryption/signature
- Must satisfy
gcd(k, p-1) == 1
- Errors:
- Bad ranges →
InputError - Invalid math relationships →
CryptoError
- Bad ranges →
- Group sharing:
- Multiple parties can share
(p, g)but have different(individual_base, decrypt_exp)
- Multiple parties can share
DSA (Digital Signature Algorithm)
https://en.wikipedia.org/wiki/Digital_Signature_Algorithm
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.
from transcrypto import dsa
# Shared parameters (p, q, g)
shared = dsa.DSASharedPublicKey.New(p_bits=1024, q_bits=160)
print(shared.prime_modulus) # p
print(shared.prime_seed) # q (q | p-1)
print(shared.group_base) # g
# Individual key pair
priv = dsa.DSAPrivateKey.New(shared)
pub = dsa.DSAPublicKey.Copy(priv)
# Safe Sign & verify
msg = b'xyz'
signature = priv.Sign(msg) # can also have associated_data, optionally
assert pub.Verify(msg, signature)
# Raw Sign & verify (message must be 1 ≤ m < q)
msg = 123456789 % shared.prime_seed
sig = priv.RawSign(msg)
assert pub.RawVerify(msg, sig)
- ranges:
1 ≤ message < q- signatures:
(s1, s2)with2 ≤ s1, s2 < q
- errors:
- invalid ranges →
InputError - inconsistent parameters →
CryptoError
- invalid ranges →
Security notes
- Choose large parameters (e.g.,
p ≥ 2048 bits,q ≥ 224 bits) for non-toy settings. - In practice, compute
m = int.from_bytes(Hash(message), 'big') % qbefore callingSign(m).
Advanced: custom primes generator
# Generate primes (p, q) with q | (p-1); also returns m = (p-1)//q
p, q, m = dsa.NBitRandomDSAPrimes(p_bits=1024, q_bits=160)
assert (p - 1) % q == 0
Used internally by DSASharedPublicKey.New().
Search breadth and retry caps are bounded; repeated failures raise CryptoError.
Public Bidding
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.
from transcrypto import base
# Generate the private and public bids
bid_priv = base.PrivateBid512.New(secret) # this one you keep private
bid_pub = base.PublicBid512.Copy(bid_priv) # this one you publish
# Checking that a bid is genuine requires the public bid and knowing the nonce and the secret:
print(bid_pub.VerifyBid(private_key, secret_bid)) # these come from a divulged private bid
# of course, you want to also make sure the provided private data matches your version of it, e.g.:
bid_pub_expected = base.PublicBid512.Copy(bid_priv)
print(bid_pub == bid_pub_expected)
SSS (Shamir Shared Secret)
https://en.wikipedia.org/wiki/Shamir's_secret_sharing
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.
from transcrypto import sss
# Generate parameters: at least 3 of 5 shares needed,
# coefficients & modulus are 128-bit primes
priv = sss.ShamirSharedSecretPrivate.New(minimum_shares=3, bit_length=128)
pub = sss.ShamirSharedSecretPublic.Copy(priv) # what you publish
print(f'threshold : {pub.minimum}')
print(f'prime mod : {pub.modulus}')
print(f'poly coefficients: {priv.polynomial}') # keep these private!
# Safe Issuing shares
secret = b'xyz'
# Generate 5 shares, each has a copy of the encrypted secret
five_shares = priv.MakeDataShares(secret, 5)
for sh in five_shares:
print(sh)
# Raw Issuing shares
secret = 0xC0FFEE
# Generate an unlimited stream; here we take 5
five_shares = list(priv.RawShares(secret, max_shares=5))
for sh in five_shares:
print(f'share {sh.share_key} → {sh.share_value}')
A single share object looks like sss.ShamirSharePrivate(minimum=3, modulus=..., share_key=42, share_value=123456789).
# Safe Re-constructing the secret
secret = b'xyz'
five_shares = priv.MakeDataShares(secret, 5)
subset = five_shares[:3] # any 3 distinct shares
recovered = subset[0].RecoverData(subset) # each share has the encrypted data, so you ask it to join with the others
assert recovered == secret
# Raw Re-constructing the secret
secret = 0xC0FFEE
five_shares = list(priv.RawShares(secret, max_shares=5))
subset = five_shares[:3] # any 3 distinct shares
recovered = pub.RawRecoverSecret(subset)
assert recovered == secret
If you supply fewer than minimum shares you get a CryptoError, unless you explicitly override:
try:
pub.RawRecoverSecret(five_shares[:2]) # raises
except Exception as e:
print(e) # "unrecoverable secret …"
# Force the interpolation even with 2 points (gives a wrong secret, of course)
print(pub.RawRecoverSecret(five_shares[:2], force_recover=True))
# Checking that a share is genuine
share = five_shares[0]
ok = priv.RawVerifyShare(secret, share) # ▶ True
tampered = sss.ShamirSharePrivate(
minimum=share.minimum,
modulus=share.modulus,
share_key=share.share_key,
share_value=(share.share_value + 1) % share.modulus)
print(priv.RawVerifyShare(secret, tampered)) # ▶ False
Appendix: Development Instructions
Setup
If you want to develop for this project, first install python 3.13 and Poetry, but to get the versions you will need, we suggest you do it like this (Linux):
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git python3 python3-pip pipx python3-dev python3-venv build-essential software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa # install arbitrary python version
sudo apt-get update
sudo apt-get install python3.13
sudo apt-get remove python3-poetry
python3.13 -m pipx ensurepath
# re-open terminal
pipx install poetry
poetry --version # should be >=2.1
poetry config virtualenvs.in-project true # creates .venv inside project directory
poetry config pypi-token.pypi <TOKEN> # add your personal PyPI project token, if any
or this (Mac):
brew update
brew upgrade
brew cleanup -s
brew install git python@3.13 # install arbitrary python version
brew uninstall poetry
python3.13 -m pip install --user pipx
python3.13 -m pipx ensurepath
# re-open terminal
pipx install poetry
poetry --version # should be >=2.1
poetry config virtualenvs.in-project true # creates .venv inside project directory
poetry config pypi-token.pypi <TOKEN> # add your personal PyPI project token, if any
Now install the project:
git clone https://github.com/balparda/transcrypto.git transcrypto
cd transcrypto
poetry env use python3.13 # creates the venv
poetry install --sync # HONOR the project's poetry.lock file, uninstalls stray packages
poetry env info # no-op: just to check
poetry run pytest -vvv
# or any command as:
poetry run <any-command>
To activate like a regular environment do:
poetry env activate
# will print activation command which you next execute, or you can do:
source .env/bin/activate # if .env is local to the project
source "$(poetry env info --path)/bin/activate" # for other paths
pytest # or other commands
deactivate
Updating Dependencies
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.
To add a new dependency you should do:
poetry add "pkg>=1.2.3" # regenerates lock, updates env (adds dep to prod code)
poetry add -G dev "pkg>=1.2.3" # adds dep to dev code ("group" dev)
# also remember: "pkg@^1.2.3" = latest 1.* ; "pkg@~1.2.3" = latest 1.2.* ; "pkg@1.2.3" exact
If you manually added a dependency to pyproject.toml you should very carefully recreate the environment and files:
rm -rf .venv .poetry poetry.lock
poetry env use python3.13
poetry install
Remember to check your diffs before submitting (especially poetry.lock) to avoid surprises!
When dependencies change, always regenerate requirements.txt by running:
poetry export --format requirements.txt --without-hashes --output requirements.txt
Creating a New Version
# bump the version!
poetry version minor # updates 1.6 to 1.7, for example
# or:
poetry version patch # updates 1.6 to 1.6.1
# or:
poetry version <version-number>
# (also updates `pyproject.toml` and `poetry.lock`)
# publish to GIT, including a TAG
git commit -a -m "release version 1.0.2"
git tag 1.0.2
git push
git push --tags
# prepare package for PyPI
poetry build
poetry publish
If you changed the CLI interface at all run:
poetry run transcrypto doc md > CLI.md
./tools/inject_md_includes.py
You can find the 10 top slowest tests by running:
poetry run pytest -vvv -q --durations=10
You can search for flaky tests by running all tests 100 times:
poetry run pytest --flake-finder --flake-runs=100
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file transcrypto-1.2.0.tar.gz.
File metadata
- Download URL: transcrypto-1.2.0.tar.gz
- Upload date:
- Size: 121.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.13.5 Darwin/24.6.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ff7b741707476deaac4390ead1ec0a729d7a490d9aece2871d3f1a4b1864d8d
|
|
| MD5 |
bb290d0570cc5b990a192fbbf7e1a6a6
|
|
| BLAKE2b-256 |
368f339a093db47fd71a0d937935bad2ac5eceba9bdc7004a4437f4b0e53f8c8
|
File details
Details for the file transcrypto-1.2.0-py3-none-any.whl.
File metadata
- Download URL: transcrypto-1.2.0-py3-none-any.whl
- Upload date:
- Size: 87.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.13.5 Darwin/24.6.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6647e4eeedc581e033b8e87253d1816a25bdfafc9b8381439aaa0e42f3307588
|
|
| MD5 |
812125d9ce874585f07947903ea76ee4
|
|
| BLAKE2b-256 |
9ae0c8e3b2d5b53e53fa67f6f70148ae4afe28f9d12543e0b3dd436b660d0dde
|