Local Deployment
In this tutorial you will set up a TSM on your local machine. The TSM will contain three MPC nodes, and each MPC node will connect to its own database server. The MPC nodes as well as the database servers will run in adjacent Docker containers on your machine.
The tutorial has been tested on Linux and Mac OS. If you use a different OS, you may need to do things slightly different.
Prerequisites
- Docker on your local machine
- Credentials for https://nexus.sepior.net. You can get these from our support team. We will use NEXUS_USERNAME and NEXUS_PASSWORD in the following, but remember to replace these with the credentials received from our support team.
Configuring the TSM
Configure the TSM with the following steps:
- Create a new project folder on your local machine and open a terminal window in the folder.
- Create a file
docker-compose.yml
in the folder, with the following content:
services:
tsm_node_0:
image: nexus.sepior.net:19001/tsm-node:65.0.0
container_name: tsm-node-0
ports:
- "8500:8000"
networks:
- example-tsm
environment:
- WAIT_HOST=db0:5432
- CONFIG_FILE=/config/config.toml
volumes:
- ./config0.toml:/config/config.toml
tsm_node_1:
image: nexus.sepior.net:19001/tsm-node:65.0.0
container_name: tsm-node-1
ports:
- "8501:8000"
networks:
- example-tsm
environment:
- WAIT_HOST=db1:3306
- CONFIG_FILE=/config/config.toml
volumes:
- ./config1.toml:/config/config.toml
tsm_node_2:
image: nexus.sepior.net:19001/tsm-node:65.0.0
container_name: tsm-node-2
ports:
- "8502:8000"
networks:
- example-tsm
environment:
- WAIT_HOST=db2:5432
- CONFIG_FILE=/config/config.toml
volumes:
- ./config2.toml:/config/config.toml
db0:
image: postgres:15.4-alpine
container_name: db0
networks:
- example-tsm
environment:
- POSTGRES_DB=db0
- POSTGRES_USER=db0user
- POSTGRES_PASSWORD=db0password
restart: always
db1:
container_name: db1
image: mariadb:10.8.2
networks:
- example-tsm
environment:
MARIADB_DATABASE: db1
MARIADB_USER: db1user
MARIADB_PASSWORD: db1password
MARIADB_RANDOM_ROOT_PASSWORD: 1
command:
mysqld --max_connections=1500
db2:
image: postgres:15.2-alpine
container_name: db2
networks:
- example-tsm
environment:
- POSTGRES_DB=db2
- POSTGRES_USER=db2user
- POSTGRES_PASSWORD=db2password
restart: always
networks:
example-tsm:
- Create three files
config0.toml
,config1.toml
, andconfig2.toml
in the project folder. Make sure that the files have the following contents:
[Player]
Index = 0
PrivateKey = "MHcCAQEEIJZ2T0ESxG34wA77rhn+9KMOrkz296jeDUOenHsLmWO/oAoGCCqGSM49AwEHoUQDQgAE0AyIB0e0A00Z+ovqDQ5mjffEqVabU/eEOwOOrkElnSX1qPkgIn5eLIOC7OWQq6dgZnJLjElg6R4vR5a91aAE8w=="
ExportWhiteList = ["*"] # Allow any wrapping key when exporting; only do this in tests
[Players.0]
Address = "tcp://tsm_node_0:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0AyIB0e0A00Z+ovqDQ5mjffEqVabU/eEOwOOrkElnSX1qPkgIn5eLIOC7OWQq6dgZnJLjElg6R4vR5a91aAE8w=="
[Players.1]
Address = "tcp://tsm_node_1:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZsbGXaVTkx8iiXb7iDSBFs24xYdbe5jTRg57aU0F71BMxhlV46cKMsCDXARriCUBwApfCoAf/ByyJ7TpWRm4Rw=="
[Players.2]
Address = "tcp://tsm_node_2:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJZx6N1ARYmc/6DQBL/47yRL/dMvWi5UQRUiqA05pdjLAb3eXO6yPioocnZNxsQjCerxcMJ2LnvELmK5L6Ovsqw=="
[Database]
DriverName = "postgres"
DataSourceName = "postgres://db0user:db0password@db0:5432/db0?sslmode=disable"
EncryptorMasterPassword = "db0masterPassword"
[MPCTCPServer]
Port = 9000
[SDKServer]
Port = 8000
[[Authentication.APIKeys]]
APIKey = "IntV2sEZRwwd2F+UkDLC7zmFhwvpxAwb0eQKwdEnSZU=" # apikey0
ApplicationID = "demoapp"
[DKLS19.Features]
GenerateKey = true
GeneratePresignatures = true
Sign = true
SignWithPresignature = true
GenerateRecoveryData = true
PublicKey = true
ChainCode = true
Reshare = true
CopyKey = true
BackupKeyShare = true
RestoreKeyShare = true
ExportKeyShares = true
ImportKeyShares = true
BIP32GenerateSeed = true
BIP32DeriveFromSeed = true
BIP32DeriveFromKey = true
BIP32ConvertKey = true
BIP32ExportSeed = true
BIP32ImportSeed = true
BIP32Info = true
[SEPD19S.Features]
GenerateKey = true
GeneratePresignatures = true
Sign = true
SignWithPresignature = true
GenerateRecoveryData = true
PublicKey = true
ChainCode = true
Reshare = true
CopyKey = true
BackupKeyShare = true
RestoreKeyShare = true
ExportKeyShares = true
ImportKeyShares = true
[ADN06.Features]
PublicKey = true
SignPKCS1v15 = true
SignPSS = true
Decrypt = true
ExportKeyShares = true
ImportKeyShares = true
[MRZ15.AESFeatures]
GenerateKey = true
ExportKeyShares = true
ImportKeyShares = true
CTRKeyStream = true
CBCEncrypt = true
CBCDecrypt = true
GCMEncrypt = true
GCMDecrypt = true
CMAC = true
[MRZ15.HMACFeatures]
GenerateKey = true
ExportKeyShares = true
ImportKeyShares = true
HMACSHA256 = true
HMACSHA512 = true
[Player]
Index = 1
PrivateKey = "MHcCAQEEILWaOgXLxJUxodTrASskOfTN0y8RD/vuwuv/bOM+f2wroAoGCCqGSM49AwEHoUQDQgAEZsbGXaVTkx8iiXb7iDSBFs24xYdbe5jTRg57aU0F71BMxhlV46cKMsCDXARriCUBwApfCoAf/ByyJ7TpWRm4Rw=="
ExportWhiteList = ["*"] # Allow any wrapping key when exporting; only do this in tests
[Players.0]
Address = "tcp://tsm_node_0:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0AyIB0e0A00Z+ovqDQ5mjffEqVabU/eEOwOOrkElnSX1qPkgIn5eLIOC7OWQq6dgZnJLjElg6R4vR5a91aAE8w=="
[Players.1]
Address = "tcp://tsm_node_1:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZsbGXaVTkx8iiXb7iDSBFs24xYdbe5jTRg57aU0F71BMxhlV46cKMsCDXARriCUBwApfCoAf/ByyJ7TpWRm4Rw=="
[Players.2]
Address = "tcp://tsm_node_2:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJZx6N1ARYmc/6DQBL/47yRL/dMvWi5UQRUiqA05pdjLAb3eXO6yPioocnZNxsQjCerxcMJ2LnvELmK5L6Ovsqw=="
[Database]
DriverName = "mysql"
DataSourceName = "db1user:db1password@tcp(db1:3306)/db1?parseTime=true"
EncryptorMasterPassword = "db1masterPassword"
MaxIdleConns = 500
MaxOpenConns = 500
[MPCTCPServer]
Port = 9000
[SDKServer]
Port = 8000
[[Authentication.APIKeys]]
APIKey = "1PebMT+BBvWvEIrZb/UWIi2/1aCrUvQwjksa0ddA3mA=" # apikey1
ApplicationID = "demoapp"
[DKLS19.Features]
GenerateKey = true
GeneratePresignatures = true
Sign = true
SignWithPresignature = true
GenerateRecoveryData = true
PublicKey = true
ChainCode = true
Reshare = true
CopyKey = true
BackupKeyShare = true
RestoreKeyShare = true
ExportKeyShares = true
ImportKeyShares = true
BIP32GenerateSeed = true
BIP32DeriveFromSeed = true
BIP32DeriveFromKey = true
BIP32ConvertKey = true
BIP32ExportSeed = true
BIP32ImportSeed = true
BIP32Info = true
[SEPD19S.Features]
GenerateKey = true
GeneratePresignatures = true
Sign = true
SignWithPresignature = true
GenerateRecoveryData = true
PublicKey = true
ChainCode = true
Reshare = true
CopyKey = true
BackupKeyShare = true
RestoreKeyShare = true
ExportKeyShares = true
ImportKeyShares = true
[ADN06.Features]
PublicKey = true
SignPKCS1v15 = true
SignPSS = true
Decrypt = true
ExportKeyShares = true
ImportKeyShares = true
[MRZ15.AESFeatures]
GenerateKey = true
ExportKeyShares = true
ImportKeyShares = true
CTRKeyStream = true
CBCEncrypt = true
CBCDecrypt = true
GCMEncrypt = true
GCMDecrypt = true
CMAC = true
[MRZ15.HMACFeatures]
GenerateKey = true
ExportKeyShares = true
ImportKeyShares = true
HMACSHA256 = true
HMACSHA512 = true
[Player]
Index = 2
PrivateKey = "MHcCAQEEIHGb0I8CEE6db7/buOQiX8SgnbkkAI5aX9mowvCpUjOJoAoGCCqGSM49AwEHoUQDQgAEJZx6N1ARYmc/6DQBL/47yRL/dMvWi5UQRUiqA05pdjLAb3eXO6yPioocnZNxsQjCerxcMJ2LnvELmK5L6Ovsqw=="
ExportWhiteList = ["*"] # Allow any wrapping key when exporting; only do this in tests
[Players.0]
Address = "tcp://tsm_node_0:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0AyIB0e0A00Z+ovqDQ5mjffEqVabU/eEOwOOrkElnSX1qPkgIn5eLIOC7OWQq6dgZnJLjElg6R4vR5a91aAE8w=="
[Players.1]
Address = "tcp://tsm_node_1:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZsbGXaVTkx8iiXb7iDSBFs24xYdbe5jTRg57aU0F71BMxhlV46cKMsCDXARriCUBwApfCoAf/ByyJ7TpWRm4Rw=="
[Players.2]
Address = "tcp://tsm_node_2:9000"
PublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJZx6N1ARYmc/6DQBL/47yRL/dMvWi5UQRUiqA05pdjLAb3eXO6yPioocnZNxsQjCerxcMJ2LnvELmK5L6Ovsqw=="
[Database]
DriverName = "postgres"
DataSourceName = "postgres://db2user:db2password@db2:5432/db2?sslmode=disable"
EncryptorMasterPassword = "db2masterPassword"
[MPCTCPServer]
Port = 9000
[SDKServer]
Port = 8000
[[Authentication.APIKeys]]
APIKey = "FfrI+hyZAiVosAi53wewS0U1SsXKR0AEHZBM088rOeM=" # apikey2
ApplicationID = "demoapp"
[DKLS19.Features]
GenerateKey = true
GeneratePresignatures = true
Sign = true
SignWithPresignature = true
GenerateRecoveryData = true
PublicKey = true
ChainCode = true
Reshare = true
CopyKey = true
BackupKeyShare = true
RestoreKeyShare = true
ExportKeyShares = true
ImportKeyShares = true
BIP32GenerateSeed = true
BIP32DeriveFromSeed = true
BIP32DeriveFromKey = true
BIP32ConvertKey = true
BIP32ExportSeed = true
BIP32ImportSeed = true
BIP32Info = true
[SEPD19S.Features]
GenerateKey = true
GeneratePresignatures = true
Sign = true
SignWithPresignature = true
GenerateRecoveryData = true
PublicKey = true
ChainCode = true
Reshare = true
CopyKey = true
BackupKeyShare = true
RestoreKeyShare = true
ExportKeyShares = true
ImportKeyShares = true
[ADN06.Features]
PublicKey = true
SignPKCS1v15 = true
SignPSS = true
Decrypt = true
ExportKeyShares = true
ImportKeyShares = true
[MRZ15.AESFeatures]
GenerateKey = true
ExportKeyShares = true
ImportKeyShares = true
CTRKeyStream = true
CBCEncrypt = true
CBCDecrypt = true
GCMEncrypt = true
GCMDecrypt = true
CMAC = true
[MRZ15.HMACFeatures]
GenerateKey = true
ExportKeyShares = true
ImportKeyShares = true
HMACSHA256 = true
HMACSHA512 = true
Note
The files above contain a number of private keys and passwords. Make sure that you replace these with your own keys and strong passwords if you at any point use the TSM in production.
The files contain many details that are not explained in this Getting Started tutorial. The details on how to configure and run a TSM are explained in the section TSM Management.
Note also that all protocol features are enabled here. In production you probably only want to enable the features that are actually used.
Starting the TSM
With the above files all placed in your project folder, you can start the TSM with the following steps.
- Docker will fetch the MPC node images from https://nexus.sepior.net:19001. So first, we must log into that image repository with the following command:
docker login -u NEXUS_USERNAME -p NEXUS_PASSWORD nexus.sepior.net:19001
Remember to replace NEXUS_USERNANE and NEXUS_PASSWORD with the credentials provided by our support team.
- The TSM can now be started in the background by executing this command:
docker compose up -d
You should now have a local TSM running on your machine.
To check that everything went well you can execute the following command, that contacts each of the MPC nodes on an unauthenticated endpoint /ping
:
curl http://localhost:8500/ping http://localhost:8501/ping http://localhost:8502/ping
This should result in the output PongPongPong
.
You can also inspect the log messages generated by an MPC node, say tsm-node-1, as follows:
docker compose logs tsm_node_1
If you have trouble running the TSM, you may want to take a look at our troubleshooting guide, or you can contact our support team.
Using the TSM
Once the TSM is up and running, the next step is to connect to the TSM using one of the available SDKs. To do this, you can follow any of the tutorials in the Builder Vault SDK Quick Start section. In our case, you have just started a Builder Vault instance on your local machine, so you should use these URLs and API keys when connecting to the Builder Vault:
MPC Node | URL | |
---|---|---|
MPC Node 0 | http://localhost:8500 | apikey0 |
MPC Node 1 | http://localhost:8501 | apikey1 |
MPC Node 2 | http://localhost:8502 | apikey2 |
Updated 28 days ago