Documentation
¶
Overview ¶
Package sdhash implements the sdhash similarity digest algorithm.
sdhash produces compact bloom-filter-based fingerprints of binary data that can be compared to produce a similarity score in the range [0, 100]. A score of 100 means the inputs are identical; a score of 0 means they share no detectable similarity.
This is a focused implementation of the core digest algorithm. It has no CLI, no index, and no filesystem dependencies. It takes bytes in and returns digest strings out.
Modes ¶
Stream mode (default) treats the input as a single stream and produces a digest representing the file as a whole. DD mode (WithBlockSize) divides the input into fixed-size blocks and produces one bloom filter per block, enabling localized similarity detection.
Usage ¶
factory, err := sdhash.New(data)
if err != nil {
log.Fatal(err)
}
digest, err := factory.Compute()
if err != nil {
log.Fatal(err)
}
fmt.Println(digest.String())
score, ok := digest1.Compare(digest2)
Degenerate digests ¶
Low-entropy or repetitive input may produce digests without enough features for meaningful comparison. Use FeatureDensity to detect these cases before trusting a score. See the README for threshold guidance.
C++ reference compatibility ¶
CompareRef provides a scoring path that reproduces the exact behavior of the C++ sdhash reference implementation. It differs from Compare in two scoring behaviors — a staged early-exit heuristic in the AND-popcount calculation and conditional score-accumulation semantics — and in its return convention: a single int with -1 as a degenerate sentinel, versus Compare's (score, ok).
The modern construction path also diverges from the reference: New fixes a sliding-window feature-selection double-count on equal-rank runs that the C++ digester exhibits (issue #57), which changes digest output. NewRef reproduces the C++ construction byte-for-byte, so full C++ parity requires NewRef digests scored with CompareRef.
CompareRef exists for cross-validation against C++ reference output and for comparing digests originally produced by the C++ implementation. For all new work, prefer Compare which returns (score, ok).
NewRef and CompareRef are part of the C++ reference-compatibility surface, frozen at v0.6.0 and removed in v1.0.0. Pin to v0.6.0 to retain them; see the README for migration guidance.
Concurrency ¶
Every method on Sdbf is safe for concurrent use. Each Compute call produces an independent digest with no shared state. The recommended pattern for high-throughput processing is one goroutine per input.
Index ¶
- Constants
- Variables
- func CompareDebug(s1, s2 Sdbf) (int, bool)deprecated
- func DDBlockSize(s Sdbf) uint32
- func ElemCount(s Sdbf, index uint32) uint32
- func Hamming(s Sdbf, index uint32) uint16
- func LastCount(s Sdbf) uint32
- func MaxElem(s Sdbf) uint32
- func TotalElements(s Sdbf) uint64
- type Sdbf
- type SdbfFactory
Constants ¶
const (
// MinFileSize is the minimum input size (in bytes) required to compute a digest.
MinFileSize = 512
)
Variables ¶
var DebugRevertAdditiveAccumulation bool
DebugRevertAdditiveAccumulation makes CompareDebug use the C++-faithful conditional-first-assignment accumulation pattern instead of the modern additive accumulation from zero when true. Additive accumulation is the correct algorithm; the C++ pattern was a defect. Used for demonstrations.
Default: false.
var DebugRevertChunkScoresDoubleCount bool
DebugRevertChunkScoresDoubleCount makes NewDebug construct digests using the C++-faithful two-block chunk-score feature selection instead of the modern one-increment-per-window selection when true. The C++ two-block algorithm double-counts positions in equal-rank runs; the modern algorithm is the correct one. Unlike the other toggles this affects hashing (digest construction), not scoring, so it changes which features a digest contains.
Default: false.
var DebugRevertExactPopcount bool
DebugRevertExactPopcount makes CompareDebug use the C++-faithful staged early-exit popcount heuristic (andPopcountCut screening before exact andPopcount) instead of the modern exact popcount directly when true. Exact popcount is the correct algorithm; the C++ heuristic traded correctness for performance. Used for demonstrations.
Default: false.
Functions ¶
func CompareDebug
deprecated
added in
v0.6.0
CompareDebug performs a pairwise comparison using a toggle-gated variant of the modern Compare algorithm. When both toggles are at their default false values, CompareDebug produces output identical to Compare. Individual toggles revert specific fixes:
- DebugRevertAdditiveAccumulation: when true, reverts to the C++ conditional-first-assignment accumulation pattern.
- DebugRevertExactPopcount: when true, reverts to the C++ staged early-exit popcount heuristic (andPopcountCut screening before exact andPopcount).
This function is used exclusively for the handoff scoring investigation and for demonstrations. It is not part of the library's public scoring API.
Deprecated: CompareDebug is part of the debug surface, frozen at v0.6.0 and removed in v1.0.0. Pin to v0.6.0 to retain it. It is an A/B demonstration tool with no public replacement; use Compare.
func DDBlockSize ¶ added in v0.6.0
DDBlockSize returns the DD-mode block size in bytes, or 0 for stream-mode digests.
func ElemCount ¶ added in v0.6.0
ElemCount returns the element count of the bloom filter at the given index. Callers must ensure 0 <= index < FilterCount(s).
func Hamming ¶ added in v0.6.0
Hamming returns the Hamming weight (number of set bits) of the bloom filter at the given index. Callers must ensure 0 <= index < FilterCount(s).
func LastCount ¶ added in v0.6.0
LastCount returns the element count of the final bloom filter. In stream mode this is the tail filter's count; in DD mode it is always 0.
func MaxElem ¶
MaxElem returns the per-filter element saturation cap configured for this digest. This is 160 for stream-mode digests and 192 for DD-mode digests.
func TotalElements ¶ added in v0.6.0
TotalElements returns the sum of element counts across all bloom filters in the digest. This is the numerator of FeatureDensity (FeatureDensity returns TotalElements / InputSize).
Types ¶
type Sdbf ¶
type Sdbf interface {
// FilterSize returns the total byte size of the bloom filter data within this Sdbf.
FilterSize() uint64
// InputSize returns the size of the original data this Sdbf was generated from.
InputSize() uint64
// FilterCount returns the number of bloom filters in this Sdbf.
FilterCount() uint32
// Compare returns a similarity score in [0, 100] between this Sdbf and other,
// and a boolean indicating whether the comparison was meaningful. Returns
// (0, false) if other is nil, was not produced by this package, or if both
// digests are degenerate and all filters fall below the minimum element
// threshold.
Compare(other Sdbf) (int, bool)
// CompareRef returns the similarity score between this Sdbf and other
// using C++-reference-compatible semantics. The returned int is in
// [0, 100] for a valid comparison, or -1 if the comparison is
// degenerate (all filters below the minimum element threshold).
//
// It was built during the reference-correctness phase of the port to
// support external test harnesses that compared the Go library's
// output byte-for-byte against the C++ reference via CSV diffing. Its
// return shape matches the C++ compare() method exactly.
//
// Deprecated: CompareRef is part of the C++ reference-compatibility
// surface, frozen at v0.6.0 and removed in v1.0.0. Pin to v0.6.0 to
// retain it. New code should use Compare, which returns (score, ok)
// in idiomatic Go form.
CompareRef(other Sdbf) int
// String returns the digest encoded as a string in the sdbf wire format.
String() string
// FeatureDensity returns the ratio of total unique features inserted across
// all bloom filters to the original input size. A low value indicates the
// digest is degenerate — the input was too repetitive, low-entropy, or small
// to produce enough features for a meaningful similarity comparison. Callers
// should check this value and treat digests below a corpus-appropriate
// threshold as unreliable.
FeatureDensity() float64
}
Sdbf represents the similarity digest of a file or byte buffer. Two Sdbf values can be compared to produce a score indicating how similar their source data is.
Sdbf values are immutable after construction. Every method is safe for concurrent use by multiple goroutines because no field is ever written after the factory returns.
func ParseSdbfFromReader ¶ added in v0.3.0
ParseSdbfFromReader decodes a single Sdbf from a reader in sdbf wire format. The reader is consumed through the end of the digest, including the trailing newline if present. For files containing multiple digests, call this function repeatedly until io.EOF is encountered.
func ParseSdbfFromString ¶
ParseSdbfFromString decodes a Sdbf from a digest string in sdbf wire format.
type SdbfFactory ¶
type SdbfFactory interface {
// WithBlockSize sets the block size for block-aligned (dd) mode and returns
// a new factory with that configuration applied. A value of 0 (the default)
// produces a digest in stream mode.
WithBlockSize(blockSize uint32) SdbfFactory
// Compute runs the digesting process and returns the resulting Sdbf.
Compute() (Sdbf, error)
}
SdbfFactory creates a Sdbf digest from a binary source. Use WithBlockSize to configure the factory before calling Compute.
Factories are immutable: WithBlockSize returns a new factory rather than modifying the receiver, so all methods are inherently safe for concurrent use.
func New ¶ added in v0.3.0
func New(buffer []byte) (SdbfFactory, error)
New returns a factory that will produce a Sdbf from the given byte slice. The slice must be at least MinFileSize bytes.
func NewDebug
deprecated
added in
v0.6.0
func NewDebug(buffer []byte) (SdbfFactory, error)
NewDebug returns a factory that produces a Sdbf using the toggle-gated construction path. See DebugRevertChunkScoresDoubleCount.
Deprecated: NewDebug is part of the debug surface, frozen at v0.6.0 and removed in v1.0.0. Pin to v0.6.0 to retain it. New code should use New, which produces the modern digest.
func NewRef
deprecated
added in
v0.6.0
func NewRef(buffer []byte) (SdbfFactory, error)
NewRef returns a factory that produces a Sdbf using the C++-reference- compatible construction path (the pre-fix chunk-score feature selection). It is the construction-side analogue of CompareRef: it was built during the reference-correctness phase so external harnesses could compare the Go library's digests byte-for-byte against the C++ reference.
Deprecated: NewRef is part of the C++ reference-compatibility surface, frozen at v0.6.0 and removed in v1.0.0. Pin to v0.6.0 to retain it. New code should use New, which produces the modern digest.