sidetree_client/
operations.rs1use crate::Error;
2use crate::{
3 did::*,
4 multihash::{canonicalize_then_double_hash_then_encode, canonicalize_then_hash_then_encode},
5 secp256k1::KeyPair,
6 Delta, Patch, SuffixData,
7};
8use serde::{ser::SerializeMap, Serialize};
9
10#[derive(Debug, Clone)]
11pub enum Operation {
12 Create(SuffixData, Delta),
13}
14
15#[derive(Serialize, Debug, Clone, Default)]
16pub struct OperationInput {
17 signing_key: Option<PublicKey>,
18 update_key: Option<JsonWebKey>,
19 recovery_key: Option<JsonWebKey>,
20}
21
22#[derive(Serialize, Debug, Clone)]
23pub struct OperationOutput {
24 operation_request: Operation,
25 did_suffix: String,
26 update_key: JsonWebKey,
27 recovery_key: JsonWebKey,
28 signing_key: PublicKey,
29}
30
31impl Serialize for Operation {
32 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
33 where
34 S: serde::Serializer,
35 {
36 let mut map = serializer.serialize_map(None)?;
37
38 match self {
39 Operation::Create(suffix_data, delta) => {
40 map.serialize_entry("type", "create")?;
41 map.serialize_entry("suffixData", suffix_data)?;
42 map.serialize_entry("delta", delta)?;
43 }
44 }
45
46 map.end()
47 }
48}
49
50pub fn create() -> Result<OperationOutput, Error> {
51 let update_key = KeyPair::random();
52 let recovery_key = KeyPair::random();
53
54 let signing_key = KeyPair::random();
55 let signing_key_public = signing_key.to_public_key("key-1".into(), Some(Purpose::all()));
56
57 let document = Document {
58 public_keys: vec![signing_key_public.clone()],
59 services: vec![],
60 };
61
62 let patches = vec![Patch::Replace(document)];
63
64 let mut update_key_public: JsonWebKey = (&update_key).into();
65 update_key_public.d = None;
66
67 let delta = Delta {
68 update_commitment: canonicalize_then_double_hash_then_encode(&update_key_public).unwrap(),
69 patches,
70 };
71
72 let delta_hash = canonicalize_then_hash_then_encode(&delta, crate::multihash::HashAlgorithm::Sha256);
73
74 let mut recovery_key_public: JsonWebKey = (&recovery_key).into();
75 recovery_key_public.d = None;
76
77 let suffix_data = SuffixData {
78 delta_hash,
79 recovery_commitment: canonicalize_then_double_hash_then_encode(&recovery_key_public).unwrap(),
80 data_type: None,
81 };
82
83 let did_suffix = compute_unique_suffix(&suffix_data);
84 let operation = Operation::Create(suffix_data, delta);
85
86 Ok(OperationOutput {
87 update_key: (&update_key).into(),
88 recovery_key: (&recovery_key).into(),
89 signing_key: signing_key_public,
90 operation_request: operation,
91 did_suffix,
92 })
93}
94
95#[cfg(test)]
96mod test {
97 use super::{create, Operation};
98
99 #[test]
100 fn generate_create_operation() {
101 let result = create().unwrap();
102 let json = serde_json::to_string_pretty(&result.operation_request);
103
104 assert!(matches!(json, Result::Ok(_)));
105 assert!(matches!(result.operation_request, Operation::Create(_, _)));
106 assert!(result.did_suffix.len() > 0);
107
108 println!("did:ion:{}", result.did_suffix);
109 println!("{}", json.unwrap());
110 }
111}