Skip to content

Commit

Permalink
Revert backward-incompatible piece of #1233: removal of eth_compatibi…
Browse files Browse the repository at this point in the history
…lity crate
  • Loading branch information
agryaznov committed Jun 6, 2022
1 parent cd26767 commit 061c94e
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ members = [
"crates/primitives",
"crates/engine",
"crates/env",
"crates/eth_compatibility",
"crates/storage",
"crates/storage/derive",
]
Expand Down
30 changes: 30 additions & 0 deletions crates/eth_compatibility/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "ink_eth_compatibility"
version = "3.0.1"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"

license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/paritytech/ink"
documentation = "https://docs.rs/ink_eth_compatibility/"
homepage = "https://www.parity.io/"
description = "[ink!] Ethereum related stuff."
keywords = ["wasm", "parity", "webassembly", "blockchain", "ethereum"]
categories = ["no-std", "embedded"]
include = ["Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"]

[dependencies]
ink_env = { version = "3.0.1", path = "../env", default-features = false }

[target.'cfg(not(target_os = "windows"))'.dependencies]
# We do not include `libsecp256k1` on Windows, since it's incompatible.
# We have https://github.com/paritytech/ink/issues/1068 for removing
# this dependency altogether.
libsecp256k1 = { version = "0.7.0", default-features = false }

[features]
default = ["std"]
std = [
"ink_env/std",
]
1 change: 1 addition & 0 deletions crates/eth_compatibility/LICENSE
1 change: 1 addition & 0 deletions crates/eth_compatibility/README.md
150 changes: 150 additions & 0 deletions crates/eth_compatibility/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright 2018-2022 Parity Technologies (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![no_std]

use ink_env::{
DefaultEnvironment,
Environment,
};

/// The ECDSA compressed public key.
#[derive(Debug, Copy, Clone)]
pub struct ECDSAPublicKey([u8; 33]);

impl Default for ECDSAPublicKey {
fn default() -> Self {
// Default is not implemented for [u8; 33], so we can't derive it for ECDSAPublicKey
// But clippy thinks that it is possible. So it is workaround for clippy.
let empty = [0; 33];
Self(empty)
}
}

impl AsRef<[u8; 33]> for ECDSAPublicKey {
fn as_ref(&self) -> &[u8; 33] {
&self.0
}
}

impl AsMut<[u8; 33]> for ECDSAPublicKey {
fn as_mut(&mut self) -> &mut [u8; 33] {
&mut self.0
}
}

impl From<[u8; 33]> for ECDSAPublicKey {
fn from(bytes: [u8; 33]) -> Self {
Self(bytes)
}
}

/// The address of an Ethereum account.
#[derive(Debug, Default, Copy, Clone)]
pub struct EthereumAddress([u8; 20]);

impl AsRef<[u8; 20]> for EthereumAddress {
fn as_ref(&self) -> &[u8; 20] {
&self.0
}
}

impl AsMut<[u8; 20]> for EthereumAddress {
fn as_mut(&mut self) -> &mut [u8; 20] {
&mut self.0
}
}

impl From<[u8; 20]> for EthereumAddress {
fn from(bytes: [u8; 20]) -> Self {
Self(bytes)
}
}

impl ECDSAPublicKey {
/// Returns Ethereum address from the ECDSA compressed public key.
///
/// # Example
///
/// ```
/// use ink_eth_compatibility::{ECDSAPublicKey, EthereumAddress};
/// let pub_key: ECDSAPublicKey = [
/// 2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11,
/// 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23,
/// 152,
/// ].into();
///
/// let EXPECTED_ETH_ADDRESS: EthereumAddress = [
/// 126, 95, 69, 82, 9, 26, 105, 18, 93, 93, 252, 183, 184, 194, 101, 144, 41, 57, 91, 223
/// ].into();
///
/// assert_eq!(pub_key.to_eth_address().as_ref(), EXPECTED_ETH_ADDRESS.as_ref());
/// ```
// We do not include this function on Windows, since it depends on `libsecp256k1`,
// which is incompatible with Windows.
// We have https://github.com/paritytech/ink/issues/1068 for removing this
// dependency altogether.
#[cfg(not(target_os = "windows"))]
pub fn to_eth_address(&self) -> EthereumAddress {
use ink_env::hash;
use libsecp256k1::PublicKey;

// Transform compressed public key into uncompressed.
let pub_key = PublicKey::parse_compressed(&self.0)
.expect("Unable to parse the compressed ECDSA public key");
let uncompressed = pub_key.serialize();

// Hash the uncompressed public key by Keccak256 algorithm.
let mut hash = <hash::Keccak256 as hash::HashOutput>::Type::default();
// The first byte indicates that the public key is uncompressed.
// Let's skip it for hashing the public key directly.
ink_env::hash_bytes::<hash::Keccak256>(&uncompressed[1..], &mut hash);

// Take the last 20 bytes as an Address
let mut result = EthereumAddress::default();
result.as_mut().copy_from_slice(&hash[12..]);

result
}

/// Returns the default Substrate's `AccountId` from the ECDSA compressed public key.
/// It hashes the compressed public key with the `blake2b_256` algorithm like in substrate.
///
/// # Example
///
/// ```
/// use ink_eth_compatibility::ECDSAPublicKey;
/// let pub_key: ECDSAPublicKey = [
/// 2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11,
/// 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23,
/// 152,
/// ].into();
///
/// const EXPECTED_ACCOUNT_ID: [u8; 32] = [
/// 41, 117, 241, 210, 139, 146, 182, 232, 68, 153, 184, 59, 7, 151, 239, 82,
/// 53, 85, 62, 235, 126, 218, 160, 206, 162, 67, 193, 18, 140, 47, 231, 55,
/// ];
///
/// assert_eq!(pub_key.to_default_account_id(), EXPECTED_ACCOUNT_ID.into());
pub fn to_default_account_id(
&self,
) -> <DefaultEnvironment as Environment>::AccountId {
use ink_env::hash;

let mut output = <hash::Blake2x256 as hash::HashOutput>::Type::default();
ink_env::hash_bytes::<hash::Blake2x256>(&self.0[..], &mut output);

output.into()
}
}

0 comments on commit 061c94e

Please sign in to comment.