Hierarchical Threshold Signature demonstration

This article is an example explanation of the open source project Alice (HTSS library from AMIS).

Introduction

In the previous article, we introduced the basic concept of HTSS. We know that the emergence of TSS is to deal with private key management. First, we could lower the risk of assets being transferred maliciously because the control of the assets is not belonged to one single entity (avoid single-point-of-failure). Second, with M-of-N scheme, we could prevent loss of the assets even if some of shares are missing (increase fault tolerance).

Compared with multi-signature, TSS offers shorter signature and better privacy. Also, it does not save private key on the server and provides risk control as well as separation of duties. However, there is still room for improvement. HTSS introduced the different level of each share, which makes the application could be much closer to the real life scene and this property doesn’t exist in TSS.

In this article, we will explain thoroughly about the example of Alice, an implementation of HTSS library worked by us. We will first illustrate the simplification of our example flow. Second, we will highlight the takeaway when running the example. Then, we will dive into the detail of 3 main commands of our TSS library. Last, we will conclude the demonstration.


Simplification

Image for post
roles of TSS

We imagine that the roles in TSS will be composed of two parts: an initiator and a group of share servers.

  1. initiator: The one who will initiate a TSS process. It could be one of the share servers or it could be a third-party entity.
  2. share servers: Servers that actually participate in TSS process.

For example, an initiator might want some share servers to sign a message for it. First it will create a message and send it to specific share servers. Then it will initiate the signing process by telling these share servers they could start the process.

However, in our example, we simplify the process of this flow. We discard the role of initiator. Each participant will consume a config file and that file will contain the required information to start a TSS process. Therefore, we don’t need the role of initiator to give orders.


Highlights

We leverage go-libp2p library to deal with the network connection in this example. To be noted, the communication in this example is not encrypted and the host ID of one peer is associated with its port, which means it’s not random. If you want to adopt this example to your production implementation, please be sure to adjust these configurations.

According to the previous article, TSS contains four phases which are Key Generation, Sign a transaction, Verification, and Refresh share. In Alice, corresponding to the four phases TSS have, we have three main functions which are dkg (key generation), signer (sign a transaction), and reshare (refresh share). Verification could be achieved by using standard library of programming language. Take GoLang for example:

import crypto/ecdsa...
ecdsa.Verify(publicKey, msg, r, s)
...

Configuration

All three commands in the example should have their own configuration. These config files are YAML format and they should contain the required input that commands need. Also, all three commands will create their own results after successful executions. These result files are YAML format as well.

The input and output files of each command will be put at the same folder. And the naming rule is similar. For example, if a node is listening for port 10000 and it tries to start a dkg process, it will need to consume the input file dkg/id-10000-input.yaml and it will generate an output file dkg/id-10000-output.yaml if the process went well. If the required input file doesn’t exist, the execution will fail.

By default, all config files already exist and have contained executable configurations. You don’t need to adjust anything to run the example.

Image for post
the location and the naming rule of each input / output file

Execution

In this example, we try to simulate the real situation of TSS algorithm. You will need to open different terminals and run TSS program on each terminal. After each process is executed, a node will be started and it will be blocked until it connects to all the peers. Therefore, you will see the following warnings when a new process started.

WARN [04-15|11:07:07.592|peer/node.go:141] Failed to connect to peer                err="..."
WARN [04-15|11:07:07.592|peer/pm.go:89] Failed to connect to peer to=... err="..."
WARN [04-15|11:07:07.592|peer/node.go:141] Failed to connect to peer err="..."
WARN [04-15|11:07:07.592|peer/pm.go:89] Failed to connect to peer to=... err="..."

These warnings are normal since it requires all peers connected before the algorithm execution. By default setting in the example, you will need to run three processes on three different terminals. After all three nodes are started and they are connected with each other, you will see the following debug messages and the process will continue.

DEBUG[04-15|11:07:13.600|peer/pm.go:93]    Successfully connect to peer             to=...
DEBUG[04-15|11:07:16.602|peer/pm.go:93] Successfully connect to peer to=...

Usage

At project root directory, you could use the following command to build an executable binary in example/ folder.

> make tss-example
> cd example

DKG (Distributed Key Generation)

When running a dkg process in the example, there are four parameters you need to provide: port, rank, threshold, peers.

  • port: Port that this node will listen for.
  • rank: The rank of this node during HTSS algorithm. The smaller the rank means the higher the level of the node’s share.
  • threshold: Threshold that how many participants needed to generate a valid signature.
  • peers: A list of peer’s ports that this node will try to connect.

A complete dkg configuration is show below.

port: 10001
rank: 0
threshold: 3
peers:
- 10002
- 10003

Then, run three hosts on different terminals. Each node will need to consume a config file (e.g dkg/id-10001-input.yaml) by using --config or -c to specify the path of the config file. These three nodes will try to connect to each other. Once it connects to a peer, it will send the peer message out. The peer message is the input of the first step of key generation in HTSS. After the messages are fully transmitted, each node will start the process respectively. When the process is done, the result will be recorded as a file and put in dkg/ folder.

On node A,

> ./example dkg --config dkg/id-10001-input.yaml

On node B,

> ./example dkg --config dkg/id-10002-input.yaml

On node C,

> ./example dkg --config dkg/id-10003-input.yaml

Signer

When running a signer process in the example, there are six parameters you need to provide: port, peers, share, public key, Birkhoff parameters, and message. The port and peers are the same with the ones in dkg.

  • share: The respective share generated from dkg.
  • public key: The public key generated from dkg.
  • Birkhoff parameters: The Birkhoff parameter of all peers. Birkhoff interpolation is the problem of finding a polynomial f of degree t such that certain derivatives have specified values at specified points. A pair (derivative, x-coordinate) is called a Birkhoff parameter.
  • message: Message to be signed. The value of message for all participants must be the same. If the value of message is different, signing process will fail. Most of the time, this message will be a cryptographic transaction. And the transaction might be created from one party. Therefore, practically, before signing, another information exchange for the message might be required.

A complete signer configuration is show below.

port: 10001
peers:
- 10002
- 10003
share: "101420976052030730685561069719911392914434824397492564228646546319061446487458"
pubkey:
x: "47143094896967716337843669989860432144962851204356940818421228324575441222601"
y: "23336444423741848139737884993242101588835841992098573257496438799812162311375"
bks:
id-10001:
x: "60804574656888231803750758362258552766945294870709728961250573287297336332061"
rank: 0
id-10002:
x: "69585139089653513675598669644888535871994689088749672680139122876344694547847"
rank: 0
id-10003:
x: "42617894318064911861435689891609248836936982258022075394462053252726961520252"
rank: 0
msg: "hello tss"

Then, run three hosts on different terminals. Each node will need to consume a config file (e.g signer/id-10001-input.yaml) by using --config or -c to specify the path of the config file. These three nodes will try to connect to each other. Once it connects to a peer, it will send the public key message out. The public key message is the input of the first step of signing in HTSS. After the messages are fully transmitted, each node will start the process respectively. When the process is done, the result will be recorded as a file and put in signer/ folder.

On node A,

> ./example signer --config signer/id-10001-input.yaml

On node B,

> ./example signer --config signer/id-10002-input.yaml

On node C,

> ./example signer --config signer/id-10003-input.yaml

As we said before, all signer config files have already contained executable configurations. However, you could also try to copy the results from dkg/reshare result files and overwrite the configurations (e.g from dkg/id-10001-output.yaml to signer/id-10001-input.yaml). This should work as well.

Reshare (Refresh share)

When running a reshare process in the example, there are six parameters you need to provide: port, peers, threshold, share, public key, and Birkhoff parameters. All the parameters have appeared before.

A complete reshare configuration is show below.

port: 10001
threshold: 3
peers:
- 10002
- 10003
share: "101420976052030730685561069719911392914434824397492564228646546319061446487458"
pubkey:
x: "47143094896967716337843669989860432144962851204356940818421228324575441222601"
y: "23336444423741848139737884993242101588835841992098573257496438799812162311375"
bks:
id-10001:
x: "60804574656888231803750758362258552766945294870709728961250573287297336332061"
rank: 0
id-10002:
x: "69585139089653513675598669644888535871994689088749672680139122876344694547847"
rank: 0
id-10003:
x: "42617894318064911861435689891609248836936982258022075394462053252726961520252"
rank: 0

When refreshing share, all share servers must be involved. Again, each node will need to consume their own config file (e.g reshare/id-10001-input.yaml) by using --config or -c to specify the path of the config file. Once it connects to a peer, it will send the commit message out. The commit message is the input of the first step of refresh share in HTSS. After the messages are fully transmitted, each node will start the process respectively. When the process is done, the result will be recorded as a file and put in reshare/ folder.

On node A,

> ./example reshare --config reshare/id-10001-input.yaml

On node B,

> ./example reshare --config reshare/id-10002-input.yaml

On node C,

> ./example reshare --config reshare/id-10003-input.yaml

Again, all reshare config files have already contained executable configurations. However, you could also try to copy the results from dkg/reshare result files and overwrite the configurations (e.g from dkg/id-10001-output.yaml to reshare/id-10001-input.yaml). This should work as well.


Conclusion

In conclusion, this example demonstrates a simple implementation of HTSS library. However, you should be aware that this example is NOT production ready. Be careful when you use it in the real environment.

getamis/alice

This is Hierarchical Threshold Signature Scheme (HTSS) worked by AMIS. Comparing to Threshold Signature Scheme (TSS)…

github.com

The above link is the complete implementation of Alice (include the example we discussed in this article). Feel free to open an issue if you have any question and creating a pull request is very welcome! Hope this article is helpful and educational.

Cheers!!

Thanks to Zih-Ci Lin.

本文由 AMIS 徐粲邦 提供

原文連結

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料