1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.

// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// OpenEthereum 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with OpenEthereum.  If not, see <http://www.gnu.org/licenses/>.

//! A signer used by Engines which need to sign messages.

use crypto::publickey::{self, ecies, Error, Public, Signature};
use ethereum_types::{Address, H256};
//TODO dr

/// Everything that an Engine needs to sign messages.
pub trait EngineSigner: Send + Sync {
    /// Sign a consensus message hash.
    fn sign(&self, hash: H256) -> Result<Signature, publickey::Error>;

    /// Signing address
    fn address(&self) -> Address;

    /// Decrypt a message that was encrypted to this signer's key.
    fn decrypt(&self, auth_data: &[u8], cipher: &[u8]) -> Result<Vec<u8>, Error>;

    /// The signer's public key, if available.
    fn public(&self) -> Option<Public>;
}

/// Creates a new `EngineSigner` from given key pair.
pub fn from_keypair(keypair: publickey::KeyPair) -> Box<dyn EngineSigner> {
    Box::new(Signer(keypair))
}

struct Signer(publickey::KeyPair);

impl EngineSigner for Signer {
    fn sign(&self, hash: H256) -> Result<Signature, publickey::Error> {
        publickey::sign(self.0.secret(), &hash)
    }

    fn address(&self) -> Address {
        self.0.address()
    }

    fn decrypt(&self, auth_data: &[u8], cipher: &[u8]) -> Result<Vec<u8>, Error> {
        ecies::decrypt(self.0.secret(), auth_data, cipher).map_err(From::from)
    }

    fn public(&self) -> Option<Public> {
        Some(*self.0.public())
    }
}

#[cfg(test)]
mod test_signer {

    extern crate ethkey;

    use std::sync::Arc;

    use self::ethkey::Password;
    use accounts::{self, AccountProvider, SignError};

    use super::*;

    impl EngineSigner for (Arc<AccountProvider>, Address, Password) {
        fn sign(&self, hash: H256) -> Result<Signature, crypto::publickey::Error> {
            match self.0.sign(self.1, Some(self.2.clone()), hash) {
                Err(SignError::NotUnlocked) => unreachable!(),
                Err(SignError::NotFound) => Err(crypto::publickey::Error::InvalidAddress),
                Err(SignError::SStore(accounts::Error::EthCryptoPublicKey(err))) => Err(err),
                Err(SignError::SStore(accounts::Error::EthCrypto(err))) => {
                    warn!("Low level crypto error: {:?}", err);
                    Err(crypto::publickey::Error::InvalidSecretKey)
                }
                Err(SignError::SStore(err)) => {
                    warn!("Error signing for engine: {:?}", err);
                    Err(crypto::publickey::Error::InvalidSignature)
                }
                Ok(ok) => Ok(ok),
            }
        }

        fn address(&self) -> Address {
            self.1
        }

        fn decrypt(&self, auth_data: &[u8], cipher: &[u8]) -> Result<Vec<u8>, Error> {
            self.0
                .decrypt(self.1, None, auth_data, cipher)
                .map_err(|e| {
                    warn!("Unable to decrypt message: {:?}", e);
                    Error::InvalidMessage
                })
        }

        fn public(&self) -> Option<Public> {
            self.0.account_public(self.1, &self.2).ok()
        }
    }
}