Skip to main content

ma_did/
key.rs

1use ed25519_dalek::{Signer, SigningKey as Ed25519SigningKey, VerifyingKey};
2use rand_core::OsRng;
3use x25519_dalek::{PublicKey as X25519PublicKey, StaticSecret};
4
5use crate::{
6    did::Did,
7    error::{MaError, Result},
8    multiformat::{public_key_multibase_decode, public_key_multibase_encode},
9};
10
11pub const ASSERTION_METHOD_KEY_TYPE: &str = "Multikey";
12pub const KEY_AGREEMENT_KEY_TYPE: &str = "Multikey";
13
14// https://github.com/multiformats/multicodec/blob/master/table.csv
15pub const X25519_PUB_CODEC: u64 = 0xec;
16pub const ED25519_PUB_CODEC: u64 = 0xed;
17pub const EDDSA_SIG_CODEC: u64 = 0xd0ed;
18
19/// Ed25519 signing key for document proofs and message signatures.
20///
21/// # Examples
22///
23/// ```
24/// use ma_did::{Did, SigningKey};
25///
26/// let did = Did::new_url("k51qzi5uqu5dj9807pbuod1pplf0vxh8m4lfy3ewl9qbm2s8dsf9ugdf9gedhr", None::<String>).unwrap();
27/// let key = SigningKey::generate(did).unwrap();
28///
29/// let signature = key.sign(b"hello world");
30/// assert!(!signature.is_empty());
31///
32/// // Export and reimport private key bytes
33/// let bytes = key.private_key_bytes();
34/// let did2 = Did::new_url("k51qzi5uqu5dj9807pbuod1pplf0vxh8m4lfy3ewl9qbm2s8dsf9ugdf9gedhr", None::<String>).unwrap();
35/// let restored = SigningKey::from_private_key_bytes(did2, bytes).unwrap();
36/// assert_eq!(key.public_key_multibase, restored.public_key_multibase);
37/// ```
38#[derive(Clone)]
39pub struct SigningKey {
40    pub did: Did,
41    pub key_type: String,
42    signing_key: Ed25519SigningKey,
43    pub public_key_multibase: String,
44}
45
46impl SigningKey {
47    pub fn generate(did: Did) -> Result<Self> {
48        let signing_key = Ed25519SigningKey::generate(&mut OsRng);
49        let public_key_multibase =
50            public_key_multibase_encode(ED25519_PUB_CODEC, signing_key.verifying_key().as_bytes())?;
51
52        Ok(Self {
53            did,
54            key_type: ASSERTION_METHOD_KEY_TYPE.to_string(),
55            signing_key,
56            public_key_multibase,
57        })
58    }
59
60    pub fn sign(&self, data: &[u8]) -> Vec<u8> {
61        self.signing_key.sign(data).to_bytes().to_vec()
62    }
63
64    pub fn verifying_key(&self) -> VerifyingKey {
65        self.signing_key.verifying_key()
66    }
67
68    pub fn private_key_bytes(&self) -> [u8; ed25519_dalek::SECRET_KEY_LENGTH] {
69        self.signing_key.to_bytes()
70    }
71
72    pub fn from_private_key_bytes(
73        did: Did,
74        private_key: [u8; ed25519_dalek::SECRET_KEY_LENGTH],
75    ) -> Result<Self> {
76        let signing_key = Ed25519SigningKey::from_bytes(&private_key);
77        let public_key_multibase =
78            public_key_multibase_encode(ED25519_PUB_CODEC, signing_key.verifying_key().as_bytes())?;
79
80        Ok(Self {
81            did,
82            key_type: ASSERTION_METHOD_KEY_TYPE.to_string(),
83            signing_key,
84            public_key_multibase,
85        })
86    }
87
88    pub fn validate(&self) -> Result<()> {
89        Did::validate(&self.did.id())?;
90
91        if self.key_type != ASSERTION_METHOD_KEY_TYPE {
92            return Err(MaError::InvalidKeyType);
93        }
94
95        let (codec, key_bytes) = public_key_multibase_decode(&self.public_key_multibase)?;
96        if codec != ED25519_PUB_CODEC {
97            return Err(MaError::InvalidMulticodec {
98                expected: ED25519_PUB_CODEC,
99                actual: codec,
100            });
101        }
102
103        if key_bytes.len() != ed25519_dalek::PUBLIC_KEY_LENGTH {
104            return Err(MaError::InvalidKeyLength {
105                expected: ed25519_dalek::PUBLIC_KEY_LENGTH,
106                actual: key_bytes.len(),
107            });
108        }
109
110        Ok(())
111    }
112}
113
114/// X25519 encryption key for envelope key agreement.
115///
116/// Used to compute shared secrets via Diffie-Hellman for encrypting
117/// and decrypting [`Envelope`](crate::Envelope) payloads.
118///
119/// # Examples
120///
121/// ```
122/// use ma_did::{Did, EncryptionKey};
123///
124/// let did = Did::new_url("k51qzi5uqu5dj9807pbuod1pplf0vxh8m4lfy3ewl9qbm2s8dsf9ugdf9gedhr", None::<String>).unwrap();
125/// let key = EncryptionKey::generate(did).unwrap();
126///
127/// // Export and reimport
128/// let bytes = key.private_key_bytes();
129/// let did2 = Did::new_url("k51qzi5uqu5dj9807pbuod1pplf0vxh8m4lfy3ewl9qbm2s8dsf9ugdf9gedhr", None::<String>).unwrap();
130/// let restored = EncryptionKey::from_private_key_bytes(did2, bytes).unwrap();
131/// assert_eq!(key.public_key_multibase, restored.public_key_multibase);
132/// ```
133#[derive(Clone)]
134pub struct EncryptionKey {
135    pub did: Did,
136    pub key_type: String,
137    private_key: StaticSecret,
138    pub public_key: X25519PublicKey,
139    pub public_key_multibase: String,
140}
141
142impl EncryptionKey {
143    pub fn generate(did: Did) -> Result<Self> {
144        let private_key = StaticSecret::random_from_rng(OsRng);
145        let public_key = X25519PublicKey::from(&private_key);
146        let public_key_multibase =
147            public_key_multibase_encode(X25519_PUB_CODEC, public_key.as_bytes())?;
148
149        Ok(Self {
150            did,
151            key_type: KEY_AGREEMENT_KEY_TYPE.to_string(),
152            private_key,
153            public_key,
154            public_key_multibase,
155        })
156    }
157
158    pub fn shared_secret(&self, other: &X25519PublicKey) -> [u8; 32] {
159        self.private_key.diffie_hellman(other).to_bytes()
160    }
161
162    pub fn private_key_bytes(&self) -> [u8; 32] {
163        self.private_key.to_bytes()
164    }
165
166    pub fn from_private_key_bytes(did: Did, private_key: [u8; 32]) -> Result<Self> {
167        let private_key = StaticSecret::from(private_key);
168        let public_key = X25519PublicKey::from(&private_key);
169        let public_key_multibase =
170            public_key_multibase_encode(X25519_PUB_CODEC, public_key.as_bytes())?;
171
172        Ok(Self {
173            did,
174            key_type: KEY_AGREEMENT_KEY_TYPE.to_string(),
175            private_key,
176            public_key,
177            public_key_multibase,
178        })
179    }
180
181    pub fn validate(&self) -> Result<()> {
182        Did::validate(&self.did.id())?;
183
184        if self.key_type != KEY_AGREEMENT_KEY_TYPE {
185            return Err(MaError::InvalidKeyType);
186        }
187
188        let (codec, key_bytes) = public_key_multibase_decode(&self.public_key_multibase)?;
189        if codec != X25519_PUB_CODEC {
190            return Err(MaError::InvalidMulticodec {
191                expected: X25519_PUB_CODEC,
192                actual: codec,
193            });
194        }
195
196        if key_bytes.len() != 32 {
197            return Err(MaError::InvalidKeyLength {
198                expected: 32,
199                actual: key_bytes.len(),
200            });
201        }
202
203        Ok(())
204    }
205}