Metadata-Version: 2.4
Name: block58
Version: 0.4.1
Requires-Dist: tqdm>=4.60 ; extra == 'progress'
Requires-Dist: based58>=0.1.1 ; extra == 'test'
Provides-Extra: progress
Provides-Extra: test
License-File: LICENSE
License-File: THIRD_PARTY_LICENSES/DEPENDENCIES.json
License-File: THIRD_PARTY_LICENSES/bs58-0.5.1-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/bs58-0.5.1-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/crossbeam-deque-0.8.8-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/crossbeam-deque-0.8.8-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/crossbeam-epoch-0.9.21-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/crossbeam-epoch-0.9.21-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/crossbeam-utils-0.8.23-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/crossbeam-utils-0.8.23-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/either-1.19.0-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/either-1.19.0-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/heck-0.5.0-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/heck-0.5.0-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/libc-0.2.190-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/libc-0.2.190-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/once_cell-1.21.4-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/once_cell-1.21.4-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/portable-atomic-1.15.0-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/portable-atomic-1.15.0-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/proc-macro2-1.0.107-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/proc-macro2-1.0.107-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/pyo3-0.28.3-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/pyo3-0.28.3-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/pyo3-build-config-0.28.3-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/pyo3-build-config-0.28.3-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/pyo3-ffi-0.28.3-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/pyo3-ffi-0.28.3-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/pyo3-macros-0.28.3-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/pyo3-macros-0.28.3-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/pyo3-macros-backend-0.28.3-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/pyo3-macros-backend-0.28.3-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/quote-1.0.47-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/quote-1.0.47-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/rayon-1.10.0-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/rayon-1.10.0-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/rayon-core-1.13.0-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/rayon-core-1.13.0-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/syn-2.0.119-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/syn-2.0.119-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/target-lexicon-0.13.5-LICENSE
License-File: THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-APACHE.md
License-File: THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-MIT.md
License-File: THIRD_PARTY_LICENSES/tinyvec-1.13.3-LICENSE-ZLIB.md
License-File: THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-APACHE
License-File: THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-MIT
License-File: THIRD_PARTY_LICENSES/unicode-ident-1.0.27-LICENSE-UNICODE
Summary: Rust-backed ordinary and Monero block Base58
License-Expression: MIT
Requires-Python: >=3.7
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# block58 0.4.1（PyPI 发行名：block58）

同一个 Python 包提供普通 Base58 和 Monero 8 字节分块 Base58。分块模式的完整循环在 Rust 内执行，一次提交大批数据，避免 Python 为每个块调用一次原生函数。

```python
from block58 import b58encode, b58decode, monero_encode, monero_decode

# 默认：全部字节作为一次普通 Base58 编码对象，与 based58 默认格式一致。
ordinary = b58encode(b'hello world')
assert ordinary == b'StV1DL6CwTryKyV'
assert b58decode(ordinary) == b'hello world'

# 可选：8 字节分块；整个循环在 Rust，沿用旧 Python 脚本的格式。
blocked = b58encode(b'hello world', mode='monero')
assert b58decode(blocked, mode='monero') == b'hello world'
assert monero_decode(monero_encode(b'hello world')) == b'hello world'
```

普通模式对大输入做整段转换，不能因为使用 Rust 就假定 MB 数据也会快速完成。MB 文件建议选择分块模式；这两种格式不互换，也没有自动模式识别。

## 查看编码信息与中文提示

```bash
# 按默认 8 字节分块规则推算，不实际解码
python -m block58 info output.b58

# 按指定规则实际流式解码检查；不生成文件，不打印解码正文
python -m block58 info output.b58 --block-size 16 --verify

# 含排版空白的整段编码文件
python -m block58 info output.b58 --ignore-whitespace --verify
```

纯 Base58 没有参数头，info 不会自动判断实际模式、块长或原始大小。它展示文件大小、编码字符数、所用参数假设，以及推算/实际解码后的字节数。不加 --verify 仅分析长度；非法字符或数值溢出可能尚未被发现。--verify 成功只说明指定参数下可解码，不能确认原始内容或完整性。文件 CLI/info 使用分块模式，普通整段 Base58 使用 Python b58encode/b58decode。

Python 同样可调用 `inspect_file('output.b58', block_size=16, verify=True)`，返回 FileInfo；`verified` 表示是否实际检查，`decoded_bytes=None` 表示无法按长度推算。info 不落盘，但检查源文件变化；输出保留明确的参数假设。

CLI 错误用中文解释原因与处理方法：目标已存在、权限不足、非法字符、尾部长度不符、溢出、源文件变化及无效参数。转换失败会说明本次未发布新输出；已有目标保留。发布成功后的进度/UI 错误则明确说明输出已生成。库异常类型保持兼容，未把所有底层异常改成中文。

## 可选大小上限与参考摘要校验

0.4.1 的文件接口和 info 支持 max_input_bytes / max_output_bytes（非负整数，默认 None 不限制），对应 CLI 的 --max-input-bytes / --max-output-bytes。输入上限按打开时文件大小检查；转换输出按批次检查，超过上限不发布并保留旧目标。它们不是 CPU 时间、内存或跨调用并发配额；一个计算批次可能先分配结果再发现超限，仍需按机器资源设置 chunk_size。

```bash
python -m block58 encode input.bin output.b58 --max-input-bytes 16777216 --max-output-bytes 33554432
python -m block58 decode output.b58 restored.bin --block-size 16 --expected-sha256 这里替换为原始文件的64位十六进制SHA256
python -m block58 info output.b58 --block-size 16 --verify --expected-sha256 这里替换为同一参考摘要
```

```python
from block58 import decode_file, inspect_file

# 从可信的独立记录获取，而不是信任待解码文件自己给出的摘要。
expected = '这里替换为原始文件的64位十六进制SHA256'
decode_file('output.b58', 'restored.bin', block_size=16,
            expected_sha256=expected, max_output_bytes=16 * 1024 * 1024)
info = inspect_file('output.b58', block_size=16, verify=True, expected_sha256=expected)
assert info.integrity_verified
```

摘要校验在发布前完成，错误块长或内容变化导致摘要不匹配时取消转换。摘要覆盖完整解码字节（按行模式包含保留的 LF/CRLF），无需改变旧编码格式。编码命令不接受参考解码摘要；info 必须启用 verify。错误提示不打印实际/参考摘要或解码正文。摘要比对不能代替加密、签名或可信来源；默认不自动生成或保存摘要文件。

## 每行独立转换

按行处理与输出自动换行是不同功能：每个 LF/CRLF 分隔的记录单独编码/解码，行内仍用所选固定字节块。空行、行首尾空格、末尾换行保留；裸 CR 作为数据。该行为不用于任意二进制文件的通用分割；此类文件继续用默认整段分块模式。

```bash
python -m block58 encode records.txt records.b58 --by-line --block-size 16
python -m block58 decode records.b58 restored.txt --by-line --block-size 16
python -m block58 info records.b58 --by-line --block-size 16 --verify
```

```python
from block58 import b58encode, b58decode, LineEncoder, LineDecoder

data = '你好\r\n世界\n\n'.encode('utf8')
encoded = b58encode(data, mode='block', block_size=16, by_line=True)
assert b58decode(encoded, mode='block', block_size=16, by_line=True) == data

# 普通 Base58 同样支持每行独立处理，方便与普通在线工具互操作。
ordinary = b58encode(data, by_line=True)
assert b58decode(ordinary, by_line=True) == data

# 流式按行接口只保留一个未完整的字节块及可能属于 CRLF 的 CR。
encoder = LineEncoder(block_size=16)
encoded = encoder.update(data[:5]) + encoder.update(data[5:]) + encoder.finalize()
decoder = LineDecoder(block_size=16)
assert decoder.update(encoded) + decoder.finalize() == data
```

文件接口使用 `encode_file(..., by_line=True)` / `decode_file(..., by_line=True)`；默认仍不按行。按行模式改变编码结果，解码必须启用相同模式。如果只是长编码字符串被排版换行，用 --ignore-whitespace 解码整段，不要使用 --by-line。某行失败会取消本次整个文件转换，不发布混有错误文本的部分结果。按行自定义字母表不能含 CR/LF，以免与记录分隔符混淆。

## 可配置块长

0.3.0 新增 `mode='block'` 和 `block_size`，支持 1～4096 字节，省略块长时默认 8。原来的 `mode='monero'` 固定 8 字节；普通和 Monero 模式不接受 block_size，避免参数被静默忽略。

```python
from block58 import b58encode, b58decode, BlockEncoder, BlockDecoder
from block58 import encode_file, decode_file

data = b'hello world' * 100
encoded = b58encode(data, mode='block', block_size=16)
assert b58decode(encoded, mode='block', block_size=16) == data

encoder = BlockEncoder(block_size=16)
encoded = encoder.update(data[:19]) + encoder.update(data[19:]) + encoder.finalize()
decoder = BlockDecoder(block_size=16)
assert decoder.update(encoded) + decoder.finalize() == data

encode_file('input.bin', 'output.b58', block_size=16)
decode_file('output.b58', 'restored.bin', block_size=16)
```

```bash
python -m block58 encode input.bin output.b58 --block-size 16
python -m block58 decode output.b58 restored.bin --block-size 16
```

每个 n 字节块左侧补齐到能够容纳 `256**n-1` 的最小 Base58 字符宽度；尾块按实际字节数确定宽度。例：8 字节对应 11 字符，16 字节对应 22 字符。块长不写入输出，解码必须自行记住相同块长；错误块长不保证报错。

`block_size` 决定编码格式，`chunk_size` 只决定文件每批读取多少。8 字节复用原 u64 快速路径；其他不超过 16 字节的块使用 u128，较大的块用通用多字节转换。可配置模式也使用共享线程池。更大块长不保证提速；默认 8 字节保持原有兼容性和性能路径。

## 自动并行与流式文件工具

分块 API 增加 workers：0 为自动，1 为单线程，2～8 为请求的并行任务上限；实际不超过系统可用核心数和共享池的 8 线程上限。输入不足 1 MiB 时走单线程，超过阈值才使用懒初始化的共享 Rayon 池。线程创建失败安全回到单线程，不改变格式。普通模式只接受 workers=0/1，不对整段输入拆分编码。

```python
from block58 import monero_encode, monero_decode, MoneroEncoder
from block58 import encode_file, decode_file

encoded = monero_encode(data, workers=0)  # 自动使用合适的原生并行路径
assert monero_decode(encoded, workers=0) == data

# 输入批次可以不是 8 的倍数：增量编码器会保留不足一块的尾部。
stream = MoneroEncoder(workers=0)
encoded = stream.update(b'hello') + stream.update(b' world') + stream.finalize()

# 文件接口默认使用 Monero 格式、4 MiB 批次和有界读/算/写流水线。
result = encode_file('input.bin', 'output.b58')
decode_file('output.b58', 'restored.bin')
```

MoneroDecoder 支持同样的 update/finalize 与可选 ignore_whitespace。finalize 只调用一次；失败后的流不可重用。单个流实例的状态串行化，但并发调用不能代替调用者管理输入顺序。

文件目标存在时默认报错。显式 overwrite=True 支持覆盖，也支持输入输出同一路径。结果验证和刷盘完成后才发布；不覆盖发布采用同目录硬链接排他创建，文件系统不支持时明确报错，不使用存在竞态的降级实现。中途错误/取消清理临时输出；发布之后的 UI 或临时名清理故障分别记录为 FileResult.progress_error/cleanup_error。源文件大小/mtime 检查可发现普通变更，不保证对抗恶意并发写入的完整快照。

```bash
python -m block58 encode input.bin output.b58 --workers 0
python -m block58 decode output.b58 restored.bin --workers 0
python -m block58 decode formatted.b58 restored.bin --ignore-whitespace --overwrite
```

CLI 仅在交互终端显示进度，显示需要安装 progress extra（tqdm）；--no-progress 可禁用，重定向时自动不显示。进度按批次更新，100% 在发布成功后报告。可用 --no-pipeline、--chunk-size 和 --workers 1 分别比较顺序 IO、批次大小与单线程。

原生 API 一次性输入仍使用整块内存；文件接口只保留少量批次，内存规模由 chunk_size 控制。单次原生调用不是瞬时可取消的任务，文件处理在批次边界响应取消。

输入接受 bytes、bytearray、memoryview；解码另接受 ASCII str；返回均为 bytes。非法 mode、字母表、字符、尾块长度或溢出会报错。默认不接受排版空白，读取邮件文本时可显式指定 ignore_whitespace=True；不会忽略 Unicode 空白。

## 兼容性

默认字母表为 Bitcoin/Monero 使用的 58 字符序列。Monero 模式完整块为 8 字节对应 11 字符；尾块长度映射为 0,2,3,5,6,7,9,10,11。保持大端数值解释及前导零，与此前 file_base58_enc.py/file_base58_dec.py 相同。

可传 alphabet=58 个不同 ASCII 字节，自定义时编码与解码必须保持一致。只有默认字母表输出承诺与现有文件兼容。

这不是 Monero 地址完整生成器，不自动加入地址网络前缀或校验和，也不提供加密功能。

## 编译和安装

安装构建依赖 maturin，然后在本目录运行：

```bash
python -m maturin build --release
python -m pip install 路径/生成的.whl
python -m unittest discover -s tests -v
```

包使用 PyO3 0.28.3 和 CPython abi3-py37，目标 ABI 为 CPython 3.7+；这不是所有系统均已实测的声明。Windows wheel 不能直接安装到 UOS，Linux 和各 CPU 架构需要相应 wheel 或从源码构建。原生计算期间释放 GIL；大批次分块计算可使用共享线程池，不创建 Python 编码子进程。mutable 输入在 Python 侧先快照。

运行时不依赖 based58 或 tqdm；原生库随 wheel 安装。交叉验证测试需要 based58，可安装本包的 test extra。已有桌面和邮件脚本仍使用原实现，接入本包时必须显式指定 mode='monero' 或使用 monero_encode/monero_decode，不能只替换默认普通模式函数。

## 验证与设计

使用公开合成数据进行测试和性能测量。基准工具 tools/benchmark.py 不读取私人文件。单元测试覆盖跨实现兼容、前导零、尾块、错误输入、自定义字母表、线程调用和参数契约。

完整设计、流式方案和平台验证计划见 [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 尚需各平台构建验证。

文件转换按打开时的大小限制读取量，并在发布前检查读取字节数、文件大小和修改时间。持续追加不会让转换无限追赶；但这不是快照，无法保证识别恶意恢复元数据的改写。需要一致性时，先停止写入或使用文件系统快照。

Base58 不隐藏内容，也没有认证校验；合法字符的替换可能解码成不同数据而不报错。包不主动联网或记录输入正文，CLI 会显示调用错误和路径。内存不会专门擦除；临时文件清理失败时可能残留转换结果，权限由操作系统和目录规则共同决定。处理敏感数据时，应使用自己控制的目录，并检查 cleanup_error。

本机公开合成输入内存 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 性能承诺，也不表示普通格式获得了同样加速。

公开合成性能矩阵可运行 tools/benchmark_suite.py --output results.json；其中普通模式的大输入在有时间上限的子进程测试，超时表示该次完整测试未在窗口内结束，不伪造编码完成时间。线程比较复用线程池且不包含输入切分；文件测试区分缓存读取和 fsync 写出。

构建时建议在干净目录进行并重映射用户路径。生成 wheel 和 sdist 后执行：

```bash
python tools/check_release.py dist/生成的.whl dist/生成的.tar.gz
```

若构建工具生成的 SBOM 含本地项目路径，在检查前规范化根项目引用（保留依赖关系并更新 RECORD）：

```bash
python tools/prepare_wheel.py dist/生成的.whl
python tools/check_release.py dist/生成的.whl dist/生成的.tar.gz
```

发行检查会拒绝嵌套安装包、编译缓存、私人基准和 Windows 用户绝对路径。源码采用明确清单；wheel 的许可证放在 dist-info/licenses，避免安装到 site-packages 顶层。

0.3.0 可配置块长新增回归后，Windows / CPython 3.14 下通过 59 项 Python 测试、5 项 Rust 测试和 Clippy 检查。覆盖 1～64、127、256、4096 字节块长的参考比对、前导零、尾块、参数限制、流式/文件边界和并行一致性，以及随机非法输入、精确错误位置和最大值溢出边界。大块通用转换也直接写入预分配输出切片，不逐块分配结果 Vec。

发行名为 block58，Python 导入名也为 block58。Windows wheel 与源码包分别提供；Linux/UOS 需要对应平台构建。

0.4.0 安装到独立环境后通过 68 项 Python 测试，新增按行 CRLF/空行/长行、推算与验证区别、源文件追加拒绝、某行失败保留旧输出和中文 CLI 提示验证。Rust 核心规则未改变，Windows wheel 不适用于 Linux/UOS。

0.4.1 按此前风险结论增加大小上限和参考摘要检查，并改为逐个扫描换行、复用空记录的编码状态，降低大量空行的对象和初始化开销。独立环境 72 项 Python 测试通过，覆盖超限/摘要失败保留旧输出、错误块长摘要拒绝、info 无落盘校验及大量空行处理。

## 代码与许可证

分块循环、增量状态与文件流水线独立编写；普通模式依赖 bs58，绑定依赖 PyO3，并行调度依赖 Rayon。第三方许可随包保留在 THIRD_PARTY_LICENSES；Cargo.lock 固定构建依赖。自身代码采用 MIT 许可，不声称是 based58 或 Monero 官方项目。

