minisketch-rs 0.1.9

Rust interface to Pieter Wuille's minisketch library for efficient set reconciliation
Documentation
//! Example of set reconciliation that uses "bisection" approach when number of differences
//! between two sets is exceeding an estimate and simple reconciliation fails.
//!
//! Bisection leverages the "divide-and-conquer" approach. It is possible thanks to the linearity of
//! the set sketches.
//!
//! In following example Bob wants to reconcile his set with Alice:
//!
//! ```notrust
//! +-------+                            +-------+
//! |  Bob  |                            | Alice |
//! +-------+                            +-------+
//!     |                                   |
//!     | Sketch from a set [0..8]          |  Sketch from a set [0..32]
//!     |-------------------------------    |-------------------------------
//!     |                              |    |                              |
//!     |<------------------------------    |<------------------------------
//!     |                                   |
//!     | Serialized sketch (B)             |
//!     |---------------------------------->|
//!     |                                   |
//!     |                                   | Deserialize sketch
//!     |                                   |-------------------
//!     |                                   |                  |
//!     |                                   |<------------------
//!     |                                   |
//!     |                                   | reconcile(A, B)
//!     |                                   |-------------------------------
//!     |                                   |                              | failed!
//!     |                                   |<------------------------------
//!     |                                   |
//!     |      Ask for B/2 (bisect request) |
//!     |<----------------------------------|
//!     |                                   |
//!     | Sketch from B/2 [0, 2, 4, 6]      |
//!     |-----------------------------      |
//!     |                            |      |
//!     |<----------------------------      |
//!     |                                   |
//!     | Serialized sketch (B/2)           |
//!     |---------------------------------->|
//!     |                                   |
//!     |                                   | Deserialize sketch
//!     |                                   |-------------------
//!     |                                   |                  |
//!     |                                   |<------------------
//!     |                                   |
//!     |                                   | Compute: A/2, reconcile(A, A/2), reconcile(B, B/2)
//!     |                                   |---------------------------------------------------
//!     |                                   |                                                  |
//!     |                                   |<--------------------------------------------------
//!     |                                   |
//!     |                                   | Perform bisection:
//!     |                                   | diff1 = reconcile(A/2, B/2)
//!     |                                   | diff2 = reconcile(A - A/2, B - B/2)
//!     |                                   | bob_missing = diff1 ∪ diff2
//!     |                                   |-------------------------------------
//!     |                                   |                                    |
//!     |                                   |<------------------------------------
//!     |                                   |
//!     |                                   |
//!     |                  Send bob_missing |
//!     |<----------------------------------|
//!     |                                   |
//! ```
//!
//! ```
//! use minisketch_rs::Minisketch;
//! 
//! /// Extracts remainder sketch from a difference of two sketches
//! fn sub_sketches(s1: &[u8], s2: &[u8], d: usize, seed: Option<u64>) -> Vec<u8> {
//!     let mut a = create_minisketch(d, seed);
//!     if let Some(seed) = seed {
//!         a.set_seed(seed);
//!     }
//!     a.deserialize(s1);
//! 
//!     let mut b = create_minisketch(d, seed);
//!     if let Some(seed) = seed {
//!         b.set_seed(seed);
//!     }
//!     b.deserialize(s2);
//! 
//!     a.merge(&b).expect("Sketch sub merge");
//! 
//!     let mut sketch = vec![0u8; a.serialized_size()];
//!     a.serialize(&mut sketch).expect("Serialize sketch sub");
//! 
//!     sketch
//! }
//! 
//! /// Creates a_whole set from a_whole range of elements
//! fn sketch_from_range(
//!     range: impl IntoIterator<Item = u64>,
//!     capacity: usize,
//!     seed: Option<u64>,
//! ) -> Minisketch {
//!     let mut sketch = create_minisketch(capacity, seed);
//!     for i in range {
//!         sketch.add(i);
//!     }
//!     sketch
//! }
//! 
//! /// Creates `Minisketch` for given `capacity` and optional `seed`.
//! fn create_minisketch(capacity: usize, seed: Option<u64>) -> Minisketch {
//!     let mut minisketch = Minisketch::try_new(64, 0, capacity).unwrap();
//! 
//!     if let Some(seed) = seed {
//!         minisketch.set_seed(seed);
//!     }
//! 
//!     minisketch
//! }
//! 
//! /// Creates serialized sketch.
//! fn serialize_sketch(sketch: Minisketch) -> Vec<u8> {
//!     let mut buf = vec![0u8; sketch.serialized_size()];
//!     sketch.serialize(&mut buf).expect("Minisketch serialize");
//! 
//!     buf
//! }
//! 
//! /// Does set reconciliation from two sets.
//! fn reconcile(
//!     sketch_a: &[u8],
//!     sketch_b: &[u8],
//!     capacity: usize,
//!     seed: Option<u64>,
//! ) -> Result<Vec<u64>, ()> {
//!     let mut a = create_minisketch(capacity, seed);
//!     a.deserialize(sketch_a);
//! 
//!     let mut b = create_minisketch(capacity, seed);
//!     b.deserialize(sketch_b);
//! 
//!     a.merge(&b).expect("Minisketch merge");
//! 
//!     let mut diffs = vec![0u64; capacity];
//!     let num_diffs = a.decode(&mut diffs).map_err(|_| ())?;
//! 
//!     Ok(diffs.into_iter().take(num_diffs).collect())
//! }
//! 
//! fn example(capacity: usize) -> Result<Vec<u64>, ()> {
//!     let seed = None;
//! 
//!     // There is exactly 24 differences, but since capacity = 16, simple set reconciliation will fail
//!     let a = 0..32;
//!     let b = 0..8;
//! 
//!     // Count difference between two sets
//!     let set_diff = a.clone().into_iter().filter(|e| !b.contains(e)).count();
//! 
//!     println!(
//!         "Alice's set: {:?}",
//!         a.clone().into_iter().collect::<Vec<_>>()
//!     );
//!     println!("Bob's set: {:?}", b.clone().into_iter().collect::<Vec<_>>());
//! 
//!     // To increase chance of bisect success, take only even elements of the set,
//!     // so they're distributed uniformly.
//!     let b_half = b
//!         .clone()
//!         .into_iter()
//!         .enumerate()
//!         .filter(|(i, _)| *i % 2 == 0)
//!         .map(|(_, n)| n)
//!         .collect::<Vec<_>>();
//!     let a_half = a
//!         .clone()
//!         .into_iter()
//!         .enumerate()
//!         .filter(|(i, _)| *i % 2 == 0)
//!         .map(|(_, n)| n)
//!         .collect::<Vec<_>>();
//! 
//!     let alice_set_full = sketch_from_range(a, capacity, seed);
//!     let a_whole = serialize_sketch(alice_set_full);
//!     let a_half = serialize_sketch(sketch_from_range(a_half, capacity, seed));
//! 
//!     let bob_set_full = sketch_from_range(b, capacity, seed);
//!     let b_whole = serialize_sketch(bob_set_full);
//!     let b_half = serialize_sketch(sketch_from_range(b_half, capacity, seed));
//! 
//!     println!("Trying simple reconciliation");
//!     let simple = reconcile(&a_whole, &b_whole, capacity, seed);
//!     if let Err(()) = simple {
//!         println!(
//!             "Error. Difference exceeds sketch capacity: {} > {}",
//!             set_diff, capacity
//!         );
//!         println!("Trying bisection");
//! 
//!         let a_minus_a_2 = sub_sketches(&a_whole, &a_half, capacity, seed);
//!         let b_minus_b_2 = sub_sketches(&b_whole, &b_half, capacity, seed);
//! 
//!         let res_1 = reconcile(&a_half, &b_half, capacity, seed);
//!         let res_2 = reconcile(&a_minus_a_2, &b_minus_b_2, capacity, seed);
//! 
//!         let res = res_1.and_then(|diffs1| {
//!             res_2.and_then(|diffs2| {
//!                 Ok(diffs1
//!                     .into_iter()
//!                     .chain(diffs2.into_iter())
//!                     .collect::<Vec<_>>())
//!             })
//!         });
//! 
//!         res
//!     } else {
//!         Ok(simple.unwrap())
//!     }
//! }
//! 
//! pub fn main() {
//!     let capacity = 16; // Try to change it to 24 and compare results
//! 
//!     match example(capacity) {
//!         Ok(mut diffs) => {
//!             // Sort differences for result readability (not required)
//!             diffs.sort();
//! 
//!             println!("Success!");
//!             println!("Differences: {:?}", diffs);
//!         }
//! 
//!         Err(()) => println!("Example failed"),
//!     }
//! }
//! ```
// Auto-generated. Do not modify.