-
Notifications
You must be signed in to change notification settings - Fork 11
Add spec for proofs #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ae6cb3d
c5e173b
e0b62bc
1c4f105
71e0c5b
f67e687
c97b7ff
c583207
2b314cb
521b459
a3331d9
53abb81
e2fc0c3
486a3eb
333f579
23c2995
a8053cf
1e952c2
aea2dc3
12d0bd4
09bf877
7bce59f
4326429
3d64512
bfc1a28
fa244ff
088b8aa
4a069a1
9ae4a15
c0d15ed
72bff56
865c9d4
fee322c
14fed5e
428dd5b
01a9054
051eb9b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
= Proof Attribute (#14) | ||
:cddl: ./cddl/ | ||
|
||
This attribute represents a proof of an object requested with respect to the blockchain's underlying state represented as a Merkle tree. | ||
|
||
== Example | ||
The following is taken from https://github.com/liftedinit/merk/blob/develop/docs/algorithms.md#example-proofs | ||
|
||
Let's walk through a concrete proof example. Consider the following tree: | ||
|
||
``` | ||
5 | ||
/ \ | ||
/ \ | ||
2 9 | ||
/ \ / \ | ||
1 4 7 11 | ||
/ / \ / | ||
3 6 8 10 | ||
``` | ||
|
||
_Small proof:_ | ||
|
||
First, let's create a proof for a small part of the tree. Let's say the user makes a query for keys `1, 2, 3, 4`. | ||
|
||
If we follow our proof generation algorithm, we should get a proof that looks like this: | ||
|
||
``` | ||
Push(KV(1, <value of 1>)), | ||
Push(KV(2, <value of 2>)), | ||
Parent, | ||
Push(KV(3, <value of 3>)), | ||
Push(KV(4, <value of 4>)), | ||
Parent, | ||
Child, | ||
Push(KVHash(<kv_hash of 5>)), | ||
Parent, | ||
Push(Hash(<hash of 9>)), | ||
Child | ||
``` | ||
|
||
Let's step through verification to show that this proof works. | ||
We'll create a verification stack, which starts out empty, and walk through each operator in the proof, in order: | ||
|
||
``` | ||
Stack: (empty) | ||
``` | ||
|
||
We will push a key/value pair on the stack, creating a node. | ||
However, note that for verification purposes this node will only need to contain the kv_hash which we will compute at this step. | ||
|
||
``` | ||
Operator: Push(KV(1, <value of 1>)) | ||
|
||
Stack: | ||
1 | ||
``` | ||
|
||
``` | ||
Operator: Push(KV(2, <value of 2>)) | ||
|
||
Stack: | ||
1 | ||
2 | ||
``` | ||
|
||
Now we connect nodes 1 and 2, with 2 as the parent. | ||
|
||
``` | ||
Operator: Parent | ||
|
||
Stack: | ||
2 | ||
/ | ||
1 | ||
``` | ||
|
||
``` | ||
Operator: Push(KV(3, <value of 3>)) | ||
|
||
Stack: | ||
2 | ||
/ | ||
1 | ||
3 | ||
``` | ||
|
||
``` | ||
Operator: Push(KV(4, <value of 4>)) | ||
|
||
Stack: | ||
2 | ||
/ | ||
1 | ||
3 | ||
4 | ||
``` | ||
|
||
``` | ||
Operator: Parent | ||
|
||
Stack: | ||
2 | ||
/ | ||
1 | ||
4 | ||
/ | ||
3 | ||
``` | ||
|
||
Now connect these two graphs with 4 as the child of 2. | ||
|
||
``` | ||
Operator: Child | ||
|
||
Stack: | ||
2 | ||
/ \ | ||
1 4 | ||
/ | ||
3 | ||
``` | ||
|
||
Since the user isn't querying the data from node 5, we only need its kv_hash. | ||
|
||
``` | ||
Operator: Push(KVHash(<kv_hash of 5>)) | ||
|
||
Stack: | ||
2 | ||
/ \ | ||
1 4 | ||
/ | ||
3 | ||
5 | ||
``` | ||
|
||
``` | ||
Operator: Parent | ||
|
||
Stack: | ||
5 | ||
/ | ||
2 | ||
/ \ | ||
1 4 | ||
/ | ||
3 | ||
``` | ||
|
||
We only need the hash of node 9. | ||
|
||
``` | ||
Operator: Push(Hash(<hash of 9>)) | ||
|
||
Stack: | ||
5 | ||
/ | ||
2 | ||
/ \ | ||
1 4 | ||
/ | ||
3 | ||
9 | ||
``` | ||
|
||
``` | ||
Operator: Child | ||
|
||
Stack: | ||
5 | ||
/ \ | ||
2 9 | ||
/ \ | ||
1 4 | ||
/ | ||
3 | ||
``` | ||
|
||
Now after going through all these steps, we have sufficient knowlege of the tree's structure and data to compute node hashes in order to verify. | ||
At the end, we will have computed a hash for node 5 (the root), and we verify by comparing this hash to the one we expected. | ||
|
||
[sources,cddl] | ||
---- | ||
include::{cddl}14_proof.cddl | ||
---- | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
; Attribute id (related to hashing implementation) | ||
proof@attribute-arg = uint | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
= Proof Request Attribute (#3) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What will go here? |
||
:cddl: ./cddl/ | ||
|
||
This attribute is used to request a proof in the response for a particular request sent to the server. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
= Proof Response Attribute (#3) | ||
:cddl: ./cddl/ | ||
|
||
This attribute allows server to deliver the proof of an object requested. | ||
The proof itself is a sequence of actions used to construct the state in which the object is embedded within the corresponding Merkle tree. | ||
|
||
== Attribute Argument | ||
|
||
This is a `uint` representing the hasher used in constructing the proofs. | ||
|
||
* 0 - `merk` default hash (see xref:../../spec/proof_hash_scheme.adoc.) | ||
|
||
== Returns | ||
|
||
A proof is a collection of operations used to reconstruct a state that can be embedded into the existing state of the Merkle tree that contains it. | ||
|
||
Each state can be represented by one of five operations: | ||
|
||
* A node hash | ||
|
||
* A key/value hash of a node | ||
|
||
* A key and value pair of a node | ||
|
||
* The "parent" operation | ||
|
||
* The "child" operation | ||
|
||
Interpreting these operations as acting on a stack, the first three operations listed can be interpreted as pushing data onto the stack. | ||
In the parent operation, two items are popped from the stack, and a new item with the second item as the left child of the first item is pushed onto the stack. | ||
In the child operation, two items are popped from the stack, and a new item with the first item as the right child of the second item is pushed back onto the stack. | ||
|
||
[source,cddl] | ||
.... | ||
include::{cddl}/3_proof.cddl[] | ||
.... | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
proof@request-attribute-arg //= { | ||
; Block height. | ||
[3, [0, 0]] => uint | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
; Proof. If requested, this is the set of steps constituting a proof of existence of what was requested in the state of the Merkle tree. | ||
proof@response-attribute-arg = { | ||
; Root application hash | ||
0 => bstr, | ||
|
||
; The proof operations | ||
1 => proof, | ||
|
||
; Extensible attribute related indices for extra information (implementation specific) | ||
* proof-attribute-related-index, | ||
} | ||
|
||
proof-attribute-related-index = () | ||
|
||
proof = [ + proof-operation ] | ||
|
||
proof-operation = ( node-hash / key-value-hash / key-value-pair / parent / child ) | ||
|
||
; Represents a parent operation in a proof | ||
parent = 0x10 | ||
|
||
; Represents a child operation in a proof | ||
child = 0x11 | ||
|
||
; The hash of a key-value pair | ||
key-value-hash = [1, bstr] | ||
|
||
; The hash of a node in a proof, containing, in order, the hash of the key-value pair, the hash of the left child, and the hash of the right child | ||
node-hash = [2, bstr] | ||
|
||
; The key-value pair of a proof | ||
key-value-pair = [3, bstr, bstr] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
= Proof Hash Scheme | ||
:cddl: ./cddl/ | ||
|
||
The following list of hash schemes is ordered by attribute id | ||
|
||
== 0 | ||
|
||
Each node contains a "kv hash", which is the hash of a prefix concatenanted with the nodes key and its value. | ||
The hash of the node is the hash of a distinct prefix, the kv hash, and the hash of each of the left and right child nodes. | ||
|
||
``` | ||
kv_hash = H(0x00, key.length, key, value.length, value) | ||
node_hash = H(0x01, kv_hash, left_child_hash, right_child_hash) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, the node hash does not have the lengths in the hash. |
||
``` | ||
|
||
The hash function H is currently the blake3 hash. | ||
|
Uh oh!
There was an error while loading. Please reload this page.