Skip to content
Snippets Groups Projects
Select Git revision
  • 31a2502316872b07091cc4e3d6eed08c2f589933
  • master default protected
  • ci-embed-raw-specs
  • network/gtest-1000 protected
  • upgradable-multisig
  • runtime/gtest-1000
  • network/gdev-800 protected
  • cgeek/issue-297-cpu
  • gdev-800-tests
  • update-docker-compose-rpc-squid-names
  • fix-252
  • 1000i100-test
  • hugo/tmp-0.9.1
  • network/gdev-803 protected
  • hugo/endpoint-gossip
  • network/gdev-802 protected
  • hugo/distance-precompute
  • network/gdev-900 protected
  • tuxmain/anonymous-tx
  • debug/podman
  • hugo/195-doc
  • gtest-1000-0.11.0 protected
  • gtest-1000 protected
  • gdev-900-0.10.1 protected
  • gdev-900-0.10.0 protected
  • gdev-900-0.9.2 protected
  • gdev-800-0.8.0 protected
  • gdev-900-0.9.1 protected
  • gdev-900-0.9.0 protected
  • gdev-803 protected
  • gdev-802 protected
  • runtime-801 protected
  • gdev-800 protected
  • runtime-800-bis protected
  • runtime-800 protected
  • runtime-800-backup protected
  • runtime-701 protected
  • runtime-700 protected
  • runtime-600 protected
  • runtime-500 protected
  • v0.4.1 protected
41 results

weights-benchmarking.md

Blame
  • ed25519.rs 14.07 KiB
    //  Copyright (C) 2017  The Duniter Project Developers.
    //
    // This program is free software: you can redistribute it and/or modify
    // it under the terms of the GNU Affero General Public License as
    // published by the Free Software Foundation, either version 3 of the
    // License, or (at your option) any later version.
    //
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU Affero General Public License for more details.
    //
    // You should have received a copy of the GNU Affero General Public License
    // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    
    //! Provide wrappers around ed25519 keys and signatures
    //!
    //! Key pairs can be generated with [`KeyPairGenerator`].
    //!
    //! [`KeyPairGenerator`]: struct.KeyPairGenerator.html
    
    use std::fmt::Display;
    use std::fmt::Error;
    use std::fmt::Formatter;
    use std::fmt::Debug;
    
    use base58::{FromBase58, FromBase58Error, ToBase58};
    use base64;
    use base64::DecodeError;
    use crypto;
    
    use super::BaseConvertionError;
    
    /// Store a ed25519 signature.
    #[derive(Clone, Copy)]
    pub struct Signature(pub [u8; 64]);
    
    impl super::Signature for Signature {
        fn from_base64(base64_data: &str) -> Result<Signature, BaseConvertionError> {
            match base64::decode(base64_data) {
                Ok(result) => {
                    if result.len() == 64 {
                        let mut u8_array = [0; 64];
    
                        u8_array[..64].clone_from_slice(&result[..64]);
    
                        Ok(Signature(u8_array))
                    } else {
                        Err(BaseConvertionError::InvalidKeyLendth(result.len(), 64))
                    }
                }
                Err(DecodeError::InvalidByte(pos, byte)) => {
                    Err(BaseConvertionError::InvalidCharacter(byte as char, pos))
                }
                Err(DecodeError::InvalidLength) => {
                    Err(BaseConvertionError::InvalidBaseConverterLength())
                }
            }
        }
    
        fn to_base64(&self) -> String {
            base64::encode(&self.0[..]) // need to take a slice for required trait `AsRef<[u8]>`
        }
    }
    
    impl Display for Signature {
        fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
            use super::Signature;
    
            write!(f, "{}", self.to_base64())
        }
    }
    
    impl Debug for Signature {
        // Signature { 1eubHHb... }
        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
            write!(f, "Signature {{ {} }}", self)
        }
    }
    
    impl PartialEq<Signature> for Signature {
        fn eq(&self, other: &Signature) -> 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]
        }
    }
    
    impl Eq for Signature {}
    
    /// Store a Ed25519 public key.
    ///
    /// Can be generated with [`KeyPairGenerator`].
    ///
    /// [`KeyPairGenerator`]: struct.KeyPairGenerator.html
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct PublicKey(pub [u8; 32]);
    
    impl ToBase58 for PublicKey {
        fn to_base58(&self) -> String {
            self.0.to_base58()
        }
    }
    
    impl Display for PublicKey {
        fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
            write!(f, "{}", self.to_base58())
        }
    }
    
    impl Debug for PublicKey {
        // PublicKey { DNann1L... }
        fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
            write!(f, "PublicKey {{ {} }}", self)
        }
    }
    
    impl super::PublicKey for PublicKey {
        type Signature = Signature;
    
        fn from_base58(base58_data: &str) -> Result<Self, BaseConvertionError> {
            match base58_data.from_base58() {
                Ok(result) => {
                    if result.len() == 32 {
                        let mut u8_array = [0; 32];
    
                        u8_array[..32].clone_from_slice(&result[..32]);
    
                        Ok(PublicKey(u8_array))
                    } else {
                        Err(BaseConvertionError::InvalidKeyLendth(result.len(), 32))
                    }
                }
                Err(FromBase58Error::InvalidBase58Character(character, pos)) => {
                    Err(BaseConvertionError::InvalidCharacter(character, pos))
                }
                Err(FromBase58Error::InvalidBase58Length) => {
                    Err(BaseConvertionError::InvalidBaseConverterLength())
                }
            }
        }
    
        fn verify(&self, message: &[u8], signature: &Self::Signature) -> bool {
            crypto::ed25519::verify(message, &self.0, &signature.0)
        }
    }
    
    /// 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<(), Error> {
            write!(f, "{}", self.to_base58())
        }
    }
    
    impl Debug for PrivateKey {
        // PrivateKey { 468Q1XtT... }
        fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
            write!(f, "PrivateKey {{ {} }}", self)
        }
    }
    
    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]
        }
    }
    
    impl Eq for PrivateKey {}
    
    impl super::PrivateKey for PrivateKey {
        type Signature = Signature;
    
        fn from_base58(base58_data: &str) -> Result<Self, BaseConvertionError> {
            match base58_data.from_base58() {
                Ok(result) => {
                    if result.len() == 64 {
                        let mut u8_array = [0; 64];
    
                        u8_array[..64].clone_from_slice(&result[..64]);
    
                        Ok(PrivateKey(u8_array))
                    } else {
                        Err(BaseConvertionError::InvalidKeyLendth(result.len(), 64))
                    }
                }
                Err(FromBase58Error::InvalidBase58Character(character, pos)) => {
                    Err(BaseConvertionError::InvalidCharacter(character, pos))
                }
                Err(FromBase58Error::InvalidBase58Length) => {
                    Err(BaseConvertionError::InvalidBaseConverterLength())
                }
            }
        }
    
        /// Sign a message with this private key.
        fn sign(&self, message: &[u8]) -> Self::Signature {
            Signature(crypto::ed25519::signature(message, &self.0))
        }
    }
    
    /// Store a ed25519 cryptographic key pair (`PublicKey` + `PrivateKey`)
    #[derive(Debug, Copy, Clone)]
    pub struct KeyPair {
        /// Store a Ed25519 public key.
        pub pubkey:PublicKey,
        /// Store a Ed25519 private key.
        privkey:PrivateKey,
    }
    
    impl Display for KeyPair {
        fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
            write!(f, "{}", 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 Eq for KeyPair {}
    
    impl super::KeyPair for KeyPair {
        type Signature = Signature;
    
        fn new(password: &[u8], salt: &[u8]) -> KeyPair {
            let generator = self::KeyPairGenerator::with_default_parameters();
            let (privkey, pubkey) = generator.generate(password, salt);
            KeyPair {
                pubkey,
                privkey
            }
        }
        fn sign(&self, message: &[u8]) -> Signature {
            Signature(crypto::ed25519::signature(message, &self.privkey.0))
        }
    }
    
    /// Keypair generator with given parameters for `scrypt` keypair function.
    #[derive(Debug, Copy, Clone)]
    pub struct KeyPairGenerator {
        /// The log2 of the Scrypt parameter `N`.
        log_n: u8,
        /// The Scrypt parameter `r`
        r: u32,
        /// The Scrypt parameter `p`
        p: u32,
    }
    
    impl KeyPairGenerator {
        /// Create a `KeyPairGenerator` with default arguments `(log_n: 12, r: 16, p: 1)`
        pub fn with_default_parameters() -> KeyPairGenerator {
            KeyPairGenerator {
                log_n: 12,
                r: 16,
                p: 1,
            }
        }
    
        /// Create a `KeyPairGenerator` with given arguments.
        ///
        /// # Arguments
        ///
        /// - log_n - The log2 of the Scrypt parameter N
        /// - r - The Scrypt parameter r
        /// - p - The Scrypt parameter p
        pub fn with_parameters(log_n: u8, r: u32, p: u32) -> KeyPairGenerator {
            KeyPairGenerator { log_n, r, p }
        }
    
        /// 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]) -> (PrivateKey, PublicKey) {
            let mut seed = [0u8; 32];
            crypto::scrypt::scrypt(
                password,
                salt,
                &crypto::scrypt::ScryptParams::new(self.log_n, self.r, self.p),
                &mut seed,
            );
    
            let (private, public) = crypto::ed25519::keypair(&seed);
            (PrivateKey(private), PublicKey(public))
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
        use {PrivateKey, PublicKey, Signature, KeyPair};
    
        #[test]
        fn base58_private_key() {
            let private58 =
                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9r\
                 qnXuW3iAfZACm7";
            let private_key = super::PrivateKey::from_base58(private58).unwrap();
            let private_raw = private58.from_base58().unwrap();
    
            for (key, raw) in private_key.0.iter().zip(private_raw.iter()) {
                assert_eq!(key, raw);
            }
    
            assert_eq!(private_key.to_base58(), private58);
            assert_eq!(
                private_key,
                super::PrivateKey::from_base58(private58).unwrap()
            );
    
            assert_eq!(
                super::PrivateKey::from_base58(
                    "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iA\
                    fZACm7djh",
                ).unwrap_err(),
                BaseConvertionError::InvalidKeyLendth(67, 64)
            );
            assert_eq!(
                super::PrivateKey::from_base58(
                    "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9",
                ).unwrap_err(),
                BaseConvertionError::InvalidKeyLendth(53, 64)
            );
            assert_eq!(
                super::PrivateKey::from_base58(
                    "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9<<",
                ).unwrap_err(),
                BaseConvertionError::InvalidCharacter('<', 73)
            );
        }
    
        #[test]
        fn base58_public_key() {
            let public58 = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV";
            let public_key = super::PublicKey::from_base58(public58).unwrap();
            let public_raw = public58.from_base58().unwrap();
    
            for (key, raw) in public_key.0.iter().zip(public_raw.iter()) {
                assert_eq!(key, raw);
            }
    
            assert_eq!(public_key.to_base58(), public58);
            assert_eq!(public_key, super::PublicKey::from_base58(public58).unwrap());
    
            assert_eq!(
                super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLVdjq")
                    .unwrap_err(),
                BaseConvertionError::InvalidKeyLendth(35, 32)
            );
            assert_eq!(
                super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd")
                    .unwrap_err(),
                BaseConvertionError::InvalidKeyLendth(31, 32)
            );
            assert_eq!(
                super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<")
                    .unwrap_err(),
                BaseConvertionError::InvalidCharacter('<', 42)
            );
        }
    
        #[test]
        fn base64_signature() {
            let signature64 = "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FG\
                               MMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==";
            let signature = super::Signature::from_base64(signature64).unwrap();
            let signature_raw = base64::decode(signature64).unwrap();
    
            for (sig, raw) in signature.0.iter().zip(signature_raw.iter()) {
                assert_eq!(sig, raw);
            }
    
            assert_eq!(
                super::Signature::from_base64("YmhlaW9iaHNlcGlvaGVvaXNlcGl2ZXBvdm5pc2U=").unwrap_err(),
                BaseConvertionError::InvalidKeyLendth(29, 64)
            );
            assert_eq!(
                super::Signature::from_base64(
                    "YmhlaW9iaHNlcGlvaGVvaXNlcGl2ZXBvdm5pc2V2c2JlaW9idmVpb3Zqc\
                     2V2Z3BpaHNlamVwZ25qZXNqb2dwZWpnaW9zZXNkdnNic3JicmJyZGJyZGI=",
                ).unwrap_err(),
                BaseConvertionError::InvalidKeyLendth(86, 64)
            );
            assert_eq!(
                super::Signature::from_base64(
                    "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
                     mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAgdha<<",
                ).unwrap_err(),
                BaseConvertionError::InvalidCharacter('<', 89)
            );
        }
    
        #[test]
        fn message_sign_verify() {
            let pubkey =
                super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap();
    
            let prikey = super::PrivateKey::from_base58(
                "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt\
                 5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7",
            ).unwrap();
    
            let expected_signature = super::Signature::from_base64(
                "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FG\
                 MMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
            ).unwrap();
    
            let message = "Version: 10
    Type: Identity
    Currency: duniter_unit_test_currency
    Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
    UniqueID: tic
    Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
    ";
    
            let sig = prikey.sign(message.as_bytes());
    
            assert_eq!(sig, expected_signature);
            assert!(pubkey.verify(message.as_bytes(), &sig));
        }
    
        #[test]
        fn keypair_generate_sign_and_verify () {
            let keypair = super::KeyPair::new("password".as_bytes(), "salt".as_bytes());
    
            let message = "Version: 10
    Type: Identity
    Currency: duniter_unit_test_currency
    Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
    UniqueID: tic
    Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
    ";
    
            let sig = keypair.sign(message.as_bytes());
            assert!(keypair.pubkey.verify(message.as_bytes(), &sig));
        }
    }