From b9e988d7f450598b3e277810e73e4dd7483ba255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Haudebourg?= Date: Tue, 25 Jun 2024 17:36:14 -0300 Subject: [PATCH] One step signature and verification (#552) * Remove the `Verifiable` type. * Simplify signature/verification environment using latest `json-ld`. --- Cargo.toml | 1 - crates/claims/Cargo.toml | 1 - crates/claims/core/Cargo.toml | 2 + crates/claims/core/src/lib.rs | 186 +------------ crates/claims/core/src/linked_data.rs | 76 ------ crates/claims/core/src/serde.rs | 41 --- crates/claims/core/src/signature.rs | 85 +++--- crates/claims/core/src/verification/claims.rs | 98 +++++-- crates/claims/core/src/verification/mod.rs | 62 ++--- crates/claims/core/src/verification/proof.rs | 86 +----- .../claims/crates/data-integrity/Cargo.toml | 4 +- .../crates/data-integrity/core/Cargo.toml | 1 - .../core/src/canonicalization.rs | 36 +-- .../crates/data-integrity/core/src/decode.rs | 28 +- .../crates/data-integrity/core/src/lib.rs | 21 +- .../core/src/proof/configuration/expansion.rs | 144 +++++----- .../core/src/proof/configuration/mod.rs | 2 +- .../core/src/proof/configuration/reference.rs | 4 +- .../data-integrity/core/src/proof/mod.rs | 81 +++--- .../data-integrity/core/src/proof/prepared.rs | 2 +- .../core/src/proof/reference.rs | 2 +- .../data-integrity/core/src/signing/jws.rs | 12 +- .../core/src/signing/multibase.rs | 4 +- .../data-integrity/core/src/suite/bounds.rs | 5 +- .../core/src/suite/configuration.rs | 2 +- .../data-integrity/core/src/suite/mod.rs | 149 ++++++----- .../core/src/suite/signature.rs | 7 +- .../core/src/suite/standard/hashing.rs | 8 +- .../core/src/suite/standard/mod.rs | 58 ++-- .../core/src/suite/standard/signature.rs | 2 +- .../core/src/suite/standard/transformation.rs | 12 +- .../core/src/suite/standard/verification.rs | 2 +- .../core/src/suite/verification.rs | 7 +- .../crates/data-integrity/src/any/context.rs | 115 -------- .../crates/data-integrity/src/any/macros.rs | 77 ++---- .../crates/data-integrity/src/any/mod.rs | 2 - .../data-integrity/src/any/suite/mod.rs | 10 +- .../crates/data-integrity/suites/Cargo.toml | 1 - .../data-integrity/suites/src/eip712/mod.rs | 35 --- ...ecdsa_secp256k1_recovery_signature_2020.rs | 2 +- .../suites/unspecified/aleo_signature_2021.rs | 6 +- .../unspecified/eip712_signature_2021.rs | 45 ++-- .../ethereum_personal_signature_2021.rs | 10 +- .../ethereum_personal_signature_2021/v0_1.rs | 4 +- .../unspecified/solana_signature_2021.rs | 6 +- .../suites/src/suites/unspecified/tezos.rs | 18 +- .../tezos/tezos_jcs_signature_2021.rs | 10 +- .../unspecified/tezos/tezos_signature_2021.rs | 8 +- .../w3c/ethereum_eip712_signature_2021.rs | 21 +- .../ethereum_eip712_signature_2021/v0_1.rs | 8 +- .../src/suites/w3c/json_web_signature_2020.rs | 8 +- .../src/suites/w3c/rsa_signature_2018.rs | 8 +- crates/claims/crates/jws/src/compact/bytes.rs | 29 +- crates/claims/crates/jws/src/compact/str.rs | 7 +- crates/claims/crates/jws/src/lib.rs | 108 +++++--- crates/claims/crates/jws/src/verification.rs | 117 +++++--- crates/claims/crates/jwt/src/claims/any.rs | 12 +- .../claims/crates/jwt/src/claims/mixed/mod.rs | 23 +- .../crates/jwt/src/claims/registered.rs | 6 +- crates/claims/crates/jwt/src/decoding.rs | 6 +- crates/claims/crates/status/Cargo.toml | 2 - .../crates/status/examples/status_list.rs | 10 +- crates/claims/crates/status/src/impl/any.rs | 6 +- .../syntax/entry_set/credential.rs | 97 ++++--- .../syntax/status_list/credential.rs | 97 ++++--- .../status/src/impl/token_status_list/json.rs | 21 +- .../status/src/impl/token_status_list/mod.rs | 15 +- crates/claims/crates/vc/Cargo.toml | 1 - crates/claims/crates/vc/examples/sign.rs | 43 +-- crates/claims/crates/vc/src/data_integrity.rs | 82 +----- .../crates/vc/src/data_model/credential.rs | 7 +- crates/claims/crates/vc/src/revocation/mod.rs | 2 - .../claims/crates/vc/src/revocation/v2020.rs | 9 +- .../claims/crates/vc/src/revocation/v2021.rs | 9 +- crates/claims/crates/vc/src/syntax/context.rs | 26 +- .../vc/src/syntax/json/credential/mod.rs | 47 ++-- .../vc/src/syntax/json/presentation/mod.rs | 47 ++-- crates/dids/core/Cargo.toml | 2 +- .../src/document/representation/json_ld.rs | 2 +- crates/dids/core/src/lib.rs | 2 +- .../dids/methods/ethr/src/json_ld_context.rs | 2 +- crates/dids/methods/ethr/src/lib.rs | 51 ++-- .../methods/ion/src/sidetree/operation/mod.rs | 15 +- crates/dids/methods/jwk/src/lib.rs | 2 +- crates/dids/methods/key/src/lib.rs | 68 ++--- crates/dids/methods/pkh/Cargo.toml | 1 - .../dids/methods/pkh/src/json_ld_context.rs | 2 +- crates/dids/methods/pkh/src/lib.rs | 174 ++++-------- crates/dids/methods/tz/tests/did.rs | 129 +++------ crates/dids/methods/web/src/lib.rs | 25 +- crates/eip712/Cargo.toml | 1 + crates/eip712/src/lib.rs | 23 -- crates/eip712/src/ty.rs | 40 +++ crates/json-ld/Cargo.toml | 4 +- crates/json-ld/src/context.rs | 68 ++--- crates/json-ld/src/lib.rs | 166 +++++------- crates/rdf/src/expand.rs | 177 +------------ crates/rdf/src/lib.rs | 8 +- crates/ucan/src/lib.rs | 21 +- crates/verification-methods/Cargo.toml | 2 - crates/verification-methods/core/Cargo.toml | 2 +- crates/zcap-ld/Cargo.toml | 1 - crates/zcap-ld/src/lib.rs | 250 +++++++++++------- examples/issue-revocation-list.rs | 14 +- examples/issue-status-list.rs | 14 +- examples/issue.rs | 8 +- examples/present.rs | 8 +- examples/vc_parse.rs | 15 +- examples/vc_verify.rs | 10 +- src/lib.rs | 3 +- src/prelude.rs | 12 +- tests/send.rs | 3 +- 112 files changed, 1490 insertions(+), 2289 deletions(-) delete mode 100644 crates/claims/core/src/linked_data.rs delete mode 100644 crates/claims/core/src/serde.rs delete mode 100644 crates/claims/crates/data-integrity/src/any/context.rs diff --git a/Cargo.toml b/Cargo.toml index de4009471..8ae49db31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,7 +86,6 @@ locspan = "0.8" json-syntax = "0.12.2" nquads-syntax = "0.19" multibase = "0.9.1" -json-ld = "0.16" serde = "1.0" serde_json = { version = "1.0", features = ["arbitrary_precision"] } serde_jcs = "0.1.0" diff --git a/crates/claims/Cargo.toml b/crates/claims/Cargo.toml index 60ff265cc..20f377706 100644 --- a/crates/claims/Cargo.toml +++ b/crates/claims/Cargo.toml @@ -74,6 +74,5 @@ linked-data.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true json-syntax.workspace = true -json-ld.workspace = true locspan.workspace = true educe.workspace = true \ No newline at end of file diff --git a/crates/claims/core/Cargo.toml b/crates/claims/core/Cargo.toml index 03ecd1b42..e4e1a7df5 100644 --- a/crates/claims/core/Cargo.toml +++ b/crates/claims/core/Cargo.toml @@ -30,6 +30,8 @@ ssi-core.workspace = true educe.workspace = true thiserror.workspace = true chrono.workspace = true +ssi-json-ld.workspace = true +ssi-eip712.workspace = true serde = { workspace = true, optional = true } linked-data = { workspace = true, optional = true } \ No newline at end of file diff --git a/crates/claims/core/src/lib.rs b/crates/claims/core/src/lib.rs index 14872013a..a0dbc5600 100644 --- a/crates/claims/core/src/lib.rs +++ b/crates/claims/core/src/lib.rs @@ -1,191 +1,7 @@ -use std::ops::Deref; +pub use chrono; mod signature; pub use signature::*; mod verification; pub use verification::*; - -/// Claims serialization utils. -#[cfg(feature = "serde")] -pub mod serde; - -/// Claims data-integrity serialization utils. -#[cfg(feature = "linked-data")] -pub mod linked_data; - -/// Verifiable claims, and their proof. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Verifiable { - /// Claims. - pub claims: Claims, - - /// Prepared proof. - /// - /// This is not just the proof, but also any information derived from the - /// claims and/or proof required for the verification. - pub proof: P::Prepared, -} - -impl Verifiable { - pub fn from_parts(claims: T, proof: P::Prepared) -> Self { - Self { claims, proof } - } - - pub async fn new(value: U) -> Result - where - U: ExtractProof + DefaultEnvironment, - P: PrepareWith, - { - Self::new_with(value, U::Environment::default()).await - } - - pub async fn new_with(value: U, mut environment: E) -> Result - where - U: ExtractProof, - P: PrepareWith, - { - let (value, raw_proof) = value.extract_proof(); - let proof = raw_proof.prepare_with(&value, &mut environment).await?; - Ok(Verifiable::from_parts(value, proof)) - } - - /// Merge the claims with their proof(s). - /// - /// This will effectively unprepare the proof and make them unverifiable - /// until [`Self::new`] is called again. - pub fn unprepare(self) -> P::Attached - where - P: AttachProof, - P::Prepared: UnprepareProof, - { - let (claims, prepared_proof) = self.into_parts(); - prepared_proof.unprepare().attach_to(claims) - } - - /// Tamper with the claims without changing the proofs. - /// - /// The proofs may become invalid. - pub async fn tamper( - self, - environment: E, - f: impl FnOnce(T) -> U, - ) -> Result, ProofPreparationError> - where - P: PrepareWith, - P::Prepared: UnprepareProof, - { - self.tamper_with_proofs(environment, f, |p| p).await - } - - /// Tamper with the claims and proofs. - /// - /// The proofs may become invalid. - pub async fn tamper_with_proofs( - self, - mut environment: E, - f: impl FnOnce(T) -> U, - mut g: impl FnMut(P) -> P, - ) -> Result, ProofPreparationError> - where - P: PrepareWith, - P::Prepared: UnprepareProof, - { - self.async_try_map(|value, proof| async { - let u = f(value); - - let unprepared_proof = g(proof.unprepare()); - let new_proof = unprepared_proof.prepare_with(&u, &mut environment).await?; - - Ok((u, new_proof)) - }) - .await - } - - /// Validates the claims and verify them against the proof. - pub async fn verify(&self, verifier: &V) -> Result - where - T: Validate, - P::Prepared: ValidateProof, - { - let env = ValidationEnvironment::default(); - self.verify_with(verifier, &env).await - } - - /// Validates the claims and verify them against the proof. - pub async fn verify_with( - &self, - verifier: &V, - env: &E, - ) -> Result - where - T: Validate, - P::Prepared: ValidateProof, - { - match self.claims.validate(env, &self.proof) { - Ok(_) => self - .proof - .validate_proof(&self.claims, verifier) - .await - .map(|r| r.map_err(Invalid::Proof)), - Err(e) => { - // Claims are not valid on their own. - Ok(Err(Invalid::Claims(e))) - } - } - } - - pub fn map( - self, - f: impl FnOnce(T, P::Prepared) -> (D, Q::Prepared), - ) -> Verifiable { - let (claims, proof) = f(self.claims, self.proof); - - Verifiable { claims, proof } - } - - pub fn try_map( - self, - f: impl FnOnce(T, P::Prepared) -> Result<(D, Q::Prepared), E>, - ) -> Result, E> { - let (claims, proof) = f(self.claims, self.proof)?; - - Ok(Verifiable { claims, proof }) - } - - pub async fn async_map( - self, - f: impl FnOnce(T, P::Prepared) -> F, - ) -> Verifiable - where - F: std::future::Future, - { - let (claims, proof) = f(self.claims, self.proof).await; - - Verifiable { claims, proof } - } - - pub async fn async_try_map( - self, - f: impl FnOnce(T, P::Prepared) -> F, - ) -> Result, E> - where - F: std::future::Future>, - { - let (claims, proof) = f(self.claims, self.proof).await?; - - Ok(Verifiable { claims, proof }) - } - - pub fn into_parts(self) -> (T, P::Prepared) { - (self.claims, self.proof) - } -} - -impl Deref for Verifiable { - type Target = C; - - fn deref(&self) -> &Self::Target { - &self.claims - } -} diff --git a/crates/claims/core/src/linked_data.rs b/crates/claims/core/src/linked_data.rs deleted file mode 100644 index c2fd5f2ba..000000000 --- a/crates/claims/core/src/linked_data.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::{Proof, Verifiable}; -use linked_data::{ - rdf_types::{Interpretation, Vocabulary}, - GraphVisitor, LinkedData, LinkedDataGraph, LinkedDataResource, LinkedDataSubject, - SubjectVisitor, Visitor, -}; - -impl, P: Proof> - LinkedDataResource for Verifiable -{ - fn interpretation( - &self, - vocabulary: &mut V, - interpretation: &mut I, - ) -> linked_data::ResourceInterpretation { - self.claims.interpretation(vocabulary, interpretation) - } -} - -/// Linked-Data claims. -pub trait LinkedDataClaims { - fn visit_with_proof(&self, proof: &P::Prepared, visitor: S) -> Result - where - S: Visitor; -} - -impl, P: Proof> LinkedData - for Verifiable -{ - fn visit(&self, visitor: S) -> Result - where - S: Visitor, - { - self.claims.visit_with_proof(&self.proof, visitor) - } -} - -/// Linked-Data subject claims. -pub trait LinkedDataSubjectClaims { - fn visit_subject_with_proof( - &self, - proof: &P::Prepared, - visitor: S, - ) -> Result - where - S: SubjectVisitor; -} - -impl, P: Proof> - LinkedDataSubject for Verifiable -{ - fn visit_subject(&self, visitor: S) -> Result - where - S: SubjectVisitor, - { - self.claims.visit_subject_with_proof(&self.proof, visitor) - } -} - -/// Linked-Data graph claims. -pub trait LinkedDataGraphClaims { - fn visit_graph_with_proof(&self, proof: &P::Prepared, visitor: S) -> Result - where - S: GraphVisitor; -} - -impl, P: Proof> - LinkedDataGraph for Verifiable -{ - fn visit_graph(&self, visitor: S) -> Result - where - S: GraphVisitor, - { - self.claims.visit_graph_with_proof(&self.proof, visitor) - } -} diff --git a/crates/claims/core/src/serde.rs b/crates/claims/core/src/serde.rs deleted file mode 100644 index 4a0668a36..000000000 --- a/crates/claims/core/src/serde.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{Proof, Verifiable}; - -/// Serializable claims. -pub trait SerializeVerifiableClaims { - fn serialize_verifiable_claims(&self, claims: &T, serializer: S) -> Result - where - S: serde::Serializer; -} - -impl serde::Serialize for Verifiable -where - P::Prepared: SerializeVerifiableClaims, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.proof - .serialize_verifiable_claims(&self.claims, serializer) - } -} - -/// Serialize claims with a slice of proofs. -pub trait SerializeVerifiableClaimsFromSlice: Sized { - fn serialize_verifiable_claims_from_slice( - proofs: &[Self], - claims: &T, - serializer: S, - ) -> Result - where - S: serde::Serializer; -} - -impl> SerializeVerifiableClaims for Vec

{ - fn serialize_verifiable_claims(&self, claims: &T, serializer: S) -> Result - where - S: serde::Serializer, - { - P::serialize_verifiable_claims_from_slice(self, claims, serializer) - } -} diff --git a/crates/claims/core/src/signature.rs b/crates/claims/core/src/signature.rs index 241b40402..26f5e890c 100644 --- a/crates/claims/core/src/signature.rs +++ b/crates/claims/core/src/signature.rs @@ -1,5 +1,8 @@ use core::fmt; +use ssi_eip712::Eip712TypesEnvironment; +use ssi_json_ld::ContextLoaderEnvironment; + #[derive(Debug, thiserror::Error)] pub enum SignatureError { #[error("missing signature algorithm")] @@ -42,50 +45,54 @@ impl SignatureError { } } -// #[derive(Debug, thiserror::Error)] -// pub enum SignatureError { -// #[error("verification method resolution failed: {0}")] -// Resolution(#[from] VerificationMethodResolutionError), - -// #[error("missing verification method")] -// MissingVerificationMethod, - -// #[error("unknown verification method")] -// UnknownVerificationMethod, - -// #[error("no signer for requested verification method")] -// MissingSigner, - -// #[error("invalid hash")] -// InvalidHash, - -// #[error("invalid public key")] -// InvalidPublicKey, - -// #[error("invalid secret key")] -// InvalidSecretKey, - -// #[error(transparent)] -// InvalidVerificationMethod(#[from] InvalidVerificationMethod), +impl From for SignatureError { + fn from(_value: std::convert::Infallible) -> Self { + unreachable!() + } +} -// #[error("missing public key")] -// MissingPublicKey, +/// Signature environment. +/// +/// This is a common environment implementation expected to work with most +/// claims. +/// +/// It is possible to define a custom environment type, as long it implements +/// the accessor traits required for signature. +pub struct SignatureEnvironment { + pub json_ld_loader: JsonLdLoader, + + pub eip712_loader: Eip712Loader, +} -// #[error(transparent)] -// Signer(#[from] ssi_crypto::MessageSignatureError), +impl Default for SignatureEnvironment { + fn default() -> Self { + Self { + json_ld_loader: ssi_json_ld::ContextLoader::default(), + eip712_loader: (), + } + } +} -// #[error("invalid received signature")] -// InvalidSignature, +impl ContextLoaderEnvironment + for SignatureEnvironment +where + JsonLdLoader: ssi_json_ld::Loader, +{ + type Loader = JsonLdLoader; -// #[error("invalid signature algorithm")] -// InvalidAlgorithm, + fn loader(&self) -> &Self::Loader { + &self.json_ld_loader + } +} -// #[error("missing signature algorithm")] -// MissingAlgorithm, -// } +impl Eip712TypesEnvironment + for SignatureEnvironment +where + Eip712Loader: ssi_eip712::TypesProvider, +{ + type Provider = Eip712Loader; -impl From for SignatureError { - fn from(_value: std::convert::Infallible) -> Self { - unreachable!() + fn eip712_types(&self) -> &Self::Provider { + &self.eip712_loader } } diff --git a/crates/claims/core/src/verification/claims.rs b/crates/claims/core/src/verification/claims.rs index bd95720e6..584cb3ee4 100644 --- a/crates/claims/core/src/verification/claims.rs +++ b/crates/claims/core/src/verification/claims.rs @@ -1,9 +1,9 @@ +use chrono::{DateTime, Utc}; use core::fmt; use std::borrow::Cow; -use chrono::{DateTime, Utc}; - -use crate::Proof; +pub use ssi_eip712::Eip712TypesEnvironment; +pub use ssi_json_ld::ContextLoaderEnvironment; #[derive(Debug, thiserror::Error, PartialEq)] pub enum InvalidClaims { @@ -48,31 +48,31 @@ pub type ClaimsValidity = Result<(), InvalidClaims>; /// /// The `validate` function is also provided with the proof, as some claim type /// require information from the proof to be validated. -pub trait Validate { +pub trait Validate { /// Validates the claims. - fn validate(&self, env: &E, proof: &P::Prepared) -> ClaimsValidity; + fn validate(&self, env: &E, proof: &P) -> ClaimsValidity; } -impl Validate for () { - fn validate(&self, _env: &E, _proof: &P::Prepared) -> ClaimsValidity { +impl Validate for () { + fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity { Ok(()) } } -impl Validate for [u8] { - fn validate(&self, _env: &E, _proof: &P::Prepared) -> ClaimsValidity { +impl Validate for [u8] { + fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity { Ok(()) } } -impl Validate for Vec { - fn validate(&self, _env: &E, _proof: &P::Prepared) -> ClaimsValidity { +impl Validate for Vec { + fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity { Ok(()) } } -impl<'a, E, P: Proof, T: ?Sized + ToOwned + Validate> Validate for Cow<'a, T> { - fn validate(&self, _env: &E, _proof: &P::Prepared) -> ClaimsValidity { +impl<'a, E, P, T: ?Sized + ToOwned + Validate> Validate for Cow<'a, T> { + fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity { Ok(()) } } @@ -85,27 +85,89 @@ pub trait DateTimeEnvironment { fn date_time(&self) -> DateTime; } -/// Validation environment. +impl DateTimeEnvironment for () { + fn date_time(&self) -> DateTime { + Utc::now() + } +} + +/// Verifiable claims with a preferred default verification environment. +pub trait DefaultVerificationEnvironment { + type Environment: Default; +} + +impl DefaultVerificationEnvironment for () { + type Environment = (); +} + +impl DefaultVerificationEnvironment for [u8] { + type Environment = (); +} + +impl DefaultVerificationEnvironment for Vec { + type Environment = (); +} + +impl<'a> DefaultVerificationEnvironment for Cow<'a, [u8]> { + type Environment = (); +} + +impl<'a, T: DefaultVerificationEnvironment> DefaultVerificationEnvironment for &'a T { + type Environment = T::Environment; +} + +/// Verification environment. /// /// This is a common environment implementation expected to work with most /// claims. /// /// It is possible to define a custom environment type, as long it implements -/// the accessor traits required for validation such as [`DateTimeEnvironment`]. -pub struct ValidationEnvironment { +/// the accessor traits required for verification such as +/// [`DateTimeEnvironment`]. +pub struct VerificationEnvironment { pub date_time: DateTime, + + pub json_ld_loader: JsonLdLoader, + + pub eip712_loader: Eip712Loader, } -impl Default for ValidationEnvironment { +impl Default for VerificationEnvironment { fn default() -> Self { Self { date_time: Utc::now(), + json_ld_loader: ssi_json_ld::ContextLoader::default(), + eip712_loader: (), } } } -impl DateTimeEnvironment for ValidationEnvironment { +impl DateTimeEnvironment for VerificationEnvironment { fn date_time(&self) -> DateTime { self.date_time } } + +impl ContextLoaderEnvironment + for VerificationEnvironment +where + JsonLdLoader: ssi_json_ld::Loader, +{ + type Loader = JsonLdLoader; + + fn loader(&self) -> &Self::Loader { + &self.json_ld_loader + } +} + +impl Eip712TypesEnvironment + for VerificationEnvironment +where + Eip712Loader: ssi_eip712::TypesProvider, +{ + type Provider = Eip712Loader; + + fn eip712_types(&self) -> &Self::Provider { + &self.eip712_loader + } +} diff --git a/crates/claims/core/src/verification/mod.rs b/crates/claims/core/src/verification/mod.rs index 20a694c49..a1928bf38 100644 --- a/crates/claims/core/src/verification/mod.rs +++ b/crates/claims/core/src/verification/mod.rs @@ -24,55 +24,57 @@ pub use claims::*; mod proof; pub use proof::*; -use crate::Verifiable; - /// Verifiable Claims. /// /// Set of claims bundled with a proof. pub trait VerifiableClaims { + /// Claims type. + type Claims; + /// Proof type. type Proof; + fn claims(&self) -> &Self::Claims; + + fn proof(&self) -> &Self::Proof; + + /// Validates the claims and verify them against the proof. #[allow(async_fn_in_trait)] - async fn into_verifiable( - self, - ) -> Result, ProofPreparationError> + async fn verify(&self, verifier: &V) -> Result where - Self: ExtractProof + DefaultEnvironment, - Self::Proof: PrepareWith, + Self: DefaultVerificationEnvironment, + Self::Claims: Validate, + Self::Proof: ValidateProof, { - Verifiable::new(self).await + self.verify_with(verifier, Self::Environment::default()) + .await } + /// Validates the claims and verify them against the proof. #[allow(async_fn_in_trait)] - async fn into_verifiable_with( - self, + async fn verify_with( + &self, + verifier: &V, env: E, - ) -> Result, ProofPreparationError> + ) -> Result where - Self: ExtractProof, - Self::Proof: PrepareWith, + Self::Claims: Validate, + Self::Proof: ValidateProof, { - Verifiable::new_with(self, env).await + match self.claims().validate(&env, self.proof()) { + Ok(_) => self + .proof() + .validate_proof(&env, self.claims(), verifier) + .await + .map(|r| r.map_err(Invalid::Proof)), + Err(e) => { + // Claims are not valid on their own. + Ok(Err(Invalid::Claims(e))) + } + } } } -pub trait DefaultEnvironment { - type Environment: Default; -} - -/// Proof extraction trait. -/// -/// Implemented by credential and presentation types that can be separated from -/// their proof value(s). -pub trait ExtractProof: Sized + VerifiableClaims { - /// Set of claims without the proof. - type Proofless; - - /// Separates the set of claims from the proof. - fn extract_proof(self) -> (Self::Proofless, Self::Proof); -} - /// Proof bundling trait. /// /// Provides a method to bundle the set of claims with a proof. diff --git a/crates/claims/core/src/verification/proof.rs b/crates/claims/core/src/verification/proof.rs index 01189303a..8fe018907 100644 --- a/crates/claims/core/src/verification/proof.rs +++ b/crates/claims/core/src/verification/proof.rs @@ -107,86 +107,8 @@ impl From for ProofValidationError { pub type ProofValidity = Result<(), InvalidProof>; -/// Proof type. -pub trait Proof { - /// Prepared proof type. - /// - /// A prepared proof also contains any information derived from the claims - /// and/or unprepared proof required for the verification. - /// Examples of information may be: - /// - a hash of the claims; - /// - JSON-LD expansion of the proof; - /// - canonical form of the claims; - /// - etc. - type Prepared; -} - -/// A list of proofs is also a proof. -impl Proof for Vec

{ - type Prepared = Vec; -} - -/// Proof that can be prepared to verify `T` claims. -/// -/// Preparation consists in computing any information derived from the claims -/// and/or proof required for verification. -/// Examples of information may be: -/// - a hash of the claims; -/// - JSON-LD expansion of the proof; -/// - canonical form of the claims; -/// - etc. -/// -/// An environment of type `E` is provided with all the data required for the -/// preparation. For instance, JSON-LD proofs will require a JSON-LD document -/// loader to fetch remote JSON-LD contexts. -pub trait PrepareWith: Proof { - /// Prepare this proof to verify the given claims. - #[allow(async_fn_in_trait)] - async fn prepare_with( - self, - claims: &T, - environment: &mut E, - ) -> Result; -} - -impl> PrepareWith for Vec

{ - async fn prepare_with( - self, - claims: &T, - environment: &mut E, - ) -> Result { - let mut prepared = Vec::with_capacity(self.len()); - - for p in self { - prepared.push(p.prepare_with(claims, environment).await?) - } - - Ok(prepared) - } -} - -/// Reverse proof preparation. -/// -/// Provides a method to strip a proof from its preparation data. -/// This is the inverse of [`PrepareWith`]. -pub trait UnprepareProof { - /// Unprepared proof. - type Unprepared: Proof; - - /// Reverses the proof preparation. - fn unprepare(self) -> Self::Unprepared; -} - -impl UnprepareProof for Vec

{ - type Unprepared = Vec; - - fn unprepare(self) -> Self::Unprepared { - self.into_iter().map(P::unprepare).collect() - } -} - /// Proof that can be validated against `T` claims with a verifier of type `V`. -pub trait ValidateProof { +pub trait ValidateProof { /// Validates the input claim's proof using the given verifier. /// /// The returned value is a nested `Result`. @@ -197,14 +119,16 @@ pub trait ValidateProof { #[allow(async_fn_in_trait)] async fn validate_proof<'a>( &'a self, + environment: &'a E, claims: &'a T, verifier: &'a V, ) -> Result; } -impl> ValidateProof for Vec

{ +impl> ValidateProof for Vec

{ async fn validate_proof<'a>( &'a self, + environment: &'a E, claims: &'a T, verifier: &'a V, ) -> Result { @@ -213,7 +137,7 @@ impl> ValidateProof for Vec

{ Ok(Err(InvalidProof::Missing)) } else { for p in self { - if let Err(e) = p.validate_proof(claims, verifier).await? { + if let Err(e) = p.validate_proof(environment, claims, verifier).await? { return Ok(Err(e)); } } diff --git a/crates/claims/crates/data-integrity/Cargo.toml b/crates/claims/crates/data-integrity/Cargo.toml index 20778cd56..96c6f8e75 100644 --- a/crates/claims/crates/data-integrity/Cargo.toml +++ b/crates/claims/crates/data-integrity/Cargo.toml @@ -101,9 +101,9 @@ ssi-eip712.workspace = true ssi-claims-core.workspace = true iref.workspace = true rdf-types.workspace = true -json-ld.workspace = true linked-data.workspace = true serde.workspace = true serde_json.workspace = true json-syntax.workspace = true -thiserror.workspace = true \ No newline at end of file +thiserror.workspace = true +chrono.workspace = true \ No newline at end of file diff --git a/crates/claims/crates/data-integrity/core/Cargo.toml b/crates/claims/crates/data-integrity/core/Cargo.toml index 57aaff7b0..b11f972d3 100644 --- a/crates/claims/crates/data-integrity/core/Cargo.toml +++ b/crates/claims/crates/data-integrity/core/Cargo.toml @@ -25,7 +25,6 @@ chrono.workspace = true iref.workspace = true thiserror.workspace = true static-iref.workspace = true -json-ld = { workspace = true, features = ["serde"] } locspan.workspace = true hex.workspace = true serde = { workspace = true, features = ["derive"] } diff --git a/crates/claims/crates/data-integrity/core/src/canonicalization.rs b/crates/claims/crates/data-integrity/core/src/canonicalization.rs index 96a2632b6..7724c171a 100644 --- a/crates/claims/crates/data-integrity/core/src/canonicalization.rs +++ b/crates/claims/crates/data-integrity/core/src/canonicalization.rs @@ -1,21 +1,14 @@ use digest::Digest; use std::marker::PhantomData; -use linked_data::LinkedData; -use rdf_types::{ - interpretation::{ - ReverseBlankIdInterpretation, ReverseIriInterpretation, ReverseLiteralInterpretation, - }, - InterpretationMut, Vocabulary, -}; -use ssi_json_ld::JsonLdNodeObject; -use ssi_rdf::{AnyLdEnvironment, Expandable}; +use ssi_json_ld::{ContextLoaderEnvironment, Expandable, JsonLdNodeObject}; +use ssi_rdf::{AnyLdEnvironment, LdEnvironment}; use crate::{ hashing::ConcatOutputSize, suite::standard::{self, HashingAlgorithm, TransformationAlgorithm, TransformationError}, - ConfigurationExpandingEnvironment, CryptographicSuite, ProofConfigurationRef, - SerializeCryptographicSuite, StandardCryptographicSuite, + CryptographicSuite, ProofConfigurationRef, SerializeCryptographicSuite, + StandardCryptographicSuite, }; /// Canonical claims and configuration. @@ -33,31 +26,26 @@ impl standard::TransformationAlgorithm type Output = CanonicalClaimsAndConfiguration; } -impl standard::TypedTransformationAlgorithm - for CanonicalizeClaimsAndConfiguration +impl standard::TypedTransformationAlgorithm for CanonicalizeClaimsAndConfiguration where S: SerializeCryptographicSuite, - T: Expandable + JsonLdNodeObject, - T::Expanded: LinkedData, - C: AnyLdEnvironment + ConfigurationExpandingEnvironment, - V: Vocabulary, - I: InterpretationMut - + ReverseIriInterpretation - + ReverseBlankIdInterpretation - + ReverseLiteralInterpretation, + T: JsonLdNodeObject + Expandable, + C: ContextLoaderEnvironment, { async fn transform( - context: &mut C, + context: &C, data: &T, proof_configuration: ProofConfigurationRef<'_, S>, ) -> Result { + let mut ld = LdEnvironment::default(); + let expanded = data - .expand(context) + .expand_with(&mut ld, context.loader()) .await .map_err(|e| TransformationError::JsonLdExpansion(e.to_string()))?; Ok(CanonicalClaimsAndConfiguration { - claims: context + claims: ld .canonical_form_of(&expanded) .map_err(TransformationError::JsonLdDeserialization)?, configuration: proof_configuration diff --git a/crates/claims/crates/data-integrity/core/src/decode.rs b/crates/claims/crates/data-integrity/core/src/decode.rs index d25b6f926..d2052b4a9 100644 --- a/crates/claims/crates/data-integrity/core/src/decode.rs +++ b/crates/claims/crates/data-integrity/core/src/decode.rs @@ -1,11 +1,8 @@ use serde::de::DeserializeOwned; -use ssi_claims_core::{ProofPreparationError, Verifiable, VerifiableClaims}; +use ssi_claims_core::ProofPreparationError; use ssi_json_ld::JsonLdNodeObject; -use crate::{ - suite::{CryptographicSuiteInstance, DeserializeCryptographicSuiteOwned}, - DataIntegrity, Proofs, -}; +use crate::{suite::DeserializeCryptographicSuiteOwned, DataIntegrity}; #[derive(Debug, thiserror::Error)] pub enum DecodeError { @@ -18,29 +15,20 @@ pub enum DecodeError { /// Decodes a Data-Integrity credential or presentation from its JSON binary /// representation. -pub async fn from_json_slice( - json: &[u8], - environment: E, -) -> Result>, DecodeError> +pub fn from_json_slice(json: &[u8]) -> Result, DecodeError> where T: DeserializeOwned + JsonLdNodeObject, - S: DeserializeCryptographicSuiteOwned + CryptographicSuiteInstance, + S: DeserializeCryptographicSuiteOwned, { - serde_json::from_slice::>(json)? - .into_verifiable_with(environment) - .await - .map_err(Into::into) + serde_json::from_slice::>(json).map_err(Into::into) } /// Decodes a Data-Integrity credential or presentation from its JSON textual /// representation. -pub async fn from_json_str( - json: &str, - environment: E, -) -> Result>, DecodeError> +pub fn from_json_str(json: &str) -> Result, DecodeError> where T: DeserializeOwned + JsonLdNodeObject, - S: DeserializeCryptographicSuiteOwned + CryptographicSuiteInstance, + S: DeserializeCryptographicSuiteOwned, { - from_json_slice(json.as_bytes(), environment).await + from_json_slice(json.as_bytes()) } diff --git a/crates/claims/crates/data-integrity/core/src/lib.rs b/crates/claims/crates/data-integrity/core/src/lib.rs index 985ef362e..9b8875eca 100644 --- a/crates/claims/crates/data-integrity/core/src/lib.rs +++ b/crates/claims/crates/data-integrity/core/src/lib.rs @@ -17,7 +17,7 @@ use educe::Educe; pub use options::ProofOptions; pub use proof::*; use serde::Serialize; -use ssi_claims_core::{DefaultEnvironment, ExtractProof, VerifiableClaims}; +use ssi_claims_core::{DefaultVerificationEnvironment, VerifiableClaims, VerificationEnvironment}; pub use suite::{ CloneCryptographicSuite, CryptographicSuite, DebugCryptographicSuite, DeserializeCryptographicSuite, SerializeCryptographicSuite, StandardCryptographicSuite, @@ -60,17 +60,18 @@ impl DerefMut for DataIntegrity { } impl VerifiableClaims for DataIntegrity { + type Claims = T; type Proof = Proofs; -} - -impl DefaultEnvironment for DataIntegrity { - type Environment = S::Environment; -} -impl ExtractProof for DataIntegrity { - type Proofless = T; + fn claims(&self) -> &Self::Claims { + &self.claims + } - fn extract_proof(self) -> (Self::Proofless, Self::Proof) { - (self.claims, self.proofs) + fn proof(&self) -> &Self::Proof { + &self.proofs } } + +impl DefaultVerificationEnvironment for DataIntegrity { + type Environment = VerificationEnvironment; +} diff --git a/crates/claims/crates/data-integrity/core/src/proof/configuration/expansion.rs b/crates/claims/crates/data-integrity/core/src/proof/configuration/expansion.rs index df15cb9fb..8c0d15fe3 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/configuration/expansion.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/configuration/expansion.rs @@ -1,19 +1,19 @@ -use core::fmt; -use std::{borrow::Cow, hash::Hash}; - use ::linked_data::{LinkedDataResource, LinkedDataSubject}; use iref::IriBuf; +use linked_data::LinkedData; use rdf_types::{ dataset::{BTreeGraph, IndexedBTreeDataset, PatternMatchingDataset}, - interpretation::ReverseTermInterpretation, + interpretation::{ReverseTermInterpretation, WithGenerator}, vocabulary::IriVocabulary, - Id, Interpretation, InterpretationMut, LexicalQuad, Quad, Term, Triple, VocabularyMut, + Id, InterpretationMut, LexicalQuad, Quad, Term, Triple, Vocabulary, VocabularyMut, }; use serde::Serialize; use ssi_json_ld::{ - AnyJsonLdEnvironment, CompactJsonLd, JsonLdNodeObject, JsonLdObject, JsonLdTypes, + CompactJsonLd, ContextLoaderEnvironment, Expandable, ExpandedDocument, JsonLdError, + JsonLdNodeObject, JsonLdObject, JsonLdTypes, Loader, }; -use ssi_rdf::{urdna2015, AnyLdEnvironment, Expandable, IntoNQuads}; +use ssi_rdf::{urdna2015, Interpretation, IntoNQuads, LdEnvironment}; +use std::{borrow::Cow, hash::Hash}; use crate::{suite::SerializeCryptographicSuite, CryptographicSuite, ProofConfigurationRef}; @@ -31,56 +31,23 @@ impl<'a, S: CryptographicSuite> ProofConfigurationRef<'a, S> { pub async fn expand( self, - environment: &mut impl ConfigurationExpandingEnvironment, + environment: &impl ContextLoaderEnvironment, document: &impl JsonLdNodeObject, ) -> Result where S: SerializeCryptographicSuite, { - environment.expand_configuration(document, self).await - } -} - -/// Any environment able to expand a proof configuration. -/// -/// This trait only exists to alias all the trait bounds required for its -/// unique implementation. -pub trait ConfigurationExpandingEnvironment { - #[allow(async_fn_in_trait)] - async fn expand_configuration( - &mut self, - document: &impl JsonLdNodeObject, - proof_configuration: ProofConfigurationRef<'_, S>, - ) -> Result; -} - -impl ConfigurationExpandingEnvironment for E -where - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, - V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, - I: InterpretationMut - + ReverseTermInterpretation, - I::Resource: Clone, - L: json_ld::Loader, - L::Error: fmt::Display, -{ - async fn expand_configuration( - &mut self, - document: &impl JsonLdNodeObject, - proof_configuration: ProofConfigurationRef<'_, S>, - ) -> Result { - let embedded = proof_configuration.embed(document); - let expanded = embedded.expand(self).await?; - expanded.extract(self) + let embedded = self.embed(document); + let expanded = embedded.expand(environment.loader()).await?; + let mut interpretation = WithGenerator::new((), ssi_rdf::generator::Blank::new()); + expanded.extract(&mut (), &mut interpretation) } } #[derive(Debug, thiserror::Error)] pub enum ConfigurationExpansionError { #[error("JSON-LD expansion failed: {0}")] - Expansion(String), + Expansion(#[from] JsonLdError), #[error(transparent)] IntoQuads(#[from] ::linked_data::IntoQuadsError), @@ -101,17 +68,11 @@ pub enum ConfigurationExpansionError { InvalidContext, } -impl From> for ConfigurationExpansionError { - fn from(value: ssi_json_ld::JsonLdError) -> Self { - Self::Expansion(value.to_string()) - } -} - #[derive(Serialize)] #[serde(bound = "S: SerializeCryptographicSuite")] pub struct EmbeddedProofConfigurationRef<'d, 'a, S: CryptographicSuite> { #[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")] - context: Option>, + context: Option>, #[serde(rename = "type", skip_serializing_if = "JsonLdTypes::is_empty")] type_: JsonLdTypes<'d>, @@ -120,7 +81,7 @@ pub struct EmbeddedProofConfigurationRef<'d, 'a, S: CryptographicSuite> { } impl<'d, 'a, S: CryptographicSuite> JsonLdObject for EmbeddedProofConfigurationRef<'d, 'a, S> { - fn json_ld_context(&self) -> Option> { + fn json_ld_context(&self) -> Option> { self.context.as_deref().map(Cow::Borrowed) } } @@ -131,54 +92,60 @@ impl<'d, 'a, S: CryptographicSuite> JsonLdNodeObject for EmbeddedProofConfigurat } } -impl<'d, 'a, S: SerializeCryptographicSuite, E, V, L> Expandable +impl<'d, 'a, S: SerializeCryptographicSuite> Expandable for EmbeddedProofConfigurationRef<'d, 'a, S> -where - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash, - V::BlankId: Clone + Eq + Hash, - L: json_ld::Loader, - L::Error: fmt::Display, { type Error = ConfigurationExpansionError; - type Expanded = ExpandedEmbeddedProofConfiguration; - - async fn expand(&self, environment: &mut E) -> Result { + type Expanded = ExpandedEmbeddedProofConfiguration + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; + + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + { let json = json_syntax::to_value(self).unwrap(); Ok(ExpandedEmbeddedProofConfiguration( - CompactJsonLd(json).expand(environment).await?, + CompactJsonLd(json).expand_with(ld, loader).await?, )) } } -pub struct ExpandedEmbeddedProofConfiguration(json_ld::ExpandedDocument); +pub struct ExpandedEmbeddedProofConfiguration(ssi_json_ld::ExpandedDocument); impl ExpandedEmbeddedProofConfiguration where I: Clone + Eq + Hash, B: Clone + Eq + Hash, { - pub fn extract( + pub fn extract( self, - environment: &mut E, + vocabulary: &mut V, + interpretation: &mut R, ) -> Result where - E: AnyLdEnvironment, - E::Interpretation: InterpretationMut + R: InterpretationMut + ReverseTermInterpretation, - ::Resource: Clone, + R::Resource: Clone, V: VocabularyMut, - I: LinkedDataResource + LinkedDataSubject, - B: LinkedDataResource + LinkedDataSubject, + I: LinkedDataResource + LinkedDataSubject, + B: LinkedDataResource + LinkedDataSubject, { match self.0.into_main_node() { Some(node) => { - let env = environment.as_ld_environment_mut(); - // Get the proof type IRI. - let proof_prop = json_ld::Id::iri( - env.vocabulary + let proof_prop = ssi_json_ld::Id::iri( + vocabulary .get(ssi_security::PROOF) .ok_or(ConfigurationExpansionError::MissingProof)?, ); @@ -188,8 +155,8 @@ where Some(proof_graph) => match proof_graph.first() { Some(proof) => match proof.as_node() { Some(proof) => match proof.types() { - [json_ld::Id::Valid(Id::Iri(iri))] => { - Ok(env.vocabulary.iri(iri).unwrap().to_owned()) + [ssi_json_ld::Id::Valid(Id::Iri(iri))] => { + Ok(vocabulary.iri(iri).unwrap().to_owned()) } _ => Err(ConfigurationExpansionError::InvalidProofType), }, @@ -205,8 +172,8 @@ where }?; let (subject, quads) = ::linked_data::to_lexical_subject_quads_with( - env.vocabulary, - env.interpretation, + vocabulary, + interpretation, None, &node, )?; @@ -239,6 +206,19 @@ where } } +impl LinkedData + for ExpandedEmbeddedProofConfiguration +where + ExpandedDocument: LinkedData, +{ + fn visit(&self, visitor: S) -> Result + where + S: linked_data::Visitor, + { + self.0.visit(visitor) + } +} + /// Linked-Data proof configuration. pub struct ExpandedProofConfiguration { pub type_iri: IriBuf, diff --git a/crates/claims/crates/data-integrity/core/src/proof/configuration/mod.rs b/crates/claims/crates/data-integrity/core/src/proof/configuration/mod.rs index 7f32cc0da..216d55c4e 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/configuration/mod.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/configuration/mod.rs @@ -23,7 +23,7 @@ pub use reference::*; #[serde(rename_all = "camelCase", bound = "S: SerializeCryptographicSuite")] pub struct ProofConfiguration { #[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")] - pub context: Option, + pub context: Option, /// Proof type. #[serde(flatten, serialize_with = "S::serialize_type")] diff --git a/crates/claims/crates/data-integrity/core/src/proof/configuration/reference.rs b/crates/claims/crates/data-integrity/core/src/proof/configuration/reference.rs index 4d7006298..b5325d5a4 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/configuration/reference.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/configuration/reference.rs @@ -13,7 +13,7 @@ use crate::{ pub struct ProofConfigurationRef<'a, S: CryptographicSuite> { /// Proof context. #[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")] - pub context: Option<&'a json_ld::syntax::Context>, + pub context: Option<&'a ssi_json_ld::syntax::Context>, /// Proof type. #[serde(flatten, serialize_with = "S::serialize_type")] @@ -133,7 +133,7 @@ impl<'a, S: CryptographicSuite> ProofConfigurationRef<'a, S> { pub struct ProofConfigurationRefWithoutOptions<'a, S: CryptographicSuite> { /// Proof context. #[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")] - pub context: Option<&'a json_ld::syntax::Context>, + pub context: Option<&'a ssi_json_ld::syntax::Context>, /// Proof type. #[serde(flatten, serialize_with = "S::serialize_type")] diff --git a/crates/claims/crates/data-integrity/core/src/proof/mod.rs b/crates/claims/crates/data-integrity/core/src/proof/mod.rs index 2622cfa8b..9db729342 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/mod.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/mod.rs @@ -1,14 +1,13 @@ use crate::suite::bounds::{OptionsRefOf, SignatureRefOf, VerificationMethodRefOf}; -use crate::suite::{CryptographicSuiteInstance, SerializeCryptographicSuite}; +use crate::suite::{CryptographicSuiteVerification, SerializeCryptographicSuite}; use crate::{ CloneCryptographicSuite, CryptographicSuite, DataIntegrity, DebugCryptographicSuite, DeserializeCryptographicSuite, }; use educe::Educe; use serde::{Deserialize, Serialize}; -use ssi_claims_core::{AttachProof, ProofPreparationError}; +use ssi_claims_core::{AttachProof, ProofValidationError, ProofValidity}; use ssi_core::{one_or_many::OneOrManyRef, OneOrMany}; -use ssi_json_ld::JsonLdNodeObject; use ssi_verification_methods_core::{ProofPurpose, ReferenceOrOwned}; use std::collections::BTreeMap; use std::{ @@ -20,12 +19,12 @@ use std::{ mod de; mod configuration; -mod prepared; +// mod prepared; mod reference; mod r#type; pub use configuration::*; -pub use prepared::*; +// pub use prepared::*; pub use r#type::*; pub use reference::*; @@ -38,7 +37,7 @@ pub use reference::*; pub struct Proof { /// Proof context. #[serde(rename = "@context", default, skip_serializing_if = "Option::is_none")] - pub context: Option, + pub context: Option, /// Proof type. /// @@ -150,7 +149,7 @@ impl Proof { } } - pub fn with_context(self, context: json_ld::syntax::Context) -> Self { + pub fn with_context(self, context: ssi_json_ld::syntax::Context) -> Self { Self { context: Some(context), ..self @@ -219,30 +218,19 @@ impl fmt::Debug for Proof { } } -impl ssi_claims_core::Proof for Proof { - type Prepared = PreparedProof; -} - -impl ssi_claims_core::PrepareWith for Proof +impl ssi_claims_core::ValidateProof for Proof where - T: JsonLdNodeObject, - S: CryptographicSuiteInstance, + S: CryptographicSuiteVerification, { - /// Creates a new data integrity credential from the given input data. - /// - /// This will transform and hash the input data using the cryptographic - /// suite's transformation and hashing algorithms. - async fn prepare_with( - self, - value: &T, - environment: &mut E, - ) -> Result { - let hash = self - .type_ - .prepare_claims(environment, value, self.configuration()) - .await?; - - Ok(PreparedProof::new(self, hash)) + async fn validate_proof<'a>( + &'a self, + environment: &'a E, + claims: &'a T, + verifier: &'a V, + ) -> Result { + self.suite() + .verify_proof(environment, verifier, claims, self.borrowed()) + .await } } @@ -337,6 +325,20 @@ impl From>> for Proofs { } } +impl ssi_claims_core::ValidateProof for Proofs +where + S: CryptographicSuiteVerification, +{ + async fn validate_proof<'a>( + &'a self, + environment: &'a E, + claims: &'a T, + verifier: &'a V, + ) -> Result { + self.0.validate_proof(environment, claims, verifier).await + } +} + impl AttachProof for Proofs { type Attached = DataIntegrity; @@ -398,24 +400,3 @@ impl<'de, S: DeserializeCryptographicSuite<'de>> Deserialize<'de> for Proofs } } } - -impl ssi_claims_core::Proof for Proofs { - type Prepared = PreparedProofs; -} - -impl ssi_claims_core::PrepareWith for Proofs -where - T: JsonLdNodeObject, - S: CryptographicSuiteInstance, -{ - async fn prepare_with( - self, - claims: &T, - environment: &mut E, - ) -> Result { - self.0 - .prepare_with(claims, environment) - .await - .map(PreparedProofs) - } -} diff --git a/crates/claims/crates/data-integrity/core/src/proof/prepared.rs b/crates/claims/crates/data-integrity/core/src/proof/prepared.rs index aac4fad78..000b4eef2 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/prepared.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/prepared.rs @@ -61,7 +61,7 @@ where ) -> Result { self.proof() .suite() - .verify_prepared_claims(verifier, self.hash(), self.proof().borrowed()) + .verify_proof(verifier, self.hash(), self.proof().borrowed()) .await } } diff --git a/crates/claims/crates/data-integrity/core/src/proof/reference.rs b/crates/claims/crates/data-integrity/core/src/proof/reference.rs index 7383796f8..f9ed55dec 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/reference.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/reference.rs @@ -5,7 +5,7 @@ use ssi_verification_methods_core::{ProofPurpose, ReferenceOrOwnedRef}; use crate::{CryptographicSuite, ProofConfigurationRef}; pub struct ProofRef<'a, S: CryptographicSuite> { - pub context: Option<&'a json_ld::syntax::Context>, + pub context: Option<&'a ssi_json_ld::syntax::Context>, pub type_: &'a S, diff --git a/crates/claims/crates/data-integrity/core/src/signing/jws.rs b/crates/claims/crates/data-integrity/core/src/signing/jws.rs index e95e3564b..04a59c5d6 100644 --- a/crates/claims/crates/data-integrity/core/src/signing/jws.rs +++ b/crates/claims/crates/data-integrity/core/src/signing/jws.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, marker::PhantomData}; use ssi_claims_core::{ProofValidationError, SignatureError}; use ssi_jwk::{Algorithm, JWK}; -use ssi_jws::{CompactJWSString, JWS}; +use ssi_jws::{CompactJWSString, JWSSignature, JWS}; use ssi_verification_methods_core::{MessageSigner, VerifyBytes, VerifyBytesWithRecoveryJwk}; use crate::{ @@ -39,7 +39,7 @@ impl JwsSignature { pub fn decode( &self, message: &[u8], - ) -> Result<(Vec, Vec, Algorithm), ProofValidationError> { + ) -> Result<(Vec, JWSSignature, Algorithm), ProofValidationError> { let JWS { header, signature, .. } = self @@ -92,7 +92,7 @@ where async fn sign( verification_method: &S::VerificationMethod, signer: T, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof_configuration: ProofConfigurationRef<'_, S>, ) -> Result { JwsSignature::sign_detached( @@ -115,7 +115,7 @@ where { fn verify( method: &S::VerificationMethod, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof: ProofRef, ) -> Result { let JWS { @@ -154,7 +154,7 @@ where async fn sign( verification_method: &S::VerificationMethod, signer: T, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof_configuration: ProofConfigurationRef<'_, S>, ) -> Result { JwsSignature::sign_detached( @@ -178,7 +178,7 @@ where { fn verify( verification_method: &S::VerificationMethod, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof: ProofRef, ) -> Result { eprintln!("payload: {:?}", prepared_claims.as_ref()); diff --git a/crates/claims/crates/data-integrity/core/src/signing/multibase.rs b/crates/claims/crates/data-integrity/core/src/signing/multibase.rs index 25430f442..5f6a0c44b 100644 --- a/crates/claims/crates/data-integrity/core/src/signing/multibase.rs +++ b/crates/claims/crates/data-integrity/core/src/signing/multibase.rs @@ -87,7 +87,7 @@ where async fn sign( verification_method: &S::VerificationMethod, signer: T, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof_configuration: ProofConfigurationRef<'_, S>, ) -> Result { let algorithm = A::select_algorithm(verification_method, proof_configuration.options) @@ -110,7 +110,7 @@ where { fn verify( verification_method: &S::VerificationMethod, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof: ProofRef, ) -> Result { let algorithm = A::select_algorithm(verification_method, proof.options) diff --git a/crates/claims/crates/data-integrity/core/src/suite/bounds.rs b/crates/claims/crates/data-integrity/core/src/suite/bounds.rs index 08086b766..0afa31f2e 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/bounds.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/bounds.rs @@ -237,7 +237,10 @@ where } } -pub trait DeserializeCryptographicSuiteOwned: for<'de> DeserializeCryptographicSuite<'de> {} +pub trait DeserializeCryptographicSuiteOwned: + CryptographicSuite + for<'de> DeserializeCryptographicSuite<'de> +{ +} impl DeserializeCryptographicSuiteOwned for S where S: for<'de> DeserializeCryptographicSuite<'de> {} diff --git a/crates/claims/crates/data-integrity/core/src/suite/configuration.rs b/crates/claims/crates/data-integrity/core/src/suite/configuration.rs index ecd22508e..f7b388091 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/configuration.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/configuration.rs @@ -69,7 +69,7 @@ pub struct AddProofContext(PhantomData); impl ConfigurationAlgorithm for AddProofContext where - C: Default + Into, + C: Default + Into, { type InputVerificationMethod = S::VerificationMethod; type InputSuiteOptions = S::ProofOptions; diff --git a/crates/claims/crates/data-integrity/core/src/suite/mod.rs b/crates/claims/crates/data-integrity/core/src/suite/mod.rs index 910f72ea4..294e32ea8 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/mod.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/mod.rs @@ -1,5 +1,5 @@ use ssi_claims_core::{ - ProofPreparationError, ProofValidationError, ProofValidity, SignatureError, Verifiable, + ProofPreparationError, ProofValidationError, SignatureEnvironment, SignatureError, }; use ssi_verification_methods_core::VerificationMethod; @@ -9,9 +9,7 @@ pub use signature::*; mod verification; pub use verification::*; -use crate::{ - PreparedProof, Proof, ProofConfiguration, ProofConfigurationRef, ProofRef, Proofs, TypeRef, -}; +use crate::{DataIntegrity, ProofConfiguration, TypeRef}; mod configuration; pub use configuration::*; @@ -69,90 +67,113 @@ pub trait CryptographicSuite: Clone { /// Generates a verifiable document secured with this cryptographic suite. #[allow(async_fn_in_trait)] - async fn sign( + async fn sign_with( &self, + context: C, unsecured_document: T, - mut context: C, resolver: R, signer: S, options: InputOptions, - ) -> Result>, SignatureError> + ) -> Result, SignatureError> where - Self: CryptographicSuiteInstance + CryptographicSuiteSigning, + Self: CryptographicSuiteSigning, { let proof_configuration = self.configure(options)?; let proof_configuration_ref = proof_configuration.borrowed(); - let prepared_claims = self - .prepare_claims(&mut context, &unsecured_document, proof_configuration_ref) - .await?; let signature = self - .sign_prepared_claims(resolver, signer, &prepared_claims, proof_configuration_ref) + .generate_signature( + &context, + resolver, + signer, + &unsecured_document, + proof_configuration_ref, + ) .await?; + let proof = proof_configuration.into_proof(signature); - Ok(Verifiable::from_parts( - unsecured_document, - PreparedProof::new(proof, prepared_claims).into(), - )) + Ok(DataIntegrity::new(unsecured_document, proof.into())) } -} -/// Cryptographic suite instance. -/// -/// See: -pub trait CryptographicSuiteInstance: CryptographicSuite { - /// Prepare the input claims for signing or verification. - #[allow(async_fn_in_trait)] - async fn prepare_claims( - &self, - context: &mut C, - unsecured_document: &T, - proof_configuration: ProofConfigurationRef, - ) -> Result; - - /// Create a proof by signing the given unsecured document. + /// Generates a verifiable document secured with this cryptographic suite. #[allow(async_fn_in_trait)] - async fn create_proof( + async fn sign( &self, - context: &mut C, + unsecured_document: T, resolver: R, signer: S, - unsecured_document: &T, options: InputOptions, - ) -> Result, SignatureError> + ) -> Result, SignatureError> where - Self: CryptographicSuiteSigning, + Self: CryptographicSuiteSigning, { - let proof_configuration = self.configure(options)?; - let proof_configuration_ref = proof_configuration.borrowed(); - let prepared_claims = self - .prepare_claims(context, unsecured_document, proof_configuration_ref) - .await?; - let signature = self - .sign_prepared_claims(resolver, signer, &prepared_claims, proof_configuration_ref) - .await?; - Ok(proof_configuration.into_proof(signature)) - } - - /// Verify a proof of the given unsecured document. - #[allow(async_fn_in_trait)] - async fn verify_proof( - &self, - context: &mut C, - verifier: &V, - unsecured_document: &T, - proof: ProofRef<'_, Self>, - ) -> Result - where - Self: CryptographicSuiteVerification, - { - let prepared_claims = self - .prepare_claims(context, unsecured_document, proof.configuration()) - .await?; - self.verify_prepared_claims(verifier, &prepared_claims, proof) - .await + self.sign_with( + SignatureEnvironment::default(), + unsecured_document, + resolver, + signer, + options, + ) + .await } } +// /// Cryptographic suite instance. +// /// +// /// See: +// pub trait CryptographicSuiteInstance: CryptographicSuite { +// /// Prepare the input claims for signing or verification. +// #[allow(async_fn_in_trait)] +// async fn prepare_claims( +// &self, +// context: &mut C, +// unsecured_document: &T, +// proof_configuration: ProofConfigurationRef, +// ) -> Result; + +// /// Create a proof by signing the given unsecured document. +// #[allow(async_fn_in_trait)] +// async fn create_proof( +// &self, +// context: &mut C, +// resolver: R, +// signer: S, +// unsecured_document: &T, +// options: InputOptions, +// ) -> Result, SignatureError> +// where +// Self: CryptographicSuiteSigning, +// { +// let proof_configuration = self.configure(options)?; +// let proof_configuration_ref = proof_configuration.borrowed(); +// let prepared_claims = self +// .prepare_claims(context, unsecured_document, proof_configuration_ref) +// .await?; +// let signature = self +// .sign_prepared_claims(resolver, signer, &prepared_claims, proof_configuration_ref) +// .await?; +// Ok(proof_configuration.into_proof(signature)) +// } + +// /// Verify a proof of the given unsecured document. +// #[allow(async_fn_in_trait)] +// async fn verify_proof( +// &self, +// context: &mut C, +// verifier: &V, +// unsecured_document: &T, +// proof: ProofRef<'_, Self>, +// ) -> Result +// where +// Self: CryptographicSuiteVerification, +// { +// let prepared_claims = self +// .prepare_claims(context, unsecured_document, proof.configuration()) +// .await?; +// self.verify_prepared_claims(verifier, &prepared_claims, proof) +// .await +// } +// } + #[derive(Debug, thiserror::Error)] pub enum ClaimsPreparationError { #[error("proof configuration failed: {0}")] diff --git a/crates/claims/crates/data-integrity/core/src/suite/signature.rs b/crates/claims/crates/data-integrity/core/src/suite/signature.rs index 02d181a37..2df7a3635 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/signature.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/signature.rs @@ -3,13 +3,14 @@ use ssi_claims_core::SignatureError; use super::CryptographicSuite; -pub trait CryptographicSuiteSigning: CryptographicSuite { +pub trait CryptographicSuiteSigning: CryptographicSuite { #[allow(async_fn_in_trait)] - async fn sign_prepared_claims( + async fn generate_signature( &self, + context: &C, resolver: R, signer: S, - prepared_claims: &Self::PreparedClaims, + claims: &T, proof_configuration: ProofConfigurationRef<'_, Self>, ) -> Result; } diff --git a/crates/claims/crates/data-integrity/core/src/suite/standard/hashing.rs b/crates/claims/crates/data-integrity/core/src/suite/standard/hashing.rs index 6f122ef1b..3a3e71d9b 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/standard/hashing.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/standard/hashing.rs @@ -1,4 +1,4 @@ -use ssi_claims_core::SignatureError; +use ssi_claims_core::{ProofValidationError, SignatureError}; use crate::ProofConfigurationRef; @@ -22,6 +22,12 @@ impl From for SignatureError { } } +impl From for ProofValidationError { + fn from(value: HashingError) -> Self { + Self::other(value) + } +} + /// Hashing algorithm. pub trait HashingAlgorithm { type Output; diff --git a/crates/claims/crates/data-integrity/core/src/suite/standard/mod.rs b/crates/claims/crates/data-integrity/core/src/suite/standard/mod.rs index 8a3c9627f..8670080b2 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/standard/mod.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/standard/mod.rs @@ -18,10 +18,7 @@ pub use signature::*; mod verification; pub use verification::*; -use super::{ - ClaimsPreparationError, ConfigurationAlgorithm, CryptographicSuiteInstance, - CryptographicSuiteSigning, CryptographicSuiteVerification, -}; +use super::{ConfigurationAlgorithm, CryptographicSuiteSigning, CryptographicSuiteVerification}; // mod test_bbs; @@ -56,7 +53,7 @@ pub trait StandardCryptographicSuite: Clone { #[allow(async_fn_in_trait)] async fn transform( &self, - context: &mut C, + context: &C, unsecured_document: &T, options: ProofConfigurationRef<'_, Self>, ) -> Result, TransformationError> @@ -101,19 +98,25 @@ impl CryptographicSuite for S { } } -impl CryptographicSuiteSigning for S +impl CryptographicSuiteSigning for S where R: VerificationMethodResolver, T: Signer<::VerificationMethod>, + S::Transformation: TypedTransformationAlgorithm, S::SignatureAlgorithm: SignatureAlgorithm, { - async fn sign_prepared_claims( + async fn generate_signature( &self, + context: &E, resolver: R, signers: T, - prepared_claims: &Self::PreparedClaims, + claims: &C, proof_configuration: ProofConfigurationRef<'_, Self>, ) -> Result { + let transformed = self.transform(context, claims, proof_configuration).await?; + + let hashed = self.hash(transformed, proof_configuration)?; + let options = ssi_verification_methods_core::ResolutionOptions { accept: Some(Box::new(Self::VerificationMethod::type_set())), }; @@ -133,21 +136,29 @@ where .await .ok_or(SignatureError::MissingSigner)?; - S::SignatureAlgorithm::sign(&method, signer, prepared_claims, proof_configuration).await + S::SignatureAlgorithm::sign(&method, signer, hashed, proof_configuration).await } } -impl CryptographicSuiteVerification for S +impl CryptographicSuiteVerification for S where V: VerificationMethodResolver, + S::Transformation: TypedTransformationAlgorithm, S::SignatureAlgorithm: VerificationAlgorithm, { - async fn verify_prepared_claims( + async fn verify_proof( &self, + context: &E, verifier: &V, - prepared_claims: &Self::PreparedClaims, + claims: &C, proof: ProofRef<'_, Self>, ) -> Result { + let proof_configuration = proof.configuration(); + + let transformed = self.transform(context, claims, proof_configuration).await?; + + let hashed = self.hash(transformed, proof_configuration)?; + let options = ssi_verification_methods_core::ResolutionOptions { accept: Some(Box::new(Self::VerificationMethod::type_set())), }; @@ -157,27 +168,6 @@ where .resolve_verification_method_with(None, Some(proof.verification_method), options) .await?; - S::SignatureAlgorithm::verify(&method, prepared_claims, proof) - } -} - -impl CryptographicSuiteInstance for S -where - S::Transformation: TypedTransformationAlgorithm, -{ - async fn prepare_claims( - &self, - context: &mut C, - unsecured_document: &T, - proof_configuration: ProofConfigurationRef<'_, Self>, - ) -> Result { - // Transform unsecured document. - let transformed = self - .transform(context, unsecured_document, proof_configuration) - .await?; - - // Hashing. - self.hash(transformed, proof_configuration) - .map_err(Into::into) + S::SignatureAlgorithm::verify(&method, hashed, proof) } } diff --git a/crates/claims/crates/data-integrity/core/src/suite/standard/signature.rs b/crates/claims/crates/data-integrity/core/src/suite/standard/signature.rs index 92d44aef7..60e5abfc7 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/standard/signature.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/standard/signature.rs @@ -11,7 +11,7 @@ pub trait SignatureAlgorithm: SignatureAndVerification async fn sign( verification_method: &S::VerificationMethod, signer: T, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof_configuration: ProofConfigurationRef<'_, S>, ) -> Result; } diff --git a/crates/claims/crates/data-integrity/core/src/suite/standard/transformation.rs b/crates/claims/crates/data-integrity/core/src/suite/standard/transformation.rs index d05820a0c..f4929f735 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/standard/transformation.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/standard/transformation.rs @@ -1,6 +1,6 @@ use linked_data::IntoQuadsError; use serde::Serialize; -use ssi_claims_core::SignatureError; +use ssi_claims_core::{ProofValidationError, SignatureError}; use crate::{ConfigurationExpansionError, CryptographicSuite, ProofConfigurationRef}; @@ -45,6 +45,12 @@ impl From for SignatureError { } } +impl From for ProofValidationError { + fn from(value: TransformationError) -> Self { + Self::other(value) + } +} + /// Transformation algorithm definition. pub trait TransformationAlgorithm { /// Transformed data. @@ -56,7 +62,7 @@ pub trait TypedTransformationAlgorithm: { #[allow(async_fn_in_trait)] async fn transform( - context: &mut C, + context: &C, data: &T, options: ProofConfigurationRef, ) -> Result; @@ -72,7 +78,7 @@ impl TypedTransformationAlgorithm, ) -> Result { diff --git a/crates/claims/crates/data-integrity/core/src/suite/standard/verification.rs b/crates/claims/crates/data-integrity/core/src/suite/standard/verification.rs index 82a30cc9a..8b9da6ee6 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/standard/verification.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/standard/verification.rs @@ -5,7 +5,7 @@ use crate::{CryptographicSuite, ProofRef}; pub trait VerificationAlgorithm { fn verify( method: &S::VerificationMethod, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof: ProofRef, ) -> Result; } diff --git a/crates/claims/crates/data-integrity/core/src/suite/verification.rs b/crates/claims/crates/data-integrity/core/src/suite/verification.rs index 4468f7a95..b4edca680 100644 --- a/crates/claims/crates/data-integrity/core/src/suite/verification.rs +++ b/crates/claims/crates/data-integrity/core/src/suite/verification.rs @@ -2,12 +2,13 @@ use super::CryptographicSuite; use crate::ProofRef; use ssi_claims_core::{ProofValidationError, ProofValidity}; -pub trait CryptographicSuiteVerification: CryptographicSuite { +pub trait CryptographicSuiteVerification: CryptographicSuite { #[allow(async_fn_in_trait)] - async fn verify_prepared_claims( + async fn verify_proof( &self, + context: &C, verifier: &V, - prepared_claims: &Self::PreparedClaims, + claims: &T, proof: ProofRef<'_, Self>, ) -> Result; } diff --git a/crates/claims/crates/data-integrity/src/any/context.rs b/crates/claims/crates/data-integrity/src/any/context.rs deleted file mode 100644 index 75c5b8ab9..000000000 --- a/crates/claims/crates/data-integrity/src/any/context.rs +++ /dev/null @@ -1,115 +0,0 @@ -use rdf_types::{ - generator, - interpretation::{self, WithGenerator}, - vocabulary::IriVocabulary, -}; -use ssi_json_ld::{AnyJsonLdEnvironment, ContextLoader, JsonLdEnvironment}; -use ssi_rdf::{AnyLdEnvironment, LdEnvironment}; - -/// Input environment for any cryptographic suite supported by `AnySuite` with -/// a given JSON-LD context loader and sensible defaults for the vocabulary, -/// interpretation and EIP712 type loader. -pub type AnyEnvironmentWithLdLoader = - AnyInputContext, L>>; - -/// Input context for any cryptographic suite supported by `AnySuite`. -pub struct AnyInputContext { - /// The Linked-Data context used to interpret RDF terms. - pub ld: E, - - /// Remote resources loader. - /// - /// Used for instance with the `EthereumEip712Signature2021` suite to load - /// EIP712 type definitions from the URI given in the proof options. - pub loader: L, -} - -impl AnyInputContext { - pub fn new(ld: E, loader: L) -> Self { - Self { ld, loader } - } -} - -impl AnyInputContext, L>> { - pub fn from_ld_context_loader(loader: L) -> Self { - Self { - ld: JsonLdEnvironment::from_loader(loader), - loader: (), - } - } -} - -impl AnyLdEnvironment for AnyInputContext { - type Vocabulary = E::Vocabulary; - type Interpretation = E::Interpretation; - - fn as_ld_environment_mut( - &mut self, - ) -> LdEnvironment<&mut Self::Vocabulary, &mut Self::Interpretation> { - self.ld.as_ld_environment_mut() - } -} - -impl AnyJsonLdEnvironment for AnyInputContext -where - E::Vocabulary: IriVocabulary, -{ - type Loader = E::Loader; - - fn as_json_ld_environment_mut( - &mut self, - ) -> ssi_json_ld::JsonLdEnvironment< - &mut Self::Vocabulary, - &mut Self::Interpretation, - &mut Self::Loader, - > { - self.ld.as_json_ld_environment_mut() - } -} - -impl - ssi_data_integrity_suites::eip712::TypesProvider for AnyInputContext -{ - async fn fetch_types( - &self, - uri: &iref::Uri, - ) -> Result { - self.loader.fetch_types(uri).await - } -} - -impl AnyInputContext { - pub fn from_environment(ld: E) -> Self { - Self { ld, loader: () } - } -} - -impl From> for AnyInputContext> { - fn from(value: LdEnvironment) -> Self { - AnyInputContext { - ld: value, - loader: (), - } - } -} - -impl Default - for AnyInputContext< - JsonLdEnvironment<(), interpretation::WithGenerator>, - (), - > -{ - fn default() -> Self { - Self { - ld: JsonLdEnvironment { - vocabulary: (), - interpretation: interpretation::WithGenerator::new( - (), - rdf_types::generator::Blank::new(), - ), - loader: ContextLoader::default(), - }, - loader: (), - } - } -} diff --git a/crates/claims/crates/data-integrity/src/any/macros.rs b/crates/claims/crates/data-integrity/src/any/macros.rs index 609337e95..4117decd1 100644 --- a/crates/claims/crates/data-integrity/src/any/macros.rs +++ b/crates/claims/crates/data-integrity/src/any/macros.rs @@ -126,58 +126,22 @@ macro_rules! crypto_suites { )* #[allow(unused_variables)] - impl ssi_data_integrity_core::suite::CryptographicSuiteInstance for AnySuite - where - C: ssi_json_ld::AnyJsonLdEnvironment - + ssi_data_integrity_suites::eip712::TypesProvider, - V: rdf_types::VocabularyMut, - V::Iri: Clone + Eq + std::hash::Hash + linked_data::LinkedDataSubject + linked_data::LinkedDataResource, - V::BlankId: Clone + Eq + std::hash::Hash + linked_data::LinkedDataSubject + linked_data::LinkedDataResource, - I: rdf_types::InterpretationMut - + rdf_types::interpretation::ReverseTermInterpretation, - I::Resource: Clone, - L: json_ld::Loader, - L::Error: std::fmt::Display, - T: serde::Serialize + ssi_rdf::Expandable + ssi_json_ld::JsonLdNodeObject, - T::Expanded: linked_data::LinkedData - { - async fn prepare_claims( - &self, - context: &mut C, - unsecured_document: &T, - proof_configuration: ssi_data_integrity_core::ProofConfigurationRef<'_, Self>, - ) -> Result { - match self { - $( - $(#[cfg($($t)*)])? - Self::$name => { - >::prepare_claims( - &ssi_data_integrity_suites::$name, - context, - unsecured_document, - Self::project_proof_configuration(proof_configuration) - ).await.map(AnyPreparedClaims::$name) - }, - )* - Self::Unknown(_) => { - Ok(AnyPreparedClaims::Unknown) - } - } - } - } - - #[allow(unused_variables)] - impl ssi_data_integrity_core::suite::CryptographicSuiteSigning for AnySuite + impl ssi_data_integrity_core::suite::CryptographicSuiteSigning for AnySuite where + C: ssi_json_ld::ContextLoaderEnvironment + + ssi_eip712::Eip712TypesEnvironment, + T: serde::Serialize + ssi_json_ld::Expandable + ssi_json_ld::JsonLdNodeObject, + // R: ssi_verification_methods::VerificationMethodResolver, S: ssi_verification_methods::Signer, S::MessageSigner: ssi_verification_methods::MessageSigner { - async fn sign_prepared_claims( + async fn generate_signature( &self, + context: &C, resolver: R, signer: S, - prepared_claims: &AnyPreparedClaims, + claims: &T, proof_configuration: ssi_data_integrity_core::ProofConfigurationRef<'_, Self>, ) -> Result { match self { @@ -187,11 +151,12 @@ macro_rules! crypto_suites { let signer = crate::AnySigner(signer); let resolver = crate::AnyResolver::<_, ::VerificationMethod>::new(resolver); - >::sign_prepared_claims( + >::generate_signature( &ssi_data_integrity_suites::$name, + context, resolver, signer, - >::project_prepared_claims(prepared_claims), + claims, Self::project_proof_configuration(proof_configuration) ).await.map(AnySignature::$name) }, @@ -204,14 +169,19 @@ macro_rules! crypto_suites { } #[allow(unused_variables)] - impl ssi_data_integrity_core::suite::CryptographicSuiteVerification for AnySuite + impl ssi_data_integrity_core::suite::CryptographicSuiteVerification for AnySuite where - V: ssi_verification_methods::VerificationMethodResolver, + C: ssi_json_ld::ContextLoaderEnvironment + + ssi_eip712::Eip712TypesEnvironment, + T: serde::Serialize + ssi_json_ld::Expandable + ssi_json_ld::JsonLdNodeObject, + // + F: ssi_verification_methods::VerificationMethodResolver, { - async fn verify_prepared_claims( + async fn verify_proof( &self, - verifier: &V, - prepared_claims: &AnyPreparedClaims, + environment: &C, + verifier: &F, + claims: &T, proof: ssi_data_integrity_core::ProofRef<'_, Self>, ) -> Result { match self { @@ -220,10 +190,11 @@ macro_rules! crypto_suites { Self::$name => { let verifier = crate::AnyResolver::<_, ::VerificationMethod>::new(verifier); - >::verify_prepared_claims( + >::verify_proof( &ssi_data_integrity_suites::$name, + environment, &verifier, - >::project_prepared_claims(prepared_claims), + claims, Self::project_proof(proof) ).await }, diff --git a/crates/claims/crates/data-integrity/src/any/mod.rs b/crates/claims/crates/data-integrity/src/any/mod.rs index 22fc594bc..15b4b563b 100644 --- a/crates/claims/crates/data-integrity/src/any/mod.rs +++ b/crates/claims/crates/data-integrity/src/any/mod.rs @@ -1,4 +1,3 @@ -mod context; pub(crate) mod macros; mod options; mod protocol; @@ -6,7 +5,6 @@ mod resolution; mod signature; mod suite; -pub use context::*; pub use options::*; pub use protocol::*; pub use resolution::*; diff --git a/crates/claims/crates/data-integrity/src/any/suite/mod.rs b/crates/claims/crates/data-integrity/src/any/suite/mod.rs index 9065dd042..9e999e159 100644 --- a/crates/claims/crates/data-integrity/src/any/suite/mod.rs +++ b/crates/claims/crates/data-integrity/src/any/suite/mod.rs @@ -1,11 +1,7 @@ -use ssi_claims_core::DefaultEnvironment; - -// mod requirements; - mod unknown; pub use unknown::*; -use crate::{macros, AnyInputContext}; +use crate::macros; mod pick; @@ -98,10 +94,6 @@ macros::crypto_suites! { ethereum_personal_signature_2021_v0_1: EthereumPersonalSignature2021v0_1 } -impl DefaultEnvironment for AnySuite { - type Environment = AnyInputContext; -} - impl AnyProofOptions { #[cfg(all(feature = "w3c", feature = "eip712"))] pub fn eip712( diff --git a/crates/claims/crates/data-integrity/suites/Cargo.toml b/crates/claims/crates/data-integrity/suites/Cargo.toml index 60fb14af6..050b5e7c2 100644 --- a/crates/claims/crates/data-integrity/suites/Cargo.toml +++ b/crates/claims/crates/data-integrity/suites/Cargo.toml @@ -109,7 +109,6 @@ multibase.workspace = true iref.workspace = true thiserror.workspace = true static-iref.workspace = true -json-ld = { workspace = true, features = ["serde"] } locspan.workspace = true hex.workspace = true serde = { workspace = true, features = ["derive"] } diff --git a/crates/claims/crates/data-integrity/suites/src/eip712/mod.rs b/crates/claims/crates/data-integrity/suites/src/eip712/mod.rs index d73140516..e87265638 100644 --- a/crates/claims/crates/data-integrity/suites/src/eip712/mod.rs +++ b/crates/claims/crates/data-integrity/suites/src/eip712/mod.rs @@ -1,5 +1,3 @@ -use iref::Uri; - mod hashing; pub use hashing::Eip712Hashing; @@ -83,36 +81,3 @@ impl Input { "Document".into() } } - -/// Errors that can occur while fetching remote EIP712 type definitions. -#[derive(Debug, thiserror::Error)] -pub enum TypesFetchError { - /// Error for applications that do not support remote types. - /// - /// This is the error always returned by the `()` implementation of - /// `TypesProvider`. - #[error("remote EIP712 types are not supported")] - Unsupported, -} - -/// Type providing remote EIP712 type definitions from an URI. -/// -/// A default implementation is provided for the `()` type that always return -/// `TypesFetchError::Unsupported`. -pub trait TypesProvider { - /// Fetches the type definitions located behind the given `uri`. - /// - /// This is an asynchronous function returning a `Self::Fetch` future that - /// resolves into ether the EIP712 [`Types`](ssi_eip712::Types) or an error - /// of type `TypesFetchError`. - #[allow(async_fn_in_trait)] - async fn fetch_types(&self, uri: &Uri) -> Result; -} - -/// Simple EIP712 loader implementation that always return -/// `TypesFetchError::Unsupported`. -impl TypesProvider for () { - async fn fetch_types(&self, _uri: &Uri) -> Result { - Err(TypesFetchError::Unsupported) - } -} diff --git a/crates/claims/crates/data-integrity/suites/src/suites/dif/ecdsa_secp256k1_recovery_signature_2020.rs b/crates/claims/crates/data-integrity/suites/src/suites/dif/ecdsa_secp256k1_recovery_signature_2020.rs index ead74d304..5aa8c7427 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/dif/ecdsa_secp256k1_recovery_signature_2020.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/dif/ecdsa_secp256k1_recovery_signature_2020.rs @@ -42,7 +42,7 @@ impl StandardCryptographicSuite for EcdsaSecp256k1RecoverySignature2020 { #[derive(Default)] pub struct Secp256k1Recovery2020v2Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: Secp256k1Recovery2020v2Context) -> Self { iri!("https://w3id.org/security/suites/secp256k1recovery-2020/v2").into() } diff --git a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/aleo_signature_2021.rs b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/aleo_signature_2021.rs index 7aef81d61..961bbc42b 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/aleo_signature_2021.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/aleo_signature_2021.rs @@ -99,7 +99,7 @@ where async fn sign( _verification_method: &VerificationMethod, _signer: T, - _prepared_claims: &[u8; 64], + _prepared_claims: [u8; 64], _proof_configuration: ProofConfigurationRef<'_, AleoSignature2021>, ) -> Result { // ssi_jws::sign_bytes(algorithm, data, key) @@ -113,7 +113,7 @@ where impl VerificationAlgorithm for AleoSignatureAlgorithm { fn verify( method: &VerificationMethod, - prepared_claims: &[u8; 64], + prepared_claims: [u8; 64], proof: ProofRef, ) -> Result { let (_, signature_bytes) = multibase::decode(&proof.signature.proof_value) @@ -130,7 +130,7 @@ impl VerificationAlgorithm for AleoSignatureAlgorithm { } let result = ssi_jwk::aleo::verify( - prepared_claims, + &prepared_claims, &account_id.account_address, &signature_bytes, ); diff --git a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/eip712_signature_2021.rs b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/eip712_signature_2021.rs index 0588c9ecd..c980debd2 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/eip712_signature_2021.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/eip712_signature_2021.rs @@ -1,12 +1,6 @@ //! EIP-712 Signature 2021 implementation. use crate::eip712::{Eip712Hashing, Eip712Signature}; -use linked_data::LinkedData; -use rdf_types::{ - interpretation::{ - ReverseBlankIdInterpretation, ReverseIriInterpretation, ReverseLiteralInterpretation, - }, - InterpretationMut, LexicalQuad, Quad, Vocabulary, -}; +use rdf_types::{LexicalQuad, Quad}; use ssi_claims_core::{ProofValidationError, ProofValidity, SignatureError}; use ssi_data_integrity_core::{ suite::{ @@ -16,11 +10,10 @@ use ssi_data_integrity_core::{ }, AddProofContext, }, - ConfigurationExpandingEnvironment, CryptographicSuite, ProofConfigurationRef, - StandardCryptographicSuite, TypeRef, + CryptographicSuite, ProofConfigurationRef, StandardCryptographicSuite, TypeRef, }; -use ssi_json_ld::JsonLdNodeObject; -use ssi_rdf::{AnyLdEnvironment, Expandable, NQuadsStatement}; +use ssi_json_ld::{ContextLoaderEnvironment, Expandable, JsonLdNodeObject}; +use ssi_rdf::{AnyLdEnvironment, LdEnvironment, NQuadsStatement}; use ssi_verification_methods::{ ecdsa_secp_256k1_recovery_method_2020, ecdsa_secp_256k1_verification_key_2019, verification_method_union, AnyMethod, EcdsaSecp256k1RecoveryMethod2020, @@ -29,7 +22,7 @@ use ssi_verification_methods::{ use static_iref::iri; lazy_static::lazy_static! { - pub static ref EIP712VM_CONTEXT: json_ld::syntax::ContextEntry = { + pub static ref EIP712VM_CONTEXT: ssi_json_ld::syntax::ContextEntry = { let context_str = ssi_contexts::EIP712VM; serde_json::from_str(context_str).unwrap() }; @@ -38,9 +31,9 @@ lazy_static::lazy_static! { #[derive(Default)] pub struct Eip712VmContext; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: Eip712VmContext) -> Self { - json_ld::syntax::Context::One(EIP712VM_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(EIP712VM_CONTEXT.clone()) } } @@ -110,28 +103,24 @@ impl TransformationAlgorithm for Eip712Transformation { type Output = ssi_eip712::TypedData; } -impl TypedTransformationAlgorithm for Eip712Transformation +impl TypedTransformationAlgorithm for Eip712Transformation where - T: Expandable + JsonLdNodeObject, - T::Expanded: LinkedData, - C: AnyLdEnvironment + ConfigurationExpandingEnvironment, - V: Vocabulary, - I: InterpretationMut - + ReverseIriInterpretation - + ReverseBlankIdInterpretation - + ReverseLiteralInterpretation, + T: Expandable + JsonLdNodeObject, + C: ContextLoaderEnvironment, { async fn transform( - context: &mut C, + context: &C, data: &T, proof_configuration: ProofConfigurationRef<'_, Eip712Signature2021>, ) -> Result { + let mut ld = LdEnvironment::default(); + let expanded = data - .expand(context) + .expand_with(&mut ld, context.loader()) .await .map_err(|e| TransformationError::JsonLdExpansion(e.to_string()))?; - let claims = context + let claims = ld .canonical_quads_of(&expanded) .map_err(TransformationError::JsonLdDeserialization)?; @@ -258,7 +247,7 @@ where async fn sign( verification_method: &::VerificationMethod, signer: T, - prepared_claims: &::PreparedClaims, + prepared_claims: ::PreparedClaims, _proof_configuration: ProofConfigurationRef<'_, Eip712Signature2021>, ) -> Result { Eip712Signature::sign( @@ -273,7 +262,7 @@ where impl VerificationAlgorithm for Eip712SignatureAlgorithm { fn verify( method: &::VerificationMethod, - prepared_claims: &::PreparedClaims, + prepared_claims: ::PreparedClaims, proof: ssi_data_integrity_core::ProofRef, ) -> Result { let signature_bytes = proof.signature.decode()?; diff --git a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/ethereum_personal_signature_2021.rs b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/ethereum_personal_signature_2021.rs index 0c84fd9cd..56cf91d82 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/ethereum_personal_signature_2021.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/ethereum_personal_signature_2021.rs @@ -22,7 +22,7 @@ mod v0_1; pub use v0_1::*; lazy_static::lazy_static! { - pub static ref EPSIG_CONTEXT: json_ld::syntax::ContextEntry = { + pub static ref EPSIG_CONTEXT: ssi_json_ld::syntax::ContextEntry = { let context_str = ssi_contexts::EPSIG_V0_1; serde_json::from_str(context_str).unwrap() }; @@ -62,9 +62,9 @@ impl StandardCryptographicSuite for EthereumPersonalSignature2021 { #[derive(Default)] pub struct EthereumPersonalSignature2021Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: EthereumPersonalSignature2021Context) -> Self { - json_ld::syntax::Context::One(EPSIG_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(EPSIG_CONTEXT.clone()) } } @@ -113,7 +113,7 @@ where async fn sign( verification_method: &S::VerificationMethod, signer: T, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, _proof_configuration: ProofConfigurationRef<'_, S>, ) -> Result { let proof_value_bytes = signer @@ -136,7 +136,7 @@ where { fn verify( method: &S::VerificationMethod, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, proof: ProofRef, ) -> Result { let message = EthereumWallet::prepare_message(prepared_claims.as_ref()); diff --git a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/ethereum_personal_signature_2021/v0_1.rs b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/ethereum_personal_signature_2021/v0_1.rs index 56ded3edb..a74101c86 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/ethereum_personal_signature_2021/v0_1.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/ethereum_personal_signature_2021/v0_1.rs @@ -37,8 +37,8 @@ impl StandardCryptographicSuite for EthereumPersonalSignature2021v0_1 { #[derive(Default)] pub struct EthereumPersonalSignature2021v0_1Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: EthereumPersonalSignature2021v0_1Context) -> Self { - json_ld::syntax::Context::One(EPSIG_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(EPSIG_CONTEXT.clone()) } } diff --git a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/solana_signature_2021.rs b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/solana_signature_2021.rs index 701541baf..acdcc70fc 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/solana_signature_2021.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/solana_signature_2021.rs @@ -89,7 +89,7 @@ where async fn sign( _verification_method: &SolanaMethod2021, _signer: T, - _prepared_claims: &[u8; 64], + _prepared_claims: [u8; 64], _proof_configuration: ProofConfigurationRef<'_, SolanaSignature2021>, ) -> Result { todo!() @@ -99,10 +99,10 @@ where impl VerificationAlgorithm for SolanaSignatureAlgorithm { fn verify( method: &SolanaMethod2021, - prepared_claims: &[u8; 64], + prepared_claims: [u8; 64], proof: ProofRef, ) -> Result { - let tx = LocalSolanaTransaction::with_message(prepared_claims); + let tx = LocalSolanaTransaction::with_message(&prepared_claims); let signing_bytes = tx.to_bytes(); let signature_bytes = Base58Btc::decode_signature(proof.signature.proof_value.as_bytes()) diff --git a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos.rs b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos.rs index 243917889..4ea18d7d1 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos.rs @@ -31,17 +31,17 @@ const P2SIG_PREFIX: [u8; 4] = [54, 240, 44, 52]; lazy_static::lazy_static! { /// JSON-LD context for Linked Data Proofs based on Tezos addresses - pub static ref TZ_CONTEXT: json_ld::syntax::ContextEntry = { + pub static ref TZ_CONTEXT: ssi_json_ld::syntax::ContextEntry = { let context_str = ssi_contexts::TZ_V2; serde_json::from_str(context_str).unwrap() }; - pub static ref TZVM_CONTEXT: json_ld::syntax::ContextEntry = { + pub static ref TZVM_CONTEXT: ssi_json_ld::syntax::ContextEntry = { let context_str = ssi_contexts::TZVM_V1; serde_json::from_str(context_str).unwrap() }; - pub static ref TZJCSVM_CONTEXT: json_ld::syntax::ContextEntry = { + pub static ref TZJCSVM_CONTEXT: ssi_json_ld::syntax::ContextEntry = { let context_str = ssi_contexts::TZJCSVM_V1; serde_json::from_str(context_str).unwrap() }; @@ -50,27 +50,27 @@ lazy_static::lazy_static! { #[derive(Default)] pub struct TezosV2Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: TezosV2Context) -> Self { - json_ld::syntax::Context::One(TZ_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(TZ_CONTEXT.clone()) } } #[derive(Default)] pub struct TezosJcsVmV1Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: TezosJcsVmV1Context) -> Self { - json_ld::syntax::Context::One(TZJCSVM_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(TZJCSVM_CONTEXT.clone()) } } #[derive(Default)] pub struct TezosVmV1Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: TezosVmV1Context) -> Self { - json_ld::syntax::Context::One(TZVM_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(TZVM_CONTEXT.clone()) } } diff --git a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos/tezos_jcs_signature_2021.rs b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos/tezos_jcs_signature_2021.rs index 40e9904a3..4a4dbad1b 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos/tezos_jcs_signature_2021.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos/tezos_jcs_signature_2021.rs @@ -26,7 +26,7 @@ pub use super::{Signature, TZJCSVM_CONTEXT}; pub const TZ_JCS_PROOF_CONTEXT_STR: &str = include_str!("tzjcsvm-2021-v1.jsonld"); lazy_static! { - pub static ref TZ_JCS_PROOF_CONTEXT: json_ld::syntax::Context = + pub static ref TZ_JCS_PROOF_CONTEXT: ssi_json_ld::syntax::Context = serde_json::from_str(TZ_JCS_PROOF_CONTEXT_STR).unwrap(); } @@ -150,7 +150,7 @@ where async fn sign( verification_method: &::VerificationMethod, signer: T, - prepared_claims: &Vec, + prepared_claims: Vec, proof_configuration: ProofConfigurationRef<'_, TezosJcsSignature2021>, ) -> Result { let public_key_jwk = proof_configuration @@ -164,7 +164,7 @@ where Ok(key) => { Signature::sign( verification_method.public_key.as_jwk().or(key.as_ref()), - prepared_claims, + &prepared_claims, signer, ) .await @@ -177,7 +177,7 @@ where impl VerificationAlgorithm for TezosJcsSignatureAlgorithm { fn verify( method: &TezosMethod2021, - prepared_claims: &Vec, + prepared_claims: Vec, proof: ProofRef, ) -> Result { let public_key_jwk = proof @@ -191,7 +191,7 @@ impl VerificationAlgorithm for TezosJcsSignatureAlgorithm method .verify_bytes( public_key_jwk.as_ref(), - prepared_claims, + &prepared_claims, algorithm, &signature_bytes, ) diff --git a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos/tezos_signature_2021.rs b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos/tezos_signature_2021.rs index be72db6ff..49f2c9fc3 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos/tezos_signature_2021.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/unspecified/tezos/tezos_signature_2021.rs @@ -109,7 +109,7 @@ where async fn sign( verification_method: &::VerificationMethod, signer: T, - prepared_claims: &Vec, + prepared_claims: Vec, proof_configuration: ProofConfigurationRef<'_, TezosSignature2021>, ) -> Result { // AnyBlake2b @@ -118,7 +118,7 @@ where .public_key .as_jwk() .or(proof_configuration.options.public_key_jwk.as_deref()), - prepared_claims, + &prepared_claims, signer, ) .await @@ -128,7 +128,7 @@ where impl VerificationAlgorithm for TezosSignatureAlgorithm { fn verify( method: &TezosMethod2021, - prepared_claims: &Vec, + prepared_claims: Vec, proof: ProofRef, ) -> Result { // AnyBlake2b @@ -136,7 +136,7 @@ impl VerificationAlgorithm for TezosSignatureAlgorithm { method .verify_bytes( proof.options.public_key_jwk.as_deref(), - prepared_claims, + &prepared_claims, algorithm, &signature_bytes, ) diff --git a/crates/claims/crates/data-integrity/suites/src/suites/w3c/ethereum_eip712_signature_2021.rs b/crates/claims/crates/data-integrity/suites/src/suites/w3c/ethereum_eip712_signature_2021.rs index cbf9b8ccf..bcd0896f9 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/w3c/ethereum_eip712_signature_2021.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/w3c/ethereum_eip712_signature_2021.rs @@ -15,7 +15,7 @@ use ssi_data_integrity_core::{ CryptographicSuite, ProofConfigurationRef, ProofRef, SerializeCryptographicSuite, StandardCryptographicSuite, TypeRef, }; -use ssi_eip712::Value; +use ssi_eip712::{Eip712TypesEnvironment, TypesProvider, Value}; use ssi_jwk::algorithm::{AlgorithmError, AnyESKeccakK}; use ssi_verification_methods::{ ecdsa_secp_256k1_recovery_method_2020, ecdsa_secp_256k1_verification_key_2019, @@ -28,11 +28,11 @@ use static_iref::{iri, iri_ref}; pub mod v0_1; pub use v0_1::EthereumEip712Signature2021v0_1; -use crate::eip712::{Eip712Hashing, Eip712Signature, Input, TypesOrURI, TypesProvider}; +use crate::eip712::{Eip712Hashing, Eip712Signature, Input, TypesOrURI}; lazy_static! { - static ref PROOF_CONTEXT: json_ld::syntax::ContextEntry = { - json_ld::syntax::ContextEntry::IriRef( + static ref PROOF_CONTEXT: ssi_json_ld::syntax::ContextEntry = { + ssi_json_ld::syntax::ContextEntry::IriRef( iri_ref!("https://w3id.org/security/suites/eip712sig-2021/v1").to_owned(), ) }; @@ -41,9 +41,9 @@ lazy_static! { #[derive(Default)] pub struct Eip712Sig2021v1Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: Eip712Sig2021v1Context) -> Self { - json_ld::syntax::Context::One(PROOF_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(PROOF_CONTEXT.clone()) } } @@ -269,10 +269,10 @@ where S: SerializeCryptographicSuite, S::ProofOptions: AnyEip712Options, T: Serialize, - C: TypesProvider, + C: Eip712TypesEnvironment, { async fn transform( - context: &mut C, + context: &C, data: &T, proof_configuration: ProofConfigurationRef<'_, S>, ) -> Result { @@ -280,6 +280,7 @@ where Some(TypesOrURI::Object(types)) => Some(types.clone()), Some(TypesOrURI::URI(uri)) => Some( context + .eip712_types() .fetch_types(uri) .await .map_err(TransformationError::internal)?, @@ -323,7 +324,7 @@ where async fn sign( verification_method: &S::VerificationMethod, signer: T, - prepared_claims: &S::PreparedClaims, + prepared_claims: S::PreparedClaims, _proof_configuration: ProofConfigurationRef<'_, S>, ) -> Result { // ssi_jwk::algorithm::AnyESKeccakK @@ -343,7 +344,7 @@ where { fn verify( method: &::VerificationMethod, - prepared_claims: &::PreparedClaims, + prepared_claims: ::PreparedClaims, proof: ProofRef, ) -> Result { let signature_bytes = proof.signature.decode()?; diff --git a/crates/claims/crates/data-integrity/suites/src/suites/w3c/ethereum_eip712_signature_2021/v0_1.rs b/crates/claims/crates/data-integrity/suites/src/suites/w3c/ethereum_eip712_signature_2021/v0_1.rs index 13f54edfc..80198247a 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/w3c/ethereum_eip712_signature_2021/v0_1.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/w3c/ethereum_eip712_signature_2021/v0_1.rs @@ -11,8 +11,8 @@ use super::{ }; lazy_static! { - static ref PROOF_CONTEXT: json_ld::syntax::ContextEntry = { - json_ld::syntax::ContextEntry::IriRef( + static ref PROOF_CONTEXT: ssi_json_ld::syntax::ContextEntry = { + ssi_json_ld::syntax::ContextEntry::IriRef( iri_ref!("https://demo.spruceid.com/ld/eip712sig-2021/v0.1.jsonld").to_owned(), ) }; @@ -21,9 +21,9 @@ lazy_static! { #[derive(Default)] pub struct Eip712Sig2021v0_1Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: Eip712Sig2021v0_1Context) -> Self { - json_ld::syntax::Context::One(PROOF_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(PROOF_CONTEXT.clone()) } } diff --git a/crates/claims/crates/data-integrity/suites/src/suites/w3c/json_web_signature_2020.rs b/crates/claims/crates/data-integrity/suites/src/suites/w3c/json_web_signature_2020.rs index be6ec9981..b815f0448 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/w3c/json_web_signature_2020.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/w3c/json_web_signature_2020.rs @@ -10,8 +10,8 @@ use ssi_verification_methods::JsonWebKey2020; use static_iref::{iri, iri_ref}; lazy_static! { - static ref W3ID_JWS2020_V1_CONTEXT: json_ld::syntax::ContextEntry = { - json_ld::syntax::ContextEntry::IriRef( + static ref W3ID_JWS2020_V1_CONTEXT: ssi_json_ld::syntax::ContextEntry = { + ssi_json_ld::syntax::ContextEntry::IriRef( iri_ref!("https://w3id.org/security/suites/jws-2020/v1").to_owned(), ) }; @@ -20,9 +20,9 @@ lazy_static! { #[derive(Default)] pub struct Jws2020v1Context; -impl From for json_ld::syntax::Context { +impl From for ssi_json_ld::syntax::Context { fn from(_: Jws2020v1Context) -> Self { - json_ld::syntax::Context::One(W3ID_JWS2020_V1_CONTEXT.clone()) + ssi_json_ld::syntax::Context::One(W3ID_JWS2020_V1_CONTEXT.clone()) } } diff --git a/crates/claims/crates/data-integrity/suites/src/suites/w3c/rsa_signature_2018.rs b/crates/claims/crates/data-integrity/suites/src/suites/w3c/rsa_signature_2018.rs index a64e1661a..931d11a20 100644 --- a/crates/claims/crates/data-integrity/suites/src/suites/w3c/rsa_signature_2018.rs +++ b/crates/claims/crates/data-integrity/suites/src/suites/w3c/rsa_signature_2018.rs @@ -75,11 +75,11 @@ where async fn sign( _verification_method: &RsaVerificationKey2018, signer: T, - prepared_claims: &[u8; 64], + prepared_claims: [u8; 64], _proof_configuration: ProofConfigurationRef<'_, RsaSignature2018>, ) -> Result { let signature = signer - .sign(ssi_jwk::algorithm::RS256, prepared_claims) + .sign(ssi_jwk::algorithm::RS256, &prepared_claims) .await?; Ok(Signature { @@ -91,13 +91,13 @@ where impl VerificationAlgorithm for RsaSignatureAlgorithm { fn verify( method: &RsaVerificationKey2018, - prepared_claims: &[u8; 64], + prepared_claims: [u8; 64], proof: ProofRef, ) -> Result { let signature = base64::decode(&proof.signature.signature_value) .map_err(|_| ProofValidationError::InvalidSignature)?; method - .verify_bytes(prepared_claims, &signature) + .verify_bytes(&prepared_claims, &signature) .map(Into::into) } } diff --git a/crates/claims/crates/jws/src/compact/bytes.rs b/crates/claims/crates/jws/src/compact/bytes.rs index 679b9d5c1..d87e77680 100644 --- a/crates/claims/crates/jws/src/compact/bytes.rs +++ b/crates/claims/crates/jws/src/compact/bytes.rs @@ -1,6 +1,8 @@ -use crate::{DecodeError, DecodedJWS, Header, InvalidHeader, JWSVerifier, JWS}; +use crate::{ + DecodeError, DecodedJWS, DecodedSigningBytes, Header, InvalidHeader, JWSVerifier, JWS, +}; pub use base64::DecodeError as Base64DecodeError; -use ssi_claims_core::{ProofValidationError, Verification}; +use ssi_claims_core::{ProofValidationError, VerifiableClaims, Verification}; use std::{borrow::Cow, ops::Deref}; /// JWS in compact serialized form. @@ -123,15 +125,22 @@ impl CompactJWS { let header = self.decode_header().map_err(DecodeError::Header)?; let payload = self.decode_payload(&header).map_err(DecodeError::Payload)?; let signature = self.decode_signature().map_err(DecodeError::Signature)?; - Ok(JWS::new(header, payload, signature)) + Ok(JWS::new(header, payload, signature.into())) } /// Decodes the entire JWS while preserving the signing bytes so they can /// be verified. pub fn to_decoded(&self) -> Result>, DecodeError> { + let signing_bytes = self.signing_bytes().to_owned(); + let jws = self.decode()?; + Ok(DecodedJWS::new( - self.signing_bytes().to_owned(), - self.decode()?, + DecodedSigningBytes { + bytes: signing_bytes, + header: jws.header, + payload: jws.payload, + }, + jws.signature, )) } @@ -160,10 +169,8 @@ impl CompactJWS { &self, verifier: &impl JWSVerifier, ) -> Result { - use ssi_claims_core::Verifiable; let jws = self.to_decoded().unwrap(); - let verifiable = Verifiable::new(jws).await.unwrap(); - verifiable.verify(verifier).await + jws.verify(verifier).await } } @@ -233,7 +240,11 @@ impl CompactJWSBuf { /// be verified. pub fn into_decoded(self) -> Result>, DecodeError> { let decoded = self.decode()?.into_owned(); - Ok(DecodedJWS::new(self.into_signing_bytes(), decoded)) + let signing_bytes = self.into_signing_bytes(); + Ok(DecodedJWS::new( + DecodedSigningBytes::new(signing_bytes, decoded.header, decoded.payload), + decoded.signature, + )) } } diff --git a/crates/claims/crates/jws/src/compact/str.rs b/crates/claims/crates/jws/src/compact/str.rs index 8c9a8c739..a2b7de4d9 100644 --- a/crates/claims/crates/jws/src/compact/str.rs +++ b/crates/claims/crates/jws/src/compact/str.rs @@ -1,7 +1,7 @@ use core::fmt; use std::{ops::Deref, str::FromStr}; -use crate::{CompactJWS, DecodeError, DecodedJWS, Header, InvalidCompactJWS}; +use crate::{CompactJWS, DecodeError, DecodedJWS, DecodedSigningBytes, Header, InvalidCompactJWS}; /// JWS in UTF-8 compact serialized form. /// @@ -221,9 +221,10 @@ impl CompactJWSString { /// be verified. pub fn into_decoded(self) -> Result>, DecodeError> { let decoded = self.decode()?.into_owned(); + let signing_bytes = self.into_signing_bytes().into_bytes(); Ok(DecodedJWS::new( - self.into_signing_bytes().into_bytes(), - decoded, + DecodedSigningBytes::new(signing_bytes, decoded.header, decoded.payload), + decoded.signature, )) } } diff --git a/crates/claims/crates/jws/src/lib.rs b/crates/claims/crates/jws/src/lib.rs index 83f31de6d..0d248266f 100644 --- a/crates/claims/crates/jws/src/lib.rs +++ b/crates/claims/crates/jws/src/lib.rs @@ -106,11 +106,11 @@ pub struct JWS> { pub payload: T, /// Signature. - pub signature: Vec, + pub signature: JWSSignature, } impl JWS { - pub fn new(header: Header, payload: T, signature: Vec) -> Self { + pub fn new(header: Header, payload: T, signature: JWSSignature) -> Self { Self { header, payload, @@ -146,37 +146,57 @@ impl<'a, T: ?Sized + ToOwned> JWS> { /// JWS with its signing bytes. #[derive(Clone, PartialEq, Eq)] pub struct DecodedJWS> { - pub signing_bytes: Vec, - pub decoded: JWS, + pub signing_bytes: DecodedSigningBytes, + pub signature: JWSSignature, } impl DecodedJWS { - pub fn new(signing_bytes: Vec, decoded: JWS) -> Self { + pub fn new(signing_bytes: DecodedSigningBytes, signature: JWSSignature) -> Self { Self { signing_bytes, - decoded, + signature, } } pub fn map(self, f: impl FnOnce(T) -> U) -> DecodedJWS { - DecodedJWS::new(self.signing_bytes, self.decoded.map(f)) + DecodedJWS::new(self.signing_bytes.map(f), self.signature) } pub fn try_map(self, f: impl FnOnce(T) -> Result) -> Result, E> { Ok(DecodedJWS::new( - self.signing_bytes, - self.decoded.try_map(f)?, + self.signing_bytes.try_map(f)?, + self.signature, )) } + + pub fn into_jws(self) -> JWS { + JWS::new( + self.signing_bytes.header, + self.signing_bytes.payload, + self.signature, + ) + } + + pub fn into_jws_and_signing_bytes(self) -> (JWS, Vec) { + ( + JWS::new( + self.signing_bytes.header, + self.signing_bytes.payload, + self.signature, + ), + self.signing_bytes.bytes, + ) + } } impl<'a, T: ?Sized + ToOwned> DecodedJWS> { pub fn into_owned(self) -> DecodedJWS { - DecodedJWS::new(self.signing_bytes, self.decoded.into_owned()) + DecodedJWS::new(self.signing_bytes.into_owned(), self.signature) } } /// JWS decoded signing bytes. +#[derive(Clone, PartialEq, Eq)] pub struct DecodedSigningBytes> { /// Encoded bytes. pub bytes: Vec, @@ -188,6 +208,41 @@ pub struct DecodedSigningBytes> { pub payload: T, } +impl DecodedSigningBytes { + pub fn new(bytes: Vec, header: Header, payload: T) -> Self { + Self { + bytes, + header, + payload, + } + } + + pub fn map(self, f: impl FnOnce(T) -> U) -> DecodedSigningBytes { + DecodedSigningBytes { + bytes: self.bytes, + header: self.header, + payload: f(self.payload), + } + } + + pub fn try_map( + self, + f: impl FnOnce(T) -> Result, + ) -> Result, E> { + Ok(DecodedSigningBytes { + bytes: self.bytes, + header: self.header, + payload: f(self.payload)?, + }) + } +} + +impl<'a, T: ?Sized + ToOwned> DecodedSigningBytes> { + pub fn into_owned(self) -> DecodedSigningBytes { + self.map(Cow::into_owned) + } +} + #[derive(Debug, thiserror::Error)] pub enum DecodeError { #[error("invalid header: {0}")] @@ -968,18 +1023,16 @@ pub fn decode_jws_parts( } let signing_input = [header_b64.as_bytes(), b".", payload_enc].concat(); Ok(DecodedJWS::new( - signing_input, - JWS::new(header, payload, signature), + DecodedSigningBytes::new(signing_input, header, payload), + signature.into(), )) } /// Verify a JWS with detached payload. Returns the JWS header on success. pub fn detached_verify(jws: &str, payload_enc: &[u8], key: &JWK) -> Result { let (header_b64, signature_b64) = split_detached_jws(jws)?; - let DecodedJWS { - signing_bytes, - decoded: jws, - } = decode_jws_parts(header_b64, payload_enc, signature_b64)?; + let (jws, signing_bytes) = + decode_jws_parts(header_b64, payload_enc, signature_b64)?.into_jws_and_signing_bytes(); verify_bytes(jws.header.algorithm, &signing_bytes, key, &jws.signature)?; Ok(jws.header) } @@ -987,10 +1040,8 @@ pub fn detached_verify(jws: &str, payload_enc: &[u8], key: &JWK) -> Result Result<(Header, JWK), Error> { let (header_b64, signature_b64) = split_detached_jws(jws)?; - let DecodedJWS { - signing_bytes, - decoded: jws, - } = decode_jws_parts(header_b64, payload_enc, signature_b64)?; + let (jws, signing_bytes) = + decode_jws_parts(header_b64, payload_enc, signature_b64)?.into_jws_and_signing_bytes(); let key = recover(jws.header.algorithm, &signing_bytes, &jws.signature)?; Ok((jws.header, key)) } @@ -1000,10 +1051,8 @@ pub fn detached_recover_legacy_keccak_es256kr( payload_enc: &[u8], ) -> Result<(Header, JWK), Error> { let (header_b64, signature_b64) = split_detached_jws(jws)?; - let DecodedJWS { - signing_bytes, - decoded: mut jws, - } = decode_jws_parts(header_b64, payload_enc, signature_b64)?; + let (mut jws, signing_bytes) = + decode_jws_parts(header_b64, payload_enc, signature_b64)?.into_jws_and_signing_bytes(); // Allow ESKeccakK-R misimplementation of ES256K-R, for legacy reasons. if jws.header.algorithm != Algorithm::ES256KR { return Err(Error::AlgorithmMismatch); @@ -1015,20 +1064,15 @@ pub fn detached_recover_legacy_keccak_es256kr( pub fn decode_verify(jws: &str, key: &JWK) -> Result<(Header, Vec), Error> { let (header_b64, payload_enc, signature_b64) = split_jws(jws)?; - let DecodedJWS { - signing_bytes, - decoded: jws, - } = decode_jws_parts(header_b64, payload_enc.as_bytes(), signature_b64)?; + let (jws, signing_bytes) = decode_jws_parts(header_b64, payload_enc.as_bytes(), signature_b64)? + .into_jws_and_signing_bytes(); verify_bytes(jws.header.algorithm, &signing_bytes, key, &jws.signature)?; Ok((jws.header, jws.payload)) } pub fn decode_unverified(jws: &str) -> Result<(Header, Vec), Error> { let (header_b64, payload_enc, signature_b64) = split_jws(jws)?; - let DecodedJWS { - signing_bytes: _, - decoded: jws, - } = decode_jws_parts(header_b64, payload_enc.as_bytes(), signature_b64)?; + let jws = decode_jws_parts(header_b64, payload_enc.as_bytes(), signature_b64)?.into_jws(); Ok((jws.header, jws.payload)) } diff --git a/crates/claims/crates/jws/src/verification.rs b/crates/claims/crates/jws/src/verification.rs index 0e5e5029a..57f31638a 100644 --- a/crates/claims/crates/jws/src/verification.rs +++ b/crates/claims/crates/jws/src/verification.rs @@ -1,10 +1,38 @@ -use crate::{verify_bytes, DecodedJWS, DecodedSigningBytes, Error}; +use crate::{verify_bytes, DecodedJWS, DecodedSigningBytes, Error, Header}; use ssi_claims_core::{ - DefaultEnvironment, ExtractProof, InvalidProof, PrepareWith, Proof, ProofPreparationError, - ProofValidationError, ProofValidity, Validate, ValidateProof, VerifiableClaims, + ClaimsValidity, DefaultVerificationEnvironment, InvalidProof, ProofValidationError, + ProofValidity, Validate, ValidateProof, VerifiableClaims, }; use ssi_jwk::{Algorithm, JWK}; -use std::borrow::Cow; +use std::{ + borrow::{Borrow, Cow}, + ops::Deref, +}; + +pub trait ValidateJWSHeader { + fn validate_jws_header(&self, env: &E, header: &Header) -> ClaimsValidity; +} + +impl ValidateJWSHeader for [u8] { + fn validate_jws_header(&self, _env: &E, _header: &Header) -> ClaimsValidity { + Ok(()) + } +} + +impl<'a, E, T: ?Sized + ToOwned + ValidateJWSHeader> ValidateJWSHeader for Cow<'a, T> { + fn validate_jws_header(&self, env: &E, header: &Header) -> ClaimsValidity { + self.as_ref().validate_jws_header(env, header) + } +} + +impl + ValidateJWSHeader> Validate + for DecodedSigningBytes +{ + fn validate(&self, env: &E, proof: &JWSSignature) -> ClaimsValidity { + self.payload.validate_jws_header(env, &self.header)?; + self.payload.validate(env, proof) + } +} /// JWS verifier. /// @@ -65,56 +93,75 @@ impl JWSVerifier for JWK { } } -/// Signing bytes are valid if the decoded payload is valid. -impl> Validate for DecodedSigningBytes { - fn validate(&self, env: &E, proof: &P::Prepared) -> ssi_claims_core::ClaimsValidity { - self.payload.validate(env, proof) - } -} +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct JWSSignature(Vec); -pub struct Signature(Vec); +impl JWSSignature { + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } -impl VerifiableClaims for DecodedJWS { - type Proof = Signature; + pub fn into_bytes(self) -> Vec { + self.0 + } } -impl DefaultEnvironment for DecodedJWS { - type Environment = (); +impl From> for JWSSignature { + fn from(value: Vec) -> Self { + Self(value) + } } -impl ExtractProof for DecodedJWS { - type Proofless = DecodedSigningBytes; +impl From for Vec { + fn from(value: JWSSignature) -> Self { + value.into_bytes() + } +} - fn extract_proof(self) -> (Self::Proofless, Self::Proof) { - let signing_bytes = DecodedSigningBytes { - bytes: self.signing_bytes, - header: self.decoded.header, - payload: self.decoded.payload, - }; +impl Deref for JWSSignature { + type Target = [u8]; - let signature = Signature(self.decoded.signature); + fn deref(&self) -> &Self::Target { + &self.0 + } +} - (signing_bytes, signature) +impl AsRef<[u8]> for JWSSignature { + fn as_ref(&self) -> &[u8] { + &self.0 } } -impl Proof for Signature { - type Prepared = Self; +impl Borrow<[u8]> for JWSSignature { + fn borrow(&self) -> &[u8] { + &self.0 + } } -impl PrepareWith> for Signature { - async fn prepare_with( - self, - _claims: &DecodedSigningBytes, - _environment: &mut (), - ) -> Result { - Ok(self) +impl VerifiableClaims for DecodedJWS { + type Claims = DecodedSigningBytes; + type Proof = JWSSignature; + + fn claims(&self) -> &Self::Claims { + &self.signing_bytes + } + + fn proof(&self) -> &Self::Proof { + &self.signature } } -impl ValidateProof, V> for Signature { +impl DefaultVerificationEnvironment for DecodedJWS { + type Environment = (); +} + +impl ValidateProof, E, V> for JWSSignature +where + V: JWSVerifier, +{ async fn validate_proof<'a>( &'a self, + _environment: &'a E, claims: &'a DecodedSigningBytes, verifier: &'a V, ) -> Result { diff --git a/crates/claims/crates/jwt/src/claims/any.rs b/crates/claims/crates/jwt/src/claims/any.rs index 8a3a1f0b7..12982c06e 100644 --- a/crates/claims/crates/jwt/src/claims/any.rs +++ b/crates/claims/crates/jwt/src/claims/any.rs @@ -1,6 +1,8 @@ use std::{borrow::Cow, collections::BTreeMap}; -use ssi_claims_core::{ClaimsValidity, DateTimeEnvironment, Proof, Validate}; +use ssi_claims_core::{ + ClaimsValidity, DateTimeEnvironment, DefaultVerificationEnvironment, Validate, +}; use crate::{Claim, ClaimSet}; @@ -75,11 +77,15 @@ impl ClaimSet for AnyClaims { } } -impl Validate for AnyClaims +impl Validate for AnyClaims where E: DateTimeEnvironment, { - fn validate(&self, env: &E, _proof: &P::Prepared) -> ClaimsValidity { + fn validate(&self, env: &E, _proof: &P) -> ClaimsValidity { ClaimSet::validate_registered_claims(self, env) } } + +impl DefaultVerificationEnvironment for AnyClaims { + type Environment = (); +} diff --git a/crates/claims/crates/jwt/src/claims/mixed/mod.rs b/crates/claims/crates/jwt/src/claims/mixed/mod.rs index 8a325ac83..881457dba 100644 --- a/crates/claims/crates/jwt/src/claims/mixed/mod.rs +++ b/crates/claims/crates/jwt/src/claims/mixed/mod.rs @@ -1,6 +1,8 @@ use serde::Serialize; -use ssi_claims_core::{ClaimsValidity, DateTimeEnvironment, Proof, Validate}; -use ssi_jws::JWSPayload; +use ssi_claims_core::{ + ClaimsValidity, DateTimeEnvironment, DefaultVerificationEnvironment, Validate, +}; +use ssi_jws::{JWSPayload, ValidateJWSHeader}; use std::borrow::Cow; use super::{Claim, InfallibleClaimSet, RegisteredClaims}; @@ -75,12 +77,25 @@ impl JWSPayload for JWTClaims { } } -impl, E, P: Proof> Validate for JWTClaims +impl ValidateJWSHeader for JWTClaims { + fn validate_jws_header(&self, _env: &E, _header: &ssi_jws::Header) -> ClaimsValidity { + Ok(()) + } +} + +impl, E, P> Validate for JWTClaims where E: DateTimeEnvironment, { - fn validate(&self, env: &E, proof: &P::Prepared) -> ClaimsValidity { + fn validate(&self, env: &E, proof: &P) -> ClaimsValidity { Validate::::validate(&self.registered, env, proof)?; self.private.validate(env, proof) } } + +impl DefaultVerificationEnvironment for JWTClaims +where + T::Environment: DateTimeEnvironment, +{ + type Environment = T::Environment; +} diff --git a/crates/claims/crates/jwt/src/claims/registered.rs b/crates/claims/crates/jwt/src/claims/registered.rs index 69f7da691..78a220eea 100644 --- a/crates/claims/crates/jwt/src/claims/registered.rs +++ b/crates/claims/crates/jwt/src/claims/registered.rs @@ -1,6 +1,6 @@ use super::{Claim, JWTClaims}; use crate::{CastClaim, ClaimSet, NumericDate, StringOrURI}; -use ssi_claims_core::{ClaimsValidity, DateTimeEnvironment, Proof, Validate}; +use ssi_claims_core::{ClaimsValidity, DateTimeEnvironment, Validate}; use ssi_core::OneOrMany; use ssi_jws::JWSPayload; use std::{borrow::Cow, collections::BTreeMap}; @@ -85,11 +85,11 @@ impl JWSPayload for RegisteredClaims { } } -impl Validate for RegisteredClaims +impl Validate for RegisteredClaims where E: DateTimeEnvironment, { - fn validate(&self, env: &E, _proof: &P::Prepared) -> ClaimsValidity { + fn validate(&self, env: &E, _proof: &P) -> ClaimsValidity { ClaimSet::validate_registered_claims(self, env) } } diff --git a/crates/claims/crates/jwt/src/decoding.rs b/crates/claims/crates/jwt/src/decoding.rs index 8fc8ec6ff..b6bdd995a 100644 --- a/crates/claims/crates/jwt/src/decoding.rs +++ b/crates/claims/crates/jwt/src/decoding.rs @@ -45,11 +45,7 @@ pub trait ToDecodedJWT { &self, verifier: &impl JWSVerifier, ) -> Result { - self.to_decoded_jwt()? - .into_verifiable() - .await? - .verify(verifier) - .await + self.to_decoded_jwt()?.verify(verifier).await } } diff --git a/crates/claims/crates/status/Cargo.toml b/crates/claims/crates/status/Cargo.toml index 1a8993cd7..3763b3171 100644 --- a/crates/claims/crates/status/Cargo.toml +++ b/crates/claims/crates/status/Cargo.toml @@ -16,14 +16,12 @@ ssi-vc.workspace = true ssi-verification-methods.workspace = true ssi-data-integrity.workspace = true ssi-json-ld.workspace = true -json-ld.workspace = true serde = { workspace = true, features = ["derive"] } thiserror.workspace = true iref.workspace = true multibase.workspace = true base64.workspace = true serde_json.workspace = true -json-syntax.workspace = true rdf-types.workspace = true xsd-types.workspace = true log.workspace = true diff --git a/crates/claims/crates/status/examples/status_list.rs b/crates/claims/crates/status/examples/status_list.rs index 4d2fca941..6b3229abe 100644 --- a/crates/claims/crates/status/examples/status_list.rs +++ b/crates/claims/crates/status/examples/status_list.rs @@ -16,7 +16,7 @@ use clap::{Parser, Subcommand}; use core::fmt; use iref::UriBuf; -use ssi_data_integrity::{AnyInputContext, AnySuite, ProofOptions}; +use ssi_data_integrity::{AnySuite, ProofOptions}; use ssi_dids::{VerificationMethodDIDResolver, DIDJWK}; use ssi_jwk::JWK; use ssi_status::{ @@ -179,13 +179,7 @@ async fn create_bitstream_status_list( let suite = AnySuite::pick(&jwk, Some(&verification_method)).unwrap(); let params = ProofOptions::from_method(verification_method); let vc = suite - .sign( - credential, - AnyInputContext::default(), - &resolver, - &signer, - params, - ) + .sign(credential, &resolver, &signer, params) .await .unwrap(); diff --git a/crates/claims/crates/status/src/impl/any.rs b/crates/claims/crates/status/src/impl/any.rs index 2f32f48ea..574e851bd 100644 --- a/crates/claims/crates/status/src/impl/any.rs +++ b/crates/claims/crates/status/src/impl/any.rs @@ -1,5 +1,5 @@ use iref::Uri; -use ssi_claims_core::{Proof, ValidateProof}; +use ssi_claims_core::{ValidateProof, VerificationEnvironment}; use ssi_data_integrity::AnyProofs; use ssi_jws::JWSVerifier; @@ -42,7 +42,7 @@ pub enum FromBytesError { impl FromBytes for AnyStatusMap where V: JWSVerifier, - ::Prepared: ValidateProof, + AnyProofs: ValidateProof, { type Error = FromBytesError; @@ -179,7 +179,7 @@ pub enum AnyEntrySet { impl FromBytes for AnyEntrySet where V: JWSVerifier, - ::Prepared: ValidateProof, + AnyProofs: ValidateProof, { type Error = EntrySetFromBytesError; diff --git a/crates/claims/crates/status/src/impl/bitstream_status_list/syntax/entry_set/credential.rs b/crates/claims/crates/status/src/impl/bitstream_status_list/syntax/entry_set/credential.rs index 4494693a9..9b4b68282 100644 --- a/crates/claims/crates/status/src/impl/bitstream_status_list/syntax/entry_set/credential.rs +++ b/crates/claims/crates/status/src/impl/bitstream_status_list/syntax/entry_set/credential.rs @@ -1,14 +1,18 @@ use std::{borrow::Cow, collections::HashMap, hash::Hash}; use iref::UriBuf; -use rdf_types::VocabularyMut; +use rdf_types::{Interpretation, VocabularyMut}; use serde::{Deserialize, Serialize}; -use ssi_claims_core::{ClaimsValidity, Proof, Validate, ValidateProof, Verifiable}; -use ssi_data_integrity::{ssi_rdf::Expandable, AnyInputContext, AnyProofs}; -use ssi_json_ld::{ - AnyJsonLdEnvironment, CompactJsonLd, JsonLdError, JsonLdNodeObject, JsonLdObject, +use ssi_claims_core::{ + ClaimsValidity, DefaultVerificationEnvironment, Validate, ValidateProof, VerifiableClaims, + VerificationEnvironment, }; -use ssi_jws::{CompactJWS, InvalidCompactJWS, JWSVerifier}; +use ssi_data_integrity::{ + ssi_rdf::{LdEnvironment, LinkedDataResource, LinkedDataSubject}, + AnyProofs, AnySuite, +}; +use ssi_json_ld::{CompactJsonLd, Expandable, JsonLdError, JsonLdNodeObject, JsonLdObject, Loader}; +use ssi_jws::{CompactJWS, InvalidCompactJWS, JWSVerifier, ValidateJWSHeader}; use ssi_vc::{json::JsonCredentialTypes, Context, V2}; use ssi_verification_methods::ssi_core::OneOrMany; @@ -50,7 +54,7 @@ impl StatusMapEntrySet for BitstringStatusListEntrySetCredential { } impl JsonLdObject for BitstringStatusListEntrySetCredential { - fn json_ld_context(&self) -> Option> { + fn json_ld_context(&self) -> Option> { Some(Cow::Borrowed(self.context.as_ref())) } } @@ -61,36 +65,53 @@ impl JsonLdNodeObject for BitstringStatusListEntrySetCredential { } } -impl Expandable for BitstringStatusListEntrySetCredential -where - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash, - V::BlankId: Clone + Eq + Hash, - L: json_ld::Loader, - L::Error: std::fmt::Display, -{ - type Error = JsonLdError; - type Expanded = json_ld::ExpandedDocument; - - async fn expand(&self, environment: &mut E) -> Result { - CompactJsonLd(json_syntax::to_value(self).unwrap()) - .expand(environment) +impl Expandable for BitstringStatusListEntrySetCredential { + type Error = JsonLdError; + type Expanded = ssi_json_ld::ExpandedDocument + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; + + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + { + CompactJsonLd(ssi_json_ld::syntax::to_value(self).unwrap()) + .expand_with(ld, loader) .await } } -impl Validate for BitstringStatusListEntrySetCredential { - fn validate(&self, _env: &E, _proof: &P::Prepared) -> ClaimsValidity { +impl Validate for BitstringStatusListEntrySetCredential { + fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity { // TODO use `ssi`'s own VC DM v2.0 validation function once it's implemented. Ok(()) } } +impl ValidateJWSHeader for BitstringStatusListEntrySetCredential { + fn validate_jws_header(&self, _env: &E, _header: &ssi_jws::Header) -> ClaimsValidity { + Ok(()) + } +} + +impl DefaultVerificationEnvironment for BitstringStatusListEntrySetCredential { + type Environment = (); +} + impl FromBytes for BitstringStatusListEntrySetCredential where V: JWSVerifier, - ::Prepared: ValidateProof, + AnyProofs: ValidateProof, { type Error = FromBytesError; @@ -102,31 +123,27 @@ where ) -> Result { match media_type { "application/vc+ld+json+jwt" => { - use ssi_claims_core::VerifiableClaims; let jws = CompactJWS::new(bytes) .map_err(InvalidCompactJWS::into_owned)? .to_decoded()? - .try_map::(|bytes| serde_json::from_slice(&bytes))? - .into_verifiable() - .await?; + .try_map::(|bytes| serde_json::from_slice(&bytes))?; jws.verify(verifier).await??; - Ok(jws.into_parts().0.payload) - } - "application/vc+ld+json+sd-jwt" => { - todo!() - } - "application/vc+ld+json+cose" => { - todo!() + Ok(jws.signing_bytes.payload) } + // "application/vc+ld+json+sd-jwt" => { + // todo!() + // } + // "application/vc+ld+json+cose" => { + // todo!() + // } "application/vc+ld+json" => { - let vc: Verifiable = - ssi_data_integrity::from_json_slice(bytes, AnyInputContext::default()).await?; + let vc = ssi_data_integrity::from_json_slice::(bytes)?; - if !options.allow_unsecured || !vc.proof.is_empty() { + if !options.allow_unsecured || !vc.proofs.is_empty() { vc.verify(verifier).await??; } - Ok(vc.into_parts().0) + Ok(vc.claims) } other => Err(FromBytesError::UnexpectedMediaType(other.to_owned())), } diff --git a/crates/claims/crates/status/src/impl/bitstream_status_list/syntax/status_list/credential.rs b/crates/claims/crates/status/src/impl/bitstream_status_list/syntax/status_list/credential.rs index 26f848fd6..6896d883e 100644 --- a/crates/claims/crates/status/src/impl/bitstream_status_list/syntax/status_list/credential.rs +++ b/crates/claims/crates/status/src/impl/bitstream_status_list/syntax/status_list/credential.rs @@ -1,16 +1,18 @@ use std::{borrow::Cow, collections::HashMap, hash::Hash, io}; use iref::UriBuf; -use rdf_types::VocabularyMut; +use rdf_types::{Interpretation, Vocabulary, VocabularyMut}; use serde::{Deserialize, Serialize}; use ssi_claims_core::{ - ClaimsValidity, DateTimeEnvironment, InvalidClaims, Proof, Validate, ValidateProof, Verifiable, + ClaimsValidity, DateTimeEnvironment, DefaultVerificationEnvironment, InvalidClaims, Validate, + ValidateProof, VerifiableClaims, VerificationEnvironment, }; -use ssi_data_integrity::{ssi_rdf::Expandable, AnyInputContext, AnyProofs}; -use ssi_json_ld::{ - AnyJsonLdEnvironment, CompactJsonLd, JsonLdError, JsonLdNodeObject, JsonLdObject, +use ssi_data_integrity::{ + ssi_rdf::{LdEnvironment, LinkedDataResource, LinkedDataSubject}, + AnyProofs, AnySuite, }; -use ssi_jws::{CompactJWS, InvalidCompactJWS, JWSVerifier}; +use ssi_json_ld::{CompactJsonLd, Expandable, JsonLdError, JsonLdNodeObject, JsonLdObject, Loader}; +use ssi_jws::{CompactJWS, InvalidCompactJWS, JWSVerifier, ValidateJWSHeader}; use ssi_vc::{ json::{JsonCredentialTypes, RequiredCredentialType}, Context, V2, @@ -79,7 +81,7 @@ impl BitstringStatusListCredential { } impl JsonLdObject for BitstringStatusListCredential { - fn json_ld_context(&self) -> Option> { + fn json_ld_context(&self) -> Option> { Some(Cow::Borrowed(self.context.as_ref())) } } @@ -90,30 +92,39 @@ impl JsonLdNodeObject for BitstringStatusListCredential { } } -impl Expandable for BitstringStatusListCredential -where - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash, - V::BlankId: Clone + Eq + Hash, - L: json_ld::Loader, - L::Error: std::fmt::Display, -{ - type Error = JsonLdError; - type Expanded = json_ld::ExpandedDocument; - - async fn expand(&self, environment: &mut E) -> Result { - CompactJsonLd(json_syntax::to_value(self).unwrap()) - .expand(environment) +impl Expandable for BitstringStatusListCredential { + type Error = JsonLdError; + + type Expanded = ssi_json_ld::ExpandedDocument + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; + + #[allow(async_fn_in_trait)] + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + { + CompactJsonLd(ssi_json_ld::syntax::to_value(self).unwrap()) + .expand_with(ld, loader) .await } } -impl Validate for BitstringStatusListCredential +impl Validate for BitstringStatusListCredential where E: DateTimeEnvironment, { - fn validate(&self, env: &E, _proof: &P::Prepared) -> ClaimsValidity { + fn validate(&self, env: &E, _proof: &P) -> ClaimsValidity { // TODO use `ssi`'s own VC DM v2.0 validation function once it's implemented. let now = env.date_time(); @@ -139,6 +150,16 @@ where } } +impl ValidateJWSHeader for BitstringStatusListCredential { + fn validate_jws_header(&self, _env: &E, _header: &ssi_jws::Header) -> ClaimsValidity { + Ok(()) + } +} + +impl DefaultVerificationEnvironment for BitstringStatusListCredential { + type Environment = (); +} + #[derive(Debug, thiserror::Error)] pub enum DecodeError { #[error("invalid multibase: {0}")] @@ -187,7 +208,7 @@ pub enum FromBytesError { impl FromBytes for BitstringStatusListCredential where V: JWSVerifier, - ::Prepared: ValidateProof, + AnyProofs: ValidateProof, { type Error = FromBytesError; @@ -199,31 +220,27 @@ where ) -> Result { match media_type { "application/vc+ld+json+jwt" => { - use ssi_claims_core::VerifiableClaims; let jws = CompactJWS::new(bytes) .map_err(InvalidCompactJWS::into_owned)? .to_decoded()? - .try_map::(|bytes| serde_json::from_slice(&bytes))? - .into_verifiable() - .await?; + .try_map::(|bytes| serde_json::from_slice(&bytes))?; jws.verify(verifier).await??; - Ok(jws.into_parts().0.payload) - } - "application/vc+ld+json+sd-jwt" => { - todo!() - } - "application/vc+ld+json+cose" => { - todo!() + Ok(jws.signing_bytes.payload) } + // "application/vc+ld+json+sd-jwt" => { + // todo!() + // } + // "application/vc+ld+json+cose" => { + // todo!() + // } "application/vc+ld+json" => { - let vc: Verifiable = - ssi_data_integrity::from_json_slice(bytes, AnyInputContext::default()).await?; + let vc = ssi_data_integrity::from_json_slice::(bytes)?; - if !options.allow_unsecured || !vc.proof.is_empty() { + if !options.allow_unsecured || !vc.proofs.is_empty() { vc.verify(verifier).await??; } - Ok(vc.into_parts().0) + Ok(vc.claims) } other => Err(FromBytesError::UnexpectedMediaType(other.to_owned())), } diff --git a/crates/claims/crates/status/src/impl/token_status_list/json.rs b/crates/claims/crates/status/src/impl/token_status_list/json.rs index edbc86cd6..a0aab99d0 100644 --- a/crates/claims/crates/status/src/impl/token_status_list/json.rs +++ b/crates/claims/crates/status/src/impl/token_status_list/json.rs @@ -4,7 +4,8 @@ use std::borrow::Cow; use flate2::Compression; use iref::UriBuf; use serde::{Deserialize, Serialize}; -use ssi_claims_core::{Proof, Validate}; +use ssi_claims_core::{DefaultVerificationEnvironment, Validate}; +use ssi_jws::ValidateJWSHeader; use ssi_jwt::{match_claim_type, AnyClaims, Claim, ClaimSet, IssuedAt, Issuer, JWTClaims, Subject}; use crate::{ @@ -136,12 +137,26 @@ impl ClaimSet for StatusListJwtPrivateClaims { } } -impl Validate for StatusListJwtPrivateClaims { - fn validate(&self, _env: &E, _proof: &P::Prepared) -> ssi_claims_core::ClaimsValidity { +impl Validate for StatusListJwtPrivateClaims { + fn validate(&self, _env: &E, _proof: &P) -> ssi_claims_core::ClaimsValidity { Ok(()) } } +impl ValidateJWSHeader for StatusListJwtPrivateClaims { + fn validate_jws_header( + &self, + _env: &E, + _header: &ssi_jws::Header, + ) -> ssi_claims_core::ClaimsValidity { + Ok(()) + } +} + +impl DefaultVerificationEnvironment for StatusListJwtPrivateClaims { + type Environment = (); +} + /// Time to live JWT claim. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[serde(transparent)] diff --git a/crates/claims/crates/status/src/impl/token_status_list/mod.rs b/crates/claims/crates/status/src/impl/token_status_list/mod.rs index c20f86a8c..3dcf9b9ee 100644 --- a/crates/claims/crates/status/src/impl/token_status_list/mod.rs +++ b/crates/claims/crates/status/src/impl/token_status_list/mod.rs @@ -106,14 +106,12 @@ impl FromBytes for StatusListToken { use ssi_claims_core::VerifiableClaims; let jwt = CompactJWS::new(bytes) .map_err(InvalidCompactJWS::into_owned)? - .to_decoded_custom_jwt::()? - .into_verifiable() - .await?; + .to_decoded_custom_jwt::()?; - match jwt.header.type_.as_deref() { + match jwt.signing_bytes.header.type_.as_deref() { Some("statuslist+jwt") => { jwt.verify(verifier).await??; - Ok(Self::Jwt(jwt.into_parts().0.payload)) + Ok(Self::Jwt(jwt.signing_bytes.payload)) } Some(other) => Err(FromBytesError::UnexpectedJWSType(other.to_owned())), None => Err(FromBytesError::MissingJWSType), @@ -512,13 +510,12 @@ impl FromBytes for AnyStatusListEntrySet { use ssi_claims_core::VerifiableClaims; let jwt = CompactJWS::new(bytes) .map_err(InvalidCompactJWS::into_owned)? - .to_decoded_jwt()? - .into_verifiable() - .await?; + .to_decoded_jwt()?; jwt.verify(verifier).await??; Ok(Self::Json( - jwt.payload + jwt.signing_bytes + .payload .try_get::()? .ok_or(EntrySetFromBytesError::MissingStatus)? .into_owned(), diff --git a/crates/claims/crates/vc/Cargo.toml b/crates/claims/crates/vc/Cargo.toml index 988429c53..53d819cda 100644 --- a/crates/claims/crates/vc/Cargo.toml +++ b/crates/claims/crates/vc/Cargo.toml @@ -21,7 +21,6 @@ serde = { workspace = true, features = ["derive"] } linked-data.workspace = true serde_json.workspace = true json-syntax.workspace = true -json-ld.workspace = true ssi-core.workspace = true ssi-jwt.workspace = true ssi-claims-core.workspace = true diff --git a/crates/claims/crates/vc/examples/sign.rs b/crates/claims/crates/vc/examples/sign.rs index d4773bf7b..9f6627c58 100644 --- a/crates/claims/crates/vc/examples/sign.rs +++ b/crates/claims/crates/vc/examples/sign.rs @@ -1,10 +1,12 @@ //! This example shows how to sign and verify a custom credential type crafted //! with TreeLDR, using the `Ed25519Signature2020` cryptographic suite. use iref::{Iri, IriBuf, Uri, UriBuf}; +use linked_data::{LinkedDataResource, LinkedDataSubject}; use rand_chacha::rand_core::SeedableRng; -use ssi_claims_core::Proof; +use ssi_claims_core::VerifiableClaims; use ssi_data_integrity::{suites::Ed25519Signature2020, CryptographicSuite, ProofOptions}; -use ssi_rdf::Expandable; +use ssi_json_ld::{Expandable, Loader}; +use ssi_rdf::{Interpretation, LdEnvironment, VocabularyMut}; use ssi_verification_methods::{ Controller, ControllerError, ControllerProvider, Ed25519VerificationKey2020, MethodWithSecret, ProofPurpose, ProofPurposes, ReferenceOrOwnedRef, Signer, VerificationMethod, @@ -37,7 +39,7 @@ pub struct Credential { } impl ssi_json_ld::JsonLdObject for Credential { - fn json_ld_context(&self) -> Option> { + fn json_ld_context(&self) -> Option> { Some(Cow::Borrowed(self.context.as_ref())) } } @@ -48,11 +50,11 @@ impl ssi_json_ld::JsonLdNodeObject for Credential { } } -impl ssi_claims_core::Validate for Credential +impl ssi_claims_core::Validate for Credential where E: ssi_claims_core::DateTimeEnvironment, { - fn validate(&self, env: &E, _proof: &P::Prepared) -> ssi_claims_core::ClaimsValidity { + fn validate(&self, env: &E, _proof: &P) -> ssi_claims_core::ClaimsValidity { ssi_vc::Credential::validate_credential(self, env) } } @@ -79,11 +81,26 @@ impl ssi_vc::Credential for Credential { } } -impl Expandable for Credential { +impl Expandable for Credential { type Error = std::convert::Infallible; - type Expanded = Self; - - async fn expand(&self, _environment: &mut E) -> Result { + type Expanded = Self + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; + + async fn expand_with( + &self, + _ld: &mut LdEnvironment, + _loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject, + { Ok(self.clone()) } } @@ -148,15 +165,9 @@ async fn main() { (), ); - // We use the Linked-Data-based cryptographic suite `Ed25519Signature2020`. - // Linked-Data means that our credential will be projected into an RDF - // dataset. We define here the vocabulary and interpretation for the RDF - // dataset. - let rdf = ssi_json_ld::JsonLdEnvironment::default(); - // Sign the credential. let verifiable_credential = Ed25519Signature2020 - .sign(credential, rdf, &keyring, &keyring, proof_options.clone()) + .sign(credential, &keyring, &keyring, proof_options.clone()) .await .expect("signing failed"); diff --git a/crates/claims/crates/vc/src/data_integrity.rs b/crates/claims/crates/vc/src/data_integrity.rs index a3a9e1e9e..d33802ebe 100644 --- a/crates/claims/crates/vc/src/data_integrity.rs +++ b/crates/claims/crates/vc/src/data_integrity.rs @@ -1,86 +1,18 @@ -use std::hash::Hash; - -use linked_data::{LinkedDataResource, LinkedDataSubject}; -use rdf_types::{ - interpretation::{ - ReverseBlankIdInterpretation, ReverseIriInterpretation, ReverseLiteralInterpretation, - }, - InterpretationMut, VocabularyMut, -}; -use ssi_claims_core::Verifiable; -use ssi_data_integrity::{AnyInputContext, AnySuite, DecodeError, Proofs}; -use ssi_json_ld::AnyJsonLdEnvironment; - use crate::{JsonCredential, SpecializedJsonCredential}; +use ssi_data_integrity::{AnySuite, DataIntegrity, DecodeError}; /// Decodes a Data-Integrity credential or presentation from its JSON binary /// representation. -pub async fn any_credential_from_json_slice( - json: &[u8], -) -> Result>, DecodeError> { - any_credential_from_json_slice_with(json, AnyInputContext::default()).await -} - -/// Decodes a Data-Integrity credential or presentation from its JSON binary -/// representation. -pub async fn any_credential_from_json_slice_with< - V, - I, - L, - E, - Y: ssi_data_integrity::suites::eip712::TypesProvider, ->( +pub fn any_credential_from_json_slice( json: &[u8], - environment: AnyInputContext, -) -> Result>, DecodeError> -where - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, - V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, - I: InterpretationMut - + ReverseIriInterpretation - + ReverseBlankIdInterpretation - + ReverseLiteralInterpretation, - I::Resource: Clone, - L: json_ld::Loader, - L::Error: std::fmt::Display, -{ - ssi_data_integrity::from_json_slice(json, environment).await -} - -/// Decodes a Data-Integrity credential or presentation from its JSON textual -/// representation. -pub async fn any_credential_from_json_str( - json: &str, -) -> Result>, DecodeError> { - any_credential_from_json_str_with(json, AnyInputContext::default()).await +) -> Result, DecodeError> { + ssi_data_integrity::from_json_slice(json) } /// Decodes a Data-Integrity credential or presentation from its JSON textual /// representation. -pub async fn any_credential_from_json_str_with< - V, - I, - L, - E, - Y: ssi_data_integrity::suites::eip712::TypesProvider, ->( +pub fn any_credential_from_json_str( json: &str, - environment: AnyInputContext, -) -> Result>, DecodeError> -where - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, - V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, - I: InterpretationMut - + ReverseIriInterpretation - + ReverseBlankIdInterpretation - + ReverseLiteralInterpretation, - I::Resource: Clone, - L: json_ld::Loader, - L::Error: std::fmt::Display, -{ - ssi_data_integrity::from_json_str(json, environment).await +) -> Result, DecodeError> { + ssi_data_integrity::from_json_str(json) } diff --git a/crates/claims/crates/vc/src/data_model/credential.rs b/crates/claims/crates/vc/src/data_model/credential.rs index fbd88b8fa..c9c2a4c10 100644 --- a/crates/claims/crates/vc/src/data_model/credential.rs +++ b/crates/claims/crates/vc/src/data_model/credential.rs @@ -1,7 +1,6 @@ use iref::Uri; -use ssi_claims_core::{ - ClaimsValidity, DateTimeEnvironment, InvalidClaims, Proof, Verifiable, VerifiableClaims, -}; +use ssi_claims_core::{ClaimsValidity, DateTimeEnvironment, InvalidClaims, VerifiableClaims}; +use ssi_data_integrity::{CryptographicSuite, DataIntegrity}; use xsd_types::DateTime; use super::{CredentialStatus, Evidence, Issuer, RefreshService, TermsOfUse}; @@ -164,7 +163,7 @@ pub trait VerifiableCredential: Credential + VerifiableClaims {} impl VerifiableCredential for T {} -impl Credential for Verifiable { +impl Credential for DataIntegrity { type Subject = T::Subject; type Issuer = T::Issuer; type Status = T::Status; diff --git a/crates/claims/crates/vc/src/revocation/mod.rs b/crates/claims/crates/vc/src/revocation/mod.rs index b09c1f700..4fe5eba45 100644 --- a/crates/claims/crates/vc/src/revocation/mod.rs +++ b/crates/claims/crates/vc/src/revocation/mod.rs @@ -9,7 +9,6 @@ use iref::{IriBuf, UriBuf}; use serde::{Deserialize, Serialize}; use ssi_claims_core::{ProofPreparationError, ProofValidationError}; use ssi_data_integrity::AnyDataIntegrity; -use ssi_json_ld::ContextLoader; use ssi_verification_methods::{AnyMethod, VerificationMethodResolver}; use thiserror::Error; @@ -235,7 +234,6 @@ pub trait CredentialStatus { &self, credential: &AnyDataIntegrity, resolver: &impl VerificationMethodResolver, - context_loader: &mut ContextLoader, ) -> Result; } diff --git a/crates/claims/crates/vc/src/revocation/v2020.rs b/crates/claims/crates/vc/src/revocation/v2020.rs index 1078a4991..042649538 100644 --- a/crates/claims/crates/vc/src/revocation/v2020.rs +++ b/crates/claims/crates/vc/src/revocation/v2020.rs @@ -6,8 +6,8 @@ use bitvec::vec::BitVec; use iref::UriBuf; use serde::{Deserialize, Serialize}; use ssi_claims_core::VerifiableClaims; -use ssi_data_integrity::{AnyDataIntegrity, AnyInputContext}; -use ssi_json_ld::{ContextLoader, REVOCATION_LIST_2020_V1_CONTEXT}; +use ssi_data_integrity::AnyDataIntegrity; +use ssi_json_ld::REVOCATION_LIST_2020_V1_CONTEXT; use ssi_verification_methods::{AnyMethod, VerificationMethodResolver}; use static_iref::iri; use std::collections::BTreeMap; @@ -110,7 +110,6 @@ impl CredentialStatus for RevocationList2020Status { &self, credential: &AnyDataIntegrity, resolver: &impl VerificationMethodResolver, - context_loader: &mut ContextLoader, ) -> Result { use bitvec::prelude::*; @@ -143,9 +142,7 @@ impl CredentialStatus for RevocationList2020Status { let credential_data = load_resource(&self.revocation_list_credential).await?; let revocation_list_credential = serde_json::from_slice::< AnyDataIntegrity, - >(&credential_data)? - .into_verifiable_with(AnyInputContext::from_ld_context_loader(context_loader)) - .await?; + >(&credential_data)?; if credential.issuer.id() != revocation_list_credential.issuer.id() { return Ok(StatusCheck::Invalid(Reason::IssuerMismatch( diff --git a/crates/claims/crates/vc/src/revocation/v2021.rs b/crates/claims/crates/vc/src/revocation/v2021.rs index 57a8d4409..baf93ec9e 100644 --- a/crates/claims/crates/vc/src/revocation/v2021.rs +++ b/crates/claims/crates/vc/src/revocation/v2021.rs @@ -6,8 +6,8 @@ use bitvec::vec::BitVec; use iref::UriBuf; use serde::{Deserialize, Serialize}; use ssi_claims_core::VerifiableClaims; -use ssi_data_integrity::{AnyDataIntegrity, AnyInputContext}; -use ssi_json_ld::{ContextLoader, STATUS_LIST_2021_V1_CONTEXT}; +use ssi_data_integrity::AnyDataIntegrity; +use ssi_json_ld::STATUS_LIST_2021_V1_CONTEXT; use ssi_verification_methods::{AnyMethod, VerificationMethodResolver}; use static_iref::iri; use std::collections::BTreeMap; @@ -139,7 +139,6 @@ impl CredentialStatus for StatusList2021Entry { &self, credential: &AnyDataIntegrity, resolver: &impl VerificationMethodResolver, - context_loader: &mut ContextLoader, ) -> Result { use bitvec::prelude::*; @@ -168,9 +167,7 @@ impl CredentialStatus for StatusList2021Entry { let credential_data = load_resource(&self.status_list_credential).await?; let status_list_credential = - serde_json::from_slice::>(&credential_data)? - .into_verifiable_with(AnyInputContext::from_ld_context_loader(context_loader)) - .await?; + serde_json::from_slice::>(&credential_data)?; if credential.issuer.id() != status_list_credential.issuer.id() { return Ok(StatusCheck::Invalid(Reason::IssuerMismatch( diff --git a/crates/claims/crates/vc/src/syntax/context.rs b/crates/claims/crates/vc/src/syntax/context.rs index dbe543579..3e1f8682b 100644 --- a/crates/claims/crates/vc/src/syntax/context.rs +++ b/crates/claims/crates/vc/src/syntax/context.rs @@ -2,8 +2,8 @@ use std::{borrow::Borrow, marker::PhantomData}; use educe::Educe; use iref::{Iri, IriRef, IriRefBuf}; -use json_ld::syntax::ContextEntry; use serde::{Deserialize, Serialize}; +use ssi_json_ld::syntax::ContextEntry; use crate::V1; @@ -16,15 +16,15 @@ use crate::V1; #[derive(Educe, Serialize)] // FIXME serializing a single entry as a string breaks Tezos JCS cryptosuite. #[educe(Debug, Clone)] #[serde(transparent, bound = "")] -pub struct Context(json_ld::syntax::Context, PhantomData); +pub struct Context(ssi_json_ld::syntax::Context, PhantomData); impl Default for Context { fn default() -> Self { Self( - json_ld::syntax::Context::Many( + ssi_json_ld::syntax::Context::Many( V::CONTEXT_IRIS .iter() - .map(|&i| json_ld::syntax::ContextEntry::IriRef(i.as_iri_ref().to_owned())) + .map(|&i| ssi_json_ld::syntax::ContextEntry::IriRef(i.as_iri_ref().to_owned())) .collect(), ), PhantomData, @@ -39,23 +39,23 @@ impl Context { pub fn contains_iri_ref(&self, iri_ref: &IriRef) -> bool { match &self.0 { - json_ld::syntax::Context::One(ContextEntry::IriRef(i)) => i == iri_ref, - json_ld::syntax::Context::One(_) => false, - json_ld::syntax::Context::Many(entries) => entries + ssi_json_ld::syntax::Context::One(ContextEntry::IriRef(i)) => i == iri_ref, + ssi_json_ld::syntax::Context::One(_) => false, + ssi_json_ld::syntax::Context::Many(entries) => entries .iter() .any(|e| matches!(e, ContextEntry::IriRef(i) if i == iri_ref)), } } } -impl AsRef for Context { - fn as_ref(&self) -> &json_ld::syntax::Context { +impl AsRef for Context { + fn as_ref(&self) -> &ssi_json_ld::syntax::Context { &self.0 } } -impl Borrow for Context { - fn borrow(&self) -> &json_ld::syntax::Context { +impl Borrow for Context { + fn borrow(&self) -> &ssi_json_ld::syntax::Context { &self.0 } } @@ -89,7 +89,7 @@ impl<'de, V: RequiredContextSet> Deserialize<'de> for Context { ))) } else { Ok(Context( - json_ld::syntax::Context::Many(contexts), + ssi_json_ld::syntax::Context::Many(contexts), PhantomData, )) } @@ -130,7 +130,7 @@ impl<'de, V: RequiredContextSet> Deserialize<'de> for Context { ))) } else { Ok(Context( - json_ld::syntax::Context::Many(contexts), + ssi_json_ld::syntax::Context::Many(contexts), PhantomData, )) } diff --git a/crates/claims/crates/vc/src/syntax/json/credential/mod.rs b/crates/claims/crates/vc/src/syntax/json/credential/mod.rs index 68a368b2c..62a717443 100644 --- a/crates/claims/crates/vc/src/syntax/json/credential/mod.rs +++ b/crates/claims/crates/vc/src/syntax/json/credential/mod.rs @@ -1,8 +1,10 @@ use iref::{Uri, UriBuf}; +use linked_data::{LinkedDataResource, LinkedDataSubject}; use rdf_types::VocabularyMut; use serde::{Deserialize, Serialize}; -use ssi_claims_core::{ClaimsValidity, DateTimeEnvironment, Proof, Validate}; -use ssi_json_ld::{AnyJsonLdEnvironment, JsonLdError, JsonLdNodeObject, JsonLdObject, JsonLdTypes}; +use ssi_claims_core::{ClaimsValidity, DateTimeEnvironment, Validate}; +use ssi_json_ld::{JsonLdError, JsonLdNodeObject, JsonLdObject, JsonLdTypes, Loader}; +use ssi_rdf::{Interpretation, LdEnvironment}; use std::{borrow::Cow, collections::BTreeMap, hash::Hash}; use xsd_types::DateTime; @@ -143,7 +145,7 @@ impl SpecializedJsonCred } impl JsonLdObject for SpecializedJsonCredential { - fn json_ld_context(&self) -> Option> { + fn json_ld_context(&self) -> Option> { Some(Cow::Borrowed(self.context.as_ref())) } } @@ -154,11 +156,11 @@ impl JsonLdNodeObject for SpecializedJsonCredential { } } -impl Validate for SpecializedJsonCredential +impl Validate for SpecializedJsonCredential where E: DateTimeEnvironment, { - fn validate(&self, env: &E, _proof: &P::Prepared) -> ClaimsValidity { + fn validate(&self, env: &E, _proof: &P) -> ClaimsValidity { crate::Credential::validate_credential(self, env) } } @@ -217,23 +219,32 @@ impl crate::Credential for SpecializedJsonCredential { } } -impl ssi_rdf::Expandable for SpecializedJsonCredential +impl ssi_json_ld::Expandable for SpecializedJsonCredential where S: Serialize, - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash, - V::BlankId: Clone + Eq + Hash, - L: json_ld::Loader, - L::Error: std::fmt::Display, { - type Error = JsonLdError; - - type Expanded = json_ld::ExpandedDocument; - - async fn expand(&self, environment: &mut E) -> Result { + type Error = JsonLdError; + + type Expanded = ssi_json_ld::ExpandedDocument + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; + + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + { let json = ssi_json_ld::CompactJsonLd(json_syntax::to_value(self).unwrap()); - json.expand(environment).await + json.expand_with(ld, loader).await } } diff --git a/crates/claims/crates/vc/src/syntax/json/presentation/mod.rs b/crates/claims/crates/vc/src/syntax/json/presentation/mod.rs index 64f14229f..a24a1f391 100644 --- a/crates/claims/crates/vc/src/syntax/json/presentation/mod.rs +++ b/crates/claims/crates/vc/src/syntax/json/presentation/mod.rs @@ -2,10 +2,12 @@ use std::{borrow::Cow, collections::BTreeMap, hash::Hash}; use crate::{Context, Credential}; use iref::{Uri, UriBuf}; +use linked_data::{LinkedDataResource, LinkedDataSubject}; use rdf_types::VocabularyMut; use serde::{Deserialize, Serialize}; -use ssi_claims_core::{ClaimsValidity, Proof, Validate}; -use ssi_json_ld::{AnyJsonLdEnvironment, JsonLdError, JsonLdNodeObject, JsonLdObject, JsonLdTypes}; +use ssi_claims_core::{ClaimsValidity, Validate}; +use ssi_json_ld::{JsonLdError, JsonLdNodeObject, JsonLdObject, JsonLdTypes, Loader}; +use ssi_rdf::{Interpretation, LdEnvironment}; use super::{super::value_or_array, SpecializedJsonCredential}; @@ -76,7 +78,7 @@ impl JsonPresentation { } impl JsonLdObject for JsonPresentation { - fn json_ld_context(&self) -> Option> { + fn json_ld_context(&self) -> Option> { Some(Cow::Borrowed(self.context.as_ref())) } } @@ -87,8 +89,8 @@ impl JsonLdNodeObject for JsonPresentation { } } -impl Validate for JsonPresentation { - fn validate(&self, _: &E, _: &P::Prepared) -> ClaimsValidity { +impl Validate for JsonPresentation { + fn validate(&self, _: &E, _: &P) -> ClaimsValidity { Ok(()) } } @@ -116,22 +118,31 @@ impl crate::Presentation for JsonPresentation { } } -impl ssi_rdf::Expandable for JsonPresentation +impl ssi_json_ld::Expandable for JsonPresentation where - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash, - V::BlankId: Clone + Eq + Hash, - L: json_ld::Loader, C: Serialize, - L::Error: std::fmt::Display, { - type Error = JsonLdError; - - type Expanded = json_ld::ExpandedDocument; - - async fn expand(&self, environment: &mut E) -> Result { + type Error = JsonLdError; + + type Expanded = ssi_json_ld::ExpandedDocument + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; + + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + { let json = ssi_json_ld::CompactJsonLd(json_syntax::to_value(self).unwrap()); - json.expand(environment).await + json.expand_with(ld, loader).await } } diff --git a/crates/dids/core/Cargo.toml b/crates/dids/core/Cargo.toml index fd89575ae..b87029258 100644 --- a/crates/dids/core/Cargo.toml +++ b/crates/dids/core/Cargo.toml @@ -18,6 +18,7 @@ ssi-crypto.workspace = true ssi-verification-methods-core.workspace = true ssi-claims-core.workspace = true ssi-jws.workspace = true +ssi-json-ld.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true serde_urlencoded = "0.7" @@ -26,7 +27,6 @@ thiserror.workspace = true iref = { workspace = true, features = ["serde"] } static-iref.workspace = true pin-project.workspace = true -json-ld = { workspace = true, features = ["serde"] } # for registration ssi-jwk.workspace = true diff --git a/crates/dids/core/src/document/representation/json_ld.rs b/crates/dids/core/src/document/representation/json_ld.rs index 98a5531d6..68a1dab3e 100644 --- a/crates/dids/core/src/document/representation/json_ld.rs +++ b/crates/dids/core/src/document/representation/json_ld.rs @@ -1,7 +1,7 @@ use serde::{ser::SerializeSeq, Deserialize, Serialize}; use std::{ops::Deref, str::FromStr}; -pub use json_ld::syntax::{context, ContextEntry}; +pub use ssi_json_ld::syntax::{context, ContextEntry}; use crate::Document; diff --git a/crates/dids/core/src/lib.rs b/crates/dids/core/src/lib.rs index 6c1cfe032..4a5b97930 100644 --- a/crates/dids/core/src/lib.rs +++ b/crates/dids/core/src/lib.rs @@ -22,7 +22,7 @@ pub use document::Document; pub use method_resolver::VerificationMethodDIDResolver; pub use resolution::{DIDMethodResolver, DIDResolver, StaticDIDResolver}; -pub use json_ld; +pub use ssi_json_ld; /// URI [required](https://www.w3.org/TR/did-core/#production-0) as the first value of the `@context` property for a DID Document in JSON-LD representation. pub const JSON_LD_CONTEXT_IRI: &Iri = iri!("https://www.w3.org/ns/did/v1"); diff --git a/crates/dids/methods/ethr/src/json_ld_context.rs b/crates/dids/methods/ethr/src/json_ld_context.rs index d32424885..be536de29 100644 --- a/crates/dids/methods/ethr/src/json_ld_context.rs +++ b/crates/dids/methods/ethr/src/json_ld_context.rs @@ -1,6 +1,6 @@ use ssi_dids_core::{ document::representation, - json_ld::{ + ssi_json_ld::{ syntax::context::{ term_definition::{Expanded, Id, Type, TypeKeyword}, Definition, TermDefinition, diff --git a/crates/dids/methods/ethr/src/lib.rs b/crates/dids/methods/ethr/src/lib.rs index e31432f96..b06af66d1 100644 --- a/crates/dids/methods/ethr/src/lib.rs +++ b/crates/dids/methods/ethr/src/lib.rs @@ -377,11 +377,11 @@ mod tests { use serde_json::json; use ssi_claims::{ data_integrity::{ - signing::AlterSignature, AnyInputContext, AnyInputSuiteOptions, AnySuite, - CryptographicSuite, ProofOptions, + signing::AlterSignature, AnyInputSuiteOptions, AnySuite, CryptographicSuite, + ProofOptions, }, vc::{JsonCredential, JsonPresentation}, - Verifiable, + VerifiableClaims, }; use ssi_dids_core::{did, DIDResolver}; use ssi_jwk::JWK; @@ -513,34 +513,24 @@ mod tests { eprintln!("vm {:?}", issue_options.verification_method); let signer = SingleSecretSigner::new(key).into_local(); let vc = suite - .sign( - cred.clone(), - AnyInputContext::default(), - &didethr, - &signer, - issue_options.clone(), - ) + .sign(cred.clone(), &didethr, &signer, issue_options.clone()) .await .unwrap(); println!( "proof: {}", - serde_json::to_string_pretty(&vc.proof).unwrap() + serde_json::to_string_pretty(&vc.proofs).unwrap() ); if eip712 { - assert_eq!(vc.proof.first().unwrap().signature.as_ref(), "0xd3f4a049551fd25c7fb0789c7303be63265e8ade2630747de3807710382bbb7a25b0407e9f858a771782c35b4f487f4337341e9a4375a073730bda643895964e1b") + assert_eq!(vc.proofs.first().unwrap().signature.as_ref(), "0xd3f4a049551fd25c7fb0789c7303be63265e8ade2630747de3807710382bbb7a25b0407e9f858a771782c35b4f487f4337341e9a4375a073730bda643895964e1b") } else { - assert_eq!(vc.proof.first().unwrap().signature.as_ref(), "eyJhbGciOiJFUzI1NkstUiIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..nwNfIHhCQlI-j58zgqwJgX2irGJNP8hqLis-xS16hMwzs3OuvjqzZIHlwvdzDMPopUA_Oq7M7Iql2LNe0B22oQE"); + assert_eq!(vc.proofs.first().unwrap().signature.as_ref(), "eyJhbGciOiJFUzI1NkstUiIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..nwNfIHhCQlI-j58zgqwJgX2irGJNP8hqLis-xS16hMwzs3OuvjqzZIHlwvdzDMPopUA_Oq7M7Iql2LNe0B22oQE"); } assert!(vc.verify(&didethr).await.unwrap().is_ok()); // test that issuer property is used for verification - let vc_bad_issuer = - Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:pkh:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into(); + // It should fail. assert!(vc_bad_issuer.verify(&didethr).await.unwrap().is_err()); @@ -550,7 +540,6 @@ mod tests { let vc_wrong_key = suite .sign( cred, - AnyInputContext::default(), &didethr, &wrong_signer, ProofOptions { @@ -579,13 +568,7 @@ mod tests { ); let vp = suite - .sign( - presentation, - AnyInputContext::default(), - &didethr, - &signer, - vp_issue_options, - ) + .sign(presentation, &didethr, &signer, vp_issue_options) .await .unwrap(); @@ -594,17 +577,14 @@ mod tests { // Mess with proof signature to make verify fail. let mut vp_fuzzed = vp.clone(); - vp_fuzzed.proof.first_mut().unwrap().signature.alter(); + vp_fuzzed.proofs.first_mut().unwrap().signature.alter(); let vp_fuzzed_result = vp_fuzzed.verify(&didethr).await; assert!(vp_fuzzed_result.is_err() || vp_fuzzed_result.is_ok_and(|v| v.is_err())); // test that holder is verified - let vp_bad_holder = Verifiable::tamper(vp, AnyInputContext::default(), |mut pres| { - pres.holder = Some(uri!("did:pkh:example:bad").to_owned().into()); - pres - }) - .await - .unwrap(); + let mut vp_bad_holder = vp; + vp_bad_holder.holder = Some(uri!("did:pkh:example:bad").to_owned().into()); + // It should fail. assert!(vp_bad_holder.verify(&didethr).await.unwrap().is_err()); } @@ -613,7 +593,6 @@ mod tests { async fn credential_verify_eip712vm() { let didethr = DIDEthr.with_default_options(); let vc = ssi_claims::vc::any_credential_from_json_str(include_str!("../tests/vc.jsonld")) - .await .unwrap(); // eprintln!("vc {:?}", vc); assert!(vc.verify(&didethr).await.unwrap().is_ok()) diff --git a/crates/dids/methods/ion/src/sidetree/operation/mod.rs b/crates/dids/methods/ion/src/sidetree/operation/mod.rs index c5a5a08fc..1a25f0d2f 100644 --- a/crates/dids/methods/ion/src/sidetree/operation/mod.rs +++ b/crates/dids/methods/ion/src/sidetree/operation/mod.rs @@ -8,7 +8,7 @@ pub use deactivate::*; pub use recover::*; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use ssi_jwk::JWK; -use ssi_jws::JWS; +use ssi_jws::DecodedSigningBytes; pub use update::*; use super::{ @@ -301,12 +301,13 @@ pub fn jws_decode_verify_inner( let (header_b64, payload_enc, signature_b64) = split_jws(jwt).map_err(JWSDecodeVerifyError::SplitJWS)?; let DecodedJWS { - signing_bytes, - decoded: JWS { - header, - payload, - signature, - }, + signing_bytes: + DecodedSigningBytes { + bytes: signing_bytes, + header, + payload, + }, + signature, } = decode_jws_parts(header_b64, payload_enc.as_bytes(), signature_b64) .map_err(JWSDecodeVerifyError::DecodeJWSParts)?; let claims: Claims = diff --git a/crates/dids/methods/jwk/src/lib.rs b/crates/dids/methods/jwk/src/lib.rs index 33948282e..e7d4142ee 100644 --- a/crates/dids/methods/jwk/src/lib.rs +++ b/crates/dids/methods/jwk/src/lib.rs @@ -7,8 +7,8 @@ use ssi_dids_core::{ verification_method::DIDVerificationMethod, VerificationRelationships, }, - json_ld::syntax::ContextEntry, resolution::{DIDMethodResolver, Error, Metadata, Options, Output}, + ssi_json_ld::syntax::ContextEntry, DIDBuf, DIDMethod, DIDURLBuf, Document, RelativeDIDURLBuf, DID, DIDURL, }; use ssi_jwk::JWK; diff --git a/crates/dids/methods/key/src/lib.rs b/crates/dids/methods/key/src/lib.rs index 4daa7c867..0fe6cb077 100644 --- a/crates/dids/methods/key/src/lib.rs +++ b/crates/dids/methods/key/src/lib.rs @@ -447,10 +447,10 @@ mod tests { use rand_chacha::rand_core::SeedableRng; use resolution::Parameters; use ssi_claims::{ - data_integrity::{AnyInputContext, AnyInputSuiteOptions, AnySuite}, + data_integrity::{AnyInputSuiteOptions, AnySuite}, jws::JWSVerifier, vc::JsonCredential, - Verifiable, + VerifiableClaims, }; use ssi_data_integrity::{CryptographicSuite, ProofOptions as SuiteOptions}; use ssi_dids_core::{ @@ -681,30 +681,20 @@ mod tests { ); let signer = SingleSecretSigner::new(key).into_local(); let vc = suite - .sign( - cred, - AnyInputContext::default(), - &didkey, - &signer, - issue_options, - ) + .sign(cred, &didkey, &signer, issue_options) .await .unwrap(); println!( "proof: {}", - serde_json::to_string_pretty(&vc.proof).unwrap() + serde_json::to_string_pretty(&vc.proofs).unwrap() ); - assert_eq!(vc.proof.first().unwrap().signature.as_ref(), "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..o4SzDo1RBQqdK49OPdmfVRVh68xCTNEmb7hq39IVqISkelld6t6Aatg4PCXKpopIXmX8RCCF4BwrO8ERg1YFBg"); + assert_eq!(vc.proofs.first().unwrap().signature.as_ref(), "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..o4SzDo1RBQqdK49OPdmfVRVh68xCTNEmb7hq39IVqISkelld6t6Aatg4PCXKpopIXmX8RCCF4BwrO8ERg1YFBg"); assert!(vc.verify(&didkey).await.unwrap().is_ok()); // test that issuer is verified - let vc_bad_issuer = - Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:pkh:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into(); + // It should fail. assert!(vc_bad_issuer.verify(&didkey).await.unwrap().is_err()); } @@ -744,30 +734,20 @@ mod tests { ); let signer = SingleSecretSigner::new(key).into_local(); let vc = suite - .sign( - cred, - AnyInputContext::default(), - &didkey, - &signer, - issue_options, - ) + .sign(cred, &didkey, &signer, issue_options) .await .unwrap(); println!( "proof: {}", - serde_json::to_string_pretty(&vc.proof).unwrap() + serde_json::to_string_pretty(&vc.proofs).unwrap() ); - assert_eq!(vc.proof.first().unwrap().signature.as_ref(), "eyJhbGciOiJFUzI1NksiLCJjcml0IjpbImI2NCJdLCJiNjQiOmZhbHNlfQ..jTUkFd_eYI72Y8j2OS5LRLhlc3gZn-gVsb76soi3FuJ5gWrbOb0W2CW6D-sjEsCuLkvSOfYd8Y8hB9pyeeZ2TQ"); + assert_eq!(vc.proofs.first().unwrap().signature.as_ref(), "eyJhbGciOiJFUzI1NksiLCJjcml0IjpbImI2NCJdLCJiNjQiOmZhbHNlfQ..jTUkFd_eYI72Y8j2OS5LRLhlc3gZn-gVsb76soi3FuJ5gWrbOb0W2CW6D-sjEsCuLkvSOfYd8Y8hB9pyeeZ2TQ"); assert!(vc.verify(&didkey).await.unwrap().is_ok()); // test that issuer is verified - let vc_bad_issuer = - Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:pkh:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into(); + // It should fail. assert!(vc_bad_issuer.verify(&didkey).await.unwrap().is_err()); } @@ -807,29 +787,19 @@ mod tests { ); let signer = SingleSecretSigner::new(key).into_local(); let vc = suite - .sign( - cred, - AnyInputContext::default(), - &didkey, - &signer, - issue_options, - ) + .sign(cred, &didkey, &signer, issue_options) .await .unwrap(); println!( "proof: {}", - serde_json::to_string_pretty(&vc.proof).unwrap() + serde_json::to_string_pretty(&vc.proofs).unwrap() ); assert!(vc.verify(&didkey).await.unwrap().is_ok()); // test that issuer is verified - let vc_bad_issuer = - Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:pkh:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into(); + // It should fail. assert!(vc_bad_issuer.verify(&didkey).await.unwrap().is_err()); } diff --git a/crates/dids/methods/pkh/Cargo.toml b/crates/dids/methods/pkh/Cargo.toml index b28ab32a9..80661d368 100644 --- a/crates/dids/methods/pkh/Cargo.toml +++ b/crates/dids/methods/pkh/Cargo.toml @@ -49,7 +49,6 @@ ssi-jws.workspace = true rdf-types.workspace = true xsd-types.workspace = true linked-data.workspace = true -json-ld.workspace = true json-syntax.workspace = true locspan.workspace = true tokio = { version = "1.0", features = ["macros", "rt"] } diff --git a/crates/dids/methods/pkh/src/json_ld_context.rs b/crates/dids/methods/pkh/src/json_ld_context.rs index a1fc142ee..cceccda02 100644 --- a/crates/dids/methods/pkh/src/json_ld_context.rs +++ b/crates/dids/methods/pkh/src/json_ld_context.rs @@ -1,7 +1,7 @@ use iref::Iri; use ssi_dids_core::{ document::representation, - json_ld::{ + ssi_json_ld::{ syntax::context::{ term_definition::{Expanded, Id, Type, TypeKeyword}, TermDefinition, diff --git a/crates/dids/methods/pkh/src/lib.rs b/crates/dids/methods/pkh/src/lib.rs index 2c59d2644..ab4dc2594 100644 --- a/crates/dids/methods/pkh/src/lib.rs +++ b/crates/dids/methods/pkh/src/lib.rs @@ -747,7 +747,7 @@ impl DIDPKH { #[cfg(test)] mod tests { use super::*; - use ssi_claims::{data_integrity::AnyInputContext, Verifiable}; + use ssi_claims::VerifiableClaims; use ssi_dids_core::{did, resolution::ErrorKind, DIDResolver, VerificationMethodDIDResolver}; #[cfg(all(feature = "eip", feature = "tezos"))] @@ -999,46 +999,30 @@ mod tests { eprintln!("key: {key}"); eprintln!("suite: {proof_suite:?}"); let vc = proof_suite - .sign( - cred.clone(), - AnyInputContext::default(), - &didpkh, - &signer, - issue_options.clone(), - ) + .sign(cred.clone(), &didpkh, &signer, issue_options.clone()) .await .unwrap(); println!("VC: {}", serde_json::to_string_pretty(&vc).unwrap()); assert!(vc.verify(&didpkh).await.unwrap().is_ok()); // Test that issuer property is used for verification. - let vc_bad_issuer = - Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:pkh:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into(); + // It should fail. assert!(vc_bad_issuer.verify(&didpkh).await.unwrap().is_err()); // Check that proof JWK must match proof verificationMethod let wrong_signer = SingleSecretSigner::new(wrong_key.clone()).into_local(); let vc_wrong_key = proof_suite - .sign( - cred, - AnyInputContext::default(), - &didpkh, - &wrong_signer, - issue_options, - ) + .sign(cred, &didpkh, &wrong_signer, issue_options) .await .unwrap(); assert!(vc_wrong_key.verify(&didpkh).await.unwrap().is_err()); // Mess with proof signature to make verify fail. let mut vc_fuzzed = vc.clone(); - vc_fuzzed.proof.first_mut().unwrap().signature.alter(); + vc_fuzzed.proofs.first_mut().unwrap().signature.alter(); let vc_fuzzed_result = vc_fuzzed.verify(&didpkh).await; assert!(vc_fuzzed_result.is_err() || vc_fuzzed_result.is_ok_and(|v| v.is_err())); @@ -1064,13 +1048,7 @@ mod tests { serde_json::to_string_pretty(&presentation).unwrap() ); let vp = proof_suite - .sign( - presentation, - AnyInputContext::default(), - &didpkh, - &signer, - vp_issue_options, - ) + .sign(presentation, &didpkh, &signer, vp_issue_options) .await .unwrap(); @@ -1079,18 +1057,14 @@ mod tests { // Mess with proof signature to make verify fail. let mut vp_fuzzed = vp.clone(); - vp_fuzzed.proof.first_mut().unwrap().signature.alter(); + vp_fuzzed.proofs.first_mut().unwrap().signature.alter(); let vp_fuzzed_result = vp_fuzzed.verify(&didpkh).await; assert!(vp_fuzzed_result.is_err() || vp_fuzzed_result.is_ok_and(|v| v.is_err())); // Test that holder is verified. - let vp_bad_holder = - Verifiable::tamper(vp.clone(), AnyInputContext::default(), |mut pres| { - pres.holder = Some(uri!("did:pkh:example:bad").to_owned().into()); - pres - }) - .await - .unwrap(); + let mut vp_bad_holder = vp.clone(); + vp_bad_holder.holder = Some(uri!("did:pkh:example:bad").to_owned().into()); + // It should fail. assert!(vp_bad_holder.verify(&didpkh).await.unwrap().is_err()); } @@ -1109,6 +1083,7 @@ mod tests { signing::AlterSignature, AnyInputSuiteOptions, CryptographicSuite, ProofOptions, }, vc::{JsonCredential, JsonPresentation}, + VerifiableClaims, }; use ssi_verification_methods_core::{ProofPurpose, SingleSecretSigner}; use static_iref::uri; @@ -1140,45 +1115,28 @@ mod tests { eprintln!("key: {key}"); eprintln!("suite: {proof_suite:?}"); let vc = proof_suite - .sign( - cred.clone(), - AnyInputContext::default(), - &didpkh, - &signer, - issue_options.clone(), - ) + .sign(cred.clone(), &didpkh, &signer, issue_options.clone()) .await .unwrap(); println!("VC: {}", serde_json::to_string_pretty(&vc).unwrap()); assert!(vc.verify(&didpkh).await.unwrap().is_ok()); // test that issuer property is used for verification - let vc_bad_issuer = - Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:pkh:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into(); assert!(!vc_bad_issuer.verify(&didpkh).await.unwrap().is_ok()); // Check that proof JWK must match proof verificationMethod. let wrong_signer = SingleSecretSigner::new(wrong_key.clone()).into_local(); let vc_wrong_key = proof_suite - .sign( - cred, - AnyInputContext::default(), - &didpkh, - &wrong_signer, - issue_options, - ) + .sign(cred, &didpkh, &wrong_signer, issue_options) .await .unwrap(); assert!(vc_wrong_key.verify(&didpkh).await.unwrap().is_err()); // Mess with proof signature to make verify fail let mut vc_fuzzed = vc.clone(); - vc_fuzzed.proof.first_mut().unwrap().signature.alter(); + vc_fuzzed.proofs.first_mut().unwrap().signature.alter(); let vc_fuzzed_result = vc_fuzzed.verify(&didpkh).await; assert!(vc_fuzzed_result.is_err() || vc_fuzzed_result.is_ok_and(|v| v.is_err())); @@ -1197,13 +1155,7 @@ mod tests { ); let vp = proof_suite - .sign( - presentation, - AnyInputContext::default(), - &didpkh, - &signer, - vp_issue_options, - ) + .sign(presentation, &didpkh, &signer, vp_issue_options) .await .unwrap(); @@ -1212,18 +1164,13 @@ mod tests { // Mess with proof signature to make verify fail. let mut vp_fuzzed = vp.clone(); - vp_fuzzed.proof.first_mut().unwrap().signature.alter(); + vp_fuzzed.proofs.first_mut().unwrap().signature.alter(); let vp_fuzzed_result = vp_fuzzed.verify(&didpkh).await; assert!(vp_fuzzed_result.is_err() || vp_fuzzed_result.is_ok_and(|v| v.is_err())); // Test that holder is verified. - let vp_bad_holder = - Verifiable::tamper(vp.clone(), AnyInputContext::default(), |mut pres| { - pres.holder = Some(uri!("did:pkh:example:bad").to_owned().into()); - pres - }) - .await - .unwrap(); + let mut vp_bad_holder = vp.clone(); + vp_bad_holder.holder = Some(uri!("did:pkh:example:bad").to_owned().into()); // It should fail. assert!(vp_bad_holder.verify(&didpkh).await.unwrap().is_err()); } @@ -1556,9 +1503,7 @@ mod tests { eprintln!("test verify vc `{name}`"); eprintln!("input: {vc_str}"); - let vc = ssi_claims::vc::any_credential_from_json_str(vc_str) - .await - .unwrap(); + let vc = ssi_claims::vc::any_credential_from_json_str(vc_str).unwrap(); let didpkh = VerificationMethodDIDResolver::new(DIDPKH); let verification_result = vc.verify(&didpkh).await.unwrap(); @@ -1567,51 +1512,38 @@ mod tests { // // assert_eq!(verification_result.warnings.len(), num_warnings); // TODO warnings // Negative test: tamper with the VC and watch verification fail. - let bad_vc = Verifiable::tamper_with_proofs( - vc.clone(), - AnyInputContext::default(), - |mut cred| { - cred.additional_properties - .insert("http://example.org/foo".into(), "bar".into()); - cred - }, - |mut proofs| { - for proof in &mut proofs { - // Add the `foo` field to the EIP712 VC schema if necessary. - // This is required so hashing can succeed. - if let Some(eip712) = proof.options.eip712_mut() { - if let Some( - ssi_claims::data_integrity::suites::eip712::TypesOrURI::Object(types), - ) = &mut eip712.types - { - let vc_schema = types.types.get_mut("VerifiableCredential").unwrap(); - vc_schema.push(ssi_eip712::MemberVariable::new( - "http://example.org/foo".to_owned(), - ssi_eip712::TypeRef::String, - )); - } - } - - // Same as above but for the legacy EIP712 cryptosuite (v0.1). - if let Some(eip712) = proof.options.eip712_v0_1_mut() { - if let Some( - ssi_claims::data_integrity::suites::eip712::TypesOrURI::Object(types), - ) = &mut eip712.message_schema - { - let vc_schema = types.types.get_mut("VerifiableCredential").unwrap(); - vc_schema.push(ssi_eip712::MemberVariable::new( - "http://example.org/foo".to_owned(), - ssi_eip712::TypeRef::String, - )); - } - } + let mut bad_vc = vc.clone(); + bad_vc + .additional_properties + .insert("http://example.org/foo".into(), "bar".into()); + for proof in &mut bad_vc.proofs { + // Add the `foo` field to the EIP712 VC schema if necessary. + // This is required so hashing can succeed. + if let Some(eip712) = proof.options.eip712_mut() { + if let Some(ssi_claims::data_integrity::suites::eip712::TypesOrURI::Object(types)) = + &mut eip712.types + { + let vc_schema = types.types.get_mut("VerifiableCredential").unwrap(); + vc_schema.push(ssi_eip712::MemberVariable::new( + "http://example.org/foo".to_owned(), + ssi_eip712::TypeRef::String, + )); } + } - proofs - }, - ) - .await - .unwrap(); + // Same as above but for the legacy EIP712 cryptosuite (v0.1). + if let Some(eip712) = proof.options.eip712_v0_1_mut() { + if let Some(ssi_claims::data_integrity::suites::eip712::TypesOrURI::Object(types)) = + &mut eip712.message_schema + { + let vc_schema = types.types.get_mut("VerifiableCredential").unwrap(); + vc_schema.push(ssi_eip712::MemberVariable::new( + "http://example.org/foo".to_owned(), + ssi_eip712::TypeRef::String, + )); + } + } + } let verification_result = bad_vc.verify(&didpkh).await.unwrap(); assert!(verification_result.is_err()); diff --git a/crates/dids/methods/tz/tests/did.rs b/crates/dids/methods/tz/tests/did.rs index 8b43cb6dc..9baa24753 100644 --- a/crates/dids/methods/tz/tests/did.rs +++ b/crates/dids/methods/tz/tests/did.rs @@ -4,14 +4,13 @@ use rand_chacha::rand_core::SeedableRng; use serde_json::json; use ssi_claims::{ data_integrity::{ - signing::AlterSignature, AnyInputContext, AnyInputSuiteOptions, AnySuite, - CryptographicSuite, DataIntegrity, ProofOptions as SuiteOptions, + signing::AlterSignature, AnyInputSuiteOptions, AnySuite, CryptographicSuite, DataIntegrity, + ProofOptions as SuiteOptions, }, vc::{JsonCredential, JsonPresentation}, - Verifiable, + VerifiableClaims, }; use ssi_dids_core::{did, resolution::Options, DIDResolver, VerificationMethodDIDResolver}; -use ssi_json_ld::JsonLdEnvironment; use ssi_jwk::JWK; use ssi_jws::CompactJWSString; use ssi_verification_methods_core::{ProofPurpose, SingleSecretSigner}; @@ -218,7 +217,7 @@ async fn credential_prove_verify_did_tz1() { ))); let did = did!("did:tz:delphinet:tz1WvvbEGpBXGeTVbLiR6DYBe1izmgiYuZbq").to_owned(); - let cred = DataIntegrity::new( + let vc = DataIntegrity::new( JsonCredential::new( None, did.clone().into_uri().into(), @@ -243,23 +242,14 @@ async fn credential_prove_verify_did_tz1() { ).with_context(ssi_claims::data_integrity::suites::tezos::TZ_CONTEXT.clone().into())].into() ); - let vc = Verifiable::new_with(cred, JsonLdEnvironment::default()) - .await - .unwrap(); - // FIXME: this cannot work because the VC is wrong! // `Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021` expects an // EdBlake2b signature, but the provided signature is EdDsa. // assert_eq!(vc.verify(&didtz).await.unwrap(), Ok(())); // test that issuer property is used for verification - let _vc_bad_issuer = - Verifiable::tamper(vc.clone(), JsonLdEnvironment::default(), |mut cred| { - cred.issuer = uri!("did:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut _vc_bad_issuer = vc.clone(); + _vc_bad_issuer.issuer = uri!("did:example:bad").to_owned().into(); // FIXME: this cannot work because the VC is wrong! See above. // assert!(vc_bad_issuer.verify(&didtz).await.unwrap().is_err()); @@ -269,16 +259,15 @@ async fn credential_prove_verify_did_tz1() { let vc_wrong_key = ssi_claims::data_integrity::suites::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021.sign( vc.claims.clone(), - JsonLdEnvironment::default(), &didtz, &wrong_signer, - vc.proof.first().unwrap().configuration().to_owned().into_options() + vc.proofs.first().unwrap().configuration().to_owned().into_options() ) .await .unwrap(); assert!(vc_wrong_key.verify(&didtz).await.unwrap().is_err()); - let presentation = DataIntegrity::new( + let vp = DataIntegrity::new( JsonPresentation::new( Some(uri!("http://example.org/presentations/3731").to_owned()), Some(did.into()), @@ -300,10 +289,6 @@ async fn credential_prove_verify_did_tz1() { ).with_context(ssi_claims::data_integrity::suites::tezos::TZ_CONTEXT.clone().into())].into() ); - let vp = Verifiable::new_with(presentation, JsonLdEnvironment::default()) - .await - .unwrap(); - println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); // FIXME: this cannot work because the VP is wrong! See above. @@ -311,18 +296,16 @@ async fn credential_prove_verify_did_tz1() { // mess with the VP proof to make verify fail let mut vp1 = vp.clone(); - vp1.proof.first_mut().unwrap().signature.jws = - CompactJWSString::from_string(format!("x{}", vp1.proof.first_mut().unwrap().signature.jws)) - .unwrap(); + vp1.proofs.first_mut().unwrap().signature.jws = CompactJWSString::from_string(format!( + "x{}", + vp1.proofs.first_mut().unwrap().signature.jws + )) + .unwrap(); assert!(vp1.verify(&didtz).await.is_err()); // test that holder is verified - let _vp2 = Verifiable::tamper(vp.clone(), JsonLdEnvironment::default(), |mut pres| { - pres.holder = Some(did!("did:example:bad").to_owned().into()); - pres - }) - .await - .unwrap(); + let mut _vp2 = vp.clone(); + _vp2.holder = Some(did!("did:example:bad").to_owned().into()); // FIXME: this cannot work because the VP is wrong! See above. // assert!(vp2.verify(&didtz).await.unwrap().is_err()); @@ -361,25 +344,15 @@ async fn credential_prove_verify_did_tz2() { ); let suite = AnySuite::pick(&key, vc_issue_options.verification_method.as_ref()).unwrap(); let vc = suite - .sign( - cred, - AnyInputContext::default(), - &didtz, - &signer, - vc_issue_options, - ) + .sign(cred, &didtz, &signer, vc_issue_options) .await .unwrap(); - println!("{}", serde_json::to_string_pretty(&vc.proof).unwrap()); + println!("{}", serde_json::to_string_pretty(&vc.proofs).unwrap()); assert!(vc.verify(&didtz).await.unwrap().is_ok()); // Test that issuer property is used for verification. - let vc_bad_issuer = Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:example:bad").to_owned().into(); assert!(vc_bad_issuer.verify(&didtz).await.unwrap().is_err()); // Check that proof JWK must match proof verificationMethod @@ -388,10 +361,9 @@ async fn credential_prove_verify_did_tz2() { let vc_wrong_key = suite .sign( vc.claims.clone(), - AnyInputContext::default(), &didtz, &wrong_signer, - vc.proof + vc.proofs .first() .unwrap() .configuration() @@ -419,30 +391,20 @@ async fn credential_prove_verify_did_tz2() { ); let suite = AnySuite::pick(&key, vp_issue_options.verification_method.as_ref()).unwrap(); let vp = suite - .sign( - presentation, - AnyInputContext::default(), - &didtz, - &signer, - vp_issue_options, - ) + .sign(presentation, &didtz, &signer, vp_issue_options) .await .unwrap(); - println!("VP: {}", serde_json::to_string_pretty(&vp.proof).unwrap()); + println!("VP: {}", serde_json::to_string_pretty(&vp.proofs).unwrap()); assert!(vp.verify(&didtz).await.unwrap().is_ok()); // mess with the VP proof to make verify fail let mut vp1 = vp.clone(); - vp1.proof.first_mut().unwrap().signature.alter(); + vp1.proofs.first_mut().unwrap().signature.alter(); assert!(vp1.verify(&didtz).await.is_err()); // test that holder is verified - let vp2 = Verifiable::tamper(vp.clone(), AnyInputContext::default(), |mut pres| { - pres.holder = Some(did!("did:example:bad").to_owned().into()); - pres - }) - .await - .unwrap(); + let mut vp2 = vp.clone(); + vp2.holder = Some(did!("did:example:bad").to_owned().into()); assert!(vp2.verify(&didtz).await.unwrap().is_err()); } @@ -480,25 +442,15 @@ async fn credential_prove_verify_did_tz3() { let suite = AnySuite::pick(&key, vc_issue_options.verification_method.as_ref()).unwrap(); eprintln!("suite {suite:?}"); let vc = suite - .sign( - cred, - AnyInputContext::default(), - &didtz, - &signer, - vc_issue_options, - ) + .sign(cred, &didtz, &signer, vc_issue_options) .await .unwrap(); - println!("{}", serde_json::to_string_pretty(&vc.proof).unwrap()); + println!("{}", serde_json::to_string_pretty(&vc.proofs).unwrap()); assert!(vc.verify(&didtz).await.unwrap().is_ok()); // Test that issuer property is used for verification. - let vc_bad_issuer = Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:example:bad").to_owned().into(); assert!(vc_bad_issuer.verify(&didtz).await.unwrap().is_err()); // Check that proof JWK must match proof verificationMethod @@ -506,10 +458,9 @@ async fn credential_prove_verify_did_tz3() { let vc_wrong_key = suite .sign( vc.claims.clone(), - AnyInputContext::default(), &didtz, &wrong_signer, - vc.proof + vc.proofs .first() .unwrap() .configuration() @@ -539,29 +490,19 @@ async fn credential_prove_verify_did_tz3() { ); let suite = AnySuite::pick(&key, vp_issue_options.verification_method.as_ref()).unwrap(); let vp = suite - .sign( - presentation, - AnyInputContext::default(), - &didtz, - &signer, - vp_issue_options, - ) + .sign(presentation, &didtz, &signer, vp_issue_options) .await .unwrap(); - println!("VP: {}", serde_json::to_string_pretty(&vp.proof).unwrap()); + println!("VP: {}", serde_json::to_string_pretty(&vp.proofs).unwrap()); assert!(vp.verify(&didtz).await.unwrap().is_ok()); // mess with the VP proof to make verify fail let mut vp1 = vp.clone(); - vp1.proof.first_mut().unwrap().signature.alter(); + vp1.proofs.first_mut().unwrap().signature.alter(); assert!(vp1.verify(&didtz).await.is_err()); // test that holder is verified - let vp2 = Verifiable::tamper(vp.clone(), AnyInputContext::default(), |mut pres| { - pres.holder = Some(did!("did:example:bad").to_owned().into()); - pres - }) - .await - .unwrap(); + let mut vp2 = vp.clone(); + vp2.holder = Some(did!("did:example:bad").to_owned().into()); assert!(vp2.verify(&didtz).await.unwrap().is_err()); } diff --git a/crates/dids/methods/web/src/lib.rs b/crates/dids/methods/web/src/lib.rs index 51294dd06..8eda6220e 100644 --- a/crates/dids/methods/web/src/lib.rs +++ b/crates/dids/methods/web/src/lib.rs @@ -137,9 +137,9 @@ impl DIDMethodResolver for DIDWeb { #[cfg(test)] mod tests { use ssi_claims::{ - data_integrity::{AnyInputContext, AnySuite, CryptographicSuite, ProofOptions}, + data_integrity::{AnySuite, CryptographicSuite, ProofOptions}, vc::JsonCredential, - Verifiable, + VerifiableClaims, }; use ssi_dids_core::{did, DIDResolver, Document, VerificationMethodDIDResolver}; use ssi_jwk::JWK; @@ -271,31 +271,20 @@ mod tests { ); let signer = SingleSecretSigner::new(key).into_local(); let vc = suite - .sign( - cred, - AnyInputContext::default(), - &didweb, - &signer, - issue_options, - ) + .sign(cred, &didweb, &signer, issue_options) .await .unwrap(); println!( "proof: {}", - serde_json::to_string_pretty(&vc.proof).unwrap() + serde_json::to_string_pretty(&vc.proofs).unwrap() ); - assert_eq!(vc.proof.first().unwrap().signature.as_ref(), "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..BCvVb4jz-yVaTeoP24Wz0cOtiHKXCdPcmFQD_pxgsMU6aCAj1AIu3cqHyoViU93nPmzqMLswOAqZUlMyVnmzDw"); + assert_eq!(vc.proofs.first().unwrap().signature.as_ref(), "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..BCvVb4jz-yVaTeoP24Wz0cOtiHKXCdPcmFQD_pxgsMU6aCAj1AIu3cqHyoViU93nPmzqMLswOAqZUlMyVnmzDw"); assert!(vc.verify(&didweb).await.unwrap().is_ok()); // test that issuer property is used for verification - let vc_bad_issuer = - Verifiable::tamper(vc.clone(), AnyInputContext::default(), |mut cred| { - cred.issuer = uri!("did:pkh:example:bad").to_owned().into(); - cred - }) - .await - .unwrap(); + let mut vc_bad_issuer = vc.clone(); + vc_bad_issuer.issuer = uri!("did:pkh:example:bad").to_owned().into(); // It should fail. assert!(vc_bad_issuer.verify(&didweb).await.unwrap().is_err()); diff --git a/crates/eip712/Cargo.toml b/crates/eip712/Cargo.toml index f96cf8387..f83c903c5 100644 --- a/crates/eip712/Cargo.toml +++ b/crates/eip712/Cargo.toml @@ -19,6 +19,7 @@ rdf-types.workspace = true indexmap = { version = "2.0.0", features = ["serde"] } json-syntax = { workspace = true, features = ["serde"] } linked-data.workspace = true +iref.workspace = true [dev-dependencies] lazy_static = "1.4" \ No newline at end of file diff --git a/crates/eip712/src/lib.rs b/crates/eip712/src/lib.rs index 0564bca71..4f7665ee6 100644 --- a/crates/eip712/src/lib.rs +++ b/crates/eip712/src/lib.rs @@ -43,29 +43,6 @@ impl TypedData { } } -// #[derive(Debug, thiserror::Error)] -// pub enum ProofGenerationError { -// #[error("Unable to generate types: {0}")] -// TypesGeneration(#[from] TypesGenerationError), -// } - -// // Generate eip712Domain proof property, using [generate_types]. -// pub fn generate_proof_info(doc: &EIP712Value) -> Result { -// // Default primaryType to Document for consistency with generate_types. -// let primary_type = StructName::from("Document"); -// let types = generate_types(doc, Some(primary_type.clone()))?; -// let domain = EIP712Value::Struct(HashMap::default()); -// let eip712_domain = eip712sig_default_domain(); -// Ok(ProofInfo { -// types_or_uri: TypesOrURI::Object(Types { -// eip712_domain, -// types, -// }), -// primary_type, -// domain, -// }) -// } - pub(crate) fn bytes_from_hex(s: &str) -> Option> { s.strip_prefix("0x") .and_then(|hex_str| hex::decode(hex_str).ok()) diff --git a/crates/eip712/src/ty.rs b/crates/eip712/src/ty.rs index bb51e432e..7cf9b1750 100644 --- a/crates/eip712/src/ty.rs +++ b/crates/eip712/src/ty.rs @@ -1,11 +1,51 @@ use std::{collections::BTreeMap, fmt, num::ParseIntError, str::FromStr}; +use iref::Uri; use serde::{Deserialize, Serialize}; use crate::Value; pub type StructName = String; +/// Errors that can occur while fetching remote EIP712 type definitions. +#[derive(Debug, thiserror::Error)] +pub enum TypesFetchError { + /// Error for applications that do not support remote types. + /// + /// This is the error always returned by the `()` implementation of + /// `TypesProvider`. + #[error("remote EIP712 types are not supported")] + Unsupported, +} + +/// Type providing remote EIP712 type definitions from an URI. +/// +/// A default implementation is provided for the `()` type that always return +/// `TypesFetchError::Unsupported`. +pub trait TypesProvider { + /// Fetches the type definitions located behind the given `uri`. + /// + /// This is an asynchronous function returning a `Self::Fetch` future that + /// resolves into ether the EIP712 [`Types`] or an error + /// of type `TypesFetchError`. + #[allow(async_fn_in_trait)] + async fn fetch_types(&self, uri: &Uri) -> Result; +} + +/// Simple EIP712 loader implementation that always return +/// `TypesFetchError::Unsupported`. +impl TypesProvider for () { + async fn fetch_types(&self, _uri: &Uri) -> Result { + Err(TypesFetchError::Unsupported) + } +} + +pub trait Eip712TypesEnvironment { + type Provider: TypesProvider; + + fn eip712_types(&self) -> &Self::Provider; +} + /// EIP-712 types #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] #[serde(untagged)] diff --git a/crates/json-ld/Cargo.toml b/crates/json-ld/Cargo.toml index 23e5889b8..86c23fe27 100644 --- a/crates/json-ld/Cargo.toml +++ b/crates/json-ld/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/ssi-json-ld/" [dependencies] thiserror.workspace = true async-std = { version = "1.9", features = ["attributes"] } -json-ld.workspace = true +json-ld = { version = "0.19.1", features = ["serde"] } iref.workspace = true static-iref.workspace = true rdf-types.workspace = true @@ -31,4 +31,4 @@ serde.workspace = true difference = "2.0" nquads-syntax.workspace = true serde_json.workspace = true -tokio = { version = "1.27.0", features = ["rt", "macros"] } +tokio = { version = "1.27.0", features = ["rt", "macros"] } \ No newline at end of file diff --git a/crates/json-ld/src/context.rs b/crates/json-ld/src/context.rs index d1cd2a750..65f673ff8 100644 --- a/crates/json-ld/src/context.rs +++ b/crates/json-ld/src/context.rs @@ -1,18 +1,13 @@ -use std::collections::HashMap; -use std::sync::Arc; - -use async_std::sync::RwLock; use iref::{Iri, IriBuf}; -pub use json_ld::{syntax, Options, RemoteDocumentReference}; -use json_ld::{syntax::TryFromJson, Loader, RemoteContext, RemoteContextReference, RemoteDocument}; +use json_ld::{ + syntax::TryFromJson, LoadError, Loader, RemoteContext, RemoteContextReference, RemoteDocument, +}; +pub use json_ld::{Options, RemoteDocumentReference}; use json_syntax::Parse; -use rdf_types::vocabulary::IriVocabularyMut; use static_iref::iri; +use std::collections::HashMap; use thiserror::Error; -/// Error raised by the `json_to_dataset` function. -pub type ToRdfError = json_ld::ToRdfError; - pub const CREDENTIALS_V1_CONTEXT: &Iri = iri!("https://www.w3.org/2018/credentials/v1"); pub const CREDENTIALS_V2_CONTEXT: &Iri = iri!("https://www.w3.org/ns/credentials/v2"); pub const CREDENTIALS_EXAMPLES_V1_CONTEXT: &Iri = @@ -236,23 +231,14 @@ macro_rules! iri_match { /// Error raised when an unknown context is loaded with [`StaticLoader`] or /// [`ContextLoader`]. #[derive(thiserror::Error, Debug)] -#[error("Unknown context: {0}")] -pub struct UnknownContext(pub IriBuf); +#[error("Unknown context")] +pub struct UnknownContext; #[derive(Clone)] pub struct StaticLoader; -impl Loader for StaticLoader { - type Error = UnknownContext; - - async fn load_with( - &mut self, - _vocabulary: &mut V, - url: IriBuf, - ) -> json_ld::LoadingResult - where - V: IriVocabularyMut, - { +impl Loader for StaticLoader { + async fn load(&self, url: &Iri) -> json_ld::LoadingResult { iri_match! { match url { CREDENTIALS_V1_CONTEXT => Ok(CREDENTIALS_V1_CONTEXT_DOCUMENT.clone()), @@ -308,7 +294,7 @@ impl Loader for StaticLoader { JFF_VC_EDU_PLUGFEST_2022_2_CONTEXT => { Ok(JFF_VC_EDU_PLUGFEST_2022_2_CONTEXT_DOCUMENT.clone()) }, - _ as iri => Err(UnknownContext(iri)) + _ as iri => Err(LoadError::new(iri.to_owned(), UnknownContext)) } } } @@ -320,10 +306,11 @@ pub type ContextMap = HashMap; pub struct ContextLoader { // Specifies if StaticLoader is meant to be checked first. static_loader: Option, + // This map holds the optional, additional context objects. This is where any app-specific context // objects would go. The Arc> is necessary because json_ld::Loader trait unfortunately // has a method that uses `&mut self`. - context_map: Option>>, + context_map: Option, } impl std::fmt::Debug for ContextLoader { @@ -388,7 +375,7 @@ impl ContextLoader { }, ) .collect::, FromContextMapError>>()?; - self.context_map = Some(Arc::new(RwLock::new(context_map))); + self.context_map = Some(context_map); Ok(self) } } @@ -403,25 +390,16 @@ impl std::default::Default for ContextLoader { } } -impl Loader for ContextLoader { - type Error = UnknownContext; - - async fn load_with( - &mut self, - _vocabulary: &mut V, - url: IriBuf, - ) -> json_ld::LoadingResult - where - V: IriVocabularyMut, - { - let url = match &mut self.static_loader { +impl Loader for ContextLoader { + async fn load(&self, url: &Iri) -> json_ld::LoadingResult { + let url = match &self.static_loader { Some(static_loader) => { match static_loader.load(url).await { Ok(x) => { // The url was present in `StaticLoader`. return Ok(x); } - Err(UnknownContext(url)) => { + Err(_) => { // This is ok, the url just wasn't found in // `StaticLoader`. Fall through to // `self.context_map`. @@ -433,15 +411,13 @@ impl Loader for ContextLoader { }; // If we fell through, then try `self.context_map`. - if let Some(context_map) = &mut self.context_map { + if let Some(context_map) = &self.context_map { context_map - .read() - .await - .get(&url) + .get(url) .cloned() - .ok_or(UnknownContext(url)) + .ok_or_else(|| LoadError::new(url.to_owned(), UnknownContext)) } else { - Err(UnknownContext(url)) + Err(LoadError::new(url.to_owned(), UnknownContext)) } } } @@ -472,7 +448,7 @@ mod test { #[tokio::test] async fn context_loader() { - let mut cl = ContextLoader::default().with_context_map_from([( + let cl = ContextLoader::default().with_context_map_from([( "https://w3id.org/age/v1".to_string(), serde_json::to_string(&json!({ "@context": { diff --git a/crates/json-ld/src/lib.rs b/crates/json-ld/src/lib.rs index 78d07ba81..f3257dbed 100644 --- a/crates/json-ld/src/lib.rs +++ b/crates/json-ld/src/lib.rs @@ -4,101 +4,31 @@ mod context; use std::{borrow::Cow, hash::Hash}; pub use context::*; -use json_ld::{Expand, Loader}; -use rdf_types::{ - generator, interpretation::WithGenerator, vocabulary::IriVocabulary, Interpretation, - VocabularyMut, -}; -use ssi_rdf::{AnyLdEnvironment, Expandable, LdEnvironment}; +use json_ld::Expand; +use linked_data::{LinkedData, LinkedDataResource, LinkedDataSubject}; +use rdf_types::interpretation::WithGenerator; +use rdf_types::{Vocabulary, VocabularyMut}; -pub trait AnyJsonLdEnvironment: AnyLdEnvironment -where - Self::Vocabulary: IriVocabulary, -{ - type Loader: Loader<::Iri>; +pub use json_ld; +pub use json_ld::{syntax, ExpandedDocument, Id, LoadError, Loader, Nullable, ToRdfError}; +use ssi_rdf::{generator, Interpretation, LdEnvironment}; - fn as_json_ld_environment_mut( - &mut self, - ) -> JsonLdEnvironment<&mut Self::Vocabulary, &mut Self::Interpretation, &mut Self::Loader>; +/// Environment that provides a JSON-LD context loader. +pub trait ContextLoaderEnvironment { + type Loader: json_ld::Loader; + + fn loader(&self) -> &Self::Loader; } #[derive(Debug, thiserror::Error)] -pub enum JsonLdError { +pub enum JsonLdError { #[error("expansion error: {0}")] - Expansion(#[from] json_ld::expansion::Error), + Expansion(#[from] json_ld::expansion::Error), #[error("interpretation error: {0}")] Interpretation(#[from] linked_data::IntoQuadsError), } -pub struct JsonLdEnvironment, L = ContextLoader> { - /// Vocabulary. - pub vocabulary: V, - - /// Interpretation. - pub interpretation: I, - - /// Document loader. - pub loader: L, -} - -impl JsonLdEnvironment { - pub fn new(vocabulary: V, interpretation: I, loader: L) -> Self { - Self { - vocabulary, - interpretation, - loader, - } - } -} - -impl AnyLdEnvironment for JsonLdEnvironment { - type Vocabulary = V; - type Interpretation = I; - - fn as_ld_environment_mut( - &mut self, - ) -> LdEnvironment<&mut Self::Vocabulary, &mut Self::Interpretation> { - LdEnvironment { - vocabulary: &mut self.vocabulary, - interpretation: &mut self.interpretation, - } - } -} - -impl> AnyJsonLdEnvironment - for JsonLdEnvironment -{ - type Loader = L; - - fn as_json_ld_environment_mut( - &mut self, - ) -> JsonLdEnvironment<&mut Self::Vocabulary, &mut Self::Interpretation, &mut Self::Loader> - { - JsonLdEnvironment { - vocabulary: &mut self.vocabulary, - interpretation: &mut self.interpretation, - loader: &mut self.loader, - } - } -} - -impl JsonLdEnvironment<(), WithGenerator, L> { - pub fn from_loader(loader: L) -> Self { - Self { - vocabulary: (), - interpretation: WithGenerator::new((), generator::Blank::new()), - loader, - } - } -} - -impl Default for JsonLdEnvironment { - fn default() -> Self { - Self::from_loader(ContextLoader::default()) - } -} - #[repr(transparent)] pub struct CompactJsonLd(pub json_syntax::Value); @@ -108,30 +38,66 @@ impl CompactJsonLd { } } -impl Expandable for CompactJsonLd -where - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash, - V::BlankId: Clone + Eq + Hash, - L: json_ld::Loader, - L::Error: std::fmt::Display, -{ - type Error = JsonLdError; +/// JSON-LD-Expandable value. +pub trait Expandable: Sized { + type Error: std::fmt::Display; - // type Resource = I::Resource; - type Expanded = json_ld::ExpandedDocument; + type Expanded: LinkedData + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; + + #[allow(async_fn_in_trait)] + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject; - async fn expand(&self, environment: &mut E) -> Result { - let environment = environment.as_json_ld_environment_mut(); + #[allow(async_fn_in_trait)] + async fn expand( + &self, + loader: &impl Loader, + ) -> Result, ()>, Self::Error> { + let mut ld = LdEnvironment::default(); + self.expand_with(&mut ld, loader).await + } +} +impl Expandable for CompactJsonLd { + type Error = JsonLdError; + type Expanded = json_ld::ExpandedDocument + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; + + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + { let expanded = self .0 .expand_full( - environment.vocabulary, + &mut ld.vocabulary, Default::default(), None, - environment.loader, + loader, json_ld::expansion::Options { policy: json_ld::expansion::Policy::Strict, ..Default::default() diff --git a/crates/rdf/src/expand.rs b/crates/rdf/src/expand.rs index b606137c2..bc15d2483 100644 --- a/crates/rdf/src/expand.rs +++ b/crates/rdf/src/expand.rs @@ -1,20 +1,11 @@ use linked_data::LinkedData; use rdf_types::{ - interpretation::ReverseTermInterpretation, + generator, + interpretation::{ReverseTermInterpretation, WithGenerator}, vocabulary::{BlankIdVocabulary, IriVocabulary, LiteralVocabulary}, Interpretation, InterpretationMut, Vocabulary, }; -/// LD-Expandable value. -pub trait Expandable: Sized { - type Error: std::fmt::Display; - - type Expanded; - - #[allow(async_fn_in_trait)] - async fn expand(&self, environment: &mut E) -> Result; -} - pub trait AnyLdEnvironment { type Vocabulary; @@ -86,7 +77,7 @@ pub trait AnyLdEnvironment { } } -pub struct LdEnvironment { +pub struct LdEnvironment> { /// Vocabulary. pub vocabulary: V, @@ -103,6 +94,12 @@ impl LdEnvironment { } } +impl Default for LdEnvironment { + fn default() -> Self { + Self::new((), WithGenerator::new((), generator::Blank::new())) + } +} + impl AnyLdEnvironment for LdEnvironment { type Vocabulary = V; type Interpretation = I; @@ -116,159 +113,3 @@ impl AnyLdEnvironment for LdEnvironment { } } } - -// impl Expandable> for T -// where -// T: linked_data::LinkedDataSubject + linked_data::LinkedDataResource, -// V: VocabularyMut, -// V::Iri: Clone + LinkedDataResource + LinkedDataSubject, -// V::BlankId: Clone + LinkedDataResource + LinkedDataSubject, -// V::LanguageTag: Clone, -// V::Value: From + From + From, -// V::Type: From>, -// I: InterpretationMut -// + IriInterpretationMut -// + BlankIdInterpretationMut -// + LiteralInterpretationMut, -// I::Resource: Clone + Ord, -// { -// type Error = linked_data::IntoQuadsError; - -// type Resource = I::Resource; - -// async fn expand( -// self, -// environment: &mut LdEnvironment, -// ) -> Result, Self::Error> { -// let (subject, quads) = linked_data::to_interpreted_subject_quads( -// &mut environment.vocabulary, -// &mut environment.interpretation, -// None, -// &self, -// )?; - -// Ok(Expanded::new(self, quads.into_iter().collect(), subject)) -// } -// } - -// /// LD-Expanded value. -// pub struct Expanded { -// /// Compact value. -// compact: C, - -// /// Expanded value (the RDF dataset). -// dataset: BTreeDataset, - -// /// Resource representing the compact value in the dataset. -// subject: R, -// } - -// impl Expanded { -// pub fn new(compact: C, dataset: BTreeDataset, subject: R) -> Self { -// Self { -// compact, -// dataset, -// subject, -// } -// } - -// pub fn rdf_dataset(&self) -> &BTreeDataset { -// &self.dataset -// } - -// pub fn rdf_subject(&self) -> &R { -// &self.subject -// } - -// pub fn into_rdf_parts(self) -> (BTreeDataset, R) { -// (self.dataset, self.subject) -// } -// } - -// impl Deref for Expanded { -// type Target = C; - -// fn deref(&self) -> &Self::Target { -// &self.compact -// } -// } - -// impl serde::Serialize for Expanded { -// fn serialize(&self, serializer: S) -> Result -// where -// S: serde::Serializer { -// self.compact.serialize(serializer) -// } -// } - -// impl linked_data::LinkedDataResource for Expanded -// where -// I: Interpretation, -// V: Vocabulary, -// { -// fn interpretation( -// &self, -// _vocabulary: &mut V, -// _interpretation: &mut I, -// ) -> linked_data::ResourceInterpretation { -// linked_data::ResourceInterpretation::Interpreted(&self.subject) -// } -// } - -// impl linked_data::LinkedDataSubject for Expanded -// where -// I: Interpretation, -// I::Resource: Ord + Hash + LinkedDataResource, -// V: Vocabulary, -// { -// fn visit_subject(&self, serializer: S) -> Result -// where -// S: linked_data::SubjectVisitor, -// { -// self.dataset -// .view(None, &self.subject, grdf::IdentityAccess) -// .visit_subject(serializer) -// } -// } - -// impl linked_data::LinkedDataPredicateObjects for Expanded -// where -// I: Interpretation, -// I::Resource: Ord + Hash + LinkedDataResource, -// V: Vocabulary, -// { -// fn visit_objects(&self, mut visitor: S) -> Result -// where -// S: linked_data::PredicateObjectsVisitor { -// visitor.object(self)?; -// visitor.end() -// } -// } - -// impl linked_data::LinkedDataGraph for Expanded -// where -// I: Interpretation, -// I::Resource: Ord + Hash + LinkedDataResource, -// V: Vocabulary, -// { -// fn visit_graph(&self, mut visitor: S) -> Result -// where -// S: linked_data::GraphVisitor { -// visitor.subject(self)?; -// visitor.end() -// } -// } - -// impl linked_data::LinkedData for Expanded -// where -// I: Interpretation, -// I::Resource: Ord + Hash + LinkedDataResource, -// V: Vocabulary, -// { -// fn visit(&self, mut visitor: S) -> Result -// where -// S: linked_data::Visitor { -// visitor.default_graph(self)?; -// visitor.end() -// } -// } diff --git a/crates/rdf/src/lib.rs b/crates/rdf/src/lib.rs index 23958e957..5fc6fca59 100644 --- a/crates/rdf/src/lib.rs +++ b/crates/rdf/src/lib.rs @@ -10,9 +10,15 @@ use rdf_types::{ dataset::IndexedBTreeDataset, interpretation::ReverseTermInterpretation, vocabulary::{ByRef, ExtractFromVocabulary, Predicate}, - Interpretation, LexicalQuad, Vocabulary, }; +pub use rdf_types::{ + generator, Interpretation, InterpretationMut, LexicalQuad, LexicalQuadRef, Vocabulary, + VocabularyMut, +}; + +pub use linked_data::{LinkedData, LinkedDataResource, LinkedDataSubject}; + /// Interpreted RDF dataset with an entry point. pub struct DatasetWithEntryPoint<'a, V, I: Interpretation> { pub vocabulary: &'a V, diff --git a/crates/ucan/src/lib.rs b/crates/ucan/src/lib.rs index dbd5e7497..856389b06 100644 --- a/crates/ucan/src/lib.rs +++ b/crates/ucan/src/lib.rs @@ -21,7 +21,7 @@ use ssi_dids_core::{ DIDBuf, DIDResolver, DIDURLBuf, Document, }; use ssi_jwk::{Algorithm, JWK}; -use ssi_jws::{decode_jws_parts, sign_bytes, split_jws, verify_bytes, Header}; +use ssi_jws::{decode_jws_parts, sign_bytes, split_jws, verify_bytes, Header, JWSSignature}; use ssi_jwt::NumericDate; use ssi_verification_methods::{GenericVerificationMethod, InvalidVerificationMethod}; use std::{ @@ -35,7 +35,7 @@ use std::{ pub struct Ucan { pub header: Header, pub payload: Payload, - pub signature: Vec, + pub signature: JWSSignature, // unfortunately this matters for sig verification // we have to keep track of how this ucan was created // alternatively we could have 2 different types? @@ -120,19 +120,19 @@ impl Ucan { { let parts = split_jws(jwt).and_then(|(h, p, s)| decode_jws_parts(h, p.as_bytes(), s))?; let (payload, codec): (Payload, UcanCodec) = - match serde_json::from_slice(&parts.decoded.payload) { + match serde_json::from_slice(&parts.signing_bytes.payload) { Ok(p) => Ok((p, UcanCodec::Raw(jwt.to_string()))), - Err(e) => match DagJsonCodec.decode(&parts.decoded.payload) { + Err(e) => match DagJsonCodec.decode(&parts.signing_bytes.payload) { Ok(p) => Ok((p, UcanCodec::DagJson)), Err(_) => Err(e), }, }?; - if parts.decoded.header.type_.as_deref() != Some("JWT") { + if parts.signing_bytes.header.type_.as_deref() != Some("JWT") { return Err(Error::MissingUCANHeaderField("type: JWT")); } - match parts.decoded.header.additional_parameters.get("ucv") { + match parts.signing_bytes.header.additional_parameters.get("ucv") { Some(JsonValue::String(v)) if v == "0.9.0" => (), _ => return Err(Error::MissingUCANHeaderField("ucv: 0.9.0")), } @@ -142,9 +142,9 @@ impl Ucan { } Ok(Self { - header: parts.decoded.header, + header: parts.signing_bytes.header, payload, - signature: parts.decoded.signature, + signature: parts.signature, codec, }) } @@ -313,7 +313,8 @@ impl Payload { .join(".") .as_bytes(), key, - )?; + )? + .into(); Ok(Ucan { header, @@ -643,7 +644,7 @@ mod ipld_encoding { Self { header: u.header, payload: u.payload.into(), - signature: u.signature, + signature: u.signature.into(), codec: UcanCodec::DagJson, } } diff --git a/crates/verification-methods/Cargo.toml b/crates/verification-methods/Cargo.toml index a0d947336..25b682cd9 100644 --- a/crates/verification-methods/Cargo.toml +++ b/crates/verification-methods/Cargo.toml @@ -56,8 +56,6 @@ iref = { workspace = true, features = ["serde"] } static-iref.workspace = true rdf-types.workspace = true thiserror.workspace = true -json-ld.workspace = true -# treeldr-rust-prelude.workspace = true linked-data = { workspace = true, features = ["derive"] } ssi-multicodec.workspace = true multibase.workspace = true diff --git a/crates/verification-methods/core/Cargo.toml b/crates/verification-methods/core/Cargo.toml index e30cd0b7f..2d5c050e6 100644 --- a/crates/verification-methods/core/Cargo.toml +++ b/crates/verification-methods/core/Cargo.toml @@ -14,13 +14,13 @@ ssi-crypto.workspace = true ssi-claims-core.workspace = true ssi-jwk.workspace = true ssi-jws.workspace = true +ssi-json-ld.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true iref = { workspace = true, features = ["serde"] } static-iref.workspace = true rdf-types.workspace = true thiserror.workspace = true -json-ld.workspace = true linked-data = { workspace = true, features = ["derive"] } educe.workspace = true multibase.workspace = true diff --git a/crates/zcap-ld/Cargo.toml b/crates/zcap-ld/Cargo.toml index 77f2be0c8..3236c5543 100644 --- a/crates/zcap-ld/Cargo.toml +++ b/crates/zcap-ld/Cargo.toml @@ -20,7 +20,6 @@ rdf-types.workspace = true ssi-jwk = { workspace = true, features = ["ed25519"] } ssi-core.workspace = true ssi-dids-core.workspace = true -json-ld.workspace = true ssi-rdf.workspace = true ssi-json-ld.workspace = true ssi-claims.workspace = true diff --git a/crates/zcap-ld/src/lib.rs b/crates/zcap-ld/src/lib.rs index be128804c..8c9e48871 100644 --- a/crates/zcap-ld/src/lib.rs +++ b/crates/zcap-ld/src/lib.rs @@ -12,14 +12,16 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use ssi_claims::{ data_integrity::{ - suite::{CryptographicSuiteInstance, CryptographicSuiteSigning, InputOptions}, - AnyDataIntegrity, AnyInputContext, AnyProofs, AnySignatureAlgorithm, AnySuite, - CryptographicSuite, PreparedProof, PreparedProofs, Proofs, + suite::{CryptographicSuiteSigning, InputOptions}, + AnyDataIntegrity, AnyProofs, AnySignatureAlgorithm, AnySuite, CryptographicSuite, + DataIntegrity, Proof, Proofs, }, vc::{Context, RequiredContext}, - ClaimsValidity, InvalidClaims, SignatureError, Validate, Verifiable, + ClaimsValidity, DateTimeEnvironment, Eip712TypesEnvironment, InvalidClaims, SignatureError, + Validate, VerificationEnvironment, }; -use ssi_json_ld::{AnyJsonLdEnvironment, JsonLdError, JsonLdNodeObject, JsonLdObject}; +use ssi_json_ld::{ContextLoaderEnvironment, JsonLdError, JsonLdNodeObject, JsonLdObject, Loader}; +use ssi_rdf::{Interpretation, LdEnvironment, LinkedDataResource, LinkedDataSubject}; use ssi_verification_methods::{AnyMethod, ProofPurpose, VerificationMethodResolver}; use ssi_verification_methods::{MessageSigner, Signer}; use static_iref::iri; @@ -93,10 +95,7 @@ impl Delegation { } } - pub fn validate( - &self, - proofs: &PreparedProofs, - ) -> Result<(), DelegationValidationError> { + pub fn validate(&self, proofs: &Proofs) -> Result<(), DelegationValidationError> { for proof in proofs.iter() { if proof.configuration().proof_purpose != ProofPurpose::CapabilityDelegation { return Err(DelegationValidationError::InvalidProofPurpose); @@ -108,7 +107,7 @@ impl Delegation { pub fn validate_invocation_proof( &self, - proof: &PreparedProof, + proof: &Proof, ) -> Result<(), InvocationValidationError> { let id: &Uri = proof .extra_properties @@ -139,7 +138,7 @@ impl Delegation { signer: S, proof_configuration: InputOptions, capability_chain: &[&str], - ) -> Result, SignatureError> + ) -> Result, SignatureError> where C: Serialize, P: Serialize, @@ -148,7 +147,7 @@ impl Delegation { { self.sign_with( suite, - AnyInputContext::default(), + VerificationEnvironment::default(), resolver, signer, proof_configuration, @@ -166,9 +165,9 @@ impl Delegation { signer: S, mut proof_configuration: InputOptions, capability_chain: &[&str], - ) -> Result>, SignatureError> + ) -> Result, SignatureError> where - D: CryptographicSuiteInstance + CryptographicSuiteSigning, + D: CryptographicSuiteSigning, { proof_configuration.extra_properties.insert( "capabilityChain".into(), @@ -180,13 +179,73 @@ impl Delegation { } suite - .sign(self, environment, resolver, signer, proof_configuration) + .sign_with(environment, self, resolver, signer, proof_configuration) .await } } +pub trait TargetCapabilityEnvironment { + type Caveat; + type AdditionalProperties; + + fn target_capability(&self) -> &Delegation; +} + +pub struct EnvironmentDelegation<'a, E, C, S>(E, &'a Delegation); + +impl<'a, E, C, S> TargetCapabilityEnvironment for EnvironmentDelegation<'a, E, C, S> { + type Caveat = C; + type AdditionalProperties = S; + + fn target_capability(&self) -> &Delegation { + self.1 + } +} + +impl<'a, E: ContextLoaderEnvironment, C, S> ContextLoaderEnvironment + for EnvironmentDelegation<'a, E, C, S> +{ + type Loader = E::Loader; + + fn loader(&self) -> &Self::Loader { + self.0.loader() + } +} + +impl<'a, E: Eip712TypesEnvironment, C, S> Eip712TypesEnvironment + for EnvironmentDelegation<'a, E, C, S> +{ + type Provider = E::Provider; + + fn eip712_types(&self) -> &Self::Provider { + self.0.eip712_types() + } +} + +impl<'a, E: DateTimeEnvironment, C, S> DateTimeEnvironment for EnvironmentDelegation<'a, E, C, S> { + fn date_time(&self) -> ssi_claims::chrono::DateTime { + self.0.date_time() + } +} + +pub trait WithCapabilityChain: Sized { + fn with_target_capability( + self, + delegation: &Delegation, + ) -> EnvironmentDelegation; +} + +impl WithCapabilityChain for E { + fn with_target_capability( + self, + delegation: &Delegation, + ) -> EnvironmentDelegation { + EnvironmentDelegation(self, delegation) + } +} + impl JsonLdObject for Delegation { - fn json_ld_context(&self) -> Option> { + fn json_ld_context(&self) -> Option> { Some(Cow::Borrowed(self.context.as_ref())) } } @@ -194,30 +253,40 @@ impl JsonLdObject for Delegation { impl JsonLdNodeObject for Delegation {} impl Validate for Delegation { - fn validate(&self, _: &E, proofs: &PreparedProofs) -> ClaimsValidity { + fn validate(&self, _: &E, proofs: &Proofs) -> ClaimsValidity { self.validate(proofs).map_err(InvalidClaims::other) } } -impl ssi_rdf::Expandable for Delegation +impl ssi_json_ld::Expandable for Delegation where C: Serialize, P: Serialize, - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash, - V::BlankId: Clone + Eq + Hash, - L: json_ld::Loader, - L::Error: std::fmt::Display, { - type Error = JsonLdError; + type Error = JsonLdError; - // type Resource = I::Resource; - type Expanded = json_ld::ExpandedDocument; + type Expanded = ssi_json_ld::ExpandedDocument + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; - async fn expand(&self, environment: &mut E) -> Result { + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + { let json = json_syntax::to_value(self).unwrap(); - ssi_json_ld::CompactJsonLd(json).expand(environment).await + ssi_json_ld::CompactJsonLd(json) + .expand_with(ld, loader) + .await } } @@ -285,24 +354,16 @@ impl

Invocation

{ .extra_properties .insert("capability".into(), json_syntax::to_value(target).unwrap()); - Ok(Verifiable::unprepare( - suite - .sign( - self, - AnyInputContext::default(), - resolver, - signer, - proof_configuration, - ) - .await?, - )) + suite + .sign(self, resolver, signer, proof_configuration) + .await } pub fn validate( &self, // TODO make this a list for delegation chains target_capability: &Delegation, - proofs: &PreparedProofs, + proofs: &Proofs, ) -> Result<(), InvocationValidationError> { for proof in proofs.iter() { if proof.configuration().proof_purpose != ProofPurpose::CapabilityInvocation { @@ -317,69 +378,58 @@ impl

Invocation

{ } impl

JsonLdObject for Invocation

{ - fn json_ld_context(&self) -> Option> { + fn json_ld_context(&self) -> Option> { Some(Cow::Borrowed(self.context.as_ref())) } } impl

JsonLdNodeObject for Invocation

{} -impl ssi_rdf::Expandable for Invocation

+impl

ssi_json_ld::Expandable for Invocation

where P: Serialize, - E: AnyJsonLdEnvironment, - V: VocabularyMut, - V::Iri: Clone + Eq + Hash, - V::BlankId: Clone + Eq + Hash, - L: json_ld::Loader, - L::Error: std::fmt::Display, { - type Error = JsonLdError; + type Error = JsonLdError; - // type Resource = I::Resource; - type Expanded = json_ld::ExpandedDocument; + type Expanded = ssi_json_ld::ExpandedDocument + where + I: Interpretation, + V: VocabularyMut, + V::Iri: LinkedDataResource + LinkedDataSubject, + V::BlankId: LinkedDataResource + LinkedDataSubject; - async fn expand(&self, environment: &mut E) -> Result { + async fn expand_with( + &self, + ld: &mut LdEnvironment, + loader: &impl Loader, + ) -> Result, Self::Error> + where + I: Interpretation, + V: VocabularyMut, + V::Iri: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + V::BlankId: Clone + Eq + Hash + LinkedDataResource + LinkedDataSubject, + { let json = json_syntax::to_value(self).unwrap(); - ssi_json_ld::CompactJsonLd(json).expand(environment).await + ssi_json_ld::CompactJsonLd(json) + .expand_with(ld, loader) + .await } } -impl Validate, AnyProofs> for Invocation { - fn validate( - &self, - target_capability: &Delegation, - proofs: &PreparedProofs, - ) -> ClaimsValidity { - self.validate(target_capability, proofs) +impl Validate for Invocation +where + E: TargetCapabilityEnvironment, +{ + fn validate(&self, env: &E, proofs: &Proofs) -> ClaimsValidity { + self.validate(env.target_capability(), proofs) .map_err(InvalidClaims::other) } } -// impl

VerifiableInvocation

{ - -// #[allow(unused, unreachable_code)] -// pub async fn verify( -// &self, -// // TODO make this a list for delegation chains -// target_capability: &Delegation, -// verifier: &impl VerificationMethodResolver, -// ) -> Result -// where -// P: Clone + Serialize, -// { -// let vc = self -// .clone() -// .into_verifiable_claims(target_capability) -// .await?; -// vc.verify(verifier).await.map_err(Into::into) -// } -// } - #[cfg(test)] mod tests { use super::*; - use ssi_claims::{UnprepareProof, VerifiableClaims}; + use ssi_claims::VerifiableClaims; use ssi_data_integrity::DataIntegrity; use ssi_dids_core::{example::ExampleDIDResolver, VerificationMethodDIDResolver}; use ssi_jwk::JWK; @@ -500,16 +550,16 @@ mod tests { &signed_del.id, ) .await - .unwrap() - .into_verifiable() - .await .unwrap(); // happy path assert!(signed_del.verify(&dk).await.unwrap().is_ok()); assert!(signed_inv - .verify_with(&dk, &signed_del.claims) + .verify_with( + &dk, + VerificationEnvironment::default().with_target_capability(&signed_del.claims) + ) .await .unwrap() .is_ok()); @@ -519,24 +569,19 @@ mod tests { invoker: Some(uri!("did:someone_else").to_owned()), ..signed_del.claims.clone() }, - signed_del.proof.clone().unprepare(), - ) - .into_verifiable() - .await - .unwrap(); - let bad_sig_inv = signed_inv - .clone() - .tamper(AnyInputContext::default(), |mut inv| { - inv.id = uri!("urn:different_id").to_owned(); - inv - }) - .await - .unwrap(); + signed_del.proofs.clone(), + ); + + let mut bad_sig_inv = signed_inv.clone(); + bad_sig_inv.id = uri!("urn:different_id").to_owned(); // invalid proof for data assert!(bad_sig_del.verify(&dk).await.unwrap().is_err()); assert!(bad_sig_inv - .verify_with(&dk, &signed_del.claims) + .verify_with( + &dk, + VerificationEnvironment::default().with_target_capability(&signed_del.claims) + ) .await .unwrap() .is_err()); @@ -557,7 +602,10 @@ mod tests { .await .unwrap(); assert!(signed_inv - .verify_with(&dk, &signed_wrong_del.claims) + .verify_with( + &dk, + VerificationEnvironment::default().with_target_capability(&signed_wrong_del.claims) + ) .await .unwrap() .is_err()); diff --git a/examples/issue-revocation-list.rs b/examples/issue-revocation-list.rs index 3f2556c3c..c4c6b8ddc 100644 --- a/examples/issue-revocation-list.rs +++ b/examples/issue-revocation-list.rs @@ -2,10 +2,11 @@ // cargo run --example issue-revocation-list > tests/revocationList.json use ssi::{ claims::{ - data_integrity::{AnyInputContext, AnySuite, CryptographicSuite, ProofOptions}, + data_integrity::{AnySuite, CryptographicSuite, ProofOptions}, vc::revocation::{ RevocationList2020, RevocationList2020Credential, RevocationList2020Subject, }, + VerifiableClaims, }, jwk::JWK, verification_methods::SingleSecretSigner, @@ -36,16 +37,7 @@ async fn main() { let params = ProofOptions::from_method_and_options(verification_method, Default::default()); let suite = AnySuite::pick(&key, params.verification_method.as_ref()).unwrap(); - let vc = suite - .sign( - rl_vc, - AnyInputContext::default(), - &resolver, - &signer, - params, - ) - .await - .unwrap(); + let vc = suite.sign(rl_vc, &resolver, &signer, params).await.unwrap(); assert!(vc.verify(&resolver).await.unwrap().is_ok()); diff --git a/examples/issue-status-list.rs b/examples/issue-status-list.rs index cc2c3854e..fbb94c9a2 100644 --- a/examples/issue-status-list.rs +++ b/examples/issue-status-list.rs @@ -2,8 +2,9 @@ // cargo run --example issue-status-list > tests/statusList.json use ssi::{ claims::{ - data_integrity::{AnyInputContext, AnySuite, CryptographicSuite, ProofOptions}, + data_integrity::{AnySuite, CryptographicSuite, ProofOptions}, vc::revocation::{StatusList2021, StatusList2021Credential, StatusList2021Subject}, + VerifiableClaims, }, jwk::JWK, verification_methods::SingleSecretSigner, @@ -34,16 +35,7 @@ async fn main() { let params = ProofOptions::from_method_and_options(verification_method, Default::default()); let suite = AnySuite::pick(&key, params.verification_method.as_ref()).unwrap(); - let vc = suite - .sign( - rl_vc, - AnyInputContext::default(), - &resolver, - &signer, - params, - ) - .await - .unwrap(); + let vc = suite.sign(rl_vc, &resolver, &signer, params).await.unwrap(); assert!(vc.verify(&resolver).await.unwrap().is_ok()); diff --git a/examples/issue.rs b/examples/issue.rs index 7701e1ebb..c234aa812 100644 --- a/examples/issue.rs +++ b/examples/issue.rs @@ -4,9 +4,10 @@ use serde_json::json; use ssi_claims::{ - data_integrity::{AnyInputContext, AnySuite, CryptographicSuite, ProofOptions}, + data_integrity::{AnySuite, CryptographicSuite, ProofOptions}, jws::JWSPayload, vc::ToJwtClaims, + VerifiableClaims, }; use ssi_dids::DIDResolver; use ssi_verification_methods::SingleSecretSigner; @@ -39,10 +40,7 @@ async fn main() { ProofOptions::from_method_and_options(verification_method, Default::default()); let suite = AnySuite::pick(&key, params.verification_method.as_ref()).unwrap(); - let vc = suite - .sign(vc, AnyInputContext::default(), &resolver, &signer, params) - .await - .unwrap(); + let vc = suite.sign(vc, &resolver, &signer, params).await.unwrap(); let result = vc.verify(&resolver).await.expect("verification failed"); if !result.is_ok() { diff --git a/examples/present.rs b/examples/present.rs index 8910c16ae..7448aa22a 100644 --- a/examples/present.rs +++ b/examples/present.rs @@ -11,8 +11,9 @@ // cat examples/files/vc.jwt | cargo run --example present jwt jwt | save examples/files/vp-jwtvc.jwt use ssi::{ claims::{ - data_integrity::{AnyInputContext, AnySuite, CryptographicSuite, ProofOptions}, + data_integrity::{AnySuite, CryptographicSuite, ProofOptions}, jws::{CompactJWSString, JWSPayload}, + VerifiableClaims, }, verification_methods::{ProofPurpose, SingleSecretSigner}, }; @@ -73,10 +74,7 @@ async fn main() { params.challenge = Some("example".to_owned()); let suite = AnySuite::pick(&key, params.verification_method.as_ref()).unwrap(); - let vp = suite - .sign(vp, AnyInputContext::default(), &resolver, &signer, params) - .await - .unwrap(); + let vp = suite.sign(vp, &resolver, &signer, params).await.unwrap(); let result = vp.verify(&resolver).await.expect("verification failed"); if !result.is_ok() { diff --git a/examples/vc_parse.rs b/examples/vc_parse.rs index d0620f8f6..3d38b43b5 100644 --- a/examples/vc_parse.rs +++ b/examples/vc_parse.rs @@ -9,21 +9,12 @@ async fn main() { let credential_content = fs::read_to_string("examples/files/vc.jsonld").unwrap(); // Parse the credential into a JSON VC with any Data-Integrity proof. - let credential: AnyDataIntegrity = - serde_json::from_str(&credential_content).unwrap(); + let vc: AnyDataIntegrity = serde_json::from_str(&credential_content).unwrap(); - // Separate the claims from the proofs and turn it into actually verifiable - // claims. - let vc = ssi::claims::Verifiable::new(credential).await.unwrap(); - - // At this point the VC is ready to be verified. - // We just print it instead in this example. println!("{}", serde_json::to_string_pretty(&vc).unwrap()); - // All of the above can be done with the following helper function. - let vc = ssi::claims::vc::any_credential_from_json_str(&credential_content) - .await - .unwrap(); + // The above can also be done with the following helper function. + let vc = ssi::claims::vc::any_credential_from_json_str(&credential_content).unwrap(); // Print the same credential. println!("{}", serde_json::to_string_pretty(&vc).unwrap()); diff --git a/examples/vc_verify.rs b/examples/vc_verify.rs index 25828efd6..028db6af7 100644 --- a/examples/vc_verify.rs +++ b/examples/vc_verify.rs @@ -1,18 +1,16 @@ //! This example shows how to verify a Data-Integrity Verifiable Credential. -use std::fs; - +use ssi_claims::VerifiableClaims; use ssi_dids::{DIDResolver, StaticDIDResolver, VerificationMethodDIDResolver}; use ssi_verification_methods::AnyMethod; +use std::fs; #[async_std::main] async fn main() { // Load the credential textual representation from the file system. let credential_content = fs::read_to_string("examples/files/vc.jsonld").unwrap(); - // All of the above can be done with the following helper function. - let vc = ssi::claims::vc::any_credential_from_json_str(&credential_content) - .await - .unwrap(); + // Parse the VC. + let vc = ssi::claims::vc::any_credential_from_json_str(&credential_content).unwrap(); // Prepare our verifier. let verifier = create_verifier(); diff --git a/src/lib.rs b/src/lib.rs index 823d5b00e..a50c569bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,7 +86,7 @@ //! let vc = any_credential_from_json_str( //! &std::fs::read_to_string("examples/files/vc.jsonld") //! .expect("unable to load VC") -//! ).await.expect("invalid VC"); +//! ).expect("invalid VC"); //! //! // Setup a verification method resolver, in charge of retrieving the //! // public key used to sign the JWT. @@ -205,7 +205,6 @@ //! //! let vc = cryptosuite.sign( //! credential, -//! AnyInputContext::default(), //! &vm_resolver, //! &signer, //! ProofOptions::from_method(verification_method) diff --git a/src/prelude.rs b/src/prelude.rs index 9c686028f..4f26f05b1 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,15 +1,13 @@ pub use crate::{ claims::{ data_integrity::{ - AnyDataIntegrity, AnyInputContext, AnySuite, CryptographicSuite, DataIntegrity, - ProofConfiguration, ProofOptions, - }, - vc::{ - any_credential_from_json_slice, any_credential_from_json_slice_with, - any_credential_from_json_str, any_credential_from_json_str_with, + AnyDataIntegrity, AnySuite, CryptographicSuite, DataIntegrity, ProofConfiguration, + ProofOptions, }, + vc::{any_credential_from_json_slice, any_credential_from_json_str}, CompactJWS, CompactJWSBuf, CompactJWSStr, CompactJWSString, JWSPayload, JWTClaims, - JsonCredential, JsonPresentation, SpecializedJsonCredential, + JsonCredential, JsonPresentation, SpecializedJsonCredential, VerifiableClaims, + VerificationEnvironment, }, dids::{DIDResolver, DIDJWK}, verification_methods::{AnyJwkMethod, AnyMethod, SingleSecretSigner}, diff --git a/tests/send.rs b/tests/send.rs index 2412fda55..b029cff59 100644 --- a/tests/send.rs +++ b/tests/send.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use ssi::{ claims::{ - data_integrity::{AnyInputContext, AnySuite, CryptographicSuite, ProofOptions}, + data_integrity::{AnySuite, CryptographicSuite, ProofOptions}, vc::SpecializedJsonCredential, }, dids::{DIDResolver, DIDJWK}, @@ -41,7 +41,6 @@ fn data_integrity_sign_is_send() { assert_send(cryptosuite.sign( credential, - AnyInputContext::default(), &vm_resolver, &signer, ProofOptions::from_method(verification_method),