From 65dbb7ae70c02dcf24e7304c3b62751cbc77974c Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Wed, 28 Aug 2019 01:40:01 +0200
Subject: [PATCH] [ref] whole: migrate from cryptoxide to ring

---
 Cargo.lock                                    |  22 +-
 lib/core/conf/Cargo.toml                      |   2 -
 lib/core/conf/src/keys.rs                     |  84 ++---
 lib/core/conf/src/lib.rs                      |  48 ++-
 lib/core/conf/test/v1/keypairs.json           |   6 +-
 lib/core/conf/test/v2/keypairs.json           |   6 +-
 lib/core/module/src/lib.rs                    |   6 +-
 lib/crypto/Cargo.toml                         |   3 +-
 lib/crypto/src/keys/bin_signable.rs           |  39 ++-
 lib/crypto/src/keys/ed25519.rs                | 278 ++++++---------
 lib/crypto/src/keys/mod.rs                    | 324 +++++++++---------
 lib/crypto/src/keys/seed.rs                   |  74 ++++
 lib/crypto/src/keys/text_signable.rs          |  28 +-
 lib/crypto/src/lib.rs                         |  10 +-
 lib/crypto/src/rand/mod.rs                    |  43 +++
 lib/dubp/block-doc/src/block.rs               |   8 +-
 lib/dubp/block-doc/src/block/v10.rs           |   4 +-
 lib/dubp/common-doc/src/traits.rs             |   6 +-
 lib/dubp/common-doc/src/traits/text.rs        |   6 +-
 .../src/documents/certification/v10.rs        |  31 +-
 .../user-docs/src/documents/identity/v10.rs   |  36 +-
 .../user-docs/src/documents/membership/v10.rs |  36 +-
 .../user-docs/src/documents/revocation/v10.rs |  35 +-
 .../user-docs/src/documents/transaction.rs    |  36 +-
 lib/dunp/network-documents/src/lib.rs         |   6 +-
 .../network-documents/src/network_head_v3.rs  |   4 +-
 .../network-documents/src/network_peer.rs     |   4 +-
 lib/modules/ws2p-v1-legacy/Cargo.toml         |   2 -
 .../ws2p-v1-legacy/src/events/received.rs     |   2 +-
 lib/modules/ws2p-v1-legacy/src/heads.rs       |  14 +-
 lib/modules/ws2p-v1-legacy/src/lib.rs         |  10 +-
 .../ws2p-v1-legacy/src/responses/received.rs  |   2 +-
 .../src/ws_connections/handler.rs             |  47 ++-
 .../src/ws_connections/messages.rs            |   6 +-
 .../src/ws_connections/meta_datas.rs          |  10 +-
 .../ws2p-v1-legacy/src/ws_connections/mod.rs  |  30 +-
 lib/modules/ws2p/ws2p-messages/lib.rs         |  10 +-
 .../ws2p/ws2p-messages/v2/api_features.rs     |  18 +-
 lib/modules/ws2p/ws2p-messages/v2/connect.rs  |   9 +-
 lib/modules/ws2p/ws2p-messages/v2/mod.rs      |  11 +-
 .../ws2p/ws2p-messages/v2/secret_flags.rs     |   4 +-
 .../src/controller/meta_datas.rs              |  12 +-
 .../src/controller/on_message/ack_msg.rs      |   2 +-
 .../src/controller/on_message/connect_msg.rs  |   4 +-
 .../ws2p-protocol/src/controller/on_open.rs   |   4 +-
 lib/modules/ws2p/ws2p-protocol/src/lib.rs     |   2 +-
 .../src/controllers/incoming_connections.rs   |   2 +-
 .../src/controllers/outgoing_connections.rs   |   2 +-
 lib/modules/ws2p/ws2p/src/generate_peer.rs    |  12 +-
 lib/modules/ws2p/ws2p/src/services/mod.rs     |   2 +-
 .../ws2p/ws2p/tests/connection_negociation.rs |  16 +-
 51 files changed, 747 insertions(+), 671 deletions(-)
 create mode 100644 lib/crypto/src/keys/seed.rs
 create mode 100644 lib/crypto/src/rand/mod.rs

diff --git a/Cargo.lock b/Cargo.lock
index ccb8f7e6..12bb427b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -198,6 +198,14 @@ dependencies = [
  "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "clear_on_drop"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "cloudabi"
 version = "0.0.3"
@@ -290,11 +298,6 @@ dependencies = [
  "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "cryptoxide"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "csv"
 version = "1.1.1"
@@ -460,7 +463,8 @@ dependencies = [
  "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "cryptoxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "durs-common-tools 0.2.0",
  "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -556,7 +560,6 @@ dependencies = [
 name = "durs-conf"
 version = "0.3.0-dev"
 dependencies = [
- "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "dubp-currency-params 0.2.0",
  "dubp-user-docs 0.14.0",
@@ -565,7 +568,6 @@ dependencies = [
  "durs-module 0.3.0-dev",
  "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "ring 0.16.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -803,7 +805,6 @@ name = "durs-ws2p-v1-legacy"
 version = "0.3.0-dev"
 dependencies = [
  "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "dubp-block-doc 0.1.0",
  "dubp-common-doc 0.1.0",
  "dubp-currency-params 0.2.0",
@@ -819,7 +820,6 @@ dependencies = [
  "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "ring 0.16.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2188,6 +2188,7 @@ dependencies = [
 "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
 "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
 "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
+"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
 "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
 "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
 "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
@@ -2198,7 +2199,6 @@ dependencies = [
 "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
 "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
 "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
-"checksum cryptoxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b486f0f6730b6972b7831f0faf2dc7c3280aab69bc07357c7a2f24042b945e36"
 "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d"
 "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
diff --git a/lib/core/conf/Cargo.toml b/lib/core/conf/Cargo.toml
index f5119122..b2aa864e 100644
--- a/lib/core/conf/Cargo.toml
+++ b/lib/core/conf/Cargo.toml
@@ -10,7 +10,6 @@ edition = "2018"
 path = "src/lib.rs"
 
 [dependencies]
-byteorder = "1.2.7"
 dirs = "1.0.2"
 dup-crypto = { path = "../../crypto" }
 dubp-currency-params = { path = "../../dubp/currency-params" }
@@ -19,7 +18,6 @@ durs-module = { path = "../module" }
 durs-common-tools = { path = "../../tools/common-tools" }
 failure = "0.1.5"
 log = "0.4.*"
-ring = "0.16.5"
 rpassword = "1.0.0"
 serde = "1.0.*"
 serde_derive = "1.0.*"
diff --git a/lib/core/conf/src/keys.rs b/lib/core/conf/src/keys.rs
index cdc98fcd..84bb0579 100644
--- a/lib/core/conf/src/keys.rs
+++ b/lib/core/conf/src/keys.rs
@@ -170,14 +170,12 @@ pub fn key_wizard(mut key_pairs: DuniterKeyPairs) -> Result<DuniterKeyPairs, Wiz
 mod tests {
     use super::*;
 
-    static BASE58_SEC_INIT: &'static str =
-        "4iXXx5GgRkZ85BVPwn8vFXvztdXAAa5yB573ErcAnngAgSVEknNqc16xRnCmsuHFAJ3j3XArB4mv8UVpvrG32vLV";
+    static BASE58_SEED_INIT: &'static str = "4iXXx5GgRkZ85BVPwn8vFXvztdXAAa5yB573ErcAnngA";
     static BASE58_PUB_INIT: &'static str = "otDgSpKvKAPPmE1MUYxc3UQ3RtEnKYz4iGD3BmwKPzM";
     //static SALT_INIT: &'static str = "initsalt";
     //static PASSWORD_INIT: &'static str = "initpassword";
 
-    static BASE58_SEC_TEST: &'static str =
-        "4xr2CFHWQtDUQiPCon3FhEAvSpXEoFZHeEPiBzDUtEbt2wnrFS9ZTtAvUyZypbDvw8wmYhHrJgBVo6GidMrpwoQq";
+    static BASE58_SEED_TEST: &'static str = "ELjDWGPyCGMuhr7R7H2aip6UJA9qLRepmK77pcD41UqQ";
     static BASE58_PUB_TEST: &'static str = "6sewkaNWyEMqkEa2PVRWrDb3hxWtjPdUSB1zXVCqhdWV";
     static SALT_TEST: &'static str = "testsalt";
     static PASSWORD_TEST: &'static str = "testpassword";
@@ -185,9 +183,9 @@ mod tests {
     #[test]
     fn test_modify_member_keys() {
         let key_pairs = DuniterKeyPairs {
-            network_keypair: KeyPairEnum::Ed25519(ed25519::KeyPair {
-                privkey: ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("conf : keypairs file : fail to parse network_sec !"),
+            network_keypair: KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair {
+                seed: Seed::from_base58(BASE58_SEED_INIT)
+                    .expect("conf : keypairs file : fail to parse network_seed !"),
                 pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT)
                     .expect("conf : keypairs file : fail to parse network_pub !"),
             }),
@@ -203,11 +201,8 @@ mod tests {
             )
         );
         assert_eq!(
-            result_key_pairs.network_keypair.private_key(),
-            PrivKey::Ed25519(
-                ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("Wrong data in BASE58_SEC_TEST")
-            )
+            result_key_pairs.network_keypair.seed(),
+            Seed::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_INIT"),
         );
 
         // We expect member key to update as intended
@@ -219,20 +214,17 @@ mod tests {
             )
         );
         assert_eq!(
-            result_key_pairs.member_keypair.unwrap().private_key(),
-            PrivKey::Ed25519(
-                ed25519::PrivateKey::from_base58(BASE58_SEC_TEST)
-                    .expect("Wrong data in BASE58_SEC_TEST")
-            )
+            result_key_pairs.member_keypair.unwrap().seed(),
+            Seed::from_base58(BASE58_SEED_TEST).expect("Wrong data in BASE58_SEED_TEST"),
         );
     }
 
     #[test]
     fn test_modify_network_keys() {
         let key_pairs = DuniterKeyPairs {
-            network_keypair: KeyPairEnum::Ed25519(ed25519::KeyPair {
-                privkey: ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("conf : keypairs file : fail to parse network_sec !"),
+            network_keypair: KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair {
+                seed: Seed::from_base58(BASE58_SEED_INIT)
+                    .expect("conf : keypairs file : fail to parse network_seed !"),
                 pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT)
                     .expect("conf : keypairs file : fail to parse network_pub !"),
             }),
@@ -248,11 +240,8 @@ mod tests {
             )
         );
         assert_eq!(
-            result_key_pairs.network_keypair.private_key(),
-            PrivKey::Ed25519(
-                ed25519::PrivateKey::from_base58(BASE58_SEC_TEST)
-                    .expect("Wrong data in BASE58_SEC_TEST")
-            )
+            result_key_pairs.network_keypair.seed(),
+            Seed::from_base58(BASE58_SEED_TEST).expect("Wrong data in BASE58_SEED_TEST")
         );
         // We expect member key not to change
         assert_eq!(result_key_pairs.member_keypair, None);
@@ -261,15 +250,15 @@ mod tests {
     #[test]
     fn test_clear_network_keys() {
         let key_pairs = DuniterKeyPairs {
-            network_keypair: KeyPairEnum::Ed25519(ed25519::KeyPair {
-                privkey: ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("conf : keypairs file : fail to parse network_sec !"),
+            network_keypair: KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair {
+                seed: Seed::from_base58(BASE58_SEED_INIT)
+                    .expect("conf : keypairs file : fail to parse network_seed !"),
                 pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT)
                     .expect("conf : keypairs file : fail to parse network_pub !"),
             }),
-            member_keypair: Some(KeyPairEnum::Ed25519(ed25519::KeyPair {
-                privkey: ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("conf : keypairs file : fail to parse network_sec !"),
+            member_keypair: Some(KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair {
+                seed: Seed::from_base58(BASE58_SEED_INIT)
+                    .expect("conf : keypairs file : fail to parse network_seed !"),
                 pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT)
                     .expect("conf : keypairs file : fail to parse network_pub !"),
             })),
@@ -284,11 +273,8 @@ mod tests {
             )
         );
         assert_ne!(
-            result_key_pairs.network_keypair.private_key(),
-            PrivKey::Ed25519(
-                ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("Wrong data in BASE58_SEC_TEST")
-            )
+            result_key_pairs.network_keypair.seed(),
+            Seed::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST")
         );
 
         // We expect member key not to change
@@ -300,26 +286,23 @@ mod tests {
             )
         );
         assert_eq!(
-            result_key_pairs.member_keypair.unwrap().private_key(),
-            PrivKey::Ed25519(
-                ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("Wrong data in BASE58_SEC_TEST")
-            )
+            result_key_pairs.member_keypair.unwrap().seed(),
+            Seed::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST")
         );
     }
 
     #[test]
     fn test_clear_member_keys() {
         let key_pairs = DuniterKeyPairs {
-            network_keypair: KeyPairEnum::Ed25519(ed25519::KeyPair {
-                privkey: ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("conf : keypairs file : fail to parse network_sec !"),
+            network_keypair: KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair {
+                seed: Seed::from_base58(BASE58_SEED_INIT)
+                    .expect("conf : keypairs file : fail to parse network_seed !"),
                 pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT)
                     .expect("conf : keypairs file : fail to parse network_pub !"),
             }),
-            member_keypair: Some(KeyPairEnum::Ed25519(ed25519::KeyPair {
-                privkey: ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("conf : keypairs file : fail to parse network_sec !"),
+            member_keypair: Some(KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair {
+                seed: Seed::from_base58(BASE58_SEED_INIT)
+                    .expect("conf : keypairs file : fail to parse network_seed !"),
                 pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT)
                     .expect("conf : keypairs file : fail to parse network_pub !"),
             })),
@@ -334,11 +317,8 @@ mod tests {
             )
         );
         assert_eq!(
-            result_key_pairs.network_keypair.private_key(),
-            PrivKey::Ed25519(
-                ed25519::PrivateKey::from_base58(BASE58_SEC_INIT)
-                    .expect("Wrong data in BASE58_SEC_TEST")
-            )
+            result_key_pairs.network_keypair.seed(),
+            Seed::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST")
         );
 
         // We expect member key to change
diff --git a/lib/core/conf/src/lib.rs b/lib/core/conf/src/lib.rs
index 00a42436..03bd0fb0 100644
--- a/lib/core/conf/src/lib.rs
+++ b/lib/core/conf/src/lib.rs
@@ -36,15 +36,14 @@ pub mod constants;
 pub mod keys;
 
 use crate::constants::MODULES_DATAS_FOLDER;
-use byteorder::{BigEndian, ByteOrder};
 use dubp_currency_params::CurrencyName;
 use dup_crypto::keys::*;
+use dup_crypto::rand;
 use durs_common_tools::fatal_error;
 use durs_module::{
     DursConfTrait, DursGlobalConfTrait, ModuleName, RequiredKeys, RequiredKeysContent,
 };
 use failure::Fail;
-use ring::rand;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 use std::collections::HashSet;
 use std::fs;
@@ -370,8 +369,8 @@ impl Serialize for DuniterKeyPairs {
     where
         S: Serializer,
     {
-        let member_sec = if let Some(member_keypair) = self.member_keypair {
-            member_keypair.private_key().to_string()
+        let member_seed = if let Some(member_keypair) = self.member_keypair {
+            member_keypair.seed().to_string()
         } else {
             String::from("")
         };
@@ -382,14 +381,14 @@ impl Serialize for DuniterKeyPairs {
         };
         let mut state = serializer.serialize_struct("DuniterKeyPairs", 4)?;
         state.serialize_field(
-            "network_sec",
-            &self.network_keypair.private_key().to_string().as_str(),
+            "network_seed",
+            &self.network_keypair.seed().to_string().as_str(),
         )?;
         state.serialize_field(
             "network_pub",
             &self.network_keypair.public_key().to_string().as_str(),
         )?;
-        state.serialize_field("member_sec", member_sec.as_str())?;
+        state.serialize_field("member_seed", member_seed.as_str())?;
         state.serialize_field("member_pub", member_pub.as_str())?;
         state.end()
     }
@@ -426,17 +425,14 @@ impl DuniterKeyPairs {
 // Warning: This function cannot use the macro fatal_error! because the logger is not yet initialized, so it must use panic !
 fn generate_random_keypair(algo: KeysAlgo) -> KeyPairEnum {
     match algo {
-        KeysAlgo::Ed25519 => KeyPairEnum::Ed25519(ed25519::KeyPair::generate_random()),
+        KeysAlgo::Ed25519 => KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair::generate_random()),
         KeysAlgo::Schnorr => panic!("Schnorr algo not yet supported !"),
     }
 }
 
+#[inline]
 fn generate_random_node_id() -> u32 {
-    if let Ok(random_bytes) = rand::generate::<[u8; 4]>(&rand::SystemRandom::new()) {
-        BigEndian::read_u32(&random_bytes.expose())
-    } else {
-        fatal_error!("System error: fail to generate random hash !")
-    }
+    rand::gen_u32()
 }
 
 /// Return the user datas folder name
@@ -552,37 +548,37 @@ pub fn load_conf_at_path(
                 let json_conf: serde_json::Value =
                     serde_json::from_str(&contents).expect("Conf: Fail to parse keypairs file !");
 
-                if let Some(network_sec) = json_conf.get("network_sec") {
+                if let Some(network_seed) = json_conf.get("network_seed") {
                     if let Some(network_pub) = json_conf.get("network_pub") {
-                        let network_sec = network_sec
+                        let network_seed = network_seed
                             .as_str()
                             .expect("Conf: Fail to parse keypairs file !");
                         let network_pub = network_pub
                             .as_str()
                             .expect("Conf: Fail to parse keypairs file !");
-                        let network_keypair = KeyPairEnum::Ed25519(ed25519::KeyPair {
-                            privkey: ed25519::PrivateKey::from_base58(network_sec)
-                                .expect("conf : keypairs file : fail to parse network_sec !"),
+                        let network_keypair = KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair {
+                            seed: Seed::from_base58(network_seed)
+                                .expect("conf : keypairs file : fail to parse network_seed !"),
                             pubkey: ed25519::PublicKey::from_base58(network_pub)
                                 .expect("conf : keypairs file : fail to parse network_pub !"),
                         });
 
-                        let member_keypair = if let Some(member_sec) = json_conf.get("member_sec") {
+                        let member_keypair = if let Some(member_seed) = json_conf.get("member_seed")
+                        {
                             if let Some(member_pub) = json_conf.get("member_pub") {
-                                let member_sec = member_sec
+                                let member_seed = member_seed
                                     .as_str()
                                     .expect("Conf: Fail to parse keypairs file !");
                                 let member_pub = member_pub
                                     .as_str()
                                     .expect("Conf: Fail to parse keypairs file !");
-                                if member_sec.is_empty() || member_pub.is_empty() {
+                                if member_seed.is_empty() || member_pub.is_empty() {
                                     None
                                 } else {
-                                    Some(KeyPairEnum::Ed25519(ed25519::KeyPair {
-                                        privkey: ed25519::PrivateKey::from_base58(member_sec)
-                                            .expect(
-                                                "conf : keypairs file : fail to parse member_sec !",
-                                            ),
+                                    Some(KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair {
+                                        seed: Seed::from_base58(member_seed).expect(
+                                            "conf : keypairs file : fail to parse member_seed !",
+                                        ),
                                         pubkey: ed25519::PublicKey::from_base58(member_pub).expect(
                                             "conf : keypairs file : fail to parse member_pub !",
                                         ),
diff --git a/lib/core/conf/test/v1/keypairs.json b/lib/core/conf/test/v1/keypairs.json
index e52b2647..b9b380f5 100644
--- a/lib/core/conf/test/v1/keypairs.json
+++ b/lib/core/conf/test/v1/keypairs.json
@@ -1,6 +1,6 @@
 {
-	"network_sec": "RcrnPyfgEaet2VqQvLeBsgKvfaoUqinQnCooP9bFoDr1W1Focos351r4xBee6Hj2RaV6RRV8PxpdMR6hVVhNNDb",
-	"network_pub": "39SvsGzGZjdCh1wFS1QKdCR1ZB6rTxRbTZRW8sY5fhq7",
-	"member_sec": "",
+	"network_seed": "ELjDWGPyCGMuhr7R7H2aip6UJA9qLRepmK77pcD41UqQ",
+	"network_pub": "6sewkaNWyEMqkEa2PVRWrDb3hxWtjPdUSB1zXVCqhdWV",
+	"member_seed": "",
 	"member_pub": ""
   }
\ No newline at end of file
diff --git a/lib/core/conf/test/v2/keypairs.json b/lib/core/conf/test/v2/keypairs.json
index e52b2647..b9b380f5 100644
--- a/lib/core/conf/test/v2/keypairs.json
+++ b/lib/core/conf/test/v2/keypairs.json
@@ -1,6 +1,6 @@
 {
-	"network_sec": "RcrnPyfgEaet2VqQvLeBsgKvfaoUqinQnCooP9bFoDr1W1Focos351r4xBee6Hj2RaV6RRV8PxpdMR6hVVhNNDb",
-	"network_pub": "39SvsGzGZjdCh1wFS1QKdCR1ZB6rTxRbTZRW8sY5fhq7",
-	"member_sec": "",
+	"network_seed": "ELjDWGPyCGMuhr7R7H2aip6UJA9qLRepmK77pcD41UqQ",
+	"network_pub": "6sewkaNWyEMqkEa2PVRWrDb3hxWtjPdUSB1zXVCqhdWV",
+	"member_seed": "",
 	"member_pub": ""
   }
\ No newline at end of file
diff --git a/lib/core/module/src/lib.rs b/lib/core/module/src/lib.rs
index d0a09fd3..2f6a6824 100644
--- a/lib/core/module/src/lib.rs
+++ b/lib/core/module/src/lib.rs
@@ -32,7 +32,7 @@
 extern crate serde_derive;
 
 use dubp_currency_params::CurrencyName;
-use dup_crypto::keys::{KeyPair, KeyPairEnum};
+use dup_crypto::keys::{KeyPair, KeyPairEnum, Signator};
 use durs_common_tools::fatal_error;
 use durs_common_tools::traits::merge::Merge;
 use durs_network_documents::network_endpoint::{ApiPart, EndpointEnum};
@@ -270,11 +270,11 @@ pub enum RequiredKeysContent {
     /// Contains the member keypair (private key included).
     MemberKeyPair(Option<KeyPairEnum>),
     /// Contains the member public key.
-    MemberPublicKey(Option<<KeyPairEnum as KeyPair>::PublicKey>),
+    MemberPublicKey(Option<<<KeyPairEnum as KeyPair>::Signator as Signator>::PublicKey>),
     /// Contains the network keypair (private key included).
     NetworkKeyPair(KeyPairEnum),
     /// Contains the network public key.
-    NetworkPublicKey(<KeyPairEnum as KeyPair>::PublicKey),
+    NetworkPublicKey(<<KeyPairEnum as KeyPair>::Signator as Signator>::PublicKey),
     /// Does not contain any keys
     None(),
 }
diff --git a/lib/crypto/Cargo.toml b/lib/crypto/Cargo.toml
index 87782b60..b51bda46 100644
--- a/lib/crypto/Cargo.toml
+++ b/lib/crypto/Cargo.toml
@@ -15,7 +15,8 @@ path = "src/lib.rs"
 [dependencies]
 base58 = "0.1.*"
 base64 = "0.10.*"
-cryptoxide = "0.1.2"
+byteorder = "1.2.3"
+clear_on_drop = "0.2.3"
 failure = "0.1.5"
 ring = "0.16.5"
 scrypt = { version = "0.2", default-features = false }
diff --git a/lib/crypto/src/keys/bin_signable.rs b/lib/crypto/src/keys/bin_signable.rs
index 8c985220..b0a89418 100644
--- a/lib/crypto/src/keys/bin_signable.rs
+++ b/lib/crypto/src/keys/bin_signable.rs
@@ -30,24 +30,21 @@ pub trait BinSignable<'de>: Serialize + Deserialize<'de> {
     fn get_bin_without_sig(&self) -> Result<Vec<u8>, failure::Error>;
     /// Add signature to bin datas
     fn add_sig_to_bin_datas(&self, bin_datas: &mut Vec<u8>);
-    /// Sign entity with a private key
-    fn sign(&mut self, priv_key: PrivKey) -> Result<Vec<u8>, SignError> {
+    /// Sign entity with a signator
+    fn sign(&mut self, signator: &SignatorEnum) -> Result<Vec<u8>, SignError> {
         if self.signature().is_some() {
             return Err(SignError::AlreadySign);
         }
         match self.issuer_pubkey() {
-            PubKey::Ed25519(_) => match priv_key {
-                PrivKey::Ed25519(priv_key) => {
-                    let mut bin_msg = self
-                        .get_bin_without_sig()
-                        .map_err(|e| SignError::SerdeError(e.to_string()))?;
-                    let sig = Sig::Ed25519(priv_key.sign(&bin_msg));
-                    self.set_signature(sig);
-                    self.add_sig_to_bin_datas(&mut bin_msg);
-                    Ok(bin_msg)
-                }
-                _ => Err(SignError::WrongAlgo),
-            },
+            PubKey::Ed25519(_) => {
+                let mut bin_msg = self
+                    .get_bin_without_sig()
+                    .map_err(|e| SignError::SerdeError(e.to_string()))?;
+                let sig = signator.sign(&bin_msg);
+                self.set_signature(sig);
+                self.add_sig_to_bin_datas(&mut bin_msg);
+                Ok(bin_msg)
+            }
             _ => Err(SignError::WrongAlgo),
         }
     }
@@ -119,10 +116,16 @@ mod tests {
 
     #[test]
     fn test_bin_signable() {
-        let key_pair = ed25519::KeyPairFromSeedGenerator::generate(&[
+        let key_pair = ed25519::KeyPairFromSeedGenerator::generate(&Seed::new([
             0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
             10, 11, 12, 13, 14, 15,
-        ]);
+        ]));
+
+        let signator = SignatorEnum::Ed25519(
+            key_pair
+                .generate_signator()
+                .expect("fail to generate signator !"),
+        );
 
         let mut bin_signable_datas = BinSignableTestImpl {
             datas: vec![0, 1, 2, 3],
@@ -133,12 +136,12 @@ mod tests {
         assert_eq!(Err(SigError::NotSig), bin_signable_datas.verify());
 
         let _bin_msg = bin_signable_datas
-            .sign(PrivKey::Ed25519(key_pair.privkey))
+            .sign(&signator)
             .expect("Fail to sign datas !");
 
         assert_eq!(
             Err(SignError::AlreadySign),
-            bin_signable_datas.sign(PrivKey::Ed25519(key_pair.privkey))
+            bin_signable_datas.sign(&signator)
         );
 
         assert_eq!(Ok(()), bin_signable_datas.verify())
diff --git a/lib/crypto/src/keys/ed25519.rs b/lib/crypto/src/keys/ed25519.rs
index c767197c..db072b99 100644
--- a/lib/crypto/src/keys/ed25519.rs
+++ b/lib/crypto/src/keys/ed25519.rs
@@ -19,14 +19,13 @@
 //!
 //! [`KeyPairGenerator`]: struct.KeyPairGenerator.html
 
-use super::{PrivateKey as PrivateKeyMethods, PublicKey as PublicKeyMethods};
+use super::seed::Seed;
+use super::PublicKey as PublicKeyMethods;
 use crate::bases::*;
 use base58::ToBase58;
 use base64;
-use cryptoxide as crypto;
-use durs_common_tools::fatal_error;
-use log::error;
-use ring::rand;
+use clear_on_drop::ClearOnDrop;
+use ring::signature::{Ed25519KeyPair as RingKeyPair, KeyPair, UnparsedPublicKey, ED25519};
 use serde::de::{Deserialize, Deserializer, Error, SeqAccess, Visitor};
 use serde::ser::{Serialize, SerializeTuple, Serializer};
 use std::fmt;
@@ -181,116 +180,94 @@ impl super::PublicKey for PublicKey {
     }
 
     fn verify(&self, message: &[u8], signature: &Self::Signature) -> Result<(), SigError> {
-        if crypto::ed25519::verify(message, &self.0, &signature.0) {
-            Ok(())
-        } else {
-            Err(SigError::InvalidSig)
-        }
-    }
-}
-
-/// Store a Ed25519 private key.
-///
-/// Can be generated with [`KeyPairGenerator`].
-///
-/// [`KeyPairGenerator`]: struct.KeyPairGenerator.html
-#[derive(Copy, Clone)]
-pub struct PrivateKey(pub [u8; 64]);
-
-impl ToBase58 for PrivateKey {
-    fn to_base58(&self) -> String {
-        self.0.to_base58()
-    }
-}
-
-impl Display for PrivateKey {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
-        write!(f, "{}", self.to_base58())
-    }
-}
-
-impl Debug for PrivateKey {
-    // PrivateKey { 468Q1XtT... }
-    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
-        write!(f, "PrivateKey {{ {} }}", self)
+        Ok(UnparsedPublicKey::new(&ED25519, &self.0)
+            .verify(message, &signature.0)
+            .map_err(|_| SigError::InvalidSig)?)
     }
 }
 
-impl PartialEq<PrivateKey> for PrivateKey {
-    fn eq(&self, other: &PrivateKey) -> bool {
-        // No PartialEq for [u8;64], need to use 2 [u8;32]
-        self.0[0..32] == other.0[0..32] && self.0[32..64] == other.0[32..64]
-    }
+#[inline]
+fn get_ring_ed25519_pubkey(ring_key_pair: &RingKeyPair) -> PublicKey {
+    let ring_pubkey: <RingKeyPair as KeyPair>::PublicKey = *ring_key_pair.public_key();
+    let mut ring_pubkey_bytes: [u8; 32] = [0u8; 32];
+    ring_pubkey_bytes.copy_from_slice(ring_pubkey.as_ref());
+    PublicKey(ring_pubkey_bytes)
 }
 
-impl Eq for PrivateKey {}
+/// Store a ed25519 cryptographic signator
+#[derive(Debug)]
+pub struct Signator(RingKeyPair);
 
-impl super::PrivateKey for PrivateKey {
+impl super::Signator for Signator {
     type Signature = Signature;
+    type PublicKey = PublicKey;
 
-    #[inline]
-    fn from_base58(base58_data: &str) -> Result<Self, BaseConvertionError> {
-        Ok(PrivateKey(b58::str_base58_to_64bytes(base58_data)?))
+    fn public_key(&self) -> Self::PublicKey {
+        get_ring_ed25519_pubkey(&self.0)
     }
-
-    /// Sign a message with this private key.
     fn sign(&self, message: &[u8]) -> Self::Signature {
-        Signature(crypto::ed25519::signature(message, &self.0))
+        let mut sig_bytes = [0u8; 64];
+        sig_bytes.copy_from_slice(self.0.sign(message).as_ref());
+        Signature(sig_bytes)
     }
 }
 
 /// Store a ed25519 cryptographic key pair (`PublicKey` + `PrivateKey`)
 #[derive(Debug, Copy, Clone, Eq)]
-pub struct KeyPair {
+pub struct Ed25519KeyPair {
     /// Store a Ed25519 public key.
     pub pubkey: PublicKey,
-    /// Store a Ed25519 private key.
-    pub privkey: PrivateKey,
+    /// Store a seed of 32 bytes.
+    pub seed: Seed,
 }
 
-impl Display for KeyPair {
+impl Display for Ed25519KeyPair {
     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
         write!(f, "({}, hidden)", self.pubkey.to_base58())
     }
 }
 
-impl PartialEq<KeyPair> for KeyPair {
-    fn eq(&self, other: &KeyPair) -> bool {
-        self.pubkey.eq(&other.pubkey) && self.privkey.eq(&other.privkey)
+impl PartialEq<Ed25519KeyPair> for Ed25519KeyPair {
+    fn eq(&self, other: &Ed25519KeyPair) -> bool {
+        self.pubkey.eq(&other.pubkey) && self.seed.eq(&other.seed)
     }
 }
 
-impl super::KeyPair for KeyPair {
-    type Signature = Signature;
-    type PublicKey = PublicKey;
-    type PrivateKey = PrivateKey;
+impl super::KeyPair for Ed25519KeyPair {
+    type Signator = Signator;
 
-    fn public_key(&self) -> PublicKey {
-        self.pubkey
+    fn generate_signator(&self) -> Result<Self::Signator, super::SignError> {
+        Ok(Signator(
+            RingKeyPair::from_seed_and_public_key(self.seed.as_ref(), &self.pubkey.0)
+                .map_err(|_| super::SignError::CorruptedKeyPair)?,
+        ))
     }
 
-    fn private_key(&self) -> PrivateKey {
-        self.privkey
+    fn public_key(&self) -> PublicKey {
+        self.pubkey
     }
 
-    fn sign(&self, message: &[u8]) -> Signature {
-        self.private_key().sign(message)
+    fn seed(&self) -> Seed {
+        self.seed
     }
 
-    fn verify(&self, message: &[u8], signature: &Self::Signature) -> Result<(), SigError> {
+    fn verify(
+        &self,
+        message: &[u8],
+        signature: &<Self::Signator as super::Signator>::Signature,
+    ) -> Result<(), SigError> {
         self.public_key().verify(message, signature)
     }
 }
 
-impl KeyPair {
+impl Ed25519KeyPair {
     /// Generate random keypair
     pub fn generate_random() -> Self {
-        let random_seed =
-            if let Ok(random_bytes) = rand::generate::<[u8; 32]>(&rand::SystemRandom::new()) {
-                random_bytes.expose()
-            } else {
-                fatal_error!("System error: fail to generate random hash !")
-            };
+        // generate random seed
+        let mut random_seed = Seed::random();
+        // For security, clear automatically random_seed when it's droped
+        let random_seed = ClearOnDrop::new(&mut random_seed);
+        // Generate and return keypair from seed
         KeyPairFromSeedGenerator::generate(&random_seed)
     }
 }
@@ -304,11 +281,13 @@ impl KeyPairFromSeedGenerator {
     ///
     /// The [`PublicKey`](struct.PublicKey.html) will be able to verify messaged signed with
     /// the [`PrivateKey`](struct.PrivateKey.html).
-    pub fn generate(seed: &[u8; 32]) -> KeyPair {
-        let (private, public) = crypto::ed25519::keypair(seed);
-        KeyPair {
-            pubkey: PublicKey(public),
-            privkey: PrivateKey(private),
+    pub fn generate(seed: &Seed) -> Ed25519KeyPair {
+        let ring_key_pair = RingKeyPair::from_seed_unchecked(seed.as_ref())
+            .expect("dev error: fail to generate ed25519 keypair.");
+
+        Ed25519KeyPair {
+            pubkey: get_ring_ed25519_pubkey(&ring_key_pair),
+            seed: *seed,
         }
     }
 }
@@ -346,106 +325,95 @@ impl KeyPairFromSaltedPasswordGenerator {
     }
 
     /// Create a seed based on a given password and salt.
-    pub fn generate_seed(&self, password: &[u8], salt: &[u8]) -> [u8; 32] {
+    pub fn generate_seed(&self, password: &[u8], salt: &[u8]) -> Seed {
         let mut seed = [0u8; 32];
 
         scrypt::scrypt(salt, password, &self.scrypt_params, &mut seed)
             .expect("dev error: invalid seed len");
 
-        seed
+        Seed::new(seed)
     }
 
     /// Create a keypair based on a given password and salt.
     ///
     /// The [`PublicKey`](struct.PublicKey.html) will be able to verify messaged signed with
     /// the [`PrivateKey`](struct.PrivateKey.html).
-    pub fn generate(&self, password: &[u8], salt: &[u8]) -> KeyPair {
-        let seed: [u8; 32] = self.generate_seed(password, salt);
+    pub fn generate(&self, password: &[u8], salt: &[u8]) -> Ed25519KeyPair {
+        // Generate seed from tuple (password + salt)
+        let mut seed = self.generate_seed(password, salt);
+        // For security, clear automatically seed when it's droped
+        let seed = ClearOnDrop::new(&mut seed);
+        // Generate keypair from seed
         KeyPairFromSeedGenerator::generate(&seed)
     }
 }
 
 #[cfg(test)]
 mod tests {
-    use super::KeyPair as ed25519KeyPair;
     use super::*;
-    use crate::keys::{KeyPair, Sig, Signature};
+    use crate::keys::{KeyPair, Seed, Sig, Signator, Signature};
     use base58::FromBase58;
     use bincode;
     use std::collections::hash_map::DefaultHasher;
 
     #[test]
-    fn base58_private_key() {
-        let private58 =
-            "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9r\
-             qnXuW3iAfZACm7";
-        let private_key = super::PrivateKey::from_base58(private58).unwrap();
+    fn base58_seed() {
+        let seed58 = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV";
 
         // Test base58 encoding/decoding (loop for every bytes)
-        assert_eq!(private_key.to_base58(), private58);
-        let private_raw = private58.from_base58().unwrap();
-        for (key, raw) in private_key.0.iter().zip(private_raw.iter()) {
-            assert_eq!(key, raw);
-        }
+        let seed = Seed::from_base58(seed58).expect("fail to parser seed !");
+        assert_eq!(seed.to_base58(), seed58);
 
-        // Test privkey display and debug
+        // Test seed display and debug
         assert_eq!(
-            "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7".to_owned(),
-            format!("{}", private_key)
+            "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV".to_owned(),
+            format!("{}", seed)
         );
         assert_eq!(
-            "PrivateKey { 468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7 }".to_owned(),
-            format!("{:?}", private_key)
+            "Seed { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(),
+            format!("{:?}", seed)
         );
 
-        // Test privkey equality
-        let same_private_key = private_key.clone();
-        let other_private_key = PrivateKey([
-            0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0,
-        ]);
-        assert!(private_key.eq(&same_private_key));
-        assert!(!private_key.eq(&other_private_key));
+        // Test seed equality
+        let same_seed = seed.clone();
+        let other_seed = Seed::default();
+        assert!(seed.eq(&same_seed));
+        assert!(!seed.eq(&other_seed));
 
-        // Test privkey parsing
+        // Test seed parsing
         assert_eq!(
-            super::PrivateKey::from_base58(
-                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iA\
-                fZACm7djh",
-            ).unwrap_err(),
-            BaseConvertionError::InvalidLength { found: 67, expected: 64 }
+            Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLVgth",).unwrap_err(),
+            BaseConvertionError::InvalidLength {
+                found: 35,
+                expected: 32
+            }
         );
         assert_eq!(
-            super::PrivateKey::from_base58(
-                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9",
-            )
-            .unwrap_err(),
+            Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd",).unwrap_err(),
             BaseConvertionError::InvalidLength {
-                found: 53,
-                expected: 64
+                found: 31,
+                expected: 32
             }
         );
         assert_eq!(
-            super::PrivateKey::from_base58(
-                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9<<",
-            )
-            .unwrap_err(),
+            Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<").unwrap_err(),
             BaseConvertionError::InvalidCharacter {
                 character: '<',
-                offset: 73
+                offset: 42
             }
         );
         assert_eq!(
-            super::PrivateKey::from_base58(
+            Seed::from_base58(
                 "\
-                 468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9\
-                 468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9\
-                 468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9\
-                 ",
+                 DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\
+                 DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\
+                 DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\
+                 DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\
+                 DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\
+                 "
             )
             .unwrap_err(),
-            BaseConvertionError::InvalidBaseConverterLength,
+            BaseConvertionError::InvalidBaseConverterLength
         );
     }
 
@@ -594,18 +562,10 @@ mod tests {
 
     #[test]
     fn message_sign_verify() {
-        let pubkey =
-            super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap();
-
-        let prikey = super::PrivateKey::from_base58(
-            "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt\
-             5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-        )
-        .unwrap();
+        let seed = Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap();
 
         let expected_signature = super::Signature::from_base64(
-            "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FG\
-             MMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
+            "9ARKYkEAwp+kQ01rgvWUwJLchVLpZvHg3t/3H32XwWOoG119NiVCtfPSPtR4GDOeOz6Y+29drOLahqhzy+ciBw==",
         )
         .unwrap();
 
@@ -617,7 +577,11 @@ UniqueID: tic
 Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
 ";
 
-        let sig = prikey.sign(message.as_bytes());
+        let signator = KeyPairFromSeedGenerator::generate(&seed)
+            .generate_signator()
+            .expect("fail to generate signator !");
+        let pubkey = signator.public_key();
+        let sig = signator.sign(message.as_bytes());
         let wrong_sig = Signature([
             0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -656,10 +620,10 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
 
         // Test key_pair equality
         let same_key_pair = key_pair2.clone();
-        let other_key_pair = KeyPairFromSeedGenerator::generate(&[
+        let other_key_pair = KeyPairFromSeedGenerator::generate(&Seed::new([
             0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0,
-        ]);
+        ]));
         assert!(key_pair2.eq(&same_key_pair));
         assert!(!key_pair2.eq(&other_key_pair));
     }
@@ -677,24 +641,10 @@ UniqueID: tic
 Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
 ";
 
-        let sig = keypair.sign(message.as_bytes());
+        let sig = keypair
+            .generate_signator()
+            .expect("fail to gen signator")
+            .sign(message.as_bytes());
         assert!(keypair.verify(message.as_bytes(), &sig).is_ok());
     }
-
-    #[test]
-    fn test_exchange_dh() {
-        let kp1 = ed25519KeyPair::generate_random();
-        let kp2 = ed25519KeyPair::generate_random();
-
-        let secret1 = crypto::ed25519::exchange(&kp1.pubkey.0, &kp2.privkey.0);
-        let secret2 = crypto::ed25519::exchange(&kp2.pubkey.0, &kp1.privkey.0);
-
-        assert_eq!(secret1, secret2);
-
-        println!("pk1={}", kp1.pubkey);
-        println!("pk2={}", kp2.pubkey);
-        println!("shared_secret1={:?}", secret1);
-        println!("shared_secret2={:?}", secret2);
-        //panic!();
-    }
 }
diff --git a/lib/crypto/src/keys/mod.rs b/lib/crypto/src/keys/mod.rs
index e873a720..090d5f00 100644
--- a/lib/crypto/src/keys/mod.rs
+++ b/lib/crypto/src/keys/mod.rs
@@ -21,7 +21,7 @@
 //! # Usage
 //!
 //! ```
-//! use dup_crypto::keys::{Signature, PublicKey, PrivateKey, KeyPair};
+//! use dup_crypto::keys::{KeyPair, PublicKey, Signator, Signature};
 //! use dup_crypto::keys::ed25519::KeyPairFromSaltedPasswordGenerator;
 //!
 //! let generator = KeyPairFromSaltedPasswordGenerator::with_default_parameters();
@@ -31,9 +31,11 @@
 //!     b"salt"
 //! );
 //!
+//! let signator = keypair.generate_signator().expect("keypair corrupted");
+//!
 //! let message = "Hello, world!";
 //!
-//! let signature = keypair.sign(&message.as_bytes());
+//! let signature = signator.sign(&message.as_bytes());
 //!
 //! assert!(keypair.pubkey.verify(&message.as_bytes(), &signature).is_ok());
 //! ```
@@ -46,6 +48,13 @@
 //! `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`
 //! with `=` as padding character.
 
+pub mod bin_signable;
+pub mod ed25519;
+pub mod seed;
+pub mod text_signable;
+
+pub use seed::Seed;
+
 use crate::bases::BaseConvertionError;
 use base58::ToBase58;
 use durs_common_tools::fatal_error;
@@ -57,10 +66,6 @@ use std::fmt::Formatter;
 use std::hash::Hash;
 use std::str::FromStr;
 
-pub mod bin_signable;
-pub mod ed25519;
-pub mod text_signable;
-
 /// Cryptographic keys algorithms list
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
 pub enum KeysAlgo {
@@ -96,6 +101,9 @@ pub enum SigError {
 /// SignError
 #[derive(Debug, Eq, Fail, PartialEq)]
 pub enum SignError {
+    /// Corrupted key pair
+    #[fail(display = "Corrupted key pair.")]
+    CorruptedKeyPair,
     /// WrongAlgo
     #[fail(display = "Wrong algo.")]
     WrongAlgo,
@@ -306,107 +314,47 @@ impl PublicKey for PubKey {
     }
 }
 
-/// Define the operations that can be performed on a cryptographic private key.
-///
-/// A `PrivateKey` can be converted from/to Base58 format.
-/// When converted back and forth the value should be the same.
-///
-/// A `PrivateKey` is used to sign a message. The corresponding [`PublicKey`]
-/// will then be used to verify that signature.
-///
-/// [`PublicKey`]: trait.PublicKey.html
-pub trait PrivateKey: Clone + Display + Debug + PartialEq + Eq + ToBase58 {
-    /// Signature type of associated cryptosystem.
-    type Signature: Signature;
-
-    /// Create a PrivateKey from a Base58 string.
-    ///
-    /// The Base58 string should contains only valid Base58 characters
-    /// and have a correct length. If it's not the case, a [`BaseConvertionError`]
-    /// is returned with the corresponding variant.
-    ///
-    /// [`BaseConvertionError`]: enum.BaseConvertionError.html
-    fn from_base58(base58_string: &str) -> Result<Self, BaseConvertionError>;
-
-    /// Sign a message with this private key.
-    fn sign(&self, message: &[u8]) -> Self::Signature;
-}
-
-/// Store a cryptographic private key.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum PrivKey {
-    /// Store a ed25519 private key.
-    Ed25519(ed25519::PrivateKey),
-    /// Store a Schnorr private key.
-    Schnorr(),
-}
-
-impl GetKeysAlgo for PrivKey {
-    fn algo(&self) -> KeysAlgo {
-        match *self {
-            PrivKey::Ed25519(_) => KeysAlgo::Ed25519,
-            PrivKey::Schnorr() => KeysAlgo::Schnorr,
-        }
-    }
-}
+/// Define the operations that can be performed on a cryptographic key pair.
+pub trait KeyPair: Clone + Display + Debug + PartialEq + Eq {
+    /// Signator type of associated cryptosystem.
+    type Signator: Signator;
 
-impl ToBase58 for PrivKey {
-    fn to_base58(&self) -> String {
-        match *self {
-            PrivKey::Ed25519(ed25519_privkey) => ed25519_privkey.to_base58(),
-            PrivKey::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
-        }
-    }
-}
+    /// Generate signator.
+    fn generate_signator(&self) -> Result<Self::Signator, SignError>;
 
-impl Display for PrivKey {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f, "{}", self.to_base58())
-    }
-}
+    /// Get `PublicKey`
+    fn public_key(&self) -> <Self::Signator as Signator>::PublicKey;
 
-impl PrivateKey for PrivKey {
-    type Signature = Sig;
+    /// Get `Seed`
+    fn seed(&self) -> Seed;
 
-    #[cfg_attr(tarpaulin, skip)]
-    fn from_base58(_base58_string: &str) -> Result<Self, BaseConvertionError> {
-        unimplemented!()
-    }
-    fn sign(&self, message: &[u8]) -> Self::Signature {
-        match *self {
-            PrivKey::Ed25519(ed25519_privkey) => Sig::Ed25519(ed25519_privkey.sign(message)),
-            PrivKey::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
-        }
-    }
+    /// Verify a signature with public key.
+    fn verify(
+        &self,
+        message: &[u8],
+        signature: &<Self::Signator as Signator>::Signature,
+    ) -> Result<(), SigError>;
 }
 
-/// Define the operations that can be performed on a cryptographic key pair.
-pub trait KeyPair: Clone + Display + Debug + PartialEq + Eq {
+/// Define the operations that can be performed on a cryptographic signator.
+pub trait Signator: Debug {
     /// Signature type of associated cryptosystem.
     type Signature: Signature;
     /// PublicKey type of associated cryptosystem.
     type PublicKey: PublicKey;
-    /// PrivateKey type of associated cryptosystem.
-    type PrivateKey: PrivateKey;
 
     /// Get `PublicKey`
     fn public_key(&self) -> Self::PublicKey;
 
-    /// Get `PrivateKey`
-    fn private_key(&self) -> Self::PrivateKey;
-
-    /// Sign a message with private key.
+    /// Sign a message with private key encasuled in signator.
     fn sign(&self, message: &[u8]) -> Self::Signature;
-
-    /// Verify a signature with public key.
-    fn verify(&self, message: &[u8], signature: &Self::Signature) -> Result<(), SigError>;
 }
 
 /// Store a cryptographic key pair.
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum KeyPairEnum {
     /// Store a ed25519 key pair.
-    Ed25519(ed25519::KeyPair),
+    Ed25519(ed25519::Ed25519KeyPair),
     /// Store a Schnorr key pair.
     Schnorr(),
 }
@@ -432,21 +380,25 @@ impl Display for KeyPairEnum {
 }
 
 impl KeyPair for KeyPairEnum {
-    type Signature = Sig;
-    type PublicKey = PubKey;
-    type PrivateKey = PrivKey;
+    type Signator = SignatorEnum;
 
-    fn public_key(&self) -> Self::PublicKey {
+    fn generate_signator(&self) -> Result<Self::Signator, SignError> {
+        match *self {
+            KeyPairEnum::Ed25519(ed25519_keypair) => {
+                Ok(SignatorEnum::Ed25519(ed25519_keypair.generate_signator()?))
+            }
+            KeyPairEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
+        }
+    }
+    fn public_key(&self) -> <Self::Signator as Signator>::PublicKey {
         match *self {
             KeyPairEnum::Ed25519(ed25519_keypair) => PubKey::Ed25519(ed25519_keypair.public_key()),
             KeyPairEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
         }
     }
-    fn private_key(&self) -> Self::PrivateKey {
+    fn seed(&self) -> Seed {
         match *self {
-            KeyPairEnum::Ed25519(ed25519_keypair) => {
-                PrivKey::Ed25519(ed25519_keypair.private_key())
-            }
+            KeyPairEnum::Ed25519(ed25519_keypair) => ed25519_keypair.seed(),
             KeyPairEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
         }
     }
@@ -462,10 +414,36 @@ impl KeyPair for KeyPairEnum {
             KeyPairEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
         }
     }
+}
+
+/// Store a cryptographic signator.
+#[derive(Debug)]
+pub enum SignatorEnum {
+    /// Store a ed25519 signator.
+    Ed25519(ed25519::Signator),
+    /// Store a Schnorr signator.
+    Schnorr(),
+}
+
+impl Signator for SignatorEnum {
+    type PublicKey = PubKey;
+    type Signature = Sig;
+
+    fn public_key(&self) -> Self::PublicKey {
+        match self {
+            SignatorEnum::Ed25519(ref ed25519_signator) => {
+                PubKey::Ed25519(ed25519_signator.public_key())
+            }
+            SignatorEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
+        }
+    }
+
     fn sign(&self, message: &[u8]) -> Sig {
-        match *self {
-            KeyPairEnum::Ed25519(ed25519_keypair) => Sig::Ed25519(ed25519_keypair.sign(message)),
-            KeyPairEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
+        match self {
+            SignatorEnum::Ed25519(ref ed25519_signator) => {
+                Sig::Ed25519(ed25519_signator.sign(message))
+            }
+            SignatorEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"),
         }
     }
 }
@@ -474,24 +452,14 @@ impl KeyPair for KeyPairEnum {
 mod tests {
 
     use super::*;
+    use crate::hashs::Hash;
+    use ring::{agreement, rand};
 
     pub fn valid_key_pair_1() -> KeyPairEnum {
-        let kp = KeyPairEnum::Ed25519(ed25519::KeyPair {
-            pubkey: ed25519::PublicKey([
-                59u8, 106, 39, 188, 206, 182, 164, 45, 98, 163, 168, 208, 42, 111, 13, 115, 101,
-                50, 21, 119, 29, 226, 67, 166, 58, 192, 72, 161, 139, 89, 218, 41,
-            ]),
-            privkey: ed25519::PrivateKey([
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 59, 106, 39, 188, 206, 182, 164, 45, 98, 163, 168, 208, 42, 111, 13,
-                115, 101, 50, 21, 119, 29, 226, 67, 166, 58, 192, 72, 161, 139, 89, 218, 41,
-            ]),
-        });
-        println!("kp.pub={:?}", kp.public_key().to_bytes_vector());
-        if let PrivKey::Ed25519(ed_pk) = kp.private_key() {
-            println!("kp.priv={:?}", ed_pk.0.to_vec());
-        }
-        kp
+        KeyPairEnum::Ed25519(ed25519::KeyPairFromSeedGenerator::generate(&Seed::new([
+            59u8, 106, 39, 188, 206, 182, 164, 45, 98, 163, 168, 208, 42, 111, 13, 115, 101, 50,
+            21, 119, 29, 226, 67, 166, 58, 192, 72, 161, 139, 89, 218, 41,
+        ])))
     }
 
     #[test]
@@ -555,41 +523,31 @@ mod tests {
     }
 
     #[test]
-    fn privkey() {
-        let privkey_bytes = [
+    fn seed() {
+        let seed_default = Seed::default();
+        let seed_bytes = [
             0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0,
         ];
-        let privkey_str_b58 =
-            "1111111111111111111111111111111111111111111111111111111111111111".to_owned();
-        let privkey = PrivKey::Ed25519(ed25519::PrivateKey(privkey_bytes));
-
-        assert_eq!(privkey_str_b58, format!("{}", privkey));
-
-        assert_eq!(KeysAlgo::Ed25519, privkey.algo());
-        assert_eq!(KeysAlgo::Schnorr, PrivKey::Schnorr().algo());
-
-        assert_eq!(privkey_str_b58, privkey.to_base58());
+        let seed_str_b58 = "11111111111111111111111111111111".to_owned();
+        let seed = Seed::new(seed_bytes);
 
+        assert_eq!(seed_default, seed);
         assert_eq!(
-            Sig::Ed25519(ed25519::Signature::from_base64("JPurBgnHExHND1woow9nB7xVQjKkdHGs1znQbgv0ttboJXueHKd4SOvxuNWmw4w07F4CT//olYMEBw51Cy0SDA==").unwrap()),
-            privkey.sign(b"message")
+            seed_default,
+            Seed::from_base58(&seed_str_b58).expect("Fail to parse seed !")
         );
+
+        assert_eq!(seed_str_b58, format!("{}", seed));
+
+        assert_eq!(seed_str_b58, seed.to_base58());
     }
 
-    fn false_key_pair_ed25519() -> ed25519::KeyPair {
-        ed25519::KeyPair {
-            pubkey: ed25519::PublicKey([
-                0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0,
-            ]),
-            privkey: ed25519::PrivateKey([
-                0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0,
-            ]),
-        }
+    fn false_key_pair_ed25519() -> ed25519::Ed25519KeyPair {
+        ed25519::KeyPairFromSeedGenerator::generate(&Seed::new([
+            0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0,
+        ]))
     }
 
     #[test]
@@ -600,17 +558,14 @@ mod tests {
         assert_eq!(KeysAlgo::Ed25519, false_key_pair.algo());
         assert_eq!(KeysAlgo::Schnorr, KeyPairEnum::Schnorr().algo());
         assert_eq!(
-            "(11111111111111111111111111111111, hidden)".to_owned(),
+            "(4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS, hidden)".to_owned(),
             format!("{}", false_key_pair)
         );
         assert_eq!(
             PubKey::Ed25519(false_key_pair_ed25519.pubkey),
             false_key_pair.public_key()
         );
-        assert_eq!(
-            PrivKey::Ed25519(false_key_pair_ed25519.privkey),
-            false_key_pair.private_key()
-        );
+        assert_eq!(false_key_pair_ed25519.seed, false_key_pair.seed());
         assert_eq!(
             Err(SigError::InvalidSig),
             false_key_pair.verify(
@@ -627,7 +582,7 @@ mod tests {
     #[test]
     #[should_panic(
         expected = "Try to verify a signature with key pair of a different algorithm !\n\
-                    Signature=Schnorr\nKeyPair=(11111111111111111111111111111111, hidden)"
+                    Signature=Schnorr\nKeyPair=(4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS, hidden)"
     )]
     fn key_pair_verify_wrong_sig_algo() {
         let false_key_pair_ed25519 = false_key_pair_ed25519();
@@ -694,20 +649,6 @@ mod tests {
         let _ = pubkey.verify(b"message", &Sig::Schnorr());
     }
 
-    #[test]
-    #[should_panic(expected = "Schnorr algo not yet supported !")]
-    fn privkey_schnorr_base58() {
-        let privkey = PrivKey::Schnorr();
-        privkey.to_base58();
-    }
-
-    #[test]
-    #[should_panic(expected = "Schnorr algo not yet supported !")]
-    fn privkey_schnorr_sign() {
-        let privkey = PrivKey::Schnorr();
-        privkey.sign(b"message");
-    }
-
     #[test]
     #[should_panic(expected = "Schnorr algo not yet supported !")]
     fn key_pair_schnorr_display() {
@@ -724,9 +665,9 @@ mod tests {
 
     #[test]
     #[should_panic(expected = "Schnorr algo not yet supported !")]
-    fn key_pair_schnorr_get_privkey() {
+    fn key_pair_schnorr_get_seed() {
         let key_pair = KeyPairEnum::Schnorr();
-        key_pair.private_key();
+        key_pair.seed();
     }
 
     #[test]
@@ -738,8 +679,59 @@ mod tests {
 
     #[test]
     #[should_panic(expected = "Schnorr algo not yet supported !")]
-    fn key_pair_schnorr_sign() {
-        let key_pair = KeyPairEnum::Schnorr();
-        key_pair.sign(b"message");
+    fn signator_schnorr_get_pubkey() {
+        let signator = SignatorEnum::Schnorr();
+        signator.public_key();
+    }
+
+    #[test]
+    #[should_panic(expected = "Schnorr algo not yet supported !")]
+    fn signator_schnorr_sign() {
+        let signator = SignatorEnum::Schnorr();
+        signator.sign(b"message");
+    }
+
+    #[test]
+    fn test_exchange_dh() -> Result<(), ring::error::Unspecified> {
+        let rng = rand::SystemRandom::new();
+
+        let secret_key_1 = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?;
+        let public_key_1 = secret_key_1.compute_public_key()?;
+
+        let secret_key_2 = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?;
+        let public_key_2 = secret_key_2.compute_public_key()?;
+
+        let dh1 = agreement::agree_ephemeral(
+            secret_key_1,
+            &agreement::UnparsedPublicKey::new(&agreement::X25519, &public_key_2),
+            ring::error::Unspecified,
+            |key_material| {
+                // In a real application, we'd apply a KDF to the key material and the
+                // public keys (as recommended in RFC 7748) and then derive session
+                // keys from the result.
+                Ok(Hash::compute(key_material))
+            },
+        )?;
+
+        let dh2 = agreement::agree_ephemeral(
+            secret_key_2,
+            &agreement::UnparsedPublicKey::new(&agreement::X25519, &public_key_1),
+            ring::error::Unspecified,
+            |key_material| {
+                // In a real application, we'd apply a KDF to the key material and the
+                // public keys (as recommended in RFC 7748) and then derive session
+                // keys from the result.
+                Ok(Hash::compute(key_material))
+            },
+        )?;
+
+        assert_eq!(dh1, dh2);
+
+        println!("pk1={:?}", public_key_1);
+        println!("pk2={:?}", public_key_2);
+        println!("shared_secret1={:?}", dh1);
+        println!("shared_secret2={:?}", dh2);
+        //panic!();
+        Ok(())
     }
 }
diff --git a/lib/crypto/src/keys/seed.rs b/lib/crypto/src/keys/seed.rs
new file mode 100644
index 00000000..34facb3b
--- /dev/null
+++ b/lib/crypto/src/keys/seed.rs
@@ -0,0 +1,74 @@
+//  Copyright (C) 2017-2019  The AXIOM TEAM Association.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Provide wrappers around cryptographic seed
+
+use crate::bases::*;
+use base58::ToBase58;
+use durs_common_tools::fatal_error;
+use log::error;
+use ring::rand;
+use std::fmt::{self, Debug, Display, Formatter};
+
+/// Store a 32 bytes seed used to generate keys.
+#[derive(Copy, Clone, Default, Deserialize, PartialEq, Eq, Hash, Serialize)]
+pub struct Seed([u8; 32]);
+
+impl AsRef<[u8]> for Seed {
+    fn as_ref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+impl ToBase58 for Seed {
+    fn to_base58(&self) -> String {
+        self.0.to_base58()
+    }
+}
+
+impl Display for Seed {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
+        write!(f, "{}", self.to_base58())
+    }
+}
+
+impl Debug for Seed {
+    // Seed { DNann1L... }
+    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
+        write!(f, "Seed {{ {} }}", self)
+    }
+}
+
+impl Seed {
+    #[inline]
+    /// Create new seed
+    pub fn new(seed_bytes: [u8; 32]) -> Seed {
+        Seed(seed_bytes)
+    }
+    #[inline]
+    /// Create seed from base58 str
+    pub fn from_base58(base58_str: &str) -> Result<Self, BaseConvertionError> {
+        Ok(Seed(b58::str_base58_to_32bytes(base58_str)?))
+    }
+    #[inline]
+    /// Generate random seed
+    pub fn random() -> Seed {
+        if let Ok(random_bytes) = rand::generate::<[u8; 32]>(&rand::SystemRandom::new()) {
+            Seed(random_bytes.expose())
+        } else {
+            fatal_error!("System error: fail to generate random seed !")
+        }
+    }
+}
diff --git a/lib/crypto/src/keys/text_signable.rs b/lib/crypto/src/keys/text_signable.rs
index 34552512..27c0c6c2 100644
--- a/lib/crypto/src/keys/text_signable.rs
+++ b/lib/crypto/src/keys/text_signable.rs
@@ -28,15 +28,15 @@ pub trait TextSignable: Debug + Clone {
     /// Change signature
     fn set_signature(&mut self, _signature: Sig);
     /// Sign entity
-    fn sign(&mut self, priv_key: PrivKey) -> Result<String, SignError> {
+    fn sign(&mut self, signator: &SignatorEnum) -> Result<String, SignError> {
         if self.signature().is_some() {
             return Err(SignError::AlreadySign);
         }
         match self.issuer_pubkey() {
-            PubKey::Ed25519(_) => match priv_key {
-                PrivKey::Ed25519(priv_key) => {
+            PubKey::Ed25519(_) => match signator {
+                SignatorEnum::Ed25519(ed25519_signator) => {
                     let text = self.as_signable_text();
-                    let sig = priv_key.sign(&text.as_bytes());
+                    let sig = ed25519_signator.sign(&text.as_bytes());
                     self.set_signature(Sig::Ed25519(sig));
                     let str_sig = sig.to_base64();
                     Ok(format!("{}{}", text, str_sig))
@@ -102,6 +102,10 @@ mod tests {
     fn test_text_signable() {
         let key_pair = super::super::tests::valid_key_pair_1();
 
+        let signator = key_pair
+            .generate_signator()
+            .expect("fail to generate signator");
+
         let mut text_signable = TextSignableTestImpl {
             issuer: key_pair.public_key(),
             text: "toto".to_owned(),
@@ -111,22 +115,16 @@ mod tests {
         assert_eq!(Err(SigError::NotSig), text_signable.verify());
         assert_eq!(
             Err(SignError::WrongAlgo),
-            text_signable.sign(PrivKey::Schnorr())
+            text_signable.sign(&SignatorEnum::Schnorr())
         );
         text_signable.issuer = PubKey::Schnorr();
-        assert_eq!(
-            Err(SignError::WrongAlgo),
-            text_signable.sign(key_pair.private_key())
-        );
+        assert_eq!(Err(SignError::WrongAlgo), text_signable.sign(&signator));
         text_signable.issuer = key_pair.public_key();
         assert_eq!(
-            Ok("4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS:totoe53bEIYLX3IK7p0IBm60jAZfrQWxrBpinvzJqGxvD3kAzoe+zp2FGIXuxHMobrImu/Au33sB9k/6yOhtFz/YAw==".to_owned()),
-            text_signable.sign(key_pair.private_key())
-        );
-        assert_eq!(
-            Err(SignError::AlreadySign),
-            text_signable.sign(key_pair.private_key())
+            Ok("VYgskcKKh525MzFRzpCiT5KXCQrnFLTnzMLffbvm9uw:toto+IC1fFkkYo5ox2loc1IMLCtrir1i6oyljfshNXIyXVcz6sJMFqn+6o8Zip4XdTzoBEORkbcnEnqQEr4TgaHpCw==".to_owned()),
+            text_signable.sign(&signator)
         );
+        assert_eq!(Err(SignError::AlreadySign), text_signable.sign(&signator));
         assert_eq!(Ok(()), text_signable.verify());
         let old_sig = text_signable.sig.replace(Sig::Schnorr());
         assert_eq!(Err(SigError::NotSameAlgo), text_signable.verify());
diff --git a/lib/crypto/src/lib.rs b/lib/crypto/src/lib.rs
index fd648c3c..33ac9c5c 100644
--- a/lib/crypto/src/lib.rs
+++ b/lib/crypto/src/lib.rs
@@ -13,7 +13,7 @@
 // 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/>.
 
-//! Manage cryptographic operations for the DUP (DUniter Protocol).
+//! Manage cryptographic operations.
 
 #![deny(
     clippy::option_unwrap_used,
@@ -39,25 +39,27 @@ extern crate log;
 pub mod bases;
 pub mod hashs;
 pub mod keys;
+pub mod rand;
 
 #[cfg(test)]
 mod tests {
 
     use super::*;
+    use crate::keys::Seed;
     use ring::signature::Ed25519KeyPair;
     use ring::signature::KeyPair;
 
     #[test]
     fn test_ring_gen_keypair() {
-        let seed = [
+        let seed = Seed::new([
             61u8, 245, 136, 162, 155, 50, 205, 43, 116, 15, 45, 84, 138, 54, 114, 214, 71, 213, 11,
             251, 135, 182, 202, 131, 48, 91, 166, 226, 40, 255, 251, 172,
-        ];
+        ]);
 
         let legacy_key_pair = keys::ed25519::KeyPairFromSeedGenerator::generate(&seed);
 
         let ring_key_pair: Ed25519KeyPair =
-            Ed25519KeyPair::from_seed_and_public_key(&seed, &legacy_key_pair.pubkey.0)
+            Ed25519KeyPair::from_seed_and_public_key(seed.as_ref(), &legacy_key_pair.pubkey.0)
                 .expect("fail to generate ring key pair !");
 
         let ring_pubkey: <Ed25519KeyPair as KeyPair>::PublicKey = *ring_key_pair.public_key();
diff --git a/lib/crypto/src/rand/mod.rs b/lib/crypto/src/rand/mod.rs
new file mode 100644
index 00000000..313cd60f
--- /dev/null
+++ b/lib/crypto/src/rand/mod.rs
@@ -0,0 +1,43 @@
+//  Copyright (C) 2017-2019  The AXIOM TEAM Association.
+//
+// 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/>.
+
+//! Manage random generation.
+
+use byteorder::ByteOrder;
+use durs_common_tools::fatal_error;
+use log::error;
+use ring::rand;
+
+#[inline]
+/// Generate random u32
+pub fn gen_u32() -> u32 {
+    let rng = rand::SystemRandom::new();
+    if let Ok(random_bytes) = rand::generate::<[u8; 4]>(&rng) {
+        byteorder::BigEndian::read_u32(&random_bytes.expose())
+    } else {
+        fatal_error!("System error: fail to generate random boolean !")
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    #[test]
+    fn test_gen_u32() {
+        assert_ne!(gen_u32(), gen_u32())
+    }
+}
diff --git a/lib/dubp/block-doc/src/block.rs b/lib/dubp/block-doc/src/block.rs
index 4bb62449..0364e451 100644
--- a/lib/dubp/block-doc/src/block.rs
+++ b/lib/dubp/block-doc/src/block.rs
@@ -21,7 +21,7 @@ use dubp_common_doc::blockstamp::Blockstamp;
 use dubp_common_doc::traits::{Document, ToStringObject};
 use dubp_common_doc::{BlockHash, BlockNumber};
 use dup_crypto::hashs::Hash;
-use dup_crypto::keys::{PrivKey, PubKey, PublicKey};
+use dup_crypto::keys::{PubKey, PublicKey, SignatorEnum};
 
 pub use v10::{BlockDocumentV10, BlockDocumentV10Stringified};
 
@@ -88,7 +88,7 @@ pub trait BlockDocumentTrait {
     /// Verify block hash
     fn verify_hash(&self) -> Result<(), VerifyBlockHashError>;
     /// Sign block
-    fn sign(&mut self, privkey: PrivKey);
+    fn sign(&mut self, signator: SignatorEnum);
 }
 
 impl BlockDocumentTrait for BlockDocument {
@@ -201,9 +201,9 @@ impl BlockDocumentTrait for BlockDocument {
         }
     }
     #[inline]
-    fn sign(&mut self, privkey: PrivKey) {
+    fn sign(&mut self, signator: SignatorEnum) {
         match self {
-            BlockDocument::V10(block) => block.sign(privkey),
+            BlockDocument::V10(block) => block.sign(signator),
         }
     }
 }
diff --git a/lib/dubp/block-doc/src/block/v10.rs b/lib/dubp/block-doc/src/block/v10.rs
index 857d7915..497c9d47 100644
--- a/lib/dubp/block-doc/src/block/v10.rs
+++ b/lib/dubp/block-doc/src/block/v10.rs
@@ -345,8 +345,8 @@ Transactions:{transactions}
             i.reduce();
         }
     }
-    fn sign(&mut self, privkey: PrivKey) {
-        self.signatures = vec![privkey.sign(self.compute_will_signed_string().as_bytes())];
+    fn sign(&mut self, signator: SignatorEnum) {
+        self.signatures = vec![signator.sign(self.compute_will_signed_string().as_bytes())];
     }
     fn verify_inner_hash(&self) -> Result<(), VerifyBlockHashError> {
         match self.inner_hash {
diff --git a/lib/dubp/common-doc/src/traits.rs b/lib/dubp/common-doc/src/traits.rs
index 1a0c46b4..206aab0e 100644
--- a/lib/dubp/common-doc/src/traits.rs
+++ b/lib/dubp/common-doc/src/traits.rs
@@ -117,8 +117,8 @@ pub trait DocumentBuilder {
     /// Type of the builded document.
     type Document: Document;
 
-    /// Type of the private keys signing the documents.
-    type PrivateKey: PrivateKey<
+    /// Type of the signator signing the documents.
+    type Signator: Signator<
         Signature = <<Self::Document as Document>::PublicKey as PublicKey>::Signature,
     >;
 
@@ -129,7 +129,7 @@ pub trait DocumentBuilder {
     ) -> Self::Document;
 
     /// Build a document and sign it with the private key.
-    fn build_and_sign(&self, private_keys: Vec<Self::PrivateKey>) -> Self::Document;
+    fn build_and_sign(&self, signators: Vec<Self::Signator>) -> Self::Document;
 }
 
 /// Trait for a document parser from a `S` source
diff --git a/lib/dubp/common-doc/src/traits/text.rs b/lib/dubp/common-doc/src/traits/text.rs
index e3c721e1..717e7a88 100644
--- a/lib/dubp/common-doc/src/traits/text.rs
+++ b/lib/dubp/common-doc/src/traits/text.rs
@@ -117,14 +117,14 @@ pub trait TextDocumentBuilder: DocumentBuilder {
     ///
     /// - Text without signatures
     /// - Signatures
-    fn build_signed_text(&self, private_keys: Vec<PrivKey>) -> (String, Vec<Sig>) {
+    fn build_signed_text(&self, signators: Vec<SignatorEnum>) -> (String, Vec<Sig>) {
         let text = self.generate_text();
 
         let signatures: Vec<_> = {
             let text_bytes = text.as_bytes();
-            private_keys
+            signators
                 .iter()
-                .map(|key| key.sign(text_bytes))
+                .map(|signator| signator.sign(text_bytes))
                 .collect()
         };
 
diff --git a/lib/dubp/user-docs/src/documents/certification/v10.rs b/lib/dubp/user-docs/src/documents/certification/v10.rs
index d125639d..d21a823c 100644
--- a/lib/dubp/user-docs/src/documents/certification/v10.rs
+++ b/lib/dubp/user-docs/src/documents/certification/v10.rs
@@ -296,13 +296,13 @@ impl<'a> CertificationDocumentV10Builder<'a> {
 
 impl<'a> DocumentBuilder for CertificationDocumentV10Builder<'a> {
     type Document = CertificationDocumentV10;
-    type PrivateKey = PrivKey;
+    type Signator = SignatorEnum;
 
     fn build_with_signature(&self, signatures: Vec<Sig>) -> CertificationDocumentV10 {
         self.build_with_text_and_sigs(self.generate_text(), signatures)
     }
 
-    fn build_and_sign(&self, private_keys: Vec<PrivKey>) -> CertificationDocumentV10 {
+    fn build_and_sign(&self, private_keys: Vec<SignatorEnum>) -> CertificationDocumentV10 {
         let (text, signatures) = self.build_signed_text(private_keys);
         self.build_with_text_and_sigs(text, signatures)
     }
@@ -335,21 +335,19 @@ CertTimestamp: {blockstamp}
 #[cfg(test)]
 mod tests {
     use super::*;
-    use dup_crypto::keys::{PrivateKey, PublicKey, Signature};
+    use dup_crypto::keys::{PublicKey, Signature};
 
     #[test]
     fn generate_real_document() {
-        let pubkey = PubKey::Ed25519(
-            ed25519::PublicKey::from_base58("4tNQ7d9pj2Da5wUVoW9mFn7JjuPoowF977au8DdhEjVR")
-                .unwrap(),
+        let keypair = ed25519::KeyPairFromSeedGenerator::generate(
+            &Seed::from_base58("4tNQ7d9pj2Da5wUVoW9mFn7JjuPoowF977au8DdhEjVR").unwrap(),
         );
-
-        let prikey = PrivKey::Ed25519(ed25519::PrivateKey::from_base58(
-            "3XGWuuU1dQ7zaYPzE76ATfY71STzRkbT3t4DE1bSjMhYje81XdJFeXVG9uMPi3oDeRTosT2dmBAFH8VydrAUWXRZ",
-        ).unwrap());
+        let pubkey = PubKey::Ed25519(keypair.public_key());
+        let signator =
+            SignatorEnum::Ed25519(keypair.generate_signator().expect("fail to gen signator"));
 
         let sig = Sig::Ed25519(ed25519::Signature::from_base64(
-            "qfR6zqT1oJbqIsppOi64gC9yTtxb6g6XA9RYpulkq9ehMvqg2VYVigCbR0yVpqKFsnYiQTrnjgFuFRSJCJDfCw==",
+            "sYbaZp3pP9F/CveT1LPiJXECTBHlNurDXqmBo71N7JX/rvmHw6m/sid9bGdIa8cUq+vDD4DMB/F7r7As1p4rAg==",
         ).unwrap());
 
         let target = PubKey::Ed25519(
@@ -381,13 +379,22 @@ mod tests {
             blockstamp: &blockstamp,
         };
 
+        /*println!(
+            "Signatures = {:?}",
+            builder
+                .build_and_sign(vec![SignatorEnum::Ed25519(
+                    keypair.generate_signator().expect("fail to gen signator")
+                )])
+                .signatures()
+        );*/
+
         assert!(builder
             .build_with_signature(vec![sig])
             .verify_signatures()
             .is_ok());
 
         assert!(builder
-            .build_and_sign(vec![prikey])
+            .build_and_sign(vec![signator])
             .verify_signatures()
             .is_ok());
     }
diff --git a/lib/dubp/user-docs/src/documents/identity/v10.rs b/lib/dubp/user-docs/src/documents/identity/v10.rs
index b26c078f..82741e9b 100644
--- a/lib/dubp/user-docs/src/documents/identity/v10.rs
+++ b/lib/dubp/user-docs/src/documents/identity/v10.rs
@@ -234,13 +234,13 @@ impl<'a> IdentityDocumentV10Builder<'a> {
 
 impl<'a> DocumentBuilder for IdentityDocumentV10Builder<'a> {
     type Document = IdentityDocumentV10;
-    type PrivateKey = PrivKey;
+    type Signator = SignatorEnum;
 
     fn build_with_signature(&self, signatures: Vec<Sig>) -> IdentityDocumentV10 {
         self.build_with_text_and_sigs(self.generate_text(), signatures)
     }
 
-    fn build_and_sign(&self, private_keys: Vec<PrivKey>) -> IdentityDocumentV10 {
+    fn build_and_sign(&self, private_keys: Vec<SignatorEnum>) -> IdentityDocumentV10 {
         let (text, signatures) = self.build_signed_text(private_keys);
         self.build_with_text_and_sigs(text, signatures)
     }
@@ -268,27 +268,20 @@ Timestamp: {blockstamp}
 mod tests {
     use super::*;
     use dubp_common_doc::traits::Document;
-    use dup_crypto::keys::{PrivateKey, PublicKey, Signature};
+    use dup_crypto::keys::Signature;
 
     #[test]
     fn generate_real_document() {
-        let pubkey = PubKey::Ed25519(
-            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
-                .unwrap(),
-        );
-
-        let prikey = PrivKey::Ed25519(
-            ed25519::PrivateKey::from_base58(
-                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5G\
-                 iERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-            )
-            .unwrap(),
+        let keypair = ed25519::KeyPairFromSeedGenerator::generate(
+            &Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(),
         );
+        let pubkey = PubKey::Ed25519(keypair.public_key());
+        let signator =
+            SignatorEnum::Ed25519(keypair.generate_signator().expect("fail to gen signator"));
 
         let sig = Sig::Ed25519(
             ed25519::Signature::from_base64(
-                "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGM\
-                 MmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
+                "mmFepRsiOjILKnCvEvN3IZScLOfg8+e0JPAl5VkiuTLZRGJKgKhPy8nQlCKbeg0jefQm/2HJ78e/Sj+NMqYLCw==",
             )
             .unwrap(),
         );
@@ -305,12 +298,21 @@ mod tests {
             issuer: &pubkey,
         };
 
+        /*println!(
+            "Signatures = {:?}",
+            builder
+                .build_and_sign(vec![SignatorEnum::Ed25519(
+                    keypair.generate_signator().expect("fail to gen signator")
+                )])
+                .signatures()
+        );*/
+
         assert!(builder
             .build_with_signature(vec![sig])
             .verify_signatures()
             .is_ok());
         assert!(builder
-            .build_and_sign(vec![prikey])
+            .build_and_sign(vec![signator])
             .verify_signatures()
             .is_ok());
     }
diff --git a/lib/dubp/user-docs/src/documents/membership/v10.rs b/lib/dubp/user-docs/src/documents/membership/v10.rs
index 25ecc0b0..966c9f66 100644
--- a/lib/dubp/user-docs/src/documents/membership/v10.rs
+++ b/lib/dubp/user-docs/src/documents/membership/v10.rs
@@ -291,13 +291,13 @@ impl<'a> MembershipDocumentV10Builder<'a> {
 
 impl<'a> DocumentBuilder for MembershipDocumentV10Builder<'a> {
     type Document = MembershipDocumentV10;
-    type PrivateKey = PrivKey;
+    type Signator = SignatorEnum;
 
     fn build_with_signature(&self, signatures: Vec<Sig>) -> MembershipDocumentV10 {
         self.build_with_text_and_sigs(self.generate_text(), signatures)
     }
 
-    fn build_and_sign(&self, private_keys: Vec<PrivKey>) -> MembershipDocumentV10 {
+    fn build_and_sign(&self, private_keys: Vec<SignatorEnum>) -> MembershipDocumentV10 {
         let (text, signatures) = self.build_signed_text(private_keys);
         self.build_with_text_and_sigs(text, signatures)
     }
@@ -331,27 +331,20 @@ CertTS: {ity_blockstamp}
 #[cfg(test)]
 mod tests {
     use super::*;
-    use dup_crypto::keys::{PrivateKey, PublicKey, Signature};
+    use dup_crypto::keys::Signature;
 
     #[test]
     fn generate_real_document() {
-        let pubkey = PubKey::Ed25519(
-            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
-                .unwrap(),
-        );
-
-        let prikey = PrivKey::Ed25519(
-            ed25519::PrivateKey::from_base58(
-                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5G\
-                 iERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-            )
-            .unwrap(),
+        let keypair = ed25519::KeyPairFromSeedGenerator::generate(
+            &Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(),
         );
+        let pubkey = PubKey::Ed25519(keypair.public_key());
+        let signator =
+            SignatorEnum::Ed25519(keypair.generate_signator().expect("fail to gen signator"));
 
         let sig = Sig::Ed25519(
             ed25519::Signature::from_base64(
-                "s2hUbokkibTAWGEwErw6hyXSWlWFQ2UWs2PWx8d/kkEl\
-                 AyuuWaQq4Tsonuweh1xn4AC1TVWt4yMR3WrDdkhnAw==",
+                "cUgoc8AI+Tae/AZmRfTnW+xq3XFtmYoUi2LXlmXr8/7LaXiUccQb8+Ds1nZoBp/8+t031HMwqAUpVIqww2FGCg==",
             )
             .unwrap(),
         );
@@ -370,12 +363,21 @@ mod tests {
             identity_blockstamp: &block,
         };
 
+        /*println!(
+            "Signatures = {:?}",
+            builder
+                .build_and_sign(vec![SignatorEnum::Ed25519(
+                    keypair.generate_signator().expect("fail to gen signator")
+                )])
+                .signatures()
+        );*/
+
         assert!(builder
             .build_with_signature(vec![sig])
             .verify_signatures()
             .is_ok());
         assert!(builder
-            .build_and_sign(vec![prikey])
+            .build_and_sign(vec![signator])
             .verify_signatures()
             .is_ok());
     }
diff --git a/lib/dubp/user-docs/src/documents/revocation/v10.rs b/lib/dubp/user-docs/src/documents/revocation/v10.rs
index d58118e8..daf0539e 100644
--- a/lib/dubp/user-docs/src/documents/revocation/v10.rs
+++ b/lib/dubp/user-docs/src/documents/revocation/v10.rs
@@ -264,13 +264,13 @@ impl<'a> RevocationDocumentV10Builder<'a> {
 
 impl<'a> DocumentBuilder for RevocationDocumentV10Builder<'a> {
     type Document = RevocationDocumentV10;
-    type PrivateKey = PrivKey;
+    type Signator = SignatorEnum;
 
     fn build_with_signature(&self, signatures: Vec<Sig>) -> RevocationDocumentV10 {
         self.build_with_text_and_sigs(self.generate_text(), signatures)
     }
 
-    fn build_and_sign(&self, private_keys: Vec<PrivKey>) -> RevocationDocumentV10 {
+    fn build_and_sign(&self, private_keys: Vec<SignatorEnum>) -> RevocationDocumentV10 {
         let (text, signatures) = self.build_signed_text(private_keys);
         self.build_with_text_and_sigs(text, signatures)
     }
@@ -299,25 +299,19 @@ IdtySignature: {idty_sig}
 #[cfg(test)]
 mod tests {
     use super::*;
-    use dup_crypto::keys::{PrivateKey, PublicKey, Signature};
+    use dup_crypto::keys::Signature;
 
     #[test]
     fn generate_real_document() {
-        let pubkey = PubKey::Ed25519(
-            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
-                .unwrap(),
-        );
-
-        let prikey = PrivKey::Ed25519(
-            ed25519::PrivateKey::from_base58(
-                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5G\
-                 iERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-            )
-            .unwrap(),
+        let keypair = ed25519::KeyPairFromSeedGenerator::generate(
+            &Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(),
         );
+        let pubkey = PubKey::Ed25519(keypair.public_key());
+        let signator =
+            SignatorEnum::Ed25519(keypair.generate_signator().expect("fail to gen signator"));
 
         let sig = Sig::Ed25519(ed25519::Signature::from_base64(
-            "XXOgI++6qpY9O31ml/FcfbXCE6aixIrgkT5jL7kBle3YOMr+8wrp7Rt+z9hDVjrNfYX2gpeJsuMNfG4T/fzVDQ==",
+            "gBD2mCr7E/tW8u3wqVK7IWtQB6IKxddg13UMl9ypVsv/VhqhAFTBba9BwoK5t6H9eqF1d+4sCB3WY2eJ/yuUAg==",
         ).unwrap());
 
         let identity_blockstamp = Blockstamp::from_string(
@@ -337,13 +331,22 @@ mod tests {
             identity_sig: &identity_sig,
         };
 
+        /*println!(
+            "Signatures = {:?}",
+            builder
+                .build_and_sign(vec![SignatorEnum::Ed25519(
+                    keypair.generate_signator().expect("fail to gen signator")
+                )])
+                .signatures()
+        );*/
+
         assert!(builder
             .build_with_signature(vec![sig])
             .verify_signatures()
             .is_ok());
 
         assert!(builder
-            .build_and_sign(vec![prikey])
+            .build_and_sign(vec![signator])
             .verify_signatures()
             .is_ok());
     }
diff --git a/lib/dubp/user-docs/src/documents/transaction.rs b/lib/dubp/user-docs/src/documents/transaction.rs
index 8a172294..38bf5a7e 100644
--- a/lib/dubp/user-docs/src/documents/transaction.rs
+++ b/lib/dubp/user-docs/src/documents/transaction.rs
@@ -851,13 +851,13 @@ impl<'a> TransactionDocumentBuilder<'a> {
 
 impl<'a> DocumentBuilder for TransactionDocumentBuilder<'a> {
     type Document = TransactionDocument;
-    type PrivateKey = PrivKey;
+    type Signator = SignatorEnum;
 
     fn build_with_signature(&self, signatures: Vec<Sig>) -> TransactionDocument {
         self.build_with_text_and_sigs(self.generate_text(), signatures)
     }
 
-    fn build_and_sign(&self, private_keys: Vec<PrivKey>) -> TransactionDocument {
+    fn build_and_sign(&self, private_keys: Vec<SignatorEnum>) -> TransactionDocument {
         let (text, signatures) = self.build_signed_text(private_keys);
         self.build_with_text_and_sigs(text, signatures)
     }
@@ -951,21 +951,15 @@ mod tests {
 
     #[test]
     fn generate_real_document() {
-        let pubkey = PubKey::Ed25519(
-            ed25519::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
-                .unwrap(),
-        );
-
-        let prikey = PrivKey::Ed25519(
-            ed25519::PrivateKey::from_base58(
-                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5G\
-                 iERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
-            )
-            .unwrap(),
+        let keypair = ed25519::KeyPairFromSeedGenerator::generate(
+            &Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(),
         );
+        let pubkey = PubKey::Ed25519(keypair.public_key());
+        let signator =
+            SignatorEnum::Ed25519(keypair.generate_signator().expect("fail to gen signator"));
 
         let sig = Sig::Ed25519(ed25519::Signature::from_base64(
-            "pRQeKlzCsvPNmYAAkEP5jPPQO1RwrtFMRfCajEfkkrG0UQE0DhoTkxG3Zs2JFmvAFLw67pn1V5NQ08zsSfJkBg==",
+            "cq86RugQlqAEyS8zFkB9o0PlWPSb+a6D/MEnLe8j+okyFYf/WzI6pFiBkQ9PSOVn5I0dwzVXg7Q4N1apMWeGAg==",
         ).unwrap());
 
         let block = Blockstamp::from_string(
@@ -998,16 +992,20 @@ mod tests {
             comment: "test",
             hash: None,
         };
-        println!(
-            "Signature = {:?}",
-            builder.build_and_sign(vec![prikey]).signatures()
-        );
+        /*println!(
+            "Signatures = {:?}",
+            builder
+                .build_and_sign(vec![SignatorEnum::Ed25519(
+                    keypair.generate_signator().expect("fail to gen signator")
+                )])
+                .signatures()
+        );*/
         assert!(builder
             .build_with_signature(vec![sig])
             .verify_signatures()
             .is_ok());
         assert!(builder
-            .build_and_sign(vec![prikey])
+            .build_and_sign(vec![signator])
             .verify_signatures()
             .is_ok());
     }
diff --git a/lib/dunp/network-documents/src/lib.rs b/lib/dunp/network-documents/src/lib.rs
index 074deb93..573c1acf 100644
--- a/lib/dunp/network-documents/src/lib.rs
+++ b/lib/dunp/network-documents/src/lib.rs
@@ -159,11 +159,11 @@ mod tests {
     use super::network_endpoint::*;
     use super::*;
 
-    pub fn keypair1() -> ed25519::KeyPair {
-        let seed = [
+    pub fn keypair1() -> ed25519::Ed25519KeyPair {
+        let seed = Seed::new([
             61u8, 245, 136, 162, 155, 50, 205, 43, 116, 15, 45, 84, 138, 54, 114, 214, 71, 213, 11,
             251, 135, 182, 202, 131, 48, 91, 166, 226, 40, 255, 251, 172,
-        ];
+        ]);
         ed25519::KeyPairFromSeedGenerator::generate(&seed)
     }
 
diff --git a/lib/dunp/network-documents/src/network_head_v3.rs b/lib/dunp/network-documents/src/network_head_v3.rs
index 1dc80cc8..1dddb956 100644
--- a/lib/dunp/network-documents/src/network_head_v3.rs
+++ b/lib/dunp/network-documents/src/network_head_v3.rs
@@ -233,6 +233,8 @@ mod tests {
     #[test]
     fn head_v3_sign_and_verify() {
         let keypair = keypair1();
+        let signator =
+            SignatorEnum::Ed25519(keypair.generate_signator().expect("Fail to gen signator"));
         let mut head_v3 = NetworkHeadV3 {
             currency_name: CurrencyName("g1".to_owned()),
             api_outgoing_conf: 0u8,
@@ -251,7 +253,7 @@ mod tests {
             step: 0,
         };
         // Sign
-        let sign_result = head_v3.sign(PrivKey::Ed25519(keypair.private_key()));
+        let sign_result = head_v3.sign(&signator);
         if let Ok(head_v3_raw) = sign_result {
             println!("{}", head_v3_raw);
             assert_eq!(
diff --git a/lib/dunp/network-documents/src/network_peer.rs b/lib/dunp/network-documents/src/network_peer.rs
index 6b9d63f6..f4fd7dea 100644
--- a/lib/dunp/network-documents/src/network_peer.rs
+++ b/lib/dunp/network-documents/src/network_peer.rs
@@ -316,6 +316,8 @@ mod tests {
     #[test]
     fn peer_card_v11_sign_and_verify() {
         let keypair1 = keypair1();
+        let signator =
+            SignatorEnum::Ed25519(keypair1.generate_signator().expect("Fail to gen signator"));
         let mut peer_card_v11 = PeerCardV11 {
             currency_name: CurrencyName(String::from("g1")),
             issuer: PubKey::Ed25519(keypair1.public_key()),
@@ -326,7 +328,7 @@ mod tests {
             sig: None,
         };
         // Sign
-        let sign_result = peer_card_v11.sign(PrivKey::Ed25519(keypair1.private_key()));
+        let sign_result = peer_card_v11.sign(&signator);
         if let Ok(peer_card_v11_raw) = sign_result {
             println!("{}", peer_card_v11_raw);
             assert_eq!(
diff --git a/lib/modules/ws2p-v1-legacy/Cargo.toml b/lib/modules/ws2p-v1-legacy/Cargo.toml
index 042c5664..0a54e936 100644
--- a/lib/modules/ws2p-v1-legacy/Cargo.toml
+++ b/lib/modules/ws2p-v1-legacy/Cargo.toml
@@ -11,7 +11,6 @@ path = "src/lib.rs"
 
 [dependencies]
 bincode = "1.0.1"
-byteorder = "1.2.3"
 dubp-block-doc = { path = "../../dubp/block-doc"} #, version = "0.1.0" }
 dubp-common-doc = { path = "../../dubp/common-doc"} #, version = "0.1.0" }
 dubp-currency-params = { path = "../../dubp/currency-params" }
@@ -27,7 +26,6 @@ durs-wot = { path = "../../dubp/wot" }
 failure = "0.1.5"
 log = "0.4.*"
 maplit = "1.0.1"
-ring = "0.16.5"
 serde = { version = "1.0.*", features = ["derive"] }
 serde_json = "1.0.*"
 structopt= "0.2.*"
diff --git a/lib/modules/ws2p-v1-legacy/src/events/received.rs b/lib/modules/ws2p-v1-legacy/src/events/received.rs
index 377f1150..4f67ecfa 100644
--- a/lib/modules/ws2p-v1-legacy/src/events/received.rs
+++ b/lib/modules/ws2p-v1-legacy/src/events/received.rs
@@ -36,7 +36,7 @@ pub fn receive_event(
                     ws2p_module.current_blockstamp
                 );
                 ws2p_module.my_head = Some(heads::generate_my_head(
-                    &ws2p_module.key_pair,
+                    &ws2p_module.my_signator,
                     ws2p_module.node_id,
                     ws2p_module.soft_name,
                     ws2p_module.soft_version,
diff --git a/lib/modules/ws2p-v1-legacy/src/heads.rs b/lib/modules/ws2p-v1-legacy/src/heads.rs
index 40b17925..50726fe8 100644
--- a/lib/modules/ws2p-v1-legacy/src/heads.rs
+++ b/lib/modules/ws2p-v1-legacy/src/heads.rs
@@ -18,7 +18,7 @@ use dubp_common_doc::Blockstamp;
 use durs_network_documents::network_head_v2::*;
 
 pub fn generate_my_head(
-    network_keypair: &KeyPairEnum,
+    network_signator: &SignatorEnum,
     node_id: NodeId,
     soft_name: &str,
     soft_version: &str,
@@ -28,7 +28,7 @@ pub fn generate_my_head(
     let message = NetworkHeadMessage::V2(NetworkHeadMessageV2 {
         api: String::from("WS2POCA"),
         version: 1,
-        pubkey: network_keypair.public_key(),
+        pubkey: network_signator.public_key(),
         blockstamp: *my_current_blockstamp,
         node_uuid: node_id,
         software: String::from(soft_name),
@@ -40,7 +40,7 @@ pub fn generate_my_head(
     let message_v2 = NetworkHeadMessage::V2(NetworkHeadMessageV2 {
         api: String::from("WS2POCA"),
         version: 2,
-        pubkey: network_keypair.public_key(),
+        pubkey: network_signator.public_key(),
         blockstamp: *my_current_blockstamp,
         node_uuid: node_id,
         software: String::from(soft_name),
@@ -51,13 +51,9 @@ pub fn generate_my_head(
     });
     NetworkHead::V2(Box::new(NetworkHeadV2 {
         message: message.clone(),
-        sig: network_keypair
-            .private_key()
-            .sign(message.to_string().as_bytes()),
+        sig: network_signator.sign(message.to_string().as_bytes()),
         message_v2: message_v2.clone(),
-        sig_v2: network_keypair
-            .private_key()
-            .sign(message_v2.to_string().as_bytes()),
+        sig_v2: network_signator.sign(message_v2.to_string().as_bytes()),
         step: 0,
         uid: my_uid,
     }))
diff --git a/lib/modules/ws2p-v1-legacy/src/lib.rs b/lib/modules/ws2p-v1-legacy/src/lib.rs
index 382fdb53..2463631b 100644
--- a/lib/modules/ws2p-v1-legacy/src/lib.rs
+++ b/lib/modules/ws2p-v1-legacy/src/lib.rs
@@ -250,6 +250,7 @@ pub struct WS2Pv1Module {
         mpsc::Receiver<WS2PThreadSignal>,
     ),
     pub my_head: Option<NetworkHead>,
+    pub my_signator: SignatorEnum,
     pub next_receiver: usize,
     pub node_id: NodeId,
     pub pending_received_requests: HashMap<ModuleReqId, WS2Pv1ReqFullId>,
@@ -297,6 +298,11 @@ impl WS2Pv1Module {
             requests_awaiting_response: HashMap::new(),
             heads_cache: HashMap::new(),
             my_head: None,
+            my_signator: if let Ok(signator) = key_pair.generate_signator() {
+                signator
+            } else {
+                fatal_error!("Your key pair is corrupted, please recreate it !");
+            },
             uids_cache: HashMap::new(),
             count_dal_requests: 0,
         }
@@ -322,8 +328,8 @@ impl From<dup_crypto::bases::BaseConvertionError> for WS2PMsgParseErr {
 pub trait WS2PMessage: Sized {
     fn parse(v: &serde_json::Value, currency: String) -> Result<Self, WS2PMsgParseErr>;
     fn to_raw(&self) -> String;
-    fn sign(&self, key_pair: KeyPairEnum) -> Sig {
-        key_pair.sign(self.to_raw().as_bytes())
+    fn sign(&self, signator: &SignatorEnum) -> Sig {
+        signator.sign(self.to_raw().as_bytes())
     }
     fn verify(&self) -> bool;
     //fn parse_and_verify(v: serde_json::Value, currency: String) -> bool;
diff --git a/lib/modules/ws2p-v1-legacy/src/responses/received.rs b/lib/modules/ws2p-v1-legacy/src/responses/received.rs
index cb3df65e..8c7d3e96 100644
--- a/lib/modules/ws2p-v1-legacy/src/responses/received.rs
+++ b/lib/modules/ws2p-v1-legacy/src/responses/received.rs
@@ -33,7 +33,7 @@ pub fn receive_response(
                 ws2p_module.current_blockstamp = *current_blockstamp_;
                 if ws2p_module.my_head.is_none() {
                     ws2p_module.my_head = Some(heads::generate_my_head(
-                        &ws2p_module.key_pair,
+                        &ws2p_module.my_signator,
                         ws2p_module.node_id,
                         ws2p_module.soft_name,
                         ws2p_module.soft_version,
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs
index 1c6987be..ff7d51ba 100644
--- a/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs
@@ -21,6 +21,8 @@ use super::states::WS2PConnectionState;
 use crate::constants::*;
 use crate::*;
 use dup_crypto::keys::*;
+use durs_common_tools::fatal_error;
+use log::error;
 use std::sync::mpsc;
 #[allow(deprecated)]
 use ws::util::{Timeout, Token};
@@ -38,10 +40,10 @@ pub struct Client {
     ws: Sender,
     conductor_sender: mpsc::Sender<WS2PThreadSignal>,
     currency: String,
-    key_pair: KeyPairEnum,
     connect_message: Message,
     conn_meta_datas: WS2PConnectionMetaDatas,
     last_mess_time: SystemTime,
+    signator: SignatorEnum,
     spam_interval: bool,
     spam_counter: usize,
     timeout: Option<Timeout>,
@@ -51,7 +53,7 @@ pub fn connect_to_ws2p_endpoint(
     endpoint: &EndpointV1,
     conductor_sender: &mpsc::Sender<WS2PThreadSignal>,
     currency: &str,
-    key_pair: KeyPairEnum,
+    keypair: &KeyPairEnum,
 ) -> ws::Result<()> {
     // Get endpoint url
     let ws_url = endpoint.get_url(true, false).expect("Endpoint unreachable");
@@ -67,25 +69,34 @@ pub fn connect_to_ws2p_endpoint(
             .expect("WS2P: Fail to get ep.node_uuid() !"),
     );
 
-    // Generate connect message
-    let connect_message =
-        generate_connect_message(currency, key_pair, conn_meta_datas.challenge.clone());
-
     // Log
     info!("WS2P: Try connection to {} ...", ws_url);
 
     // Connect to websocket
-    ws::connect(ws_url, |ws| Client {
-        ws,
-        conductor_sender: conductor_sender.clone(),
-        currency: String::from(currency),
-        key_pair,
-        connect_message: connect_message.clone(),
-        conn_meta_datas: conn_meta_datas.clone(),
-        last_mess_time: SystemTime::now(),
-        spam_interval: false,
-        spam_counter: 0,
-        timeout: None,
+    ws::connect(ws_url, |ws| {
+        // Generate signator
+        let signator = if let Ok(signator) = keypair.generate_signator() {
+            signator
+        } else {
+            fatal_error!("Your key pair is corrupted, please recreate it !");
+        };
+
+        // Generate connect message
+        let connect_message =
+            generate_connect_message(currency, &signator, conn_meta_datas.challenge.clone());
+
+        Client {
+            ws,
+            conductor_sender: conductor_sender.clone(),
+            currency: String::from(currency),
+            connect_message: connect_message.clone(),
+            conn_meta_datas: conn_meta_datas.clone(),
+            last_mess_time: SystemTime::now(),
+            signator,
+            spam_interval: false,
+            spam_counter: 0,
+            timeout: None,
+        }
     })
 }
 
@@ -157,7 +168,7 @@ impl Handler for Client {
                     from: self.conn_meta_datas.node_full_id(),
                     payload: self.conn_meta_datas.parse_and_check_incoming_message(
                         &self.currency,
-                        self.key_pair,
+                        &self.signator,
                         &json_message,
                     ),
                 }));
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/messages.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/messages.rs
index 64167849..37e85c74 100644
--- a/lib/modules/ws2p-v1-legacy/src/ws_connections/messages.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/messages.rs
@@ -58,17 +58,17 @@ pub enum WS2Pv1MsgPayload {
 
 pub fn generate_connect_message(
     currency: &str,
-    key_pair: KeyPairEnum,
+    signator: &SignatorEnum,
     challenge: String,
 ) -> Message {
     // Create CONNECT Message
     let mut connect_message = WS2PConnectMessageV1 {
         currency: String::from(currency),
-        pubkey: key_pair.public_key(),
+        pubkey: signator.public_key(),
         challenge,
         signature: None,
     };
-    connect_message.signature = Some(connect_message.sign(key_pair));
+    connect_message.signature = Some(connect_message.sign(signator));
     Message::text(
         serde_json::to_string(&connect_message).expect("Fail to serialize CONNECT message !"),
     )
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/meta_datas.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/meta_datas.rs
index d88eca23..3d8d08dc 100644
--- a/lib/modules/ws2p-v1-legacy/src/ws_connections/meta_datas.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/meta_datas.rs
@@ -61,7 +61,7 @@ impl WS2PConnectionMetaDatas {
     pub fn parse_and_check_incoming_message(
         &mut self,
         currency: &str,
-        key_pair: KeyPairEnum,
+        signator: &SignatorEnum,
         msg: &serde_json::Value,
     ) -> WS2Pv1MsgPayload {
         if let Some(s) = msg.get("auth") {
@@ -78,11 +78,11 @@ impl WS2PConnectionMetaDatas {
                                     self.remote_challenge = message.challenge.clone();
                                     let mut response = WS2PAckMessageV1 {
                                         currency: currency.to_string(),
-                                        pubkey: key_pair.public_key(),
+                                        pubkey: signator.public_key(),
                                         challenge: self.remote_challenge.clone(),
                                         signature: None,
                                     };
-                                    response.signature = Some(response.sign(key_pair));
+                                    response.signature = Some(response.sign(signator));
                                     return WS2Pv1MsgPayload::ValidConnectMessage(
                                         unwrap!(serde_json::to_string(&response)),
                                         self.state,
@@ -111,11 +111,11 @@ impl WS2PConnectionMetaDatas {
                             };
                             let mut response = WS2POkMessageV1 {
                                 currency: currency.to_string(),
-                                pubkey: key_pair.public_key(),
+                                pubkey: signator.public_key(),
                                 challenge: self.challenge.to_string(),
                                 signature: None,
                             };
-                            response.signature = Some(response.sign(key_pair));
+                            response.signature = Some(response.sign(signator));
                             return WS2Pv1MsgPayload::ValidAckMessage(
                                 unwrap!(serde_json::to_string(&response)),
                                 self.state,
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/mod.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/mod.rs
index 32becf36..3be33dda 100644
--- a/lib/modules/ws2p-v1-legacy/src/ws_connections/mod.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/mod.rs
@@ -24,8 +24,8 @@ pub mod states;
 
 use crate::*;
 use dup_crypto::keys::*;
+use dup_crypto::rand;
 use durs_network_documents::network_endpoint::EndpointV1;
-use ring::rand;
 use states::WS2PConnectionState;
 use std::cmp::Ordering;
 use std::collections::HashSet;
@@ -140,7 +140,7 @@ pub fn connect_to_without_checking_quotas(
             &endpoint_copy,
             &conductor_sender_copy,
             &currency_copy.expect("WS2PError : No currency !").0,
-            key_pair_copy,
+            &key_pair_copy,
         );
     });
 }
@@ -171,23 +171,19 @@ pub fn close_connection(
 pub fn get_random_connection<S: ::std::hash::BuildHasher>(
     connections: HashSet<&NodeFullId, S>,
 ) -> NodeFullId {
-    let mut loop_count = 0;
-    let rng = rand::SystemRandom::new();
-    loop {
-        for ws2p_full_id in &connections {
-            if loop_count > 10 {
-                return **ws2p_full_id;
-            }
-            if let Ok(random_bytes) = rand::generate::<[u8; 4]>(&rng) {
-                if random_bytes.expose()[0] < 0b1000_0000 {
-                    return **ws2p_full_id;
-                }
-            } else {
-                fatal_error!("System error: fail to generate random boolean !")
-            }
+    let random_usize = rand::gen_u32() as usize;
+    let mut count = random_usize % connections.len();
+    let mut last_node_full_id = None;
+    for node_full_id in &connections {
+        if count == 0 {
+            return **node_full_id;
+        } else {
+            count -= 1;
+            last_node_full_id = Some(**node_full_id);
+            continue;
         }
-        loop_count += 1;
     }
+    last_node_full_id.expect("ws2p connections set must be not empty !")
 }
 
 pub fn count_established_connections(ws2p_module: &WS2Pv1Module) -> usize {
diff --git a/lib/modules/ws2p/ws2p-messages/lib.rs b/lib/modules/ws2p/ws2p-messages/lib.rs
index d5306564..8b5d399a 100644
--- a/lib/modules/ws2p/ws2p-messages/lib.rs
+++ b/lib/modules/ws2p/ws2p-messages/lib.rs
@@ -174,11 +174,11 @@ mod tests {
     use std::net::Ipv4Addr;
     use std::str::FromStr;
 
-    pub fn keypair1() -> ed25519::KeyPair {
-        let seed = [
+    pub fn keypair1() -> ed25519::Ed25519KeyPair {
+        let seed = Seed::new([
             228, 125, 124, 120, 57, 212, 246, 250, 139, 246, 62, 26, 56, 241, 175, 123, 151, 209,
             5, 106, 2, 148, 43, 101, 118, 160, 233, 7, 112, 222, 0, 169,
-        ];
+        ]);
         ed25519::KeyPairFromSeedGenerator::generate(&seed)
     }
 
@@ -223,6 +223,8 @@ mod tests {
 
     pub fn test_ws2p_message(payload: WS2Pv2MessagePayload) {
         let keypair1 = keypair1();
+        let signator =
+            SignatorEnum::Ed25519(keypair1.generate_signator().expect("fail to gen signator"));
         let mut ws2p_message = WS2PMessage::V2(WS2Pv2Message {
             currency_name: CurrencyName(String::from("g1")),
             issuer_node_id: NodeId(0),
@@ -232,7 +234,7 @@ mod tests {
             signature: None,
         });
 
-        let sign_result = ws2p_message.sign(PrivKey::Ed25519(keypair1.private_key()));
+        let sign_result = ws2p_message.sign(&signator);
         if let Ok(bin_msg) = sign_result {
             // Test binarization
             assert_eq!(
diff --git a/lib/modules/ws2p/ws2p-messages/v2/api_features.rs b/lib/modules/ws2p/ws2p-messages/v2/api_features.rs
index 5a704aee..e37ad4d1 100644
--- a/lib/modules/ws2p/ws2p-messages/v2/api_features.rs
+++ b/lib/modules/ws2p/ws2p-messages/v2/api_features.rs
@@ -13,13 +13,13 @@
 // 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/>.
 
-#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
 /// WS2PFeatures
-pub struct WS2PFeatures(pub Vec<u8>);
+pub struct WS2PFeatures(pub [u8; 4]);
 
 impl WS2PFeatures {
     /// Return true if all flags are disabled (or if it's really empty).
-    pub fn is_empty(&self) -> bool {
+    pub fn is_empty(self) -> bool {
         for byte in &self.0 {
             if *byte > 0u8 {
                 return false;
@@ -28,23 +28,23 @@ impl WS2PFeatures {
         true
     }
     /// Check flag DEF
-    pub fn def(&self) -> bool {
+    pub fn def(self) -> bool {
         self.0[0] | 0b1111_1110 == 255u8
     }
     /// Check flag LOW
-    pub fn low(&self) -> bool {
+    pub fn low(self) -> bool {
         self.0[0] | 0b1111_1101 == 255u8
     }
     /// Check flag ABF
-    pub fn abf(&self) -> bool {
+    pub fn abf(self) -> bool {
         self.0[0] | 0b1111_1011 == 255u8
     }
     /// Check features compatibility
     pub fn check_features_compatibility(
-        &self,
-        remote_features: &WS2PFeatures,
+        self,
+        remote_features: WS2PFeatures,
     ) -> Result<WS2PFeatures, ()> {
-        let mut merged_features = self.clone();
+        let mut merged_features = self;
         // Remove features unsuported by remote node
         if self.def() && !remote_features.def() {
             merged_features.0[0] &= 0b1111_1110;
diff --git a/lib/modules/ws2p/ws2p-messages/v2/connect.rs b/lib/modules/ws2p/ws2p-messages/v2/connect.rs
index 4f45a524..b1ac8257 100644
--- a/lib/modules/ws2p/ws2p-messages/v2/connect.rs
+++ b/lib/modules/ws2p/ws2p-messages/v2/connect.rs
@@ -129,7 +129,7 @@ impl Default for WS2Pv2ConnectMsg {
     fn default() -> Self {
         WS2Pv2ConnectMsg {
             challenge: Hash::random(),
-            api_features: WS2PFeatures(vec![]),
+            api_features: WS2PFeatures([0u8; 4]),
             flags_queries: WS2PConnectFlags(vec![]),
             peer_card: None,
             chunkstamp: None,
@@ -187,15 +187,16 @@ mod tests {
     #[test]
     fn test_ws2p_message_connect() {
         let keypair1 = keypair1();
+        let signator =
+            SignatorEnum::Ed25519(keypair1.generate_signator().expect("fail to gen signator"));
         let mut peer = create_peer_card_v11();
-        peer.sign(PrivKey::Ed25519(keypair1.private_key()))
-            .expect("Fail to sign peer card !");
+        peer.sign(&signator).expect("Fail to sign peer card !");
         let connect_msg = WS2Pv2ConnectMsg {
             challenge: Hash::from_hex(
                 "000007722B243094269E548F600BD34D73449F7578C05BD370A6D301D20B5F10",
             )
             .unwrap(),
-            api_features: WS2PFeatures(vec![7u8]),
+            api_features: WS2PFeatures([7u8, 0, 0, 0]),
             flags_queries: WS2PConnectFlags(vec![]),
             peer_card: Some(peer),
             chunkstamp: Some(
diff --git a/lib/modules/ws2p/ws2p-messages/v2/mod.rs b/lib/modules/ws2p/ws2p-messages/v2/mod.rs
index fb57861e..9aad9194 100644
--- a/lib/modules/ws2p/ws2p-messages/v2/mod.rs
+++ b/lib/modules/ws2p/ws2p-messages/v2/mod.rs
@@ -64,18 +64,18 @@ impl WS2Pv2Message {
     pub fn encapsulate_payload(
         currency_name: CurrencyName,
         issuer_node_id: NodeId,
-        issuer_keypair: KeyPairEnum,
+        issuer_signator: &SignatorEnum,
         payload: WS2Pv2MessagePayload,
     ) -> Result<(WS2PMessage, Vec<u8>), SignError> {
         let mut msg = WS2PMessage::V2(WS2Pv2Message {
             currency_name,
             issuer_node_id,
-            issuer_pubkey: issuer_keypair.public_key(),
+            issuer_pubkey: issuer_signator.public_key(),
             payload,
             message_hash: None,
             signature: None,
         });
-        match msg.sign(issuer_keypair.private_key()) {
+        match msg.sign(issuer_signator) {
             Ok(bin_msg) => Ok((msg, bin_msg)),
             Err(e) => Err(e),
         }
@@ -98,9 +98,10 @@ mod tests {
     #[test]
     fn test_ws2p_message_peers() {
         let keypair1 = keypair1();
+        let signator =
+            SignatorEnum::Ed25519(keypair1.generate_signator().expect("fail to gen signator"));
         let mut peer = create_peer_card_v11();
-        peer.sign(PrivKey::Ed25519(keypair1.private_key()))
-            .expect("Fail to sign peer card !");
+        peer.sign(&signator).expect("Fail to sign peer card !");
         test_ws2p_message(WS2Pv2MessagePayload::Peers(vec![peer]));
     }
 }
diff --git a/lib/modules/ws2p/ws2p-messages/v2/secret_flags.rs b/lib/modules/ws2p/ws2p-messages/v2/secret_flags.rs
index 514eacfe..78193a97 100644
--- a/lib/modules/ws2p/ws2p-messages/v2/secret_flags.rs
+++ b/lib/modules/ws2p/ws2p-messages/v2/secret_flags.rs
@@ -71,12 +71,14 @@ mod tests {
     #[test]
     fn test_ws2p_message_secret_flags() {
         let keypair1 = keypair1();
+        let signator =
+            SignatorEnum::Ed25519(keypair1.generate_signator().expect("fail to gen signator"));
         let challenge = Hash::random();
         let msg = WS2Pv2SecretFlagsMsg {
             secret_flags: WS2Pv2SecretFlags(vec![]),
             member_proof: Some(MemberProof {
                 pubkey: PubKey::Ed25519(keypair1.public_key()),
-                sig: Sig::Ed25519(keypair1.private_key().sign(&challenge.0)),
+                sig: signator.sign(&challenge.0),
             }),
         };
         test_ws2p_message(WS2Pv2MessagePayload::SecretFlags(msg));
diff --git a/lib/modules/ws2p/ws2p-protocol/src/controller/meta_datas.rs b/lib/modules/ws2p/ws2p-protocol/src/controller/meta_datas.rs
index 1ba32077..0164d0a6 100644
--- a/lib/modules/ws2p/ws2p-protocol/src/controller/meta_datas.rs
+++ b/lib/modules/ws2p/ws2p-protocol/src/controller/meta_datas.rs
@@ -20,13 +20,16 @@ use crate::MySelfWs2pNode;
 use dubp_common_doc::Blockstamp;
 use dubp_currency_params::CurrencyName;
 use dup_crypto::hashs::Hash;
+use dup_crypto::keys::{KeyPair, SignatorEnum};
+use durs_common_tools::fatal_error;
 use durs_network_documents::network_peer::PeerCardV11;
 use durs_network_documents::NodeFullId;
 use durs_ws2p_messages::v2::api_features::WS2PFeatures;
 use durs_ws2p_messages::v2::connect::WS2Pv2ConnectType;
+use log::error;
 use std::time::SystemTime;
 
-#[derive(Debug, Clone)]
+#[derive(Debug)]
 /// WS2p Connection meta datas
 pub struct WS2PControllerMetaDatas {
     /// Local challenge
@@ -41,6 +44,8 @@ pub struct WS2PControllerMetaDatas {
     pub creation_time: SystemTime,
     /// Connection features
     pub features: Option<WS2PFeatures>,
+    /// Signator
+    pub signator: SignatorEnum,
     /// Timestamp of last received message
     pub last_mess_time: SystemTime,
     /// Local node properties
@@ -76,6 +81,11 @@ impl WS2PControllerMetaDatas {
             local_node,
             remote_connect_type: None,
             remote_node: None,
+            signator: if let Ok(signator) = local_node.my_key_pair.generate_signator() {
+                signator
+            } else {
+                fatal_error!("Your keypair is corrupted, please recreate it !");
+            },
             spam_interval: false,
             spam_counter: 0,
             state: WS2PConnectionState::TryToOpenWS,
diff --git a/lib/modules/ws2p/ws2p-protocol/src/controller/on_message/ack_msg.rs b/lib/modules/ws2p/ws2p-protocol/src/controller/on_message/ack_msg.rs
index b7780e6d..c987782c 100644
--- a/lib/modules/ws2p/ws2p-protocol/src/controller/on_message/ack_msg.rs
+++ b/lib/modules/ws2p/ws2p-protocol/src/controller/on_message/ack_msg.rs
@@ -81,7 +81,7 @@ fn send_ok_msg<M: ModuleMessage>(
     if let Ok((_, bin_ok_msg)) = WS2Pv2Message::encapsulate_payload(
         controller.meta_datas.currency.clone(),
         controller.meta_datas.local_node.my_node_id,
-        controller.meta_datas.local_node.my_key_pair,
+        &controller.meta_datas.signator,
         WS2Pv2MessagePayload::Ok(ok_msg),
     ) {
         // Order the sending of a OK message
diff --git a/lib/modules/ws2p/ws2p-protocol/src/controller/on_message/connect_msg.rs b/lib/modules/ws2p/ws2p-protocol/src/controller/on_message/connect_msg.rs
index ca48f635..e8f7ec69 100644
--- a/lib/modules/ws2p/ws2p-protocol/src/controller/on_message/connect_msg.rs
+++ b/lib/modules/ws2p/ws2p-protocol/src/controller/on_message/connect_msg.rs
@@ -83,7 +83,7 @@ pub fn process_ws2p_v2p_connect_msg<M: ModuleMessage>(
         .meta_datas
         .local_node
         .my_features
-        .check_features_compatibility(&connect_msg.api_features)
+        .check_features_compatibility(connect_msg.api_features)
     {
         Ok(merged_features) => controller.meta_datas.features = Some(merged_features),
         Err(_) => {
@@ -95,7 +95,7 @@ pub fn process_ws2p_v2p_connect_msg<M: ModuleMessage>(
     if let Ok((_, bin_ack_msg)) = WS2Pv2Message::encapsulate_payload(
         controller.meta_datas.currency.clone(),
         controller.meta_datas.local_node.my_node_id,
-        controller.meta_datas.local_node.my_key_pair,
+        &controller.meta_datas.signator,
         WS2Pv2MessagePayload::Ack {
             challenge: remote_challenge,
         },
diff --git a/lib/modules/ws2p/ws2p-protocol/src/controller/on_open.rs b/lib/modules/ws2p/ws2p-protocol/src/controller/on_open.rs
index aa78bd89..ca8c4d21 100644
--- a/lib/modules/ws2p/ws2p-protocol/src/controller/on_open.rs
+++ b/lib/modules/ws2p/ws2p-protocol/src/controller/on_open.rs
@@ -39,7 +39,7 @@ pub fn process<M: ModuleMessage>(
     // Generate connect message
     let connect_msg = generate_connect_message(
         controller.meta_datas.connect_type,
-        controller.meta_datas.local_node.my_features.clone(),
+        controller.meta_datas.local_node.my_features,
         controller.meta_datas.challenge,
         None,
     );
@@ -48,7 +48,7 @@ pub fn process<M: ModuleMessage>(
     if let Ok((_ws2p_full_msg, bin_connect_msg)) = WS2Pv2Message::encapsulate_payload(
         controller.meta_datas.currency.clone(),
         controller.meta_datas.local_node.my_node_id,
-        controller.meta_datas.local_node.my_key_pair,
+        &controller.meta_datas.signator,
         WS2Pv2MessagePayload::Connect(Box::new(connect_msg)),
     ) {
         // Order the sending of a CONNECT message
diff --git a/lib/modules/ws2p/ws2p-protocol/src/lib.rs b/lib/modules/ws2p/ws2p-protocol/src/lib.rs
index 2f0a9399..2e79c206 100644
--- a/lib/modules/ws2p/ws2p-protocol/src/lib.rs
+++ b/lib/modules/ws2p/ws2p-protocol/src/lib.rs
@@ -39,7 +39,7 @@ use durs_network_documents::{NodeFullId, NodeId};
 use durs_ws2p_messages::v2::api_features::WS2PFeatures;
 
 /// Store self WS2P properties
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub struct MySelfWs2pNode {
     /// Local node id
     pub my_node_id: NodeId,
diff --git a/lib/modules/ws2p/ws2p/src/controllers/incoming_connections.rs b/lib/modules/ws2p/ws2p/src/controllers/incoming_connections.rs
index d3e306d1..041af740 100644
--- a/lib/modules/ws2p/ws2p/src/controllers/incoming_connections.rs
+++ b/lib/modules/ws2p/ws2p/src/controllers/incoming_connections.rs
@@ -46,7 +46,7 @@ pub fn listen_on_ws2p_v2_endpoint<A: ToSocketAddrs + Debug>(
                 Hash::random(),
                 WS2Pv2ConnectType::Incoming,
                 currency.clone(),
-                self_node.clone(),
+                *self_node,
             ),
             orchestrator_sender.clone(),
         ) {
diff --git a/lib/modules/ws2p/ws2p/src/controllers/outgoing_connections.rs b/lib/modules/ws2p/ws2p/src/controllers/outgoing_connections.rs
index dcabd55e..3c492f07 100644
--- a/lib/modules/ws2p/ws2p/src/controllers/outgoing_connections.rs
+++ b/lib/modules/ws2p/ws2p/src/controllers/outgoing_connections.rs
@@ -56,7 +56,7 @@ pub fn connect_to_ws2p_v2_endpoint(
                 Hash::random(),
                 WS2Pv2ConnectType::OutgoingServer,
                 currency.clone(),
-                self_node.clone(),
+                *self_node,
             ),
             orchestrator_sender.clone(),
         ) {
diff --git a/lib/modules/ws2p/ws2p/src/generate_peer.rs b/lib/modules/ws2p/ws2p/src/generate_peer.rs
index d013268e..9eef193c 100644
--- a/lib/modules/ws2p/ws2p/src/generate_peer.rs
+++ b/lib/modules/ws2p/ws2p/src/generate_peer.rs
@@ -19,7 +19,7 @@ use bincode;
 use dubp_common_doc::BlockNumber;
 use dubp_currency_params::CurrencyName;
 use dup_crypto::keys::text_signable::TextSignable;
-use dup_crypto::keys::{KeyPair, KeyPairEnum, SignError};
+use dup_crypto::keys::{SignError, Signator, SignatorEnum};
 use durs_common_tools::fatal_error;
 use durs_network_documents::network_endpoint::*;
 use durs_network_documents::network_peer::*;
@@ -27,7 +27,7 @@ use durs_network_documents::*;
 
 pub fn _self_peer_update_endpoints(
     self_peer: PeerCardV11,
-    issuer_keys: KeyPairEnum,
+    issuer_signator: &SignatorEnum,
     created_on: BlockNumber,
     new_endpoints: Vec<EndpointEnum>,
 ) -> Result<PeerCardV11, SignError> {
@@ -84,14 +84,14 @@ pub fn _self_peer_update_endpoints(
         ..self_peer
     };
 
-    new_self_peer.sign(issuer_keys.private_key())?;
+    new_self_peer.sign(issuer_signator)?;
 
     Ok(new_self_peer)
 }
 
 pub fn _generate_self_peer(
     currency_name: CurrencyName,
-    issuer_keys: KeyPairEnum,
+    issuer_signator: &SignatorEnum,
     node_id: NodeId,
     created_on: BlockNumber,
     endpoints: Vec<EndpointEnum>,
@@ -120,7 +120,7 @@ pub fn _generate_self_peer(
 
     let mut self_peer = PeerCardV11 {
         currency_name,
-        issuer: issuer_keys.public_key(),
+        issuer: issuer_signator.public_key(),
         node_id,
         created_on,
         endpoints: endpoints_bin,
@@ -128,7 +128,7 @@ pub fn _generate_self_peer(
         sig: None,
     };
 
-    self_peer.sign(issuer_keys.private_key())?;
+    self_peer.sign(issuer_signator)?;
 
     Ok(self_peer)
 }
diff --git a/lib/modules/ws2p/ws2p/src/services/mod.rs b/lib/modules/ws2p/ws2p/src/services/mod.rs
index cbd379be..34ac134a 100644
--- a/lib/modules/ws2p/ws2p/src/services/mod.rs
+++ b/lib/modules/ws2p/ws2p/src/services/mod.rs
@@ -29,7 +29,7 @@ pub enum WsError {
 }
 
 /// Store self WS2P properties
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub struct MySelfWs2pNode {
     /// Local node id
     pub my_node_id: NodeId,
diff --git a/lib/modules/ws2p/ws2p/tests/connection_negociation.rs b/lib/modules/ws2p/ws2p/tests/connection_negociation.rs
index 71964484..ae944334 100644
--- a/lib/modules/ws2p/ws2p/tests/connection_negociation.rs
+++ b/lib/modules/ws2p/ws2p/tests/connection_negociation.rs
@@ -39,19 +39,19 @@ pub fn currency() -> CurrencyName {
     CurrencyName(String::from("g1"))
 }
 
-pub fn keypair1() -> ed25519::KeyPair {
-    let seed = [
+pub fn keypair1() -> ed25519::Ed25519KeyPair {
+    let seed = Seed::new([
         61u8, 245, 136, 162, 155, 50, 205, 43, 116, 15, 45, 84, 138, 54, 114, 214, 71, 213, 11,
         251, 135, 182, 202, 131, 48, 91, 166, 226, 40, 255, 251, 172,
-    ];
+    ]);
     ed25519::KeyPairFromSeedGenerator::generate(&seed)
 }
 
-pub fn keypair2() -> ed25519::KeyPair {
-    let seed = [
+pub fn keypair2() -> ed25519::Ed25519KeyPair {
+    let seed = Seed::new([
         228, 125, 124, 120, 57, 212, 246, 250, 139, 246, 62, 26, 56, 241, 175, 123, 151, 209, 5,
         106, 2, 148, 43, 101, 118, 160, 233, 7, 112, 222, 0, 169,
-    ];
+    ]);
     ed25519::KeyPairFromSeedGenerator::generate(&seed)
 }
 
@@ -59,7 +59,7 @@ fn server_node() -> MySelfWs2pNode {
     MySelfWs2pNode {
         my_node_id: NodeId(0),
         my_key_pair: KeyPairEnum::Ed25519(keypair1()),
-        my_features: WS2PFeatures(vec![5u8]),
+        my_features: WS2PFeatures([5u8, 0, 0, 0]),
     }
 }
 
@@ -67,7 +67,7 @@ fn client_node() -> MySelfWs2pNode {
     MySelfWs2pNode {
         my_node_id: NodeId(1),
         my_key_pair: KeyPairEnum::Ed25519(keypair2()),
-        my_features: WS2PFeatures(vec![5u8]),
+        my_features: WS2PFeatures([5u8, 0, 0, 0]),
     }
 }
 
-- 
GitLab