iqkms_ethereum/
signer.rs

1//! iqkms Ethereum RPC service.
2
3use crate::Error;
4use proto::ethereum::{signer_server::Signer, SignDigestRequest, SignEip155Request, Signature};
5use signing::{
6    signature::{ecdsa::secp256k1::RecoverableSignature, hazmat::PrehashSigner},
7    KeyRing,
8};
9use tonic::{Request, Response, Status};
10use tracing::trace;
11use types::ethereum::Address;
12
13/// Keccak256 digest.
14type H256 = [u8; 32];
15
16/// Signer gRPC service.
17pub struct SignerService {
18    /// Signing keyring.
19    keyring: KeyRing,
20}
21
22impl SignerService {
23    /// Create a new RPC service with the given keyring.
24    pub fn new(keyring: KeyRing) -> Self {
25        Self { keyring }
26    }
27
28    /// Parse the given string as an Ethereum address and look up the
29    /// corresponding key in the keyring.
30    fn sign_digest(&self, address: &str, digest: &[u8]) -> Result<Signature, Error> {
31        let address = address.parse::<Address>().map_err(Error::from)?;
32
33        let signing_key = self
34            .keyring
35            .find_by_eth_address(&address)
36            .map_err(Error::from)?;
37
38        let digest = H256::try_from(digest).map_err(|_| Error::DigestMalformed)?;
39        let signature: RecoverableSignature =
40            signing_key.sign_prehash(&digest).map_err(Error::from)?;
41
42        let r = signature.r().to_bytes().to_vec();
43        let s = signature.s().to_bytes().to_vec();
44        let v = u8::from(signature.recovery_id()) + 27;
45
46        Ok(Signature { r, s, v: v.into() })
47    }
48}
49
50#[tonic::async_trait]
51impl Signer for SignerService {
52    async fn sign_digest(
53        &self,
54        request: Request<SignDigestRequest>,
55    ) -> Result<Response<Signature>, Status> {
56        trace!("sign_digest[{:?}]: {:?}", request.remote_addr(), request);
57
58        let request = request.into_inner();
59        Ok(self
60            .sign_digest(&request.address, &request.digest)
61            .map(Response::new)
62            .map_err(Error::from)?)
63    }
64
65    async fn sign_eip155(
66        &self,
67        request: Request<SignEip155Request>,
68    ) -> Result<Response<Signature>, Status> {
69        trace!("sign_eip155[{:?}]: {:?}", request.remote_addr(), request);
70
71        let request = request.into_inner();
72        let mut signature = self
73            .sign_digest(&request.address, &request.digest)
74            .map_err(Error::from)?;
75
76        // Apply EIP-155
77        signature.v = (request.chain_id * 2 + 35) + ((signature.v - 1) % 2);
78        Ok(Response::new(signature))
79    }
80}