block58 0.4.1__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.
- block58-0.4.1/Cargo.lock +201 -0
- block58-0.4.1/Cargo.toml +25 -0
- block58-0.4.1/DESIGN.md +106 -0
- block58-0.4.1/LICENSE +21 -0
- block58-0.4.1/PKG-INFO +280 -0
- block58-0.4.1/PROVENANCE.md +39 -0
- block58-0.4.1/README.md +220 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/DEPENDENCIES.json +380 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/bs58-0.5.1-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/bs58-0.5.1-LICENSE-MIT +20 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/crossbeam-deque-0.8.8-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/crossbeam-deque-0.8.8-LICENSE-MIT +27 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/crossbeam-epoch-0.9.21-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/crossbeam-epoch-0.9.21-LICENSE-MIT +27 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/crossbeam-utils-0.8.23-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/crossbeam-utils-0.8.23-LICENSE-MIT +27 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/either-1.19.0-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/either-1.19.0-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/heck-0.5.0-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/heck-0.5.0-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/libc-0.2.190-LICENSE-APACHE +176 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/libc-0.2.190-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/once_cell-1.21.4-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/once_cell-1.21.4-LICENSE-MIT +23 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/portable-atomic-1.15.0-LICENSE-APACHE +177 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/portable-atomic-1.15.0-LICENSE-MIT +23 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/proc-macro2-1.0.107-LICENSE-APACHE +176 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/proc-macro2-1.0.107-LICENSE-MIT +23 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-0.28.3-LICENSE-APACHE +178 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-0.28.3-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-build-config-0.28.3-LICENSE-APACHE +178 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-build-config-0.28.3-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-ffi-0.28.3-LICENSE-APACHE +178 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-ffi-0.28.3-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-macros-0.28.3-LICENSE-APACHE +178 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-macros-0.28.3-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-macros-backend-0.28.3-LICENSE-APACHE +178 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/pyo3-macros-backend-0.28.3-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/quote-1.0.47-LICENSE-APACHE +176 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/quote-1.0.47-LICENSE-MIT +23 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/rayon-1.10.0-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/rayon-1.10.0-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/rayon-core-1.13.0-LICENSE-APACHE +201 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/rayon-core-1.13.0-LICENSE-MIT +25 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/syn-2.0.119-LICENSE-APACHE +176 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/syn-2.0.119-LICENSE-MIT +23 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/target-lexicon-0.13.5-LICENSE +220 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-APACHE.md +202 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-MIT.md +5 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-ZLIB.md +11 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-APACHE +176 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-MIT +23 -0
- block58-0.4.1/THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-UNICODE +39 -0
- block58-0.4.1/pyproject.toml +26 -0
- block58-0.4.1/python/block58/__init__.py +142 -0
- block58-0.4.1/python/block58/__init__.pyi +68 -0
- block58-0.4.1/python/block58/__main__.py +181 -0
- block58-0.4.1/python/block58/_files.py +358 -0
- block58-0.4.1/python/block58/_stream.py +223 -0
- block58-0.4.1/python/block58/py.typed +0 -0
- block58-0.4.1/src/lib.rs +579 -0
- block58-0.4.1/tests/test_api.py +137 -0
- block58-0.4.1/tests/test_contract.py +36 -0
- block58-0.4.1/tests/test_randomized.py +124 -0
- block58-0.4.1/tests/test_release_tools.py +159 -0
- block58-0.4.1/tests/test_stream_files.py +611 -0
- block58-0.4.1/tools/benchmark.py +35 -0
- block58-0.4.1/tools/benchmark_optimized.py +50 -0
- block58-0.4.1/tools/benchmark_suite.py +156 -0
- block58-0.4.1/tools/check_release.py +181 -0
- block58-0.4.1/tools/prepare_wheel.py +101 -0
block58-0.4.1/Cargo.lock
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "block58"
|
|
7
|
+
version = "0.4.1"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"bs58",
|
|
10
|
+
"pyo3",
|
|
11
|
+
"rayon",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "bs58"
|
|
16
|
+
version = "0.5.1"
|
|
17
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
18
|
+
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
|
|
19
|
+
dependencies = [
|
|
20
|
+
"tinyvec",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[[package]]
|
|
24
|
+
name = "crossbeam-deque"
|
|
25
|
+
version = "0.8.8"
|
|
26
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
27
|
+
checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a"
|
|
28
|
+
dependencies = [
|
|
29
|
+
"crossbeam-epoch",
|
|
30
|
+
"crossbeam-utils",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[[package]]
|
|
34
|
+
name = "crossbeam-epoch"
|
|
35
|
+
version = "0.9.21"
|
|
36
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
37
|
+
checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d"
|
|
38
|
+
dependencies = [
|
|
39
|
+
"crossbeam-utils",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[[package]]
|
|
43
|
+
name = "crossbeam-utils"
|
|
44
|
+
version = "0.8.23"
|
|
45
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
46
|
+
checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
|
|
47
|
+
|
|
48
|
+
[[package]]
|
|
49
|
+
name = "either"
|
|
50
|
+
version = "1.19.0"
|
|
51
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
52
|
+
checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
|
|
53
|
+
|
|
54
|
+
[[package]]
|
|
55
|
+
name = "heck"
|
|
56
|
+
version = "0.5.0"
|
|
57
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
58
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
59
|
+
|
|
60
|
+
[[package]]
|
|
61
|
+
name = "libc"
|
|
62
|
+
version = "0.2.190"
|
|
63
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
64
|
+
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
|
|
65
|
+
|
|
66
|
+
[[package]]
|
|
67
|
+
name = "once_cell"
|
|
68
|
+
version = "1.21.4"
|
|
69
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
70
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
71
|
+
|
|
72
|
+
[[package]]
|
|
73
|
+
name = "portable-atomic"
|
|
74
|
+
version = "1.15.0"
|
|
75
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
76
|
+
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
|
77
|
+
|
|
78
|
+
[[package]]
|
|
79
|
+
name = "proc-macro2"
|
|
80
|
+
version = "1.0.107"
|
|
81
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
82
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
83
|
+
dependencies = [
|
|
84
|
+
"unicode-ident",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[[package]]
|
|
88
|
+
name = "pyo3"
|
|
89
|
+
version = "0.28.3"
|
|
90
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
91
|
+
checksum = "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12"
|
|
92
|
+
dependencies = [
|
|
93
|
+
"libc",
|
|
94
|
+
"once_cell",
|
|
95
|
+
"portable-atomic",
|
|
96
|
+
"pyo3-build-config",
|
|
97
|
+
"pyo3-ffi",
|
|
98
|
+
"pyo3-macros",
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
[[package]]
|
|
102
|
+
name = "pyo3-build-config"
|
|
103
|
+
version = "0.28.3"
|
|
104
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
105
|
+
checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e"
|
|
106
|
+
dependencies = [
|
|
107
|
+
"target-lexicon",
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
[[package]]
|
|
111
|
+
name = "pyo3-ffi"
|
|
112
|
+
version = "0.28.3"
|
|
113
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
114
|
+
checksum = "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e"
|
|
115
|
+
dependencies = [
|
|
116
|
+
"libc",
|
|
117
|
+
"pyo3-build-config",
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
[[package]]
|
|
121
|
+
name = "pyo3-macros"
|
|
122
|
+
version = "0.28.3"
|
|
123
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
124
|
+
checksum = "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813"
|
|
125
|
+
dependencies = [
|
|
126
|
+
"proc-macro2",
|
|
127
|
+
"pyo3-macros-backend",
|
|
128
|
+
"quote",
|
|
129
|
+
"syn",
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
[[package]]
|
|
133
|
+
name = "pyo3-macros-backend"
|
|
134
|
+
version = "0.28.3"
|
|
135
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
136
|
+
checksum = "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb"
|
|
137
|
+
dependencies = [
|
|
138
|
+
"heck",
|
|
139
|
+
"proc-macro2",
|
|
140
|
+
"pyo3-build-config",
|
|
141
|
+
"quote",
|
|
142
|
+
"syn",
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
[[package]]
|
|
146
|
+
name = "quote"
|
|
147
|
+
version = "1.0.47"
|
|
148
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
149
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
150
|
+
dependencies = [
|
|
151
|
+
"proc-macro2",
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
[[package]]
|
|
155
|
+
name = "rayon"
|
|
156
|
+
version = "1.10.0"
|
|
157
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
158
|
+
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
|
159
|
+
dependencies = [
|
|
160
|
+
"either",
|
|
161
|
+
"rayon-core",
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
[[package]]
|
|
165
|
+
name = "rayon-core"
|
|
166
|
+
version = "1.13.0"
|
|
167
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
168
|
+
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
|
169
|
+
dependencies = [
|
|
170
|
+
"crossbeam-deque",
|
|
171
|
+
"crossbeam-utils",
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
[[package]]
|
|
175
|
+
name = "syn"
|
|
176
|
+
version = "2.0.119"
|
|
177
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
178
|
+
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
|
179
|
+
dependencies = [
|
|
180
|
+
"proc-macro2",
|
|
181
|
+
"quote",
|
|
182
|
+
"unicode-ident",
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
[[package]]
|
|
186
|
+
name = "target-lexicon"
|
|
187
|
+
version = "0.13.5"
|
|
188
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
189
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
190
|
+
|
|
191
|
+
[[package]]
|
|
192
|
+
name = "tinyvec"
|
|
193
|
+
version = "1.13.3"
|
|
194
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
195
|
+
checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee"
|
|
196
|
+
|
|
197
|
+
[[package]]
|
|
198
|
+
name = "unicode-ident"
|
|
199
|
+
version = "1.0.27"
|
|
200
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
201
|
+
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
block58-0.4.1/Cargo.toml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "block58"
|
|
3
|
+
version = "0.4.1"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
rust-version = "1.83"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
description = "Ordinary and Monero block Base58 for Python"
|
|
8
|
+
include = ["Cargo.toml", "Cargo.lock", "src/**", "python/**", "tests/test_api.py", "tests/test_contract.py", "tests/test_release_tools.py", "tests/test_randomized.py", "tests/test_stream_files.py", "tools/**", "pyproject.toml", "README.md", "DESIGN.md", "PROVENANCE.md", "LICENSE", "THIRD_PARTY_LICENSES/**"]
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
|
|
11
|
+
[lib]
|
|
12
|
+
name = "_native"
|
|
13
|
+
crate-type = ["cdylib", "rlib"]
|
|
14
|
+
|
|
15
|
+
[dependencies]
|
|
16
|
+
bs58 = "=0.5.1"
|
|
17
|
+
rayon = "=1.10.0"
|
|
18
|
+
pyo3 = { version = "=0.28.3", features = ["extension-module", "abi3-py37"] }
|
|
19
|
+
|
|
20
|
+
[profile.release]
|
|
21
|
+
lto = "thin"
|
|
22
|
+
codegen-units = 1
|
|
23
|
+
debug = false
|
|
24
|
+
strip = "debuginfo"
|
|
25
|
+
|
block58-0.4.1/DESIGN.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Rust 核心与 Python 接口设计
|
|
2
|
+
|
|
3
|
+
状态:2026-10-14,0.2.0 本地开发。文中分开说明已实现能力与后续计划,未发布 PyPI。
|
|
4
|
+
|
|
5
|
+
## 1. 目标与格式契约
|
|
6
|
+
|
|
7
|
+
同一个包显式提供两种编码,不根据输入大小自动切换,不对解码结果猜测模式。默认 mode='standard' 对全部输入进行一次普通 Base58 转换;mode='monero' 按 8 字节完整块处理,最后不足 8 字节的块使用固定尾长映射。模式、字母表和是否带校验和属于调用契约;原始编码结果不包含这些元信息。
|
|
8
|
+
|
|
9
|
+
8 字节/11 字符和大端解释是固定协议,不作为性能配置参数。批次大小属于处理方式,可以调节,但不能悄悄改变算法块长。当前 monero 模式不会生成完整 Monero 地址,不附加任何地址或校验和字段。未来若增加 Base58Check,应使用独立命名接口,不改变现有 b58encode 的输出。
|
|
10
|
+
|
|
11
|
+
默认字母表保证与现有分块实现一致。自定义字母表要求 58 个不同 ASCII 字节;支持 ASCII 控制字符的字母表不适合文本传输。它是通用数值变换能力,不代表与 Monero 协议兼容。ignore_whitespace 与包含空白字符的字母表不能同时使用。
|
|
12
|
+
|
|
13
|
+
## 2. 层次与责任
|
|
14
|
+
|
|
15
|
+
| 层 | 当前责任 | 后续约束 |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| Python 公共接口 | 输入类型、可变输入快照、ASCII 文本和空白处理 | 不包含逐块编码循环,不自动加载无关文件 |
|
|
18
|
+
| PyO3 绑定 | 保持 bytes 生命周期、释放 GIL、映射错误、返回 bytes | 不在 detach 闭包里访问 Python 对象 |
|
|
19
|
+
| Rust 核心 | 普通转换、分块循环、固定宽度、溢出检查 | 尽量纯函数;不联网,不访问文件,无全局可变编码状态 |
|
|
20
|
+
| 构建与发布 | 固定依赖、许可证、各平台产物 | 对生成的 wheel/sdist 本身做检查 |
|
|
21
|
+
|
|
22
|
+
目前核心和绑定仍在一个 Rust 文件,便于审查。流式状态或更多编解码协议加入后,再拆为 codec / error / python 模块;不为目录数量先行扩展。纯 Rust 核心应保持不依赖 Python 运行时的逻辑,方便独立测试。
|
|
23
|
+
|
|
24
|
+
## 3. 类型与错误
|
|
25
|
+
|
|
26
|
+
编码接受 bytes、bytearray、memoryview;解码另外接受 ASCII str。返回都是 bytes。int、list、None 不隐式转为字节;编码 str 不隐式选择 UTF-8。需要 UTF-8 的调用者自行 encode/decode,二进制数据不会因文本解码失败而被改变。
|
|
27
|
+
|
|
28
|
+
| 情况 | 错误 |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| 输入类型、参数类型错误 | TypeError |
|
|
31
|
+
| 非法模式、字母表、字符、尾长、数值溢出、非 ASCII 文本 | ValueError |
|
|
32
|
+
| 可失败 Rust 输出缓冲区预留失败 | MemoryError |
|
|
33
|
+
| 未来文件 IO 错误 | 对应 OSError 子类,不包装成编码错误 |
|
|
34
|
+
|
|
35
|
+
错误文本不是稳定机器协议。后续若需要字段化错误,再增加 ValueError 子类及 position / block_index 等属性。启用空白移除后,当前错误位置相对于去空白后的字节序列;不声称对应原始文件偏移。非法输入的单次 API 调用不会返回部分结果。
|
|
36
|
+
|
|
37
|
+
Python 输出构造使用可失败的 PyBytes::new_with,避免 new 在分配失败时转为 Rust panic。发行检查覆盖重复/特殊归档成员、反斜杠路径、UTF-16/JSON 转义路径和 RECORD 的结构及散列。SBOM 规范化先确认原包完整性,拒绝修改已签名 wheel,临时产物复检通过后才替换原文件。
|
|
38
|
+
|
|
39
|
+
RECORD 不是来源认证:同时修改内容与散列的第三方仍可制造一致的归档。当前工具不声称验证发布者签名。公开网络服务若接入该 API,需要在调用方限制输入大小、并发及计算时间;特别是普通模式的大输入,不因为释放 GIL 就变成有界时间操作。核心没有网络上传或日志输出,不自动清除进程内的明文数据。
|
|
40
|
+
|
|
41
|
+
## 4. 内存与边界
|
|
42
|
+
|
|
43
|
+
monero 编码大小:floor(n/8)*11 + sizes[n%8];解码先验证尾长,再确定输出大小。所有长度运算使用 checked 运算,数值使用 u64 的 checked_mul/checked_add,最后验证尾块能放入对应字节容量。
|
|
44
|
+
|
|
45
|
+
输出使用 try_reserve_exact 后填充预留空间;普通模式也先建立保守输出容量,再通过 bs58 onto 写入。分配失败映射成 MemoryError。由本项目控制的容量预留可失败返回,不保证操作系统 OOM kill、Python 侧分配或所有依赖内部小分配均能恢复。
|
|
46
|
+
|
|
47
|
+
当前路径不是端到端零拷贝:immutable bytes 可借用,但可变输入需要一次快照,Rust Vec 返回 Python bytes 时需要一次复制;str 转 ASCII、空白清理也可能再分配。MB 数据目前可接受,GB 输入应优先使用现有有界文件接口。暂不加入 unsafe 直接写 Python 缓冲区,除非基准证明复制是主要瓶颈且经过独立生命周期审查。
|
|
48
|
+
|
|
49
|
+
## 5. GIL、线程与取消
|
|
50
|
+
|
|
51
|
+
已实现:Rust 数值计算时使用 Python::detach,让其他 Python 线程继续执行。Python bytes 的生命周期贯穿整个调用;不能在释放 GIL 后借用会被其他线程修改的 bytearray。并发调用不共享可变编码状态。[PyO3 官方依据](https://pyo3.rs/v0.28.3/parallelism)
|
|
52
|
+
|
|
53
|
+
0.2.0 已加入 Rayon 共享池与 workers=0/1/2~8。至少 1 MiB 的批次才能进入并行路径;有效任务数量不超过可用核心数和池上限。不同 workers 值不创建多份池。输入按协议完整块划分,每个任务直接写独占输出切片,错误按输入顺序选择,避免复制和重排。fork 后 PID 变化会回退单线程,spawn 子进程建立自己的池;Linux fork 行为仍需实机验证。池初始化失败回到单线程。调用方外层并发较多时可显式 workers=1。
|
|
54
|
+
|
|
55
|
+
长时间单次原生调用不保证立即响应 Ctrl+C。现有流式接口以有界批次返回 Python,让进度和取消在批次边界执行。不要为每 8 字节重新进入 Python 回调,否则会恢复原来的调用开销。
|
|
56
|
+
|
|
57
|
+
## 6. 流式与文件能力:0.2.0 已实现
|
|
58
|
+
|
|
59
|
+
MoneroEncoder/MoneroDecoder 提供增量编码器/解码器:update(chunk) / finalize()。编码保留不足 8 字节的尾部;解码去除允许的 ASCII 排版空白后保留不足 11 字符的尾部。finalize 只调用一次,之后 update/finalize 报清晰状态错误。失败后的实例不可继续输出,避免混合有效与无效状态。
|
|
60
|
+
|
|
61
|
+
任何大小的输入批次都应支持,但缓存必须保持有界。每次 update 输出按原始次序拼接,与一次性调用结果一致。流式输出尚不能保证整个文件事务性:如果后面的块非法,前面的输出可能已写出。文件工具已经写入同目录临时文件,全部校验和 fsync 成功后发布。不覆盖模式使用排他硬链接;覆盖模式使用 os.replace。发布之前失败不改变旧目标,发布之后不能原子回滚。
|
|
62
|
+
|
|
63
|
+
普通 Base58 不允许通过“各批次独立编码后拼接”实现流式,因为那会改变数值与格式。普通增量算法必须保持全局变换状态,不能假称有界内存;第一版文件流式只支持 monero,standard 保留一次性接口。
|
|
64
|
+
|
|
65
|
+
进度条位于 CLI;progress extra 提供 tqdm,核心不依赖它。文件接口默认 4 MiB 上限批次,尽量对齐协议块,减少尾部拼接复制。两个 Python IO 工作线程分别预读下一批和写上一批,每类最多一个 future,主线程发起当前批 Rust 计算。回调在主线程执行,最终 100% 在发布后报告;回调/临时名清理的后置故障记录在 FileResult 中。可禁用流水线,显式覆盖支持输入输出同一路径。
|
|
66
|
+
|
|
67
|
+
## 7. 验证与性能
|
|
68
|
+
|
|
69
|
+
现有测试:普通模式与 based58 交叉,分块模式与独立参考交叉;各种尾长、前导零、全 0/全 FF、非法字符和数值溢出;自定义字母表、对齐批次和多线程结果。新增契约测试覆盖普通模式前导零、类型及空白冲突、跨模式误用。
|
|
70
|
+
|
|
71
|
+
后续增加公开规范测试向量、随机属性测试与原生 fuzz。测试数据限公开或本项目合成数据;私有样本只在包外用于自用回归,不进入发布物。fuzz 的失败输入先去除私人信息再作为公开回归夹具。
|
|
72
|
+
|
|
73
|
+
公开基准使用固定种子合成数据,分开报告内存 API、文件 IO、冷启动、单核和并行,不用单次最快数字当结论。比较模式、字母表、输入数据、构建优化必须一致;错误模式和不同机器间的时间不直接相除。性能目标是单核分块吞吐和有界内存,不为宣传增加未经验证的倍数承诺。
|
|
74
|
+
|
|
75
|
+
## 8. 平台与发布
|
|
76
|
+
|
|
77
|
+
ABI 目标为 CPython 3.7+,PyO3 固定 0.28.3;Rust 基线为 1.83,已在 Windows 用 1.83.0 完成锁定依赖的 release 编译与 Rust 测试,也在 1.99 上完成检查和 wheel 构建。Python 实测版本仍为 3.14;ABI 标签不是所有 Python/系统组合实测的证明。PyPy 和自由线程 Python 不在当前已验证支持列表。
|
|
78
|
+
|
|
79
|
+
先为 Windows amd64、Linux x86_64、Linux aarch64 做候选 wheel,UOS 的其他架构另行验证。Linux 还要检查 glibc/manylinux 基线;Windows 产物不能移植到 Linux。平台构建后用干净环境安装 wheel 验证,不能只在源码目录导入成功就认为已交付。
|
|
80
|
+
|
|
81
|
+
发行清单限源码、公开测试、设计、许可证和锁文件。检查生成归档,防止嵌套 dist、编译缓存、绝对用户路径或私有回归输入。原生二进制仍可能保留编译路径字符串,发布构建应使用干净构建目录和路径重映射;剥离调试信息不等于已经去除所有路径。
|
|
82
|
+
|
|
83
|
+
正式发布前固定包名、版本策略和作者信息,测试 TestPyPI 安装,采用 PyPI Trusted Publishing;实际账号授权和发布动作另行执行。不要把测试 CI 和生产发布权限混在一起。[发布官方依据](https://docs.pypi.org/trusted-publishers/)
|
|
84
|
+
|
|
85
|
+
## 9. 下一步顺序
|
|
86
|
+
|
|
87
|
+
1. 已落实:两种模式的格式契约、可失败输出分配、Rust 基线、发行清单和私有样本隔离。
|
|
88
|
+
2. 已落实:monero 增量接口、有界文件工具、批次进度与取消、原生共享池;普通模式保留一次性语义。
|
|
89
|
+
3. 发布前:最低版本与 Linux/UOS 构建、公开规范向量、随机/fuzz、干净 wheel 安装、发行来源与归档复核。
|
|
90
|
+
4. 已落实原生并行与直接写独占切片。进一步减少 Python 输出复制或 SIMD 仍需新的基准与生命周期审查;默认格式永远不因优化变化。
|
|
91
|
+
|
|
92
|
+
来源边界见 PROVENANCE.md。未确认来源或公开权利的代码不能进入实现,即使它能节省开发时间。
|
|
93
|
+
# 0.3.0 可配置固定块长补充
|
|
94
|
+
|
|
95
|
+
新增 block 模式,块长上限 4096 字节。完整块与唯一尾块均采用固定字符宽度;宽度由最大块值的整数进制递推求出,不使用浮点对数。解码拒绝不存在的尾长及超过对应字节容量的块值。
|
|
96
|
+
|
|
97
|
+
8 字节复用 Monero 实现,其他 1~16 字节使用 u128,大块依赖公开 bs58 实现;通用路径的大块临时缓冲随块长受限。线程任务按完整块边界切分,保持错误选择顺序。流式实例保留不足一个块的输入,文件 IO 批次与编码块长相互独立。输出无参数头,调用方负责持久化块长/字母表;误用块长可能静默得到其他数据。
|
|
98
|
+
|
|
99
|
+
# 0.4.0 行记录与信息查看
|
|
100
|
+
|
|
101
|
+
按行转换是逐行独立结束编码对象,不是对一段编码文本自动换行。文件实现不缓冲整行,使用底层固定块增量状态,并延迟一个末尾 CR 以识别跨批次 CRLF。LF/CRLF 不参与 Base58 数值转换,裸 CR 作为数据;记录分隔、空行、末尾换行保留。某行失败使整个文件转换失败,发布仍沿用临时文件和排他创建/显式覆盖策略。
|
|
102
|
+
|
|
103
|
+
info 对纯 Base58 只展示参数假设:长度推算不验证字符与数值,verify 路径实际解码并丢弃结果,没有输出落盘。行模式推算独立计算每行尾块并计入保留的分隔字节。源文件读取按初始大小限制并做变化检查;成功可解码不等于原始格式或完整性已确认。
|
|
104
|
+
|
|
105
|
+
中文错误解释只处理已知原因,不打印未知进度回调异常正文。CLI 记录结果是否已发布,避免控制台显示失败时声称转换未生成文件。运行时接口不新增网络请求。
|
|
106
|
+
|
block58-0.4.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WTElf
|
|
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.
|
block58-0.4.1/PKG-INFO
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: block58
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Requires-Dist: tqdm>=4.60 ; extra == 'progress'
|
|
5
|
+
Requires-Dist: based58>=0.1.1 ; extra == 'test'
|
|
6
|
+
Provides-Extra: progress
|
|
7
|
+
Provides-Extra: test
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
License-File: THIRD_PARTY_LICENSES/DEPENDENCIES.json
|
|
10
|
+
License-File: THIRD_PARTY_LICENSES/bs58-0.5.1-LICENSE-APACHE
|
|
11
|
+
License-File: THIRD_PARTY_LICENSES/bs58-0.5.1-LICENSE-MIT
|
|
12
|
+
License-File: THIRD_PARTY_LICENSES/crossbeam-deque-0.8.8-LICENSE-APACHE
|
|
13
|
+
License-File: THIRD_PARTY_LICENSES/crossbeam-deque-0.8.8-LICENSE-MIT
|
|
14
|
+
License-File: THIRD_PARTY_LICENSES/crossbeam-epoch-0.9.21-LICENSE-APACHE
|
|
15
|
+
License-File: THIRD_PARTY_LICENSES/crossbeam-epoch-0.9.21-LICENSE-MIT
|
|
16
|
+
License-File: THIRD_PARTY_LICENSES/crossbeam-utils-0.8.23-LICENSE-APACHE
|
|
17
|
+
License-File: THIRD_PARTY_LICENSES/crossbeam-utils-0.8.23-LICENSE-MIT
|
|
18
|
+
License-File: THIRD_PARTY_LICENSES/either-1.19.0-LICENSE-APACHE
|
|
19
|
+
License-File: THIRD_PARTY_LICENSES/either-1.19.0-LICENSE-MIT
|
|
20
|
+
License-File: THIRD_PARTY_LICENSES/heck-0.5.0-LICENSE-APACHE
|
|
21
|
+
License-File: THIRD_PARTY_LICENSES/heck-0.5.0-LICENSE-MIT
|
|
22
|
+
License-File: THIRD_PARTY_LICENSES/libc-0.2.190-LICENSE-APACHE
|
|
23
|
+
License-File: THIRD_PARTY_LICENSES/libc-0.2.190-LICENSE-MIT
|
|
24
|
+
License-File: THIRD_PARTY_LICENSES/once_cell-1.21.4-LICENSE-APACHE
|
|
25
|
+
License-File: THIRD_PARTY_LICENSES/once_cell-1.21.4-LICENSE-MIT
|
|
26
|
+
License-File: THIRD_PARTY_LICENSES/portable-atomic-1.15.0-LICENSE-APACHE
|
|
27
|
+
License-File: THIRD_PARTY_LICENSES/portable-atomic-1.15.0-LICENSE-MIT
|
|
28
|
+
License-File: THIRD_PARTY_LICENSES/proc-macro2-1.0.107-LICENSE-APACHE
|
|
29
|
+
License-File: THIRD_PARTY_LICENSES/proc-macro2-1.0.107-LICENSE-MIT
|
|
30
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-0.28.3-LICENSE-APACHE
|
|
31
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-0.28.3-LICENSE-MIT
|
|
32
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-build-config-0.28.3-LICENSE-APACHE
|
|
33
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-build-config-0.28.3-LICENSE-MIT
|
|
34
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-ffi-0.28.3-LICENSE-APACHE
|
|
35
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-ffi-0.28.3-LICENSE-MIT
|
|
36
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-macros-0.28.3-LICENSE-APACHE
|
|
37
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-macros-0.28.3-LICENSE-MIT
|
|
38
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-macros-backend-0.28.3-LICENSE-APACHE
|
|
39
|
+
License-File: THIRD_PARTY_LICENSES/pyo3-macros-backend-0.28.3-LICENSE-MIT
|
|
40
|
+
License-File: THIRD_PARTY_LICENSES/quote-1.0.47-LICENSE-APACHE
|
|
41
|
+
License-File: THIRD_PARTY_LICENSES/quote-1.0.47-LICENSE-MIT
|
|
42
|
+
License-File: THIRD_PARTY_LICENSES/rayon-1.10.0-LICENSE-APACHE
|
|
43
|
+
License-File: THIRD_PARTY_LICENSES/rayon-1.10.0-LICENSE-MIT
|
|
44
|
+
License-File: THIRD_PARTY_LICENSES/rayon-core-1.13.0-LICENSE-APACHE
|
|
45
|
+
License-File: THIRD_PARTY_LICENSES/rayon-core-1.13.0-LICENSE-MIT
|
|
46
|
+
License-File: THIRD_PARTY_LICENSES/syn-2.0.119-LICENSE-APACHE
|
|
47
|
+
License-File: THIRD_PARTY_LICENSES/syn-2.0.119-LICENSE-MIT
|
|
48
|
+
License-File: THIRD_PARTY_LICENSES/target-lexicon-0.13.5-LICENSE
|
|
49
|
+
License-File: THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-APACHE.md
|
|
50
|
+
License-File: THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-MIT.md
|
|
51
|
+
License-File: THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-ZLIB.md
|
|
52
|
+
License-File: THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-APACHE
|
|
53
|
+
License-File: THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-MIT
|
|
54
|
+
License-File: THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-UNICODE
|
|
55
|
+
Summary: Rust-backed ordinary and Monero block Base58
|
|
56
|
+
License-Expression: MIT
|
|
57
|
+
Requires-Python: >=3.7
|
|
58
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
59
|
+
|
|
60
|
+
# block58 0.4.1(PyPI 发行名:block58)
|
|
61
|
+
|
|
62
|
+
同一个 Python 包提供普通 Base58 和 Monero 8 字节分块 Base58。分块模式的完整循环在 Rust 内执行,一次提交大批数据,避免 Python 为每个块调用一次原生函数。
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from block58 import b58encode, b58decode, monero_encode, monero_decode
|
|
66
|
+
|
|
67
|
+
# 默认:全部字节作为一次普通 Base58 编码对象,与 based58 默认格式一致。
|
|
68
|
+
ordinary = b58encode(b'hello world')
|
|
69
|
+
assert ordinary == b'StV1DL6CwTryKyV'
|
|
70
|
+
assert b58decode(ordinary) == b'hello world'
|
|
71
|
+
|
|
72
|
+
# 可选:8 字节分块;整个循环在 Rust,沿用旧 Python 脚本的格式。
|
|
73
|
+
blocked = b58encode(b'hello world', mode='monero')
|
|
74
|
+
assert b58decode(blocked, mode='monero') == b'hello world'
|
|
75
|
+
assert monero_decode(monero_encode(b'hello world')) == b'hello world'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
普通模式对大输入做整段转换,不能因为使用 Rust 就假定 MB 数据也会快速完成。MB 文件建议选择分块模式;这两种格式不互换,也没有自动模式识别。
|
|
79
|
+
|
|
80
|
+
## 查看编码信息与中文提示
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# 按默认 8 字节分块规则推算,不实际解码
|
|
84
|
+
python -m block58 info output.b58
|
|
85
|
+
|
|
86
|
+
# 按指定规则实际流式解码检查;不生成文件,不打印解码正文
|
|
87
|
+
python -m block58 info output.b58 --block-size 16 --verify
|
|
88
|
+
|
|
89
|
+
# 含排版空白的整段编码文件
|
|
90
|
+
python -m block58 info output.b58 --ignore-whitespace --verify
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
纯 Base58 没有参数头,info 不会自动判断实际模式、块长或原始大小。它展示文件大小、编码字符数、所用参数假设,以及推算/实际解码后的字节数。不加 --verify 仅分析长度;非法字符或数值溢出可能尚未被发现。--verify 成功只说明指定参数下可解码,不能确认原始内容或完整性。文件 CLI/info 使用分块模式,普通整段 Base58 使用 Python b58encode/b58decode。
|
|
94
|
+
|
|
95
|
+
Python 同样可调用 `inspect_file('output.b58', block_size=16, verify=True)`,返回 FileInfo;`verified` 表示是否实际检查,`decoded_bytes=None` 表示无法按长度推算。info 不落盘,但检查源文件变化;输出保留明确的参数假设。
|
|
96
|
+
|
|
97
|
+
CLI 错误用中文解释原因与处理方法:目标已存在、权限不足、非法字符、尾部长度不符、溢出、源文件变化及无效参数。转换失败会说明本次未发布新输出;已有目标保留。发布成功后的进度/UI 错误则明确说明输出已生成。库异常类型保持兼容,未把所有底层异常改成中文。
|
|
98
|
+
|
|
99
|
+
## 可选大小上限与参考摘要校验
|
|
100
|
+
|
|
101
|
+
0.4.1 的文件接口和 info 支持 max_input_bytes / max_output_bytes(非负整数,默认 None 不限制),对应 CLI 的 --max-input-bytes / --max-output-bytes。输入上限按打开时文件大小检查;转换输出按批次检查,超过上限不发布并保留旧目标。它们不是 CPU 时间、内存或跨调用并发配额;一个计算批次可能先分配结果再发现超限,仍需按机器资源设置 chunk_size。
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
python -m block58 encode input.bin output.b58 --max-input-bytes 16777216 --max-output-bytes 33554432
|
|
105
|
+
python -m block58 decode output.b58 restored.bin --block-size 16 --expected-sha256 这里替换为原始文件的64位十六进制SHA256
|
|
106
|
+
python -m block58 info output.b58 --block-size 16 --verify --expected-sha256 这里替换为同一参考摘要
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from block58 import decode_file, inspect_file
|
|
111
|
+
|
|
112
|
+
# 从可信的独立记录获取,而不是信任待解码文件自己给出的摘要。
|
|
113
|
+
expected = '这里替换为原始文件的64位十六进制SHA256'
|
|
114
|
+
decode_file('output.b58', 'restored.bin', block_size=16,
|
|
115
|
+
expected_sha256=expected, max_output_bytes=16 * 1024 * 1024)
|
|
116
|
+
info = inspect_file('output.b58', block_size=16, verify=True, expected_sha256=expected)
|
|
117
|
+
assert info.integrity_verified
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
摘要校验在发布前完成,错误块长或内容变化导致摘要不匹配时取消转换。摘要覆盖完整解码字节(按行模式包含保留的 LF/CRLF),无需改变旧编码格式。编码命令不接受参考解码摘要;info 必须启用 verify。错误提示不打印实际/参考摘要或解码正文。摘要比对不能代替加密、签名或可信来源;默认不自动生成或保存摘要文件。
|
|
121
|
+
|
|
122
|
+
## 每行独立转换
|
|
123
|
+
|
|
124
|
+
按行处理与输出自动换行是不同功能:每个 LF/CRLF 分隔的记录单独编码/解码,行内仍用所选固定字节块。空行、行首尾空格、末尾换行保留;裸 CR 作为数据。该行为不用于任意二进制文件的通用分割;此类文件继续用默认整段分块模式。
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
python -m block58 encode records.txt records.b58 --by-line --block-size 16
|
|
128
|
+
python -m block58 decode records.b58 restored.txt --by-line --block-size 16
|
|
129
|
+
python -m block58 info records.b58 --by-line --block-size 16 --verify
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from block58 import b58encode, b58decode, LineEncoder, LineDecoder
|
|
134
|
+
|
|
135
|
+
data = '你好\r\n世界\n\n'.encode('utf8')
|
|
136
|
+
encoded = b58encode(data, mode='block', block_size=16, by_line=True)
|
|
137
|
+
assert b58decode(encoded, mode='block', block_size=16, by_line=True) == data
|
|
138
|
+
|
|
139
|
+
# 普通 Base58 同样支持每行独立处理,方便与普通在线工具互操作。
|
|
140
|
+
ordinary = b58encode(data, by_line=True)
|
|
141
|
+
assert b58decode(ordinary, by_line=True) == data
|
|
142
|
+
|
|
143
|
+
# 流式按行接口只保留一个未完整的字节块及可能属于 CRLF 的 CR。
|
|
144
|
+
encoder = LineEncoder(block_size=16)
|
|
145
|
+
encoded = encoder.update(data[:5]) + encoder.update(data[5:]) + encoder.finalize()
|
|
146
|
+
decoder = LineDecoder(block_size=16)
|
|
147
|
+
assert decoder.update(encoded) + decoder.finalize() == data
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
文件接口使用 `encode_file(..., by_line=True)` / `decode_file(..., by_line=True)`;默认仍不按行。按行模式改变编码结果,解码必须启用相同模式。如果只是长编码字符串被排版换行,用 --ignore-whitespace 解码整段,不要使用 --by-line。某行失败会取消本次整个文件转换,不发布混有错误文本的部分结果。按行自定义字母表不能含 CR/LF,以免与记录分隔符混淆。
|
|
151
|
+
|
|
152
|
+
## 可配置块长
|
|
153
|
+
|
|
154
|
+
0.3.0 新增 `mode='block'` 和 `block_size`,支持 1~4096 字节,省略块长时默认 8。原来的 `mode='monero'` 固定 8 字节;普通和 Monero 模式不接受 block_size,避免参数被静默忽略。
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from block58 import b58encode, b58decode, BlockEncoder, BlockDecoder
|
|
158
|
+
from block58 import encode_file, decode_file
|
|
159
|
+
|
|
160
|
+
data = b'hello world' * 100
|
|
161
|
+
encoded = b58encode(data, mode='block', block_size=16)
|
|
162
|
+
assert b58decode(encoded, mode='block', block_size=16) == data
|
|
163
|
+
|
|
164
|
+
encoder = BlockEncoder(block_size=16)
|
|
165
|
+
encoded = encoder.update(data[:19]) + encoder.update(data[19:]) + encoder.finalize()
|
|
166
|
+
decoder = BlockDecoder(block_size=16)
|
|
167
|
+
assert decoder.update(encoded) + decoder.finalize() == data
|
|
168
|
+
|
|
169
|
+
encode_file('input.bin', 'output.b58', block_size=16)
|
|
170
|
+
decode_file('output.b58', 'restored.bin', block_size=16)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
python -m block58 encode input.bin output.b58 --block-size 16
|
|
175
|
+
python -m block58 decode output.b58 restored.bin --block-size 16
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
每个 n 字节块左侧补齐到能够容纳 `256**n-1` 的最小 Base58 字符宽度;尾块按实际字节数确定宽度。例:8 字节对应 11 字符,16 字节对应 22 字符。块长不写入输出,解码必须自行记住相同块长;错误块长不保证报错。
|
|
179
|
+
|
|
180
|
+
`block_size` 决定编码格式,`chunk_size` 只决定文件每批读取多少。8 字节复用原 u64 快速路径;其他不超过 16 字节的块使用 u128,较大的块用通用多字节转换。可配置模式也使用共享线程池。更大块长不保证提速;默认 8 字节保持原有兼容性和性能路径。
|
|
181
|
+
|
|
182
|
+
## 自动并行与流式文件工具
|
|
183
|
+
|
|
184
|
+
分块 API 增加 workers:0 为自动,1 为单线程,2~8 为请求的并行任务上限;实际不超过系统可用核心数和共享池的 8 线程上限。输入不足 1 MiB 时走单线程,超过阈值才使用懒初始化的共享 Rayon 池。线程创建失败安全回到单线程,不改变格式。普通模式只接受 workers=0/1,不对整段输入拆分编码。
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from block58 import monero_encode, monero_decode, MoneroEncoder
|
|
188
|
+
from block58 import encode_file, decode_file
|
|
189
|
+
|
|
190
|
+
encoded = monero_encode(data, workers=0) # 自动使用合适的原生并行路径
|
|
191
|
+
assert monero_decode(encoded, workers=0) == data
|
|
192
|
+
|
|
193
|
+
# 输入批次可以不是 8 的倍数:增量编码器会保留不足一块的尾部。
|
|
194
|
+
stream = MoneroEncoder(workers=0)
|
|
195
|
+
encoded = stream.update(b'hello') + stream.update(b' world') + stream.finalize()
|
|
196
|
+
|
|
197
|
+
# 文件接口默认使用 Monero 格式、4 MiB 批次和有界读/算/写流水线。
|
|
198
|
+
result = encode_file('input.bin', 'output.b58')
|
|
199
|
+
decode_file('output.b58', 'restored.bin')
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
MoneroDecoder 支持同样的 update/finalize 与可选 ignore_whitespace。finalize 只调用一次;失败后的流不可重用。单个流实例的状态串行化,但并发调用不能代替调用者管理输入顺序。
|
|
203
|
+
|
|
204
|
+
文件目标存在时默认报错。显式 overwrite=True 支持覆盖,也支持输入输出同一路径。结果验证和刷盘完成后才发布;不覆盖发布采用同目录硬链接排他创建,文件系统不支持时明确报错,不使用存在竞态的降级实现。中途错误/取消清理临时输出;发布之后的 UI 或临时名清理故障分别记录为 FileResult.progress_error/cleanup_error。源文件大小/mtime 检查可发现普通变更,不保证对抗恶意并发写入的完整快照。
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
python -m block58 encode input.bin output.b58 --workers 0
|
|
208
|
+
python -m block58 decode output.b58 restored.bin --workers 0
|
|
209
|
+
python -m block58 decode formatted.b58 restored.bin --ignore-whitespace --overwrite
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
CLI 仅在交互终端显示进度,显示需要安装 progress extra(tqdm);--no-progress 可禁用,重定向时自动不显示。进度按批次更新,100% 在发布成功后报告。可用 --no-pipeline、--chunk-size 和 --workers 1 分别比较顺序 IO、批次大小与单线程。
|
|
213
|
+
|
|
214
|
+
原生 API 一次性输入仍使用整块内存;文件接口只保留少量批次,内存规模由 chunk_size 控制。单次原生调用不是瞬时可取消的任务,文件处理在批次边界响应取消。
|
|
215
|
+
|
|
216
|
+
输入接受 bytes、bytearray、memoryview;解码另接受 ASCII str;返回均为 bytes。非法 mode、字母表、字符、尾块长度或溢出会报错。默认不接受排版空白,读取邮件文本时可显式指定 ignore_whitespace=True;不会忽略 Unicode 空白。
|
|
217
|
+
|
|
218
|
+
## 兼容性
|
|
219
|
+
|
|
220
|
+
默认字母表为 Bitcoin/Monero 使用的 58 字符序列。Monero 模式完整块为 8 字节对应 11 字符;尾块长度映射为 0,2,3,5,6,7,9,10,11。保持大端数值解释及前导零,与此前 file_base58_enc.py/file_base58_dec.py 相同。
|
|
221
|
+
|
|
222
|
+
可传 alphabet=58 个不同 ASCII 字节,自定义时编码与解码必须保持一致。只有默认字母表输出承诺与现有文件兼容。
|
|
223
|
+
|
|
224
|
+
这不是 Monero 地址完整生成器,不自动加入地址网络前缀或校验和,也不提供加密功能。
|
|
225
|
+
|
|
226
|
+
## 编译和安装
|
|
227
|
+
|
|
228
|
+
安装构建依赖 maturin,然后在本目录运行:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
python -m maturin build --release
|
|
232
|
+
python -m pip install 路径/生成的.whl
|
|
233
|
+
python -m unittest discover -s tests -v
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
包使用 PyO3 0.28.3 和 CPython abi3-py37,目标 ABI 为 CPython 3.7+;这不是所有系统均已实测的声明。Windows wheel 不能直接安装到 UOS,Linux 和各 CPU 架构需要相应 wheel 或从源码构建。原生计算期间释放 GIL;大批次分块计算可使用共享线程池,不创建 Python 编码子进程。mutable 输入在 Python 侧先快照。
|
|
237
|
+
|
|
238
|
+
运行时不依赖 based58 或 tqdm;原生库随 wheel 安装。交叉验证测试需要 based58,可安装本包的 test extra。已有桌面和邮件脚本仍使用原实现,接入本包时必须显式指定 mode='monero' 或使用 monero_encode/monero_decode,不能只替换默认普通模式函数。
|
|
239
|
+
|
|
240
|
+
## 验证与设计
|
|
241
|
+
|
|
242
|
+
使用公开合成数据进行测试和性能测量。基准工具 tools/benchmark.py 不读取私人文件。单元测试覆盖跨实现兼容、前导零、尾块、错误输入、自定义字母表、线程调用和参数契约。
|
|
243
|
+
|
|
244
|
+
完整设计、流式方案和平台验证计划见 [DESIGN.md](DESIGN.md)。来源、许可证及发行边界见 [PROVENANCE.md](PROVENANCE.md)。0.2.0 在 Windows / CPython 3.14 下通过 50 项 Python 测试,另通过 4 项 Rust 测试和 Clippy 检查。Rust 1.83.0 与 1.99 的 release 编译均通过。Linux/UOS wheel 尚需各平台构建验证。
|
|
245
|
+
|
|
246
|
+
文件转换按打开时的大小限制读取量,并在发布前检查读取字节数、文件大小和修改时间。持续追加不会让转换无限追赶;但这不是快照,无法保证识别恶意恢复元数据的改写。需要一致性时,先停止写入或使用文件系统快照。
|
|
247
|
+
|
|
248
|
+
Base58 不隐藏内容,也没有认证校验;合法字符的替换可能解码成不同数据而不报错。包不主动联网或记录输入正文,CLI 会显示调用错误和路径。内存不会专门擦除;临时文件清理失败时可能残留转换结果,权限由操作系统和目录规则共同决定。处理敏感数据时,应使用自己控制的目录,并检查 cleanup_error。
|
|
249
|
+
|
|
250
|
+
本机公开合成输入内存 API 中位数:8 MiB,0.1 编码 17.365 ms,0.2 自动编码 8.145 ms;32 MiB,69.287 ms → 31.508 ms。文件读入、编码、fsync 与发布:8 MiB 默认流水线约 18.789 ms,32 MiB 约 52.459 ms;整文件单线程基线分别为 27.352/101.765 ms。它们不是 UOS 性能承诺,也不表示普通格式获得了同样加速。
|
|
251
|
+
|
|
252
|
+
公开合成性能矩阵可运行 tools/benchmark_suite.py --output results.json;其中普通模式的大输入在有时间上限的子进程测试,超时表示该次完整测试未在窗口内结束,不伪造编码完成时间。线程比较复用线程池且不包含输入切分;文件测试区分缓存读取和 fsync 写出。
|
|
253
|
+
|
|
254
|
+
构建时建议在干净目录进行并重映射用户路径。生成 wheel 和 sdist 后执行:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
python tools/check_release.py dist/生成的.whl dist/生成的.tar.gz
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
若构建工具生成的 SBOM 含本地项目路径,在检查前规范化根项目引用(保留依赖关系并更新 RECORD):
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
python tools/prepare_wheel.py dist/生成的.whl
|
|
264
|
+
python tools/check_release.py dist/生成的.whl dist/生成的.tar.gz
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
发行检查会拒绝嵌套安装包、编译缓存、私人基准和 Windows 用户绝对路径。源码采用明确清单;wheel 的许可证放在 dist-info/licenses,避免安装到 site-packages 顶层。
|
|
268
|
+
|
|
269
|
+
0.3.0 可配置块长新增回归后,Windows / CPython 3.14 下通过 59 项 Python 测试、5 项 Rust 测试和 Clippy 检查。覆盖 1~64、127、256、4096 字节块长的参考比对、前导零、尾块、参数限制、流式/文件边界和并行一致性,以及随机非法输入、精确错误位置和最大值溢出边界。大块通用转换也直接写入预分配输出切片,不逐块分配结果 Vec。
|
|
270
|
+
|
|
271
|
+
发行名为 block58,Python 导入名也为 block58。Windows wheel 与源码包分别提供;Linux/UOS 需要对应平台构建。
|
|
272
|
+
|
|
273
|
+
0.4.0 安装到独立环境后通过 68 项 Python 测试,新增按行 CRLF/空行/长行、推算与验证区别、源文件追加拒绝、某行失败保留旧输出和中文 CLI 提示验证。Rust 核心规则未改变,Windows wheel 不适用于 Linux/UOS。
|
|
274
|
+
|
|
275
|
+
0.4.1 按此前风险结论增加大小上限和参考摘要检查,并改为逐个扫描换行、复用空记录的编码状态,降低大量空行的对象和初始化开销。独立环境 72 项 Python 测试通过,覆盖超限/摘要失败保留旧输出、错误块长摘要拒绝、info 无落盘校验及大量空行处理。
|
|
276
|
+
|
|
277
|
+
## 代码与许可证
|
|
278
|
+
|
|
279
|
+
分块循环、增量状态与文件流水线独立编写;普通模式依赖 bs58,绑定依赖 PyO3,并行调度依赖 Rayon。第三方许可随包保留在 THIRD_PARTY_LICENSES;Cargo.lock 固定构建依赖。自身代码采用 MIT 许可,不声称是 based58 或 Monero 官方项目。
|
|
280
|
+
|