For your understanding, here is a formal description of the verification process.

From a file and a **proof of timestamp** receipt:

- 1 - compute the SHA256 hash of the file
- 2 - check that the
*targetHash*property matches the hash of the file - 3 - check that the
*proof*property is a valid Merkle proof (see the Chainpoint standard for this step) - 4 - retrieve the Bitcoin transaction from the
*anchors*property - 5 - check that the
*OP_RETURN*field of the Bitcoin transaction matches the*merkleRoot*property

**These steps verify the existence of the file at the time of the Bitcoin transaction.**

From a file and a **proof of seal** or **proof of signature** receipt:

- 1 - compute the SHA256 hash of the file
- 2 - check that the
*signature.signedHash*property matches the hash of the file - 3 - check that the
*signature.signature*property is a valid signature of the*signature.signedHash*property for the public key stored in the*signature.pubKey*property - 4 - check that the
*targetHash*property matches the SHA256 hash of the*signature.signature*property - 5 - check that the
*proof*property is a valid Merkle proof (see the Chainpoint standard for this step) - 6 - retrieve the Bitcoin transaction from the
*anchors*property - 7 - check that the
*OP_RETURN*field of the Bitcoin transaction matches the*merkleRoot*property

Additionally, if a *signature.identityURL* property is available:

- call
*signature.identityURL*to make the identity provider sign some random data using the public key*signature.pubKey* - check that the returned signature is a valid signature of the random data
- get the TLS certificates of the URL (it must be an HTTPS URL) to get insight about the identity provider

Note that verification steps 4 to 7 for proofs of signature are similar to steps 2 to 5 for proofs of existence: **these steps verify the existence of the signature at the time of the Bitcoin transaction, which by transitivity verifies the existence of the file at the time of the Bitcoin transaction.**