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.