From bc6e24d1da899a2adf767dac90381fc920776b2a Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com> Date: Fri, 18 Mar 2022 10:39:16 +0100 Subject: [PATCH] Move DID Document proof outside metadata (#728) * move proof outside metadata * remove proof from bindings * update proof in method spec * create new document example in method spec --- bindings/wasm/docs/api-reference.md | 31 +++++++------------ bindings/wasm/src/did/wasm_document.rs | 8 ++--- .../wasm/src/did/wasm_document_metadata.rs | 11 ------- .../docs/specs/did/iota_did_method_spec.md | 27 ++++++++-------- .../src/diff/diff_iota_document.rs | 6 ++-- .../src/diff/diff_iota_document_metadata.rs | 2 -- .../src/document/iota_document.rs | 22 ++++++++----- .../src/document/iota_document_metadata.rs | 5 +-- identity-iota/src/chain/document_chain.rs | 9 +----- 9 files changed, 49 insertions(+), 72 deletions(-) diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md index 0ccc3c2dc6..ddd3b826c4 100644 --- a/bindings/wasm/docs/api-reference.md +++ b/bindings/wasm/docs/api-reference.md @@ -192,8 +192,8 @@ publishing to the Tangle. * [.updateDocumentUnchecked(document)](#Account+updateDocumentUnchecked) ⇒ Promise.<void> * [.fetchState()](#Account+fetchState) ⇒ Promise.<void> * [.deleteMethod(options)](#Account+deleteMethod) ⇒ Promise.<void> - * [.createService(options)](#Account+createService) ⇒ Promise.<void> * [.createMethod(options)](#Account+createMethod) ⇒ Promise.<void> + * [.createService(options)](#Account+createService) ⇒ Promise.<void> * [.attachMethodRelationships(options)](#Account+attachMethodRelationships) ⇒ Promise.<void> * [.detachMethodRelationships(options)](#Account+detachMethodRelationships) ⇒ Promise.<void> @@ -368,27 +368,27 @@ Deletes a verification method if the method exists. | --- | --- | | options | DeleteMethodOptions | - + -### account.createService(options) ⇒ Promise.<void> -Adds a new Service to the DID Document. +### account.createMethod(options) ⇒ Promise.<void> +Adds a new verification method to the DID document. **Kind**: instance method of [Account](#Account) | Param | Type | | --- | --- | -| options | CreateServiceOptions | +| options | CreateMethodOptions | - + -### account.createMethod(options) ⇒ Promise.<void> -Adds a new verification method to the DID document. +### account.createService(options) ⇒ Promise.<void> +Adds a new Service to the DID Document. **Kind**: instance method of [Account](#Account) | Param | Type | | --- | --- | -| options | CreateMethodOptions | +| options | CreateServiceOptions | @@ -1388,7 +1388,7 @@ Deserializes a `DiffMessage` from a JSON object. * [.setMetadataUpdated(timestamp)](#Document+setMetadataUpdated) * [.metadataPreviousMessageId()](#Document+metadataPreviousMessageId) ⇒ string * [.setMetadataPreviousMessageId(value)](#Document+setMetadataPreviousMessageId) - * [.metadataProof()](#Document+metadataProof) ⇒ any + * [.proof()](#Document+proof) ⇒ any * [.toJSON()](#Document+toJSON) ⇒ any * [.clone()](#Document+clone) ⇒ [Document](#Document) * _static_ @@ -1843,9 +1843,9 @@ Sets the previous integration chain message id. | --- | --- | | value | string | - + -### document.metadataProof() ⇒ any +### document.proof() ⇒ any Returns a copy of the `proof` object. **Kind**: instance method of [Document](#Document) @@ -2011,7 +2011,6 @@ Additional attributes related to an IOTA DID Document. * [.previousMessageId](#DocumentMetadata+previousMessageId) ⇒ string * [.created()](#DocumentMetadata+created) ⇒ [Timestamp](#Timestamp) * [.updated()](#DocumentMetadata+updated) ⇒ [Timestamp](#Timestamp) - * [.proof()](#DocumentMetadata+proof) ⇒ any * [.clone()](#DocumentMetadata+clone) ⇒ [DocumentMetadata](#DocumentMetadata) @@ -2029,12 +2028,6 @@ Returns a copy of the timestamp of when the DID document was created. ### documentMetadata.updated() ⇒ [Timestamp](#Timestamp) Returns a copy of the timestamp of the last DID document update. -**Kind**: instance method of [DocumentMetadata](#DocumentMetadata) - - -### documentMetadata.proof() ⇒ any -Returns a copy of the reference to the `proof`. - **Kind**: instance method of [DocumentMetadata](#DocumentMetadata) diff --git a/bindings/wasm/src/did/wasm_document.rs b/bindings/wasm/src/did/wasm_document.rs index eda6d85701..60678b9c7a 100644 --- a/bindings/wasm/src/did/wasm_document.rs +++ b/bindings/wasm/src/did/wasm_document.rs @@ -646,10 +646,10 @@ impl WasmDocument { } /// Returns a copy of the `proof` object. - #[wasm_bindgen(js_name = metadataProof)] - pub fn metadata_proof(&self) -> Result { - // TODO: implement proper bindings for the proof - match &self.0.metadata.proof { + #[wasm_bindgen] + pub fn proof(&self) -> Result { + // TODO: implement proper bindings for the proof. + match &self.0.proof { Some(proof) => JsValue::from_serde(proof).wasm_result(), None => Ok(JsValue::NULL), } diff --git a/bindings/wasm/src/did/wasm_document_metadata.rs b/bindings/wasm/src/did/wasm_document_metadata.rs index d198498714..59138b2199 100644 --- a/bindings/wasm/src/did/wasm_document_metadata.rs +++ b/bindings/wasm/src/did/wasm_document_metadata.rs @@ -5,8 +5,6 @@ use identity::iota_core::IotaDocumentMetadata; use wasm_bindgen::prelude::*; use crate::common::WasmTimestamp; -use crate::error::Result; -use crate::error::WasmResult; // ============================================================================= // ============================================================================= @@ -36,15 +34,6 @@ impl WasmDocumentMetadata { pub fn previous_message_id(&self) -> String { self.0.previous_message_id.to_string() } - - /// Returns a copy of the reference to the `proof`. - #[wasm_bindgen] - pub fn proof(&self) -> Result { - match &self.0.proof { - Some(proof) => JsValue::from_serde(proof).wasm_result(), - None => Ok(JsValue::NULL), - } - } } impl_wasm_clone!(WasmDocumentMetadata, DocumentMetadata); diff --git a/documentation/docs/specs/did/iota_did_method_spec.md b/documentation/docs/specs/did/iota_did_method_spec.md index fe845c5c7b..bb83ab5679 100644 --- a/documentation/docs/specs/did/iota_did_method_spec.md +++ b/documentation/docs/specs/did/iota_did_method_spec.md @@ -113,32 +113,31 @@ An Integration (Int) DID message MUST contain both a valid DID Document and a [D * The first DID Document in the chain MUST contain a `verificationMethod` that contains a public key that, when hashed using the `Blake2b-256` hashing function, equals the tag section of the DID. This prevents the creation of conflicting entry messages of the chain by adversaries. * An Integration DID message must be published to an IOTA Tangle on an index that is generated by the `BLAKE2b-256` of the public key, created in the [generation](#generation) event, encoded in `hex`. * Integration DID messages SHOULD contain all cumulative changes from the Diff Chain associated to the last Integration Chain message. Any changes added in the Diff Chain that are not added to the new Integration DID message will be lost. -* The DID Document Metadata MUST include at least the following attributes: - * `previousMessageId` (REQUIRED): This field provides an immutable link to the previous integration DID message that is used for basic ordering of the DID messages, creating a chain. The value of `previousMessageId` MUST be a string that contains an IOTA MessageId from the previous DID message it updates, which MUST reference an integration DID message. The field SHOULD be omitted if the DID message is the start of the Int chain, otherwise the field is REQUIRED. Read the [Previous Message Id](#previous-message-id) section for more information. - * `proof` (REQUIRED): This field provides a cryptographic proof on the message that proves ownership over the DID Document. The value of the `proof` object MUST contain an object as defined by [Anatomy of the Proof object](#anatomy-of-the-proof-object). +* The DID Document Metadata MUST include a `previousMessageId` attribute. This field provides an immutable link to the previous integration DID message that is used for basic ordering of the DID messages, creating a chain. The value of `previousMessageId` MUST be a string that contains an IOTA MessageId from the previous DID message it updates, which MUST reference an integration DID message. The field SHOULD be omitted if the DID message is the start of the Int chain, otherwise the field is REQUIRED. Read the [Previous Message Id](#previous-message-id) section for more information. +* The DID Document MUST include a `proof` attribute. This field provides a cryptographic proof on the message that proves ownership over the DID Document. The value of the `proof` object MUST contain an object as defined by [Anatomy of the Proof object](#anatomy-of-the-proof-object). Example of an Integration DID Message: ```json { "doc": { - "id": "did:iota:X7U84ez4YeaLwpfdnhdgFyPLa53twvAuMSYdRQas54e", + "id": "did:iota:ERtmNv3hYnWU7fZMGKpMLy7QBJqPovCSYyewtoHUGmpf", "capabilityInvocation": [ { - "id": "did:iota:X7U84ez4YeaLwpfdnhdgFyPLa53twvAuMSYdRQas54e#sign-0", - "controller": "did:iota:X7U84ez4YeaLwpfdnhdgFyPLa53twvAuMSYdRQas54e", + "id": "did:iota:ERtmNv3hYnWU7fZMGKpMLy7QBJqPovCSYyewtoHUGmpf#sign-0", + "controller": "did:iota:ERtmNv3hYnWU7fZMGKpMLy7QBJqPovCSYyewtoHUGmpf", "type": "Ed25519VerificationKey2018", - "publicKeyMultibase": "zCqNmbG7e4GMohTndkStNXUQGHFD5YusnwWpFdpyWFWH3" + "publicKeyMultibase": "zETX79R6G5fkTMZhHXaCMhjC3Xpx3NLJVSNurat8Ls9Tn" } ] }, "meta": { - "created": "2022-01-21T09:50:09Z", - "updated": "2022-01-21T09:50:09Z", - "proof": { - "type": "JcsEd25519Signature2020", - "verificationMethod": "#sign-0", - "signatureValue": "4pzMWzn19oqibHXqEdLr4EEHygs7QF2mMdvEhSMPiCVejEZGL4Vi5BGnmrJjMqKyNr6c6sSd3EXKoYxAuC2YiZNF" - } + "created": "2022-03-18T06:59:50Z", + "updated": "2022-03-18T06:59:50Z" + }, + "proof": { + "type": "JcsEd25519Signature2020", + "verificationMethod": "did:iota:ERtmNv3hYnWU7fZMGKpMLy7QBJqPovCSYyewtoHUGmpf#sign-0", + "signatureValue": "278R6WyoG359VjnGm2GJK6XAjBNh6AM59BXJmjfRQerVQMTG3EjWGXw64CKgGKvVBbP98QMVUw1YXBbuGuDbJW6A" } } ``` diff --git a/identity-iota-core/src/diff/diff_iota_document.rs b/identity-iota-core/src/diff/diff_iota_document.rs index acf4c29c41..ca8f456d7d 100644 --- a/identity-iota-core/src/diff/diff_iota_document.rs +++ b/identity-iota-core/src/diff/diff_iota_document.rs @@ -55,7 +55,8 @@ impl Diff for IotaDocument { .transpose()? .unwrap_or_else(|| self.metadata.clone()); - Ok(IotaDocument::from((document, metadata))) + // NOTE: proof intentionally excluded + Ok(IotaDocument::from((document, metadata, None))) } fn from_diff(diff: Self::Type) -> Result { @@ -71,7 +72,8 @@ impl Diff for IotaDocument { .transpose()? .ok_or_else(|| Error::convert("Missing field `metadata`"))?; - Ok(IotaDocument::from((document, metadata))) + // NOTE: proof intentionally excluded + Ok(IotaDocument::from((document, metadata, None))) } fn into_diff(self) -> Result { diff --git a/identity-iota-core/src/diff/diff_iota_document_metadata.rs b/identity-iota-core/src/diff/diff_iota_document_metadata.rs index 111bf147fc..e3d70d5ca4 100644 --- a/identity-iota-core/src/diff/diff_iota_document_metadata.rs +++ b/identity-iota-core/src/diff/diff_iota_document_metadata.rs @@ -96,7 +96,6 @@ impl Diff for IotaDocumentMetadata { created, updated, previous_message_id, - proof: None, // NOTE: proof intentionally excluded. properties, }) } @@ -130,7 +129,6 @@ impl Diff for IotaDocumentMetadata { created, updated, previous_message_id, - proof: None, // NOTE: proof intentionally excluded. properties, }) } diff --git a/identity-iota-core/src/document/iota_document.rs b/identity-iota-core/src/document/iota_document.rs index 976e74946e..2824e04640 100644 --- a/identity-iota-core/src/document/iota_document.rs +++ b/identity-iota-core/src/document/iota_document.rs @@ -65,6 +65,8 @@ pub struct IotaDocument { pub(crate) document: IotaCoreDocument, #[serde(rename = "meta")] pub metadata: IotaDocumentMetadata, + #[serde(skip_serializing_if = "Option::is_none")] + pub proof: Option, } impl TryMethod for IotaDocument { @@ -160,7 +162,7 @@ impl IotaDocument { .capability_invocation(MethodRef::Embed(method)) .build()?; let metadata: IotaDocumentMetadata = IotaDocumentMetadata::new(); - Ok(Self::from((document, metadata))) + Ok(Self::from((document, metadata, None))) } /// Returns whether the given [`MethodType`] can be used to sign document updates. @@ -616,9 +618,13 @@ impl IotaDocument { impl<'a, 'b, 'c> IotaDocument {} -impl From<(IotaCoreDocument, IotaDocumentMetadata)> for IotaDocument { - fn from((document, metadata): (IotaCoreDocument, IotaDocumentMetadata)) -> Self { - Self { document, metadata } +impl From<(IotaCoreDocument, IotaDocumentMetadata, Option)> for IotaDocument { + fn from((document, metadata, proof): (IotaCoreDocument, IotaDocumentMetadata, Option)) -> Self { + Self { + document, + metadata, + proof, + } } } @@ -636,19 +642,19 @@ impl Display for IotaDocument { impl TrySignature for IotaDocument { fn signature(&self) -> Option<&Signature> { - self.metadata.proof.as_ref() + self.proof.as_ref() } } impl TrySignatureMut for IotaDocument { fn signature_mut(&mut self) -> Option<&mut Signature> { - self.metadata.proof.as_mut() + self.proof.as_mut() } } impl SetSignature for IotaDocument { fn set_signature(&mut self, signature: Signature) { - self.metadata.proof = Some(signature) + self.proof = Some(signature) } } @@ -724,7 +730,7 @@ mod tests { .build() .unwrap(); - IotaDocument::from((document, metadata)) + IotaDocument::from((document, metadata, None)) } fn generate_testkey() -> KeyPair { diff --git a/identity-iota-core/src/document/iota_document_metadata.rs b/identity-iota-core/src/document/iota_document_metadata.rs index 94b5475f9b..a25c69f61f 100644 --- a/identity-iota-core/src/document/iota_document_metadata.rs +++ b/identity-iota-core/src/document/iota_document_metadata.rs @@ -9,7 +9,7 @@ use core::fmt::Result as FmtResult; use identity_core::common::Object; use identity_core::common::Timestamp; use identity_core::convert::FmtJson; -use identity_core::crypto::Signature; + use serde::Deserialize; use serde::Serialize; @@ -27,8 +27,6 @@ pub struct IotaDocumentMetadata { skip_serializing_if = "MessageId::is_null" )] pub previous_message_id: MessageId, - #[serde(skip_serializing_if = "Option::is_none")] - pub proof: Option, #[serde(flatten)] pub properties: Object, } @@ -42,7 +40,6 @@ impl IotaDocumentMetadata { created: now, updated: now, previous_message_id: MessageId::null(), - proof: None, properties: Object::default(), } } diff --git a/identity-iota/src/chain/document_chain.rs b/identity-iota/src/chain/document_chain.rs index 38ac45f083..05a5e573e0 100644 --- a/identity-iota/src/chain/document_chain.rs +++ b/identity-iota/src/chain/document_chain.rs @@ -200,14 +200,7 @@ mod test { keys.push(keypair); assert_eq!( - chain - .current() - .document - .metadata - .proof - .as_ref() - .unwrap() - .verification_method(), + chain.current().document.proof.as_ref().unwrap().verification_method(), format!("#{}", IotaDocument::DEFAULT_METHOD_FRAGMENT) ); assert_eq!(chain.current().diff_message_id, MessageId::null());