Crates.io | merkle-tree-bulletin-board |
lib.rs | merkle-tree-bulletin-board |
version | 0.3.0 |
source | src |
created_at | 2021-08-11 13:49:13.938042 |
updated_at | 2023-03-10 11:54:26.825053 |
description | A public bulletin board based upon Merkle trees. |
homepage | https://github.com/RightToAskOrg/bulletin-board |
repository | https://github.com/RightToAskOrg/bulletin-board |
max_upload_size | |
id | 434769 |
size | 710,900 |
This implements a verifiable bulletin board based upon a Merkle tree. It is included in a repository which also contains a demo web server using it and a mysql backend.
There is a common addage "trust, but verify." Unfortunately, it is often impossible to verify, so if you are on the other end of this addage you should "be trustworthy, but be verifiable." This is designed to help a trustworthy bulletin board be verifiable.
Specifically, it allows for the continuous additions of elements to the bulletin board. Periodically, the bulletin board publishes a hashcode that is a commitment to all the elements published to date. Everyone can call their friends and check that everyone is being told the same hash, as evidence that everyone is being shown the same bulletin board. Anyone can check that any specific entry is referenced by said hash, and it is also possible to download the entire board (or additions since the last published hash) and check that is compatible with the provided hash.
This gives everyone confidence that the bulletin board operator is actually trustworthy. Or they have worked out how to reverse SHA2, which is considered hard. For a comparable definition of hard to "achieving world peace, prosperity and universal love" is hard.
That solves a very similar problem in a simpler manner, and is preferable except for a couple of advantages of this approach:
Start from the BulletinBoard structure, which has extensive documentation.
There are also helper verifier functions for inclusion proofs, but you should write your own as the whole point is to not need to trust this!
The bulletin board needs to store its information somewhere. There are a variety of ways of doing this, abstracted into a Backend. You can pretty easily write your own, or there are a variety of backends available:
See Wikipedia or Google for the general theory.
Different problems have somewhat different details depending upon their specific requirements. For the bulletin board, we want the additions of items to be an ongoing process, with occasional publications not synchronized to the additions. In particular, we can't assume a power of two entries on the board. We also record the text of the items rather than just their hash.
There are three different types of node in the system:
0|timestamp|entry
1|left|right
2|timestamp|prior|elements concatenated
See comments in hash_history.rs
for precise description of the hash definitions.
Each time an entry is added, a new leaf is created. This is appended to a pending list of trees. (a leaf is considered a tree of depth 0). If the last two entries in the pending list have the same depth, then a new branch is created from those two, and replaces them on the pending list. This is continued recursively until the last two entries in the pending list are different depth (or there is only one entry in the list). This list will never get longer than 1+log base 2 of N, where N is the number of leaves.
This pending list contains the list of leaves and branches that have no parents; a published root is really a list of these elements. This means publishing a root hash is a relatively minor operation, very similar to a git commit object.
Many Merkle tree implementations bunch all nodes together into one tree at the point of publication, and ensure that that tree is present in future published trees. This common approach has the advantage that a published root is simpler as it only has one item in it, so an inclusion proof for a prior published root is just an inclusion proof for that one item instead of several items. However that approach leads to unbalanced binary trees, and often poor performance and/or complexity for inclusion proofs for old entries with respect to new published roots. The approach used in this library guarantees simple log N size inclusion proofs.
The following picture from the demo shows the status after submitting three entries, A, B, and C, and then publishing a root.
013c...
b8ba...
e4d5...
23e3...
bf9a...
that referenced the branch e4d5...
and leaf 23e3...
Then an extra entry "D" was submitted and a new publication was done.
1f14...
ef57...
1fd7...
dbe3...
that referenced the branch 1fd7...
Note that if you do the same with the demo you will get the same structure but different hash values as timestamps are included.
Note also that the picture above does not show (for space reasons) the link in the published root dbe3...
to the prior published root bf9a...
A full inclusion proof for the entry A in this example in the published root dbe3...
is given
in the following screenshot of the demo webserver:
Copyright 2021 Thinking Cybersecurity Pty. Ltd.
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
0.1.0 : Initial release
0.1.1 : Better tags, images in docs point to repository as relative links to images don't seem to work with crates.io
0.3 : Better error handling. Replace "anyhow" errors with more useful enum errors (API change). Removed itertools & anyhow dependency.