zcash-devtool Tutorial
This tutorial explaining how to use FROST to sign a Zcash transaction using zcash-devtool.
Setting up
Install cargo and git.
Install the zcash-devtool:
cargo install --git https://github.com/zcash/zcash-devtool.git --locked
Install the frost-client tool:
cargo install --git https://github.com/ZcashFoundation/frost-zcash-demo.git --locked frost-client
Install the zcash-sign tool:
cargo install --git https://github.com/ZcashFoundation/frost-zcash-demo.git --locked zcash-sign
Switch to an empty folder which will store the files generated in the demo. For example:
mkdir frost-demo
cd frost-demo/
Running the server
This demo uses the ZF FROST server (frostd) to help participants communicate. While in practice users would use an existing online server, for the demo you can run a local server by following these instructions (the "Compiling, Running and Deploying" and "Local Testing" sections).
The rest of the tutorial assumes the server is up and running.
Initializing the users
Run the following command to initialize three users (in practice, each user would run a similar command, but for demo purposes we're assuming you will simulate all of them in the same machine, so run these commands in your machine):
frost-client init -c alice.toml
frost-client init -c bob.toml
frost-client init -c eve.toml
This will create a config file for three users; Alice, Bob and Eve.
If you really want to run the demo in separate machines, then you can omit the
-c alice.toml part of the command (i.e. run frost-client init); it will
save to a default location in the user's home directory.
Generating FROST key shares
First we will generate the FROST key shares. For simplicity we'll use trusted dealer; if you want to use Distributed Key Generation, skip to the next section.
In a new terminal (in case the previous terminal is running the server), run the following:
frost-client trusted-dealer -d "Alice, Bob and Eve's group" --names Alice,Bob,Eve -c alice.toml -c bob.toml -c eve.toml -C redpallas
This will by default generate a 2-of-3 key shares. The key shares will be
written into each participant's config file. You can change the threhsold,
number of shares and file names using the command line; append -h to the
commend above for the command line help.
Generating FROST key shares using DKG
For real-word usage we commend generating key shares using Distributed Key Generation. If you did the previous section, skip to "Generating the Full Viewing Key for the wallet".
This section assumes each participant is running the commands in their own
machine. If you want to simulate all of them in a single machine,
specify the config file for the user (e.g. -c alice.toml) accordingly.
Initializing config files
If they haven't yet, each participant should run:
frost-client init
Sharing contacts
Each participant must now generate a contact string that they will need to share with the other participants. This contact string will include a name, which they can choose when exporting and will be shown to whoever they send the contact to.
Run the following, substituting the name accordingly:
frost-client export --name 'Alice'
The command will print an encoded contact string such as
zffrost1qyqq2stvd93k2g84hudcr98zp67a9rnx9v00euw9e5424hjathvre7ymy344fynjdvxmwxfg.
Send it to the other participants using some trusted communication channel
(instant messaging, etc.).
The other participants will send you their contacts. Import them by running the
following command for each contact (replace <contact-string> with the contact
string accordingly):
frost-client import <contact-string>
Generating shares
Finally, to generate the shares, one of the participants will need to initiate the process. They will need to public key of each participant, so they need to first list them with the following command:
frost-client contacts
Then run the following command, replacing the <pubkey1> and <pubkey2> hex
strings with the public keys of the contacts which will participate (along with
the user running the command):
frost-client dkg -d "Alice, Bob and Eve's group" -s localhost:2744 -S <pubkey1>,<pubkey2> -t 2 -C redpallas -c alice.toml
The user should then notify the others that a signing session has started (e.g. via instant messaging again), and also share the threshold number that was used. They should then run the following, replacing the name of the group if they wish and the threshold number with the one given by the first participant.
frost-client dkg -d "Alice, Bob and Eve's group" -s localhost:2744 -t 2 -C redpallas
Generating the Full Viewing Key for the wallet
Next, we will need to generate a Zcash Full Viewing Key from the FROST group material we have just generated; this address will then be imported into a wallet so that we'll be able to create Zcash transactions for it.
Run the following command:
frost-client groups
It will list all groups you're in - at this point it should list the only one
you have just created. Copy the Public Key it shows (it will look like e.g.
79d6bcee79c88ad9ba259067772b97f5de12f1435b474d03bc98f255be08a610)
The run the following command, replacing <ak> with the value you copied,
and test with main if you're using Mainnet.
zcash-sign generate --net test --ak <ak>
It will print an Orchard address, and a Unified Full Viewing Key. Copy and paste both somewhere to use them later.
Importing the Full Viewing Key into zcash-devtool
In the zcash-devtool folder, run the following, replacing <UFVK> with the
UFVK printed in the last step:
zcash-devtool wallet -w ./.frost.view/ init-fvk --name FROST_wallet --fvk <UFVK> --birthday 3720000 -s zecrocks
(Change ./.frost-view or FROST_wallet if you want to change the folder or
name of the wallet.)
Funding the wallet
Now you will need to fund this wallet with some ZEC. Send ZEC to that address using another account (or try ZecFaucet).
Creating the transaction
Run the following, replacing <DEST_ADDR> with the address you want to ZEC to,
<VALUE> with the value you want to send in Zatoshis, <MEMO> with the
memo you want to send:
zcash-devtool pczt -w ./.frost.view/ create --address <DEST_ADDR> --value <VALUE> --memo <MEMO> > frost_pczt.created
Signing the transaction
Now you will need to simulate two participants and a Coordinator to sign the transaction, and you should still have the FROST server running which will handle communications between them. It's probably easier to open three new terminals.
Go back to the signer terminal and run the following, replacing <pczt_path>
with the path to the file you saved in the previous step, and <pczt_signed_path>
with the path where you want to write the signed transaction (e.g.
frost_pczt.signed).
zcash-sign sign -n test --tx-plan frost_pczt.created -o frost_pczt.signed
(Replace test with main if you're using Mainnet.)
The program will print a SIGHASH and a Randomizer, and will prompt for a signature. This is what you will get after running FROST, so let's do that; leave the prompt there without typing anything.
Coordinator
In the second terminal, the Coordinator, run (in the same folder where you initialized the users and ran the key generation) the following:
frost-client groups -c alice.toml
This will list the groups Alice is in; it should only list the one you created
earlier. You will need to copy some values in the command. Run the following,
replacing the value after <group> with the "Public key" listed for the group;
replacing <pubkey1> and <pubkey2> with the public keys of Alice and Bob (the
hexadecimal values printed next to their names; Alice's name will be empty to
indicate it's her own).
frost-client coordinator -c alice.toml --server-url localhost:2744 --group <group> -S <pubkey1>,<pubkey2> -m - -r -
It will prompt you for a message. Paste the SIGHASH generated with the
zcash-sign tool and press enter. It will then prompt for a randomizer. Paste
the one generated with the zcash-sign tool and press enter.
The tool will connect to the server and wait for the other participants.
If you prefer to pass the message (SIGHASH) or randomizer as files by using
the -m and -r arguments, you will need to convert them to binary format.
Participant 1 (Alice)
In the third terminal, Participant 1, run the following (replacing <group>
with the same group public key used in the previous command):
frost-client participant -c alice.toml --server-url localhost:2744 --group <group>
(We are using "Alice" again. There's nothing stopping a Coordinator from being a Partcipant too!)
Participant 2 (Bob)
In the fourth terminal, for Participant 2, run the following (replacing <group>
again):
frost-client participant -c bob.toml --server-url localhost:2744 --group <group>
Coordinator
Go back to the Coordinator CLI. The protocol should run and complete successfully. It will print the final FROST-generated signature. Hurrah! Copy it (just the hex value).
Go back to the signer and paste the signature. It will write the signed transaction to the file you specified.
Proving the transaction
You will need to prove the transaction separately:
cargo run -p zcash-sign -- sign -n test --tx-plan frost_pczt.created -o frost_pczt.signed
And then combine signed and proven into a final transaction:
zcash-devtool pczt combine -i frost_pczt.signed -i frost_pczt.proven > frost_pczt.combined
Broadcasting the transaction
Run:
zcash-devtool pczt -w ./.frost.view/ send -s zecrocks < test_pczt.combined