identity_storage/key_storage/
memstore.rs1use core::fmt::Debug;
5use std::collections::HashMap;
6use std::fmt::Display;
7use std::str::FromStr;
8
9use async_trait::async_trait;
10use fastcrypto::ed25519::Ed25519KeyPair;
11use fastcrypto::ed25519::Ed25519Signature;
12use fastcrypto::traits::KeyPair as _;
13use fastcrypto::traits::Signer;
14use identity_verification::jose::jwk::EdCurve;
15use identity_verification::jose::jwk::Jwk;
16use identity_verification::jose::jwk::JwkType;
17use identity_verification::jose::jws::JwsAlgorithm;
18use identity_verification::jwk::BlsCurve;
19use identity_verification::jwk::FromJwk as _;
20use identity_verification::jwk::ToJwk as _;
21use rand::distributions::DistString;
22use shared::Shared;
23use tokio::sync::RwLockReadGuard;
24use tokio::sync::RwLockWriteGuard;
25
26use super::jwk_gen_output::JwkGenOutput;
27use super::KeyId;
28use super::KeyStorageError;
29use super::KeyStorageErrorKind;
30use super::KeyStorageResult;
31use super::KeyType;
32use crate::key_storage::JwkStorage;
33
34type JwkKeyStore = HashMap<KeyId, Jwk>;
36
37#[derive(Debug)]
39pub struct JwkMemStore {
40 jwk_store: Shared<JwkKeyStore>,
41}
42
43impl JwkMemStore {
44 pub fn new() -> Self {
46 Self {
47 jwk_store: Shared::new(HashMap::new()),
48 }
49 }
50
51 pub async fn count(&self) -> usize {
53 self.jwk_store.read().await.keys().count()
54 }
55}
56
57#[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
59#[cfg_attr(feature = "send-sync-storage", async_trait)]
60impl JwkStorage for JwkMemStore {
61 async fn generate(&self, key_type: KeyType, alg: JwsAlgorithm) -> KeyStorageResult<JwkGenOutput> {
62 let key_type: MemStoreKeyType = MemStoreKeyType::try_from(&key_type)?;
63
64 check_key_alg_compatibility(key_type, &alg)?;
65
66 let keypair = match key_type {
67 MemStoreKeyType::Ed25519 => Ed25519KeyPair::generate(&mut rand::thread_rng()),
68 other => {
69 return Err(
70 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
71 .with_custom_message(format!("{other} is not supported")),
72 );
73 }
74 };
75
76 let kid: KeyId = random_key_id();
77
78 let mut jwk: Jwk = keypair.to_jwk().map_err(|err| {
79 KeyStorageError::new(KeyStorageErrorKind::Unspecified)
80 .with_custom_message("could not convert `Ed25519KeyPair` to `Jwk`")
81 .with_source(err)
82 })?;
83 jwk.set_alg(alg.name());
84 jwk.set_kid(jwk.thumbprint_sha256_b64());
85 let public_jwk: Jwk = jwk.to_public().expect("should only panic if kty == oct");
86
87 let mut jwk_store: RwLockWriteGuard<'_, JwkKeyStore> = self.jwk_store.write().await;
88 jwk_store.insert(kid.clone(), jwk);
89
90 Ok(JwkGenOutput::new(kid, public_jwk))
91 }
92
93 async fn insert(&self, jwk: Jwk) -> KeyStorageResult<KeyId> {
94 let key_type = MemStoreKeyType::try_from(&jwk)?;
95
96 if !jwk.is_private() {
97 return Err(
98 KeyStorageError::new(KeyStorageErrorKind::Unspecified)
99 .with_custom_message("expected a Jwk with all private key components set"),
100 );
101 }
102
103 match jwk.alg() {
104 Some(alg) => {
105 let alg: JwsAlgorithm = JwsAlgorithm::from_str(alg)
106 .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::UnsupportedSignatureAlgorithm).with_source(err))?;
107 check_key_alg_compatibility(key_type, &alg)?;
108 }
109 None => {
110 return Err(
111 KeyStorageError::new(KeyStorageErrorKind::UnsupportedSignatureAlgorithm)
112 .with_custom_message("expected a Jwk with an `alg` parameter"),
113 );
114 }
115 }
116
117 if jwk.alg().is_none() {
118 return Err(
119 KeyStorageError::new(KeyStorageErrorKind::UnsupportedSignatureAlgorithm)
120 .with_custom_message("expected a Jwk with an `alg` parameter"),
121 );
122 }
123
124 let key_id: KeyId = random_key_id();
125
126 let mut jwk_store: RwLockWriteGuard<'_, JwkKeyStore> = self.jwk_store.write().await;
127
128 jwk_store.insert(key_id.clone(), jwk);
129
130 Ok(key_id)
131 }
132
133 async fn sign(&self, key_id: &KeyId, data: &[u8], public_key: &Jwk) -> KeyStorageResult<Vec<u8>> {
134 let jwk_store: RwLockReadGuard<'_, JwkKeyStore> = self.jwk_store.read().await;
135
136 let alg = public_key
138 .alg()
139 .ok_or(KeyStorageErrorKind::UnsupportedSignatureAlgorithm)
140 .and_then(|alg_str| {
141 JwsAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedSignatureAlgorithm)
142 })?;
143
144 match alg {
146 JwsAlgorithm::EdDSA => {
147 let okp_params = public_key.try_okp_params().map_err(|err| {
148 KeyStorageError::new(KeyStorageErrorKind::Unspecified)
149 .with_custom_message(format!("expected a Jwk with Okp params in order to sign with {alg}"))
150 .with_source(err)
151 })?;
152 if okp_params.crv != EdCurve::Ed25519.name() {
153 return Err(
154 KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!(
155 "expected Jwk with Okp {} crv in order to sign with {alg}",
156 EdCurve::Ed25519
157 )),
158 );
159 }
160 }
161 other => {
162 return Err(
163 KeyStorageError::new(KeyStorageErrorKind::UnsupportedSignatureAlgorithm)
164 .with_custom_message(format!("{other} is not supported")),
165 );
166 }
167 };
168
169 let jwk: &Jwk = jwk_store
171 .get(key_id)
172 .ok_or_else(|| KeyStorageError::new(KeyStorageErrorKind::KeyNotFound))?;
173 let secret_key = Ed25519KeyPair::from_jwk(jwk).map_err(|err| {
174 KeyStorageError::new(KeyStorageErrorKind::Unspecified)
175 .with_custom_message("could not convert `Jwk` to `Ed25519KeyPair`")
176 .with_source(err)
177 })?;
178 Ok(Signer::<Ed25519Signature>::sign(&secret_key, data).as_ref().to_vec())
179 }
180
181 async fn delete(&self, key_id: &KeyId) -> KeyStorageResult<()> {
182 let mut jwk_store: RwLockWriteGuard<'_, JwkKeyStore> = self.jwk_store.write().await;
183
184 jwk_store
185 .remove(key_id)
186 .map(|_| ())
187 .ok_or_else(|| KeyStorageError::new(KeyStorageErrorKind::KeyNotFound))
188 }
189
190 async fn exists(&self, key_id: &KeyId) -> KeyStorageResult<bool> {
191 let jwk_store: RwLockReadGuard<'_, JwkKeyStore> = self.jwk_store.read().await;
192 Ok(jwk_store.contains_key(key_id))
193 }
194}
195
196#[derive(Debug, Copy, Clone)]
197enum MemStoreKeyType {
198 Ed25519,
199 BLS12381G2,
200}
201
202impl JwkMemStore {
203 const ED25519_KEY_TYPE_STR: &'static str = "Ed25519";
204 pub const ED25519_KEY_TYPE: KeyType = KeyType::from_static_str(Self::ED25519_KEY_TYPE_STR);
206
207 const BLS12381G2_KEY_TYPE_STR: &'static str = "BLS12381G2";
208 pub const BLS12381G2_KEY_TYPE: KeyType = KeyType::from_static_str(Self::BLS12381G2_KEY_TYPE_STR);
210}
211
212impl MemStoreKeyType {
213 const fn name(&self) -> &'static str {
214 match self {
215 MemStoreKeyType::Ed25519 => JwkMemStore::ED25519_KEY_TYPE_STR,
216 MemStoreKeyType::BLS12381G2 => JwkMemStore::BLS12381G2_KEY_TYPE_STR,
217 }
218 }
219}
220
221impl Display for MemStoreKeyType {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 f.write_str(self.name())
224 }
225}
226
227impl TryFrom<&KeyType> for MemStoreKeyType {
228 type Error = KeyStorageError;
229
230 fn try_from(value: &KeyType) -> Result<Self, Self::Error> {
231 match value.as_str() {
232 JwkMemStore::ED25519_KEY_TYPE_STR => Ok(MemStoreKeyType::Ed25519),
233 JwkMemStore::BLS12381G2_KEY_TYPE_STR => Ok(MemStoreKeyType::BLS12381G2),
234 _ => Err(KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)),
235 }
236 }
237}
238
239impl TryFrom<&Jwk> for MemStoreKeyType {
240 type Error = KeyStorageError;
241
242 fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
243 match jwk.kty() {
244 JwkType::Okp => {
245 let okp_params = jwk.try_okp_params().map_err(|err| {
246 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
247 .with_custom_message("expected Okp parameters for a JWK with `kty` Okp")
248 .with_source(err)
249 })?;
250 match okp_params.try_ed_curve().map_err(|err| {
251 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
252 .with_custom_message("only Ed curves are supported for signing")
253 .with_source(err)
254 })? {
255 EdCurve::Ed25519 => Ok(MemStoreKeyType::Ed25519),
256 curve => Err(
257 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
258 .with_custom_message(format!("{curve} not supported")),
259 ),
260 }
261 }
262 JwkType::Ec => {
263 let ec_params = jwk.try_ec_params().map_err(|err| {
264 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
265 .with_custom_message("expected EC parameters for a JWK with `kty` Ec")
266 .with_source(err)
267 })?;
268 match ec_params.try_bls_curve().map_err(|err| {
269 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
270 .with_custom_message("only Ed curves are supported for signing")
271 .with_source(err)
272 })? {
273 BlsCurve::BLS12381G2 => Ok(MemStoreKeyType::BLS12381G2),
274 curve => Err(
275 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
276 .with_custom_message(format!("{curve} not supported")),
277 ),
278 }
279 }
280 other => Err(
281 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
282 .with_custom_message(format!("Jwk `kty` {other} not supported")),
283 ),
284 }
285 }
286}
287
288impl Default for JwkMemStore {
289 fn default() -> Self {
290 Self::new()
291 }
292}
293
294fn random_key_id() -> KeyId {
296 KeyId::new(rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 32))
297}
298
299fn check_key_alg_compatibility(key_type: MemStoreKeyType, alg: &JwsAlgorithm) -> KeyStorageResult<()> {
301 match (key_type, alg) {
302 (MemStoreKeyType::Ed25519, JwsAlgorithm::EdDSA) => Ok(()),
303 (key_type, alg) => Err(
304 KeyStorageError::new(crate::key_storage::KeyStorageErrorKind::KeyAlgorithmMismatch)
305 .with_custom_message(format!("`cannot use key type `{key_type}` with algorithm `{alg}`")),
306 ),
307 }
308}
309
310#[cfg(feature = "jpt-bbs-plus")]
311mod bbs_plus_impl {
312 use std::str::FromStr as _;
313
314 use crate::key_storage::bls::encode_bls_jwk;
315 use crate::key_storage::bls::expand_bls_jwk;
316 use crate::key_storage::bls::generate_bbs_keypair;
317 use crate::key_storage::bls::sign_bbs;
318 use crate::key_storage::bls::update_bbs_signature;
319 use crate::JwkGenOutput;
320 use crate::JwkMemStore;
321 use crate::JwkStorageBbsPlusExt;
322 use crate::KeyId;
323 use crate::KeyStorageError;
324 use crate::KeyStorageErrorKind;
325 use crate::KeyStorageResult;
326 use crate::KeyType;
327 use crate::ProofUpdateCtx;
328 use async_trait::async_trait;
329 use identity_verification::jwk::BlsCurve;
330 use identity_verification::jwk::Jwk;
331 use jsonprooftoken::jpa::algs::ProofAlgorithm;
332
333 use super::random_key_id;
334
335 #[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))]
337 #[cfg_attr(feature = "send-sync-storage", async_trait)]
338 impl JwkStorageBbsPlusExt for JwkMemStore {
339 async fn generate_bbs(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult<JwkGenOutput> {
340 if key_type != JwkMemStore::BLS12381G2_KEY_TYPE {
341 return Err(
342 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
343 .with_custom_message(format!("unsupported key type {key_type}")),
344 );
345 }
346
347 let (private_key, public_key) = generate_bbs_keypair(alg)?;
348 let (jwk, public_jwk) = encode_bls_jwk(&private_key, &public_key, alg);
349
350 let kid: KeyId = random_key_id();
351 let mut jwk_store = self.jwk_store.write().await;
352 jwk_store.insert(kid.clone(), jwk);
353
354 Ok(JwkGenOutput::new(kid, public_jwk))
355 }
356
357 async fn sign_bbs(
358 &self,
359 key_id: &KeyId,
360 data: &[Vec<u8>],
361 header: &[u8],
362 public_key: &Jwk,
363 ) -> KeyStorageResult<Vec<u8>> {
364 let jwk_store = self.jwk_store.read().await;
365
366 let alg = public_key
368 .alg()
369 .and_then(|alg_str| ProofAlgorithm::from_str(alg_str).ok())
370 .ok_or(KeyStorageErrorKind::UnsupportedProofAlgorithm)?;
371
372 if !public_key
374 .try_ec_params()
375 .map(|ec| ec.crv == BlsCurve::BLS12381G2.to_string())
376 .unwrap_or(false)
377 {
378 return Err(
379 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
380 .with_custom_message(format!("expected a key from the {} curve", BlsCurve::BLS12381G2)),
381 );
382 }
383
384 let jwk: &Jwk = jwk_store.get(key_id).ok_or(KeyStorageErrorKind::KeyNotFound)?;
386 let (sk, pk) = expand_bls_jwk(jwk)?;
387
388 sign_bbs(alg, data, &sk.expect("jwk is private"), &pk, header)
389 }
390
391 async fn update_signature(
392 &self,
393 key_id: &KeyId,
394 public_key: &Jwk,
395 signature: &[u8],
396 ctx: ProofUpdateCtx,
397 ) -> KeyStorageResult<Vec<u8>> {
398 let jwk_store = self.jwk_store.read().await;
399
400 let alg = public_key
402 .alg()
403 .ok_or(KeyStorageErrorKind::UnsupportedProofAlgorithm)
404 .and_then(|alg_str| {
405 ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm)
406 })?;
407
408 if !public_key
410 .try_ec_params()
411 .map(|ec| ec.crv == BlsCurve::BLS12381G2.to_string())
412 .unwrap_or(false)
413 {
414 return Err(
415 KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)
416 .with_custom_message(format!("expected a key from the {} curve", BlsCurve::BLS12381G2)),
417 );
418 }
419
420 let jwk = jwk_store.get(key_id).ok_or(KeyStorageErrorKind::KeyNotFound)?;
422 let sk = expand_bls_jwk(jwk)?.0.expect("jwk is private");
423
424 update_bbs_signature(alg, signature, &sk, &ctx)
426 }
427 }
428}
429pub(crate) mod shared {
430 use core::fmt::Debug;
431 use core::fmt::Formatter;
432 use tokio::sync::RwLock;
433 use tokio::sync::RwLockReadGuard;
434 use tokio::sync::RwLockWriteGuard;
435
436 #[derive(Default)]
437 pub(crate) struct Shared<T>(RwLock<T>);
438
439 impl<T> Shared<T> {
440 pub(crate) fn new(data: T) -> Self {
441 Self(RwLock::new(data))
442 }
443
444 pub(crate) async fn read(&self) -> RwLockReadGuard<'_, T> {
445 self.0.read().await
446 }
447
448 pub(crate) async fn write(&self) -> RwLockWriteGuard<'_, T> {
449 self.0.write().await
450 }
451 }
452
453 impl<T: Debug> Debug for Shared<T> {
454 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
455 Debug::fmt(&self.0, f)
456 }
457 }
458}
459
460#[cfg(test)]
461mod tests {
462 use crate::key_storage::tests::utils::generate_ed25519;
463 use fastcrypto::ed25519::Ed25519PublicKey;
464 use fastcrypto::traits::ToFromBytes as _;
465 use fastcrypto::traits::VerifyingKey as _;
466 use identity_verification::jose::jwk::EcCurve;
467 use identity_verification::jose::jwk::JwkParamsEc;
468 use identity_verification::jwk::FromJwk as _;
469
470 use super::*;
471
472 #[tokio::test]
473 async fn generate_and_sign() {
474 let test_msg: &[u8] = b"test";
475 let store: JwkMemStore = JwkMemStore::new();
476
477 let JwkGenOutput { key_id, jwk } = store
478 .generate(JwkMemStore::ED25519_KEY_TYPE, JwsAlgorithm::EdDSA)
479 .await
480 .unwrap();
481
482 let signature = store.sign(&key_id, test_msg, &jwk.to_public().unwrap()).await.unwrap();
483
484 let public_key = Ed25519PublicKey::from_jwk(&jwk).unwrap();
485 let signature = Ed25519Signature::from_bytes(&signature).unwrap();
486
487 assert!(public_key.verify(test_msg, &signature).is_ok());
488 assert!(store.exists(&key_id).await.unwrap());
489 store.delete(&key_id).await.unwrap();
490 }
491
492 #[tokio::test]
493 async fn insert() {
494 let store: JwkMemStore = JwkMemStore::new();
495
496 let key_pair = generate_ed25519();
497 let mut jwk: Jwk = key_pair.to_jwk().unwrap();
498
499 let err = store.insert(jwk.clone()).await.unwrap_err();
501 assert!(matches!(err.kind(), KeyStorageErrorKind::UnsupportedSignatureAlgorithm));
502
503 jwk.set_alg(JwsAlgorithm::EdDSA.name());
505 store.insert(jwk.clone()).await.unwrap();
506
507 let err = store.insert(jwk.to_public().unwrap()).await.unwrap_err();
509 assert!(matches!(err.kind(), KeyStorageErrorKind::Unspecified))
510 }
511
512 #[tokio::test]
513 async fn exists() {
514 let store: JwkMemStore = JwkMemStore::new();
515 assert!(!store.exists(&KeyId::new("non-existent-id")).await.unwrap());
516 }
517
518 #[tokio::test]
519 async fn incompatible_key_type() {
520 let store: JwkMemStore = JwkMemStore::new();
521
522 let mut ec_params = JwkParamsEc::new();
523 ec_params.crv = EcCurve::P256.name().to_string();
524 ec_params.x = String::new();
525 ec_params.y = String::new();
526 ec_params.d = Some(String::new());
527 let jwk_ec = Jwk::from_params(ec_params);
528
529 let err = store.insert(jwk_ec).await.unwrap_err();
530 assert!(matches!(err.kind(), KeyStorageErrorKind::UnsupportedKeyType));
531 }
532
533 #[tokio::test]
534 async fn incompatible_key_alg() {
535 let store: JwkMemStore = JwkMemStore::new();
536
537 let key_pair = generate_ed25519();
538 let mut jwk: Jwk = key_pair.to_jwk().unwrap();
539 jwk.set_alg(JwsAlgorithm::ES256.name());
540
541 let err = store.insert(jwk.clone()).await.unwrap_err();
543 assert!(matches!(err.kind(), KeyStorageErrorKind::KeyAlgorithmMismatch));
544 }
545}