Skip to content

Commit

Permalink
Verifier simplification. (#559)
Browse files Browse the repository at this point in the history
* Merge `context` and `verifier`.
* Rename `with_default_options` into `into_vm_resolver`.
* Rename `Validate` into `ValidateClaims` trait.
* Rename `*Environment` traits into `*Provider` traits.
* Add `ResolverProvider` trait.
* Rename `Verifier` type into `VerificationParameters`.
* Add dedicated `verify` methods for secured claims types (`CompactJWS`, `DecodedJWS` and `DataIntegrity`).
* Optional date time parameter in `VerificationParameters`.
* Add documentation.
  • Loading branch information
timothee-haudebourg committed Jul 3, 2024
1 parent 0567fda commit 30f29a9
Show file tree
Hide file tree
Showing 71 changed files with 904 additions and 597 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ let jwt = CompactJWSString::from_string(
// public key used to sign the JWT.
// Here we use the example `ExampleDIDResolver` resolver, enabled with the
// `example` feature.
let vm_resolver = ExampleDIDResolver::default().with_default_options::<AnyJwkMethod>();
let vm_resolver = ExampleDIDResolver::default().into_vm_resolver::<AnyJwkMethod>();

// Verify the JWT.
assert!(jwt.verify(&vm_resolver).await.expect("verification failed").is_ok())
Expand All @@ -89,7 +89,7 @@ let vc = ssi::claims::vc::v1::data_integrity::any_credential_from_json_str(

// Setup a verification method resolver, in charge of retrieving the
// public key used to sign the JWT.
let vm_resolver = ExampleDIDResolver::default().with_default_options();
let vm_resolver = ExampleDIDResolver::default().into_vm_resolver();

assert!(vc.verify(&vm_resolver).await.expect("verification failed").is_ok());
```
Expand Down Expand Up @@ -133,7 +133,7 @@ let jwt = claims.sign(&key).await.expect("signature failed");

// Create a verification method resolver, which will be in charge of
// decoding the DID back into a public key.
let vm_resolver = DIDJWK.with_default_options::<AnyJwkMethod>();
let vm_resolver = DIDJWK.into_vm_resolver::<AnyJwkMethod>();

// Verify the JWT.
assert!(jwt.verify(&vm_resolver).await.expect("verification failed").is_ok());
Expand Down Expand Up @@ -181,7 +181,7 @@ let did = DIDJWK::generate_url(&key.to_public());

// Create a verification method resolver, which will be in charge of
// decoding the DID back into a public key.
let vm_resolver = DIDJWK.with_default_options();
let vm_resolver = DIDJWK.into_vm_resolver();

// Create a signer from the secret key.
// Here we use the simple `SingleSecretSigner` signer type which always uses
Expand Down
14 changes: 7 additions & 7 deletions crates/claims/core/src/signature.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::fmt;

use ssi_eip712::Eip712TypesEnvironment;
use ssi_json_ld::ContextLoaderEnvironment;
use ssi_eip712::Eip712TypesLoaderProvider;
use ssi_json_ld::JsonLdLoaderProvider;

#[derive(Debug, thiserror::Error)]
pub enum SignatureError {
Expand Down Expand Up @@ -73,7 +73,7 @@ impl Default for SignatureEnvironment {
}
}

impl<JsonLdLoader, Eip712Loader> ContextLoaderEnvironment
impl<JsonLdLoader, Eip712Loader> JsonLdLoaderProvider
for SignatureEnvironment<JsonLdLoader, Eip712Loader>
where
JsonLdLoader: ssi_json_ld::Loader,
Expand All @@ -85,14 +85,14 @@ where
}
}

impl<JsonLdLoader, Eip712Loader> Eip712TypesEnvironment
impl<JsonLdLoader, Eip712Loader> Eip712TypesLoaderProvider
for SignatureEnvironment<JsonLdLoader, Eip712Loader>
where
Eip712Loader: ssi_eip712::TypesProvider,
Eip712Loader: ssi_eip712::TypesLoader,
{
type Provider = Eip712Loader;
type Loader = Eip712Loader;

fn eip712_types(&self) -> &Self::Provider {
fn eip712_types(&self) -> &Self::Loader {
&self.eip712_loader
}
}
124 changes: 13 additions & 111 deletions crates/claims/core/src/verification/claims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use chrono::{DateTime, Utc};
use core::fmt;
use std::borrow::Cow;

pub use ssi_eip712::Eip712TypesEnvironment;
pub use ssi_json_ld::ContextLoaderEnvironment;
pub use ssi_eip712::Eip712TypesLoaderProvider;
pub use ssi_json_ld::JsonLdLoaderProvider;

#[derive(Debug, thiserror::Error, PartialEq)]
pub enum InvalidClaims {
Expand Down Expand Up @@ -39,7 +39,7 @@ pub type ClaimsValidity = Result<(), InvalidClaims>;

/// Claims that can be validated.
///
/// Validation consists in verifying that the claims themselves are
/// This consists in verifying that the claims themselves are
/// consistent and valid with regard to the verification environment.
/// For instance, checking that a credential's expiration date is not in the
/// past, or the issue date not in the future.
Expand All @@ -48,128 +48,30 @@ 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<E, P> {
/// Validates the claims.
fn validate(&self, env: &E, proof: &P) -> ClaimsValidity;
pub trait ValidateClaims<E, P = ()> {
fn validate_claims(&self, environment: &E, proof: &P) -> ClaimsValidity;
}

impl<E, P> Validate<E, P> for () {
fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity {
impl<E, P> ValidateClaims<E, P> for () {
fn validate_claims(&self, _env: &E, _proof: &P) -> ClaimsValidity {
Ok(())
}
}

impl<E, P> Validate<E, P> for [u8] {
fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity {
impl<E, P> ValidateClaims<E, P> for [u8] {
fn validate_claims(&self, _env: &E, _proof: &P) -> ClaimsValidity {
Ok(())
}
}

impl<E, P> Validate<E, P> for Vec<u8> {
fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity {
impl<E, P> ValidateClaims<E, P> for Vec<u8> {
fn validate_claims(&self, _env: &E, _proof: &P) -> ClaimsValidity {
Ok(())
}
}

impl<'a, E, P, T: ?Sized + ToOwned + Validate<E, P>> Validate<E, P> for Cow<'a, T> {
fn validate(&self, _env: &E, _proof: &P) -> ClaimsValidity {
impl<'a, E, P, T: ?Sized + ToOwned + ValidateClaims<E, P>> ValidateClaims<E, P> for Cow<'a, T> {
fn validate_claims(&self, _env: &E, _proof: &P) -> ClaimsValidity {
Ok(())
}
}

/// Environment that provides date and time.
///
/// Used to check the validity period of given claims.
pub trait DateTimeEnvironment {
/// Returns the current date and time.
fn date_time(&self) -> DateTime<Utc>;
}

impl DateTimeEnvironment for () {
fn date_time(&self) -> DateTime<Utc> {
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<u8> {
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 verification such as
/// [`DateTimeEnvironment`].
pub struct VerificationEnvironment<JsonLdLoader = ssi_json_ld::ContextLoader, Eip712Loader = ()> {
pub date_time: DateTime<Utc>,

pub json_ld_loader: JsonLdLoader,

pub eip712_loader: Eip712Loader,
}

impl Default for VerificationEnvironment {
fn default() -> Self {
Self {
date_time: Utc::now(),
json_ld_loader: ssi_json_ld::ContextLoader::default(),
eip712_loader: (),
}
}
}

impl<JsonLdLoader, Eip712Loader> DateTimeEnvironment
for VerificationEnvironment<JsonLdLoader, Eip712Loader>
{
fn date_time(&self) -> DateTime<Utc> {
self.date_time
}
}

impl<JsonLdLoader, Eip712Loader> ContextLoaderEnvironment
for VerificationEnvironment<JsonLdLoader, Eip712Loader>
where
JsonLdLoader: ssi_json_ld::Loader,
{
type Loader = JsonLdLoader;

fn loader(&self) -> &Self::Loader {
&self.json_ld_loader
}
}

impl<JsonLdLoader, Eip712Loader> Eip712TypesEnvironment
for VerificationEnvironment<JsonLdLoader, Eip712Loader>
where
Eip712Loader: ssi_eip712::TypesProvider,
{
type Provider = Eip712Loader;

fn eip712_types(&self) -> &Self::Provider {
&self.eip712_loader
}
}
80 changes: 58 additions & 22 deletions crates/claims/core/src/verification/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@
//! - Proof validation: the claims verified against the proof using the
//! [`ValidateProof`] trait.
mod claims;

use chrono::{DateTime, Utc};
pub use claims::*;
mod proof;
pub use proof::*;
mod parameters;
pub use parameters::*;

/// Verifiable Claims.
///
Expand All @@ -34,37 +38,38 @@ pub trait VerifiableClaims {
/// Proof type.
type Proof;

/// The claims.
fn claims(&self) -> &Self::Claims;

/// The proof.
fn proof(&self) -> &Self::Proof;

/// Validates the claims and verify them against the proof.
#[allow(async_fn_in_trait)]
async fn verify<V>(&self, verifier: &V) -> Result<Verification, ProofValidationError>
where
Self: DefaultVerificationEnvironment,
Self::Claims: Validate<Self::Environment, Self::Proof>,
Self::Proof: ValidateProof<Self::Claims, Self::Environment, V>,
{
self.verify_with(verifier, Self::Environment::default())
.await
}

/// Validates the claims and verify them against the proof.
/// Validates the claims and proof.
///
/// The `params` argument provides all the verification parameters required
/// to validate the claims and proof.
///
/// # What verification parameters should I use?
///
/// It really depends on the claims type `Self::Claims` and proof type
/// `Self::Proof`, but the [`VerificationParameters`] type is a good
/// starting point that should work most of the time.
///
/// # Passing the parameters by reference
///
/// If the validation traits are implemented for `P`, they will be
/// implemented for `&P` as well. This means the parameters can be passed
/// by move *or* by reference.
#[allow(async_fn_in_trait)]
async fn verify_with<V, E>(
&self,
verifier: &V,
env: E,
) -> Result<Verification, ProofValidationError>
async fn verify<P>(&self, params: P) -> Result<Verification, ProofValidationError>
where
Self::Claims: Validate<E, Self::Proof>,
Self::Proof: ValidateProof<Self::Claims, E, V>,
Self::Claims: ValidateClaims<P, Self::Proof>,
Self::Proof: ValidateProof<P, Self::Claims>,
{
match self.claims().validate(&env, self.proof()) {
match self.claims().validate_claims(&params, self.proof()) {
Ok(_) => self
.proof()
.validate_proof(&env, self.claims(), verifier)
.validate_proof(&params, self.claims())
.await
.map(|r| r.map_err(Invalid::Proof)),
Err(e) => {
Expand Down Expand Up @@ -98,3 +103,34 @@ pub enum Invalid {
#[error("invalid proof: {0}")]
Proof(#[from] InvalidProof),
}

/// Type that provides a public key resolver.
pub trait ResolverProvider {
/// Public key resolver.
type Resolver;

/// Returns a reference to the environment's public key resolver.
fn resolver(&self) -> &Self::Resolver;
}

impl<'a, E: ResolverProvider> ResolverProvider for &'a E {
type Resolver = E::Resolver;

fn resolver(&self) -> &Self::Resolver {
E::resolver(*self)
}
}

/// Type that provides date and time.
///
/// Used to check the validity period of given claims.
pub trait DateTimeProvider {
/// Returns the current date and time.
fn date_time(&self) -> DateTime<Utc>;
}

impl<'a, E: DateTimeProvider> DateTimeProvider for &'a E {
fn date_time(&self) -> DateTime<Utc> {
E::date_time(*self)
}
}
Loading

0 comments on commit 30f29a9

Please sign in to comment.