This is a simple example showing case how to use the chainark
library.
Suppose we have a chain structure:
data0 <- data1 <- data2 <- data3
Following the rule:
Each data is simply composed by below two elements concatenated together hash || string_literal
, where:
hash
is hash value of 32 bytes, which is the SHA256 hash of its predecessor data;string literal
ischainark example
.
Now the LinkageID
is the hash
value. In the supplied data file, the first hash
is generated by running this command:
echo 0000000000000000000000000000000000000000000000000000000000000000 | xxd -r -p | openssl sha256 -hex
It outputs hash value 66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
.
Then data0
, or the first line of the data file is simply
66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925636861696e61726b206578616d706c65
with 636861696e61726b206578616d706c65
as the hex encode of chainark example
.
Going forward we may have the ID corresponding to data0
from running the command:
echo 66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925636861696e61726b206578616d706c65 | xxd -r -p | openssl sha256 -hex
and its value is 843d12c93f9079e0d63a6101c31ac8a7eda3b78d6c4ea5b63fef0bf3eb91aa85
. This is then the genesis ID
or id0
. Usually a genesis ID is publically known and recognized.
Now data1
becomes 843d12c93f9079e0d63a6101c31ac8a7eda3b78d6c4ea5b63fef0bf3eb91aa85636861696e61726b206578616d706c65
, and we can compute id1
, and so on.
Now we want to prove that following the above hashing computation rule, a hash value of ad057c8b077361d9f5673d5faa0bf4f6c5013bb5fb745339042329976637a705
could be computed starting from the data identified by the genesis ID
of 843d12c93f9079e0d63a6101c31ac8a7eda3b78d6c4ea5b63fef0bf3eb91aa85
.
To do this, we first need to generate the unit
proofs, that is, we need a ZK-proof from a data item (hash || "chainark example"
) to an ID (hash
) for all the IDs from genesis to the one under question. UnitCircuit
is implemented in the [unit/core/circuit.go]. For demonstration, 4 types unit circuits are defined, each handle 8/4/2/1 hash iteration. Besides unit circuit definition, a main function in unit/unit.go is defined to generate the unit proofs.
Then we also need to create main functions to output the genesis and recursive proofs. The genesis circuit verifies the first unit proof, building the initial chain structure starting from the chosen genesis ID. The recursive circuit verifies first a genesis proof or a recursive proof, then a unit proof. The proof generated from the recursive circuit could be used to verify the existence of a chain from the genesis ID to the one under question.
Please refer to the general doc.
Note that the fingerprints of all verification keys have been hardcoded in the example codes. Usually you don't need to worry about it. But if you have modified some of the circuits, or if you are planning to build your own application based on this example, here are general procedures to follow:
- Go to the
unit
folder, build the application, run./unit --setup
to generate proving key and verification key for the unit circuit; - Go to the
recursive
folder, build the application, run./recursive --setup
to generate proving key and verification key for the recursive circuit;
Or just
sh setup.sh
Now setup is complete. Run below commands to compute the proof:
- Go to the
unit
folder, run./unit_prove.sh
; - Go to the
recursive
folder, run./recursive_prove.sh
.
Now you have exactly one proof for each and every id: the genesis id is recognized, its successor is proved with a unit
proof, and the rest with a corresponding recursive
proof.
sh run.sh