diff --git a/.gitignore b/.gitignore
index f06b49a0e10c9eacff6fce8f7b95d7c1178fd8cd..7b5ce765893a9af1f088be19e906acc40bf4ee94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,4 +43,14 @@ typedoc/
 app/**/*.js*
 app/**/*.d.ts
 test/**/*.d.ts
-test/**/*.js*
\ No newline at end of file
+test/**/*.js*
+
+# files generated by neon tests
+test2.bin.gz
+
+# rust intermediate binaries
+target
+
+# files generated by rust tests
+neon/native/tests/*.txt
+neon/native/tests/wotb-*
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000000000000000000000000000000000000..4231a086a501edfab6b11677e8bca2bfd4a74a73
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,677 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "adler32"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+
+[[package]]
+name = "base64"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
+
+[[package]]
+name = "bincode"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
+dependencies = [
+ "byteorder",
+ "serde",
+]
+
+[[package]]
+name = "bs58"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb"
+
+[[package]]
+name = "bumpalo"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
+
+[[package]]
+name = "byteorder"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+
+[[package]]
+name = "cc"
+version = "1.0.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "crc32fast"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+ "maybe-uninit",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "crossbeam-utils",
+ "lazy_static",
+ "maybe-uninit",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "lazy_static",
+]
+
+[[package]]
+name = "cslice"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "697c714f50560202b1f4e2e09cd50a421881c83e9025db75d15f276616f04f40"
+
+[[package]]
+name = "curve25519-dalek"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839"
+dependencies = [
+ "byteorder",
+ "digest",
+ "rand_core",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "digest"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "dubp-wot"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0f76dd4b734d34be5613c470402ccdb21cb21b84ecd75acdc81cf80c618201a"
+dependencies = [
+ "log",
+ "rayon",
+ "serde",
+]
+
+[[package]]
+name = "duniteroxyde"
+version = "0.2.9"
+dependencies = [
+ "bincode",
+ "bs58",
+ "dubp-wot",
+ "dup-crypto",
+ "flate2",
+ "neon",
+ "neon-build",
+]
+
+[[package]]
+name = "dup-crypto"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d1f07e794fd7bbe2851c9c2538b470ab5f99ef46b470b1ec28a2dc565d52127"
+dependencies = [
+ "base64",
+ "bs58",
+ "byteorder",
+ "curve25519-dalek",
+ "ring",
+ "thiserror",
+ "unwrap",
+ "zeroize",
+]
+
+[[package]]
+name = "either"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
+
+[[package]]
+name = "flate2"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42"
+dependencies = [
+ "cfg-if",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
+
+[[package]]
+name = "log"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "maybe-uninit"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
+
+[[package]]
+name = "memchr"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+
+[[package]]
+name = "memoffset"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5"
+dependencies = [
+ "adler32",
+]
+
+[[package]]
+name = "neon"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cac4691701b686e6c07b2eb5b51a9f26f5c11179c5d7924b78100dd387fc99d"
+dependencies = [
+ "cslice",
+ "neon-build",
+ "neon-runtime",
+ "semver",
+]
+
+[[package]]
+name = "neon-build"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9ed332afd4711b84f4f83d334428a1fd9ce53620b62b87595934297c5ede2ed"
+dependencies = [
+ "cfg-if",
+ "neon-sys",
+]
+
+[[package]]
+name = "neon-runtime"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2beea093a60c08463f65e1da4cda68149986f60d8d2177489b44589463c782a6"
+dependencies = [
+ "cfg-if",
+ "neon-sys",
+]
+
+[[package]]
+name = "neon-sys"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69a6c1ba6b926746f4d3f596de18ce49d062d78fd9f35f636080232aa77a0e16"
+dependencies = [
+ "cc",
+ "regex",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rayon"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
+dependencies = [
+ "crossbeam-deque",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-queue",
+ "crossbeam-utils",
+ "lazy_static",
+ "num_cpus",
+]
+
+[[package]]
+name = "regex"
+version = "1.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+ "thread_local",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
+
+[[package]]
+name = "ring"
+version = "0.16.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ba5a8ec64ee89a76c98c549af81ff14813df09c3e6dc4766c3856da48597a0c"
+dependencies = [
+ "cc",
+ "lazy_static",
+ "libc",
+ "spin",
+ "untrusted",
+ "web-sys",
+ "winapi",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+
+[[package]]
+name = "serde"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
+[[package]]
+name = "subtle"
+version = "2.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941"
+
+[[package]]
+name = "syn"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unicode-xid",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54b3d3d2ff68104100ab257bb6bb0cb26c901abe4bd4ba15961f3bf867924012"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca972988113b7715266f91250ddb98070d033c62a011fa0fcc57434a649310dd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "typenum"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+
+[[package]]
+name = "untrusted"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60369ef7a31de49bcb3f6ca728d4ba7300d9a1658f94c727d4cab8c8d9f4aece"
+
+[[package]]
+name = "unwrap"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e33648dd74328e622c7be51f3b40a303c63f93e6fa5f08778b6203a4c25c20f"
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd"
+dependencies = [
+ "bumpalo",
+ "lazy_static",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639"
+
+[[package]]
+name = "web-sys"
+version = "0.3.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "zeroize"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..551b803b8e95fa86068ce5cce35a3c0d1ba91003
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["neon/native"]
diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts
index e5659a1d2cfa428f496c62338b7419dcd4d6404d..faeec03d731e958e4fa3faae4dc22f06b6a93264 100644
--- a/app/lib/blockchain/DuniterBlockchain.ts
+++ b/app/lib/blockchain/DuniterBlockchain.ts
@@ -38,7 +38,7 @@ import { DBTx } from "../db/DBTx";
 import { Underscore } from "../common-libs/underscore";
 import { OtherConstants } from "../other_constants";
 import { MonitorExecutionTime } from "../debug/MonitorExecutionTime";
-import { Wot } from "duniteroxyde";
+import { Wot } from "../../../neon/lib";
 import { Directory } from "../system/directory";
 
 export class DuniterBlockchain {
diff --git a/app/lib/common-libs/crypto/keyring.ts b/app/lib/common-libs/crypto/keyring.ts
index 200e32b2822fca6e48ec02cbde66c4b0af245391..720762f23dbdde2bd59015570cc2ed6a682b7b43 100644
--- a/app/lib/common-libs/crypto/keyring.ts
+++ b/app/lib/common-libs/crypto/keyring.ts
@@ -15,7 +15,7 @@ import {
   KeyPairBuilder,
   generateRandomSeed,
   seedToSecretKey,
-} from "duniteroxyde";
+} from "../../../../neon/lib";
 
 export class Key {
   constructor(readonly pub: string, readonly sec: string) {}
diff --git a/app/lib/common.ts b/app/lib/common.ts
index db15a6444e6d6c428eeaf84d803ebf6d541fb583..4d254483693ae6b5d57977708932e68e139478d9 100644
--- a/app/lib/common.ts
+++ b/app/lib/common.ts
@@ -11,7 +11,7 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import { sha256 } from "duniteroxyde";
+import { sha256 } from "../../neon/lib";
 
 export const hashf = function hashf(str: string) {
   return sha256(str);
diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index 3bed0ef10f6e19e69451cc94793710ffecdcda65..7929b72b4acfe25bbb1cfdd201debc08f61f123c 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -43,7 +43,7 @@ import { MetaDAL } from "./sqliteDAL/MetaDAL";
 import { DataErrors } from "../common-libs/errors";
 import { BasicRevocableIdentity, IdentityDTO } from "../dto/IdentityDTO";
 import { FileSystem } from "../system/directory";
-import { Wot } from "duniteroxyde";
+import { Wot } from "../../../neon/lib";
 import { IIndexDAO } from "./indexDAL/abstract/IIndexDAO";
 import { BIndexDAO } from "./indexDAL/abstract/BIndexDAO";
 import { MIndexDAO } from "./indexDAL/abstract/MIndexDAO";
diff --git a/app/lib/dto/TransactionDTO.ts b/app/lib/dto/TransactionDTO.ts
index d58d660fe7afba0867124594fdc73bc4da41a9a3..71dfa660f6176053edb6f5eba203ea2e7e34e46a 100644
--- a/app/lib/dto/TransactionDTO.ts
+++ b/app/lib/dto/TransactionDTO.ts
@@ -13,7 +13,7 @@
 
 import { hashf } from "../common";
 import { Cloneable } from "./Cloneable";
-import { verify } from "duniteroxyde";
+import { verify } from "../../../neon/lib";
 
 export interface BaseDTO {
   base: number;
diff --git a/app/lib/indexer.ts b/app/lib/indexer.ts
index 8ce3c8f368baa6591a7b992740c9c7d45d89541b..c691672f4c65e06431fbe83894f2d28104eb0f9e 100644
--- a/app/lib/indexer.ts
+++ b/app/lib/indexer.ts
@@ -18,7 +18,7 @@ import { RevocationDTO } from "./dto/RevocationDTO";
 import { CertificationDTO } from "./dto/CertificationDTO";
 import { TransactionDTO } from "./dto/TransactionDTO";
 import { DBHead } from "./db/DBHead";
-import { verify } from "duniteroxyde";
+import { verify } from "../../neon/lib";
 import { rawer, txunlock } from "./common-libs/index";
 import { CommonConstants } from "./common-libs/constants";
 import { MembershipDTO } from "./dto/MembershipDTO";
@@ -31,7 +31,7 @@ import { Underscore } from "./common-libs/underscore";
 import { DataErrors } from "./common-libs/errors";
 import { MonitorExecutionTime } from "./debug/MonitorExecutionTime";
 import { NewLogger } from "./logger";
-import { WotBuilder } from "duniteroxyde";
+import { WotBuilder } from "../../neon/lib";
 
 const constants = CommonConstants;
 
diff --git a/app/lib/rules/global_rules.ts b/app/lib/rules/global_rules.ts
index dd6d1fa5e90c29ac15bab80ed30f1d3affcfb9f1..c168807bffda3c74c90285a777039281cee9cb0a 100644
--- a/app/lib/rules/global_rules.ts
+++ b/app/lib/rules/global_rules.ts
@@ -16,7 +16,7 @@ import { FileDAL } from "../dal/fileDAL";
 import { DBBlock } from "../db/DBBlock";
 import { TransactionDTO, TxSignatureResult } from "../dto/TransactionDTO";
 import { BlockDTO } from "../dto/BlockDTO";
-import { verify } from "duniteroxyde";
+import { verify } from "../../../neon/lib";
 import { rawer, txunlock } from "../common-libs/index";
 import { CommonConstants } from "../common-libs/constants";
 import { IdentityDTO } from "../dto/IdentityDTO";
diff --git a/app/lib/rules/local_rules.ts b/app/lib/rules/local_rules.ts
index 81e52bee163b2f61729cb2cb30f97198ca7d7829..ea5f8a578e143bc9ad9dfd5c5eb39cb1a492846d 100644
--- a/app/lib/rules/local_rules.ts
+++ b/app/lib/rules/local_rules.ts
@@ -22,7 +22,7 @@ import {
 } from "../indexer";
 import { BaseDTO, TransactionDTO } from "../dto/TransactionDTO";
 import { DBBlock } from "../db/DBBlock";
-import { verify } from "duniteroxyde";
+import { verify } from "../../../neon/lib";
 import { hashf } from "../common";
 import { CommonConstants } from "../common-libs/constants";
 import { IdentityDTO } from "../dto/IdentityDTO";
diff --git a/app/lib/system/directory.ts b/app/lib/system/directory.ts
index 3a5e7c9ba3bfc0934e1cbe556ea34db5feed5f68..9c364b5c5489ec787ed90462b8be47a1ac5349da 100644
--- a/app/lib/system/directory.ts
+++ b/app/lib/system/directory.ts
@@ -15,7 +15,7 @@ import * as path from "path";
 import * as fs from "fs";
 import { SQLiteDriver } from "../dal/drivers/SQLiteDriver";
 import { CFSCore } from "../dal/fileDALs/CFSCore";
-import { Wot, WotBuilder } from "duniteroxyde";
+import { Wot, WotBuilder } from "../../../neon/lib";
 import { FileDALParams } from "../dal/fileDAL";
 import { cliprogram } from "../common-libs/programOptions";
 import { LevelDBDriver } from "../dal/drivers/LevelDBDriver";
diff --git a/app/modules/crawler/lib/req2fwd.ts b/app/modules/crawler/lib/req2fwd.ts
index 39b71672546cc8d07a9bae52bb3484d1ca23b306..14bee1a634139c3ea270bba8b9229d6c3297851b 100644
--- a/app/modules/crawler/lib/req2fwd.ts
+++ b/app/modules/crawler/lib/req2fwd.ts
@@ -12,7 +12,7 @@
 // GNU Affero General Public License for more details.
 
 import { Contacter } from "./contacter";
-import { verify } from "duniteroxyde";
+import { verify } from "../../../../neon/lib";
 import { rawer } from "../../../lib/common-libs/index";
 import { HttpRequirements } from "../../bma/lib/dtos";
 
diff --git a/app/modules/crawler/lib/sync/v2/GlobalIndexStream.ts b/app/modules/crawler/lib/sync/v2/GlobalIndexStream.ts
index b4c222601ac1f293f6e980ab79bd8340bf9386c8..c28345513b657b605e01e032a312b83954e4b013 100644
--- a/app/modules/crawler/lib/sync/v2/GlobalIndexStream.ts
+++ b/app/modules/crawler/lib/sync/v2/GlobalIndexStream.ts
@@ -18,7 +18,7 @@ import {
 import { BlockDTO } from "../../../../../lib/dto/BlockDTO";
 import { Underscore } from "../../../../../lib/common-libs/underscore";
 import { MonitorExecutionTime } from "../../../../../lib/debug/MonitorExecutionTime";
-import { Wot } from "duniteroxyde";
+import { Wot } from "../../../../../../neon/lib";
 import { NewLogger } from "../../../../../lib/logger";
 import { CommonConstants } from "../../../../../lib/common-libs/constants";
 import { DBBlock } from "../../../../../lib/db/DBBlock";
diff --git a/app/modules/keypair/lib/scrypt.ts b/app/modules/keypair/lib/scrypt.ts
index d66eba7fa7e74e2f464523b29103dcf5d4784a61..3135ecad6609695a3a0c43684155613337bbae2e 100644
--- a/app/modules/keypair/lib/scrypt.ts
+++ b/app/modules/keypair/lib/scrypt.ts
@@ -12,7 +12,7 @@
 // GNU Affero General Public License for more details.
 
 import * as crypto from "crypto";
-import { KeyPairBuilder, seedToSecretKey } from "duniteroxyde";
+import { KeyPairBuilder, seedToSecretKey } from "../../../../neon/lib";
 
 const SEED_LENGTH = 32; // Length of the key
 
diff --git a/app/modules/prover/lib/blockGenerator.ts b/app/modules/prover/lib/blockGenerator.ts
index 58917e2f1c99ed937c82f8b61a94979e0fe7051c..66c1aa75167741e95efc5517bf98c7271f9f3ba7 100644
--- a/app/modules/prover/lib/blockGenerator.ts
+++ b/app/modules/prover/lib/blockGenerator.ts
@@ -19,7 +19,7 @@ import { GLOBAL_RULES_HELPERS } from "../../../lib/rules/global_rules";
 import { LOCAL_RULES_HELPERS } from "../../../lib/rules/local_rules";
 import { Indexer } from "../../../lib/indexer";
 import { DBBlock } from "../../../lib/db/DBBlock";
-import { verify } from "duniteroxyde";
+import { verify } from "../../../../neon/lib";
 import { rawer } from "../../../lib/common-libs/index";
 import { hashf } from "../../../lib/common";
 import { CommonConstants } from "../../../lib/common-libs/constants";
diff --git a/app/modules/prover/lib/proof.ts b/app/modules/prover/lib/proof.ts
index 2f5e68d1cfa9a818f67e8a88bf63ae518889a709..f24d30571026488f51a3e663b20fdb2c9a5546c7 100644
--- a/app/modules/prover/lib/proof.ts
+++ b/app/modules/prover/lib/proof.ts
@@ -17,7 +17,7 @@ import { hashf } from "../../../lib/common";
 import { DBBlock } from "../../../lib/db/DBBlock";
 import { ConfDTO } from "../../../lib/dto/ConfDTO";
 import { ProverConstants } from "./constants";
-import { Ed25519Signator, KeyPairBuilder } from "duniteroxyde";
+import { Ed25519Signator, KeyPairBuilder } from "../../../../neon/lib";
 import { dos2unix } from "../../../lib/common-libs/dos2unix";
 import { rawer } from "../../../lib/common-libs/index";
 import { ProcessCpuProfiler } from "../../../ProcessCpuProfiler";
diff --git a/app/modules/ws2p/lib/WS2PCluster.ts b/app/modules/ws2p/lib/WS2PCluster.ts
index 535eea0191873f3db571ba47b6efd171611c3825..fe2d29e3cc184d9e6083966b902bc7049869e9ff 100644
--- a/app/modules/ws2p/lib/WS2PCluster.ts
+++ b/app/modules/ws2p/lib/WS2PCluster.ts
@@ -25,7 +25,7 @@ import { PeerDTO, WS2PEndpoint } from "../../../lib/dto/PeerDTO";
 import { GlobalFifoPromise } from "../../../service/GlobalFifoPromise";
 import { OtherConstants } from "../../../lib/other_constants";
 import { Key } from "../../../lib/common-libs/crypto/keyring";
-import { verify } from "duniteroxyde";
+import { verify } from "../../../../neon/lib";
 import { WS2PServerMessageHandler } from "./interface/WS2PServerMessageHandler";
 import { WS2PMessageHandler } from "./impl/WS2PMessageHandler";
 import { CommonConstants } from "../../../lib/common-libs/constants";
diff --git a/app/modules/ws2p/lib/WS2PConnection.ts b/app/modules/ws2p/lib/WS2PConnection.ts
index a049abbf55851c1b4ed0e9b9a1fdf44a809a5e15..e186327f196c8cd57512cd58f52668dc8544b403 100644
--- a/app/modules/ws2p/lib/WS2PConnection.ts
+++ b/app/modules/ws2p/lib/WS2PConnection.ts
@@ -12,7 +12,7 @@
 // GNU Affero General Public License for more details.
 
 import { Key } from "../../../lib/common-libs/crypto/keyring";
-import { verify } from "duniteroxyde";
+import { verify } from "../../../../neon/lib";
 import { WS2PMessageHandler } from "./impl/WS2PMessageHandler";
 import { BlockDTO } from "../../../lib/dto/BlockDTO";
 import { IdentityDTO } from "../../../lib/dto/IdentityDTO";
diff --git a/app/service/IdentityService.ts b/app/service/IdentityService.ts
index 9833f05d4c4df44c6b195352bdca0757a0d195d8..676b8602a57b183a8582444c9be37e77ca39cd12 100644
--- a/app/service/IdentityService.ts
+++ b/app/service/IdentityService.ts
@@ -24,7 +24,7 @@ import { RevocationDTO } from "../lib/dto/RevocationDTO";
 import { BasicIdentity, IdentityDTO } from "../lib/dto/IdentityDTO";
 import { CertificationDTO } from "../lib/dto/CertificationDTO";
 import { DBCert } from "../lib/dal/sqliteDAL/CertDAL";
-import { verify } from "duniteroxyde";
+import { verify } from "../../neon/lib";
 import { FIFOService } from "./FIFOService";
 import { MindexEntry } from "../lib/indexer";
 import { DataErrors } from "../lib/common-libs/errors";
diff --git a/app/service/PeeringService.ts b/app/service/PeeringService.ts
index 0e2eb198b9971d9996ad276aa1d778c4a0119a97..6fd0a104effdeeaaed010a21e95a6a303a10a5f2 100755
--- a/app/service/PeeringService.ts
+++ b/app/service/PeeringService.ts
@@ -16,7 +16,7 @@ import { FileDAL } from "../lib/dal/fileDAL";
 import { DBBlock } from "../lib/db/DBBlock";
 import { Multicaster } from "../lib/streams/multicaster";
 import { PeerDTO } from "../lib/dto/PeerDTO";
-import { verify } from "duniteroxyde";
+import { verify } from "../../neon/lib";
 import { dos2unix } from "../lib/common-libs/dos2unix";
 import { rawer } from "../lib/common-libs/index";
 import { Server } from "../../server";
diff --git a/neon/README.md b/neon/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..72e50726ae403764e4d24075d8625f9ec81a0663
--- /dev/null
+++ b/neon/README.md
@@ -0,0 +1,39 @@
+# Duniteroxyde
+
+`duniteroxyde` is a binding for [Duniter] of the [dubp-rs-libs] libraries, a set of libraries to implement the [DUBP] protocol.
+
+[Duniter]: https://duniter.org/en/
+[dubp-rs-libs]: https://git.duniter.org/libs/dubp-rs-libs
+[DUBP]: https://git.duniter.org/documents/rfcs/-/blob/master/rfc/0010_Duniter_Blockchain_Protocol_V12.md
+
+## How to set up your development environment (or to compile manually)
+
+### Requirements
+
+You'll need nvm, yarn, and rust:
+
+- [yarn install instructions](https://classic.yarnpkg.com/en/docs/install)
+- [nvm install instructions](https://github.com/nvm-sh/nvm#installing-and-updating)
+- [rust install instructions](https://www.rust-lang.org/learn/get-started)
+
+Once these tools are installed, use nvm to install node 10:
+
+    nvm install 10
+
+Finally, before each work session on Duniteroxide, select Node 10:
+
+    nvm use 10
+
+### Compile
+
+WARNING: It takes a long time and consumes high cpu !
+
+Run the following command at the root of the repository:
+
+    yarn
+
+### Test
+
+Run the following command at the root of the repository:
+
+    yarn test
diff --git a/neon/lib/crypto.js b/neon/lib/crypto.js
new file mode 100644
index 0000000000000000000000000000000000000000..18537334af2af98897fb0606c86521de3c20891f
--- /dev/null
+++ b/neon/lib/crypto.js
@@ -0,0 +1,20 @@
+const addon = require('../native/index.node');
+
+const { Ed25519Signator, generateRandomSeed, seedToSecretKey, sha256, verify } = addon;
+
+class KeyPairBuilder {
+
+    static fromSeed(seed) {
+        return new Ed25519Signator(seed);
+    }
+
+    static fromSecretKey(secretKey) {
+        return new Ed25519Signator(secretKey);
+    }
+
+    static random() {
+        return addon.generateRandomSeed();
+    }
+}
+
+module.exports = { Ed25519Signator, KeyPairBuilder, generateRandomSeed, seedToSecretKey, sha256, verify };
diff --git a/neon/lib/index.d.ts b/neon/lib/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7a5ef5ad420af12593e60df59a7aefb88cdf924b
--- /dev/null
+++ b/neon/lib/index.d.ts
@@ -0,0 +1,91 @@
+/* tslint:disable */
+
+export class KeyPairBuilder {
+
+    static fromSeed(seed: Buffer): Ed25519Signator;
+
+    static fromSecretKey(secretKey: string): Ed25519Signator;
+
+    static random(): Ed25519Signator;
+}
+
+export class Ed25519Signator {
+
+    getPublicKey(): string;
+
+    sign(message: Buffer | string): string;
+}
+
+export function generateRandomSeed(): Buffer;
+export function seedToSecretKey(seed: Buffer): string;
+export function sha256(data: string): string;
+export function verify(message: Buffer | string, sig: string, pubkey: string): boolean;
+
+export class DetailedDistance {
+    nbSentries: number;
+    nbSuccess: number;
+    nbSuccessAtBorder: number;
+    nbReached: number;
+    nbReachedAtBorder: number;
+    isOutdistanced: number;
+}
+
+export class WotBuilder {
+    static fromWot(wot: Wot): Wot;
+
+    static fromFile(filePath: string): Wot;
+}
+
+export class Wot {
+    constructor(maxCert: number);
+
+    clear(): void;
+
+    getMaxCert(): number;
+
+    setMaxCert(maxCert: number): void;
+
+    addNode(): number;
+
+    removeNode(): number;
+
+    getWoTSize(): number;
+
+    isEnabled(node_id: number): boolean;
+
+    getEnabled(): number[];
+
+    setEnabled(enabled: boolean, node_id: number): boolean;
+
+    getDisabled(): number[];
+
+    getSentries(sentry_requirement: number): number[];
+
+    getNonSentries(sentry_requirement: number): number[];
+
+    addLink(source: number, target: number): number;
+
+    existsLink(source: number, target: number): boolean;
+
+    removeLink(source: number, target: number): number;
+
+    isOutdistanced(
+        node_id: number,
+        sentry_requirement: number,
+        step_max: number,
+        x_percent: number
+    ): boolean;
+
+    detailedDistance(
+        nde_id: number,
+        sentry_requirement: number,
+        step_max: number,
+        x_percent: number
+    ): DetailedDistance;
+
+    getPaths(source: number, target: number, step_max: number): number[][];
+
+    writeInFile(file_path: string): boolean;
+
+    dump(): string;
+}
diff --git a/neon/lib/index.js b/neon/lib/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ebb99a4cf67244f5fc17cfc96799a3baec2ed43
--- /dev/null
+++ b/neon/lib/index.js
@@ -0,0 +1,4 @@
+const { Wot, WotBuilder } = require('./wot');
+const { Ed25519Signator, KeyPairBuilder, generateRandomSeed, seedToSecretKey, sha256, verify } = require('./crypto');
+
+module.exports = { Ed25519Signator, KeyPairBuilder, generateRandomSeed, seedToSecretKey, sha256, verify, Wot, WotBuilder };
diff --git a/neon/lib/wot.js b/neon/lib/wot.js
new file mode 100644
index 0000000000000000000000000000000000000000..f2ae9703d6f841a80fb1efebb56b680bd34638f6
--- /dev/null
+++ b/neon/lib/wot.js
@@ -0,0 +1,16 @@
+const addon = require('../native/index.node');
+
+const { Wot } = addon;
+
+class WotBuilder {
+
+    static fromWot(wot) {
+        return new Wot(wot.toBytes());
+    }
+
+    static fromFile(filePath) {
+        return new Wot(filePath)
+    }
+}
+
+module.exports = { Wot, WotBuilder };
diff --git a/neon/native/Cargo.toml b/neon/native/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..7331a0a471d4617948e4b9b10b3531428ad46393
--- /dev/null
+++ b/neon/native/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "duniteroxyde"
+version = "0.2.9"
+authors = ["librelois <elois@ifee.fr>"]
+license = "AGPL-3.0"
+build = "build.rs"
+edition = "2018"
+exclude = ["artifacts.json", "index.node"]
+
+[lib]
+name = "duniteroxyde"
+crate-type = ["cdylib"]
+
+[build-dependencies]
+neon-build = "0.4.0"
+
+[dependencies]
+bincode = "1.2.1"
+bs58 = "0.3.0"
+dup-crypto = { version = "0.15.0", default-features = false, features = ["rand"] }
+dubp-wot = "0.11.0"
+flate2 = "1.0.14"
+neon = "0.4.0"
diff --git a/neon/native/artifacts.json b/neon/native/artifacts.json
new file mode 100644
index 0000000000000000000000000000000000000000..3f346e098060aa63ab49162d2e1b63335e8b2b02
--- /dev/null
+++ b/neon/native/artifacts.json
@@ -0,0 +1 @@
+{"active":"release","targets":{"debug":{"rustc":"","env":{"npm_config_target":null,"npm_config_arch":null,"npm_config_target_arch":null,"npm_config_disturl":null,"npm_config_runtime":null,"npm_config_build_from_source":null,"npm_config_devdir":null}},"release":{"rustc":"","env":{"npm_config_target":null,"npm_config_arch":null,"npm_config_target_arch":null,"npm_config_disturl":null,"npm_config_runtime":null,"npm_config_build_from_source":null,"npm_config_devdir":null}}}}
\ No newline at end of file
diff --git a/neon/native/build.rs b/neon/native/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..687a6619460e768d374855902515d54e52d23a56
--- /dev/null
+++ b/neon/native/build.rs
@@ -0,0 +1,7 @@
+extern crate neon_build;
+
+fn main() {
+    neon_build::setup(); // must be called in build.rs
+
+    // add project-specific build logic here...
+}
diff --git a/neon/native/index.node b/neon/native/index.node
new file mode 100644
index 0000000000000000000000000000000000000000..449c33850699110c7b5d0dddeefc2dc2ab218779
Binary files /dev/null and b/neon/native/index.node differ
diff --git a/neon/native/src/crypto.rs b/neon/native/src/crypto.rs
new file mode 100644
index 0000000000000000000000000000000000000000..76414e8dfbdc51a91b14a6dc7acf7bef828a2186
--- /dev/null
+++ b/neon/native/src/crypto.rs
@@ -0,0 +1,210 @@
+//  Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// 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/>.
+
+use crate::into_neon_res;
+use dup_crypto::bases::b58::ToBase58;
+use dup_crypto::hashs::Hash;
+use dup_crypto::keys::{
+    ed25519::{
+        Ed25519KeyPair, KeyPairFromSeed32Generator, PublicKey as Ed25519PublicKey,
+        Signator as Ed25519Signator, Signature as Ed25519Signature,
+    },
+    KeyPair, PublicKey, Signator, Signature,
+};
+use dup_crypto::seeds::Seed32;
+use neon::declare_types;
+use neon::prelude::*;
+use std::ops::Deref;
+
+pub fn generate_random_seed(mut cx: FunctionContext) -> JsResult<JsBuffer> {
+    let seed = into_neon_res(
+        &mut cx,
+        Seed32::random().map_err(|_| "fail to generate random seed"),
+    )?;
+
+    let mut js_buffer = JsBuffer::new(&mut cx, 32)?;
+
+    cx.borrow_mut(&mut js_buffer, |data| {
+        let slice = data.as_mut_slice::<u8>();
+        slice.copy_from_slice(seed.as_ref());
+    });
+
+    Ok(js_buffer)
+}
+
+pub fn seed_to_expanded_base58_secret_key(mut cx: FunctionContext) -> JsResult<JsString> {
+    let seed_js_buffer = cx.argument::<JsBuffer>(0)?;
+
+    let mut seed_bytes = [0u8; 32];
+    cx.borrow(&seed_js_buffer, |data| {
+        seed_bytes.copy_from_slice(data.as_slice::<u8>());
+    });
+    let keypair = KeyPairFromSeed32Generator::generate(Seed32::new(seed_bytes));
+
+    let mut expanded_secret_key_bytes = [0u8; 64];
+    expanded_secret_key_bytes[0..32].copy_from_slice(seed_bytes.as_ref());
+    expanded_secret_key_bytes[32..64].copy_from_slice(&keypair.public_key().as_ref()[..32]);
+
+    let expanded_base58_secret_key = bs58::encode(expanded_secret_key_bytes.as_ref()).into_string();
+
+    Ok(cx.string(expanded_base58_secret_key))
+}
+
+pub fn sha256(mut cx: FunctionContext) -> JsResult<JsString> {
+    let str_datas = cx.argument::<JsString>(0)?.value();
+    Ok(cx.string(Hash::compute_str(&str_datas).to_hex().to_uppercase()))
+}
+
+pub fn verify(mut cx: FunctionContext) -> JsResult<JsBoolean> {
+    let message = cx.argument::<JsValue>(0)?;
+    let sig_base58 = cx.argument::<JsString>(1)?.value();
+    let public_key_base58 = cx.argument::<JsString>(2)?.value();
+
+    match Ed25519Signature::from_base64(&sig_base58) {
+        Ok(signature) => match Ed25519PublicKey::from_base58(&public_key_base58) {
+            Ok(public_key) => apply_to_js_message(&mut cx, message, |cx, bytes| {
+                Ok(cx.boolean(public_key.verify(bytes, &signature).is_ok()))
+            }),
+            Err(_) => Ok(cx.boolean(false)),
+        },
+        Err(_) => Ok(cx.boolean(false)),
+    }
+}
+
+declare_types! {
+    pub class JsKeyPair for Ed25519Signator {
+        init(mut cx) {
+            if let Some(arg0) = cx.argument_opt(0) {
+                if arg0.is_a::<JsString>() {
+                    let expanded_base58_secret_key = arg0
+                        .downcast::<JsString>()
+                        .or_throw(&mut cx)?
+                        .value();
+                        into_neon_res(&mut cx, keypair_from_expanded_base58_secret_key(&expanded_base58_secret_key))
+                } else if arg0.is_a::<JsBuffer>() {
+                    let seed_js_buffer = arg0
+                        .downcast::<JsBuffer>()
+                        .or_throw(&mut cx)?;
+                    let mut seed_bytes = [0u8; 32];
+                    cx.borrow(&seed_js_buffer, |data| {
+                        seed_bytes.copy_from_slice(data.as_slice::<u8>());
+                    });
+                    let keypair = KeyPairFromSeed32Generator::generate(Seed32::new(seed_bytes));
+                    Ok(keypair.generate_signator())
+                } else {
+                    cx.throw_type_error("arg0 must be a string")
+                }
+            } else {
+                match Ed25519KeyPair::generate_random() {
+                    Ok(keypair) => Ok(keypair.generate_signator()),
+                    Err(_) => cx.throw_error("fail to generate random keypair"),
+                }
+            }
+
+        }
+
+        method getPublicKey(mut cx) {
+            let this = cx.this();
+            let public_key = {
+                let guard = cx.lock();
+                let keypair = this.borrow(&guard);
+                keypair.public_key()
+            };
+
+            Ok(cx.string(public_key.to_base58()).upcast())
+        }
+
+        method sign(mut cx) {
+            let message = cx.argument::<JsValue>(0)?;
+            apply_to_js_message(&mut cx, message, |cx, bytes| {
+                sign_bytes(cx, bytes)
+            })
+        }
+    }
+}
+
+fn keypair_from_expanded_base58_secret_key(
+    expanded_base58_secret_key: &str,
+) -> Result<Ed25519Signator, &'static str> {
+    let bytes = bs58::decode(expanded_base58_secret_key)
+        .into_vec()
+        .map_err(|_| "fail to decode b58")?;
+
+    let mut seed = [0u8; 32];
+    seed.copy_from_slice(&bytes[..32]);
+    let mut pubkey_bytes = [0u8; 32];
+    pubkey_bytes.copy_from_slice(&bytes[32..64]);
+
+    let keypair = KeyPairFromSeed32Generator::generate(Seed32::new(seed));
+
+    //let expected_pubkey = Ed25519PublicKey::try_from(pubkey_bytes.as_ref());
+
+    if keypair.public_key().as_ref()[..32] == pubkey_bytes {
+        Ok(keypair.generate_signator())
+    } else {
+        Err("corrupted keypair")
+    }
+}
+
+fn apply_to_js_message<'c, C: Context<'c>, T, F: FnOnce(&mut C, &[u8]) -> NeonResult<T>>(
+    cx: &mut C,
+    message: Handle<'c, JsValue>,
+    f: F,
+) -> NeonResult<T> {
+    if message.is_a::<JsString>() {
+        let message_str = message.downcast::<JsString>().or_throw(cx)?.value();
+        f(cx, message_str.as_bytes())
+    } else if message.is_a::<JsBuffer>() {
+        let js_buffer = message.downcast::<JsBuffer>().or_throw(cx)?;
+        let bytes = cx.borrow(&js_buffer, |data| data.as_slice::<u8>());
+        f(cx, bytes)
+    } else {
+        cx.throw_type_error("Message must be a string or buffer")
+    }
+}
+
+fn sign_bytes<'c>(
+    cx: &mut MethodContext<'c, JsKeyPair>,
+    bytes: &[u8],
+) -> NeonResult<Handle<'c, JsValue>> {
+    let this = cx.this();
+    let sig = {
+        let guard = cx.lock();
+        let keypair_box = this.borrow(&guard);
+        let keypair: &Ed25519Signator = keypair_box.deref();
+        keypair.sign(bytes)
+    };
+
+    Ok(cx.string(sig.to_base64()).upcast())
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    #[test]
+    fn test_keypair_from_expanded_base58_secret_key() {
+        let expanded_base58_secret_key = "51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP";
+
+        let signator = keypair_from_expanded_base58_secret_key(expanded_base58_secret_key)
+            .expect("fail to generate keypair");
+
+        assert_eq!(
+            "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd",
+            signator.public_key().to_base58(),
+        )
+    }
+}
diff --git a/neon/native/src/lib.rs b/neon/native/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..94aa1964de9374642d5aff07763705765f6ce4d5
--- /dev/null
+++ b/neon/native/src/lib.rs
@@ -0,0 +1,42 @@
+//  Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// 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/>.
+
+mod crypto;
+mod wot;
+
+use neon::{prelude::*, register_module};
+
+fn into_neon_res<'c, C: Context<'c>, T, S: AsRef<str>>(
+    context: &mut C,
+    rust_result: Result<T, S>,
+) -> NeonResult<T> {
+    match rust_result {
+        Ok(value) => Ok(value),
+        Err(e) => context.throw_error(e),
+    }
+}
+
+register_module!(mut cx, {
+    cx.export_function("generateRandomSeed", crate::crypto::generate_random_seed)?;
+    cx.export_function(
+        "seedToSecretKey",
+        crate::crypto::seed_to_expanded_base58_secret_key,
+    )?;
+    cx.export_function("sha256", crate::crypto::sha256)?;
+    cx.export_function("verify", crate::crypto::verify)?;
+    cx.export_class::<crate::crypto::JsKeyPair>("Ed25519Signator")?;
+    cx.export_class::<crate::wot::JsWoT>("Wot")?;
+    Ok(())
+});
diff --git a/neon/native/src/wot.rs b/neon/native/src/wot.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5390df0ce9e11c3b27cd754ca4ae638da198f1f7
--- /dev/null
+++ b/neon/native/src/wot.rs
@@ -0,0 +1,441 @@
+//  Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// 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/>.
+
+mod read_from_file;
+mod write_in_file;
+
+use dubp_wot::{
+    data::{
+        rusty::RustyWebOfTrust, HasLinkResult, NewLinkResult, RemLinkResult, WebOfTrust, WotId,
+    },
+    operations::distance::{
+        DistanceCalculator, RustyDistanceCalculator, WotDistance, WotDistanceParameters,
+    },
+    operations::path::{PathFinder, RustyPathFinder},
+};
+use neon::declare_types;
+use neon::prelude::*;
+use std::ops::Deref;
+
+declare_types! {
+    pub class JsWoT for RustyWebOfTrust {
+        init(mut cx) {
+            let arg0 = cx.argument::<JsValue>(0)?;
+
+            if arg0.is_a::<JsNumber>() {
+                let max_links = arg0
+                .downcast::<JsNumber>()
+                .or_throw(&mut cx)?
+                .value();
+                Ok(RustyWebOfTrust::new(max_links as usize))
+            } else if arg0.is_a::<JsString>() {
+                let file_path = arg0
+                .downcast::<JsString>()
+                .or_throw(&mut cx)?
+                .value();
+                match read_from_file::wot_from_file(file_path) {
+                    Ok(wot) => Ok(wot),
+                    Err(e) => cx.throw_error(e),
+                }
+            } else if arg0.is_a::<JsArrayBuffer>() {
+                let js_buffer = arg0
+                .downcast::<JsArrayBuffer>()
+                .or_throw(&mut cx)?;
+
+                let bytes = cx.borrow(&js_buffer, |data| {
+                    let slice = data.as_slice::<u8>();
+                    Vec::from(slice)
+                });
+
+                match bincode::deserialize(&bytes) {
+                    Ok(wot) => Ok(wot),
+                    Err(e) => cx.throw_error(e.to_string()),
+                }
+            } else {
+                panic!("Expected file path or max links.");
+            }
+        }
+
+        method clear(mut cx) {
+            let mut this = cx.this();
+            {
+                let guard = cx.lock();
+                let mut wot = this.borrow_mut(&guard);
+                wot.clear();
+            }
+
+            Ok(cx.undefined().upcast())
+        }
+
+        method getMaxCert(mut cx) {
+            let this = cx.this();
+            let max_link = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.get_max_link()
+            };
+            Ok(cx.number(max_link as f64).upcast())
+        }
+
+        method setMaxCert(mut cx) {
+            let max_links = cx.argument::<JsNumber>(0)?.value() as usize;
+            let mut this = cx.this();
+            {
+                let guard = cx.lock();
+                let mut wot = this.borrow_mut(&guard);
+                wot.set_max_link(max_links);
+            }
+            Ok(cx.undefined().upcast())
+        }
+
+        method addNode(mut cx) {
+            let mut this = cx.this();
+            let wot_id = {
+                let guard = cx.lock();
+                let mut wot = this.borrow_mut(&guard);
+                wot.add_node()
+            };
+            Ok(cx.number(wot_id.0 as f64).upcast())
+        }
+
+        method removeNode(mut cx) {
+            let mut this = cx.this();
+            let wot_id_opt = {
+                let guard = cx.lock();
+                let mut wot = this.borrow_mut(&guard);
+                wot.rem_node()
+            };
+
+            if let Some(wot_id) = wot_id_opt {
+                Ok(cx.number(wot_id.0 as f64).upcast())
+            } else {
+                cx.throw_error("empty wot")
+            }
+        }
+
+        method getWoTSize(mut cx) {
+            let this = cx.this();
+            let wot_size = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.size()
+            };
+            Ok(cx.number(wot_size as f64).upcast())
+        }
+
+        method isEnabled(mut cx) {
+            let wot_id = WotId(cx.argument::<JsNumber>(0)?.value() as usize);
+            let this = cx.this();
+            let is_enabled_opt = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.is_enabled(wot_id)
+            };
+
+            if let Some(is_enabled) = is_enabled_opt {
+                Ok(cx.boolean(is_enabled).upcast())
+            } else {
+                cx.throw_error(format!("node '{}' not exist.", wot_id.0))
+            }
+        }
+
+        method getEnabled(mut cx) {
+            let this = cx.this();
+            let enabled = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.get_enabled()
+            };
+
+            vec_wot_id_to_js_array(cx, enabled)
+        }
+
+        method setEnabled(mut cx) {
+            let enabled = cx.argument::<JsBoolean>(0)?.value();
+            let wot_id = WotId(cx.argument::<JsNumber>(1)?.value() as usize);
+
+            let mut this = cx.this();
+            let enabled_opt = {
+                let guard = cx.lock();
+                let mut wot = this.borrow_mut(&guard);
+                wot.set_enabled(wot_id, enabled)
+            };
+
+            if let Some(enabled) = enabled_opt {
+                Ok(cx.boolean(enabled).upcast())
+            } else {
+                cx.throw_error(format!("node '{}' not exist.", wot_id.0))
+            }
+        }
+
+        method getDisabled(mut cx) {
+            let this = cx.this();
+            let disabled = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.get_disabled()
+            };
+
+            vec_wot_id_to_js_array(cx, disabled)
+        }
+
+        method getSentries(mut cx) {
+            let sentry_requirement = cx.argument::<JsNumber>(0)?.value();
+            let this = cx.this();
+            let sentries = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.get_sentries(sentry_requirement as usize)
+            };
+
+            vec_wot_id_to_js_array(cx, sentries)
+        }
+
+        method getNonSentries(mut cx) {
+            let sentry_requirement = cx.argument::<JsNumber>(0)?.value();
+            let this = cx.this();
+            let non_sentries = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.get_non_sentries(sentry_requirement as usize)
+            };
+
+            vec_wot_id_to_js_array(cx, non_sentries)
+        }
+
+        method addLink(mut cx) {
+            let source = WotId(cx.argument::<JsNumber>(0)?.value() as usize);
+            let target = WotId(cx.argument::<JsNumber>(1)?.value() as usize);
+
+            let mut this = cx.this();
+            let new_link_result = {
+                let guard = cx.lock();
+                let mut wot = this.borrow_mut(&guard);
+                wot.add_link(source, target)
+            };
+
+            match new_link_result {
+                NewLinkResult::Ok(count_target_received_certs) |
+                    NewLinkResult::AllCertificationsUsed(count_target_received_certs) =>
+                        Ok(cx.number(count_target_received_certs as f64).upcast()),
+                NewLinkResult::SelfLinkingForbidden() => cx.throw_error( "self linking forbidden"),
+                NewLinkResult::UnknownSource() => cx.throw_error(format!("fail to add link {}->{}: unknown source", source.0, target.0)),
+                NewLinkResult::UnknownTarget() => cx.throw_error(format!("fail to add link {}->{}: unknown target", source.0, target.0)),
+            }
+        }
+
+        method existsLink(mut cx) {
+            let source = WotId(cx.argument::<JsNumber>(0)?.value() as usize);
+            let target = WotId(cx.argument::<JsNumber>(1)?.value() as usize);
+
+            let this = cx.this();
+            let has_link_result = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.has_link(source, target)
+            };
+
+            match has_link_result {
+                HasLinkResult::UnknownSource() => cx.throw_error(format!("fail to check link {}->{}: unknown source", source.0, target.0)),
+                HasLinkResult::UnknownTarget() => cx.throw_error(format!("fail to check link {}->{}: unknown target", source.0, target.0)),
+                HasLinkResult::Link(has_link) => Ok(cx.boolean(has_link).upcast()),
+            }
+        }
+
+        method removeLink(mut cx) {
+            let source = WotId(cx.argument::<JsNumber>(0)?.value() as usize);
+            let target = WotId(cx.argument::<JsNumber>(1)?.value() as usize);
+
+            let mut this = cx.this();
+            let rem_link_result = {
+                let guard = cx.lock();
+                let mut wot = this.borrow_mut(&guard);
+                wot.rem_link(source, target)
+            };
+
+            match rem_link_result {
+                RemLinkResult::Removed(count_target_received_certs) |
+                RemLinkResult::UnknownCert(count_target_received_certs) =>
+                        Ok(cx.number(count_target_received_certs as f64).upcast()),
+                RemLinkResult::UnknownSource() => cx.throw_error("unknown source"),
+                RemLinkResult::UnknownTarget() => cx.throw_error("unknown target"),
+            }
+        }
+
+        method isOutdistanced(mut cx) {
+            let distance_params = get_distance_params_from_js(&mut cx)?;
+
+            let this = cx.this();
+            let distance_response_opt = {
+                let guard = cx.lock();
+                let wot_box = this.borrow(&guard);
+                let wot: &RustyWebOfTrust = wot_box.deref();
+                RustyDistanceCalculator {}.compute_distance(wot, distance_params)
+            };
+
+            if let Some(distance_response) = distance_response_opt {
+                Ok(cx.boolean(distance_response.outdistanced).upcast())
+            } else {
+                cx.throw_error(format!("node '{}' not exist.", distance_params.node.0))
+            }
+        }
+
+        method detailedDistance(mut cx) {
+            let distance_params = get_distance_params_from_js(&mut cx)?;
+
+            let this = cx.this();
+            let distance_response_opt = {
+                let guard = cx.lock();
+                let wot_box = this.borrow(&guard);
+                let wot: &RustyWebOfTrust = wot_box.deref();
+                RustyDistanceCalculator {}.compute_distance(wot, distance_params)
+            };
+
+            if let Some(distance_response) = distance_response_opt {
+                distance_response_to_js_object(cx, distance_response)
+            } else {
+                cx.throw_error(format!("node '{}' not exist.", distance_params.node.0))
+            }
+        }
+
+        method getPaths(mut cx) {
+            // Get parameters
+            let from = WotId(cx.argument::<JsNumber>(0)?.value() as usize);
+            let to = WotId(cx.argument::<JsNumber>(1)?.value() as usize);
+            let k_max = cx.argument::<JsNumber>(2)?.value() as u32;
+
+            // Call rust PathFinder
+            let this = cx.this();
+            let paths = {
+                let guard = cx.lock();
+                let wot_box = this.borrow(&guard);
+                let wot: &RustyWebOfTrust = wot_box.deref();
+                RustyPathFinder {}.find_paths(wot, from, to, k_max)
+            };
+
+            // Convert Vec<Vec<WotId>> to JsArray<JsArray<JsNumber>>
+            let js_array_paths = JsArray::new(&mut cx, paths.len() as u32);
+            for (i, path) in paths.iter().enumerate() {
+                let js_array_path = JsArray::new(&mut cx, path.len() as u32);
+                for (j, wot_id) in path.iter().enumerate() {
+                    let js_number = cx.number(wot_id.0 as f64);
+                    js_array_path.set(&mut cx, j as u32, js_number)?;
+                }
+                js_array_paths.set(&mut cx, i as u32, js_array_path)?;
+            }
+
+            Ok(js_array_paths.upcast())
+        }
+
+        method toBytes(mut cx) {
+            let this = cx.this();
+            let ser_res = {
+                let guard = cx.lock();
+                let wot_box = this.borrow(&guard);
+                let wot: &RustyWebOfTrust = wot_box.deref();
+                bincode::serialize(wot)
+            };
+
+            match ser_res {
+                Ok(bytes) => {
+                    let mut js_buffer = cx.array_buffer(bytes.len() as u32)?;
+                    cx.borrow_mut(&mut js_buffer, |data| {
+                        data.as_mut_slice::<u8>().copy_from_slice(&bytes)
+                    });
+                    Ok(js_buffer.upcast())
+                },
+                Err(e) => cx.throw_error(e.to_string())
+            }
+        }
+
+        method writeInFile(mut cx) {
+            let file_path_str = cx.argument::<JsString>(0)?.value();
+
+            let this = cx.this();
+            let res = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                write_in_file::wot_in_file(file_path_str, wot.deref())
+            };
+
+            match res {
+                Ok(()) => Ok(cx.boolean(true).upcast()),
+                Err(e) => cx.throw_error(e),
+            }
+        }
+
+        method dump(mut cx) {
+            let mut dump_wot_chars = Vec::new();
+
+            let this = cx.this();
+            let res = {
+                let guard = cx.lock();
+                let wot = this.borrow(&guard);
+                wot.dump(&mut dump_wot_chars)
+            };
+            match res {
+                Ok(()) => match String::from_utf8(dump_wot_chars) {
+                    Ok(dump_wot2_str) => Ok(cx.string(dump_wot2_str).upcast()),
+                    Err(e) => cx.throw_error(e.to_string()),
+                },
+                Err(e) => cx.throw_error(e.to_string()),
+            }
+        }
+    }
+}
+
+fn vec_wot_id_to_js_array(
+    mut cx: MethodContext<JsWoT>,
+    vec: Vec<WotId>,
+) -> NeonResult<Handle<JsValue>> {
+    let js_array = JsArray::new(&mut cx, vec.len() as u32);
+    for (i, wot_id) in vec.iter().enumerate() {
+        let js_number = cx.number(wot_id.0 as f64);
+        js_array.set(&mut cx, i as u32, js_number)?;
+    }
+    Ok(js_array.upcast())
+}
+
+fn get_distance_params_from_js(cx: &mut MethodContext<JsWoT>) -> NeonResult<WotDistanceParameters> {
+    Ok(WotDistanceParameters {
+        node: WotId(cx.argument::<JsNumber>(0)?.value() as usize),
+        sentry_requirement: cx.argument::<JsNumber>(1)?.value() as u32,
+        step_max: cx.argument::<JsNumber>(2)?.value() as u32,
+        x_percent: cx.argument::<JsNumber>(3)?.value(),
+    })
+}
+
+fn distance_response_to_js_object(
+    mut cx: MethodContext<JsWoT>,
+    distance_response: WotDistance,
+) -> NeonResult<Handle<JsValue>> {
+    let object = JsObject::new(&mut cx);
+
+    let sentries = cx.number(distance_response.sentries as f64);
+    let success = cx.number(distance_response.success as f64);
+    let success_at_border = cx.number(distance_response.success_at_border as f64);
+    let reached = cx.number(distance_response.reached as f64);
+    let reached_at_border = cx.number(distance_response.reached_at_border as f64);
+    let outdistanced = cx.boolean(distance_response.outdistanced);
+
+    object.set(&mut cx, "nbSentries", sentries)?;
+    object.set(&mut cx, "nbSuccess", success)?;
+    object.set(&mut cx, "nbSuccessAtBorder", success_at_border)?;
+    object.set(&mut cx, "nbReached", reached)?;
+    object.set(&mut cx, "nbReachedAtBorder", reached_at_border)?;
+    object.set(&mut cx, "isOutdistanced", outdistanced)?;
+
+    Ok(object.upcast())
+}
diff --git a/neon/native/src/wot/read_from_file.rs b/neon/native/src/wot/read_from_file.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b9d2a75819935886da4adc10c2b13b260bc9b117
--- /dev/null
+++ b/neon/native/src/wot/read_from_file.rs
@@ -0,0 +1,139 @@
+//  Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// 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/>.
+
+use dubp_wot::data::{rusty::RustyWebOfTrust, WebOfTrust, WotId};
+use flate2::read::ZlibDecoder;
+use std::convert::TryFrom;
+use std::fs::File;
+use std::io::prelude::*;
+use std::io::BufReader;
+use std::path::{Path, PathBuf};
+
+pub(crate) fn wot_from_file(file_path_str: String) -> Result<RustyWebOfTrust, String> {
+    let file_path = PathBuf::try_from(&file_path_str).map_err(|e| format!("{}", e))?;
+    if file_path_str.ends_with(".gz") {
+        let bytes = read_and_decompress_bytes_from_file(file_path.as_path())
+            .map_err(|e| format!("{}", e))?;
+        if bytes.is_empty() {
+            Ok(RustyWebOfTrust::default())
+        } else {
+            Ok(bincode::deserialize::<RustyWebOfTrust>(&bytes).map_err(|e| format!("{}", e))?)
+        }
+    } else {
+        let bytes = read_bytes_from_file(file_path.as_path()).map_err(|e| format!("{}", e))?;
+        from_cpp_wot(&bytes)
+    }
+}
+
+/// Read bytes from file
+fn read_bytes_from_file(file_path: &Path) -> Result<Vec<u8>, std::io::Error> {
+    let file = File::open(file_path)?;
+
+    let mut buf_reader = BufReader::new(file);
+
+    let mut decompressed_bytes = Vec::new();
+    buf_reader.read_to_end(&mut decompressed_bytes)?;
+
+    Ok(decompressed_bytes)
+}
+
+/// Read and decompress bytes from file
+fn read_and_decompress_bytes_from_file(file_path: &Path) -> Result<Vec<u8>, std::io::Error> {
+    if !file_path.exists() {
+        if let Some(parent) = file_path.parent() {
+            std::fs::create_dir_all(parent)?
+        }
+        File::create(file_path)?;
+    }
+    if std::fs::metadata(file_path)?.len() > 0 {
+        let file = File::open(file_path)?;
+        let mut z = ZlibDecoder::new(file);
+        let mut decompressed_bytes = Vec::new();
+        z.read_to_end(&mut decompressed_bytes)?;
+
+        Ok(decompressed_bytes)
+    } else {
+        Ok(vec![])
+    }
+}
+
+fn from_cpp_wot(bytes: &[u8]) -> Result<RustyWebOfTrust, String> {
+    if bytes.len() < 8 {
+        return Err("wot file is corrupted".to_owned());
+    }
+
+    let mut buffer = [0u8; 4];
+    let mut cursor = 0;
+
+    // Read max_links and create empty wot
+    buffer.copy_from_slice(&bytes[cursor..cursor + 4]);
+    cursor += 4;
+    let max_links = u32::from_le_bytes(buffer);
+    let mut wot = RustyWebOfTrust::new(max_links as usize);
+
+    // Read nodes count
+    buffer.copy_from_slice(&bytes[cursor..cursor + 4]);
+    cursor += 4;
+    let nodes_count = u32::from_le_bytes(buffer);
+
+    for _ in 0..nodes_count {
+        let wot_id = wot.add_node();
+
+        // Read enabled
+        let enabled = bytes[cursor];
+        cursor += 1;
+        if enabled == 0 {
+            wot.set_enabled(wot_id, false);
+        }
+
+        // Read certs_count
+        buffer.copy_from_slice(&bytes[cursor..cursor + 4]);
+        cursor += 4;
+        let certs_count = u32::from_le_bytes(buffer);
+
+        // Read certs
+        for _ in 0..certs_count {
+            buffer.copy_from_slice(&bytes[cursor..cursor + 4]);
+            cursor += 4;
+            let cert_source = WotId(u32::from_le_bytes(buffer) as usize);
+            wot.add_link(cert_source, wot_id);
+        }
+    }
+
+    Ok(wot)
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use dubp_wot::data::HasLinkResult;
+
+    #[test]
+    fn test_from_cpp_wot() -> Result<(), std::io::Error> {
+        let bytes = read_bytes_from_file(PathBuf::from("tests/wotb.bin").as_path())?;
+
+        let wot = from_cpp_wot(&bytes).expect("fail to read cpp wot");
+
+        assert_eq!(wot.get_max_link(), 100);
+        assert_eq!(wot.size(), 3394);
+        assert_eq!(
+            wot.has_link(WotId(33), WotId(35)),
+            HasLinkResult::Link(true),
+        );
+
+        Ok(())
+    }
+}
diff --git a/neon/native/src/wot/write_in_file.rs b/neon/native/src/wot/write_in_file.rs
new file mode 100644
index 0000000000000000000000000000000000000000..746dc40e62a2a714922ccede8b559b41e05a54b1
--- /dev/null
+++ b/neon/native/src/wot/write_in_file.rs
@@ -0,0 +1,46 @@
+//  Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// 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/>.
+
+use dubp_wot::data::rusty::RustyWebOfTrust;
+use flate2::write::ZlibEncoder;
+use flate2::Compression;
+use std::convert::TryFrom;
+use std::fs::File;
+use std::io::prelude::*;
+use std::path::{Path, PathBuf};
+
+pub(crate) fn wot_in_file(file_path_str: String, wot: &RustyWebOfTrust) -> Result<(), String> {
+    let file_path = PathBuf::try_from(file_path_str).map_err(|e| format!("{}", e))?;
+    let bytes = bincode::serialize(wot).map_err(|e| format!("{}", e))?;
+
+    write_and_compress_bytes_in_file(file_path.as_path(), &bytes, flate2::Compression::default())
+        .map_err(|e| format!("{}", e))?;
+
+    Ok(())
+}
+
+/// Write and compress bytes in file
+pub(crate) fn write_and_compress_bytes_in_file(
+    file_path: &Path,
+    datas: &[u8],
+    compression: Compression,
+) -> Result<(), std::io::Error> {
+    let file = File::create(file_path)?;
+    let mut e = ZlibEncoder::new(file, compression);
+    e.write_all(&datas[..])?;
+    e.finish()?;
+
+    Ok(())
+}
diff --git a/neon/native/tests/g1_genesis.bin.gz b/neon/native/tests/g1_genesis.bin.gz
new file mode 100644
index 0000000000000000000000000000000000000000..29617bd5ccb38685e0b06479fabfae0bb8394060
Binary files /dev/null and b/neon/native/tests/g1_genesis.bin.gz differ
diff --git a/neon/native/tests/wotb.bin b/neon/native/tests/wotb.bin
new file mode 100644
index 0000000000000000000000000000000000000000..6f9678b1dd4ec45e70b649891e212ec6f30de6ca
Binary files /dev/null and b/neon/native/tests/wotb.bin differ
diff --git a/package.json b/package.json
index 91791f494d3cf6d7a0f307bbd7e7d5df0f30fd86..1150aae52f86aca05f17fe8ff450892c6232d560 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,8 @@
     "doc": "typedoc --out typedoc/ index.ts app/ --mode file --readme README.md --includeDeclarations --sourcefile-url-prefix \"https://git.duniter.org/nodes/typescript/duniter/blob/loki/\"",
     "test": "nyc --reporter html mocha",
     "start": "node bin/duniter start",
-    "build": "tsc && cd \"node_modules/duniter-ui\" && npm install && npm run build",
+    "build": "cd neon && neon build --release && cd.. && tsc && cd \"../node_modules/duniter-ui\" && npm install && npm run build",
+    "install": "cd neon && neon build --release",
     "lint": "lint-staged",
     "prettier": "prettier --write app/**/*/*.ts",
     "reformat": "eslint --cache --fix app/**/*/*.ts",
@@ -74,7 +75,6 @@
     "commander": "2.9.0",
     "cors": "2.8.5",
     "daemonize2": "0.4.2",
-    "duniteroxyde": "0.2.9",
     "ddos": "0.2.1",
     "errorhandler": "1.5.1",
     "event-stream": "4.0.1",
@@ -91,10 +91,11 @@
     "morgan": "1.10.0",
     "multimeter": "0.1.1",
     "nat-upnp": "^1.1.1",
-    "prettier": "^2.0.4",
+    "neon-cli": "^0.4.0",
     "node-pre-gyp": "0.14.0",
     "node-uuid": "1.4.8",
     "optimist": "0.6.1",
+    "prettier": "^2.0.4",
     "q-io": "1.13.6",
     "querablep": "0.1.0",
     "request": "2.88.2",
diff --git a/release/arch/arm/build-arm.sh b/release/arch/arm/build-arm.sh
index 31df3047e249f95de65cae00ec006ce0f81723f1..5fe1f1f2178c839ecda63bb11d14f219ce5c4233 100755
--- a/release/arch/arm/build-arm.sh
+++ b/release/arch/arm/build-arm.sh
@@ -80,9 +80,9 @@ rm -Rf node_modules/duniter-ui/node_modules
 # Remove non production folders
 rm -rf coverage test
 
-# Remove unused duniteroxyde intermediate binaries
-rm -rf node_modules/duniteroxyde/target
-rm -rf node_modules/duniteroxyde/native/target
+# Remove unused rust intermediate binaries
+rm -rf target
+rm -rf neon/native/target
 
 cd ..
 mkdir -p duniter_release
diff --git a/release/arch/linux/build-lin.sh b/release/arch/linux/build-lin.sh
index 1c509b53b18bfa5ad277fd86baac4330251a83a5..b42b3dc04961d9b1c9f93a838dff9870e8fba989 100644
--- a/release/arch/linux/build-lin.sh
+++ b/release/arch/linux/build-lin.sh
@@ -190,9 +190,9 @@ cp "${ROOT}/release/resources/leveldown-fix.json" "${RELEASES}/duniter/node_modu
 # Remove non production folders
 rm -rf coverage release test
 
-# Remove unused duniteroxyde intermediate binaries
-rm -rf node_modules/duniteroxyde/target
-rm -rf node_modules/duniteroxyde/native/target
+# Remove unused rust intermediate binaries
+rm -rf target
+rm -rf neon/native/target
 
 cp -r "${RELEASES}/duniter" "${RELEASES}/desktop_" || exit 1
 cp -r "${RELEASES}/duniter" "${RELEASES}/server_" || exit 1
diff --git a/release/docker/Dockerfile b/release/docker/Dockerfile
index 3b8cd3098a3535fdc95df6cb484c8c0244b27480..40d5c49049d44ef495f2ac39256293fc174ab0d9 100644
--- a/release/docker/Dockerfile
+++ b/release/docker/Dockerfile
@@ -28,8 +28,8 @@ RUN export PATH="$HOME/.cargo/bin:$PATH" && \
    yarn add duniter-ui@${DUNITER_UI_VER} && \
    mv release/docker/duniter.sh docker.sh && \
    rm -rf coverage release test && \
-   rm -rf node_modules/duniteroxyde/target && \
-   rm -rf node_modules/duniteroxyde/native/target
+   rm -rf target && \
+   rm -rf neon/native/target
 
 # ------------------------------------------------------------------------------
 # Final Stage
diff --git a/test/fast/crypto/crypto.ts b/test/fast/crypto/crypto.ts
index a1cf7df733dc4e227c5ea7cd5e05b5510598d05f..655d56c51d6a8199b59ade24fb6831f06eb54e77 100644
--- a/test/fast/crypto/crypto.ts
+++ b/test/fast/crypto/crypto.ts
@@ -13,7 +13,7 @@
 
 "use strict";
 import {Key} from "../../../app/lib/common-libs/crypto/keyring"
-import {verify} from "duniteroxyde"
+import {verify} from "../../../neon/lib"
 
 const should = require('should');
 
diff --git a/test/fast/crypto/randomKey.ts b/test/fast/crypto/randomKey.ts
index 398d37e27f2c0c44db63d24ee3cc0b7a143aded4..be51e29353e07af83219bc811e8ef21422dc3ff5 100644
--- a/test/fast/crypto/randomKey.ts
+++ b/test/fast/crypto/randomKey.ts
@@ -12,7 +12,7 @@
 // GNU Affero General Public License for more details.
 
 import {Key, randomKey} from "../../../app/lib/common-libs/crypto/keyring"
-import {verify} from "duniteroxyde"
+import {verify} from "../../../neon/lib"
 
 const should = require('should');
 
diff --git a/test/fast/modules/common/common-crypto-test.ts b/test/fast/modules/common/common-crypto-test.ts
index 6b6b64390b3509a6017cbf0d5c07b4cff11d3262..edb67c66a5e22409bcf62c6105b786b3752f64bc 100644
--- a/test/fast/modules/common/common-crypto-test.ts
+++ b/test/fast/modules/common/common-crypto-test.ts
@@ -12,7 +12,7 @@
 // GNU Affero General Public License for more details.
 
 import {Key} from "../../../../app/lib/common-libs/crypto/keyring"
-import {verify} from "duniteroxyde"
+import {verify} from "../../../../neon/lib"
 
 const should = require('should');
 
diff --git a/test/fast/modules/common/common-random-key.ts b/test/fast/modules/common/common-random-key.ts
index 57ac443d9495c93df16857ef21e48fda8110af9e..3d06a0ae52db28017f9884f60032587b9c2ca607 100644
--- a/test/fast/modules/common/common-random-key.ts
+++ b/test/fast/modules/common/common-random-key.ts
@@ -12,7 +12,7 @@
 // GNU Affero General Public License for more details.
 
 import {Key, randomKey} from "../../../../app/lib/common-libs/crypto/keyring"
-import {verify} from "duniteroxyde"
+import {verify} from "../../../../neon/lib"
 
 const should = require('should');
 
diff --git a/test/integration/wot/wotb.ts b/test/integration/wot/wotb.ts
index dc35fb631eb98d05c324288683ae565fb5049d70..64ac82aec3478a52c671f28bb19c6a69aba6edd2 100644
--- a/test/integration/wot/wotb.ts
+++ b/test/integration/wot/wotb.ts
@@ -14,7 +14,7 @@
 import {TestUser} from "../tools/TestUser"
 import {NewTestingServer, TestingServer} from "../tools/toolbox"
 import {BmaDependency} from "../../../app/modules/bma/index"
-import {Wot} from "duniteroxyde"
+import {Wot} from "../../../neon/lib"
 import {Underscore} from "../../../app/lib/common-libs/underscore"
 import {shutDownEngine} from "../tools/shutdown-engine"
 import {CommonConstants} from "../../../app/lib/common-libs/constants"
diff --git a/test/integration/ws2p/ws2p_connection.ts b/test/integration/ws2p/ws2p_connection.ts
index 3e39d94b5b96bc745185cb9761e2bcb2770626a4..9ceb8ccd677d28f5d41888ef58e90ce239fef138 100644
--- a/test/integration/ws2p/ws2p_connection.ts
+++ b/test/integration/ws2p/ws2p_connection.ts
@@ -19,7 +19,7 @@ import {
   WS2PRemoteAuth
 } from "../../../app/modules/ws2p/lib/WS2PConnection"
 import {Key} from "../../../app/lib/common-libs/crypto/keyring"
-import {verify} from "duniteroxyde"
+import {verify} from "../../../neon/lib"
 import {getNewTestingPort} from "../tools/toolbox"
 import {WS2PMessageHandler} from "../../../app/modules/ws2p/lib/impl/WS2PMessageHandler"
 import {WS2PResponse} from "../../../app/modules/ws2p/lib/impl/WS2PResponse"
diff --git a/test/neon/g1_genesis.bin.gz b/test/neon/g1_genesis.bin.gz
new file mode 100644
index 0000000000000000000000000000000000000000..29617bd5ccb38685e0b06479fabfae0bb8394060
Binary files /dev/null and b/test/neon/g1_genesis.bin.gz differ
diff --git a/test/neon/test2.bin.gz b/test/neon/test2.bin.gz
new file mode 100644
index 0000000000000000000000000000000000000000..e627908dc3f179d4da7918fdaf7d9ec3f97ee572
Binary files /dev/null and b/test/neon/test2.bin.gz differ
diff --git a/test/neon/test_crypto.ts b/test/neon/test_crypto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5a6ac3bd333a785fdb44c5b03aa2be48a3efb990
--- /dev/null
+++ b/test/neon/test_crypto.ts
@@ -0,0 +1,110 @@
+"use strict";
+
+import { Ed25519Signator, KeyPairBuilder, sha256, verify, generateRandomSeed, seedToSecretKey } from "../../neon/lib";
+import * as assert from "assert";
+
+
+let keyPair: Ed25519Signator, rawPub:string, rawSec:string
+
+describe('ed25519 tests:', function(){
+
+  before(async () => {
+    // Generate the keypair
+    keyPair = KeyPairBuilder.fromSecretKey('51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP');
+    rawPub = keyPair.getPublicKey();
+    //rawSec = keyPair.getSecretKey();
+    assert.equal(rawPub, 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd');
+    //assert.equal(rawSec, '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP');
+  })
+
+  it('sha256 hello', function(done){
+    const msg = "hello";
+    const hash = sha256(msg);
+    assert.equal(hash, "2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824")
+    done();
+  });
+
+  it('good signature from generated key should be verified', function(done){
+    const msg = "Some message to be signed";
+    const sig = keyPair.sign(msg);
+    const verified = verify(msg, sig, rawPub);
+    assert.equal(verified, true)
+    done();
+  });
+
+  it('wrong signature from generated key should NOT be verified', function(done){
+    const msg = "Some message to be signed";
+    const sig = keyPair.sign(msg);
+    const verified = verify(msg + 'delta', sig, rawPub);
+    assert.equal(verified, false)
+    done();
+  });
+
+  it('good signature on a Peer document with just BMA should be verified', function(done){
+    const msg = "Version: 10\n" +
+      "Type: Peer\n" +
+      "Currency: g1\n" +
+      "PublicKey: 3AF7bhGQRt6ymcBZgZTBMoDsEtSwruSarjNG8kDnaueX\n" +
+      "Block: 33291-0000088375C232A4DDAE171BB3D3C51347CB6DC8B7AA8BE4CD4DAEEADF26FEB8\n" +
+      "Endpoints:\n" +
+      "BASIC_MERKLED_API g1.duniter.org 10901\n"
+    const verified = verify(msg, "u8t1IoWrB/C7T+2rS0rKYJfjPG4FN/HkKGFiUO5tILIzjFDvxxQiVC+0o/Vaz805SMmqJvXqornI71U7//+wCg==", "3AF7bhGQRt6ymcBZgZTBMoDsEtSwruSarjNG8kDnaueX");
+    assert.equal(verified, true)
+    done();
+  });
+
+  it('good signature on a Peer document with just BMA + BMAS should be verified', function(done){
+    const msg = "Version: 10\n" +
+      "Type: Peer\n" +
+      "Currency: g1\n" +
+      "PublicKey: Com8rJukCozHZyFao6AheSsfDQdPApxQRnz7QYFf64mm\n" +
+      "Block: 33291-0000088375C232A4DDAE171BB3D3C51347CB6DC8B7AA8BE4CD4DAEEADF26FEB8\n" +
+      "Endpoints:\n" +
+      "BASIC_MERKLED_API g1.duniter.tednet.fr 37.187.0.204 8999\n" +
+      "BMAS g1.duniter.tednet.fr 9000\n"
+    const verified = verify(msg, "ImvQDdpGv2M6CxSnBuseM/azJhBUGzWVgQhIvb5L2oGLm2GyLk/Sbi5wkb4IjbjbQfdRPdlcx5zxaHhvZCiWAA==", "Com8rJukCozHZyFao6AheSsfDQdPApxQRnz7QYFf64mm");
+    assert.equal(verified, true)
+    done();
+  });
+
+  it('wrong block signature due to oldest tweetnacl should NOT be verified with verify', function(done){
+    const msg = "InnerHash: 8B194B5C38CF0A38D16256405AC3E5FA5C2ABD26BE4DCC0C7ED5CC9824E6155B\nNonce: 30400000119992\n";
+    const rawSig = "fJusVDRJA8akPse/sv4uK8ekUuvTGj1OoKYVdMQQAACs7OawDfpsV6cEMPcXxrQTCTRMrTN/rRrl20hN5zC9DQ==";
+    const verified = verify(msg, rawSig, "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx");
+    assert.equal(verified, false)
+    done();
+  });
+
+  it('rectified block signature should be verified with verify', function(done){
+    const msg = "InnerHash: 8B194B5C38CF0A38D16256405AC3E5FA5C2ABD26BE4DCC0C7ED5CC9824E6155B\nNonce: 30400000119992\n";
+    const rawSig = "aZusVDRJA8akPse/sv4uK8ekUuvTGj1OoKYVdMQQ/3+VMaDJ02I795GBBaLgjypZFEKYlPMssJMn/X+F/pxgAw==";
+    const verified = verify(msg, rawSig, "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx");
+    assert.equal(verified, true)
+    done();
+  });
+  it('generate random keypair', function (done) {
+    const seed = generateRandomSeed();
+    const secretKey = seedToSecretKey(seed);
+    const keyPair = KeyPairBuilder.fromSecretKey(secretKey);
+    const msg = "Some message to be signed";
+    const sig = keyPair.sign(msg);
+    const verified = verify(msg, sig, keyPair.getPublicKey());
+    assert.equal(verified, true)
+    done();
+  });
+  it('membership: should not accept wrong signature', function(done){
+    const msg = 'Version: 10\n' +
+    'Type: Membership\n' +
+    'Currency: bb\n' +
+    'Issuer: 6upqFiJ66WV6N3bPc8x8y7rXT3syqKRmwnVyunCtEj7o\n' +
+    'Block: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855\n' +
+    'Membership: IN\n' +
+    'UserID: someuid\n' +
+    'CertTS: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855\n';
+    const rawSig = "cJohoG/qmxm7KwqCB71RXRSIvHu7IcYB1zWE33OpPLGmedH mdPWad32S7G9j9IDpI8QpldalhdT4BUIHlAtCw==";
+    const verified = verify(msg, rawSig, "6upqFiJ66WV6N3bPc8x8y7rXT3syqKRmwnVyunCtEj7o");
+    assert.equal(verified, false)
+    done();
+  });
+});
+
diff --git a/test/neon/test_wot.ts b/test/neon/test_wot.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dbaf0f0e02ebef45515561f3abdd6f1a69582507
--- /dev/null
+++ b/test/neon/test_wot.ts
@@ -0,0 +1,518 @@
+"use strict";
+
+import { Wot, WotBuilder } from "../../neon/lib";
+import * as assert from "assert";
+import * as path from "path";
+
+const G1_GENESIS = path.join(__dirname, 'g1_genesis.bin.gz');
+const CPP_FILE = path.join(__dirname, 'wotb.bin');
+const X_PERCENT = 1.0;
+const _100_PERCENT = 1.0;
+const MAX_DISTANCE_1 = 1;
+const MAX_DISTANCE_2 = 2;
+const MAX_DISTANCE_3 = 3;
+const MAX_DISTANCE_4 = 4;
+const MAX_DISTANCE_5 = 5;
+const FROM_1_LINK_SENTRIES = 1;
+const FROM_2_LINKS_SENTRIES = 2;
+const FROM_3_LINKS_SENTRIES = 3;
+const __OUTDISTANCED__ = true;
+const __OK__ = false;
+
+    function newInstance(launchTest: (arg0: Wot) => any) {
+        return () => {
+            let wot = new Wot(3);
+            launchTest(wot);
+        }
+    }
+
+    describe("wotb-rs binding tests", () => {
+        describe('Basic operations', newInstance((wot) => {
+
+            it('should have 3 max links', function() {
+                assert.equal(wot.getMaxCert(), 3)
+            });
+
+            it('should have an initial size of 0', function() {
+              assert.equal(wot.getWoTSize(), 0);
+            });
+
+            it('should give number 0 if we add a node', function() {
+                // Add a node
+                assert.equal(wot.addNode(), 0);
+                assert.equal(wot.getWoTSize(), 1);
+                assert.equal(wot.isEnabled(0), true);
+                var enabled = wot.getEnabled();
+                assert.equal(enabled.length, 1);
+                assert.equal(enabled[0], 0);
+                assert.equal(wot.getDisabled().length, 0);
+                // Add another
+                assert.equal(wot.addNode(), 1);
+                assert.equal(wot.getWoTSize(), 2);
+                var enabled2 = wot.getEnabled();
+                assert.equal(enabled2.length, 2);
+                assert.equal(enabled2[1], 1);
+                assert.equal(wot.getDisabled().length, 0);
+                // Add 10 nodes
+                for (let i = 0; i < 10; i++) {
+                    assert.equal(wot.addNode(), i + 2);
+                }
+                assert.equal(wot.getWoTSize(), 2 + 10);
+                assert.equal(wot.getEnabled().length, 2 + 10);
+            });
+
+            it('should add certs only in the boundaries of maxCert', () => {
+                wot.addLink(0, 1);
+                wot.addLink(0, 2);
+                wot.addLink(0, 3);
+                //wot.addLink(0, 4);
+                assert.equal(wot.getMaxCert(), 3);
+                assert.equal(wot.existsLink(0, 1), true);
+                assert.equal(wot.existsLink(0, 2), true);
+                assert.equal(wot.existsLink(0, 3), true);
+                assert.equal(wot.existsLink(0, 4), false);
+                wot.setMaxCert(4);
+                assert.equal(wot.getMaxCert(), 4);
+                assert.equal(wot.existsLink(0, 4), false);
+                wot.addLink(0, 4);
+                assert.equal(wot.existsLink(0, 4), true);
+                wot.removeLink(0,1);
+                wot.removeLink(0,2);
+                wot.removeLink(0,3);
+                wot.removeLink(0,4);
+            });
+
+            it('should not throw if testing existsLink() with inbounds link', function() {
+                assert.equal(wot.existsLink(4, 6), false);
+            });
+        
+            it('first 4 nodes should be enabled', function() {
+                assert.equal(wot.isEnabled(0), true);
+                assert.equal(wot.isEnabled(1), true);
+                assert.equal(wot.isEnabled(2), true);
+                assert.equal(wot.isEnabled(3), true);
+            });
+
+            it('last node should be enabled', function() {
+                assert.equal(wot.isEnabled(11), true);
+            });
+
+            it('should be able to disable some nodes', function() {
+                assert.equal(wot.setEnabled(false, 0), false);
+                assert.equal(wot.setEnabled(false, 1), false);
+                assert.equal(wot.setEnabled(false, 2), false);
+                assert.equal(wot.getDisabled().length, 3);
+                assert.equal(wot.setEnabled(true, 1), true);
+            });
+
+            it('nodes 0 and 2 should be disabled', function() {
+                assert.equal(wot.isEnabled(0), false);
+                assert.equal(wot.isEnabled(1), true);
+                assert.equal(wot.isEnabled(2), false);
+                assert.equal(wot.isEnabled(3), true);
+                // Set enabled again
+                assert.equal(wot.setEnabled(true, 0), true);
+                assert.equal(wot.setEnabled(true, 1), true);
+                assert.equal(wot.setEnabled(true, 2), true);
+                assert.equal(wot.setEnabled(true, 1), true);
+                assert.equal(wot.getDisabled().length, 0);
+              });
+        
+            it('should not exist a link from 2 to 0', function() {
+                assert.equal(wot.existsLink(2, 0), false);
+            });
+        
+            it('should be able to add some links', function() {
+                assert.equal(wot.addLink(2, 0), 1);
+                assert.equal(wot.addLink(4, 0), 2);
+                //assert.equal(wot.addLink(4, 0), 2);
+                assert.equal(wot.addLink(5, 0), 3);
+            });
+
+            it('should exist new links', function() {
+                /**
+                 * WoT is:
+                 *
+                 * 2 --> 0
+                 * 4 --> 0
+                 * 5 --> 0
+                 */
+                assert.equal(wot.existsLink(2, 0), true);
+                assert.equal(wot.existsLink(4, 0), true);
+                assert.equal(wot.existsLink(5, 0), true);
+                assert.equal(wot.existsLink(2, 1), false);
+            });
+
+            it('should be able to remove some links', function() {
+                assert.equal(wot.removeLink(4, 0), 2);
+                /**
+                 * WoT is now:
+                 *
+                 * 2 --> 0
+                 * 5 --> 0
+                 */
+            });
+
+            it('should exist less links', function() {
+                assert.equal(wot.existsLink(2, 0), true);
+                assert.equal(wot.existsLink(4, 0), false);
+                assert.equal(wot.existsLink(5, 0), true);
+                assert.equal(wot.existsLink(2, 1), false);
+            });
+
+            it('should successfully use distance rule', function() {
+                assert.equal(wot.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // No because 2,4,5 have certified him
+                assert.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // No because only member 2 has 2 certs, and has certified him
+                assert.equal(wot.isOutdistanced(0, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // No because no member has issued 3 certifications
+                // We add links from member 3
+                assert.equal(wot.addLink(3, 1), 1);
+                assert.equal(wot.addLink(3, 2), 1);
+                /**
+                 * WoT is now:
+                 *
+                 * 2 --> 0
+                 * 5 --> 0
+                 * 3 --> 1
+                 * 3 --> 2
+                 */
+                assert.equal(wot.getWoTSize(), 12);
+                assert.equal(wot.getSentries(FROM_1_LINK_SENTRIES).length, 1);
+                assert.equal(wot.getSentries(FROM_1_LINK_SENTRIES)[0], 2);
+                assert.equal(wot.getSentries(FROM_2_LINKS_SENTRIES).length, 0);
+                assert.equal(wot.getSentries(FROM_3_LINKS_SENTRIES).length, 0);
+                assert.equal(wot.getNonSentries(FROM_1_LINK_SENTRIES).length, 11); // 12 - 1 = 11
+                assert.equal(wot.getNonSentries(FROM_2_LINKS_SENTRIES).length, 12); // 12 - 0 = 12
+                assert.equal(wot.getNonSentries(FROM_3_LINKS_SENTRIES).length, 12); // 12 - 0 = 12
+                assert.equal(wot.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: 2 --> 0
+                assert.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: 2 --> 0
+                assert.equal(wot.isOutdistanced(0, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: no sentry with 3 links issued
+                assert.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, X_PERCENT), __OK__); // OK: 2 --> 0
+
+                wot.addLink(1, 3);
+                wot.addLink(2, 3);
+
+                assert.equal(wot.getWoTSize(), 12);
+                assert.equal(wot.getSentries(FROM_1_LINK_SENTRIES).length, 3);
+                assert.equal(wot.getSentries(FROM_1_LINK_SENTRIES)[0], 1);
+                assert.equal(wot.getSentries(FROM_1_LINK_SENTRIES)[1], 2);
+                assert.equal(wot.getSentries(FROM_1_LINK_SENTRIES)[2], 3);
+                assert.equal(wot.getSentries(FROM_2_LINKS_SENTRIES).length, 1);
+                assert.equal(wot.getSentries(FROM_2_LINKS_SENTRIES)[0], 3);
+                assert.equal(wot.getSentries(FROM_3_LINKS_SENTRIES).length, 0);
+                assert.equal(wot.getNonSentries(FROM_1_LINK_SENTRIES).length, 9); // 12 - 3 = 9
+                assert.equal(wot.getNonSentries(FROM_2_LINKS_SENTRIES).length, 11); // 12 - 1 = 11
+                assert.equal(wot.getNonSentries(FROM_3_LINKS_SENTRIES).length, 12); // 12 - 0 = 12
+                assert.equal(wot.getPaths(3, 0, MAX_DISTANCE_1).length, 0); // KO
+                assert.equal(wot.getPaths(3, 0, MAX_DISTANCE_2).length, 1);    // It exists 3 --> 2 --> 0
+                assert.equal(wot.getPaths(3, 0, MAX_DISTANCE_2)[0].length, 3); // It exists 3 --> 2 --> 0
+                assert.equal(wot.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OUTDISTANCED__); // KO: No path 3 --> 0
+                //assert.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OUTDISTANCED__); // KO: No path 3 --> 0
+                assert.equal(wot.isOutdistanced(0, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: no sentry with 3 links issued
+                assert.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, X_PERCENT), __OK__); // OK: 3 --> 2 --> 0
+            });        
+
+            it('should have 12 nodes', function() {
+                assert.equal(wot.getWoTSize(), 12);
+              });
+        
+              it('delete top node', function() {
+                assert.equal(wot.removeNode(), 11);
+              });
+        
+              it('should have 11 nodes', function() {
+                assert.equal(wot.getWoTSize(), 11);
+            });
+
+            it('should work with member 3 disabled', function() {
+                // With member 3 disabled (non-member)
+                assert.equal(wot.setEnabled(false, 3), false);
+                let disabled_nodes = wot.getDisabled();
+                assert.equal(disabled_nodes.length, 1);
+                assert.equal(disabled_nodes[0], 3);
+                assert.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: No path 3 --> 0, but is disabled
+            });
+
+            it('should be able to make a mem copy', function() {
+                const copy = WotBuilder.fromWot(wot);
+                assert.equal(copy.setEnabled(false, 3), false);
+                assert.equal(wot.getDisabled().length, 1);
+                assert.equal(copy.addNode(), 11);
+                assert.equal(copy.getWoTSize(), 12);
+                assert.equal(wot.getWoTSize(), 11);
+                assert.equal(copy.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: No path 3 --> 0, but is disabled
+            });
+        }));
+
+
+
+        describe('Building a larger WoT', newInstance((wot) => {
+            it('should build a larget WoT', function() {
+                /* We build WoT:
+                 *
+                 * 0 --> 1 --> 2 --> 4 --> 5 <==> 6 --> 7
+                 *             ^
+                 *            ||
+                 *            ##==> 3 <-- 8 <-- 9 <========##
+                 *                       |                 ||
+                 *                       `> 10 <==> 11 <===##
+                 */
+                // Add nodes
+                for (let i = 0; i < 12; i++) {
+                  assert.equal(wot.addNode(), i);
+                }
+                // First line
+                assert.equal(wot.addLink(0, 1), 1);
+                assert.equal(wot.addLink(1, 2), 1);
+                assert.equal(wot.addLink(2, 4), 1);
+                assert.equal(wot.addLink(4, 5), 1);
+                assert.equal(wot.addLink(5, 6), 1);
+                assert.equal(wot.addLink(6, 7), 1);
+                // 2n level
+                assert.equal(wot.addLink(2, 3), 1);
+                assert.equal(wot.addLink(3, 2), 2);
+                assert.equal(wot.addLink(8, 3), 2);
+                assert.equal(wot.addLink(9, 8), 1);
+                // 3rd level
+                assert.equal(wot.addLink(8, 10), 1);
+                assert.equal(wot.addLink(10, 11), 1);
+                assert.equal(wot.addLink(11, 10), 2);
+                assert.equal(wot.addLink(11, 9), 1);
+                assert.equal(wot.addLink(9, 11), 2);
+        
+                assert.equal(wot.getWoTSize(), 12);
+                return Promise.resolve();
+            });
+
+            it('should can dump wot', function() {
+                assert.equal("max_links=3\nnodes_count=12\n000: []\n001: [0]\n002: [1, 3]\n003: [2, 8]\n004: [2]\n005: [4]\n006: [5]\n"
+                + "007: [6]\n008: [9]\n009: [11]\n010: [8, 11]\n011: [9, 10]\n", wot.dump());
+            });
+
+            describe('testing around 2 with d = 1', () => {
+      
+                /**
+                 * Sentries of 1 link (X are not sentries):
+                 *
+                 * X --> 1 --> 2 --> 4 --> 5 <==> 6 --> X
+                 *             ^
+                 *            ||
+                 *            ##==> 3 <-- 8 <-- 9 <========##
+                 *                       |                 ||
+                 *                       `> 10 <==> 11 <===##
+                 */
+                  // => It can be seen 1..6, 8..11 = 10 sentries
+                  // => MINUS the sentry #2 (which is tested and is not to be included)
+                  // => 9 sentries TESTED against member#2
+        
+                it('should have 10 sentries', function() {
+                  assert.equal(wot.getSentries(FROM_1_LINK_SENTRIES).length, 10);
+                });
+        
+                it('distance k = 1', function() {
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT), __OUTDISTANCED__);
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.5), __OUTDISTANCED__);
+                  // 20% of the sentries: OK
+                  // => 20% x 9 = 2 sentries to reach
+                  // => we have 1 --> 2
+                  // => we have 3 --> 2
+                  // => OK (1,3)
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.2), __OK__);
+                  // Who can pass 20% can pass 10%
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.1), __OK__);
+                  // Can pass 23% (1,98 => 2 sentries)
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.22), __OK__);
+                  // But cannot pass 23% (2,07 => 3 sentries)
+                  //assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.23), __OUTDISTANCED__);
+                });
+        
+                it('distance k = 2', function() {
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, _100_PERCENT), __OUTDISTANCED__);
+                  //assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.5), __OUTDISTANCED__);
+                  // 33% of the sentries: OK
+                  // => 33% x 9 = 3 sentries to reach
+                  // With k = 2 we have the following paths:
+                  // 1 --> 2
+                  // 8 --> 3 --> 2
+                  // => OK (1,8,3)
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.33), __OK__);
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.3), __OK__);
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.2), __OK__);
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.1), __OK__);
+                  // But cannot pass 34% (3,06 => 4 sentries)
+                  //assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.34), __OUTDISTANCED__);
+                });
+        
+                it('distance k = 5', function() {
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, _100_PERCENT), __OUTDISTANCED__);
+                  // 66% of the sentries: OK
+                  // => 66% x 9 = 6 sentries to reach
+                  // With k = 5 we have the following paths:
+                  // 1 --> 2
+                  // 10 --> 11 --> 9 --> 8 --> 3 --> 2
+                  // => OK (1,10,11,9,8,3)
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.66), __OK__);
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.3), __OK__);
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.2), __OK__);
+                  assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.1), __OK__);
+                  // But cannot pass 67% (6,03 => 7 sentries)
+                  //assert.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.67), __OUTDISTANCED__);
+                  assert.deepEqual(wot.detailedDistance(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.67), {
+                    nbReached: 7, // +1 compared to reached sentries, because of member `0`
+                    nbReachedAtBorder: 1,
+                    nbSuccess: 6,
+                    nbSuccessAtBorder: 1,
+                    nbSentries: 9,
+                    isOutdistanced: false
+                  });
+                });
+              });
+  
+              describe('testing around 2 with d = 2', () => {
+                  /**
+                   * Sentries of 2 links (X are not sentries):
+                   *
+                   * X --> X --> 2 --> X --> X <==> X --> X
+                   *             ^
+                   *            ||
+                   *            ##==> X <-- X <-- X <========##
+                   *                       |                 ||
+                   *                       `> X  <==> 11 <===##
+                   */
+                    // => It can be seen 2,6,8,9,11 = 5 sentries
+                    // => MINUS the sentry #2 (which is tested and is not to be included)
+                    // => 4 sentries
+          
+                  it('should have 2 sentries', function() {
+                    assert.equal(wot.getSentries(FROM_2_LINKS_SENTRIES).length, 2);
+                  });
+          
+                  it('distance k = 1', function() {
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, _100_PERCENT), __OUTDISTANCED__);
+                    // With k = 1 we have no paths
+                    // => ALWAYS KO
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, 0.99), __OUTDISTANCED__);
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, 0.5), __OUTDISTANCED__);
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, 0.01), __OUTDISTANCED__);
+                  });
+          
+                  it('distance k = 2', function() {
+                    // Always distanced with k = 2
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, _100_PERCENT), __OUTDISTANCED__);
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, 0.25), __OUTDISTANCED__);
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, 0.24), __OUTDISTANCED__);
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, 0.251), __OUTDISTANCED__);
+                  });
+          
+                  it('distance k = 3', function() {
+                    // Always distanced with k = 2
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_3, _100_PERCENT), __OUTDISTANCED__);
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_3, 0.50), __OUTDISTANCED__);
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_3, 0.49), __OUTDISTANCED__);
+                    //assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_3, 0.51), __OUTDISTANCED__);
+                  });
+          
+                  it('distance k = 4', function() {
+                    // Only 1 sentry at distance 4: always OK
+                    assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_4, _100_PERCENT), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_4, 0.75), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_4, 0.01), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_4, 0.99), __OK__);
+                  });
+          
+                  it('distance k = 5', function() {
+                    // Only 1 sentry at distance 4: always OK
+                    assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_5, _100_PERCENT), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_5, 0.75), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_5, 0.01), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_5, 0.99), __OK__);
+                  });
+              });
+          
+              describe('testing around 2 with d = 3', () => {
+                  /**
+                   * Sentries of 3 links (X are not sentries):
+                   *
+                   * X --> X --> 2 --> X --> X <==> X --> X
+                   *             ^
+                   *            ||
+                   *            ##==> X <-- X <-- X <========##
+                   *                       |                 ||
+                   *                       `> X  <==> X <===##
+                   */
+                    // => It can be seen 2 = 1 sentries
+                    // => MINUS the sentry #2 (which is tested and is not to be included)
+                    // => 0 sentries
+                    // => ALWAYS OK, no sentries to constraint
+          
+                  it('distance k = 1', function() {
+                    assert.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, _100_PERCENT), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, 0.01), __OK__);
+                  });
+          
+                  it('distance k = 2', function() {
+                    assert.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_2, _100_PERCENT), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_2, 0.01), __OK__);
+                  });
+          
+                  it('distance k = 5', function() {
+                    assert.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_5, _100_PERCENT), __OK__);
+                    assert.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_5, 0.01), __OK__);
+                  });
+              });
+        }));
+
+        describe('tests open written wot file', newInstance((wot) => {
+
+            it('should can add 12 nodes', function() {
+              for (let i = 0; i < 12; i++) {
+                assert.equal(wot.addNode(), i);
+              }
+                assert.equal(wot.getWoTSize(), 12);
+            });
+
+            it('should add node, write and read new wot with 13 nodes', function() {
+                wot.addNode();
+                assert.equal(wot.getWoTSize(), 13);
+                assert.equal(wot.writeInFile("test2.bin.gz"), true)
+                wot.clear();
+                assert.equal(wot.getWoTSize(), 0);
+                let wot2 = WotBuilder.fromFile("test2.bin.gz");
+                assert.equal(wot2.getWoTSize(), 13);
+            });
+        }));
+
+        describe('tests g1 genesis wot', newInstance((wot) => {
+
+            before(() => {
+                wot = WotBuilder.fromFile(G1_GENESIS);
+            });
+
+            it('should have a wot size of 59', function() {
+                assert.equal(wot.getWoTSize(), 59);
+            });
+
+            it('should have only enabled members', function() {
+                assert.equal(wot.getEnabled().length, 59);
+                assert.equal(wot.getDisabled().length, 0);
+            });
+
+            it('should have 48 sentries', function() {
+                assert.equal(wot.getSentries(FROM_3_LINKS_SENTRIES).length, 48);
+            });
+        }));
+
+        describe('tests cpp wot', newInstance((wot) => {
+
+          before(() => {
+              wot = WotBuilder.fromFile(CPP_FILE);
+          });
+
+          it('should have 100 max links', function() {
+            assert.equal(wot.getMaxCert(), 100)
+          });
+
+          it('should have 3394 nodes', function() {
+            assert.equal(wot.getWoTSize(), 3394)
+          });
+        }));
+    });
diff --git a/test/neon/wotb.bin b/test/neon/wotb.bin
new file mode 100644
index 0000000000000000000000000000000000000000..6f9678b1dd4ec45e70b649891e212ec6f30de6ca
Binary files /dev/null and b/test/neon/wotb.bin differ
diff --git a/yarn.lock b/yarn.lock
index caa21959b17e9ef1c68725f1cd9ce441c33408bf..a5c421932dc393c9fa218d771537ed6bc6e0f37a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1367,13 +1367,6 @@ doctrine@^3.0.0:
   dependencies:
     esutils "^2.0.2"
 
-duniteroxyde@0.2.9:
-  version "0.2.9"
-  resolved "https://registry.yarnpkg.com/duniteroxyde/-/duniteroxyde-0.2.9.tgz#ba6923977854357bb98dac9f4308f2243031eec8"
-  integrity sha512-0nZkqIPdYdMg8+JvvwhBgO/XU48SX7mgH/pzp84qfmF7qTMoLg3i9Y6L60N0vDRwyLLSHGMdlVxcKOB3FiL43A==
-  dependencies:
-    neon-cli "^0.4.0"
-
 duplexer@^0.1.1, duplexer@~0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"