jacquardSnapshot

← snapshot

2278 bytes
//! Similarity sketches: how resemblance crosses the privacy boundary.
//!
//! # Shape
//!
//! A [`MinHashSketch`] is 64 `u64` minima computed over 3-word shingles of
//! the input. Two sketches estimate the Jaccard similarity of their inputs by
//! counting equal lanes. That is the entire information content: a sketch
//! reveals *that* two texts resemble each other — which is the rendezvous
//! registry's whole purpose — and cannot reveal *what* either text says.
//!
//! Honest scoping: `MinHash` leaks set resemblance by design. An adversary
//! holding a candidate text can test it against a published sketch. What the
//! shape rules out is reconstruction — there is no path from 64 minima back
//! to words — and this crate additionally exports no accessor that returns,
//! reconstructs, or iterates input content.
//!
//! The [`ContentSketch`] / [`DecisionSketch`] newtypes keep the two kinds of
//! sketch from being compared across streams, and both implement
//! [`jac_core::DigestSafe`], which is what lets them cross the boundary.

pub mod minhash;
pub mod shingle;

use jac_core::DigestSafe;
pub use minhash::{MinHashSketch, SKETCH_LANES, Similarity};
use serde::{Deserialize, Serialize};
pub use shingle::SketchBuilder;

/// A sketch of repository content (blob text, path-tagged).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ContentSketch(pub MinHashSketch);

/// A sketch of a design decision (title and rationale).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct DecisionSketch(pub MinHashSketch);

impl ContentSketch {
    /// Estimated Jaccard similarity to another content sketch.
    ///
    /// Only content compares with content: there is deliberately no method
    /// comparing a [`ContentSketch`] with a [`DecisionSketch`].
    #[must_use]
    pub fn similarity(&self, other: &Self) -> Similarity {
        self.0.similarity(&other.0)
    }
}

impl DecisionSketch {
    /// Estimated Jaccard similarity to another decision sketch.
    #[must_use]
    pub fn similarity(&self, other: &Self) -> Similarity {
        self.0.similarity(&other.0)
    }
}

impl DigestSafe for ContentSketch {}
impl DigestSafe for DecisionSketch {}