identity_storage/key_id_storage/
keytool.rs

1// Copyright 2020-2025 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use async_trait::async_trait;
5use identity_verification::jwu::encode_b64;
6use iota_interaction::types::base_types::IotaAddress;
7use iota_interaction::KeytoolStorage;
8
9use crate::KeyId;
10
11use super::KeyIdStorage;
12use super::KeyIdStorageError;
13use super::KeyIdStorageErrorKind;
14use super::KeyIdStorageResult;
15use super::MethodDigest;
16
17const IDENTITY_VERIFICATION_METHOD_PREFIX: &str = "identity__";
18
19#[cfg_attr(feature = "send-sync-storage", async_trait)]
20#[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
21impl KeyIdStorage for KeytoolStorage {
22  async fn insert_key_id(&self, method_digest: MethodDigest, key_id: KeyId) -> KeyIdStorageResult<()> {
23    let current_alias = key_id_to_alias(self, &key_id)?;
24    let new_alias = encode_method_digest(&method_digest);
25
26    self
27      .update_alias(&current_alias, Some(&new_alias))
28      .map_err(|e| KeyIdStorageError::new(KeyIdStorageErrorKind::RetryableIOFailure).with_source(e))
29  }
30
31  async fn get_key_id(&self, method_digest: &MethodDigest) -> KeyIdStorageResult<KeyId> {
32    let alias = encode_method_digest(method_digest);
33    let pk = self
34      .get_key_by_alias(&alias)
35      .map_err(|e| KeyIdStorageError::new(KeyIdStorageErrorKind::RetryableIOFailure).with_source(e))?
36      .ok_or(KeyIdStorageErrorKind::KeyIdNotFound)?;
37    let address = IotaAddress::from(&pk);
38
39    Ok(KeyId::new(address.to_string()))
40  }
41
42  async fn delete_key_id(&self, method_digest: &MethodDigest) -> KeyIdStorageResult<()> {
43    let alias = encode_method_digest(method_digest);
44    self
45      .update_alias(&alias, None)
46      .map_err(|e| KeyIdStorageError::new(KeyIdStorageErrorKind::Unspecified).with_source(e))
47  }
48}
49
50fn key_id_to_alias(keytool: &KeytoolStorage, key_id: &KeyId) -> KeyIdStorageResult<String> {
51  let address = key_id.as_str().parse().map_err(|e| {
52    KeyIdStorageError::new(KeyIdStorageErrorKind::Unspecified)
53      .with_source(e)
54      .with_custom_message("invalid key id. Key id must be an IOTA address")
55  })?;
56  let (_, alias) = keytool
57    .get_key(address)
58    .map_err(|e| KeyIdStorageError::new(KeyIdStorageErrorKind::RetryableIOFailure).with_source(e))?
59    .ok_or(KeyIdStorageErrorKind::KeyIdNotFound)?;
60
61  Ok(alias)
62}
63
64fn encode_method_digest(method_digest: &MethodDigest) -> String {
65  let b64_method_digest = encode_b64(method_digest.pack());
66  format!("{IDENTITY_VERIFICATION_METHOD_PREFIX}{b64_method_digest}")
67}