#blake3 #hash #hash-tree #tree-hash #slice #streaming #bao

应用 bao_bin

bao crate的一部分命令行实用工具

12个版本 (破坏性)

0.12.1 2022年7月14日
0.12.0 2021年9月16日
0.11.0 2021年7月17日
0.10.1 2020年2月27日
0.5.0 2018年11月1日

#1386 in 密码学

Download history 3/week @ 2024-03-27 5/week @ 2024-04-03

每月55次下载

CC0-1.0 OR Apache-2.0

125KB
2K SLoC

Bao   Actions Status docs.rs crates.io

Bao 规范Rust 库Rust 文档

Bao 是根据《BLAKE3 规范》第6.4节描述的BLAKE3验证流式处理的实现。类似于BLAKE3的树哈希使得在不重新哈希整个文件的情况下验证文件的一部分成为可能,使用一种编码格式,该格式存储文件的字节以及其哈希树的所有节点。客户端可以流式传输此编码,或者在其中进行随机搜索,同时验证它们读取的每个字节是否与根哈希匹配。关于如何实现这一点的详细信息,请参阅Bao 规范

此项目包括两个Rust库,分别是bao库和bao_bin二进制库。后者提供了bao命令行实用工具。

注意! Bao 是beta版密码学软件。它尚未经过正式审计。

编码和解码

用例:一个安全消息应用可能通过在消息元数据中包含附件的哈希来支持附件文件。使用序列哈希,接收者需要下载整个附件来验证它,但这对于大型视频文件等来说可能不太实用。使用BLAKE3和Bao,接收者可以流式传输视频附件,同时仍然验证每个字节。 (这是Bao项目的原始动机。)

# Create an input file that's a megabyte of random data.
> head -c 1000000 /dev/urandom > f

# Convert it into a Bao encoded file.
> bao encode f f.bao

# Compare the size of the two files. The encoding overhead is small.
> stat -c "%n %s" f f.bao | column -t
f       1000000
f.bao   1062472

# Compute the BLAKE3 hash of the original file. The `b3sum` tool would
# also work here.
> hash=`bao hash f`

# Stream decoded bytes from the encoded file, using the hash above.
> bao decode $hash < f.bao > f2
> cmp f f2

# Observe that using the wrong hash to decode results in an error. This
# is also what will happen if we use the right hash but corrupt some
# bytes in the encoded file.
> bad_hash="0000000000000000000000000000000000000000000000000000000000000000"
> bao decode $bad_hash < f.bao
Error: Custom { kind: InvalidData, error: StringError("hash mismatch") }

验证切片

编码文件支持随机定位,但通过网络进行定位可能不可用或效率不高。(请注意,内容中的每次定位通常需要在编码中执行多次定位,因为解码器逐级遍历哈希树。)在这种情况下,而不是尝试远程定位,客户端可以请求包含所需内容字节的编码切片。创建切片需要发送方在完整编码中进行定位,但接收方可以流式传输切片而无需进行任何定位。解码切片使用与常规解码相同的根哈希,因此不需要发送方或接收方提前进行任何准备。

用例:一个类似BitTorrent的应用程序可以从不同的对等点获取文件的不同切片,而无需提前定义切片。或者,一个分布式文件存储应用程序可以从其存储提供商请求归档文件的随机切片,以证明他们诚实地存储了文件,而无需为未来准备或存储挑战。

# Using the encoded file from above, extract a 100 KB slice from
# somewhere in the middle. We'll use start=500000 (500 KB) and
# count=100000 (100 KB).
> bao slice 500000 100000 f.bao f.slice

# Look at the size of the slice. It contains the 100 KB of content plus
# some overhead. Again, the overhead is small.
> stat -c "%n %s" f.slice
f.slice 107272

# Using the same parameters we used to create the slice, plus the same
# hash we got above from the full encoding, decode the slice.
> bao decode-slice $hash 500000 100000 < f.slice > f.slice.out

# Confirm that the decoded output matches the corresponding section from
# the input file. (Note that `tail` numbers bytes starting with 1.)
> tail --bytes=+500001 f | head -c 100000 > expected.out
> cmp f.slice.out expected.out

# Now try decoding the slice with the wrong hash. Again, this will fail,
# as it would if we corrupted some bytes in the slice.
> bao decode-slice $bad_hash 500000 100000 < f.slice
Error: Custom { kind: InvalidData, error: StringError("hash mismatch") }

外置模式

默认情况下,上述所有操作都使用一个“组合”编码文件,即包含内容字节和树哈希字节交织在一起的文件。然而,有时您希望将它们分开,例如,为了避免重复一个非常大的输入文件。在这些情况下,您可以使用“外置”编码格式,通过--outboard标志

# Re-encode the input file from above in the outboard mode.
> bao encode f --outboard f.obao

# Compare the size of all these files. The size of the outboard file is
# equal to the overhead of the original combined file.
> stat -c "%n %s" f f.bao f.obao | column -t
f       1000000
f.bao   1062472
f.obao  62472

# Decode the whole file in outboard mode. Note that both the original
# input file and the outboard encoding are passed in as arguments.
> bao decode $hash f --outboard f.obao f4
> cmp f f4

安装和从源码构建

命令行工具bao作为bao_bin发布在crates.io上。要安装它,将~/.cargo/bin添加到您的PATH,然后运行

cargo install bao_bin

直接从该仓库构建二进制文件

git clone https://github.com/oconnor663/bao
cd bao/bao_bin
cargo build --release
./target/release/bao --help

tests/bao.py是Python的一个完全功能性的第二实现,旨在尽可能短小和易读。它是理解涉及算法的好起点,然后再深入研究Rust代码。

依赖项

~5–7MB
~138K SLoC