Working with Proofs

ProvenDB Proofs are crytographic hashes (in Chainpoint format) stored on the bitcoin blockchain that establish the time of creation and integrity of a ProvenDB database Version. This proof can also be used to prove individual documents in that version.

You can read more about proof concepts here, but in summary, a proof is a Chainpoint compatible hash tree structure that can be used to validate the entire version of the database, or any document within the database. The "root" hash from this hash tree is stored on the bitcoin blockchain.

ProvenDB proofs start in Pending status. At this point the proof has been submitted to the ChainPoint network but has not yet been stored on the ChainPoint blockchain.

Once confirmed on the ChainPoint network, proofs move to Submitted status.

When the ChainPoint proof is anchored on the bitcoin blockchain, the proof moves to Valid status.

Creating a new proof

The submitProof command creates a new proof for a specific database version.

For example, below we retrieve the current version number and submit a proof for that version:

mongo> db.runCommand({getVersion:1});
{
	"ok" : 1,
	"response" : "The version is set to: 'current'",
	"version" : NumberLong(10882250),
	"status" : "current"
}
mongo> db.runCommand({submitProof:10882250});
{
	"ok" : 1,
	"version" : NumberLong(10882250),
	"dateTime" : ISODate("2019-03-21T02:00:10Z"),
	"hash" : "5865a9e5507601068142210630cf1394bc1dceebb22b4460ed4cc7cd2ec98f10",
	"proofId" : "0ec8d9f0-4b7d-11e9-a4bd-01d7933a01fb",
	"status" : "Pending"
}

❗️

submitProof elapsed time

Depending on the size of your database, submitProof may take a while to complete. It must construct a merkle hash tree from all of the document hashes in the current version. On a database with millions of documents in the current version, this may take a couple of minutes.

Listing existing proofs

You can query the _provendb_versionProofs collection to list proofs. For instance, the following query retrieves the most recent proof:

dbKoda Mongo Shell>db.getCollection('_provendb_versionProofs').
...   find({}, { proof: 0, details: 0 }).
...   sort({ submitted: -1 }).
...   limit(1).
...   pretty();
{
	"_id" : ObjectId("5c92f02aee86fd139b2a9500"),
	"proofId" : "0ec8d9f0-4b7d-11e9-a4bd-01d7933a01fb",
	"version" : NumberLong(10882250),
	"submitted" : ISODate("2019-03-21T02:00:10Z"),
	"type" : "full",
	"hash" : "5865a9e5507601068142210630cf1394bc1dceebb22b4460ed4cc7cd2ec98f10",
	"status" : "submitted"
}

In the following example we find the highest 'valid' proof (valid proofs have been completely anchored to the bitcoin blockchain):

dbKoda Mongo Shell>db.getCollection('_provendb_versionProofs').
...   find({status:'valid'}, { proof: 0, details: 0 }).
...   sort({ version: -1 }).
...   limit(1).
...   pretty();
{
	"_id" : ObjectId("5c92b7846447b82ec0a17dbd"),
	"proofId" : "4b4bd980-4b5b-11e9-a4bd-0145f61fa886",
	"version" : NumberLong(10881844),
	"submitted" : ISODate("2019-03-20T21:58:28Z"),
	"type" : "full",
	"hash" : "409119c97176aa030c152038270980dfd1c49b19464ee157751826e18da5048b",
	"status" : "valid"
}

Getting a proof that covers a version

Not every version needs it's own proof. For instance, if two versions differ only in that documents were inserted from one proof to another, then a proof of the higher version can be used to prove any document in the lower version. Furthermore, any document that still exists unaltered in the higher version will still be provable. Only documents that have been altered between the two versions will require a seperate proof.

To find the proof closest to a particular datetime, we can do the following:

// Find the version in effect at 14th Feb 2019
mongo> db.runCommand({setVersion:new Date('2019-02-14')})
{
	"ok" : 1,
	"response" : "The version has been set to: '4486'",
	"version" : NumberLong(4486),
	"status" : "userDefined"
}
// Find the version proof closest to that version. 
mongo> db.getCollection('_provendb_versionProofs').
...            find({status:'valid',version:{$gte:4486}}, { proof: 0, details: 0 }).
...           sort({ version: -1 }).limit(1).pretty();
{
	"_id" : ObjectId("5c9433eb41d82814ca398110"),
	"proofId" : "076f78a0-4c3e-11e9-a4bd-01e33ea1e3b0",
	"version" : NumberLong(10883428),
	"submitted" : ISODate("2019-03-22T01:01:30Z"),
	"type" : "full",
	"hash" : "3c4eacc774a1d38f5f24b5d5152b108bfb5bc516824ba73cc5f19db894c60a98",
	"status" : "valid"
}

Validating a proof on-line

The verifyProof command can be used to confirm the integrity of an existing proof. It recalculates all of the hash values concerned and compares resulting hash to that stored on the blockchain. For instance here we validate the proof retrieved in the previous example:

mongo> db.runCommand({verifyProof:'076f78a0-4c3e-11e9-a4bd-01e33ea1e3b0'})
{
	"ok" : 1,
	"version" : NumberLong(10883428),
	"dateTime" : ISODate("2019-03-25T05:55:38.653Z"),
	"hash" : "3c4eacc774a1d38f5f24b5d5152b108bfb5bc516824ba73cc5f19db894c60a98",
	"proofId" : "076f78a0-4c3e-11e9-a4bd-01e33ea1e3b0",
	"proofStatus" : "Invalid",
	"btcTransaction" : "4582f2a2852dc615523f3960d9c007e53e64ecbc8e7a8e3f8ddef0d90d02de29",
	"btcBlockNumber" : "568217"
}

Validating a proof off-line

It is also possible to verify proofs using our open source utility. This procedure is described in Independently validating your blockchain proofs.

It is also possible to validate your proof using the chainpoint API and CLI tools. All ProvenDB proofs are Chainpoint compliant and can be validated using Chainpoint APIs.

Getting a version proof

The getProof command can be used to retrieve a proof. It accepts either a version number or a proofId. For instance, the following command retrieves the proof which we verified in the previous example.

ProvenDB v10882250 (valid)> db.runCommand({getProof:'4b4bd980-4b5b-11e9-a4bd-0145f61fa886'})
{
	"ok" : 1,
	"proofs" : [
		{
			"proofId" : "4b4bd980-4b5b-11e9-a4bd-0145f61fa886",
			"version" : NumberLong(10881844),
			"submitted" : ISODate("2019-03-20T21:58:28Z"),
			"type" : "Full",
			"hash" : "409119c97176aa030c152038270980dfd1c49b19464ee157751826e18da5048b",
			"status" : "Valid",
			"details" : {
				"protocol" : {
					"name" : "chainpoint",
					"uri" : "http://13.238.131.2",
					"hashIdNode" : "4b4bd980-4b5b-11e9-a4bd-0145f61fa886",
					"chainpointLocation" : "https://b.chainpoint.org/calendar/2890070/data"
				},
				"btcTxn" : "56afe6b9c71a6f55ff79f847099202b4fc8f0168e7274c18d3cc4e5bdb172564",
				"btcBlock" : "568040"
			},
			"proof" : {
				"@context" : "https://w3id.org/chainpoint/v3",
				"type" : "Chainpoint",
				"hash" : "409119c97176aa030c152038270980dfd1c49b19464ee157751826e18da5048b",
				"hash_id_node" : "4b4bd980-4b5b-11e9-a4bd-0145f61fa886",
				"hash_submitted_node_at" : "2019-03-20T21:58:28Z",
				"hash_id_core" : "4bf538e0-4b5b-11e9-9831-0196025c6395",
				"hash_submitted_core_at" : "2019-03-20T21:58:29Z",
				"branches" : [...

This information is similar to that found in the _provendb_versionProofs collection but can also include a JSON representation of the Chainpoint proof structure.

Getting a document proof

A version proof proves the entire database version as a whole. A document proof incorporates the merkle path between the version hash and the document hash and merges that into the chainpoint proof of the version. The result of that is that you have a chainpoint compatible proof proving that the individual document was incorporated into the chainpoint proof posted to the blockchain.

getDocumentProof Allows you to retrieve one or more proofs for individual documents. The example below returns proofs for any document in the collection files_5c6b4735769348aee6f8fd00 with the string "Last Will and Testement" in the name attribute as of version 8 of the database:

Mongo Shell>db.runCommand({getDocumentProof:{
...    collection:'files_5c6b4735769348aee6f8fd00' ,
...    filter:{name:{$regex:"Last Will and Testement"}},
...    version:8,
...    format:'binary'
... }})
{
	"ok" : 1,
	"proofs" : [
		{
			"collection" : "files_5c6b4735769348aee6f8fd00",
			"version" : NumberLong(6),
			"documentId" : ObjectId("5c7f46eebe1e3eaea78b1abe"),
			"versionProofId" : "cb7a1180-3fc6-11e9-a4bd-019793331702",
			"status" : "Valid",
			"btcTransaction" : "9b890c83fcdda9d415bb9c14dfac248e541f2c3387de1c5a290c1774c96e116d",
			"btcBlockNumber" : "565864",
			"documentHash" : "1bc4d9d07a4142ee9070253a86d49fff767d95bbe5cc40efbac96e60233ff592",
			"versionHash" : "ec81ad126f5e922984e34bc3bd27d875e52a0cb4406900ae3092e8900bf81dc4",
			"proof" : BinData(0,"eJysV81uZke1vfddMozT+7d...")
		}
	]
}