TSM Local Deployment

This page describes how to set up a minimal (3, 1) TSM using docker-compose, which can compute ECDSA signatures and is suitable for local development.

This article describes how to deploy the TSM itself. If you already have a TSM and want to connect to it using a SDK, you can get more information here.

Logging in to Blockdaemon's docker registry

Start by login into Blockdaemon's private docker registry using the credentials you were provided:

docker login nexus.sepior.net:19001

Create TSM configuration

The three MPC nodes will communicate internally on port 9000 using docker-composes built-in DNS server. They will also expose one SDK port per TSM, these will be mapped to 8000, 8001 and 8002 on localhost for testing and development.

Each of the three MPC nodes needs a private/public keypair. To generate this run:

$ openssl ecparam -name P-256 -genkey -param_enc named_curve -outform DER -out private0.key
$ openssl ec -inform DER -in private0.key -pubout -outform DER -out public0.key
$ openssl ecparam -name P-256 -genkey -param_enc named_curve -outform DER -out private1.key
$ openssl ec -inform DER -in private1.key -pubout -outform DER -out public1.key
$ openssl ecparam -name P-256 -genkey -param_enc named_curve -outform DER -out private2.key
$ openssl ec -inform DER -in private2.key -pubout -outform DER -out public2.key

The above requires a fairly new version of OpenSSL, so if you encounter any issues running the commands, please try and update your OpenSSL and try again.

Next, we need to create a configuration file for each of the three TSMs, let's start with config0.toml.

Get node 0's private key in base64:

$ openssl base64 -A -in private0.key; echo

Then get all the nodes' base64 encoded public keys:

openssl base64 -A -in public0.key; echo
openssl base64 -A -in public1.key; echo
openssl base64 -A -in public2.key; echo

We are now ready to create config0.toml by putting in the generated values in the following template. Under [Player] replace <node ID> in Index with 0. Also, replace <private key> in PrivateKey with the output from above. Under [Player.N] where N is 0..2 replace <nodeN public key> in PublicKey with the output from above. Replace <SDK port> in Port under [SDKServer] with 8000 and <MPC port> under [MPCTCPServer] with 9000.

# General configuration for MPC operations.
[MPC]
  # This is the security threshold for the TSM. It means that the TSM is secure as long as at most threshold number of
  # players are corrupt. Must be greater than 0 and less than the total number of players. Some MPC protocols have
  # restrictions on what the threshold can be.
  Threshold = 1

# Configuration for the local player
[Player]
  # All players in a TSM are identified by a player index. This is the index of the player running this TSM node.
  # We refer to this player as the local player. Other players are called remote players.
  Index = <node ID>
  # This is a base64 encoding of the private key used to authenticate the local player towards the remote players. This
  # must correspond to the public keys configured on the remote players for this player index. A private key can be
  # generated using the following OpenSSL commands:
  PrivateKey = "<private key>"

# The following is a list of remote players in the TSM.
#
# The logic is that lower numbered players open connections to higher numbered players, so URLs are not needed for players
# with a lower number than the local player.
[Players.0]
  # The protocol and address of player with index 0. Supported protocols are tcp, ws and wss. If no protocol is
  # specified then tcp is assumed.
  Address = "tcp://node0:9000"
  # This is a base64 encoding of the players public key.
  PublicKey = "<node0 public key>"

[Players.1]
  Address = "tcp://node1:9001"
  PublicKey = "<node1 public key>"

[Players.2]
  Address = "tcp://node2:9002"
  PublicKey = "<node2 public key>"

# Database connection configuration.
[Database]
  # The driver used for the database. The following database drivers are supported: sqlite3, mysql and postgres.
  DriverName = "sqlite3"
  DataSourceName = "/tmp/tsmdb"
  # This specifies a master encryption key used to protect database records. Note that this key is not directly
  # used to encrypt data. Use any long random string here and make sure to keep a backup of it somewhere safe.
  EncryptorMasterPassword = "ENCRYPTION_KEY"

# MPC server accepting multiplexed TCP connections from other players.
# At least one MPC server must be specified if the player index is greater than 0.
[MPCTCPServer]
  # Port number that this server listens on.
  Port = <MPC port>

# Server accepting connections from the SDK. This must be specified unless the TSM node is running as a local node.
[SDKServer]
  # Port number that this server listens on.
  Port = <SDK port>

# Configures system logging for the TSM node.
#[Logging]
  # Log level. If not specified it default to "info".
  #Level = ""

# Computes ECDSA signatures. This protocol requires n >= 2t+1. Cannot be enabled together with DKLS18 or DKLS19.
[SEPH18S]

The above should be repeated for config1.toml and config2.toml using the appropriate values. Do not forget to use the correct SDK ports and MPC ports for each.

Note that in production SDK port needs to be different, this is done here because we need all of them bound to localhost.
Note, EncryptorMasterPassword should be different per node in a production deployment.

Starting the TSM

To start the TSM with docker-compose create a file docker-compose.yml with the following contents:

version: "3.8"
services:
  node0:
    image: nexus.sepior.net:19001/tsm-node:latest
    ports:
      - "8000:8000"
    networks:
      - tsm
    environment:
      - CONFIG_FILE=/config/config0.toml
    volumes:
      - ./config0.toml:/config/config0.toml
  node1:
    image: nexus.sepior.net:19001/tsm-node:latest
    ports:
      - "8001:8001"
    networks:
      - tsm
    environment:
      - CONFIG_FILE=/config/config1.toml
    volumes:
      - ./config1.toml:/config/config1.toml
  node2:
    image: nexus.sepior.net:19001/tsm-node:latest
    ports:
      - "8002:8002"
    networks:
      - tsm
    environment:
      - CONFIG_FILE=/config/config2.toml
    volumes:
      - ./config2.toml:/config/config2.toml
networks:
  tsm:

Execute docker-compose up from the same directory where you save docker-compose.yml. A TSM should now be reachable for the SDK on ports 8000, 8001 and 8002 on localhost.

Advanced configuration

See Example TSM configuration file for further configuration hints.