Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom signing methods #287

Merged
merged 4 commits into from Nov 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/api/accounts.rs
Expand Up @@ -54,12 +54,14 @@ impl<T: Transport> Accounts<T> {
/// using keccak256.
pub fn hash_message<S>(&self, message: S) -> H256
where
S: AsRef<str>,
S: AsRef<[u8]>,
{
let message = message.as_ref();
let eth_message = format!("\x19Ethereum Signed Message:\n{}{}", message.len(), message);

eth_message.as_bytes().keccak256().into()
let mut eth_message = Vec::from(format!("\x19Ethereum Signed Message:\n{}", message.len()).as_bytes());
eth_message.extend_from_slice(message);

eth_message.keccak256().into()
}

/// Sign arbitrary string data.
Expand All @@ -72,10 +74,10 @@ impl<T: Transport> Accounts<T> {
/// such as `ethsign`.
pub fn sign<S>(&self, message: S, key: &SecretKey) -> Result<SignedData, Error>
where
S: AsRef<str>,
S: AsRef<[u8]>,
{
let message = message.as_ref().to_string();
let message_hash = self.hash_message(&message);
let message = message.as_ref();
let message_hash = self.hash_message(message);

let signature = key.sign(&message_hash[..]).map_err(EthsignError::from)?;
// convert to 'Electrum' notation
Expand All @@ -89,6 +91,9 @@ impl<T: Transport> Accounts<T> {
bytes
});

// We perform this allocation only after all previous fallible actions have completed successfully.
let message = message.to_owned();

Ok(SignedData {
message,
message_hash,
Expand All @@ -109,7 +114,7 @@ impl<T: Transport> Accounts<T> {
{
let recovery = recovery.into();
let message_hash = match recovery.message {
RecoveryMessage::String(ref message) => self.hash_message(message),
RecoveryMessage::Data(ref message) => self.hash_message(message),
RecoveryMessage::Hash(hash) => hash,
};
let signature = recovery.as_signature();
Expand Down
26 changes: 19 additions & 7 deletions src/types/recovery.rs
Expand Up @@ -105,26 +105,38 @@ impl<'a> From<&'a EthtxSignedTransaction<'a>> for Recovery {

/// Recovery message data.
///
/// The message data can either be a string message that is first hashed
/// The message data can either be a binary message that is first hashed
/// according to EIP-191 and then recovered based on the signature or a
/// precomputed hash.
#[derive(Clone, Debug, PartialEq)]
pub enum RecoveryMessage {
/// Message string
String(String),
/// Message bytes
Data(Vec<u8>),
/// Message hash
Hash(H256),
}

impl<'a> From<&'a str> for RecoveryMessage {
fn from(s: &'a str) -> Self {
impl From<&[u8]> for RecoveryMessage {
fn from(s: &[u8]) -> Self {
s.to_owned().into()
}
}

impl From<Vec<u8>> for RecoveryMessage {
fn from(s: Vec<u8>) -> Self {
RecoveryMessage::Data(s)
}
}

impl From<&str> for RecoveryMessage {
fn from(s: &str) -> Self {
s.as_bytes().to_owned().into()
}
}

impl From<String> for RecoveryMessage {
fn from(s: String) -> Self {
RecoveryMessage::String(s)
RecoveryMessage::Data(s.into_bytes())
}
}

Expand Down Expand Up @@ -170,7 +182,7 @@ mod tests {
.unwrap();

let signed = SignedData {
message: message.to_string(),
message: message.as_bytes().to_owned(),
message_hash: "1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655"
.parse()
.unwrap(),
Expand Down
6 changes: 3 additions & 3 deletions src/types/signed.rs
Expand Up @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
/// Struct representing signed data returned from `Accounts::sign` method.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct SignedData {
/// The original method that was signed.
pub message: String,
/// The original message that was signed.
pub message: Vec<u8>,
/// The keccak256 hash of the signed data.
#[serde(rename = "messageHash")]
pub message_hash: H256,
Expand All @@ -22,7 +22,7 @@ pub struct SignedData {
/// Transaction data for signing.
///
/// The `Accounts::sign_transaction` method will fill optional fields with sane
/// defaults when they are ommited. Specifically the signing account's current
/// defaults when they are omitted. Specifically the signing account's current
/// transaction count will be used for the `nonce`, the estimated recommended
/// gas price will be used for `gas_price`, and the current network ID will be
/// used for the `chain_id`.
Expand Down