diff --git a/Cargo.lock b/Cargo.lock
index 24e8cbd3a90f911bf515c1b186c7efdb300449ae..4a85fcb4bfecf048744035ca3d24bedc240329a8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -107,7 +107,7 @@ dependencies = [
 
 [[package]]
 name = "duniter-wotb"
-version = "0.7.1"
+version = "0.8.0-a0.1"
 dependencies = [
  "bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/wotb/Cargo.toml b/wotb/Cargo.toml
index 2977ee583d4aff8441d85394d8daa3e5377df931..492b4ce786a1020f1de128dd042c991b0500b649 100644
--- a/wotb/Cargo.toml
+++ b/wotb/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "duniter-wotb"
-version = "0.7.1"
+version = "0.8.0-a0.1"
 authors = ["nanocryk <nanocryk@duniter.org>", "elois <elois@duniter.org>"]
 description = "Makes Web of Trust computations for the Duniter project."
 repository = "https://git.duniter.org/nodes/rust/duniter-rs"
diff --git a/wotb/legacy.rs b/wotb/data/legacy.rs
similarity index 64%
rename from wotb/legacy.rs
rename to wotb/data/legacy.rs
index 47da7fdfa8c28121311109a7c402d37e6e00ae8a..4aa3262cd10607b2e6957d6bdc2d67ebf75fab60 100644
--- a/wotb/legacy.rs
+++ b/wotb/data/legacy.rs
@@ -16,21 +16,16 @@
 //! Provide a legacy implementation of `WebOfTrust` storage and calculations.
 //! Its mostly translated directly from the original C++ code.
 
-use std::collections::hash_set::Iter;
 use std::collections::HashSet;
+use std::collections::hash_set::Iter;
 use std::fs::File;
 use std::io::prelude::*;
-use std::rc::Rc;
-use WotDistance;
 
 use bincode::{deserialize, serialize, Infinite};
 
-use HasLinkResult;
-use NewLinkResult;
-use NodeId;
-use RemLinkResult;
+use super::{HasLinkResult, NewLinkResult, RemLinkResult};
 use WebOfTrust;
-use WotDistanceParameters;
+use NodeId;
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
 struct Node {
@@ -104,19 +99,6 @@ impl Node {
     }
 }
 
-#[derive(Debug)]
-struct WotStep {
-    pub previous: Option<Rc<Box<WotStep>>>,
-    pub node: NodeId,
-    pub distance: u32,
-}
-
-struct LookupStep {
-    paths: Vec<Rc<Box<WotStep>>>,
-    matching_paths: Vec<Rc<Box<WotStep>>>,
-    distances: Vec<u32>,
-}
-
 /// Store a Web of Trust.
 ///
 /// Allow to create/remove nodes and links between them.
@@ -135,14 +117,6 @@ pub struct LegacyWebOfTrust {
 }
 
 impl LegacyWebOfTrust {
-    /// Create a new Web of Trust with the maxium certificications count.
-    pub fn new(max_cert: usize) -> LegacyWebOfTrust {
-        LegacyWebOfTrust {
-            nodes: vec![],
-            max_cert,
-        }
-    }
-
     /// Read `WoT` from file.
     pub fn legacy_from_file(path: &str) -> Option<LegacyWebOfTrust> {
         let mut file = match File::open(path) {
@@ -170,72 +144,16 @@ impl LegacyWebOfTrust {
             Err(_) => false,
         }
     }
+}
 
-    fn check_matches(&self, node: NodeId, d: u32, d_max: u32, mut checked: Vec<bool>) -> Vec<bool> {
-        let mut linked_nodes = Vec::new();
-
-        for linked_node in self.nodes[node.0].links_iter() {
-            checked[linked_node.0] = true;
-            linked_nodes.push(*linked_node);
-        }
-
-        if d < d_max {
-            for linked_node in &linked_nodes {
-                checked = self.check_matches(*linked_node, d + 1, d_max, checked);
-            }
-        }
-
-        checked
-    }
-
-    fn lookup(
-        &self,
-        source: NodeId,
-        target: NodeId,
-        distance: u32,
-        distance_max: u32,
-        previous: &Rc<Box<WotStep>>,
-        mut lookup_step: LookupStep,
-    ) -> LookupStep {
-        if source != target && distance <= distance_max {
-            let mut local_paths: Vec<Rc<Box<WotStep>>> = vec![];
-
-            for &by in self.nodes[target.0].links_iter() {
-                if distance < lookup_step.distances[by.0] {
-                    lookup_step.distances[by.0] = distance;
-                    let step = Rc::new(Box::new(WotStep {
-                        previous: Some(Rc::clone(previous)),
-                        node: by,
-                        distance,
-                    }));
-
-                    lookup_step.paths.push(Rc::clone(&step));
-                    local_paths.push(Rc::clone(&step));
-                    if by == source {
-                        lookup_step.matching_paths.push(Rc::clone(&step));
-                    }
-                }
-            }
-
-            if distance <= distance_max {
-                for path in &local_paths {
-                    lookup_step = self.lookup(
-                        source,
-                        path.node,
-                        distance + 1,
-                        distance_max,
-                        &Rc::clone(path),
-                        lookup_step,
-                    );
-                }
-            }
+impl WebOfTrust for LegacyWebOfTrust {
+    fn new(max_cert: usize) -> LegacyWebOfTrust {
+        LegacyWebOfTrust {
+            nodes: vec![],
+            max_cert,
         }
-
-        lookup_step
     }
-}
 
-impl WebOfTrust for LegacyWebOfTrust {
     fn get_max_link(&self) -> usize {
         self.max_cert
     }
@@ -342,6 +260,19 @@ impl WebOfTrust for LegacyWebOfTrust {
         }
     }
 
+    fn is_sentry(&self, node: NodeId, sentry_requirement: usize) -> Option<bool> {
+        if node.0 >= self.size() {
+            return None;
+        }
+
+        let node = &self.nodes[node.0];
+
+        Some(
+            node.enabled && node.issued_count() >= sentry_requirement
+                && node.links_iter().count() >= sentry_requirement,
+        )
+    }
+
     fn get_sentries(&self, sentry_requirement: usize) -> Vec<NodeId> {
         self.nodes
             .iter()
@@ -380,125 +311,6 @@ impl WebOfTrust for LegacyWebOfTrust {
             Some(self.nodes[id.0].issued_count)
         }
     }
-
-    fn compute_distance(&self, params: WotDistanceParameters) -> Option<WotDistance> {
-        let WotDistanceParameters {
-            node,
-            sentry_requirement,
-            step_max,
-            x_percent,
-        } = params;
-
-        if node.0 >= self.size() {
-            return None;
-        }
-
-        let sentry_requirement = sentry_requirement as usize;
-
-        let mut result = WotDistance {
-            sentries: 0,
-            success: 0,
-            success_at_border: 0,
-            reached: 0,
-            reached_at_border: 0,
-            outdistanced: false,
-        };
-
-        let mut sentries: Vec<bool> = self.nodes
-            .iter()
-            .map(|x| {
-                x.enabled && x.issued_count() >= sentry_requirement
-                    && x.links_iter().count() >= sentry_requirement
-            })
-            .collect();
-        sentries[node.0] = false;
-
-        let mut checked: Vec<bool> = self.nodes.iter().map(|_| false).collect();
-        let mut checked_without_border: Vec<bool> = checked.clone();
-
-        if step_max >= 1 {
-            checked = self.check_matches(node, 1, step_max, checked);
-            if step_max >= 2 {
-                checked_without_border =
-                    self.check_matches(node, 1, step_max - 1, checked_without_border);
-            }
-        }
-
-        for ((&sentry, &check), &check_without_border) in sentries
-            .iter()
-            .zip(checked.iter())
-            .zip(checked_without_border.iter())
-        {
-            if sentry {
-                result.sentries += 1;
-                if check {
-                    result.success += 1;
-                    result.reached += 1;
-                    if !check_without_border {
-                        result.success_at_border += 1;
-                        result.reached_at_border += 1;
-                    }
-                }
-            } else if check {
-                result.reached += 1;
-            }
-        }
-
-        result.outdistanced = f64::from(result.success) < x_percent * f64::from(result.sentries);
-        Some(result)
-    }
-
-    fn is_outdistanced(&self, params: WotDistanceParameters) -> Option<bool> {
-        let WotDistanceParameters { node, .. } = params;
-
-        if node.0 >= self.size() {
-            None
-        } else {
-            match self.compute_distance(params) {
-                Some(distance) => Some(distance.outdistanced),
-                None => None,
-            }
-        }
-    }
-
-    fn get_paths(&self, from: NodeId, to: NodeId, step_max: u32) -> Vec<Vec<NodeId>> {
-        let mut lookup_step = LookupStep {
-            paths: vec![],
-            matching_paths: vec![],
-            distances: self.nodes.iter().map(|_| step_max + 1).collect(),
-        };
-
-        lookup_step.distances[to.0] = 0;
-
-        let root = Rc::new(Box::new(WotStep {
-            previous: None,
-            node: to,
-            distance: 0,
-        }));
-
-        lookup_step.paths.push(Rc::clone(&root));
-
-        lookup_step = self.lookup(from, to, 1, step_max, &root, lookup_step);
-
-        let mut result: Vec<Vec<NodeId>> = Vec::with_capacity(lookup_step.matching_paths.len());
-
-        for step in &lookup_step.matching_paths {
-            let mut vecpath = vec![];
-            let mut step = Rc::clone(step);
-
-            loop {
-                vecpath.push(step.node);
-                if step.previous.is_none() {
-                    break;
-                }
-                step = step.previous.clone().unwrap();
-            }
-
-            result.push(vecpath);
-        }
-
-        result
-    }
 }
 
 #[cfg(test)]
@@ -565,9 +377,8 @@ mod tests {
         assert!(node2.has_link_from(&node1));
     }
 
-    /// This test is a translation of https://github.com/duniter/wotb/blob/master/tests/test.js
     #[test]
     fn wot_tests() {
-        generic_wot_test(LegacyWebOfTrust::new);
+        generic_wot_test::<LegacyWebOfTrust>();
     }
 }
diff --git a/wotb/data/mod.rs b/wotb/data/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ff079913f72c4bcb90a77a97ff29bc05a0169695
--- /dev/null
+++ b/wotb/data/mod.rs
@@ -0,0 +1,132 @@
+//  Copyright (C) 2017-2018  The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Provide data structures to manage web of trusts.
+//! `LegacyWebOfTrust` is almost a translation of the legacy C++ coden while
+//! `RustyWebOfTrust` is a brand new implementation with a more "rusty" style.
+
+pub mod legacy;
+pub mod rusty;
+
+/// Wrapper for a node id.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct NodeId(pub usize);
+
+/// Results of a certification, with the current certification count
+/// of the destination as parameter.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum NewLinkResult {
+    /// Certification worked.
+    Ok(usize),
+    /// This certification already exist.
+    AlreadyCertified(usize),
+    /// All available certifications has been used.
+    AllCertificationsUsed(usize),
+    /// Unknown source.
+    UnknownSource(),
+    /// Unknown target.
+    UnknownTarget(),
+    /// Self linking is forbidden.
+    SelfLinkingForbidden(),
+}
+
+/// Results of a certification removal, with the current certification count
+/// of the destination as parameter.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum RemLinkResult {
+    /// Certification has been removed.
+    Removed(usize),
+    /// Requested certification doesn't exist.
+    UnknownCert(usize),
+    /// Unknown source.
+    UnknownSource(),
+    /// Unknown target.
+    UnknownTarget(),
+}
+
+/// Results of a certification test.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum HasLinkResult {
+    /// Both nodes are known, here is the result.
+    Link(bool),
+    /// Unknown source.
+    UnknownSource(),
+    /// Unknown target.
+    UnknownTarget(),
+}
+
+/// Trait for a Web Of Trust.
+/// Allow to provide other implementations of the `WoT` logic instead of the legacy C++
+/// translated one.
+pub trait WebOfTrust {
+    /// Create a new Web of Trust with the maximum of links a node can issue.
+    fn new(max_links: usize) -> Self;
+
+    /// Get the maximum number of links per user.
+    fn get_max_link(&self) -> usize;
+
+    /// Set the maximum number of links per user.
+    fn set_max_link(&mut self, max_link: usize);
+
+    /// Add a new node.
+    fn add_node(&mut self) -> NodeId;
+
+    /// Remove the last node.
+    /// Returns `None` if the WoT was empty, otherwise new top node id.
+    fn rem_node(&mut self) -> Option<NodeId>;
+
+    /// Get the size of the WoT.
+    fn size(&self) -> usize;
+
+    /// Check if given node is enabled.
+    /// Returns `None` if this node doesn't exist.
+    fn is_enabled(&self, id: NodeId) -> Option<bool>;
+
+    /// Set the enabled state of given node.
+    /// Returns `Null` if this node doesn't exist, `enabled` otherwise.
+    fn set_enabled(&mut self, id: NodeId, enabled: bool) -> Option<bool>;
+
+    /// Get enabled node array.
+    fn get_enabled(&self) -> Vec<NodeId>;
+
+    /// Get disabled node array.
+    fn get_disabled(&self) -> Vec<NodeId>;
+
+    /// Try to add a link from the source to the target.
+    fn add_link(&mut self, source: NodeId, target: NodeId) -> NewLinkResult;
+
+    /// Try to remove a link from the source to the target.
+    fn rem_link(&mut self, source: NodeId, target: NodeId) -> RemLinkResult;
+
+    /// Test if there is a link from the source to the target.
+    fn has_link(&self, source: NodeId, target: NodeId) -> HasLinkResult;
+
+    /// Get the list of links source for this target.
+    /// Returns `None` if this node doesn't exist.
+    fn get_links_source(&self, target: NodeId) -> Option<Vec<NodeId>>;
+
+    /// Get the number of issued links by a node.
+    /// Returns `None` if this node doesn't exist.
+    fn issued_count(&self, id: NodeId) -> Option<usize>;
+
+    /// Test if a node is a sentry.
+    fn is_sentry(&self, node: NodeId, sentry_requirement: usize) -> Option<bool>;
+
+    /// Get sentries array.
+    fn get_sentries(&self, sentry_requirement: usize) -> Vec<NodeId>;
+
+    /// Get non sentries array.
+    fn get_non_sentries(&self, sentry_requirement: usize) -> Vec<NodeId>;
+}
diff --git a/wotb/rusty.rs b/wotb/data/rusty.rs
similarity index 56%
rename from wotb/rusty.rs
rename to wotb/data/rusty.rs
index b87ed0e89362fda6b7386b0f13d4db360a0f453b..1a47cfc515c12c22ac952a55bb7d94df48c6653f 100644
--- a/wotb/rusty.rs
+++ b/wotb/data/rusty.rs
@@ -15,16 +15,10 @@
 
 //! Experimental implementation of the Web of Trust in a more "rusty" style.
 
-use rayon::prelude::*;
 use std::collections::HashSet;
-
-use HasLinkResult;
-use NewLinkResult;
-use RemLinkResult;
+use rayon::prelude::*;
 use WebOfTrust;
-use WotDistance;
-use WotDistanceParameters;
-
+use super::{HasLinkResult, NewLinkResult, RemLinkResult};
 use NodeId;
 
 /// A node in the `WoT` graph.
@@ -32,10 +26,8 @@ use NodeId;
 struct Node {
     /// Is this node enabled ?
     enabled: bool,
-
     /// Set of links this node is the target.
     links_source: HashSet<NodeId>,
-
     /// Number of links the node issued.
     issued_count: usize,
 }
@@ -60,31 +52,14 @@ pub struct RustyWebOfTrust {
     max_links: usize,
 }
 
-impl RustyWebOfTrust {
-    /// Create a new Web of Trust with the maximum of links a node can issue.
-    pub fn new(max_links: usize) -> RustyWebOfTrust {
+impl WebOfTrust for RustyWebOfTrust {
+    fn new(max_links: usize) -> RustyWebOfTrust {
         RustyWebOfTrust {
             nodes: vec![],
             max_links,
         }
     }
 
-    /// Test if a node is a sentry.
-    pub fn is_sentry(&self, node: NodeId, sentry_requirement: usize) -> Option<bool> {
-        if node.0 >= self.size() {
-            return None;
-        }
-
-        let node = &self.nodes[node.0];
-
-        Some(
-            node.enabled && node.issued_count >= sentry_requirement
-                && node.links_source.len() >= sentry_requirement,
-        )
-    }
-}
-
-impl WebOfTrust for RustyWebOfTrust {
     fn get_max_link(&self) -> usize {
         self.max_links
     }
@@ -193,6 +168,19 @@ impl WebOfTrust for RustyWebOfTrust {
         self.nodes.get(id.0).map(|n| n.issued_count)
     }
 
+    fn is_sentry(&self, node: NodeId, sentry_requirement: usize) -> Option<bool> {
+        if node.0 >= self.size() {
+            return None;
+        }
+
+        let node = &self.nodes[node.0];
+
+        Some(
+            node.enabled && node.issued_count >= sentry_requirement
+                && node.links_source.len() >= sentry_requirement,
+        )
+    }
+
     fn get_sentries(&self, sentry_requirement: usize) -> Vec<NodeId> {
         self.nodes
             .par_iter()
@@ -217,131 +205,6 @@ impl WebOfTrust for RustyWebOfTrust {
             .map(|(i, _)| NodeId(i))
             .collect()
     }
-
-    fn get_paths(&self, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>> {
-        // 1. We explore the k_max area around `to`, and only remember backward
-        //    links of the smallest distance.
-
-        // Stores for each node its distance to `to` node and its backward links.
-        // By default all nodes are out of range (`k_max + 1`) and links are known.
-        let mut graph: Vec<(u32, Vec<usize>)> =
-            self.nodes.iter().map(|_| (k_max + 1, vec![])).collect();
-        // `to` node is at distance 0, and have no backward links.
-        graph[to.0] = (0, vec![]);
-        // Explored zone border.
-        let mut border = HashSet::new();
-        border.insert(to.0);
-
-        for distance in 1..(k_max + 1) {
-            let mut next_border = HashSet::new();
-
-            for node in border {
-                for source in &self.nodes[node].links_source {
-                    if graph[source.0].0 > distance {
-                        // shorter path, we replace
-                        graph[source.0] = (distance, vec![node]);
-                        next_border.insert(source.0);
-                    } else if graph[source.0].0 == distance {
-                        // same length, we combine
-                        graph[source.0].1.push(node);
-                        next_border.insert(source.0);
-                    }
-                }
-            }
-
-            border = next_border;
-        }
-
-        // 2. If `from` is found, we follow the backward links and build paths.
-        //    For each path, we look at the last element sources and build new paths with them.
-        let mut paths = vec![vec![from]];
-
-        for _ in 1..(k_max + 1) {
-            let mut new_paths = vec![];
-
-            for path in &paths {
-                let node = path.last().unwrap();
-
-                if node == &to {
-                    // If path is complete, we keep it.
-                    new_paths.push(path.clone())
-                } else {
-                    // If not complete we comlete paths
-                    let sources = &graph[node.0];
-                    for source in &sources.1 {
-                        let mut new_path = path.clone();
-                        new_path.push(NodeId(*source));
-                        new_paths.push(new_path);
-                    }
-                }
-            }
-
-            paths = new_paths;
-        }
-
-        paths
-    }
-
-    fn compute_distance(&self, params: WotDistanceParameters) -> Option<WotDistance> {
-        let WotDistanceParameters {
-            node,
-            sentry_requirement,
-            step_max,
-            x_percent,
-        } = params;
-
-        if node.0 >= self.size() {
-            return None;
-        }
-
-        let mut area = HashSet::new();
-        area.insert(node);
-        let mut border = HashSet::new();
-        border.insert(node);
-
-        for _ in 0..step_max {
-            border = border
-                .par_iter()
-                .map(|&id| {
-                    self.nodes[id.0]
-                        .links_source
-                        .iter()
-                        .filter(|source| !area.contains(source))
-                        .cloned()
-                        .collect::<HashSet<_>>()
-                })
-                .reduce(HashSet::new, |mut acc, sources| {
-                    for source in sources {
-                        acc.insert(source);
-                    }
-                    acc
-                });
-            area.extend(border.iter());
-        }
-
-        let sentries: Vec<_> = self.get_sentries(sentry_requirement as usize);
-        let mut success = area.iter().filter(|n| sentries.contains(n)).count() as u32;
-        let success_at_border = border.iter().filter(|n| sentries.contains(n)).count() as u32;
-        let mut sentries = sentries.len() as u32;
-        if self.is_sentry(node, sentry_requirement as usize).unwrap() {
-            sentries -= 1;
-            success -= 1;
-        }
-
-        Some(WotDistance {
-            sentries,
-            reached: area.len() as u32,
-            reached_at_border: border.len() as u32,
-            success,
-            success_at_border,
-            outdistanced: f64::from(success) < x_percent * f64::from(sentries),
-        })
-    }
-
-    fn is_outdistanced(&self, params: WotDistanceParameters) -> Option<bool> {
-        self.compute_distance(params)
-            .map(|result| result.outdistanced)
-    }
 }
 
 #[cfg(test)]
@@ -351,6 +214,6 @@ mod tests {
 
     #[test]
     fn wot_tests() {
-        generic_wot_test(RustyWebOfTrust::new);
+        generic_wot_test::<RustyWebOfTrust>();
     }
 }
diff --git a/wotb/lib.rs b/wotb/lib.rs
index 8d760fb166a131334acc3fe9163b3b25e068ebc4..5169d7ca657780ab9bb48eab7e02f322c2f284d6 100644
--- a/wotb/lib.rs
+++ b/wotb/lib.rs
@@ -27,11 +27,9 @@
 //! [js-tests]: https://github.com/duniter/wotb/blob/master/wotcpp/webOfTrust.cpp
 
 #![cfg_attr(feature = "strict", deny(warnings))]
-#![deny(
-    missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
-    trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
-    unused_qualifications
-)]
+#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
+        trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
+        unused_qualifications)]
 
 extern crate bincode;
 extern crate byteorder;
@@ -40,359 +38,30 @@ extern crate serde;
 #[macro_use]
 extern crate serde_derive;
 
-pub mod legacy;
-pub mod rusty;
-
-pub use legacy::LegacyWebOfTrust;
-
-use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
-
-use std::fs;
-use std::fs::File;
-use std::io::prelude::*;
-
-/// Wrapper for a node id.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-pub struct NodeId(pub usize);
-
-/// Results of a certification, with the current certification count
-/// of the destination as parameter.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum NewLinkResult {
-    /// Certification worked.
-    Ok(usize),
-    /// This certification already exist.
-    AlreadyCertified(usize),
-    /// All available certifications has been used.
-    AllCertificationsUsed(usize),
-    /// Unknown source.
-    UnknownSource(),
-    /// Unknown target.
-    UnknownTarget(),
-    /// Self linking is forbidden.
-    SelfLinkingForbidden(),
-}
-
-/// Results of a certification removal, with the current certification count
-/// of the destination as parameter.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum RemLinkResult {
-    /// Certification has been removed.
-    Removed(usize),
-    /// Requested certification doesn't exist.
-    UnknownCert(usize),
-    /// Unknown source.
-    UnknownSource(),
-    /// Unknown target.
-    UnknownTarget(),
-}
-
-/// Results of `WebOfTrust` parsing from binary file.
-#[derive(Debug)]
-pub enum WotParseError {
-    /// FailToOpenFile
-    FailToOpenFile(std::io::Error),
-
-    /// IOError
-    IOError(std::io::Error),
-}
-
-impl From<std::io::Error> for WotParseError {
-    fn from(e: std::io::Error) -> WotParseError {
-        WotParseError::IOError(e)
-    }
-}
-
-/// Results of `WebOfTrust` writing to binary file.
-#[derive(Debug)]
-pub enum WotWriteError {
-    /// WrongWotSize
-    WrongWotSize(),
-
-    /// FailToCreateFile
-    FailToCreateFile(std::io::Error),
-
-    /// FailToWriteInFile
-    FailToWriteInFile(std::io::Error),
-}
-
-impl From<std::io::Error> for WotWriteError {
-    fn from(e: std::io::Error) -> WotWriteError {
-        WotWriteError::FailToWriteInFile(e)
-    }
-}
-
-/// Results of a certification test.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum HasLinkResult {
-    /// Both nodes are known, here is the result.
-    Link(bool),
-    /// Unknown source.
-    UnknownSource(),
-    /// Unknown target.
-    UnknownTarget(),
-}
-
-/// Paramters for `WoT` distance calculations
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct WotDistanceParameters {
-    /// Node from where distances are calculated.
-    pub node: NodeId,
-    /// Links count received AND issued to be a sentry.
-    pub sentry_requirement: u32,
-    /// Currency parameter.
-    pub step_max: u32,
-    /// Currency parameter.
-    pub x_percent: f64,
-}
-
-/// Results of `WebOfTrust::compute_distance`.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct WotDistance {
-    /// Sentries count
-    pub sentries: u32,
-    /// Success count
-    pub success: u32,
-    /// Succes at border count
-    pub success_at_border: u32,
-    /// Reached count
-    pub reached: u32,
-    /// Reached at border count
-    pub reached_at_border: u32,
-    /// Is the node outdistanced ?
-    pub outdistanced: bool,
-}
-
-/// Trait for a Web Of Trust.
-/// Allow to provide other implementations of the `WoT` logic instead of the legacy C++
-/// translated one.
-pub trait WebOfTrust: Clone {
-    /// Get the maximum number of links per user.
-    fn get_max_link(&self) -> usize;
-
-    /// Set the maximum number of links per user.
-    fn set_max_link(&mut self, max_link: usize);
-
-    /// Add a new node.
-    fn add_node(&mut self) -> NodeId;
-
-    /// Remove the last node.
-    /// Returns `None` if the WoT was empty, otherwise new top node id.
-    fn rem_node(&mut self) -> Option<NodeId>;
-
-    /// Get the size of the WoT.
-    fn size(&self) -> usize;
-
-    /// Check if given node is enabled.
-    /// Returns `None` if this node doesn't exist.
-    fn is_enabled(&self, id: NodeId) -> Option<bool>;
-
-    /// Set the enabled state of given node.
-    /// Returns `Null` if this node doesn't exist, `enabled` otherwise.
-    fn set_enabled(&mut self, id: NodeId, enabled: bool) -> Option<bool>;
+pub mod data;
+pub mod operations;
 
-    /// Get enabled node array.
-    fn get_enabled(&self) -> Vec<NodeId>;
-
-    /// Get disabled node array.
-    fn get_disabled(&self) -> Vec<NodeId>;
-
-    /// Try to add a link from the source to the target.
-    fn add_link(&mut self, source: NodeId, target: NodeId) -> NewLinkResult;
-
-    /// Try to remove a link from the source to the target.
-    fn rem_link(&mut self, source: NodeId, target: NodeId) -> RemLinkResult;
-
-    /// Test if there is a link from the source to the target.
-    fn has_link(&self, source: NodeId, target: NodeId) -> HasLinkResult;
-
-    /// Get the list of links source for this target.
-    /// Returns `None` if this node doesn't exist.
-    fn get_links_source(&self, target: NodeId) -> Option<Vec<NodeId>>;
-
-    /// Get the number of issued links by a node.
-    /// Returns `None` if this node doesn't exist.
-    fn issued_count(&self, id: NodeId) -> Option<usize>;
-
-    /// Get sentries array.
-    fn get_sentries(&self, sentry_requirement: usize) -> Vec<NodeId>;
-
-    /// Get non sentries array.
-    fn get_non_sentries(&self, sentry_requirement: usize) -> Vec<NodeId>;
-
-    /// Get paths from one node to the other.
-    fn get_paths(&self, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>>;
-
-    /// Compute distance between a node and the network.
-    /// Returns `None` if this node doesn't exist.
-    fn compute_distance(&self, params: WotDistanceParameters) -> Option<WotDistance>;
-
-    /// Test if a node is outdistanced in the network.
-    /// Returns `Node` if this node doesn't exist.
-    fn is_outdistanced(&self, params: WotDistanceParameters) -> Option<bool>;
-
-    /// Load WebOfTrust from binary file
-    fn from_file(&mut self, path: &str) -> Result<Vec<u8>, WotParseError> {
-        let file_size = fs::metadata(path).expect("fail to read wotb file !").len();
-        let mut file_pointing_to_blockstamp_size: Vec<u8> = vec![0; file_size as usize];
-        match File::open(path) {
-            Ok(mut file) => {
-                file.read_exact(&mut file_pointing_to_blockstamp_size.as_mut_slice())?;
-            }
-            Err(e) => return Err(WotParseError::FailToOpenFile(e)),
-        };
-        // Read up to 4 bytes (blockstamp_size)
-        let mut file_pointing_to_blockstamp = file_pointing_to_blockstamp_size.split_off(4);
-        // Get blockstamp size
-        let mut buf = &file_pointing_to_blockstamp_size[..];
-        let blockstamp_size = buf.read_u32::<BigEndian>().unwrap();
-        // Read up to blockstamp_size bytes (blockstamp)
-        let mut file_pointing_to_nodes_count =
-            file_pointing_to_blockstamp.split_off(blockstamp_size as usize);
-        // Read up to 4 bytes (nodes_count)
-        let mut file_pointing_to_nodes_states = file_pointing_to_nodes_count.split_off(4);
-        // Read nodes_count
-        let mut buf = &file_pointing_to_nodes_count[..];
-        let nodes_count = buf.read_u32::<BigEndian>().unwrap();
-        // Calcule nodes_state size
-        let nodes_states_size = match nodes_count % 8 {
-            0 => nodes_count / 8,
-            _ => (nodes_count / 8) + 1,
-        };
-        // Read up to nodes_states_size bytes (nodes_states)
-        let file_pointing_to_links =
-            file_pointing_to_nodes_states.split_off(nodes_states_size as usize);
-        // Apply nodes state
-        let mut count_remaining_nodes = nodes_count;
-        for byte in file_pointing_to_nodes_states {
-            let mut byte_integer = u8::from_be(byte);
-            let mut factor: u8 = 128;
-            for _i in 0..8 {
-                if count_remaining_nodes > 0 {
-                    self.add_node();
-                    if byte_integer >= factor {
-                        byte_integer -= factor;
-                    } else {
-                        let _test = self.set_enabled(
-                            NodeId((nodes_count - count_remaining_nodes) as usize),
-                            false,
-                        );
-                    }
-                    count_remaining_nodes -= 1;
-                }
-                factor /= 2;
-            }
-        }
-        // Apply links
-        let mut buffer_3b: Vec<u8> = Vec::with_capacity(3);
-        let mut count_bytes = 0;
-        let mut remaining_links: u8 = 0;
-        let mut target: u32 = 0;
-        for byte in file_pointing_to_links {
-            if remaining_links == 0 {
-                target += 1;
-                remaining_links = u8::from_be(byte);
-                count_bytes = 0;
-            } else {
-                buffer_3b.push(byte);
-                if count_bytes % 3 == 2 {
-                    let mut buf = &buffer_3b.clone()[..];
-                    let source = buf.read_u24::<BigEndian>().expect("fail to parse source");
-                    self.add_link(NodeId(source as usize), NodeId((target - 1) as usize));
-                    remaining_links -= 1;
-                    buffer_3b.clear();
-                }
-                count_bytes += 1;
-            }
-        }
-        Ok(file_pointing_to_blockstamp)
-    }
-
-    /// Write WebOfTrust to binary file
-    fn to_file(&self, path: &str, blockstamp: &[u8]) -> Result<(), WotWriteError> {
-        let mut buffer: Vec<u8> = Vec::new();
-        // Write blockstamp size
-        let blockstamp_size = blockstamp.len() as u32;
-        let mut bytes: Vec<u8> = Vec::with_capacity(4);
-        bytes.write_u32::<BigEndian>(blockstamp_size).unwrap();
-        buffer.append(&mut bytes);
-        // Write blockstamp
-        buffer.append(&mut blockstamp.to_vec());
-        // Write nodes_count
-        let nodes_count = self.size() as u32;
-        let mut bytes: Vec<u8> = Vec::with_capacity(4);
-        bytes.write_u32::<BigEndian>(nodes_count).unwrap();
-        buffer.append(&mut bytes);
-        // Write enable state by groups of 8 (count links at the same time)
-        let mut enable_states: u8 = 0;
-        let mut factor: u8 = 128;
-        for n in 0..nodes_count {
-            match self.is_enabled(NodeId(n as usize)) {
-                Some(enable) => {
-                    if enable {
-                        enable_states += factor;
-                    }
-                }
-                None => {
-                    return Err(WotWriteError::WrongWotSize());
-                }
-            }
-            if n % 8 == 7 {
-                factor = 128;
-                let mut tmp_buf = Vec::with_capacity(1);
-                tmp_buf.write_u8(enable_states).unwrap();
-                buffer.append(&mut tmp_buf);
-                enable_states = 0;
-            } else {
-                factor /= 2;
-            }
-        }
-        // nodes_states padding
-        if nodes_count % 8 != 7 {
-            let mut tmp_buf = Vec::with_capacity(1);
-            tmp_buf.write_u8(enable_states).unwrap();
-            buffer.append(&mut tmp_buf);
-        }
-        // Write links
-        for n in 0..nodes_count {
-            if let Some(sources) = self.get_links_source(NodeId(n as usize)) {
-                // Write sources_counts
-                let mut bytes = Vec::with_capacity(1);
-                bytes.write_u8(sources.len() as u8).unwrap();
-                buffer.append(&mut bytes);
-                for source in &sources {
-                    // Write source
-                    let mut bytes: Vec<u8> = Vec::with_capacity(3);
-                    bytes.write_u24::<BigEndian>(source.0 as u32).unwrap();
-                    buffer.append(&mut bytes);
-                }
-            };
-        }
-        // Create or open file
-        let mut file = match File::create(path) {
-            Ok(file) => file,
-            Err(e) => return Err(WotWriteError::FailToCreateFile(e)),
-        };
-        // Write buffer in file
-        file.write_all(&buffer)?;
-
-        Ok(())
-    }
-}
+pub use data::{NodeId, WebOfTrust};
 
 #[cfg(test)]
 mod tests {
     use super::*;
+    use data::*;
+    use operations::distance::*;
+    use operations::path::*;
+    use operations::file::*;
 
     /// Test translated from https://github.com/duniter/wotb/blob/master/tests/test.js
     ///
     /// Clone and file tests are not included in this generic test and should be done in
     /// the implementation test.
-    pub fn generic_wot_test<T: WebOfTrust, F>(generator: F)
+    pub fn generic_wot_test<W>()
     where
-        F: Fn(usize) -> T,
+        W: WebOfTrust + Sync,
     {
-        let mut wot = generator(3);
+        let path_finder = RustyPathFinder {};
+        let distance_calculator = RustyDistanceCalculator {};
+        let mut wot = W::new(3);
 
         // should have an initial size of 0
         assert_eq!(wot.size(), 0);
@@ -584,32 +253,41 @@ mod tests {
 
         // should successfully use distance rule
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 1,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 1,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         );
         // => no because 2,4,5 have certified him
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 2,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 2,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         );
         // => no because only member 2 has 2 certs, and has certified him
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 3,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 3,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         );
         // => no because no member has issued 3 certifications
@@ -633,48 +311,66 @@ mod tests {
         assert_eq!(wot.get_non_sentries(1).len(), 11); // 12 - 1
         assert_eq!(wot.get_non_sentries(2).len(), 12); // 12 - 0
         assert_eq!(wot.get_non_sentries(3).len(), 12); // 12 - 0
-        assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 1).len(), 0); // KO
-        assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2).len(), 1); // It exists 3 -> 2 -> 0
-        assert!(wot.get_paths(NodeId(3), NodeId(0), 2).contains(&vec![
-            NodeId(3),
-            NodeId(2),
-            NodeId(0),
-        ]));
-
-        assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 1,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+        assert_eq!(
+            path_finder.find_paths(&wot, NodeId(3), NodeId(0), 1).len(),
+            0
+        ); // KO
+        assert_eq!(
+            path_finder.find_paths(&wot, NodeId(3), NodeId(0), 2).len(),
+            1
+        ); // It exists 3 -> 2 -> 0
+        assert!(
+            path_finder
+                .find_paths(&wot, NodeId(3), NodeId(0), 2)
+                .contains(&vec![NodeId(3), NodeId(2), NodeId(0)])
+        );
+
+        assert_eq!(
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 1,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         ); // OK : 2 -> 0
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 2,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 2,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         ); // OK : 2 -> 0
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 3,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 3,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         ); // OK : no stry \w 3 lnk
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 2,
-                step_max: 2,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 2,
+                    step_max: 2,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         ); // OK : 2 -> 0
 
@@ -693,48 +389,66 @@ mod tests {
         assert_eq!(wot.get_non_sentries(1).len(), 9); // 12 - 3
         assert_eq!(wot.get_non_sentries(2).len(), 11); // 12 - 1
         assert_eq!(wot.get_non_sentries(3).len(), 12); // 12 - 0
-        assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 1).len(), 0); // KO
-        assert_eq!(wot.get_paths(NodeId(3), NodeId(0), 2).len(), 1); // It exists 3 -> 2 -> 0
-        assert!(wot.get_paths(NodeId(3), NodeId(0), 2).contains(&vec![
-            NodeId(3),
-            NodeId(2),
-            NodeId(0),
-        ]));
-
-        assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 1,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+        assert_eq!(
+            path_finder.find_paths(&wot, NodeId(3), NodeId(0), 1).len(),
+            0
+        ); // KO
+        assert_eq!(
+            path_finder.find_paths(&wot, NodeId(3), NodeId(0), 2).len(),
+            1
+        ); // It exists 3 -> 2 -> 0
+        assert!(
+            path_finder
+                .find_paths(&wot, NodeId(3), NodeId(0), 2)
+                .contains(&vec![NodeId(3), NodeId(2), NodeId(0)])
+        );
+
+        assert_eq!(
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 1,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(true)
         ); // KO : No path 3 -> 0
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 2,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 2,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(true)
         ); // KO : No path 3 -> 0
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 3,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 3,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         ); // OK : no stry \w 3 lnk
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 2,
-                step_max: 2,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 2,
+                    step_max: 2,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         ); // OK : 3 -> 2 -> 0
 
@@ -752,30 +466,38 @@ mod tests {
         assert_eq!(wot.set_enabled(NodeId(3), false), Some(false));
         assert_eq!(wot.get_disabled().len(), 1);
         assert_eq!(
-            wot.is_outdistanced(WotDistanceParameters {
-                node: NodeId(0),
-                sentry_requirement: 2,
-                step_max: 1,
-                x_percent: 1.0,
-            },),
+            distance_calculator.is_outdistanced(
+                &wot,
+                WotDistanceParameters {
+                    node: NodeId(0),
+                    sentry_requirement: 2,
+                    step_max: 1,
+                    x_percent: 1.0,
+                },
+            ),
             Some(false)
         ); // OK : Disabled
 
+        let file_formater = BinaryFileFormater {};
+
         // Write wot in file
         assert_eq!(
-            wot.to_file(
-                "test.wot",
-                &[0b0000_0000, 0b0000_0001, 0b0000_0001, 0b0000_0000]
-            ).unwrap(),
+            file_formater
+                .to_file(
+                    &wot,
+                    &[0b0000_0000, 0b0000_0001, 0b0000_0001, 0b0000_0000],
+                    "test.wot"
+                )
+                .unwrap(),
             ()
         );
 
-        let mut wot2 = generator(3);
+        let (wot2, blockstamp2) = file_formater.from_file::<W>("test.wot", 3).unwrap();
 
         // Read wot from file
         {
             assert_eq!(
-                wot2.from_file("test.wot").unwrap(),
+                blockstamp2,
                 vec![0b0000_0000, 0b0000_0001, 0b0000_0001, 0b0000_0000]
             );
             assert_eq!(wot.size(), wot2.size());
@@ -787,20 +509,25 @@ mod tests {
             assert_eq!(wot2.get_disabled().len(), 1);
             assert_eq!(wot2.is_enabled(NodeId(3)), Some(false));
             assert_eq!(
-                wot2.is_outdistanced(WotDistanceParameters {
-                    node: NodeId(0),
-                    sentry_requirement: 2,
-                    step_max: 1,
-                    x_percent: 1.0,
-                },),
+                distance_calculator.is_outdistanced(
+                    &wot2,
+                    WotDistanceParameters {
+                        node: NodeId(0),
+                        sentry_requirement: 2,
+                        step_max: 1,
+                        x_percent: 1.0,
+                    },
+                ),
                 Some(false)
             );
         }
 
         // Read g1_genesis wot
-        let mut wot3 = generator(100);
+        let (wot3, blockstamp3) = file_formater
+            .from_file::<W>("tests/g1_genesis.bin", 100)
+            .unwrap();
         assert_eq!(
-            wot3.from_file("tests/g1_genesis.bin").unwrap(),
+            blockstamp3,
             vec![
                 57, 57, 45, 48, 48, 48, 48, 49, 50, 65, 68, 52, 57, 54, 69, 67, 65, 53, 54, 68, 69,
                 48, 66, 56, 69, 53, 68, 54, 70, 55, 52, 57, 66, 55, 67, 66, 69, 55, 56, 53, 53, 51,
@@ -815,12 +542,15 @@ mod tests {
 
         // Test compute_distance in g1_genesis wot
         assert_eq!(
-            wot3.compute_distance(WotDistanceParameters {
-                node: NodeId(37),
-                sentry_requirement: 3,
-                step_max: 5,
-                x_percent: 0.8,
-            },),
+            distance_calculator.compute_distance(
+                &wot3,
+                WotDistanceParameters {
+                    node: NodeId(37),
+                    sentry_requirement: 3,
+                    step_max: 5,
+                    x_percent: 0.8,
+                },
+            ),
             Some(WotDistance {
                 sentries: 48,
                 success: 48,
@@ -839,7 +569,7 @@ mod tests {
         let mut centralities = vec![0; wot_size];
         for i in 0..wot_size {
             for j in 0..wot_size {
-                let paths = wot3.get_paths(NodeId(i), NodeId(j), 5);
+                let paths = path_finder.find_paths(&wot3, NodeId(i), NodeId(j), 5);
                 let mut intermediate_members: Vec<NodeId> = Vec::new();
                 for path in paths {
                     if path.len() > 2 {
diff --git a/wotb/operations/distance.rs b/wotb/operations/distance.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e097fe5bff7ee40be1c0ffaba6d915f44ff919b5
--- /dev/null
+++ b/wotb/operations/distance.rs
@@ -0,0 +1,128 @@
+//  Copyright (C) 2017-2018  The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Provide a trait and implementations to compute distances.
+
+use std::collections::HashSet;
+use rayon::prelude::*;
+use data::WebOfTrust;
+use data::NodeId;
+
+/// Paramters for `WoT` distance calculations
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct WotDistanceParameters {
+    /// Node from where distances are calculated.
+    pub node: NodeId,
+    /// Links count received AND issued to be a sentry.
+    pub sentry_requirement: u32,
+    /// Currency parameter.
+    pub step_max: u32,
+    /// Currency parameter.
+    pub x_percent: f64,
+}
+
+/// Results of `WebOfTrust::compute_distance`.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct WotDistance {
+    /// Sentries count
+    pub sentries: u32,
+    /// Success count
+    pub success: u32,
+    /// Succes at border count
+    pub success_at_border: u32,
+    /// Reached count
+    pub reached: u32,
+    /// Reached at border count
+    pub reached_at_border: u32,
+    /// Is the node outdistanced ?
+    pub outdistanced: bool,
+}
+
+/// Compute distance between nodes of a `WebOfTrust`.
+pub trait DistanceCalculator<T: WebOfTrust> {
+    /// Compute distance between a node and the network.
+    /// Returns `None` if this node doesn't exist.
+    fn compute_distance(&self, wot: &T, params: WotDistanceParameters) -> Option<WotDistance>;
+
+    /// Test if a node is outdistanced in the network.
+    /// Returns `Node` if this node doesn't exist.
+    fn is_outdistanced(&self, wot: &T, params: WotDistanceParameters) -> Option<bool>;
+}
+
+/// Calculate distances between 2 members in a `WebOfTrust`.
+#[derive(Debug, Clone, Copy)]
+pub struct RustyDistanceCalculator;
+
+impl<T: WebOfTrust + Sync> DistanceCalculator<T> for RustyDistanceCalculator {
+    fn compute_distance(&self, wot: &T, params: WotDistanceParameters) -> Option<WotDistance> {
+        let WotDistanceParameters {
+            node,
+            sentry_requirement,
+            step_max,
+            x_percent,
+        } = params;
+
+        if node.0 >= wot.size() {
+            return None;
+        }
+
+        let mut area = HashSet::new();
+        area.insert(node);
+        let mut border = HashSet::new();
+        border.insert(node);
+
+        for _ in 0..step_max {
+            border = border
+                .par_iter()
+                .map(|&id| {
+                    wot.get_links_source(id)
+                        .unwrap()
+                        .iter()
+                        .filter(|source| !area.contains(source))
+                        .cloned()
+                        .collect::<HashSet<_>>()
+                })
+                .reduce(HashSet::new, |mut acc, sources| {
+                    for source in sources {
+                        acc.insert(source);
+                    }
+                    acc
+                });
+            area.extend(border.iter());
+        }
+
+        let sentries: Vec<_> = wot.get_sentries(sentry_requirement as usize);
+        let mut success = area.iter().filter(|n| sentries.contains(n)).count() as u32;
+        let success_at_border = border.iter().filter(|n| sentries.contains(n)).count() as u32;
+        let mut sentries = sentries.len() as u32;
+        if wot.is_sentry(node, sentry_requirement as usize).unwrap() {
+            sentries -= 1;
+            success -= 1;
+        }
+
+        Some(WotDistance {
+            sentries,
+            reached: area.len() as u32,
+            reached_at_border: border.len() as u32,
+            success,
+            success_at_border,
+            outdistanced: f64::from(success) < x_percent * f64::from(sentries),
+        })
+    }
+
+    fn is_outdistanced(&self, wot: &T, params: WotDistanceParameters) -> Option<bool> {
+        Self::compute_distance(&self, wot, params).map(|result| result.outdistanced)
+    }
+}
diff --git a/wotb/operations/file.rs b/wotb/operations/file.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7faba196f27be96d49217d1e74e8540c8682c79a
--- /dev/null
+++ b/wotb/operations/file.rs
@@ -0,0 +1,240 @@
+//  Copyright (C) 2017-2018  The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Provide a trait and implementation to read and write `WebOfTrust` to disk.
+
+use data::NodeId;
+use std::io::prelude::*;
+use std::io;
+use std::fs;
+use std::fs::File;
+
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+
+use data::WebOfTrust;
+
+/// Results of `WebOfTrust` parsing from binary file.
+#[derive(Debug)]
+pub enum WotParseError {
+    /// FailToOpenFile
+    FailToOpenFile(io::Error),
+
+    /// IOError
+    IOError(io::Error),
+}
+
+impl From<io::Error> for WotParseError {
+    fn from(e: io::Error) -> WotParseError {
+        WotParseError::IOError(e)
+    }
+}
+
+/// Results of `WebOfTrust` writing to binary file.
+#[derive(Debug)]
+pub enum WotWriteError {
+    /// WrongWotSize
+    WrongWotSize(),
+
+    /// FailToCreateFile
+    FailToCreateFile(io::Error),
+
+    /// FailToWriteInFile
+    FailToWriteInFile(io::Error),
+}
+
+impl From<io::Error> for WotWriteError {
+    fn from(e: io::Error) -> WotWriteError {
+        WotWriteError::FailToWriteInFile(e)
+    }
+}
+
+/// Provide Read/Write functions for `WebOfTrust` objects.
+pub trait FileFormater {
+    /// Try to read a `WebOfTrust` from a file.
+    fn from_file<T: WebOfTrust>(
+        &self,
+        path: &str,
+        max_links: usize,
+    ) -> Result<(T, Vec<u8>), WotParseError>;
+
+    /// Tru to write a `WebOfTrust` in a file.
+    fn to_file<T: WebOfTrust>(&self, wot: &T, data: &[u8], path: &str)
+        -> Result<(), WotWriteError>;
+}
+
+/// Read and write WebOfTrust in a binary format.
+#[derive(Debug, Clone, Copy)]
+pub struct BinaryFileFormater;
+
+impl FileFormater for BinaryFileFormater {
+    /// Try to read a `WebOfTrust` from a file.
+    fn from_file<T: WebOfTrust>(
+        &self,
+        path: &str,
+        max_links: usize,
+    ) -> Result<(T, Vec<u8>), WotParseError> {
+        let mut wot = T::new(max_links);
+
+        let file_size = fs::metadata(path).expect("fail to read wotb file !").len();
+        let mut file_pointing_to_blockstamp_size: Vec<u8> = vec![0; file_size as usize];
+        match File::open(path) {
+            Ok(mut file) => {
+                file.read_exact(&mut file_pointing_to_blockstamp_size.as_mut_slice())?;
+            }
+            Err(e) => return Err(WotParseError::FailToOpenFile(e)),
+        };
+        // Read up to 4 bytes (blockstamp_size)
+        let mut file_pointing_to_blockstamp = file_pointing_to_blockstamp_size.split_off(4);
+        // Get blockstamp size
+        let mut buf = &file_pointing_to_blockstamp_size[..];
+        let blockstamp_size = buf.read_u32::<BigEndian>().unwrap();
+        // Read up to blockstamp_size bytes (blockstamp)
+        let mut file_pointing_to_nodes_count =
+            file_pointing_to_blockstamp.split_off(blockstamp_size as usize);
+        // Read up to 4 bytes (nodes_count)
+        let mut file_pointing_to_nodes_states = file_pointing_to_nodes_count.split_off(4);
+        // Read nodes_count
+        let mut buf = &file_pointing_to_nodes_count[..];
+        let nodes_count = buf.read_u32::<BigEndian>().unwrap();
+        // Calcule nodes_state size
+        let nodes_states_size = match nodes_count % 8 {
+            0 => nodes_count / 8,
+            _ => (nodes_count / 8) + 1,
+        };
+        // Read up to nodes_states_size bytes (nodes_states)
+        let file_pointing_to_links =
+            file_pointing_to_nodes_states.split_off(nodes_states_size as usize);
+        // Apply nodes state
+        let mut count_remaining_nodes = nodes_count;
+        for byte in file_pointing_to_nodes_states {
+            let mut byte_integer = u8::from_be(byte);
+            let mut factor: u8 = 128;
+            for _i in 0..8 {
+                if count_remaining_nodes > 0 {
+                    wot.add_node();
+                    if byte_integer >= factor {
+                        byte_integer -= factor;
+                    } else {
+                        let _test = wot.set_enabled(
+                            NodeId((nodes_count - count_remaining_nodes) as usize),
+                            false,
+                        );
+                    }
+                    count_remaining_nodes -= 1;
+                }
+                factor /= 2;
+            }
+        }
+        // Apply links
+        let mut buffer_3b: Vec<u8> = Vec::with_capacity(3);
+        let mut count_bytes = 0;
+        let mut remaining_links: u8 = 0;
+        let mut target: u32 = 0;
+        for byte in file_pointing_to_links {
+            if remaining_links == 0 {
+                target += 1;
+                remaining_links = u8::from_be(byte);
+                count_bytes = 0;
+            } else {
+                buffer_3b.push(byte);
+                if count_bytes % 3 == 2 {
+                    let mut buf = &buffer_3b.clone()[..];
+                    let source = buf.read_u24::<BigEndian>().expect("fail to parse source");
+                    wot.add_link(NodeId(source as usize), NodeId((target - 1) as usize));
+                    remaining_links -= 1;
+                    buffer_3b.clear();
+                }
+                count_bytes += 1;
+            }
+        }
+        Ok((wot, file_pointing_to_blockstamp))
+    }
+
+    /// Try to write a `WebOfTrust` in a file.
+    fn to_file<T: WebOfTrust>(
+        &self,
+        wot: &T,
+        data: &[u8],
+        path: &str,
+    ) -> Result<(), WotWriteError> {
+        let mut buffer: Vec<u8> = Vec::new();
+        // Write blockstamp size
+        let blockstamp_size = data.len() as u32;
+        let mut bytes: Vec<u8> = Vec::with_capacity(4);
+        bytes.write_u32::<BigEndian>(blockstamp_size).unwrap();
+        buffer.append(&mut bytes);
+        // Write blockstamp
+        buffer.append(&mut data.to_vec());
+        // Write nodes_count
+        let nodes_count = wot.size() as u32;
+        let mut bytes: Vec<u8> = Vec::with_capacity(4);
+        bytes.write_u32::<BigEndian>(nodes_count).unwrap();
+        buffer.append(&mut bytes);
+        // Write enable state by groups of 8 (count links at the same time)
+        let mut enable_states: u8 = 0;
+        let mut factor: u8 = 128;
+        for n in 0..nodes_count {
+            match wot.is_enabled(NodeId(n as usize)) {
+                Some(enable) => {
+                    if enable {
+                        enable_states += factor;
+                    }
+                }
+                None => {
+                    return Err(WotWriteError::WrongWotSize());
+                }
+            }
+            if n % 8 == 7 {
+                factor = 128;
+                let mut tmp_buf = Vec::with_capacity(1);
+                tmp_buf.write_u8(enable_states).unwrap();
+                buffer.append(&mut tmp_buf);
+                enable_states = 0;
+            } else {
+                factor /= 2;
+            }
+        }
+        // nodes_states padding
+        if nodes_count % 8 != 7 {
+            let mut tmp_buf = Vec::with_capacity(1);
+            tmp_buf.write_u8(enable_states).unwrap();
+            buffer.append(&mut tmp_buf);
+        }
+        // Write links
+        for n in 0..nodes_count {
+            if let Some(sources) = wot.get_links_source(NodeId(n as usize)) {
+                // Write sources_counts
+                let mut bytes = Vec::with_capacity(1);
+                bytes.write_u8(sources.len() as u8).unwrap();
+                buffer.append(&mut bytes);
+                for source in &sources {
+                    // Write source
+                    let mut bytes: Vec<u8> = Vec::with_capacity(3);
+                    bytes.write_u24::<BigEndian>(source.0 as u32).unwrap();
+                    buffer.append(&mut bytes);
+                }
+            };
+        }
+        // Create or open file
+        let mut file = match File::create(path) {
+            Ok(file) => file,
+            Err(e) => return Err(WotWriteError::FailToCreateFile(e)),
+        };
+        // Write buffer in file
+        file.write_all(&buffer)?;
+
+        Ok(())
+    }
+}
diff --git a/wotb/operations/mod.rs b/wotb/operations/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2bd2782e2ec65ae636df61d6dde65cb4b055fccb
--- /dev/null
+++ b/wotb/operations/mod.rs
@@ -0,0 +1,20 @@
+//  Copyright (C) 2017-2018  The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Provide operation traits and implementations on `WebOfTrust` objects.
+
+pub mod path;
+pub mod distance;
+pub mod file;
diff --git a/wotb/operations/path.rs b/wotb/operations/path.rs
new file mode 100644
index 0000000000000000000000000000000000000000..528283128702115dad6bf2d11440487209c50a5b
--- /dev/null
+++ b/wotb/operations/path.rs
@@ -0,0 +1,102 @@
+//  Copyright (C) 2017-2018  The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Provide a trait and implementations to find paths between nodes.
+
+use std::collections::HashSet;
+use data::NodeId;
+use data::WebOfTrust;
+
+/// Find paths between 2 nodes of a `WebOfTrust`.
+pub trait PathFinder<T: WebOfTrust> {
+    /// Get paths from one node to the other.
+    fn find_paths(&self, wot: &T, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>>;
+}
+
+/// A new "rusty-er" implementation of `WoT` path finding.
+#[derive(Debug, Clone, Copy)]
+pub struct RustyPathFinder;
+
+impl<T: WebOfTrust> PathFinder<T> for RustyPathFinder {
+    fn find_paths(&self, wot: &T, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>> {
+        if from.0 >= wot.size() || to.0 >= wot.size() {
+            return vec![];
+        }
+
+        // 1. We explore the k_max area around `to`, and only remember backward
+        //    links of the smallest distance.
+
+        // Stores for each node its distance to `to` node and its backward links.
+        // By default all nodes are out of range (`k_max + 1`) and links are known.
+        let mut graph: Vec<(u32, Vec<NodeId>)> = (0..wot.size())
+            .into_iter()
+            .map(|_| (k_max + 1, vec![]))
+            .collect();
+        // `to` node is at distance 0, and have no backward links.
+        graph[to.0] = (0, vec![]);
+        // Explored zone border.
+        let mut border = HashSet::new();
+        border.insert(to);
+
+        for distance in 1..(k_max + 1) {
+            let mut next_border = HashSet::new();
+
+            for node in border {
+                for source in &wot.get_links_source(node).unwrap() {
+                    if graph[source.0].0 > distance {
+                        // shorter path, we replace
+                        graph[source.0] = (distance, vec![node]);
+                        next_border.insert(*source);
+                    } else if graph[source.0].0 == distance {
+                        // same length, we combine
+                        graph[source.0].1.push(node);
+                        next_border.insert(*source);
+                    }
+                }
+            }
+
+            border = next_border;
+        }
+
+        // 2. If `from` is found, we follow the backward links and build paths.
+        //    For each path, we look at the last element sources and build new paths with them.
+        let mut paths = vec![vec![from]];
+
+        for _ in 1..(k_max + 1) {
+            let mut new_paths = vec![];
+
+            for path in &paths {
+                let node = path.last().unwrap();
+
+                if node == &to {
+                    // If path is complete, we keep it.
+                    new_paths.push(path.clone())
+                } else {
+                    // If not complete we comlete paths
+                    let sources = &graph[node.0];
+                    for source in &sources.1 {
+                        let mut new_path = path.clone();
+                        new_path.push(*source);
+                        new_paths.push(new_path);
+                    }
+                }
+            }
+
+            paths = new_paths;
+        }
+
+        paths
+    }
+}