diff --git a/src/crypto/base58_duniter_key.rs b/src/crypto/base58_duniter_key.rs
new file mode 100644
index 0000000000000000000000000000000000000000..63db0e3f65da4f4143c2862cf77fb36e56cb39fe
--- /dev/null
+++ b/src/crypto/base58_duniter_key.rs
@@ -0,0 +1,30 @@
+use crate::crypto::duniter_key::{ToDuniterKey, DuniterKey, PUBLIC_KEY_LEN, SECRET_KEY_LEN};
+use base64;
+use cryptoxide::ed25519;
+
+pub struct Base58DuniterKey(String, String);
+
+impl Base58DuniterKey {
+    pub fn new(public: String, secret: String) -> Self {
+        Self(public, secret)
+    }
+}
+
+impl From<Base58DuniterKey> for DuniterKey {
+    fn from(sdk: Base58DuniterKey) -> Self {
+        sdk.derive()
+    }
+}
+
+impl ToDuniterKey for Base58DuniterKey {
+
+    fn derive(&self) -> DuniterKey {
+        let public_vec = bs58::decode(&self.0).into_vec().unwrap();
+        let secret_vec = bs58::decode(&self.1).into_vec().unwrap();
+        let mut public = [0u8; PUBLIC_KEY_LEN];
+        let mut secret = [0u8; SECRET_KEY_LEN];
+        for i in 0..PUBLIC_KEY_LEN { public[i] = public_vec[i] }
+        for i in 0..SECRET_KEY_LEN { secret[i] = secret_vec[i] }
+        DuniterKey { public, secret }
+    }
+}
\ No newline at end of file
diff --git a/src/crypto/duniter_key.rs b/src/crypto/duniter_key.rs
index eba309304a728862a91f98261a00a7eb36d2908a..4a3068166aee48677dc802e0f0896f37c138a5ae 100644
--- a/src/crypto/duniter_key.rs
+++ b/src/crypto/duniter_key.rs
@@ -1,4 +1,3 @@
-use std::error::Error;
 use std::fmt::Formatter;
 
 use bs58;
@@ -7,12 +6,11 @@ use scrypt::{Params, Scrypt};
 use scrypt::password_hash::{Output, PasswordHasher, SaltString};
 
 use crate::crypto::duniter_signature::DuniterSignature;
+pub use crate::crypto::scrypt_duniter_key::ScryptDuniterKey;
+pub use crate::crypto::seed_duniter_key::SeedDuniterKey;
 
-const PUBLIC_KEY_LEN: usize = 32;
-const SECRET_KEY_LEN: usize = 64;
-const SCRYPT_N: u8 = 12;
-const SCRYPT_R: u32 = 16;
-const SCRYPT_P: u32 = 1;
+pub const PUBLIC_KEY_LEN: usize = 32;
+pub const SECRET_KEY_LEN: usize = 64;
 
 /// The main functional class for handle Duniter crypto.
 pub struct DuniterKey {
@@ -20,6 +18,10 @@ pub struct DuniterKey {
     pub secret: [u8; SECRET_KEY_LEN],
 }
 
+pub trait ToDuniterKey {
+    fn derive(&self) -> DuniterKey;
+}
+
 /// How to display a duniter keyring: "pub_base58:sec_base58" format.
 impl std::fmt::Display for DuniterKey {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@@ -29,22 +31,6 @@ impl std::fmt::Display for DuniterKey {
 
 impl DuniterKey {
 
-    pub fn from_scrypt(salt: &str, passwd: &str) -> Result<DuniterKey, Box<dyn Error>> {
-        let seed = derive_seed(salt, passwd)?;
-        let (secret, public) = ed25519::keypair(seed.as_bytes());
-        Ok(DuniterKey { public, secret })
-    }
-
-    pub fn from_base58(public: &str, secret: &str) -> Result<DuniterKey, Box<dyn Error>> {
-        let public_vec = bs58::decode(public).into_vec().unwrap();
-        let secret_vec = bs58::decode(secret).into_vec().unwrap();
-        let mut public = [0u8; PUBLIC_KEY_LEN];
-        let mut secret = [0u8; SECRET_KEY_LEN];
-        for i in 0..PUBLIC_KEY_LEN { public[i] = public_vec[i] }
-        for i in 0..SECRET_KEY_LEN { secret[i] = secret_vec[i] }
-        Ok(DuniterKey { public, secret })
-    }
-
     pub fn sign(&self, message: &str) -> DuniterSignature {
         DuniterSignature::new(ed25519::signature(message.as_bytes(), &self.secret[..]))
     }
@@ -52,12 +38,4 @@ impl DuniterKey {
     pub fn verify(&self, message: &str, signature: &DuniterSignature) -> bool {
         ed25519::verify(message.as_bytes(), &self.public, &signature.as_bytes())
     }
-}
-
-fn derive_seed(salt: &str, passwd: &str) -> Result<Output, Box<dyn Error>> {
-    let saltb64 = base64::encode(salt); // convert utf8 to base64
-    let salt = SaltString::new(saltb64.as_str())?; // expectes base64-encoded str
-    let params = Params::new(SCRYPT_N, SCRYPT_R, SCRYPT_P)?;
-    let password_hash = Scrypt.hash_password(passwd.as_bytes(), None, params, &salt)?;
-    Ok(password_hash.hash.expect("Seed should have been generated"))
 }
\ No newline at end of file
diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs
index e838147252916b52ea0d1d65b9b31b871cd853a1..e069d159f299fb13c590a65ec991ec5aeb2e8e7c 100644
--- a/src/crypto/mod.rs
+++ b/src/crypto/mod.rs
@@ -2,3 +2,6 @@ mod duniter_signature;
 
 /// The API of crypto module.
 pub mod duniter_key;
+pub mod scrypt_duniter_key;
+pub mod seed_duniter_key;
+pub mod base58_duniter_key;
diff --git a/src/crypto/scrypt_duniter_key.rs b/src/crypto/scrypt_duniter_key.rs
new file mode 100644
index 0000000000000000000000000000000000000000..bff1e78d5f00d17590e452ed9159e24c2b54ee43
--- /dev/null
+++ b/src/crypto/scrypt_duniter_key.rs
@@ -0,0 +1,42 @@
+use crate::crypto::duniter_key::{ToDuniterKey, DuniterKey};
+use base64;
+use cryptoxide::ed25519;
+use std::error::Error;
+use scrypt::password_hash::{Output, SaltString, PasswordHasher};
+use scrypt::{Params, Scrypt};
+
+const SCRYPT_N: u8 = 12;
+const SCRYPT_R: u32 = 16;
+const SCRYPT_P: u32 = 1;
+
+pub struct ScryptDuniterKey((String, String));
+
+impl ScryptDuniterKey {
+    pub fn new(salt: String, passwd: String) -> Self {
+        Self((salt, passwd))
+    }
+}
+
+impl From<ScryptDuniterKey> for DuniterKey {
+    fn from(sdk: ScryptDuniterKey) -> Self {
+        sdk.derive()
+    }
+}
+
+impl ToDuniterKey for ScryptDuniterKey {
+
+    fn derive(&self) -> DuniterKey {
+        let (salt, passwd) = &self.0;
+        let seed = derive_seed(salt.as_str(), passwd.as_str()).expect("Could not derive seed from salt/password.");
+        let (secret, public) = ed25519::keypair(seed.as_bytes());
+        DuniterKey { public, secret }
+    }
+}
+
+fn derive_seed(salt: &str, passwd: &str) -> Result<Output, Box<dyn Error>> {
+    let saltb64 = base64::encode(salt); // convert utf8 to base64
+    let salt = SaltString::new(saltb64.as_str())?; // expectes base64-encoded str
+    let params = Params::new(SCRYPT_N, SCRYPT_R, SCRYPT_P)?;
+    let password_hash = Scrypt.hash_password(passwd.as_bytes(), None, params, &salt)?;
+    Ok(password_hash.hash.expect("Seed should have been generated"))
+}
\ No newline at end of file
diff --git a/src/crypto/seed_duniter_key.rs b/src/crypto/seed_duniter_key.rs
new file mode 100644
index 0000000000000000000000000000000000000000..81dfb3c3a1991270ee025c4251df39742dbc58f2
--- /dev/null
+++ b/src/crypto/seed_duniter_key.rs
@@ -0,0 +1,31 @@
+use crate::crypto::duniter_key::{ToDuniterKey, DuniterKey};
+use base64;
+use cryptoxide::ed25519;
+
+const SEED_LEN: usize = 32;
+
+pub struct SeedDuniterKey(String);
+
+impl SeedDuniterKey {
+    pub fn new(seed: String) -> Self {
+        Self(seed)
+    }
+}
+
+impl From<SeedDuniterKey> for DuniterKey {
+    fn from(sdk: SeedDuniterKey) -> Self {
+        sdk.derive()
+    }
+}
+
+impl ToDuniterKey for SeedDuniterKey {
+
+    fn derive(&self) -> DuniterKey {
+        let seed = &self.0;
+        let seed_vec = base64::decode(seed).unwrap();
+        let mut seed = [0u8; SEED_LEN];
+        for i in 0..SEED_LEN { seed[i] = seed_vec[i] }
+        let (secret, public) = ed25519::keypair(&seed);
+        DuniterKey { public, secret }
+    }
+}
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 85f9fdbf919000a5cd94224ba4d1df7ed82976c2..c1068db3b1d4e6bf640718f82a87f804699cdc8a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,61 +1,65 @@
-mod crypto;
+pub mod crypto;
 
-use crate::crypto::duniter_key::DuniterKey;
+use crate::crypto::duniter_key::{DuniterKey, ToDuniterKey};
+use crate::crypto::scrypt_duniter_key::ScryptDuniterKey;
 
-pub fn compute_pub(salt: &str, passwd: &str) -> String {
-    let key = DuniterKey::from_scrypt(salt, passwd).expect("Error generating key from scrypt");
-    String::from(format!("{}", key).split(":").next().unwrap())
+pub fn compute_pub(sdk: impl ToDuniterKey) -> String {
+    String::from(sdk.derive().to_string().split(":").next().unwrap())
 }
 
-pub fn compute_sec(salt: &str, passwd: &str) -> String {
-    let key = DuniterKey::from_scrypt(salt, passwd).expect("Error generating key from scrypt");
-    let key_str = key.to_string();
+pub fn compute_sec(sdk: impl ToDuniterKey) -> String {
+    let key_str = sdk.derive().to_string();
     let mut split = key_str.split(":");
     split.next();
     String::from(split.next().unwrap())
 }
 
-pub fn compute_key(salt: &str, passwd: &str) -> String {
-    let key = DuniterKey::from_scrypt(salt, passwd).expect("Error generating key from scrypt");
-    format!("{}", key)
+pub fn compute_key(sdk: impl ToDuniterKey) -> String {
+    format!("{}", sdk.derive())
 }
 
 #[cfg(test)]
 mod tests {
 
     use crate::*;
+    use crate::crypto::duniter_key::SeedDuniterKey;
+    use crate::crypto::base58_duniter_key::Base58DuniterKey;
 
     const SALT: &str = "test_salt";
     const PASSWD: &str = "test_passwd";
     const PUBKEY: &str = "953SE7QJoDC2vFFwkSDojGKjUFU6BCu1kH6s4MnoyQCw";
     const SECKEY: &str = "s3G7v2FPuTSWh8f9BSrU8EurwcM214x4fMLWFDLYmH7doqfyCqM96Ai5q4xB8y4GBKTCUvHoR3Et8AJKf7XTTZR";
+    const SEED: &str = "KybWwsHnqJrs+1F10GfuK08pOyvqpb2Jn1yNO58S0l0=";
 
     #[test]
     fn should_compute_pub() {
-        assert_eq!(compute_pub(SALT, PASSWD), PUBKEY);
+        assert_eq!(compute_pub(SeedDuniterKey::new(String::from(SEED))), PUBKEY);
     }
 
     #[test]
     fn should_compute_sec() {
-        assert_eq!(compute_sec(SALT, PASSWD), SECKEY);
+        assert_eq!(compute_sec(SeedDuniterKey::new(String::from(SEED))), SECKEY);
     }
 
     #[test]
     fn should_compute_keyring() {
-        assert_eq!(compute_key(SALT, PASSWD), format!("{}:{}", PUBKEY, SECKEY));
+        assert_eq!(compute_key(SeedDuniterKey::new(String::from(SEED))), format!("{}:{}", PUBKEY, SECKEY));
     }
 
     #[test]
-    fn base58_or_scrypt_is_the_same() {
-        let scrypt_key = DuniterKey::from_scrypt(SALT, PASSWD).expect("Error generating key from scrypt");
-        let bs58_key = DuniterKey::from_base58(PUBKEY, SECKEY).expect("Wrong public/secret key");
+    fn all_derivations_leads_to_the_same() {
+        let scrypt_key = ScryptDuniterKey::new(String::from(SALT), String::from(PASSWD)).derive();
+        let bs58_key = Base58DuniterKey::new(String::from(PUBKEY), String::from(SECKEY)).derive();
+        let seed_key = SeedDuniterKey::new(String::from(SEED)).derive();
         assert_eq!(bs58_key.public, scrypt_key.public);
         assert_eq!(bs58_key.secret, scrypt_key.secret);
+        assert_eq!(seed_key.public, scrypt_key.public);
+        assert_eq!(seed_key.secret, scrypt_key.secret);
     }
 
     #[test]
     fn should_verify_or_reject_sig() {
-        let bs58_key = DuniterKey::from_base58(PUBKEY, SECKEY).expect("Wrong public/secret key");
+        let bs58_key = Base58DuniterKey::new(String::from(PUBKEY), String::from(SECKEY)).derive();
         let key = bs58_key;
         let signature = key.sign("GOOD MESSAGE");
         assert_eq!(true, key.verify("GOOD MESSAGE", &signature));
diff --git a/src/main.rs b/src/main.rs
index 368af760ffd9e434d676e3c1d5e581c40ee011ba..a38f1226d7198681d009baf97a9c357d786bd02c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,16 +5,18 @@ use duniter_mini_client::{compute_pub, compute_sec, compute_key};
 use crate::cli::Command;
 pub use crate::cli::Command::{PUB, UNKNOWN};
 use crate::cli::Command::{SEC, KEYRING};
+use duniter_mini_client::crypto::duniter_key::ScryptDuniterKey;
 
 mod cli;
+mod crypto;
 
 fn main() {
     let command = Command::from(env::args());
 
     match command {
-        PUB(salt, passwd) => println!("{}", compute_pub(salt.as_str(), passwd.as_str())),
-        SEC(salt, passwd) => println!("{}", compute_sec(salt.as_str(), passwd.as_str())),
-        KEYRING(salt, passwd) => println!("{}", compute_key(salt.as_str(), passwd.as_str())),
+        PUB(salt, passwd) => println!("{}", compute_pub(ScryptDuniterKey::new(salt, passwd))),
+        SEC(salt, passwd) => println!("{}", compute_sec(ScryptDuniterKey::new(salt, passwd))),
+        KEYRING(salt, passwd) => println!("{}", compute_key(ScryptDuniterKey::new(salt, passwd))),
         UNKNOWN(cmd) => eprintln!("Unknown command {}", cmd),
     };
 }
\ No newline at end of file