Skip to content

Commit d73d9d2

Browse files
simonr0204simonr0204Simon Robertsadlerjohn
authored
Adds ethAddress type (#1452)
* eth address type * document MemoryOverflow * ecr for eth_address working. * eth -> evm * reference std::vm in sway book * add reference to ethereum address recovery to cryptography docs * make evm specific ecrecover explicit. formatting * Update docs/src/blockchain-development/hashing_and_cryptography.md Co-authored-by: John Adler <[email protected]> * Update docs/src/introduction/standard_library.md Co-authored-by: John Adler <[email protected]> * Update sway-lib-std/src/vm/evm/ecr.sw Co-authored-by: John Adler <[email protected]> * Update sway-lib-std/src/vm/evm/ecr.sw Co-authored-by: John Adler <[email protected]> * Update sway-lib-std/src/vm/evm/evm_address.sw Co-authored-by: John Adler <[email protected]> Co-authored-by: simonr0204 <[email protected]> Co-authored-by: Simon Roberts <[email protected]> Co-authored-by: John Adler <[email protected]>
1 parent 38a857f commit d73d9d2

File tree

10 files changed

+60
-39
lines changed

10 files changed

+60
-39
lines changed

docs/src/blockchain-development/hashing_and_cryptography.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ The Sway standard library provides easy access to a selection of cryptographic h
1313
```sway
1414
{{#include ../../../examples/signatures/src/main.sw}}
1515
```
16+
17+
> **Note** Recovery of EVM addresses is also supported via `std::vm::evm`.

docs/src/introduction/standard_library.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Similar to Rust, Sway comes with its own standard library.
44

5-
The Sway Standard Library is the foundation of portable Sway software, a set of minimal shared abstractions for the broader Sway ecosystem. It offers core types, like `Result<T, E>` and `Option<T>`, library-defined operations on language primitives, native asset management, blockchain contextual operations, access control and storage management, among many other things.
5+
The Sway Standard Library is the foundation of portable Sway software, a set of minimal shared abstractions for the broader Sway ecosystem. It offers core types, like `Result<T, E>` and `Option<T>`, library-defined operations on language primitives, native asset management, blockchain contextual operations, access control, storage management, and support for types from other VMs, among many other things.
66

77
The standard library is made implicitly available to all Forc projects created using [`forc init`](../forc/commands/forc_init.md). Importing items from the standard library can be done using the `use` keyword. Example:
88

sway-lib-std/src/chain.sw

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
library chain;
2-
dep chain/auth;
2+
dep chain/auth;

sway-lib-std/src/logging.sw

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use ::intrinsics::{is_reference_type, size_of};
66
/// If the type is a reference type, `log` is used.
77
/// Otherwise `logd` is used.'
88
pub fn log<T>(value: T) {
9-
if ! is_reference_type::<T>() {
9+
if !is_reference_type::<T>() {
1010
asm(r1: value) {
1111
log r1 zero zero zero;
1212
}

sway-lib-std/src/vm/evm/ecr.sw

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
library ecr;
22

3-
use ::address::Address;
43
use ::b512::B512;
54
use ::context::registers::error;
65
use ::ecr::{EcRecoverError, ec_recover};
6+
use ::vm::evm::evm_address::EvmAddress;
77
use ::hash::keccak256;
88
use ::result::*;
99

10-
/// Recover the address derived from the private key used to sign a message.
10+
/// Recover the EVM address derived from the private key used to sign a message.
1111
/// Returns a `Result` to let the caller choose an error handling strategy.
12-
/// Ethereum addresses are 20 bytes long, so these are left-padded to fit in a 32 byte Address type.
13-
pub fn ec_recover_address(signature: B512, msg_hash: b256) -> Result<Address, EcRecoverError> {
12+
pub fn ec_recover_evm_address(signature: B512, msg_hash: b256) -> Result<EvmAddress, EcRecoverError> {
1413
let pub_key_result = ec_recover(signature, msg_hash);
1514

1615
if let Result::Err(e) = pub_key_result {
@@ -19,14 +18,9 @@ pub fn ec_recover_address(signature: B512, msg_hash: b256) -> Result<Address, Ec
1918
} else {
2019
let pub_key = pub_key_result.unwrap();
2120

22-
// Note that Ethereum addresses are derived from the Keccak256 hash of the pubkey (not sha256)
23-
let address = keccak256(((pub_key.bytes)[0], (pub_key.bytes)[1]));
21+
// Note that EVM addresses are derived from the Keccak256 hash of the pubkey (not sha256)
22+
let pubkey_hash = keccak256(((pub_key.bytes)[0], (pub_key.bytes)[1]));
2423

25-
// Zero out first 12 bytes for ethereum address
26-
asm(r1: address) {
27-
mcli r1 i12;
28-
};
29-
30-
Result::Ok(~Address::from(address))
24+
Result::Ok(~EvmAddress::from(pubkey_hash))
3125
}
3226
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
library evm_address;
2+
3+
//! A wrapper around the b256 type to help enhance type-safety.
4+
5+
/// The Address type, a struct wrappper around the inner `value`.
6+
pub struct EvmAddress {
7+
value: b256,
8+
}
9+
10+
impl core::ops::Eq for EvmAddress {
11+
fn eq(self, other: Self) -> bool {
12+
// An `Address` in Sway is 32 bytes
13+
asm(r1: self, r2: other, result, bytes_to_compare: 32) {
14+
meq result r1 r2 bytes_to_compare;
15+
result: bool
16+
}
17+
}
18+
}
19+
20+
pub trait From {
21+
fn from(b: b256) -> Self;
22+
} {
23+
fn into(addr: EvmAddress) -> b256 {
24+
addr.value
25+
}
26+
}
27+
28+
/// Functions for casting between the b256 and Address types.
29+
impl From for EvmAddress {
30+
fn from(bits: b256) -> EvmAddress {
31+
// An EVM address is only 20 bytes, so the first 12 are set to zero
32+
asm(r1: bits) {
33+
mcli r1 i12;
34+
};
35+
36+
EvmAddress {
37+
value: bits,
38+
}
39+
}
40+
}

sway-lib-std/src/vm/evm/mod.sw

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
library evm;
22

3+
dep evm_address;
34
dep ecr;

test/src/sdk-harness/test_artifacts/reentrancy_attacker_contract/src/main.sw

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
contract;
22

3-
use std::{
4-
chain::auth::*,
5-
context::call_frames::contract_id,
6-
contract_id::ContractId,
7-
result::*,
8-
revert::revert,
9-
};
3+
use std::{chain::auth::*, context::call_frames::contract_id, contract_id::ContractId, result::*, revert::revert};
104

115
use reentrancy_target_abi::Target;
126
use reentrancy_attacker_abi::Attacker;

test/src/sdk-harness/test_artifacts/reentrancy_target_contract/src/main.sw

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
contract;
22

3-
use std::{
4-
assert::assert,
5-
chain::auth::*,
6-
context::{call_frames::contract_id, gas},
7-
contract_id::ContractId,
8-
reentrancy::*,
9-
result::*,
10-
revert::revert,
11-
};
3+
use std::{assert::assert, chain::auth::*, context::{call_frames::contract_id, gas}, contract_id::ContractId, reentrancy::*, result::*, revert::revert};
124

135
use reentrancy_attacker_abi::Attacker;
146
use reentrancy_target_abi::Target;

test/src/sdk-harness/test_projects/evm_ecr/src/main.sw

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
script;
22

3-
use std::address::Address;
43
use std::assert::assert;
54
use std::b512::B512;
65
use std::ecr::EcRecoverError;
76
use std::result::*;
8-
use std::vm::evm::ecr::ec_recover_address;
7+
use std::vm::evm::evm_address::EvmAddress;
8+
use std::vm::evm::ecr::ec_recover_evm_address;
99

1010
fn main() -> bool {
1111
//======================================================
@@ -19,11 +19,9 @@ fn main() -> bool {
1919
Signature: 82115ed208d8fe8dd522d88ca77812b34d270d6bb6326ff511297766a3af1166c07204f554a00e49a2ee69f0979dc4feef07f7dba8d779d388fb2a53bc9bcde4
2020
*/
2121

22-
// Get the expected ethereum pubkeyhash
23-
let pubkey: B512 = ~B512::from(0x1d152307c6b72b0ed0418b0e70cd80e7f5295b8d86f5722d3f5213fbd2394f36, 0xb7ce9c3e45905178455900b44abb308f3ef480481a4b2ee3f70aca157fde396a);
24-
let ethereum_pubkeyhash: Address = ~Address::from(0xe4eab8f844a8d11b205fd137a1b7ea5ede26f651909505d99cf8b5c0d4c8e9c1);
25-
// Manually zero the first 12 bytes.
26-
let ethereum_address: Address = ~Address::from(0x000000000000000000000000a1b7ea5ede26f651909505d99cf8b5c0d4c8e9c1);
22+
// Get the expected ethereum address
23+
let pubkeyhash = 0xe4eab8f844a8d11b205fd137a1b7ea5ede26f651909505d99cf8b5c0d4c8e9c1;
24+
let ethereum_address = ~EvmAddress::from(pubkeyhash);
2725

2826
let msg_hash = 0x8ddb13a2ab58f413bd3121e1ddc8b83a328f3b830d19a7c471f0be652d23bb0e;
2927

@@ -33,7 +31,7 @@ fn main() -> bool {
3331
let signature: B512 = ~B512::from(sig_hi, sig_lo);
3432

3533
// recover the address:
36-
let result: Result<Address, EcRecoverError> = ec_recover_address(signature, msg_hash);
34+
let result: Result<EvmAddress, EcRecoverError> = ec_recover_evm_address(signature, msg_hash);
3735
let recovered_address = result.unwrap();
3836

3937
recovered_address == ethereum_address

0 commit comments

Comments
 (0)