HERB is a Publicly Verifiable Random Beacon protocol described in this article. This repository is HERB implementation written in Golang as Cosmos application using Kyber library.
Publicly Verifiable Random Beacon protocol allows securely generating random numbers and any third party can validate results. HERB implementation is a blockchain application and HERB participants are users of this blockchain (not full nodes). After setup phase, all process will divide into rounds. Simplified implementation description:
- New round i is starting.
- Each participant sends the ciphertext share (encrypted random number) to the blockchain (as a transaction).
- After receiving t1 ciphertext share, the common ciphertext (encrypted sum of all sent random numbers) is being aggregated.
- Each participant sends decryption share to the blockchain (as a transaction).
- After receiving t2 decryption shares, the round is completed (aggregated ciphertext can be decrypted to the random number). A new round is i + 1.
- Go to step 1.
- Disclaimer
- Implementation details
- Blockchain and Clients
- How to run it locally
- How to run a local testnet with Docker
- How to run a distributed testnet with Digital Ocean
This software is considered experimental. DO NOT USE it for anything security critical at this point.
This is a Proof-of-Concept implementation, so some details from the original paper are simplified here.
Recall, that there are 3 protocol phases (page 12):
- Setup phase. The main purpose of the setup phase is key generating. DKG phase (Section 3.1, page 13) is skipped in this implementation.
dkgcli
simulates DKG-phase and generates private/public keys. These keys have could found in thebots
folder. - Publication phase. Each entropy provider sends ciphertext share and proofs using
hcli tx herb ct-share
command. - Disclosure phase. Each key holder sends decryption share and proof using
hcli tx herb decrypt
command.
Entropy Providers and Key Holders (page 12) are the same sets.
Let's look at the original HERB protocol (page 17) closer.
- Each entropy provider ej, 1 ≤ j ≤ m, generates random point Mj ∈ G. Then encrypts it:
- ej publishes Cj along with NIZK of discrete logarithm knowledge for Aj and NIZK of representation knowledge for Bj
hcli tx herb ct-share [commonPubKey]
command calculates ciphertext share and CE proof and sends a transaction with a Ciphertext Share Message.
- When Cj is published, participants agree that the ciphertext share is correct, if CE-Verify(πCEj,G, Q, Aj, Bj) = 1.
- When all correct Cj are published, participants calculate C = (A, B)
On the blockchain side, keeper's function verifies the ciphertext share and store it into the blockchain. This function also aggregates new ciphertext with cyphertexts which are already stored.
Anyone can see stored ciphertexts by query:
hcli query herb all-ct [round]
Query for aggregated ciphertext:
hcli query herb aggregated-ct [round]
As soon as t1 ciphertext parts were stored, the application's stage changes to "disclosure phase" for the current round.
- Key holder idi, 1 ≤ i ≤ n, publishes decryption shares along with NIZK of discrete logarithm equality
hcli tx herb decrypt [privateKey] [ID]
command queries the aggregated ciphertext and calculates a decryption share. This command also sends a transaction with Decryption Share message.
- When Di is published, participants verify that DLEQ-Verify(πDLEQi,Di,A,VKi,G) = 1
On the blockchain side, keeper's function verifies the decryption share and stores it into the blockchain.
Anyone can see stored decryption shares by query:
hcli query herb all-shares [round]
- When t2 decryption shares published, participants calculate M
As soon as t2 decryption shares were stored, application decrypts an aggregated ciphertext and changes current round stage to "completed". A new round is being started.
Anyone can see generated random number by query:
hcli query herb get-random [round]
HERB round changing depends on transactions by Entropy Providers and Key Holders and doesn't depend on underlying blockchain's height. So one HERB round can take 1 block or 10 blocks, it depends only on HERB participants and blockchain throughput. Anyone can query current round and current stage by commands:
hcli query herb current-round
hcli query herb stage
There are two types of entities who maintain the system:
-
Blockchain full nodes who run application daemon (hd). Let's denote them as nodes.
-
Scripts (HERB) which represents protocol participants. Let's call them clients.
Clients use an application command line interface for querying app state and sending transactions.
-
Install dependencies:
sudo apt-get install expect -y sudo apt-get install make -y sudo apt-get install jq -y
-
Clone repository to the $HOME directory
-
Install application:
cd ~/HERB make install
-
Run setup script:
cd scripts ./init_chain_full.sh t1 t2 n
For example, t1 = t2 = 2, n = 3. n is a total number of clients, t1, t2 is a thresholds (see simplified protocol description).
init_chain.exp
initializes blockchain parameters and creates clients' secret keys (bots folder). -
Setup blocktime:
cd $HOME/.hd/config sed -i 's/timeout_commit = "5s"/timeout_commit = "1s"/' config.toml;
-
Run application daemon:
hd start
Now node is running and blocks are being generated.
-
In another terminal run clients:
cd $HOME/HERB ./scripts/run_clients.sh k j
run_clients k j
runs j clients (bot%i%.exp files) starting from k-th client. For instance, for k=0, j=3 it runs 3 client: client0.exp, client1.exp, client2.exp. -
Random number generation process is started! You can check the current HERB round by query:
hcli query herb current-round
-
You can get the random number generation results by query:
hcli query herb get-random %round-number%
-
Run the
testnet.sh
script:cd $HOME/HERB ./testnet.sh
Script will display see created docker containers' id.
You can get help:
./testnet.sh -h
-
If you want to check the random numbers generation process, then connect to the docker container:
sudo docker exec -it %container-id% /bin/bash
-
Then you can use hcli commands:
hcli query herb current-round hcli query herb get-random %round-number%
-
To stop the testnet run:
./testnet_stop.sh
For Ubuntu:
-
Create two DigitalOcean ubuntu-droplets (we'll call them node-00 and node-01).
The first one is a "zero"-node, which runs full setup phase. The second one is a "blueprint" which will be duplicated later.
-
Send DigitalOcean associated ssh-keys to node-00:
scp %ssh-keys path% root@%node-00 ip%:.ssh/
-
Run machine_setup.sh script for both nodes. It installs Go and other required software.
cd $HOME/HERB/scripts ssh root@%node-ip% 'bash -s' < machine_setup.sh
-
Connect to node-00 and perform actions below:
-
Export environment variables:
source ~/.profile
-
Clone repository to the $HOME directory.
git clone https://%username%@github.com/corestario/HERB
-
Install application:
cd ~/HERB make install
-
Run setup script:
cd $HOME/HERB/scripts ./init_chain_full.sh t1 t1 n
For example, t1 = t2 = 2, n = 3. n is a total number of clients, t1, t2 is a thresholds (see simplified protocol description).
init_chain.exp
initializes blockchain parameters and creates clients' secret keys (bots folder).-
Setup blocktime:
cd $HOME/.hd/config sed -i 's/timeout_commit = "5s"/timeout_commit = "1s"/' config.toml
-
Send configuration files and keys to node-01:
scp $HOME/.hd/config/genesis.json root@%node-01-ip%: scp -r $HOME/.hcli/keys root@%node-01-ip%: scp $HOME/.hd/config/config.toml root@%node-01-ip%: scp -r $HOME/HERB/bots root@%node-01-ip%:
-
Run app daemon:
hd start
-
-
Connect to node-00 again:
-
Get node-00 tendermint-id:
hcli status
and save "id" value somewhere.
-
Run Prometheus:
cd prometheus-2.11.1.linux-amd64 ./prometheus --config.file=$HOME/HERB/prometheus.yml
-
-
Connect to node-00 one more time:
-
Run first clients:
cd $HOME/HERB/scripts ./run_clients.sh 0 %k%
run_clients k j
runs j clients (bot%i%.exp files) starting from k-th client. Other clients will be launched by therun_testnet.sh
script later.
-
-
Connect to node-01:
-
Export environment variables:
source ~/.profile
-
Clone repository to the $HOME directory
git clone https://%username%@github.com/corestario/HERB
-
Install application:
cd ~/HERB make install
-
Set node-00 as seed for tendermint:
sed -i 's/seeds = ""/seeds = "%node-00 id%@%node-00 ip%:26656"/' tmp/config.toml
-
-
Now, node-01 is our blueprint for other nodes. Make a DigitalOcean snapshot of the node-01.
-
Create as mush droplets from node-01 snapshot as you need.
-
Copy IPs all nodes except node-00 to
HERB/scripts/servers.txt
line by line on your machine. -
Launch all application daemons and clients on the nodes from server.txt file:
cd $HOME/HERB/scripts ./run_distributed_testnet.sh servers.txt %first node number% %client per node%
Here are two arguments:
- first node number - define moniker for node daemon and the number of the first launching client
- client per node - define how many clients (bots files) will be launched on each node
For example: if we run the command with two IPs in the server.txt file:
./run_distributed_testnet.sh servers.txt 1 3
It will launch clients:
client3.exp
,client4.exp
,client5.exp
on the second node;client6.exp
,client7.exp
,client8.exp
on the third node. -
Now you can check the progress by querying current-round:
hcli query herb current-round