Skip to main content

sidetree_client/
operations.rs

1use 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}