purepycrypto 3.2.0__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.
- purepycrypto-3.2.0/CHANGELOG.md +390 -0
- purepycrypto-3.2.0/LICENSE +21 -0
- purepycrypto-3.2.0/MANIFEST.in +11 -0
- purepycrypto-3.2.0/PKG-INFO +848 -0
- purepycrypto-3.2.0/README.md +804 -0
- purepycrypto-3.2.0/docs/api.md +1588 -0
- purepycrypto-3.2.0/docs/cli.md +454 -0
- purepycrypto-3.2.0/docs/errors.md +266 -0
- purepycrypto-3.2.0/docs/quickstart.md +466 -0
- purepycrypto-3.2.0/docs/security.md +227 -0
- purepycrypto-3.2.0/purepycrypto/__init__.py +389 -0
- purepycrypto-3.2.0/purepycrypto/__main__.py +20 -0
- purepycrypto-3.2.0/purepycrypto/_ppyc_error.py +330 -0
- purepycrypto-3.2.0/purepycrypto/_version.py +1 -0
- purepycrypto-3.2.0/purepycrypto/aes.py +869 -0
- purepycrypto-3.2.0/purepycrypto/aes_gcm_siv.py +644 -0
- purepycrypto-3.2.0/purepycrypto/chacha.py +349 -0
- purepycrypto-3.2.0/purepycrypto/cli.py +1177 -0
- purepycrypto-3.2.0/purepycrypto/cli_args.py +794 -0
- purepycrypto-3.2.0/purepycrypto/common.py +210 -0
- purepycrypto-3.2.0/purepycrypto/der.py +150 -0
- purepycrypto-3.2.0/purepycrypto/ed25519.py +634 -0
- purepycrypto-3.2.0/purepycrypto/encoding.py +922 -0
- purepycrypto-3.2.0/purepycrypto/examples/encrypt_file.py +84 -0
- purepycrypto-3.2.0/purepycrypto/examples/key_exchange.py +62 -0
- purepycrypto-3.2.0/purepycrypto/examples/parallel_usage.py +61 -0
- purepycrypto-3.2.0/purepycrypto/examples/sign_verify.py +57 -0
- purepycrypto-3.2.0/purepycrypto/hash.py +253 -0
- purepycrypto-3.2.0/purepycrypto/kdf.py +553 -0
- purepycrypto-3.2.0/purepycrypto/kdf2.py +1109 -0
- purepycrypto-3.2.0/purepycrypto/parallel.py +169 -0
- purepycrypto-3.2.0/purepycrypto/py.typed +0 -0
- purepycrypto-3.2.0/purepycrypto/rand.py +606 -0
- purepycrypto-3.2.0/purepycrypto/rsa.py +775 -0
- purepycrypto-3.2.0/purepycrypto/scripts/build_single.py +487 -0
- purepycrypto-3.2.0/purepycrypto/sha3.py +477 -0
- purepycrypto-3.2.0/purepycrypto/single/purepycrypto.py +9539 -0
- purepycrypto-3.2.0/purepycrypto/tests/__init__.py +0 -0
- purepycrypto-3.2.0/purepycrypto/tests/_vectors.py +13 -0
- purepycrypto-3.2.0/purepycrypto/tests/conftest.py +12 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_aes.py +219 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_chacha.py +76 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_cli.py +213 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_ed25519.py +121 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_encoding.py +334 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_encoding_verify.py +320 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_errors.py +175 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_errors_edge.py +371 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_gcm_siv.py +113 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_hash.py +74 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_kdf.py +124 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_kdf2.py +393 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_kdf2_verify.py +299 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_multiprocess.py +160 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_rand.py +339 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_rand_verify.py +293 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_rsa.py +125 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_sha3.py +78 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_vectors_strict.py +468 -0
- purepycrypto-3.2.0/purepycrypto/tests/test_x25519.py +68 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/aes_fips197.json +11 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/aes_gcm_nist.json +13 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/argon2id_rfc9106.json +25 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/blake2b.json +11 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/ed25519_rfc8032.json +28 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/hkdf_rfc5869.json +35 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/pbkdf2.json +12 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/poly1305.json +14 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/rfc8452_gcm_siv.json +439 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/scrypt.json +10 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/sha2.json +20 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/sha3_fips202.json +47 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/shake_fips202.json +47 -0
- purepycrypto-3.2.0/purepycrypto/tests/vectors/x25519_rfc7748.json +35 -0
- purepycrypto-3.2.0/purepycrypto/x25519.py +155 -0
- purepycrypto-3.2.0/purepycrypto.egg-info/PKG-INFO +848 -0
- purepycrypto-3.2.0/purepycrypto.egg-info/SOURCES.txt +83 -0
- purepycrypto-3.2.0/purepycrypto.egg-info/dependency_links.txt +1 -0
- purepycrypto-3.2.0/purepycrypto.egg-info/entry_points.txt +2 -0
- purepycrypto-3.2.0/purepycrypto.egg-info/not-zip-safe +1 -0
- purepycrypto-3.2.0/purepycrypto.egg-info/requires.txt +12 -0
- purepycrypto-3.2.0/purepycrypto.egg-info/top_level.txt +1 -0
- purepycrypto-3.2.0/pyproject.toml +86 -0
- purepycrypto-3.2.0/setup.cfg +4 -0
- purepycrypto-3.2.0/setup.py +154 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This file records all notable changes to `purepycrypto`.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
|
6
|
+
and the version numbers follow [Semantic Versioning](https://semver.org/lang/zh-CN/).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
### Changed — full English localization
|
|
13
|
+
|
|
14
|
+
- **Documentation, code comments and error messages are now entirely in English.**
|
|
15
|
+
This covers all modules under `purepycrypto/`, `docs/*.md`, `README.md`,
|
|
16
|
+
`CHANGELOG.md`, `setup.py`, `pyproject.toml`, the test suite and the examples.
|
|
17
|
+
No public API, identifier, error code or behavior was changed.
|
|
18
|
+
- The interactive TUI keeps its Chinese interface: the `cn` language pack and the
|
|
19
|
+
TUI menu text are intentionally left as-is and switch with the TUI language.
|
|
20
|
+
|
|
21
|
+
### Fixed — TUI error localization
|
|
22
|
+
|
|
23
|
+
- Errors surfaced inside the TUI are now localized at the display layer: the library
|
|
24
|
+
itself always reports English messages/suggestions, while the TUI maps a known
|
|
25
|
+
`PPYC_ERR_*` code back to Chinese when the TUI language is `cn`
|
|
26
|
+
(see `_TUI_ERR_TEXT` / `_tui_error_text()` in `cli.py`). Unknown codes fall back to
|
|
27
|
+
the original English text.
|
|
28
|
+
- `menu9` / `menu10` (Encoding/Decoding, Secure Random) were missing from the
|
|
29
|
+
language pack and rendered as raw key names; both are now proper i18n entries in
|
|
30
|
+
`en` and `cn`.
|
|
31
|
+
- The Encoding and Secure Random sub-menus were rewritten to use the i18n layer, so
|
|
32
|
+
they are now fully Chinese in `cn` mode and fully English in `en` mode
|
|
33
|
+
(previously they mixed both).
|
|
34
|
+
- `Ctrl+C` printed the literal `bye` because `_t('bye')` referenced a non-existent
|
|
35
|
+
key; it now uses `_t('goodbye')`.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## [3.2.0] - 2026-09-27
|
|
40
|
+
|
|
41
|
+
### Added — 3 new algorithm modules
|
|
42
|
+
|
|
43
|
+
#### 1. `purepycrypto.encoding` — encoding module
|
|
44
|
+
|
|
45
|
+
Hand-written bitwise implementation (does not call the `base64` library), **byte-for-byte identical** to the standard library:
|
|
46
|
+
|
|
47
|
+
- **Base64** (RFC 4648 §4): `b64encode/b64decode`, `b64encode_urlsafe/b64decode_urlsafe` (URL-safe), `b64encode_nopad/b64decode_nopad` (no padding)
|
|
48
|
+
- **Base32** (RFC 4648 §6/§7): `b32encode/b32decode` (standard A-Z2-7), `b32encode_hex/b32decode_hex` (Extended Hex 0-9A-V)
|
|
49
|
+
- **Base16/Hex** (RFC 4648 §8): `hex_encode/hex_decode`, `hex_encode_sep/hex_decode_sep` (with separators, e.g. `de:ad:be:ef`)
|
|
50
|
+
- **Base58** (Bitcoin alphabet): `b58encode/b58decode`
|
|
51
|
+
- **Big integer ↔ Base64URL**: `b64_encode_bigint/b64_decode_bigint` (JWK `n`/`e` style)
|
|
52
|
+
- Strict validation: invalid character/length/padding → returns a unified error tuple (`PPYC_ERR_INVALID_ENCODING` / `_LENGTH` / `_HEX`)
|
|
53
|
+
|
|
54
|
+
Verification: byte-for-byte identical to the stdlib across multiple lengths × multiple random rounds; all RFC 4648 §10 vectors match exactly; zero differences over 400 fuzz rounds.
|
|
55
|
+
|
|
56
|
+
#### 2. `purepycrypto.rand` — cryptographically secure random numbers (CSPRNG)
|
|
57
|
+
|
|
58
|
+
**Uses only the OS CSPRNG** (`os.urandom` / `secrets`); the `random` module is explicitly forbidden:
|
|
59
|
+
|
|
60
|
+
- **Basic randomness**: `random_bytes(n)`, `random_int(a,b)`, `random_below(n)`, `random_bit()`, `random_bits(k)`
|
|
61
|
+
— all use **rejection sampling**, with no modulo bias
|
|
62
|
+
- **Tokens / strings**: `token_bytes`, `token_hex`, `token_urlsafe`, `random_string(length, alphabet)`
|
|
63
|
+
- **Password generation**: `random_password(length, upper, lower, digits, special, exclude)` — guarantees at least one character of each class
|
|
64
|
+
- **Uniqueness**: `random_uuid4()` (RFC 4122 v4), `random_choice`, `random_sample`
|
|
65
|
+
- Entropy source unavailable → fatal `PPYC_ERR_ENV` (never downgrades to an insecure entropy source)
|
|
66
|
+
|
|
67
|
+
Verification: chi-square uniformity test (`random_int(0,9)` χ²=6.58 < upper bound 34.5; `random_below(256)` χ²=295.9 < 390.5); 1000 uuid4/token values with no duplicates.
|
|
68
|
+
|
|
69
|
+
#### 3. `purepycrypto.kdf2` — hardened key derivation
|
|
70
|
+
|
|
71
|
+
- **PBKDF2** (RFC 8018): `pbkdf2(password, salt, iterations, dklen, hash_name)`, supporting sha1/sha256/sha384/sha512
|
|
72
|
+
- strict salt-length check (<8 bytes → `PPYC_ERR_INVALID_SALT`; `min_salt_len` can relax it for compatibility with legacy systems)
|
|
73
|
+
- **Argon2** (RFC 9106): `argon2id_hash` / `argon2i_hash` / `argon2d_hash` (with sensible defaults t=3/m=65536/p=4)
|
|
74
|
+
- `argon2id_hash_encoded()` outputs a standard **PHC string**: `$argon2id$v=19$m=...,t=...,p=...$<salt>$<hash>`
|
|
75
|
+
- `argon2id_verify()` constant-time comparison
|
|
76
|
+
- **scrypt convenience wrapper**: `scrypt_simple(password, salt, n, r, p)` (recommended parameters)
|
|
77
|
+
|
|
78
|
+
Verification: byte-for-byte identical to `hashlib.pbkdf2_hmac`; RFC 9106 §5 official vectors; the PHC format interoperates with argon2-cffi.
|
|
79
|
+
|
|
80
|
+
### Changed
|
|
81
|
+
|
|
82
|
+
- **`__init__.py`**: exports the public API of the three new modules (`_HAS_KDF2` / `_HAS_ENCODING` / `_HAS_RAND` capability flags)
|
|
83
|
+
- **New CLI subcommands**:
|
|
84
|
+
- `purepycrypto encode --format base64|base64url|base32|hex|base58 --op enc|dec`
|
|
85
|
+
- `purepycrypto random --kind bytes|token|urlsafe|password|uuid`
|
|
86
|
+
- **New TUI menu items**: `[9] Encoding` / `[10] Random` (bilingual CN/EN)
|
|
87
|
+
- **`build_single.py`**: includes `encoding` / `rand` / `kdf2` in the single-file merge; adds single-file alias guidance
|
|
88
|
+
|
|
89
|
+
### Verification
|
|
90
|
+
|
|
91
|
+
- New tests: `test_encoding.py` (44 cases), `test_rand.py` (43 cases), `test_kdf2.py`
|
|
92
|
+
- All three modules pass standard vectors + cross-verification against the stdlib/authoritative implementations
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## [3.1.4] - 2026-09-27
|
|
97
|
+
|
|
98
|
+
### Added
|
|
99
|
+
|
|
100
|
+
#### Unified error system (`purepycrypto/_ppyc_error.py`)
|
|
101
|
+
|
|
102
|
+
Library-wide error handling is fully unified into two categories:
|
|
103
|
+
|
|
104
|
+
- **Fatal error → raise `PPYC_ERR`**: scenarios where an internal invariant is broken and safe execution cannot continue.
|
|
105
|
+
Carries the three attributes `code` / `message` / `suggestion`.
|
|
106
|
+
- **Non-fatal error → return a 3-tuple** `(error_code, error_message, suggestion)`:
|
|
107
|
+
expected scenarios such as invalid input, failed validation, authentication failure, parse failure.
|
|
108
|
+
On success it returns the actual value (or `OK_TUPLE` = `(None,None,None)` for validation-style APIs).
|
|
109
|
+
|
|
110
|
+
What's new:
|
|
111
|
+
|
|
112
|
+
- Exception class `PPYC_ERR` (and alias `PPYCError`), with `as_tuple()` support.
|
|
113
|
+
- Helper functions: `err()` / `ok()` / `is_ok()` / `is_err()` / `raise_ppyc()` / `OK_TUPLE` / `PPYCResult`.
|
|
114
|
+
- **41 standard error codes**, unified prefix `PPYC_ERR_`, covering:
|
|
115
|
+
general / arguments / key-nonce-IV / authentication-decryption / encoding-parsing / file IO / environment dependencies / algorithm parameters / CLI-TUI — nine major categories.
|
|
116
|
+
- Enforced error-code prefix (`err()` rejects any prefix other than `PPYC_ERR_`).
|
|
117
|
+
- The legacy exception names `CryptoError` / `DecryptionError` / `Ed25519Error` are all kept as subclasses of `PPYC_ERR`,
|
|
118
|
+
carrying default error codes, ensuring backward compatibility.
|
|
119
|
+
- New documentation [`docs/errors.md`](docs/errors.md) (error-system manual: design principles / API / complete error-code table / real examples).
|
|
120
|
+
- New test `purepycrypto/tests/test_errors.py` (23 cases).
|
|
121
|
+
|
|
122
|
+
### Changed (⚠️ Breaking)
|
|
123
|
+
|
|
124
|
+
- **`raise ValueError` / `raise SystemExit` in all modules have been converted** to the unified system:
|
|
125
|
+
- **Public-API parameter validation / authentication failure / decryption failure → return a tuple**
|
|
126
|
+
(e.g. `AES.gcm_decrypt`, `rsa_oaep_decrypt`, `chacha20poly1305_decrypt`,
|
|
127
|
+
`blake2b` (invalid digest_size), `shake128/256` (invalid outlen), `sha3_batch` (invalid algorithm name), etc.)
|
|
128
|
+
- **Constructors / internal helpers → raise `PPYC_ERR`**
|
|
129
|
+
(e.g. `AES(key)` key length, `RSAPrivateKey(...)` key material, `choose_hash`, `oaep_encode`, etc.)
|
|
130
|
+
- **CLI**: `SystemExit` is fully replaced by `PPYC_ERR`; `_cli_main` catches them uniformly and maps exit codes:
|
|
131
|
+
`0`=success / `2`=`PPYC_ERR` / `3`=file not found / `4`=argument error.
|
|
132
|
+
- **TUI**: pipe/redirect input end (EOF) → raises `PPYC_ERR_EOF`, caught by `_tui_main`,
|
|
133
|
+
which prints a unified error message (including a suggestion) and returns exit code 2, no longer raising a bare `EOFError`.
|
|
134
|
+
- **Single-file packaging**: `_ppyc_error` is included in the merge (prioritized over other modules); the version number is now **read dynamically** from `_version.py`.
|
|
135
|
+
|
|
136
|
+
### Fixed
|
|
137
|
+
|
|
138
|
+
**6 real defects newly found by the v3.1.4 deep audit** (all captured by the new boundary tests and audit scripts):
|
|
139
|
+
|
|
140
|
+
1. **`sha3.py` hex wrapper crash**: `shake128_hex/256_hex/sha3_*_hex` called `.hex()` on an error tuple
|
|
141
|
+
returned for invalid parameters → `AttributeError`. A unified `_to_hex()` handler was added.
|
|
142
|
+
2. **CLI `_write_binary()` crash**: commands such as KDF/AES/RSA called `.hex()` directly when the
|
|
143
|
+
underlying layer returned an error tuple → `AttributeError`. Now intercepted uniformly at the I/O layer and converted to `PPYC_ERR`.
|
|
144
|
+
3. **CLI `x25519` wrong exit code**: it printed an error for a wrong private-key length but returned code 0. Now it raises
|
|
145
|
+
`PPYC_ERR` → exit code 2.
|
|
146
|
+
4. **TUI `_hash_menu`/`_kdf_menu` crash**: with invalid parameters such as `blake2b(digest_size=0)` or `scrypt(N=15)`,
|
|
147
|
+
the TUI raised a bare `AttributeError`. A unified `_raise_if_err()` handler was added.
|
|
148
|
+
5. **TUI `x25519`/`rsa` unpacking crash**: unpacks such as `shared, zero = x25519_shared(...)` received an error tuple
|
|
149
|
+
for invalid parameters → `ValueError: too many values to unpack`. Protection was added.
|
|
150
|
+
6. **TUI self-test failure**: the XChaCha tamper detection in `_self_test()` still expected `DecryptionError` to be raised,
|
|
151
|
+
but the new system returns a tuple → the self-test falsely reported "tamper detection not effective". Changed to a tuple assertion.
|
|
152
|
+
|
|
153
|
+
- Fixed an issue in `rsa.py` where internal helpers had been mistakenly changed to return tuples, causing caller unpacking failures
|
|
154
|
+
(`choose_hash` / `mgf1` / `oaep_encode` / `oaep_decode` / `pss_encode` / `mod_inverse` / `_jacobi`
|
|
155
|
+
reverted to raising `PPYC_ERR`, with the public API responsible for converting to tuples).
|
|
156
|
+
- Fixed `__init__.py` not actually exporting the error-code constants, which made `from purepycrypto import PPYC_ERR_xxx` fail.
|
|
157
|
+
- Fixed `ALL_ERROR_CODES` mistakenly counting the prefix constant `PPYC_ERR_PREFIX` in the error-code table.
|
|
158
|
+
- Fixed the single-file merge missing the `Union` import and the `_ppyc_error` module.
|
|
159
|
+
|
|
160
|
+
### Verification
|
|
161
|
+
|
|
162
|
+
- Full pytest suite: **126+ passed** (including the new `test_errors_edge.py` 69 cases + `test_vectors_strict.py` 57 cases)
|
|
163
|
+
- Deep audit: 0 remaining raises other than `PPYC_ERR`; 41 error codes with no redundancy and none missing
|
|
164
|
+
- CLI/TUI full-branch error scenarios: no `Traceback`, correct exit codes
|
|
165
|
+
- All three usage modes (library / CLI / TUI) verified in practice
|
|
166
|
+
- The single-file bundle `purepycrypto/single/purepycrypto.py` verified in practice (version 3.1.4)
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## [2.7.10] - 2026-09-27
|
|
171
|
+
|
|
172
|
+
> **Version numbering rule**: `v{major}.{feature upgrades}.{bug fixes}`
|
|
173
|
+
> In this release the major version rises to **2** (major architecture refactor), with **7 feature upgrades** + **10 bug fixes**.
|
|
174
|
+
|
|
175
|
+
### ⚠️ Breaking Changes
|
|
176
|
+
|
|
177
|
+
- **Command unification**: removed the `purepycrypto-args` command and switched to a **single command** `purepycrypto`.
|
|
178
|
+
- `purepycrypto` (no arguments) → launch the interactive TUI
|
|
179
|
+
- `purepycrypto <subcommand> ...` (with arguments) → command-line mode
|
|
180
|
+
- **Entry-behavior change**: `purepycrypto:main` now dispatches automatically based on whether arguments are present (the old form
|
|
181
|
+
`python -m purepycrypto cli ...` is still compatible, but using arguments directly is recommended).
|
|
182
|
+
- **Single-file artifact location change**: moved from the project root into the package at `purepycrypto/single/purepycrypto.py`;
|
|
183
|
+
the development-directory root no longer generates `purepycrypto_tui.py` / `purepycrypto_cli.py` / `purepycrypto_lib.py`.
|
|
184
|
+
|
|
185
|
+
### Added (7 feature upgrades)
|
|
186
|
+
|
|
187
|
+
1. **TUI CN/EN language switch (CN / EN, default EN)**
|
|
188
|
+
- A "Switch Language" item was added to the top-level menu; it takes effect immediately after switching
|
|
189
|
+
- Supports the environment variable `PUREPYCRYPTO_LANG=en|cn` to override the default language
|
|
190
|
+
- New `set_language()` / `get_language()` API
|
|
191
|
+
2. **`sha3_batch(items, algo, n_workers)` — batch parallel hashing**
|
|
192
|
+
- Multiprocessing parallelism across multiple independent messages (the SHA-3 sponge cannot split a single long message across blocks)
|
|
193
|
+
- `n_workers=None` auto-detects the CPU count; small batches automatically degenerate to serial
|
|
194
|
+
3. **AES-GCM-SIV cache switch**: `set_cache_enabled(bool)` / `cache_enabled()` / `clear_caches()`
|
|
195
|
+
- enabled by default (performance first); can be disabled if the threat model disallows derived keys residing in memory
|
|
196
|
+
4. **AES-GCM-SIV multiprocessing parameter**: `n_workers=None` (auto-optimal) / `1` (force serial)
|
|
197
|
+
5. **Single-command architecture**: one `purepycrypto` command provides both the TUI and the CLI
|
|
198
|
+
6. **Single-file bundle**: `build_single.py --mode one` generates `purepycrypto/single/purepycrypto.py`
|
|
199
|
+
(likewise: no arguments = TUI, arguments = command line)
|
|
200
|
+
7. **Performance optimization** (alternating measurement in the same process, minimum over multiple rounds)
|
|
201
|
+
- SHA-3: `keccak_f1600` 1410 → **191 µs/perm** (**7.4x**, SWAR packed integers)
|
|
202
|
+
`sha3_256` 425 → **838 KB/s** (1.97x); `hmac_sha3_256` 277 → 628 KB/s (2.27x)
|
|
203
|
+
- AES-GCM-SIV: large message auto-multiprocessing 146 → **1101 KB/s** (**7.5x**)
|
|
204
|
+
32B small message 1693 → **198 µs** (**8.5x**, POLYVAL table cache + derived-key cache)
|
|
205
|
+
- Ed25519: `sign` 3.52 → **1.79 ms**, `verify` 3.89 → **1.95 ms** (**2.0x** each)
|
|
206
|
+
|
|
207
|
+
### Fixed (10 bug fixes)
|
|
208
|
+
|
|
209
|
+
1. **BLAKE2b**: wrong digest when the input length is an integer multiple of 128 bytes (incorrect handling of the final block's `f` flag)
|
|
210
|
+
2. **Single-file constant conflict**: `aes_gcm_siv`'s `NONCE_LEN` overrode the same-named constant in `chacha`, breaking XChaCha
|
|
211
|
+
3. **Single-file entry conflict**: the `if __name__ == "__main__"` blocks bundled in each module fired first, causing the CLI build to enter the TUI by mistake
|
|
212
|
+
4. **AES-GCM-SIV unified entry**: `aes_gcm_siv_encrypt/decrypt` were missing the `n_workers` parameter (NameError)
|
|
213
|
+
5. **`sha3_batch` multiprocessing result ordering**: round-robin sharding caused the output to not correspond to the input (changed to contiguous sharding)
|
|
214
|
+
6. **`sha3_batch` Windows spawn crash**: child-process re-entry errored when the `__main__` guard was missing (added a fallback that degenerates to serial)
|
|
215
|
+
7. **CLI / TUI crash on GBK consoles**: `UnicodeEncodeError` when printing characters such as `✓` (added console-encoding compatibility)
|
|
216
|
+
8. **`build_single` mistakenly deleted the `__main__` example inside a docstring**: changed to match only top-level indentation
|
|
217
|
+
9. **`build_single` deleted the `try/except` fallback import block incompletely**: changed to delete the whole block
|
|
218
|
+
10. **Single-file entry `_sys` undefined**: the `--mode one` artifact crashed with `NameError` on startup
|
|
219
|
+
|
|
220
|
+
### Changed
|
|
221
|
+
|
|
222
|
+
- **Docs**: README / docs (api, cli, quickstart, security, verification) all updated,
|
|
223
|
+
clearly stating that **Windows multiprocessing must use the `if __name__ == "__main__":` guard** (with correct/incorrect patterns and workarounds)
|
|
224
|
+
- **New example**: `purepycrypto/examples/parallel_usage.py` demonstrates correct multiprocessing usage
|
|
225
|
+
- **pyproject.toml / setup.py**: clarified the CLI/TUI installation logic (single console script) and added the `purepycrypto.single` package
|
|
226
|
+
|
|
227
|
+
### Verification Conclusion
|
|
228
|
+
|
|
229
|
+
- Full pytest suite: **103 passed**
|
|
230
|
+
- Correctness: SHA-3 vs `hashlib` (110+ lengths × 3 algorithms), RFC 8452 (48/48), RFC 8032 (TEST 1-3) all pass
|
|
231
|
+
- All three usage modes verified in practice: `import purepycrypto` / `purepycrypto <subcommand>` / `purepycrypto` (TUI)
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## [1.1.0] - 2026-09-26
|
|
236
|
+
|
|
237
|
+
v1.1.0 adds, on top of v1.0.0, the **SHA-3/Keccak hash family**, **Ed25519 signatures**, and
|
|
238
|
+
**AES-GCM-SIV (nonce-misuse resistant AEAD)**, and upgrades the command line into three single-file artifacts: **TUI / CLI / pure library**.
|
|
239
|
+
|
|
240
|
+
### Added
|
|
241
|
+
|
|
242
|
+
#### SHA-3 / Keccak (`purepycrypto.sha3`, FIPS 202)
|
|
243
|
+
|
|
244
|
+
- `sha3_224(data)` / `sha3_256(data)` / `sha3_384(data)` / `sha3_512(data)` — SHA-3 fixed-length digests, outputting 28 / 32 / 48 / 64 bytes respectively.
|
|
245
|
+
- `shake128(data, outlen)` / `shake256(data, outlen)` — SHAKE XOF extendable output, returning an arbitrary `outlen` bytes.
|
|
246
|
+
- `hmac_sha3_256(key, message)` / `hmac_sha3_512(key, message)` — HMAC-SHA3, outputting 32 / 64 bytes (the block size is the variant's rate `r`, consistent with OpenSSL/hashlib).
|
|
247
|
+
- Convenient hex interfaces: `sha3_224_hex` / `sha3_256_hex` / `sha3_384_hex` / `sha3_512_hex` / `shake128_hex` / `shake256_hex`.
|
|
248
|
+
- Low-level: `keccak_f1600(state)` (24-round Keccak-f[1600]), sponge absorb/squeeze, pad10*1 padding.
|
|
249
|
+
|
|
250
|
+
#### Ed25519 (`purepycrypto.ed25519`, RFC 8032)
|
|
251
|
+
|
|
252
|
+
- `ed25519_keygen() -> (seed32, pub32)` — generates an Ed25519 key pair (32-byte seed + 32-byte public key).
|
|
253
|
+
- `ed25519_publickey(seed32) -> bytes` — derives the 32-byte public key from a 32-byte seed.
|
|
254
|
+
- `ed25519_sign(message, seed32) -> bytes` — generates a 64-byte signature (`R || S`).
|
|
255
|
+
- `ed25519_verify(signature64, message, pub32) -> bool` — verifies; invalid input or failed verification always returns `False` (no exception).
|
|
256
|
+
- Helper interfaces: `ed25519_scalarmult_base(scalar)`, `ed25519_is_valid_publickey(pub32)`, exception `Ed25519Error`.
|
|
257
|
+
- Implementation highlights: extended homogeneous coordinates, constant-time masked-lookup 4-bit window scalar multiplication, strict point-encoding rejection rules (y ≥ p, non-square, x=0 sign-bit anomaly).
|
|
258
|
+
|
|
259
|
+
#### AES-GCM-SIV (`purepycrypto.aes_gcm_siv`, RFC 8452)
|
|
260
|
+
|
|
261
|
+
- `aes128_gcm_siv_encrypt(key, nonce, plaintext, aad=b"") -> (ct, tag)` and `aes128_gcm_siv_decrypt(key, nonce, ct, tag, aad=b"") -> bytes`.
|
|
262
|
+
- `aes256_gcm_siv_encrypt(...)` / `aes256_gcm_siv_decrypt(...)` — AES-256 same-shaped interface.
|
|
263
|
+
- `aes_gcm_siv_encrypt(key, nonce, plaintext, aad=b"")` / `aes_gcm_siv_decrypt(key, nonce, ct, tag, aad=b"")` — unified entry dispatched automatically by key length (16 / 32 bytes).
|
|
264
|
+
- Also provides the public `polyval(h, data)` and the constants `TAG_LEN` (16), `NONCE_LEN` (12).
|
|
265
|
+
|
|
266
|
+
#### Single-File Packaging (`purepycrypto/scripts/build_single.py`)
|
|
267
|
+
|
|
268
|
+
- Added three single-file artifacts: `purepycrypto_tui.py` (interactive TUI), `purepycrypto_cli.py` (command-line mode), `purepycrypto_lib.py` (pure library).
|
|
269
|
+
- Added the command-line arguments module `purepycrypto.cli_args`, providing the subcommands `hash` / `hmac` / `kdf` / `aes` / `chacha` / `x25519` / `rsa` / `rand` / `selftest` / `version`.
|
|
270
|
+
|
|
271
|
+
#### Package Layout Adjustment
|
|
272
|
+
|
|
273
|
+
- Moved the three directories `tests/`, `examples/`, `scripts/` into the `purepycrypto/` package, leaving only one top-level package directory in the source tree.
|
|
274
|
+
|
|
275
|
+
### Fixed
|
|
276
|
+
|
|
277
|
+
- Fixed the defect where **BLAKE2b produced a wrong result when the input length is an integer multiple of 128 bytes** (final-block length / counter boundary handling).
|
|
278
|
+
|
|
279
|
+
### Changed
|
|
280
|
+
|
|
281
|
+
- `build_single.py` supports `--mode tui|cli|lib|all`, generating the three single-file artifacts individually or all at once (`--all` generates tui + cli + lib together).
|
|
282
|
+
- The command-line mode is now provided by `purepycrypto.cli_args`; `python -m purepycrypto` still launches the interactive TUI.
|
|
283
|
+
- Version bumped from `1.0.0` to `1.1.0`.
|
|
284
|
+
|
|
285
|
+
### Notes
|
|
286
|
+
|
|
287
|
+
- The new modules are all self-tested against standard official vectors: SHA-3 / SHAKE (FIPS 202, cross-verified against `hashlib`), Ed25519 (RFC 8032 §7.1), AES-GCM-SIV (RFC 8452 appendix test vectors).
|
|
288
|
+
- The statement in v1.0.0 that "Ed25519/EdDSA is not included" is void as of v1.1.0: this release provides Ed25519. It still **does not include** any post-quantum (PQC) algorithm.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## [1.0.0] - 2026-09-26
|
|
293
|
+
|
|
294
|
+
The first official release. `purepycrypto` is a **zero-third-party-dependency pure-Python cryptography library**
|
|
295
|
+
covering hashing, key derivation, symmetric encryption, authenticated encryption, key exchange, and RSA public-key cryptography.
|
|
296
|
+
|
|
297
|
+
### Added
|
|
298
|
+
|
|
299
|
+
#### Project Skeleton
|
|
300
|
+
|
|
301
|
+
- Added the top-level package `purepycrypto`, with the public API exported uniformly by `purepycrypto/__init__.py`.
|
|
302
|
+
- Added modules: `common`, `hash`, `kdf`, `aes`, `chacha`, `x25519`, `rsa`, `der`, `parallel`, `cli`.
|
|
303
|
+
- Added package metadata: `__version__`, `__author__ = "Dvs(DvsXT)"`, `__license__ = "MIT"`, `__version_tuple__`.
|
|
304
|
+
|
|
305
|
+
#### Hashing (`purepycrypto.hash`)
|
|
306
|
+
|
|
307
|
+
- `sha256(message)` — SHA-256 (FIPS 180-4).
|
|
308
|
+
- `sha512(message)` — SHA-512 (FIPS 180-4).
|
|
309
|
+
- `blake2b(data, digest_size=64)` — BLAKE2b (RFC 7693), supporting 1–64 byte digests.
|
|
310
|
+
|
|
311
|
+
#### Key Derivation and Message Authentication (`purepycrypto.kdf`)
|
|
312
|
+
|
|
313
|
+
- `hmac_sha256(key, message)` — HMAC-SHA256 (RFC 2104).
|
|
314
|
+
- `hmac_sha512(key, message)` — HMAC-SHA512 (RFC 2104).
|
|
315
|
+
- `pbkdf2_hmac(password, salt, iterations, dklen, hash_name="sha256")` — PBKDF2 (RFC 8018), supporting SHA-256 / SHA-512.
|
|
316
|
+
- `hkdf_extract(salt, ikm, hash_name="sha256")` — HKDF-Extract (RFC 5869).
|
|
317
|
+
- `hkdf_expand(prk, info, length, hash_name="sha256")` — HKDF-Expand (RFC 5869).
|
|
318
|
+
- `hkdf(ikm, salt=b"", info=b"", length=32, hash_name="sha256")` — HKDF one-shot wrapper.
|
|
319
|
+
- `scrypt(password, salt, N=4096, r=8, p=1, dklen=32)` — scrypt (RFC 7914), including Salsa20/8, BlockMix, and ROMix implementations.
|
|
320
|
+
- `argon2id(password, salt, t=1, m=256, p=1, tag_length=32, secret=b"", ad=b"", version=0x13)` — Argon2id (RFC 9106), supporting a secret (pepper) and associated data.
|
|
321
|
+
|
|
322
|
+
#### Symmetric Encryption (`purepycrypto.aes`)
|
|
323
|
+
|
|
324
|
+
- `AES(key)` — AES-128/192/256 (FIPS 197), based on a LibTomCrypt-style T-table implementation.
|
|
325
|
+
- Block operations: `encrypt_block` / `decrypt_block`.
|
|
326
|
+
- Operation modes (NIST SP 800-38A):
|
|
327
|
+
- `encrypt_ecb(data)` / `decrypt_ecb(data)`
|
|
328
|
+
- `encrypt_cbc(data, iv)` / `decrypt_cbc(data, iv)`
|
|
329
|
+
- `encrypt_ctr(data, nonce8)` / `decrypt_ctr(data, nonce8)`
|
|
330
|
+
- `encrypt_cfb(data, iv)` / `decrypt_cfb(data, iv)`
|
|
331
|
+
- `encrypt_ofb(data, iv)` / `decrypt_ofb(data, iv)`
|
|
332
|
+
- GCM (NIST SP 800-38D, AEAD):
|
|
333
|
+
- `gcm_encrypt(nonce12, plaintext, aad=b"") -> (ct, tag)`
|
|
334
|
+
- `gcm_decrypt(nonce, ct, tag, aad=b"") -> bytes`
|
|
335
|
+
- ECB / CBC / CTR / GCM support multiprocessing acceleration via the `n_workers` parameter.
|
|
336
|
+
|
|
337
|
+
#### Authenticated Encryption (`purepycrypto.chacha`)
|
|
338
|
+
|
|
339
|
+
- `poly1305_mac(key32, msg)` — Poly1305 one-time authenticator (RFC 8439).
|
|
340
|
+
- `chacha20poly1305_encrypt(key, nonce, plaintext, aad=b"")` / `chacha20poly1305_decrypt(key, nonce, ct_with_tag, aad=b"")` — ChaCha20-Poly1305 (RFC 8439).
|
|
341
|
+
- `xchacha20poly1305_encrypt(key, nonce, plaintext, aad=b"")` / `xchacha20poly1305_decrypt(key, nonce, ct_with_tag, aad=b"")` — XChaCha20-Poly1305 (192-bit nonce, draft-irtf-cfrg-xchacha).
|
|
342
|
+
|
|
343
|
+
#### Key Exchange (`purepycrypto.x25519`)
|
|
344
|
+
|
|
345
|
+
- `x25519(k, u)` — X25519 scalar multiplication (RFC 7748).
|
|
346
|
+
- `x25519_base(scalar)` — scalar multiplication with u=9 as the base point.
|
|
347
|
+
- `x25519_shared(priv, peer_pub) -> (shared, is_zero)` — shared-secret computation with low-order point (all-zero) detection.
|
|
348
|
+
- `x25519_generate_keypair() -> (priv, pub)` — generates an X25519 key pair.
|
|
349
|
+
|
|
350
|
+
#### RSA Public-Key Cryptography (`purepycrypto.rsa`)
|
|
351
|
+
|
|
352
|
+
- `RSAPublicKey` / `RSAPrivateKey` — RSA key objects, including CRT decryption, Montgomery modular-exponentiation acceleration, blinding, and self-verification.
|
|
353
|
+
- `rsa_keygen(bits=2048, parallel=True) -> (RSAPublicKey, RSAPrivateKey)` — key generation, using 4 rounds of Miller-Rabin + strong Lucas primality testing (BPSW).
|
|
354
|
+
- `rsa_oaep_encrypt(message, pub, label=b"")` / `rsa_oaep_decrypt(ciphertext, priv, label=b"")` — RSA-OAEP (RFC 8017).
|
|
355
|
+
- `rsa_pss_sign(message, priv, salt_len=None)` / `rsa_pss_verify(message, signature, pub, salt_len=None)` — RSA-PSS (RFC 8017).
|
|
356
|
+
- Internal helpers: `extended_gcd`, `mod_inverse`, `mgf1`, `oaep_encode` / `oaep_decode`, `pss_encode` / `pss_verify`.
|
|
357
|
+
|
|
358
|
+
#### Serialization (`purepycrypto.der`)
|
|
359
|
+
|
|
360
|
+
- `private_key_to_pkcs1_der(priv)` / `public_key_to_pkcs1_der(pub)` — PKCS#1 DER.
|
|
361
|
+
- `private_key_to_pkcs8_der(priv)` — PKCS#8 private-key DER (RFC 5958).
|
|
362
|
+
- `public_key_to_spki_der(pub)` — SubjectPublicKeyInfo public-key DER (RFC 5280).
|
|
363
|
+
- `private_key_to_pem(priv)` / `public_key_to_pem(pub)` — PEM encoding.
|
|
364
|
+
- `parse_private_pem(pem)` — parses a PKCS#8 PEM private key into `RSAPrivateKey`.
|
|
365
|
+
|
|
366
|
+
#### Engineering Utilities (`purepycrypto.common` / `purepycrypto.parallel`)
|
|
367
|
+
|
|
368
|
+
- Constant-time comparison: `_consttime_eq`, `_consttime_int_eq`, `_consttime_select`.
|
|
369
|
+
- Secure random: `rand_bytes(n)` (based on `os.urandom`), `rand_int(a, b)`.
|
|
370
|
+
- Padding utilities: `_pad16`, `_pad_pkcs7` / `_unpad_pkcs7`.
|
|
371
|
+
- Constants: `MASK32`, `MASK64`, `MASK128`, `POLY1305_P`, `GHASH_R`, `R_CONST`.
|
|
372
|
+
- Exceptions: `CryptoError` (base class), `DecryptionError` (authentication failure).
|
|
373
|
+
- Multiprocessing acceleration: pool reuse (`_get_pool`), `SharedMemory` allocation and release, automatic cleanup via `atexit`.
|
|
374
|
+
- Parallel-capability probe flag `_HAS_MP`; falls back to serial automatically when unsupported.
|
|
375
|
+
|
|
376
|
+
#### Command Line
|
|
377
|
+
|
|
378
|
+
- Supports `python -m purepycrypto` to launch the interactive TUI.
|
|
379
|
+
|
|
380
|
+
### Notes
|
|
381
|
+
|
|
382
|
+
- This release **does not include** Ed25519/EdDSA, nor any post-quantum (PQC) algorithm.
|
|
383
|
+
- `rsa_keygen` requires `bits >= 521`, with 2048 / 3072 / 4096 recommended.
|
|
384
|
+
- All core algorithms are self-tested against standard official vectors (FIPS 180-4 / RFC 2104 / RFC 5869 / RFC 6070 / RFC 7914 / RFC 9106 / FIPS 197 / NIST GCM / RFC 8439 / RFC 7748 / RFC 8017).
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
[Unreleased]: https://git.dvscloud.net/dvs/purepycrypto/compare/v1.1.0...HEAD
|
|
389
|
+
[1.1.0]: https://git.dvscloud.net/dvs/purepycrypto/releases/tag/v1.1.0
|
|
390
|
+
[1.0.0]: https://git.dvscloud.net/dvs/purepycrypto/releases/tag/v1.0.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dvs(DvsXT) <dvs6666@163.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
include pyproject.toml
|
|
5
|
+
include setup.py
|
|
6
|
+
recursive-include purepycrypto *.py py.typed
|
|
7
|
+
recursive-include purepycrypto/tests *.py *.json
|
|
8
|
+
recursive-include purepycrypto/examples *.py
|
|
9
|
+
recursive-include purepycrypto/scripts *.py
|
|
10
|
+
recursive-include docs *.md
|
|
11
|
+
global-exclude *.py[cod] __pycache__ *.so *.bak *.bak_* pytest_full.txt
|