diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md index e17fcf0c2c..e9e3a65a85 100644 --- a/bindings/wasm/docs/api-reference.md +++ b/bindings/wasm/docs/api-reference.md @@ -189,9 +189,10 @@ working with storage backed DID documents.

StateMetadataEncoding
-
StatusPurpose
-

Purpose of a StatusList2021.

-
+
MethodRelationship
+
+
CredentialStatus
+
SubjectHolderRelationship

Declares how credential subjects must relate to the presentation holder.

See also the Subject-Holder Relationship section of the specification.

@@ -215,6 +216,9 @@ This variant is the default.

FirstError

Return after the first error occurs.

+
StatusPurpose
+

Purpose of a StatusList2021.

+
StatusCheck

Controls validation behaviour when checking whether or not a credential has been revoked by its credentialStatus.

@@ -232,15 +236,17 @@ This variant is the default.

SkipAll

Skip all status checks.

-
CredentialStatus
-
-
MethodRelationship
-
## Functions
+
encodeB64(data)string
+

Encode the given bytes in url-safe base64.

+
+
decodeB64(data)Uint8Array
+

Decode the given url-safe base64-encoded slice into its raw bytes.

+
verifyEd25519(alg, signingInput, decodedSignature, publicKey)

Verify a JWS signature secured with the EdDSA algorithm and curve Ed25519.

This function is useful when one is composing a IJwsVerifier that delegates @@ -249,12 +255,6 @@ This variant is the default.

This function does not check whether alg = EdDSA in the protected header. Callers are expected to assert this prior to calling the function.

-
encodeB64(data)string
-

Encode the given bytes in url-safe base64.

-
-
decodeB64(data)Uint8Array
-

Decode the given url-safe base64-encoded slice into its raw bytes.

-
start()

Initializes the console error panic hook for better error messages

@@ -5233,7 +5233,6 @@ Note: digests are created using the sha-256 algorithm. * [SdObjectEncoder](#SdObjectEncoder) * [new SdObjectEncoder(object)](#new_SdObjectEncoder_new) * [.conceal(path, [salt])](#SdObjectEncoder+conceal) ⇒ [Disclosure](#Disclosure) - * [.concealArrayEntry(path, element_index, [salt])](#SdObjectEncoder+concealArrayEntry) ⇒ [Disclosure](#Disclosure) * [.addSdAlgProperty()](#SdObjectEncoder+addSdAlgProperty) * [.encodeToString()](#SdObjectEncoder+encodeToString) ⇒ string * [.toString()](#SdObjectEncoder+toString) ⇒ string @@ -5257,43 +5256,35 @@ Creates a new `SdObjectEncoder` with `sha-256` hash function. Substitutes a value with the digest of its disclosure. If no salt is provided, the disclosure will be created with a random salt value. -The value of the key specified in `path` will be concealed. E.g. for path -`["claim", "subclaim"]` the value of `claim.subclaim` will be concealed. +`path` indicates the pointer to the value that will be concealed using the syntax of +[JSON pointer](https://datatracker.ietf.org/doc/html/rfc6901). -## Error -`InvalidPath` if path is invalid or the path slice is empty. -`DataTypeMismatch` if existing SD format is invalid. +For the following object: -## Note -Use `concealArrayEntry` for values in arrays. + ``` +{ + "id": "did:value", + "claim1": { + "abc": true + }, + "claim2": ["val_1", "val_2"] +} +``` -**Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) +Path "/id" conceals `"id": "did:value"` +Path "/claim1/abc" conceals `"abc": true` +Path "/claim2/0" conceals `val_1` +``` -| Param | Type | -| --- | --- | -| path | Array.<string> | -| [salt] | string \| undefined | - - - -### sdObjectEncoder.concealArrayEntry(path, element_index, [salt]) ⇒ [Disclosure](#Disclosure) -Substitutes a value within an array with the digest of its disclosure. -If no salt is provided, the disclosure will be created with random salt value. - -`path` is used to specify the array in the object, while `element_index` specifies -the index of the element to be concealed (index start at 0). - -## Error -`InvalidPath` if path is invalid or the path slice is empty. -`DataTypeMismatch` if existing SD format is invalid. -`IndexOutofBounds` if `element_index` is out of bounds. +## Errors +* `InvalidPath` if pointer is invalid. +* `DataTypeMismatch` if existing SD format is invalid. **Kind**: instance method of [SdObjectEncoder](#SdObjectEncoder) | Param | Type | | --- | --- | -| path | Array.<string> | -| element_index | number | +| path | string | | [salt] | string \| undefined | @@ -5337,7 +5328,7 @@ If path is an empty slice, decoys will be added to the top level. | Param | Type | | --- | --- | -| path | Array.<string> | +| path | string | | number_of_decoys | number | @@ -5506,7 +5497,7 @@ A parsed [StatusList2021Credential](https://www.w3.org/TR/2023/WD-vc-status-list * [new StatusList2021Credential(credential)](#new_StatusList2021Credential_new) * _instance_ * [.id()](#StatusList2021Credential+id) ⇒ string - * [.setCredentialStatus(credential, index, value)](#StatusList2021Credential+setCredentialStatus) ⇒ [StatusList2021Entry](#StatusList2021Entry) + * [.setCredentialStatus(credential, index, revoked_or_suspended)](#StatusList2021Credential+setCredentialStatus) ⇒ [StatusList2021Entry](#StatusList2021Entry) * [.purpose()](#StatusList2021Credential+purpose) ⇒ [StatusPurpose](#StatusPurpose) * [.entry(index)](#StatusList2021Credential+entry) ⇒ [CredentialStatus](#CredentialStatus) * [.clone()](#StatusList2021Credential+clone) ⇒ [StatusList2021Credential](#StatusList2021Credential) @@ -5530,7 +5521,7 @@ Creates a new [StatusList2021Credential](#StatusList2021Credential). **Kind**: instance method of [StatusList2021Credential](#StatusList2021Credential) -### statusList2021Credential.setCredentialStatus(credential, index, value) ⇒ [StatusList2021Entry](#StatusList2021Entry) +### statusList2021Credential.setCredentialStatus(credential, index, revoked_or_suspended) ⇒ [StatusList2021Entry](#StatusList2021Entry) Sets the given credential's status using the `index`-th entry of this status list. Returns the created `credentialStatus`. @@ -5540,7 +5531,7 @@ Returns the created `credentialStatus`. | --- | --- | | credential | [Credential](#Credential) | | index | number | -| value | boolean | +| revoked_or_suspended | boolean | @@ -5700,7 +5691,7 @@ Attempts to build a valid [StatusList2021Credential](#StatusList2021Credential) * [.id()](#StatusList2021Entry+id) ⇒ string * [.purpose()](#StatusList2021Entry+purpose) ⇒ [StatusPurpose](#StatusPurpose) * [.index()](#StatusList2021Entry+index) ⇒ number - * [.status_list_credential()](#StatusList2021Entry+status_list_credential) ⇒ string + * [.statusListCredential()](#StatusList2021Entry+statusListCredential) ⇒ string * [.toStatus()](#StatusList2021Entry+toStatus) ⇒ Status * [.clone()](#StatusList2021Entry+clone) ⇒ [StatusList2021Entry](#StatusList2021Entry) * [.toJSON()](#StatusList2021Entry+toJSON) ⇒ any @@ -5738,9 +5729,9 @@ Returns the purpose of this entry. Returns the index of this entry. **Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) - + -### statusList2021Entry.status\_list\_credential() ⇒ string +### statusList2021Entry.statusListCredential() ⇒ string Returns the referenced [StatusList2021Credential](#StatusList2021Credential)'s url. **Kind**: instance method of [StatusList2021Entry](#StatusList2021Entry) @@ -6117,11 +6108,13 @@ Deserializes an instance from a JSON object. ## StateMetadataEncoding **Kind**: global variable - + -## StatusPurpose -Purpose of a [StatusList2021](#StatusList2021). +## MethodRelationship +**Kind**: global variable + +## CredentialStatus **Kind**: global variable @@ -6167,6 +6160,12 @@ Return all errors that occur during validation. ## FirstError Return after the first error occurs. +**Kind**: global variable + + +## StatusPurpose +Purpose of a [StatusList2021](#StatusList2021). + **Kind**: global variable @@ -6199,14 +6198,28 @@ Validate the status if supported, skip any unsupported Skip all status checks. **Kind**: global variable - + -## CredentialStatus -**Kind**: global variable - +## encodeB64(data) ⇒ string +Encode the given bytes in url-safe base64. + +**Kind**: global function + +| Param | Type | +| --- | --- | +| data | Uint8Array | + + + +## decodeB64(data) ⇒ Uint8Array +Decode the given url-safe base64-encoded slice into its raw bytes. + +**Kind**: global function + +| Param | Type | +| --- | --- | +| data | Uint8Array | -## MethodRelationship -**Kind**: global variable ## verifyEd25519(alg, signingInput, decodedSignature, publicKey) @@ -6229,28 +6242,6 @@ prior to calling the function. | decodedSignature | Uint8Array | | publicKey | [Jwk](#Jwk) | - - -## encodeB64(data) ⇒ string -Encode the given bytes in url-safe base64. - -**Kind**: global function - -| Param | Type | -| --- | --- | -| data | Uint8Array | - - - -## decodeB64(data) ⇒ Uint8Array -Decode the given url-safe base64-encoded slice into its raw bytes. - -**Kind**: global function - -| Param | Type | -| --- | --- | -| data | Uint8Array | - ## start() diff --git a/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts b/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts index 397f608ee3..e389118f8c 100644 --- a/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts +++ b/bindings/wasm/examples/src/1_advanced/6_sd_jwt.ts @@ -99,16 +99,16 @@ export async function sdJwt() { // Make "locality", "postal_code", "street_address" and the first entry of "nationalities" // selectively disclosable while keeping other properties in plain text. let disclosures = [ - encoder.conceal(["vc", "credentialSubject", "address", "locality"]), - encoder.conceal(["vc", "credentialSubject", "address", "postal_code"]), - encoder.conceal(["vc", "credentialSubject", "address", "street_address"]), - encoder.concealArrayEntry(["vc", "credentialSubject", "nationalities"], 1), + encoder.conceal("/vc/credentialSubject/address/locality"), + encoder.conceal("/vc/credentialSubject/address/postal_code"), + encoder.conceal("/vc/credentialSubject/address/street_address"), + encoder.conceal("/vc/credentialSubject/nationalities/1"), ]; // Add decoys in the credential top level, nationalities array and address object. - encoder.addDecoys(["vc", "credentialSubject", "nationalities"], 3); - encoder.addDecoys(["vc"], 4); - encoder.addDecoys(["vc", "credentialSubject", "address"], 2); + encoder.addDecoys("/vc/credentialSubject/nationalities", 3); + encoder.addDecoys("/vc", 4); + encoder.addDecoys("/vc/credentialSubject/address", 2); // Add the `_sd_alg` property. encoder.addSdAlgProperty(); diff --git a/bindings/wasm/src/sd_jwt/encoder.rs b/bindings/wasm/src/sd_jwt/encoder.rs index 79ad041dc1..550742b42b 100644 --- a/bindings/wasm/src/sd_jwt/encoder.rs +++ b/bindings/wasm/src/sd_jwt/encoder.rs @@ -2,14 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 use super::disclosure::WasmDisclosure; -use crate::common::ArrayString; use crate::common::RecordStringAny; use crate::error::Result; use crate::error::WasmResult; use identity_iota::sd_jwt_payload::SdObjectEncoder; use identity_iota::sd_jwt_payload::Sha256Hasher; -use js_sys::Array; -use js_sys::JsString; use serde_json::Value; use wasm_bindgen::prelude::*; @@ -32,54 +29,35 @@ impl WasmSdObjectEncoder { /// Substitutes a value with the digest of its disclosure. /// If no salt is provided, the disclosure will be created with a random salt value. /// - /// The value of the key specified in `path` will be concealed. E.g. for path - /// `["claim", "subclaim"]` the value of `claim.subclaim` will be concealed. + /// `path` indicates the pointer to the value that will be concealed using the syntax of + /// [JSON pointer](https://datatracker.ietf.org/doc/html/rfc6901). /// - /// ## Error - /// `InvalidPath` if path is invalid or the path slice is empty. - /// `DataTypeMismatch` if existing SD format is invalid. + /// For the following object: /// - /// ## Note - /// Use `concealArrayEntry` for values in arrays. + /// ``` + /// { + /// "id": "did:value", + /// "claim1": { + /// "abc": true + /// }, + /// "claim2": ["val_1", "val_2"] + /// } + /// ``` + /// + /// Path "/id" conceals `"id": "did:value"` + /// Path "/claim1/abc" conceals `"abc": true` + /// Path "/claim2/0" conceals `val_1` + /// ``` + /// + /// ## Errors + /// * `InvalidPath` if pointer is invalid. + /// * `DataTypeMismatch` if existing SD format is invalid. #[wasm_bindgen(js_name = conceal)] - pub fn conceal(&mut self, path: ArrayString, salt: Option) -> Result { - let path: Vec = path - .dyn_into::()? - .iter() - .map(|item| item.dyn_into::().map(String::from)) - .collect::>>()?; - let path: Vec<&str> = path.iter().map(|s| &**s).collect(); + pub fn conceal(&mut self, path: String, salt: Option) -> Result { let disclosure = self.0.conceal(&path, salt).wasm_result()?; Ok(WasmDisclosure(disclosure)) } - /// Substitutes a value within an array with the digest of its disclosure. - /// If no salt is provided, the disclosure will be created with random salt value. - /// - /// `path` is used to specify the array in the object, while `element_index` specifies - /// the index of the element to be concealed (index start at 0). - /// - /// ## Error - /// `InvalidPath` if path is invalid or the path slice is empty. - /// `DataTypeMismatch` if existing SD format is invalid. - /// `IndexOutofBounds` if `element_index` is out of bounds. - #[wasm_bindgen(js_name = concealArrayEntry)] - pub fn conceal_array_entry( - &mut self, - path: ArrayString, - element_index: usize, - salt: Option, - ) -> Result { - let path: Vec = path - .dyn_into::()? - .iter() - .map(|item| item.dyn_into::().map(String::from)) - .collect::>>()?; - let path: Vec<&str> = path.iter().map(|s| &**s).collect(); - let disclosure = self.0.conceal_array_entry(&path, element_index, salt).wasm_result()?; - Ok(WasmDisclosure(disclosure)) - } - /// Adds the `_sd_alg` property to the top level of the object, with /// its value set to "sha-256". #[wasm_bindgen(js_name = addSdAlgProperty)] @@ -103,7 +81,7 @@ impl WasmSdObjectEncoder { #[wasm_bindgen(js_name = encodeToObject)] pub fn encode_to_object(&self) -> Result { Ok( - JsValue::from_serde(&self.0.object()) + JsValue::from_serde(&self.0.object().wasm_result()?) .wasm_result()? .unchecked_into::(), ) @@ -112,19 +90,13 @@ impl WasmSdObjectEncoder { /// Returns the modified object. #[wasm_bindgen(js_name = toJSON)] pub fn to_json(&self) -> Result { - JsValue::from_serde(&self.0.object()).wasm_result() + JsValue::from_serde(&self.0.object().wasm_result()?).wasm_result() } /// Adds a decoy digest to the specified path. /// If path is an empty slice, decoys will be added to the top level. #[wasm_bindgen(js_name = addDecoys)] - pub fn add_decoys(&mut self, path: ArrayString, number_of_decoys: usize) -> Result<()> { - let path: Vec = path - .dyn_into::()? - .iter() - .map(|item| item.dyn_into::().map(String::from)) - .collect::>>()?; - let path: Vec<&str> = path.iter().map(|s| &**s).collect(); + pub fn add_decoys(&mut self, path: String, number_of_decoys: usize) -> Result<()> { self.0.add_decoys(&path, number_of_decoys).wasm_result()?; Ok(()) } diff --git a/bindings/wasm/tests/sd_jwt.ts b/bindings/wasm/tests/sd_jwt.ts index 3c471fab6d..31d02633e7 100644 --- a/bindings/wasm/tests/sd_jwt.ts +++ b/bindings/wasm/tests/sd_jwt.ts @@ -1,5 +1,5 @@ import * as assert from "assert"; -import { SdJwt, SdObjectDecoder, SdObjectEncoder } from "../node"; +import { SdObjectDecoder, SdObjectEncoder } from "../node"; describe("sd-jwt-payload", function() { describe("#encoder", function() { @@ -26,7 +26,7 @@ describe("sd-jwt-payload", function() { }; let encoder = new SdObjectEncoder(obj); - let emailDisclosure = encoder.conceal(["email"], "tstsalt"); + let emailDisclosure = encoder.conceal("/email", "tstsalt"); console.log(emailDisclosure); assert.deepStrictEqual(emailDisclosure.claimName(), "email"); assert.deepStrictEqual(emailDisclosure.claimValue(), "johndoe@example.com"); @@ -38,11 +38,11 @@ describe("sd-jwt-payload", function() { let disclosures = [ emailDisclosure.toEncodedString(), - encoder.conceal(["address", "street_address"]).toEncodedString(), - encoder.concealArrayEntry(["nationalities"], 0).toEncodedString(), + encoder.conceal("/address/street_address").toEncodedString(), + encoder.conceal("/nationalities/0").toEncodedString(), ]; encoder.addSdAlgProperty(); - encoder.addDecoys([], 3); + encoder.addDecoys("", 3); let encoded = encoder.encodeToObject(); assert.equal(encoded._sd.length, 4); diff --git a/examples/1_advanced/7_sd_jwt.rs b/examples/1_advanced/7_sd_jwt.rs index 90fac13307..2d2a4665ee 100644 --- a/examples/1_advanced/7_sd_jwt.rs +++ b/examples/1_advanced/7_sd_jwt.rs @@ -112,9 +112,9 @@ async fn main() -> anyhow::Result<()> { // Make "locality", "postal_code" and "street_address" selectively disclosable while keeping // other properties in plain text. let disclosures = vec![ - encoder.conceal(&["vc", "credentialSubject", "address", "locality"], None)?, - encoder.conceal(&["vc", "credentialSubject", "address", "postal_code"], None)?, - encoder.conceal(&["vc", "credentialSubject", "address", "street_address"], None)?, + encoder.conceal("/vc/credentialSubject/address/locality", None)?, + encoder.conceal("/vc/credentialSubject/address/postal_code", None)?, + encoder.conceal("/vc/credentialSubject/address/street_address", None)?, ]; // Add the `_sd_alg` property. diff --git a/examples/1_advanced/8_status_list_2021.rs b/examples/1_advanced/8_status_list_2021.rs index 3f41823bfe..0a70690e91 100644 --- a/examples/1_advanced/8_status_list_2021.rs +++ b/examples/1_advanced/8_status_list_2021.rs @@ -6,10 +6,8 @@ use examples::random_stronghold_path; use examples::MemStorage; use examples::API_ENDPOINT; use identity_eddsa_verifier::EdDSAJwsVerifier; - use identity_iota::core::FromJson; use identity_iota::core::Object; - use identity_iota::core::ToJson; use identity_iota::core::Url; use identity_iota::credential::status_list_2021::StatusList2021; @@ -17,10 +15,8 @@ use identity_iota::credential::status_list_2021::StatusList2021Credential; use identity_iota::credential::status_list_2021::StatusList2021CredentialBuilder; use identity_iota::credential::status_list_2021::StatusList2021Entry; use identity_iota::credential::status_list_2021::StatusPurpose; - use identity_iota::credential::Credential; use identity_iota::credential::CredentialBuilder; - use identity_iota::credential::FailFast; use identity_iota::credential::Issuer; use identity_iota::credential::Jwt; diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 3a0974122f..653bd436c9 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -13,7 +13,7 @@ identity_stronghold = { path = "../identity_stronghold", default-features = fals iota-sdk = { version = "1.0", default-features = false, features = ["tls", "client", "stronghold"] } primitive-types = "0.12.1" rand = "0.8.5" -sd-jwt-payload = { version = "0.1.2", default-features = false, features = ["sha"] } +sd-jwt-payload = { version = "0.2.0", default-features = false, features = ["sha"] } serde_json = { version = "1.0", default-features = false } tokio = { version = "1.29", default-features = false, features = ["rt"] } diff --git a/identity_credential/Cargo.toml b/identity_credential/Cargo.toml index 22fbb4b5da..5b4fdb1e5a 100644 --- a/identity_credential/Cargo.toml +++ b/identity_credential/Cargo.toml @@ -24,7 +24,7 @@ itertools = { version = "0.11", default-features = false, features = ["use_std"] once_cell = { version = "1.18", default-features = false, features = ["std"] } reqwest = { version = "0.11", default-features = false, features = ["default-tls", "json", "stream"], optional = true } roaring = { version = "0.10", default-features = false, optional = true } -sd-jwt-payload = { version = "0.1.2", default-features = false, features = ["sha"], optional = true } +sd-jwt-payload = { version = "0.2.0", default-features = false, features = ["sha"], optional = true } serde.workspace = true serde-aux = { version = "4.3.1", default-features = false, optional = true } serde_json.workspace = true diff --git a/identity_storage/src/storage/tests/kb_jwt.rs b/identity_storage/src/storage/tests/kb_jwt.rs index 5ea27ed5b9..e7451050fd 100644 --- a/identity_storage/src/storage/tests/kb_jwt.rs +++ b/identity_storage/src/storage/tests/kb_jwt.rs @@ -57,12 +57,8 @@ async fn setup_test() -> (Setup, Credential, SdJwt) let mut encoder = SdObjectEncoder::new(&payload).unwrap(); let disclosures = vec![ - encoder - .conceal(&["vc", "credentialSubject", "degree", "type"], None) - .unwrap(), - encoder - .conceal(&["vc", "credentialSubject", "degree", "name"], None) - .unwrap(), + encoder.conceal("/vc/credentialSubject/degree/type", None).unwrap(), + encoder.conceal("/vc/credentialSubject/degree/name", None).unwrap(), ]; encoder.add_sd_alg_property(); let encoded_payload = encoder.try_to_string().unwrap();