iop_keyvault/ed25519/
morpheus.rs1use super::*;
2use crate::multicipher::{MPrivateKey, MPublicKey};
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
8#[repr(i32)]
9pub enum DidKind {
10 Persona = 0,
13 Device = 1,
16 Group = 2,
19 Resource = 3,
22}
23
24impl DidKind {
25 pub fn bip32_path(self) -> bip32::Path {
27 Morpheus.bip32_path().append(ChildIndex::Hardened(self as i32))
28 }
29
30 pub fn all() -> &'static [DidKind] {
32 &[DidKind::Persona, DidKind::Device, DidKind::Group, DidKind::Resource]
33 }
34}
35
36impl FromStr for DidKind {
37 type Err = anyhow::Error;
38
39 fn from_str(input: &str) -> Result<Self> {
40 match input.to_lowercase().as_ref() {
41 "persona" => Ok(DidKind::Persona),
42 "device" => Ok(DidKind::Device),
43 "group" => Ok(DidKind::Group),
44 "resource" => Ok(DidKind::Resource),
45 _ => bail!("Unknown DID kind {}", input),
46 }
47 }
48}
49
50pub struct MorpheusSubtree;
52
53impl Subtree for MorpheusSubtree {
54 type Suite = Ed25519;
55
56 fn name(&self) -> &'static str {
57 "morpheus"
58 }
59 fn master(&self, seed: &Seed) -> EdExtPrivateKey {
60 Ed25519::master(seed)
61 }
62 fn key_id(&self, pk: &EdPublicKey) -> EdKeyId {
63 pk.key_id()
64 }
65}
66
67#[derive(Clone, Copy, Debug)]
68pub struct Morpheus;
70
71impl Morpheus {
72 pub const BIP43_PURPOSE: i32 = 0x1F4A4;
75
76 pub fn root(self, seed: &Seed) -> Result<MorpheusRoot> {
78 let node = Bip32.master(seed, &MorpheusSubtree).derive_hardened(Self::BIP43_PURPOSE)?;
79 Ok(MorpheusRoot { node })
80 }
81
82 pub fn bip32_path(self) -> bip32::Path {
84 Bip43Path::purpose(Morpheus::BIP43_PURPOSE).bip32_path()
85 }
86}
87
88#[derive(Clone, Debug)]
89pub struct MorpheusRoot {
91 node: Bip32Node<Ed25519>,
92}
93
94impl MorpheusRoot {
95 pub fn path(&self) -> &Morpheus {
98 &Morpheus
99 }
100
101 pub fn node(&self) -> &Bip32Node<ed25519::Ed25519> {
103 &self.node
104 }
105
106 pub fn admin(&self) -> MorpheusVaultAdmin {
108 MorpheusVaultAdmin { parent: self.clone() }
109 }
110
111 pub fn personas(&self) -> Result<MorpheusKind> {
113 self.kind(DidKind::Persona)
114 }
115
116 pub fn devices(&self) -> Result<MorpheusKind> {
118 self.kind(DidKind::Device)
119 }
120
121 pub fn groups(&self) -> Result<MorpheusKind> {
123 self.kind(DidKind::Group)
124 }
125
126 pub fn resources(&self) -> Result<MorpheusKind> {
128 self.kind(DidKind::Resource)
129 }
130
131 pub fn kind(&self, kind: DidKind) -> Result<MorpheusKind> {
133 let node = self.node.derive_hardened(kind as i32)?;
134 Ok(MorpheusKind { kind, node })
135 }
136}
137
138#[derive(Clone, Debug)]
139pub struct MorpheusVaultAdmin {
141 parent: MorpheusRoot,
142}
143
144impl MorpheusVaultAdmin {
145 pub fn path(&self) -> &Morpheus {
148 &Morpheus
149 }
150
151 pub fn node(&self) -> &Bip32Node<ed25519::Ed25519> {
153 self.parent.node()
154 }
155}
156
157#[derive(Clone, Debug)]
158pub struct MorpheusKindAdmin {
160 parent: MorpheusKind,
161}
162
163impl MorpheusKindAdmin {
164 pub fn path(&self) -> DidKind {
166 self.parent.path()
167 }
168
169 pub fn node(&self) -> &Bip32Node<ed25519::Ed25519> {
171 self.parent.node()
172 }
173}
174
175#[derive(Clone, Debug)]
177pub struct MorpheusKind {
178 kind: DidKind,
179 node: Bip32Node<Ed25519>,
180}
181
182impl MorpheusKind {
183 pub fn path(&self) -> DidKind {
185 self.kind
186 }
187
188 pub fn node(&self) -> &Bip32Node<ed25519::Ed25519> {
190 &self.node
191 }
192
193 pub fn admin(&self) -> MorpheusKindAdmin {
195 MorpheusKindAdmin { parent: self.clone() }
196 }
197
198 pub fn key(&self, idx: i32) -> Result<MorpheusPrivateKey> {
201 let path = MorpheusKeyPath { kind: self.kind, idx };
202 let node = self.node.derive_hardened(idx)?;
203 Ok(MorpheusPrivateKey { path, node })
204 }
205}
206
207#[derive(Clone, Debug)]
208pub struct MorpheusKeyPath {
211 kind: DidKind,
212 idx: i32,
213}
214
215impl MorpheusKeyPath {
216 pub fn kind(&self) -> DidKind {
218 self.kind
219 }
220
221 pub fn idx(&self) -> i32 {
223 self.idx
224 }
225
226 pub fn bip32_path(&self) -> bip32::Path {
228 self.kind.bip32_path().append(ChildIndex::Hardened(self.idx))
229 }
230}
231
232#[derive(Clone, Debug)]
233pub struct MorpheusPrivateKey {
235 path: MorpheusKeyPath,
236 node: Bip32Node<ed25519::Ed25519>,
237}
238
239impl MorpheusPrivateKey {
240 pub fn neuter(&self) -> MorpheusPublicKey {
242 let node = self.node.neuter();
243 MorpheusPublicKey { path: self.path.clone(), node }
244 }
245
246 pub fn path(&self) -> &MorpheusKeyPath {
248 &self.path
249 }
250
251 pub fn node(&self) -> &Bip32Node<ed25519::Ed25519> {
253 &self.node
254 }
255
256 pub fn private_key(&self) -> MPrivateKey {
258 MPrivateKey::from(self.node.private_key())
259 }
260}
261
262#[derive(Clone, Debug)]
263pub struct MorpheusPublicKey {
265 path: MorpheusKeyPath,
266 node: Bip32PublicNode<ed25519::Ed25519>,
267}
268
269impl MorpheusPublicKey {
270 pub fn path(&self) -> &MorpheusKeyPath {
272 &self.path
273 }
274
275 pub fn node(&self) -> &Bip32PublicNode<ed25519::Ed25519> {
277 &self.node
278 }
279
280 pub fn public_key(&self) -> MPublicKey {
282 MPublicKey::from(self.node.public_key())
283 }
284}
285
286#[cfg(test)]
287mod test {
288 use super::*;
289
290 #[test]
292 fn api_usage() -> Result<()> {
293 let seed = Bip39::new().phrase(Seed::DEMO_PHRASE)?.password(Seed::PASSWORD);
294 let morpheus = Morpheus.root(&seed)?;
295 assert_eq!(morpheus.path().bip32_path(), "m/128164'".parse()?);
296 assert_eq!(morpheus.node().path(), &"m/128164'".parse()?);
297
298 let vault_admin = morpheus.admin();
299 assert_eq!(vault_admin.path().bip32_path(), "m/128164'".parse()?);
300 assert_eq!(vault_admin.node().path(), &"m/128164'".parse()?);
301
302 let groups = morpheus.groups()?;
303 assert_eq!(groups.path(), DidKind::Group);
304 assert_eq!(groups.path().bip32_path(), "m/128164'/2'".parse()?);
305 assert_eq!(groups.node().path(), &"m/128164'/2'".parse()?);
306
307 let groups_admin = groups.admin();
308 assert_eq!(groups_admin.path().bip32_path(), "m/128164'/2'".parse()?);
309 assert_eq!(groups_admin.node().path(), &"m/128164'/2'".parse()?);
310
311 let group0 = groups.key(0)?;
312 assert_eq!(group0.path().bip32_path(), "m/128164'/2'/0'".parse()?);
313 assert_eq!(group0.node().path(), &"m/128164'/2'/0'".parse()?);
314 assert_eq!(group0.path().kind(), DidKind::Group);
315 assert_eq!(group0.path().idx(), 0);
316
317 let group0_pub = group0.neuter();
318 assert_eq!(group0_pub.path().bip32_path(), "m/128164'/2'/0'".parse()?);
319 assert_eq!(group0_pub.node().path(), &"m/128164'/2'/0'".parse()?);
320 let group0_ed_pk = group0_pub.node().public_key();
321 assert_eq!(
322 hex::encode(group0_ed_pk.to_bytes()),
323 "10634a63a4ab84d40170079f2c538d969d4693de9e399f32b8bd29e4583e2e42"
324 );
325 let group0_pk = group0_pub.public_key();
326 assert_eq!(group0_pk.to_string(), "pez26yLWBBR78PjHvMVWZWJK8BC8fQ4KyUMmvNVdpvdKCN5");
327
328 let group0_ed_sk = group0.node().private_key();
329 assert_eq!(
330 hex::encode(group0_ed_sk.to_bytes()),
331 "9f3dbcd653e8825e765c5c2c40b105e73f1eb088ec18247550ff12f2a0733947"
332 );
333 let group0_sk = group0.private_key();
334 assert_eq!(
335 group0_sk.public_key().to_string(),
336 "pez26yLWBBR78PjHvMVWZWJK8BC8fQ4KyUMmvNVdpvdKCN5"
337 );
338
339 Ok(())
345 }
346}