did_ion/sidetree/operation/
create.rs

1use std::marker::PhantomData;
2
3use serde::{Deserialize, Serialize};
4
5use crate::sidetree::{json_canonicalization_scheme, DIDSuffix, Delta, Sidetree, SidetreeDID};
6
7use super::{PartialVerificationError, SidetreeOperation};
8
9/// Sidetree DID Create operation
10///
11/// ### References
12/// - [Sidetree §11.1 Create](https://identity.foundation/sidetree/spec/v1.0.0/#create)
13/// - [Sidetree REST API §1.2.1 Create](https://identity.foundation/sidetree/api/#create)
14#[derive(Debug, Serialize, Deserialize, Clone)]
15#[serde(rename_all = "camelCase")]
16#[serde(deny_unknown_fields)]
17pub struct CreateOperation {
18    pub suffix_data: SuffixData,
19    pub delta: Delta,
20}
21
22impl CreateOperation {
23    /// Construct a [Long-Form Sidetree DID][lfdu] from a [Create Operation][CreateOperation]
24    ///
25    /// [lfdu]: https://identity.foundation/sidetree/spec/v1.0.0/#long-form-did-uris
26    pub fn to_sidetree_did<S: Sidetree>(&self) -> SidetreeDID<S> {
27        let op_json = json_canonicalization_scheme(self).unwrap();
28        // .context("Canonicalize Create Operation")?;
29        let op_string = S::data_encoding_scheme(op_json.as_bytes());
30
31        let did_suffix = S::serialize_suffix_data(&self.suffix_data);
32        // .context("Serialize DID Suffix Data")?;
33        SidetreeDID::Long {
34            did_suffix,
35            create_operation_data: op_string,
36            _marker: PhantomData,
37        }
38    }
39}
40
41impl SidetreeOperation for CreateOperation {
42    type PartiallyVerifiedForm = PartiallyVerifiedCreateOperation;
43
44    fn partial_verify<S: Sidetree>(
45        self,
46    ) -> Result<PartiallyVerifiedCreateOperation, PartialVerificationError> {
47        let did: SidetreeDID<S> = self.to_sidetree_did();
48        let did_suffix = DIDSuffix::from(did);
49        let delta_string = json_canonicalization_scheme(&self.delta).unwrap();
50        let delta_hash = S::hash(delta_string.as_bytes());
51
52        if delta_hash != self.suffix_data.delta_hash {
53            return Err(PartialVerificationError::DeltaHashMismatch);
54        }
55
56        Ok(PartiallyVerifiedCreateOperation {
57            did_suffix,
58            r#type: self.suffix_data.r#type,
59            recovery_commitment: self.suffix_data.recovery_commitment,
60            anchor_origin: self.suffix_data.anchor_origin,
61            hashed_delta: self.delta,
62        })
63    }
64}
65
66/// Partially verified DID Create operation
67///
68/// Converted from [CreateOperation].
69#[allow(dead_code)]
70#[derive(Debug, Clone)]
71pub struct PartiallyVerifiedCreateOperation {
72    pub did_suffix: DIDSuffix,
73    pub r#type: Option<String>,
74    pub recovery_commitment: String,
75    pub anchor_origin: Option<String>,
76    pub hashed_delta: Delta,
77}
78
79/// [Create Operation Suffix Data Object][data]
80///
81/// [data]: https://identity.foundation/sidetree/spec/v1.0.0/#create-suffix-data-object
82#[derive(Debug, Serialize, Deserialize, Clone)]
83#[serde(rename_all = "camelCase")]
84pub struct SuffixData {
85    /// Implementation-defined type property
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub r#type: Option<String>,
88
89    /// Delta Hash
90    ///
91    /// [Hash](Sidetree::hash) of canonicalized [Create Operation Delta Object](Delta).
92    pub delta_hash: String,
93
94    /// [Recovery commitment](https://identity.foundation/sidetree/spec/v1.0.0/#recovery-commitment)
95    ///
96    /// Generated in step 2 of the [Create](https://identity.foundation/sidetree/spec/v1.0.0/#create) process.
97    pub recovery_commitment: String,
98
99    /// Anchor Origin
100    ///
101    /// Implementation-defined identifier for most recent anchor for the DID
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub anchor_origin: Option<String>,
104    // TODO: extensible by method
105}