1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! Truncated value fingerprint (spec §10.4).
//!
//! A short hash of a **literal** secret value, so an operator can verify "did I
//! update to the right value?" without revealing it. Deliberately **truncated**
//! (leading bytes of BLAKE3) so it cannot ease brute-forcing the value, and so
//! it is safe to store in the index and surface in `list`/`doctor` output
//! (I12). It is never the full hash.
//!
//! References carry no value, so they have no fingerprint.
//!
//! **Accepted residual (security audit, INFO).** The fingerprint is an *unsalted*
//! 32-bit BLAKE3 prefix, so a holder of a *candidate* value can confirm a guess
//! against a stored fingerprint (hash the guess, compare the prefix) with a
//! ~2^-32 false-positive rate. For a high-entropy secret this leaks nothing; for
//! a **low-entropy** secret drawn from a small known set it is a confirmation
//! oracle (it cannot *recover* the value, only confirm an already-guessed one).
//! This is inherent to any "did the value change?" marker and is **accepted by
//! design** — the alternative (a per-vault *keyed* BLAKE3) would break every
//! stored fingerprint in the index and audit log (a vault migration) to harden a
//! low-stakes, low-entropy-only case. Revisit if fingerprints are ever
//! recomputed for another reason.
/// Number of leading BLAKE3 bytes kept in a fingerprint. Truncated on purpose
/// (§10.4): enough to detect a change, too short to brute-force the value.
pub const FINGERPRINT_BYTES: usize = 4;
/// Truncated, lowercase-hex BLAKE3 fingerprint of a literal value.
///
/// Deterministic and stable across runs (no salt, no nonce) — re-fingerprinting
/// the same bytes always yields the same string, which is what makes "did the
/// value change?" answerable without the value. The output is
/// `FINGERPRINT_BYTES * 2` hex characters.