This tutorial has been tested on Linux and Mac OS. If you use another OS, some steps may be a bit different.

# Prerequisites

- Go version 1.22
- URLs and API keys for the MPC nodes in a running instance of the Builder Vault TSM. You can follow one of the tutorials [Local Deployment](https://builder-vault-tsm.docs.blockdaemon.com/docs/getting-started-local-deployment), [Hosted Sandbox](https://builder-vault-tsm.docs.blockdaemon.com/docs/getting-started-hosted-sandbox), or [AWS Marketplace](https://builder-vault-tsm.docs.blockdaemon.com/docs/getting-started-aws) to get access to a Builder Vault TSM.

# Step 1: Create a Go Project and Fetch the Builder Vault SDK

In the following steps we will create a small Go project that uses the Builder Vault Go SDK:

- Create a new folder for your project on your local machine
- Open a terminal window and go to the project folder.
- Initialize the Go module by executing the following command in the project folder (you can replace `example.com` with the desired module path for your project):

```shell
go mod init example.com
```

- Check out the latest version of the SDK, by using the following command:

```shell
go get gitlab.com/Blockdaemon/go-tsm-sdkv2/v73
```

> 📘
>
> ### Builder Vault Version
>
> When you connect to an MPC node with the SDK, it is important that the version of the SDK matches the version of the MPC node. If the MPC node has the URL `https://mpc.node.net`, you can see which version the node runs with this Linux command:
>
> `curl https://mpc.node.net/version`
>
> If the returned version is for example `70.2.4`, you can fetch the corresponding version of the SDK with this:
>
> `go get gitlab.com/Blockdaemon/go-tsm-sdkv2/v70@v70.2.4`
>
> For the full list of SDK versions, please see [here](https://builder-vault-tsm.docs.blockdaemon.com/changelog).

Once fetched, you can import the SDK in your code like this:

```go
import (
    "gitlab.com/Blockdaemon/go-tsm-sdkv2/v73/tsm"
    "gitlab.com/Blockdaemon/go-tsm-sdkv2/v73/tsm/tsmutils"
)
```

# Step 2: Use the SDK to Generate a Key and Sign

In the next steps we will create a small Go program that (1) generates an ECDSA key in the TSM; (2) prints the public ECDSA key; and (3) signs a message using the newly generated key.

- Create a file `main.go` in the project folder, with the following contents. Don't worry about the details for now.

```go
package main

import (
	"bytes"
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"gitlab.com/Blockdaemon/go-tsm-sdkv2/v73/tsm"
	"golang.org/x/sync/errgroup"
	"sync"
)

func main() {

// Create clients for each of the nodes

configs := []*tsm.Configuration{
		tsm.Configuration{URL: "http://localhost:8500"}.WithAPIKeyAuthentication("apikey0"),
		tsm.Configuration{URL: "http://localhost:8501"}.WithAPIKeyAuthentication("apikey1"),
		tsm.Configuration{URL: "http://localhost:8502"}.WithAPIKeyAuthentication("apikey2"),
	}

clients := make([]*tsm.Client, len(configs))
	for i, config := range configs {
		var err error
		if clients[i], err = tsm.NewClient(config); err != nil {
			panic(err)
		}
	}

// Generate an ECDSA key

threshold := 1                  // The security threshold for this key
	keyGenPlayers := []int{0, 1, 2} // The key should be secret shared among all three MPC nodes
	keyGenSessionConfig := tsm.NewSessionConfig(tsm.GenerateSessionID(), keyGenPlayers, nil)

fmt.Println("Generating key using players", keyGenPlayers)
	ctx := context.Background()
	keyIDs := make([]string, len(clients))
	var eg errgroup.Group
	for i, client := range clients {
		client, i := client, i
		eg.Go(func() error {
			var err error
			keyIDs[i], err = client.ECDSA().GenerateKey(ctx, keyGenSessionConfig, threshold, "secp256k1", "")
			return err
		})
	}

if err := eg.Wait(); err != nil {
		panic(err)
	}

// Validate key IDs

for i := 1; i < len(keyIDs); i++ {
		if keyIDs[0] != keyIDs[i] {
			panic("key IDs do not match")
		}
	}
	keyID := keyIDs[0]
	fmt.Println("Generated key with ID:", keyID)

// Get the public key

var derivationPath []uint32 = nil // We don't use key derivation in this example

publicKeys := make([][]byte, len(clients))
	for i, client := range clients {
		var err error
		publicKeys[i], err = client.ECDSA().PublicKey(ctx, keyID, derivationPath)
		if err != nil {
			panic(err)
		}
	}

// Validate public keys

for i := 1; i < len(publicKeys); i++ {
		if !bytes.Equal(publicKeys[0], publicKeys[i]) {
			panic("public keys do not match")
		}
	}
	publicKey := publicKeys[0]
	fmt.Println("Public key:", hex.EncodeToString(publicKey))

// We can now sign with the created key

message := []byte("This is a message to be signed")
	msgHash := sha256.Sum256(message)

signPlayers := []int{0, 1} // We want to sign with the first two MPC nodes
	sessionID := tsm.GenerateSessionID()
	signSessionConfig := tsm.NewSessionConfig(sessionID, signPlayers, nil)

fmt.Println("Creating signature using players", signPlayers)
	partialSignaturesLock := sync.Mutex{}
	var partialSignatures [][]byte
	for _, player := range signPlayers {
		player := player
		eg.Go(func() error {
			if partialSignResult, err := clients[player].ECDSA().Sign(ctx, signSessionConfig, keyID, derivationPath, msgHash[:]); err != nil {
				return err
			} else {
				partialSignaturesLock.Lock()
				partialSignatures = append(partialSignatures, partialSignResult.PartialSignature)
				partialSignaturesLock.Unlock()
				return nil
			}
		})
	}

if err := eg.Wait(); err != nil {
		panic(err)
	}

signature, err := tsm.ECDSAFinalizeSignature(msgHash[:], partialSignatures)
	if err != nil {
		panic(err)
	}

// Verify the signature relative to the signed message and the public key

if err = tsm.ECDSAVerifySignature(publicKey, msgHash[:], signature.ASN1()); err != nil {
		panic(err)
	}

fmt.Println("Signature:", hex.EncodeToString(signature.ASN1()))
}
```

- Replace the API keys for the MPC nodes in line 19-21 above with the actual API keys for your Builder Vault instance.
- Execute the following commands in the project folder:

```shell
go mod tidy
go run main.go
```

You should now see some output similar to this:

```undefined
Generating key using players [0 1 2]
Generated key with ID: ymdAAttlPmCqKp0vLgz7re4k87As
Public key: 3056301006072a8648ce3d020106052b8104000a03420004a50fbc4dbb0fb9157b26408fc3dbab1b42081668fc0212e1edd97bbd6906a3ee7b3fe69323e401b2b4117edff329879adc1f82e4ef6a1f0f89f084a59665df9f
Creating signature using players [0 1]
Signature: 304402204c33273dec7dac0ff510a1f98036ce62987da8174bb4d4a8456686732096449a022063ef69e1be58275c2cb341b0dcd17d586a28fe647453397d5c9cd5243577df63
```

This means that you have successfully used the Builder Vault SDK to connect to the Builder Vault, where you generated a new ECDSA key and used it for signing.

If you get error messages instead, you can consult our [troubleshooting guide](https://builder-vault-tsm.docs.blockdaemon.com/docs/troubleshooting) or contact our support team.
