identity_storage/key_id_storage/
method_digest.rs

1// Copyright 2020-2023 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use identity_verification::MethodData;
5use identity_verification::VerificationMethod;
6use seahash::SeaHasher;
7use std::fmt::Display;
8use std::hash::Hasher;
9
10use super::KeyIdStorageError;
11
12/// Error that may occur when constructing a [`MethodDigest`].
13pub type MethodDigestConstructionError = identity_core::common::SingleStructError<MethodDigestConstructionErrorKind>;
14
15/// Characterization of the underlying cause of a [`MethodDigestConstructionError`].
16#[derive(Debug)]
17#[non_exhaustive]
18pub enum MethodDigestConstructionErrorKind {
19  /// Caused by a missing id on a verification method.
20  ///
21  /// This error should be impossible but exists for safety reasons.
22  MissingIdFragment,
23  /// Caused by a failure to decode a method's [key material](identity_verification::MethodData).
24  DataDecodingFailure,
25}
26
27impl Display for MethodDigestConstructionErrorKind {
28  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29    f.write_str("method digest construction failure: ")?;
30    match self {
31      MethodDigestConstructionErrorKind::MissingIdFragment => f.write_str("missing id fragment"),
32      MethodDigestConstructionErrorKind::DataDecodingFailure => f.write_str("data decoding failure"),
33    }
34  }
35}
36
37/// Unique identifier of a [`VerificationMethod`].
38#[derive(Clone, Debug, PartialEq, Eq, Hash)]
39pub struct MethodDigest {
40  /// Version of hashing.
41  version: u8,
42  /// Hash value.
43  value: u64,
44}
45
46impl MethodDigest {
47  /// Creates a new [`MethodDigest`].
48  pub fn new(verification_method: &VerificationMethod) -> Result<Self, MethodDigestConstructionError> {
49    // Method digest version 0 formula: SeaHash(<fragment><JWK thumbprint if JWK else decoded public key>)
50    use MethodDigestConstructionErrorKind::*;
51    let mut hasher: SeaHasher = SeaHasher::new();
52    let fragment: &str = verification_method.id().fragment().ok_or(MissingIdFragment)?;
53    let method_data: &MethodData = verification_method.data();
54
55    hasher.write(fragment.as_bytes());
56
57    match method_data {
58      MethodData::PublicKeyJwk(jwk) => hasher.write(jwk.thumbprint_sha256().as_ref()),
59      _ => hasher.write(
60        &method_data
61          .try_decode()
62          .map_err(|err| MethodDigestConstructionError::new(DataDecodingFailure).with_source(err))?,
63      ),
64    };
65
66    let key_hash: u64 = hasher.finish();
67
68    Ok(Self {
69      version: 0,
70      value: key_hash,
71    })
72  }
73
74  /// Packs [`MethodDigest`] into bytes.
75  pub fn pack(&self) -> Vec<u8> {
76    let mut pack: Vec<u8> = vec![self.version];
77    pack.append(&mut self.value.to_le_bytes().to_vec());
78    pack
79  }
80
81  /// Unpacks bytes into [`MethodDigest`].
82  pub fn unpack(bytes: Vec<u8>) -> crate::key_id_storage::KeyIdStorageResult<Self> {
83    if bytes.len() != 9 {
84      return Err(KeyIdStorageError::new(super::KeyIdStorageErrorKind::SerializationError));
85    }
86    let version: u8 = bytes[0];
87    if version != 0 {
88      return Err(KeyIdStorageError::new(super::KeyIdStorageErrorKind::SerializationError));
89    }
90    let value_le_bytes: [u8; 8] = bytes[1..9]
91      .try_into()
92      .map_err(|_| KeyIdStorageError::new(super::KeyIdStorageErrorKind::SerializationError))?;
93    let value: u64 = u64::from_le_bytes(value_le_bytes);
94    Ok(Self { version, value })
95  }
96}
97
98#[cfg(test)]
99mod test {
100  use crate::key_id_storage::KeyIdStorageError;
101  use crate::key_id_storage::KeyIdStorageErrorKind;
102  use identity_core::convert::FromJson;
103  use identity_core::json;
104  use identity_verification::VerificationMethod;
105  use serde_json::Value;
106
107  use super::MethodDigest;
108
109  #[test]
110  fn hash() {
111    // These values should be tested in the bindings too.
112    let a: Value = json!(
113      {
114        "id": "did:example:HHoh9NQC9AUsK15Jyyq53VTujxEUizKDXRXd7zbT1B5u#frag_1",
115        "controller": "did:example:HHoh9NQC9AUsK15Jyyq53VTujxEUizKDXRXd7zbT1B5u",
116        "type": "Ed25519VerificationKey2018",
117        "publicKeyMultibase": "zHHoh9NQC9AUsK15Jyyq53VTujxEUizKDXRXd7zbT1B5u"
118      }
119    );
120    let verification_method: VerificationMethod = VerificationMethod::from_json_value(a).unwrap();
121    let method_digest: MethodDigest = MethodDigest::new(&verification_method).unwrap();
122    let method_digest_expected: MethodDigest = MethodDigest {
123      version: 0,
124      value: 9634551232492878922,
125    };
126    assert_eq!(method_digest, method_digest_expected);
127
128    let packed: Vec<u8> = method_digest.pack();
129    let packed_expected: Vec<u8> = vec![0, 74, 60, 10, 199, 76, 205, 180, 133];
130    assert_eq!(packed, packed_expected);
131  }
132
133  #[test]
134  fn pack() {
135    let verification_method: VerificationMethod = crate::storage::tests::test_utils::create_verification_method();
136    let method_digest: MethodDigest = MethodDigest::new(&verification_method).unwrap();
137    let packed: Vec<u8> = method_digest.pack();
138    let method_digest_unpacked: MethodDigest = MethodDigest::unpack(packed).unwrap();
139    assert_eq!(method_digest, method_digest_unpacked);
140  }
141
142  #[test]
143  fn unpack() {
144    let packed: Vec<u8> = vec![0, 255, 212, 82, 63, 57, 19, 134, 193];
145    let method_digest_unpacked: MethodDigest = MethodDigest::unpack(packed).unwrap();
146    let method_digest_expected: MethodDigest = MethodDigest {
147      version: 0,
148      value: 13944854432795776255,
149    };
150    assert_eq!(method_digest_unpacked, method_digest_expected);
151  }
152
153  #[test]
154  fn invalid_unpack() {
155    let packed: Vec<u8> = vec![1, 255, 212, 82, 63, 57, 19, 134, 193];
156    let method_digest_unpacked = MethodDigest::unpack(packed).unwrap_err();
157    let _expected_error = KeyIdStorageError::new(KeyIdStorageErrorKind::SerializationError);
158    assert!(matches!(method_digest_unpacked, _expected_error));
159
160    // Vec size > 9.
161    let packed: Vec<u8> = vec![1, 255, 212, 82, 63, 57, 19, 134, 193, 200];
162    let method_digest_unpacked = MethodDigest::unpack(packed).unwrap_err();
163    let _expected_error = KeyIdStorageError::new(KeyIdStorageErrorKind::SerializationError);
164    assert!(matches!(method_digest_unpacked, _expected_error));
165
166    // Vec size < 9.
167    let packed: Vec<u8> = vec![1, 255, 212, 82, 63, 57, 19, 134];
168    let method_digest_unpacked = MethodDigest::unpack(packed).unwrap_err();
169    let _expected_error = KeyIdStorageError::new(KeyIdStorageErrorKind::SerializationError);
170    assert!(matches!(method_digest_unpacked, _expected_error));
171
172    // Vec size 0;
173    let packed: Vec<u8> = vec![];
174    let method_digest_unpacked = MethodDigest::unpack(packed).unwrap_err();
175    let _expected_error = KeyIdStorageError::new(KeyIdStorageErrorKind::SerializationError);
176    assert!(matches!(method_digest_unpacked, _expected_error));
177  }
178}