sdigest
Fast, tunable sparse digests. sdigest fingerprints a file by hashing
its size and a deterministic sample of its content with BLAKE3, instead of
every byte. That is often orders of magnitude faster than sha512sum,
and enough to tell most non-identical files apart.
$ sdigest -l 0 *.flac
sd1:31457806:0:9f2c…41e7 a.flac
sd1:31457806:0:9f2c…41e7 b.flac
sd1:28011203:0:03ab…c9d0 c.flac
sdigest: 3 files, 85.7 MiB in 0.01 s (8.4 GiB/s); coverage 0%, read 384 KiB (0.437%)
On a USB 3 hard disk with a cold page cache, level 0 fingerprinted 3,534 audio files (28.1 GiB) in 56 s. Its cost depends on the number of files, not their size: two 64 KiB reads per file, at the 100–170 reads per second this disk managed. Full reads on the same drive ran at about 140 MiB/s, so level 0 wins for files over about 2 MB, by more as files grow. On a 176 GiB archive, level 0 found exactly the same possible duplicates as full digests did. Details and conditions are in the design notes and #3.
Interpreting sdigests
An sdigest is evidence that content differs, never proof that it is the same.
- Different sizes, or the same coverage with different digests: the content differs. This is certain.
- Equal fingerprints: the content may be identical. Unrelated files
almost always differ even at level 0, but small edits that keep the size
can fall between samples. Sparse digests are not collision-resistant
against deliberate tampering. Confirm with
cmpwhen a false match would be costly. - Same size, different coverage: no conclusion, unless both coverages
sample the same blocks (
may_equalchecks this).
Install
uvx sdigest FILE... # run without installing (prebuilt wheels, no Rust needed)
uv tool install sdigest # install the sdigest command
pip install sdigest # Python module and command
cargo install sdigest # build the command from source
The sdigest command is identical however it is installed.
Use
sdigest -l 0 FILE... # levels 0-9; default 5 (1% coverage)
sdigest -c 2.5 FILE... # or an exact coverage percent
find . -type f -print0 | sdigest -0 # names on stdin
sdigest FILE... > sums && sdigest -k sums # check later, like sha512sum -c
| level | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
| coverage % | 0 | 0.01 | 0.03 | 0.1 | 0.3 | 1 | 3 | 10 | 30 | 100 |
Level 0 hashes the size plus the first and last 64 KiB. Level 9 hashes everything.
from sdigest import may_equal, sdigest
a = sdigest("a.flac", level=0) # path
b = sdigest(open("b.flac", "rb"), level=0) # or any seekable binary file object
may_equal(a, b) # True, False, or None (not comparable)
let fp = sdigest::digest_path(path, sdigest::Coverage::from_level(0)?)?;
For Rust library use without the CLI dependencies, use
default-features = false.
Documentation
doc/design.md: motivation, design, decisions and rationaledoc/sdigest.1: man page (man -l doc/sdigest.1)
Development
Tasks are just recipes, and CI runs the same ones.
Install just with uv tool install rust-just, cargo install just, or
your package manager.
just # list recipes
just devready # create .venv (builds the extension) and install git hooks
just cqa # lockfile, lint and format checks on all files
just cqa --from-ref main # ... or only on files changed since main
just test # Rust and Python tests
just build # check packaging: crate, sdist, wheel
Releases: push a semver tag, e.g. git tag 1.2.3 && git push --tags (no
v; pre-releases look like 1.2.3-rc.1). The tag is the only source of
truth for the version: Cargo.toml holds 0.0.0, CI writes the tag into it
before building, and CI publishes the crate and the Python wheels using
trusted publishing (no stored tokens). Development builds describe
themselves relative to the latest tag, e.g. 0.2.1-dev.3+g4b551b3.
Metadata
Release files for sdigest 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sdigest-0.2.2.tar.gz | 36.5 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| sdigest-0.2.2-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| sdigest-0.2.2-cp310-abi3-musllinux_1_2_x86_64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ x86-64 | Details |
| sdigest-0.2.2-cp310-abi3-musllinux_1_2_aarch64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ ARM64 | Details |
| sdigest-0.2.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| sdigest-0.2.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| sdigest-0.2.2-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| sdigest-0.2.2-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 4.7 MB
Release files / sdigest-0.2.2.tar.gz
| Download URL | sdigest-0.2.2.tar.gz |
|---|---|
| Size | 36.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7e08358ca3770a51f914cfa4705699740beea9883627105d88e1f7319c24a348
|
|
BLAKE2b-256 checksum How to use checksums |
4f11a429555c82520a1e4ad450e65480c2a04b8f9ae417707bbeef3366b8e709
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sdigest-0.2.2-cp310-abi3-win_amd64.whl
| Download URL | sdigest-0.2.2-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 531.0 kB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
27722a6385910c5447ea1455318add5f3326119dc4a109755e111749799d3ac4
|
|
BLAKE2b-256 checksum How to use checksums |
cac78b02d05e7f86d0947a4b01e9443f285b86cd267f0ab0d693820f973a80de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sdigest-0.2.2-cp310-abi3-musllinux_1_2_x86_64.whl
| Download URL | sdigest-0.2.2-cp310-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 860.2 kB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a33dd1e432bb1ac8713b453d04b10c8fb6a75127940f4d295c102228ba988e20
|
|
BLAKE2b-256 checksum How to use checksums |
7cdc51e4cc0042e4fbee3414a9c3de4775838efc33ad6767e8c6c808da250b34
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sdigest-0.2.2-cp310-abi3-musllinux_1_2_aarch64.whl
| Download URL | sdigest-0.2.2-cp310-abi3-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 795.0 kB |
| Tags | CPython 3.10 Linux musl 1.2+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
42823967f2c7e3fc67c0aad28b94b3c75593f9112eaf0e80adac9875b7d73f4f
|
|
BLAKE2b-256 checksum How to use checksums |
d50fd5cf8cb0d43b85c2dc31b0714b3d65c9059251ddcce5fe7819e7824bee44
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sdigest-0.2.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | sdigest-0.2.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 649.3 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a004d6f9e165dad2c7d8fc4ffd46ace51a07d2c41c451c93d0a4cd597cd735f4
|
|
BLAKE2b-256 checksum How to use checksums |
f0be857b34759aa4a7f91859577e45768fbb28b49233c9b5bba76800f073bfef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sdigest-0.2.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | sdigest-0.2.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 619.3 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
d5956cc2214623c917be258641922054c687a892a2ca238c04ef2d3153dfc384
|
|
BLAKE2b-256 checksum How to use checksums |
c1d0ef12356d7c2e94e558cbf06eba016a0013f90d911319afa2ba7f4aee3656
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sdigest-0.2.2-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | sdigest-0.2.2-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 572.3 kB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
416aa3569c322f1f13b7d51615896bc4fd26e5d53f2e3338f4c41fc0675a96f2
|
|
BLAKE2b-256 checksum How to use checksums |
018487a00500623d72cca1c9317f6f10db9de737faa30811c19e8b8663036afd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sdigest-0.2.2-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | sdigest-0.2.2-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 608.0 kB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
d96cd377896aed80d8a38149674f75f36c909f09d1600c1ba666b7e13dc83479
|
|
BLAKE2b-256 checksum How to use checksums |
e544b3013e4c1391251604017c4ae468bdff641a4b2119468880e05d95640454
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|