mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 08:51:09 +00:00
Add frame_support::crypto::ecdsa::Public.to_eth_address() (k256-based) and use it in pallets (#11087)
* `ecdsa::Public::to_eth_address` + test, beefy-mmr `convert()` to use it, contracts Ext interface * `seal_ecdsa_to_eth_address` all but benchmark done * `seal_ecdsa_to_eth_address` + wasm test * `seal_ecdsa_to_eth_address` + benchmark * fixed dependencies * Apply suggestions from code review Co-authored-by: Alexander Theißen <alex.theissen@me.com> * fixes from review #1 * ecdsa::Public(*pk).to_eth_address() moved to frame_support and contracts to use it * beefy-mmr to use newly added frame_support function for convertion * a doc fix * import fix * benchmark fix-1 (still fails) * benchmark fixed * Apply suggestions from code review Co-authored-by: Alexander Theißen <alex.theissen@me.com> * fixes on Alex T feedback * to_eth_address() put into extension trait for sp-core::ecdsa::Public * Update frame/support/src/crypto/ecdsa.rs Co-authored-by: Alexander Theißen <alex.theissen@me.com> * Update frame/contracts/src/wasm/mod.rs Co-authored-by: Alexander Theißen <alex.theissen@me.com> * fixes on issues pointed out in review * benchmark errors fixed * fmt fix * EcdsaRecoverFailed err docs updated * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * make applied suggestions compile * get rid of unwrap() in runtime * Remove expect Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> Co-authored-by: Bastian Köcher <info@kchr.de>
This commit is contained in:
committed by
GitHub
parent
c6e452108b
commit
9676ce6f36
Generated
+14
-29
@@ -456,12 +456,6 @@ version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "874f8444adcb4952a8bc51305c8be95c8ec8237bb0d2e78d2e039f771f8828a0"
|
||||
|
||||
[[package]]
|
||||
name = "beef"
|
||||
version = "0.5.1"
|
||||
@@ -1805,6 +1799,7 @@ checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9"
|
||||
dependencies = [
|
||||
"der",
|
||||
"elliptic-curve",
|
||||
"rfc6979",
|
||||
"signature",
|
||||
]
|
||||
|
||||
@@ -2311,6 +2306,7 @@ dependencies = [
|
||||
"frame-support-procedural",
|
||||
"frame-system",
|
||||
"impl-trait-for-tuples",
|
||||
"k256",
|
||||
"log 0.4.14",
|
||||
"once_cell",
|
||||
"parity-scale-codec",
|
||||
@@ -5667,7 +5663,6 @@ dependencies = [
|
||||
"frame-system",
|
||||
"hex",
|
||||
"hex-literal",
|
||||
"k256",
|
||||
"log 0.4.14",
|
||||
"pallet-beefy",
|
||||
"pallet-mmr",
|
||||
@@ -7071,17 +7066,6 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
@@ -7871,6 +7855,17 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "448296241d034b96c11173591deaa1302f2c17b56092106c1f92c1bc0183a8c9"
|
||||
|
||||
[[package]]
|
||||
name = "rfc6979"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525"
|
||||
dependencies = [
|
||||
"crypto-bigint",
|
||||
"hmac 0.11.0",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
@@ -9377,7 +9372,6 @@ checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1"
|
||||
dependencies = [
|
||||
"der",
|
||||
"generic-array 0.14.4",
|
||||
"pkcs8",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -9662,6 +9656,7 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"rand_core 0.6.2",
|
||||
]
|
||||
|
||||
@@ -10588,16 +10583,6 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ss58-registry"
|
||||
version = "1.11.0"
|
||||
|
||||
@@ -10,7 +10,6 @@ repository = "https://github.com/paritytech/substrate"
|
||||
[dependencies]
|
||||
hex = { version = "0.4", optional = true }
|
||||
codec = { version = "3.0.0", package = "parity-scale-codec", default-features = false, features = ["derive"] }
|
||||
k256 = { version = "0.10.2", default-features = false, features = ["arithmetic"] }
|
||||
log = { version = "0.4.13", default-features = false }
|
||||
scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.136", optional = true }
|
||||
@@ -42,7 +41,6 @@ std = [
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"hex",
|
||||
"k256/std",
|
||||
"log/std",
|
||||
"pallet-beefy/std",
|
||||
"pallet-mmr/std",
|
||||
|
||||
@@ -39,7 +39,7 @@ use sp_std::prelude::*;
|
||||
use beefy_primitives::mmr::{BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion};
|
||||
use pallet_mmr::{LeafDataProvider, ParentNumberAndHash};
|
||||
|
||||
use frame_support::traits::Get;
|
||||
use frame_support::{crypto::ecdsa::ECDSAExt, traits::Get};
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
@@ -71,19 +71,16 @@ where
|
||||
pub struct BeefyEcdsaToEthereum;
|
||||
impl Convert<beefy_primitives::crypto::AuthorityId, Vec<u8>> for BeefyEcdsaToEthereum {
|
||||
fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec<u8> {
|
||||
use k256::{elliptic_curve::sec1::ToEncodedPoint, PublicKey};
|
||||
use sp_core::crypto::ByteArray;
|
||||
|
||||
PublicKey::from_sec1_bytes(a.as_slice())
|
||||
.map(|pub_key| {
|
||||
// uncompress the key
|
||||
let uncompressed = pub_key.to_encoded_point(false);
|
||||
// convert to ETH address
|
||||
sp_io::hashing::keccak_256(&uncompressed.as_bytes()[1..])[12..].to_vec()
|
||||
})
|
||||
sp_core::ecdsa::Public::try_from(a.as_ref())
|
||||
.map_err(|_| {
|
||||
log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!");
|
||||
})
|
||||
.unwrap_or(sp_core::ecdsa::Public::from_raw([0u8; 33]))
|
||||
.to_eth_address()
|
||||
.map(|v| v.to_vec())
|
||||
.map_err(|_| {
|
||||
log::error!(target: "runtime::beefy", "Failed to convert BEEFY PublicKey to ETH address!");
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1963,6 +1963,44 @@ benchmarks! {
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
|
||||
|
||||
// Only calling the function itself for the list of
|
||||
// generated different ECDSA keys.
|
||||
seal_ecdsa_to_eth_address {
|
||||
let r in 0 .. API_BENCHMARK_BATCHES;
|
||||
let key_type = sp_core::crypto::KeyTypeId(*b"code");
|
||||
let pub_keys_bytes = (0..r * API_BENCHMARK_BATCH_SIZE)
|
||||
.map(|_| {
|
||||
sp_io::crypto::ecdsa_generate(key_type, None).0
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
let pub_keys_bytes_len = pub_keys_bytes.len() as i32;
|
||||
let code = WasmModule::<T>::from(ModuleDefinition {
|
||||
memory: Some(ImportedMemory::max::<T>()),
|
||||
imported_functions: vec![ImportedFunction {
|
||||
module: "__unstable__",
|
||||
name: "seal_ecdsa_to_eth_address",
|
||||
params: vec![ValueType::I32, ValueType::I32],
|
||||
return_type: Some(ValueType::I32),
|
||||
}],
|
||||
data_segments: vec![
|
||||
DataSegment {
|
||||
offset: 0,
|
||||
value: pub_keys_bytes,
|
||||
},
|
||||
],
|
||||
call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
|
||||
Counter(0, 33), // pub_key_ptr
|
||||
Regular(Instruction::I32Const(pub_keys_bytes_len)), // out_ptr
|
||||
Regular(Instruction::Call(0)),
|
||||
Regular(Instruction::Drop),
|
||||
])),
|
||||
.. Default::default()
|
||||
});
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
|
||||
|
||||
seal_set_code_hash {
|
||||
let r in 0 .. API_BENCHMARK_BATCHES;
|
||||
let code_hashes = (0..r * API_BENCHMARK_BATCH_SIZE)
|
||||
|
||||
@@ -22,6 +22,7 @@ use crate::{
|
||||
Pallet as Contracts, Schedule,
|
||||
};
|
||||
use frame_support::{
|
||||
crypto::ecdsa::ECDSAExt,
|
||||
dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Dispatchable},
|
||||
storage::{with_transaction, TransactionOutcome},
|
||||
traits::{Contains, Currency, ExistenceRequirement, OriginTrait, Randomness, Time},
|
||||
@@ -30,7 +31,7 @@ use frame_support::{
|
||||
use frame_system::RawOrigin;
|
||||
use pallet_contracts_primitives::ExecReturnValue;
|
||||
use smallvec::{Array, SmallVec};
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_core::{crypto::UncheckedFrom, ecdsa::Public as ECDSAPublic};
|
||||
use sp_io::crypto::secp256k1_ecdsa_recover_compressed;
|
||||
use sp_runtime::traits::Convert;
|
||||
use sp_std::{marker::PhantomData, mem, prelude::*};
|
||||
@@ -232,6 +233,9 @@ pub trait Ext: sealing::Sealed {
|
||||
/// Recovers ECDSA compressed public key based on signature and message hash.
|
||||
fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()>;
|
||||
|
||||
/// Returns Ethereum address from the ECDSA compressed public key.
|
||||
fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()>;
|
||||
|
||||
/// Tests sometimes need to modify and inspect the contract info directly.
|
||||
#[cfg(test)]
|
||||
fn contract_info(&mut self) -> &mut ContractInfo<Self::T>;
|
||||
@@ -1204,6 +1208,10 @@ where
|
||||
secp256k1_ecdsa_recover_compressed(&signature, &message_hash).map_err(|_| ())
|
||||
}
|
||||
|
||||
fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()> {
|
||||
ECDSAPublic(*pk).to_eth_address()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn contract_info(&mut self) -> &mut ContractInfo<Self::T> {
|
||||
self.top_frame_mut().contract_info()
|
||||
@@ -1267,6 +1275,7 @@ mod tests {
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{assert_err, assert_ok};
|
||||
use frame_system::{EventRecord, Phase};
|
||||
use hex_literal::hex;
|
||||
use pallet_contracts_primitives::ReturnFlags;
|
||||
use pretty_assertions::assert_eq;
|
||||
use sp_core::Bytes;
|
||||
@@ -2718,4 +2727,36 @@ mod tests {
|
||||
));
|
||||
});
|
||||
}
|
||||
#[test]
|
||||
fn ecdsa_to_eth_address_returns_proper_value() {
|
||||
let bob_ch = MockLoader::insert(Call, |ctx, _| {
|
||||
let pubkey_compressed: [u8; 33] =
|
||||
hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91")[..]
|
||||
.try_into()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
ctx.ext.ecdsa_to_eth_address(&pubkey_compressed).unwrap(),
|
||||
hex!("09231da7b19A016f9e576d23B16277062F4d46A8")[..]
|
||||
);
|
||||
exec_success()
|
||||
});
|
||||
|
||||
ExtBuilder::default().build().execute_with(|| {
|
||||
let schedule = <Test as Config>::Schedule::get();
|
||||
place_contract(&BOB, bob_ch);
|
||||
|
||||
let mut storage_meter = storage::meter::Meter::new(&ALICE, Some(0), 0).unwrap();
|
||||
let result = MockStack::run_call(
|
||||
ALICE,
|
||||
BOB,
|
||||
&mut GasMeter::<Test>::new(GAS_LIMIT),
|
||||
&mut storage_meter,
|
||||
&schedule,
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,6 +418,9 @@ pub struct HostFnWeights<T: Config> {
|
||||
/// Weight of calling `seal_ecdsa_recover`.
|
||||
pub ecdsa_recover: Weight,
|
||||
|
||||
/// Weight of calling `seal_ecdsa_to_eth_address`.
|
||||
pub ecdsa_to_eth_address: Weight,
|
||||
|
||||
/// The type parameter is used in the default implementation.
|
||||
#[codec(skip)]
|
||||
pub _phantom: PhantomData<T>,
|
||||
@@ -653,6 +656,7 @@ impl<T: Config> Default for HostFnWeights<T> {
|
||||
hash_blake2_128: cost_batched!(seal_hash_blake2_128),
|
||||
hash_blake2_128_per_byte: cost_byte_batched!(seal_hash_blake2_128_per_kb),
|
||||
ecdsa_recover: cost_batched!(seal_ecdsa_recover),
|
||||
ecdsa_to_eth_address: cost_batched!(seal_ecdsa_to_eth_address),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,6 +503,9 @@ mod tests {
|
||||
fn contract_info(&mut self) -> &mut crate::ContractInfo<Self::T> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn ecdsa_to_eth_address(&self, _pk: &[u8; 33]) -> Result<[u8; 20], ()> {
|
||||
Ok([2u8; 20])
|
||||
}
|
||||
}
|
||||
|
||||
fn execute<E: BorrowMut<MockExt>>(wat: &str, input_data: Vec<u8>, mut ext: E) -> ExecResult {
|
||||
@@ -1085,6 +1088,42 @@ mod tests {
|
||||
assert_eq!(mock_ext.ecdsa_recover.into_inner(), [([1; 65], [1; 32])]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn contract_ecdsa_to_eth_address() {
|
||||
/// calls `seal_ecdsa_to_eth_address` for the contstant and ensures the result equals the
|
||||
/// expected one.
|
||||
const CODE_ECDSA_TO_ETH_ADDRESS: &str = r#"
|
||||
(module
|
||||
(import "__unstable__" "seal_ecdsa_to_eth_address" (func $seal_ecdsa_to_eth_address (param i32 i32) (result i32)))
|
||||
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
(func (export "call")
|
||||
;; fill the buffer with the eth address.
|
||||
(call $seal_ecdsa_to_eth_address (i32.const 0) (i32.const 0))
|
||||
|
||||
;; Return the contents of the buffer
|
||||
(call $seal_return
|
||||
(i32.const 0)
|
||||
(i32.const 0)
|
||||
(i32.const 20)
|
||||
)
|
||||
|
||||
;; seal_return doesn't return, so this is effectively unreachable.
|
||||
(unreachable)
|
||||
)
|
||||
(func (export "deploy"))
|
||||
)
|
||||
"#;
|
||||
|
||||
let output = execute(CODE_ECDSA_TO_ETH_ADDRESS, vec![], MockExt::default()).unwrap();
|
||||
assert_eq!(
|
||||
output,
|
||||
ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes([0x02; 20].to_vec()) }
|
||||
);
|
||||
}
|
||||
|
||||
const CODE_GET_STORAGE: &str = r#"
|
||||
(module
|
||||
(import "seal0" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32) (result i32)))
|
||||
|
||||
@@ -71,7 +71,9 @@ pub enum ReturnCode {
|
||||
/// The call dispatched by `seal_call_runtime` was executed but returned an error.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CallRuntimeReturnedError = 10,
|
||||
/// ECDSA pubkey recovery failed. Most probably wrong recovery id or signature.
|
||||
/// ECDSA pubkey recovery failed (most probably wrong recovery id or signature), or
|
||||
/// ECDSA compressed pubkey conversion into Ethereum address failed (most probably
|
||||
/// wrong pubkey provided).
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
EcdsaRecoverFailed = 11,
|
||||
}
|
||||
@@ -225,6 +227,9 @@ pub enum RuntimeCosts {
|
||||
/// Weight of calling `seal_set_code_hash`
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
SetCodeHash,
|
||||
/// Weight of calling `ecdsa_to_eth_address`
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
EcdsaToEthAddress,
|
||||
}
|
||||
|
||||
impl RuntimeCosts {
|
||||
@@ -309,6 +314,8 @@ impl RuntimeCosts {
|
||||
CallRuntime(weight) => weight,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
SetCodeHash => s.set_code_hash,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
EcdsaToEthAddress => s.ecdsa_to_eth_address,
|
||||
};
|
||||
RuntimeToken {
|
||||
#[cfg(test)]
|
||||
@@ -1984,12 +1991,12 @@ define_env!(Env, <E: Ext>,
|
||||
// # Parameters
|
||||
//
|
||||
// - `signature_ptr`: the pointer into the linear memory where the signature
|
||||
// is placed. Should be decodable as a 65 bytes. Traps otherwise.
|
||||
// is placed. Should be decodable as a 65 bytes. Traps otherwise.
|
||||
// - `message_hash_ptr`: the pointer into the linear memory where the message
|
||||
// hash is placed. Should be decodable as a 32 bytes. Traps otherwise.
|
||||
// - `output_ptr`: the pointer into the linear memory where the output
|
||||
// data is placed. The buffer should be 33 bytes. Traps otherwise.
|
||||
// The function will write the result directly into this buffer.
|
||||
// data is placed. The buffer should be 33 bytes. The function
|
||||
// will write the result directly into this buffer.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
@@ -2036,7 +2043,7 @@ define_env!(Env, <E: Ext>,
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
// - code_hash_ptr: A pointer to the buffer that contains the new code hash.
|
||||
// - `code_hash_ptr`: A pointer to the buffer that contains the new code hash.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
@@ -2052,4 +2059,35 @@ define_env!(Env, <E: Ext>,
|
||||
Ok(()) => Ok(ReturnCode::Success)
|
||||
}
|
||||
},
|
||||
|
||||
// Calculates Ethereum address from the ECDSA compressed public key and stores
|
||||
// it into the supplied buffer.
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
// - `key_ptr`: a pointer to the ECDSA compressed public key. Should be decodable as a 33 bytes value.
|
||||
// Traps otherwise.
|
||||
// - `out_ptr`: the pointer into the linear memory where the output
|
||||
// data is placed. The function will write the result
|
||||
// directly into this buffer.
|
||||
//
|
||||
// The value is stored to linear memory at the address pointed to by `out_ptr`.
|
||||
// If the available space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// `ReturnCode::EcdsaRecoverFailed`
|
||||
[__unstable__] seal_ecdsa_to_eth_address(ctx, key_ptr: u32, out_ptr: u32) -> ReturnCode => {
|
||||
ctx.charge_gas(RuntimeCosts::EcdsaToEthAddress)?;
|
||||
let mut compressed_key: [u8; 33] = [0;33];
|
||||
ctx.read_sandbox_memory_into_buf(key_ptr, &mut compressed_key)?;
|
||||
let result = ctx.ext.ecdsa_to_eth_address(&compressed_key);
|
||||
match result {
|
||||
Ok(eth_address) => {
|
||||
ctx.write_sandbox_memory(out_ptr, eth_address.as_ref())?;
|
||||
Ok(ReturnCode::Success)
|
||||
},
|
||||
Err(_) => Ok(ReturnCode::EcdsaRecoverFailed),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -103,6 +103,7 @@ pub trait WeightInfo {
|
||||
fn seal_hash_blake2_128(r: u32, ) -> Weight;
|
||||
fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight;
|
||||
fn seal_ecdsa_recover(r: u32, ) -> Weight;
|
||||
fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight;
|
||||
fn seal_set_code_hash(r: u32, ) -> Weight;
|
||||
fn instr_i64const(r: u32, ) -> Weight;
|
||||
fn instr_i64load(r: u32, ) -> Weight;
|
||||
@@ -805,6 +806,17 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
// Storage: Contracts ContractInfoOf (r:1 w:1)
|
||||
// Storage: Contracts CodeStorage (r:1 w:0)
|
||||
// Storage: Timestamp Now (r:1 w:0)
|
||||
fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight {
|
||||
(272_893_000 as Weight)
|
||||
// Standard Error: 1_438_000
|
||||
.saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
// Storage: System Account (r:1 w:0)
|
||||
// Storage: Contracts ContractInfoOf (r:1 w:1)
|
||||
// Storage: Contracts CodeStorage (r:1 w:0)
|
||||
// Storage: Timestamp Now (r:1 w:0)
|
||||
// Storage: Contracts OwnerInfoOf (r:36 w:36)
|
||||
fn seal_set_code_hash(r: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
@@ -1717,6 +1729,17 @@ impl WeightInfo for () {
|
||||
// Storage: Contracts ContractInfoOf (r:1 w:1)
|
||||
// Storage: Contracts CodeStorage (r:1 w:0)
|
||||
// Storage: Timestamp Now (r:1 w:0)
|
||||
fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight {
|
||||
(272_893_000 as Weight)
|
||||
// Standard Error: 1_438_000
|
||||
.saturating_add((15_412_877_000 as Weight).saturating_mul(r as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
// Storage: System Account (r:1 w:0)
|
||||
// Storage: Contracts ContractInfoOf (r:1 w:1)
|
||||
// Storage: Contracts CodeStorage (r:1 w:0)
|
||||
// Storage: Timestamp Now (r:1 w:0)
|
||||
// Storage: Contracts OwnerInfoOf (r:36 w:36)
|
||||
fn seal_set_code_hash(r: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
|
||||
@@ -35,6 +35,7 @@ impl-trait-for-tuples = "0.2.2"
|
||||
smallvec = "1.8.0"
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
sp-core-hashing-proc-macro = { version = "5.0.0", path = "../../primitives/core/hashing/proc-macro" }
|
||||
k256 = { version = "0.10.2", default-features = false, features = ["ecdsa"] }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// 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.
|
||||
|
||||
//! Utilities for dealing with crypto primitives. Sometimes we need to use these from inside WASM
|
||||
//! contracts, where crypto calculations have weak performance.
|
||||
|
||||
pub mod ecdsa;
|
||||
@@ -0,0 +1,49 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// 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.
|
||||
|
||||
//! Simple ECDSA secp256k1 API.
|
||||
//!
|
||||
//! Provides an extension trait for [`sp_core::ecdsa::Public`] to do certain operations.
|
||||
|
||||
use sp_core::{crypto::ByteArray, ecdsa::Public};
|
||||
|
||||
/// Extension trait for [`Public`] to be used from inside the runtime.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This is needed because host functions cannot be called from within
|
||||
/// `sp_core` due to cyclic dependencies on `sp_io`.
|
||||
pub trait ECDSAExt {
|
||||
/// Returns Ethereum address calculated from this ECDSA public key.
|
||||
fn to_eth_address(&self) -> Result<[u8; 20], ()>;
|
||||
}
|
||||
|
||||
impl ECDSAExt for Public {
|
||||
fn to_eth_address(&self) -> Result<[u8; 20], ()> {
|
||||
use k256::{elliptic_curve::sec1::ToEncodedPoint, PublicKey};
|
||||
|
||||
PublicKey::from_sec1_bytes(self.as_slice()).map_err(drop).and_then(|pub_key| {
|
||||
// uncompress the key
|
||||
let uncompressed = pub_key.to_encoded_point(false);
|
||||
// convert to ETH address
|
||||
<[u8; 20]>::try_from(
|
||||
sp_io::hashing::keccak_256(&uncompressed.as_bytes()[1..])[12..].as_ref(),
|
||||
)
|
||||
.map_err(drop)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,7 @@ pub mod event;
|
||||
pub mod inherent;
|
||||
#[macro_use]
|
||||
pub mod error;
|
||||
pub mod crypto;
|
||||
pub mod instances;
|
||||
pub mod migrations;
|
||||
pub mod traits;
|
||||
|
||||
Reference in New Issue
Block a user