Node.js SDK

This article will guide you through the process of connecting the TSM Node SDK V1 by using Node.js in just four straightforward steps. Before proceeding with these steps, please ensure that you have completed the prerequisites outlined below:

Prerequisites

  • Make sure that you are using either Linux or Mac OS to install SDK
  • Install Node.js version 16 and up
  • Contact our support team to get:

1. SDK Initialization

To obtain the SDK, follow the steps below:

  1. Create a new folder for your project.
  2. Open a terminal on your local machine.
  3. Initiate a new Node.js project with default values by using the following command:
npm init -y
  1. Add your sepior credentials to ~/.npmrc by using the following commands:
npm config set @sepior:registry=https://nexus.sepior.net/repository/sepior-nodejs-tsm-sdk-group/
npm config set //nexus.sepior.net/repository/sepior-nodejs-tsm-sdk-group/:username=YOURUSERNAME
npm config set //nexus.sepior.net/repository/sepior-nodejs-tsm-sdk-group/:_password=`echo -n 'YOURPASSWORD' | base64`
npm config set //nexus.sepior.net/repository/sepior-nodejs-tsm-sdk-group/:email=YOURMAILADDRESS

📘

Note:

  • Using backticks (`) in the provided command is important because they ensure that the command is executed before the assignment takes place.
  • Replace YOURUSERNAME, YOURPASSWORDANDYOURMAILADDRESS with your Nexus credentials.
  1. After setting the credentials, install the TSM SDK by using the following command:
npm install @sepior/tsm

2. Run TSM

In this scenario, we run with three MPC nodes and a separate SDK for each of the nodes. The SDKs must be called concurrently and they each obtain a partial signature from its MPC node. The partial signatures must then be combined into the final signature. Follow the steps below to initiate TSM:

📘

Note:

This example shows the use of deterministic key derivation.

  1. Create a new Node.js file called key_derivation.js in your project folder, then use the code provided below:
const { TSMClient, algorithms, curves } = require('@sepior/tsm');
const crypto = require("crypto");

let example = async function() {

    // Initialize a separate SDK for each MPC node in the TSM
    // Remember to change player count and threshold to match you configuration
    let playerCount = 3;
    let threshold = 1;
    let tsmClient0 = await TSMClient.init(playerCount, threshold, [
        {
            url: 'http://tsm-node-0',
            userID: 'user',
            password: 'password0'
        }]);

    let tsmClient1 = await TSMClient.init(playerCount, threshold, [
        {
            url: 'http://tsm-node-1',
            userID: 'user',
            password: 'password1'
        }]);


    let tsmClient2 = await TSMClient.init(playerCount, threshold, [
        {
            url: 'http://tsm-node-2',
            userID: 'user',
            password: 'password2'
        }]);


    // Step 1: Generate a key in the TSM

    // The three SDKs need to first agree on a unique session ID.
    let sessionID = "session1";

    // Each SDK must call keygenWithSessionID with the session ID.
    let results = await Promise.all([
        tsmClient0.keygenWithSessionID(algorithms.ECDSA, sessionID, curves.SECP256K1),
        tsmClient1.keygenWithSessionID(algorithms.ECDSA, sessionID, curves.SECP256K1),
        tsmClient2.keygenWithSessionID(algorithms.ECDSA, sessionID, curves.SECP256K1)]);

    // As a result of the interactive protocol, each SDK receives the key ID.
    // Since some of the MPC nodes may be corrupt, it's best to check that they return the
    // same key ID.
    if (results[0] === results[1] && results[1] === results[2]) {
        keyID = results[0];
    } else {
        throw "nodes disagree on key ID";
    }
    
    console.log("Generated key with key ID:", keyID);


    // Step 2: Generate partial signatures

    // The message hash to sign
    let msg = "some data to sign";
    let sha256 = crypto.createHash('sha256');
    sha256.update(msg);
    let msgHash = sha256.digest();

    // In this example we will not sign with the master key, but with a key derived from the
    // master key using the chain path m/0/3.
    let chainPath = new Uint32Array([0, 3]);

    // In this example, threshold is 1, so we need threshold + 1 = 2 players to sign.
    // We will use player 0 and 1.
    let players = new Uint32Array([0, 1]);

    sessionID = "session2"
    partialSignatures = await Promise.all([
        tsmClient0.partialSign(algorithms.ECDSA, sessionID, keyID, chainPath, msgHash, players),
        tsmClient1.partialSign(algorithms.ECDSA, sessionID, keyID, chainPath, msgHash, players)]);


    // Step 3: Combine the partial signatures into the final signature

    let [signature] = await tsmClient0.finalize(algorithms.ECDSA, partialSignatures);

    // Check that the signature is valid.
    let [,pk] = await tsmClient1.publicKey(algorithms.ECDSA, keyID, chainPath);
    let isValid = await tsmClient1.verify(algorithms.ECDSA, pk, msgHash, signature, curves.SECP256K1);
    console.log("Is signature valid?", isValid)

}

example();
  1. Update the userID, URLs, and passwords placeholders with the JSON format credentials provided by our support team.
  2. The provided SDK code will automatically establish connections with each MPC node, generate a key sharing and print the corresponding key ID. It will then generate five pre-signatures and print their IDs. Finally, it will use one of the pre-signatures to acquire signature shares from each node, combine them into a full signature, and validate the signature, as shown below:
Generated key with key ID: fLzawb5DEGBgSQtS9FZXrKl6zqys
Is signature valid? true