Skip to main content

co_identity/types/
private_identity.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 1io BRANDGUARDIAN GmbH
3
4use super::didcomm::context::DidCommPublicContext;
5use crate::{DidCommPrivateContext, Identity};
6use std::{fmt::Debug, sync::Arc};
7
8/// Private identity representation.
9pub trait PrivateIdentity: Identity {
10	/// Sign data and return the signature as bytes (only signature without input data).
11	fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SignError>;
12
13	/// Private DIDComm context.
14	fn didcomm_private(&self) -> Option<DidCommPrivateContext>;
15
16	fn try_didcomm_private(&self) -> Result<DidCommPrivateContext, anyhow::Error> {
17		self.didcomm_private()
18			.ok_or(anyhow::anyhow!("unsupported identity: no private didcomm context: {}", self.identity()))
19	}
20
21	fn boxed(self) -> PrivateIdentityBox
22	where
23		Self: Sized + Clone + Send + Sync + 'static,
24	{
25		PrivateIdentityBox::new(self)
26	}
27}
28
29/// Dynamic Private Identity.
30#[derive(Clone)]
31pub struct PrivateIdentityBox {
32	identity: Arc<dyn PrivateIdentity + Send + Sync + 'static>,
33}
34impl PartialEq for PrivateIdentityBox {
35	fn eq(&self, other: &Self) -> bool {
36		self.identity.identity() == other.identity.identity()
37	}
38}
39impl PrivateIdentityBox {
40	pub fn new<I: PrivateIdentity + Send + Sync + 'static>(identity: I) -> Self {
41		Self { identity: Arc::new(identity) }
42	}
43}
44impl Debug for PrivateIdentityBox {
45	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46		f.debug_struct("PrivateIdentity")
47			.field("did", &self.identity.identity())
48			.finish()
49	}
50}
51impl Identity for PrivateIdentityBox {
52	fn identity(&self) -> &str {
53		self.identity.identity()
54	}
55
56	fn public_key(&self) -> Option<Vec<u8>> {
57		self.identity.public_key()
58	}
59
60	fn verify(&self, signature: &[u8], data: &[u8], public_key: Option<&[u8]>) -> bool {
61		self.identity.verify(signature, data, public_key)
62	}
63
64	fn didcomm_public(&self) -> Option<DidCommPublicContext> {
65		self.identity.didcomm_public()
66	}
67
68	fn networks(&self) -> std::collections::BTreeSet<co_primitives::Network> {
69		self.identity.networks()
70	}
71}
72impl PrivateIdentity for PrivateIdentityBox {
73	fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SignError> {
74		self.identity.sign(data)
75	}
76
77	fn didcomm_private(&self) -> Option<DidCommPrivateContext> {
78		self.identity.didcomm_private()
79	}
80
81	fn boxed(self) -> PrivateIdentityBox
82	where
83		Self: Sized + Clone + Send + Sync + 'static,
84	{
85		self.clone()
86	}
87}
88impl From<&PrivateIdentityBox> for String {
89	fn from(value: &PrivateIdentityBox) -> Self {
90		value.identity().to_string()
91	}
92}
93
94#[derive(Debug, thiserror::Error)]
95pub enum SignError {
96	/// Unauthorized error.
97	/// Ususally this means that this identity has no private key.
98	#[error("Unauthorized")]
99	Unauthorized,
100
101	/// Invalid argument has been supplied.
102	#[error("Invalid argument")]
103	InvalidArgument(#[source] anyhow::Error),
104
105	/// Other error
106	#[error("Signature failed")]
107	Other(#[source] anyhow::Error),
108}