tlsh_fixed/lib.rs
1//! # Trend Micro Locality Sensitive Hashing
2//! This is a Rust port of TLSH algorithm. The crate can compute a hash value of a input byte array
3//! and measure the difference between two hash values.
4//!
5//! The current implementation of TLSH has two conditions on the file size:
6//! - the input must be at least 50 bytes long
7//! - the size must not exceed 4Gb.
8//!
9//! ## Algorithm
10//!
11//! The algorithm to construct a TLSH digest is as follows (for more detail, see [J. Oliver et al.](https://documents.trendmicro.com/assets/wp/wp-locality-sensitive-hash.pdf)):
12//! - **Step 1**: processes an input stream by using a sliding window of length 5 and populates the hash buckets.
13//! Each triplet is passed through a hash function (in this implementation, the hash function is the [Pearson hashing](https://en.wikipedia.org/wiki/Pearson_hashing)).
14//! - **Step 2**: calculates the quartile points from the hash bucket obtained in step 1. This step might requires the sorting of the bucket array:
15//! ```q1```: the lowest 25% of the array
16//! ```q2```: the lowest 50% of the array
17//! ```q3```: the lowest 75% of the array
18//! - **Step 3**: computes the digest header. The first three bytes of a hash is reserved for the header. The header of a TLSH hash consists of three parts:
19//! - The first byte is a checksum (with some modulo) of the byte string
20//! - The second byte is computed from the logarithm of the byte string's length (with some modulo)
21//! - The third byte is the result of ```q1_ratio <<< 4 | q2_ratio```, where
22//! ```q1_ratio = (q1 * 100 / q3) MOD 16```
23//! ```q2_ratio = (q2 * 100 / q3) MOD 16```
24//! - **Step 4**: constructs the digest body from the bucket array. Note: in this step, the reversing order in reading the bucket is assumed. This means, the last element is read first while the first is read last. Their value is converted into hex form and appended into the final hash value.
25//!
26//! ## Examples
27//! To compute a hash value of a string, we will create an instance of [`TlshBuilder`]. After all
28//! input data are pushed into the builder, we can construct an instance of [`Tlsh`]:
29//! ```
30//! use tlsh::{Tlsh, Version, BucketKind, ChecksumKind, TlshBuilder};
31//!
32//! let s1 = "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...";
33//! let mut builder = TlshBuilder::new(
34//! BucketKind::Bucket128,
35//! ChecksumKind::OneByte,
36//! crate::tlsh::Version::Version4,
37//! );
38//! builder.update(s1.as_bytes());
39//! let tlsh1 = builder.build().unwrap();
40//!
41//! let s2 = "Morbi rhoncus ex mi, et iaculis erat euismod fermentum tincidunt";
42//! let mut builder = TlshBuilder::new(
43//! BucketKind::Bucket128,
44//! ChecksumKind::OneByte,
45//! crate::tlsh::Version::Version4,
46//! );
47//! builder.update(s2.as_bytes());
48//! let tlsh2 = builder.build().unwrap();
49//!
50//! // Calculate diff between s1 & s2, including length difference.
51//! let _ = tlsh1.diff(&tlsh2, true);
52//! // Calculate diff between s1 & s2, excluding length difference.
53//! let _ = tlsh1.diff(&tlsh2, false);
54mod helper;
55
56mod error;
57pub use error::TlshError;
58
59mod tlsh;
60pub use crate::tlsh::BucketKind;
61pub use crate::tlsh::ChecksumKind;
62pub use crate::tlsh::Tlsh;
63pub use crate::tlsh::TlshBuilder;
64pub use crate::tlsh::Version;
65
66mod tests;