Skip to content

Commit

Permalink
Breaking change: web3::api::Accounts can now sign arbitrary signed …
Browse files Browse the repository at this point in the history
…data.

Previously, it could only sign std::String and std::str (UTF-8) data.
This reflects the functionality in the Go implementation of message signing:
https://github.com/bas-vk/go-ethereum/blob/e61035c5a3630e4f6fd0fb3e5346a4eed8cedc80/internal/ethapi/api.go#L352
as well as what is available in the `ethereum-tx-sign` crate:
https://docs.rs/ethereum-tx-sign/2.0.0/ethereum_tx_sign/struct.RawTransaction.html
(note the `data` field is a Vec<u8>)
  • Loading branch information
reuvenpo committed Nov 20, 2019
1 parent 5e8e0a4 commit be7e16a
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 16 deletions.
19 changes: 12 additions & 7 deletions src/api/accounts.rs
Original file line number Diff line number Diff line change
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 action 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::Bytes(ref message) => self.hash_message(message),
RecoveryMessage::Hash(hash) => hash,
};
let signature = recovery.as_signature();
Expand Down
27 changes: 20 additions & 7 deletions src/types/recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,26 +105,39 @@ 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
Bytes(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::Bytes(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::Bytes(s.into_bytes())
}
}

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

let signed = SignedData {
message: message.to_string(),
message: message.as_bytes().to_owned(),
message_hash: "1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655"
.parse()
.unwrap(),
Expand Down
4 changes: 2 additions & 2 deletions src/types/signed.rs
Original file line number Diff line number Diff line change
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 Down

0 comments on commit be7e16a

Please sign in to comment.