ethers_signers/wallet/
yubi.rs1use super::Wallet;
3use elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
4use ethers_core::{
5 k256::{PublicKey, Secp256k1},
6 types::Address,
7 utils::keccak256,
8};
9use yubihsm::{
10 asymmetric::Algorithm::EcK256, ecdsa::Signer as YubiSigner, object, object::Label, Capability,
11 Client, Connector, Credentials, Domain,
12};
13
14impl Wallet<YubiSigner<Secp256k1>> {
15 pub fn connect(connector: Connector, credentials: Credentials, id: object::Id) -> Self {
17 let client = Client::open(connector, credentials, true).unwrap();
18 let signer = YubiSigner::create(client, id).unwrap();
19 signer.into()
20 }
21
22 pub fn new(
24 connector: Connector,
25 credentials: Credentials,
26 id: object::Id,
27 label: Label,
28 domain: Domain,
29 ) -> Self {
30 let client = Client::open(connector, credentials, true).unwrap();
31 let id = client
32 .generate_asymmetric_key(id, label, domain, Capability::SIGN_ECDSA, EcK256)
33 .unwrap();
34 let signer = YubiSigner::create(client, id).unwrap();
35 signer.into()
36 }
37
38 pub fn from_key(
40 connector: Connector,
41 credentials: Credentials,
42 id: object::Id,
43 label: Label,
44 domain: Domain,
45 key: impl Into<Vec<u8>>,
46 ) -> Self {
47 let client = Client::open(connector, credentials, true).unwrap();
48 let id = client
49 .put_asymmetric_key(id, label, domain, Capability::SIGN_ECDSA, EcK256, key)
50 .unwrap();
51 let signer = YubiSigner::create(client, id).unwrap();
52 signer.into()
53 }
54}
55
56impl From<YubiSigner<Secp256k1>> for Wallet<YubiSigner<Secp256k1>> {
57 fn from(signer: YubiSigner<Secp256k1>) -> Self {
58 let public_key = PublicKey::from_encoded_point(signer.public_key()).unwrap();
60 let public_key = public_key.to_encoded_point(false);
61 let public_key = public_key.as_bytes();
62 debug_assert_eq!(public_key[0], 0x04);
63 let hash = keccak256(&public_key[1..]);
64 let address = Address::from_slice(&hash[12..]);
65
66 Self { signer, address, chain_id: 1 }
67 }
68}
69
70#[cfg(test)]
71#[cfg(not(target_arch = "wasm32"))]
72mod tests {
73 use super::*;
74 use crate::Signer;
75 use std::str::FromStr;
76
77 #[tokio::test]
78 async fn from_key() {
79 let key = hex::decode("2d8c44dc2dd2f0bea410e342885379192381e82d855b1b112f9b55544f1e0900")
80 .unwrap();
81
82 let connector = yubihsm::Connector::mockhsm();
83 let wallet = Wallet::from_key(
84 connector,
85 Credentials::default(),
86 0,
87 Label::from_bytes(&[]).unwrap(),
88 Domain::at(1).unwrap(),
89 key,
90 );
91
92 let msg = "Some data";
93 let sig = wallet.sign_message(msg).await.unwrap();
94 assert_eq!(sig.recover(msg).unwrap(), wallet.address());
95 assert_eq!(
96 wallet.address(),
97 Address::from_str("2DE2C386082Cff9b28D62E60983856CE1139eC49").unwrap()
98 );
99 }
100
101 #[tokio::test]
102 async fn new_key() {
103 let connector = yubihsm::Connector::mockhsm();
104 let wallet = Wallet::<YubiSigner<Secp256k1>>::new(
105 connector,
106 Credentials::default(),
107 0,
108 Label::from_bytes(&[]).unwrap(),
109 Domain::at(1).unwrap(),
110 );
111
112 let msg = "Some data";
113 let sig = wallet.sign_message(msg).await.unwrap();
114 assert_eq!(sig.recover(msg).unwrap(), wallet.address());
115 }
116}