identity_storage/storage/
storage_signer.rs1use anyhow::anyhow;
5use async_trait::async_trait;
6use fastcrypto::hash::Blake2b256;
7use fastcrypto::traits::ToFromBytes;
8
9use identity_verification::jwk::FromJwk as _;
10use identity_verification::jwk::Jwk;
11
12use iota_interaction::shared_crypto::intent::Intent;
13use iota_interaction::types::crypto::PublicKey;
14use iota_interaction::types::crypto::Signature;
15
16use iota_interaction::types::transaction::TransactionData;
17use iota_interaction::IotaKeySignature;
18use iota_interaction::OptionalSync;
19use secret_storage::Error as SecretStorageError;
20use secret_storage::Signer;
21
22use crate::JwkStorage;
23use crate::KeyId;
24use crate::KeyIdStorage;
25use crate::KeyStorageErrorKind;
26use crate::Storage;
27
28pub struct StorageSigner<'a, K, I> {
31 key_id: KeyId,
32 public_key: Jwk,
33 storage: &'a Storage<K, I>,
34}
35
36impl<K, I> Clone for StorageSigner<'_, K, I> {
37 fn clone(&self) -> Self {
38 StorageSigner {
39 key_id: self.key_id.clone(),
40 public_key: self.public_key.clone(),
41 storage: self.storage,
42 }
43 }
44}
45
46impl<'a, K, I> StorageSigner<'a, K, I> {
47 pub fn new(storage: &'a Storage<K, I>, key_id: KeyId, public_key: Jwk) -> Self {
49 Self {
50 key_id,
51 public_key,
52 storage,
53 }
54 }
55
56 pub fn key_id(&self) -> &KeyId {
58 &self.key_id
59 }
60
61 pub fn public_key_jwk(&self) -> &Jwk {
63 &self.public_key
64 }
65
66 pub fn storage(&self) -> &Storage<K, I> {
68 self.storage
69 }
70}
71
72#[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
73#[cfg_attr(feature = "send-sync-storage", async_trait)]
74impl<K, I> Signer<IotaKeySignature> for StorageSigner<'_, K, I>
75where
76 K: JwkStorage + OptionalSync,
77 I: KeyIdStorage + OptionalSync,
78{
79 type KeyId = KeyId;
80
81 fn key_id(&self) -> KeyId {
82 self.key_id.clone()
83 }
84
85 async fn public_key(&self) -> Result<PublicKey, SecretStorageError> {
86 PublicKey::from_jwk(&self.public_key)
87 .map_err(|e| SecretStorageError::Other(anyhow!("failed to convert public key: {e}")))
88 }
89 async fn sign(&self, data: &TransactionData) -> Result<Signature, SecretStorageError> {
90 use fastcrypto::hash::HashFunction;
91
92 let tx_data_bcs =
93 bcs::to_bytes(data).map_err(|e| SecretStorageError::Other(anyhow!("bcs deserialization failed: {e}")))?;
94 let intent_bytes = Intent::iota_transaction().to_bytes();
95 let mut hasher = Blake2b256::default();
96 hasher.update(intent_bytes);
97 hasher.update(&tx_data_bcs);
98 let digest = hasher.finalize().digest;
99
100 let signature_bytes = self
101 .storage
102 .key_storage()
103 .sign(&self.key_id, &digest, &self.public_key)
104 .await
105 .map_err(|e| match e.kind() {
106 KeyStorageErrorKind::KeyNotFound => SecretStorageError::KeyNotFound(e.to_string()),
107 KeyStorageErrorKind::RetryableIOFailure => SecretStorageError::StoreDisconnected(e.to_string()),
108 _ => SecretStorageError::Other(anyhow::anyhow!(e)),
109 })?;
110
111 let public_key = Signer::public_key(self).await?;
112
113 let iota_signature_bytes = [[public_key.flag()].as_slice(), &signature_bytes, public_key.as_ref()].concat();
114
115 Signature::from_bytes(&iota_signature_bytes)
116 .map_err(|e| SecretStorageError::Other(anyhow!("failed to create valid IOTA signature: {e}")))
117 }
118}