trustchain_core/
verifier.rs1use std::error::Error;
3
4use crate::chain::{Chain, ChainError, DIDChain};
5use crate::commitment::{CommitmentError, DIDCommitment, TimestampCommitment};
6use crate::resolver::{ResolverError, TrustchainResolver};
7use async_trait::async_trait;
8use ssi::did_resolve::DIDResolver;
9use thiserror::Error;
10
11#[derive(Error, Debug)]
13pub enum VerifierError {
14 #[error("Invalid payload provided in proof for dDID: {0}.")]
16 InvalidPayload(String),
17 #[error("Invalid signature for proof in dDID: {0}.")]
19 InvalidSignature(String),
20 #[error("Invalid root DID error: {0}")]
22 InvalidRoot(Box<dyn std::error::Error + Send + Sync>),
23 #[error("Invalid root DID ({0}) with timestamp: {1}.")]
25 InvalidRootTimestamp(String, Timestamp),
26 #[error("Failed to build chain: {0}.")]
28 ChainBuildFailure(String),
29 #[error("Chain verification failed: {0}.")]
31 InvalidChain(String),
32 #[error("Invalid PoW hash: {0}.")]
34 InvalidProofOfWorkHash(String),
35 #[error("Error getting {0} DID operation.")]
37 FailureToGetDIDOperation(String),
38 #[error("Error getting {0} DID content.")]
40 FailureToGetDIDContent(String),
41 #[error("Unrecognised DID content found at: {0}")]
43 UnrecognisedDIDContent(String),
44 #[error("Error reading DID content found at: {0}")]
46 FailureToReadDIDContent(String),
47 #[error("Error parsing DID content: {0}")]
49 FailureToParseDIDContent(String),
50 #[error("Error verifying DID content.")]
52 FailureToVerifyDIDContent,
53 #[error("Error parsing timestamp data.")]
55 FailureToParseTimestamp,
56 #[error("Invalid block hash: {0}")]
58 InvalidBlockHash(String),
59 #[error("Invalid block height: {0}")]
61 InvalidBlockHeight(i64),
62 #[error("Invalid transaction index: {0}")]
64 InvalidTransactionIndex(i32),
65 #[error("Failed to get block hash for DID: {0}")]
67 FailureToGetBlockHash(String),
68 #[error("Failed to get block height for DID: {0}")]
70 FailureToGetBlockHeight(String),
71 #[error("Failed to get block header for block hash: {0}")]
73 FailureToGetBlockHeader(String),
74 #[error("Failed API call to PoW ledger client: {0}")]
76 LedgerClientError(String),
77 #[error("Detected multiple DID content identifiers in tx: {0}")]
79 MultipleDIDContentIdentifiers(String),
80 #[error("No DID content identifier was found in tx: {0}")]
82 NoDIDContentIdentifier(String),
83 #[error("Content hash {0} does not match expected: {1}")]
85 FailedContentHashVerification(String, String),
86 #[error("Unhandled DID content: {0}")]
88 UnhandledDIDContent(String),
89 #[error("Failed to resolve DID: {0} with associated resolution metadata: {1}")]
91 DIDResolutionError(String, Box<ResolverError>),
93 #[error("Failed to parse DID Document metadata.")]
95 DIDMetadataError,
96 #[error("Key not found in verified content for DID: {0}")]
98 KeyNotFoundInVerifiedContent(String),
99 #[error("No keys found in verified content for DID: {0}")]
101 NoKeysFoundInVerifiedContent(String),
102 #[error("Endpoint not found in verified content for DID: {0}")]
104 EndpointNotFoundInVerifiedContent(String),
105 #[error("No endpoints found in verified content for DID: {0}")]
107 NoEndpointsFoundInVerifiedContent(String),
108 #[error("Duplicate update commitments: {0}")]
110 DuplicateDIDUpdateCommitments(String),
111 #[error("PoW hashes do not match: {0}, {1}")]
113 FailedProofOfWorkHashVerification(String, String),
114 #[error("Timestamp verification failed for transaction: {0}")]
116 FailedTransactionTimestampVerification(String),
117 #[error("Block hash verification failed for DID: {0}.")]
119 FailedBlockHashVerification(String),
120 #[error("Timestamp verification failed for DID: {0}.")]
122 TimestampVerificationError(String),
123 #[error("Error fetching verification material: {0}. Error: {1}")]
125 ErrorFetchingVerificationMaterial(String, Box<dyn Error + Send + Sync>),
126 #[error("Failed to fetch verification material: {0}")]
128 FailureToFetchVerificationMaterial(String),
129 #[error("Verification material not yet fetched for DID: {0}.")]
131 VerificationMaterialNotYetFetched(String),
132 #[error("A commitment error during verification: {0}")]
134 CommitmentFailure(CommitmentError),
135 #[error("A resolver error during verification: {0}")]
137 ResolverFailure(ResolverError),
138 #[error("A chain error during verification: {0}")]
140 ChainFailure(ChainError),
141 #[error("Failed to deserialize: {0}")]
143 FailedToDeserialize(serde_json::Error),
144}
145
146impl From<CommitmentError> for VerifierError {
147 fn from(err: CommitmentError) -> Self {
148 VerifierError::CommitmentFailure(err)
149 }
150}
151
152impl From<ResolverError> for VerifierError {
153 fn from(err: ResolverError) -> Self {
154 VerifierError::ResolverFailure(err)
155 }
156}
157
158impl From<ChainError> for VerifierError {
159 fn from(err: ChainError) -> Self {
160 VerifierError::ChainFailure(err)
161 }
162}
163
164impl From<serde_json::Error> for VerifierError {
165 fn from(err: serde_json::Error) -> Self {
166 VerifierError::FailedToDeserialize(err)
167 }
168}
169
170pub type Timestamp = u64;
172
173pub trait VerifiableTimestamp {
175 fn did_commitment(&self) -> &dyn DIDCommitment;
177 fn timestamp_commitment(&self) -> &dyn TimestampCommitment;
179 fn timestamp(&self) -> Timestamp {
181 self.timestamp_commitment().timestamp()
182 }
183 fn verify(&self, target: &str) -> Result<(), CommitmentError> {
185 self.did_commitment().verify(target)?;
190 self.timestamp_commitment().verify(target)?;
191 Ok(())
192 }
193}
194
195#[async_trait]
197pub trait Verifier<T: Sync + Send + DIDResolver> {
198 async fn verify(
200 &self,
201 did: &str,
202 root_timestamp: Timestamp,
203 ) -> Result<DIDChain, VerifierError> {
204 let resolver = self.resolver();
206 let chain = DIDChain::new(did, resolver).await?;
207
208 chain.verify_proofs()?;
210
211 let root = chain.root();
213
214 let verifiable_timestamp = self.verifiable_timestamp(root, root_timestamp).await?;
215
216 verifiable_timestamp.verify(&verifiable_timestamp.timestamp_commitment().hash()?)?;
219
220 self.validate_pow_hash(&verifiable_timestamp.timestamp_commitment().hash()?)?;
222
223 if !verifiable_timestamp.timestamp().eq(&root_timestamp) {
226 Err(VerifierError::InvalidRootTimestamp(
227 root.to_string(),
228 verifiable_timestamp.timestamp(),
229 ))
230 } else {
231 Ok(chain)
232 }
233 }
234
235 async fn verifiable_timestamp(
238 &self,
239 did: &str,
240 expected_timestamp: Timestamp,
241 ) -> Result<Box<dyn VerifiableTimestamp>, VerifierError>;
242
243 async fn did_commitment(&self, did: &str) -> Result<Box<dyn DIDCommitment>, VerifierError>;
245
246 fn validate_pow_hash(&self, hash: &str) -> Result<(), VerifierError>;
248
249 fn resolver(&self) -> &dyn TrustchainResolver;
251}
252
253#[cfg(test)]
254mod tests {}