pallet_evm_precompile_substrate_ecdsa/
lib.rs

1// This file is part of Astar.
2
3// Copyright (C) Stake Technologies Pte.Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later
5
6// Astar is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// Astar is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with Astar. If not, see <http://www.gnu.org/licenses/>.
18
19#![cfg_attr(not(feature = "std"), no_std)]
20
21use fp_evm::PrecompileHandle;
22use sp_core::{ecdsa, ByteArray, ConstU32};
23use sp_std::marker::PhantomData;
24use sp_std::prelude::*;
25
26use precompile_utils::prelude::*;
27
28#[cfg(test)]
29mod mock;
30#[cfg(test)]
31mod tests;
32
33// ECDSA pub key bytes
34type ECDSAPubKeyBytes = ConstU32<33>;
35// ECDSA signature bytes
36type ECDSASignatureBytes = ConstU32<65>;
37
38/// A precompile to wrap substrate ecdsa functions.
39pub struct SubstrateEcdsaPrecompile<Runtime>(PhantomData<Runtime>);
40
41#[precompile_utils::precompile]
42impl<Runtime: pallet_evm::Config> SubstrateEcdsaPrecompile<Runtime> {
43    #[precompile::public("verify(bytes,bytes,bytes)")]
44    #[precompile::view]
45    fn verify(
46        _handle: &mut impl PrecompileHandle,
47        public_bytes: BoundedBytes<ECDSAPubKeyBytes>,
48        signature_bytes: BoundedBytes<ECDSASignatureBytes>,
49        message: UnboundedBytes,
50    ) -> EvmResult<bool> {
51        // Parse arguments
52        let public_bytes: Vec<u8> = public_bytes.into();
53        let signature_bytes: Vec<u8> = signature_bytes.into();
54        let message: Vec<u8> = message.into();
55
56        // Parse public key
57        let public = if let Ok(public) = ecdsa::Public::try_from(&public_bytes[..]) {
58            public
59        } else {
60            // Return `false` if public key length is wrong
61            return Ok(false);
62        };
63
64        // Parse signature
65        let signature_opt = ecdsa::Signature::from_slice(&signature_bytes[..]);
66
67        let signature = if let Ok(sig) = signature_opt {
68            sig
69        } else {
70            // Return `false` if signature length is wrong
71            return Ok(false);
72        };
73
74        log::trace!(
75            target: "substrate-ecdsa-precompile",
76            "Verify signature {signature:?} for public {public:?} and message {message:?}",
77        );
78
79        let is_confirmed = sp_io::crypto::ecdsa_verify(&signature, &message[..], &public);
80
81        log::trace!(
82            target: "substrate-ecdsa-precompile",
83            "Verified signature {signature:?} is {is_confirmed:?}",
84        );
85
86        Ok(is_confirmed)
87    }
88}