Web Assembly SDK

Web Assembly (WASM) SDK Overview

The Web Assembly (WASM) SDK is meant to be used anywhere you can run WASM, e.g. in a browser, or in Deno. Node.js (currently at version 23.6.0) does not allow network communication in WASM, so that will not work.

Obtaining the SDK

To obtain the SDK, you need to have access to our Nexus server, from where you can download it:

Download Command

curl -u YOUR_USERNAME https://nexus.sepior.net/repository/libtsmclient/sdkv2wasm-73.0.0.tar.gz > sdkv2wasm.tar.gz

Unpacking the Archive

Unpack the archive:

tar xf sdkv2wasm.tar.gz

Contents of the Archive

You will see the following content:

sdkv2.wasm
wasm_exec.js
wasm_exec_browser.js
wasm_exec_deno.js
tests:
    aes.test.js
    authentication.test.js
    broadcast.test.js
    ecdsa.test.js
    hmac.test.js
    rsa.test.js
    schnorr.test.js
    session.test.js
    utils.test.js

Building the WASM SDK

We are building our WASM SDK by compiling our Go SDK (with a small amount of wrapper code) into WASM. You will therefore need to include the provided wasm_exec.js, and wasm_exec_x.js files in your project, besides the actual WASM file, found in sdkv2.wasm.

Testing the SDK

In the test folder, you will find examples of how to use all the methods in the SDK. The tests have been written for use with Deno. As an example, this is the content of the tests/broadcast.test.js file:

Example Test: Broadcast

// Include WASM exec
import * as _ from "../wasm_exec_deno.js";
import { describe, it, beforeAll, afterAll } from "jsr:@std/testing/bdd";
import { expect } from "jsr:@std/expect";
import {fromHexString, toHexString, printUInt64, ersLabel, ersPublicKey, ersPrivateKey, curves} from "../jsutils.js";

const {
    createHash,
} = await import('node:crypto');

let TSM, urls, config0, config1, config2, client0, client1, client2, keyID;

const derivationPath = new Uint32Array([2,1]);

const sha256 = createHash('sha256');
const data = "some data to sign";
sha256.update(data);
const messageHash = sha256.digest();

beforeAll(async () => {
    if(TSM != undefined) return;

// Load the WASM file
    TSM = await LoadTSM('./sdkv2.wasm')
    urls = ["http://localhost:8280", "http://localhost:8281", "http://localhost:8282"];

config0 = new TSM.Configuration(urls[0]).withAPIKeyAuthentication("apikey0");
    config1 = new TSM.Configuration(urls[1]).withAPIKeyAuthentication("apikey1");
    config2 = new TSM.Configuration(urls[2]).withAPIKeyAuthentication("apikey2");
    
    client0 = await new TSM.Client(config0);
    client1 = await new TSM.Client(config1);
    client2 = await new TSM.Client(config2);
});

afterAll(async () => {
    // work around https://github.com/SGrondin/bottleneck/issues/225
    // Wait for Golang GC
    await new Promise(r => setTimeout(r, 1000));
});

describe("Broadcast", (t) => {
    it('Simple', async () => {

const msg0 = new Uint8Array([0, 4, 5, 1]);
        const msg1 = new Uint8Array([1, 4, 5, 1, 5]);
        const msg2 = new Uint8Array([2, 4, 5, 1, 7, 8]);

let sessionID = TSM.generateSessionID();
        let sessionConfig = new TSM.StaticSessionConfig(sessionID, 3);
        let promises = [\
            client0.Broadcast().simpleBroadcast(sessionConfig, msg0),\
            client1.Broadcast().simpleBroadcast(sessionConfig, msg1),\
            client2.Broadcast().simpleBroadcast(sessionConfig, msg2),\
        ];

const results = await Promise.allSettled(promises);
        results.forEach(p => {
            expect(p.status).toBe("fulfilled")
            expect(p.value.get(0)).toEqual(msg0);
            expect(p.value.get(1)).toEqual(msg1);
            expect(p.value.get(2)).toEqual(msg2);
        });
    });

it('Advanced', async () => {

const msg0 = new Uint8Array([0, 4, 5, 1]);
        const msg1 = new Uint8Array([1, 4, 5, 1, 5]);
        const msg2 = new Uint8Array([2, 4, 5, 1, 7, 8]);

let sessionID = TSM.generateSessionID();
        let sessionConfig = new TSM.StaticSessionConfig(sessionID, 3);
        let promises = [\
            client0.Broadcast().advancedBroadcast(sessionConfig, msg0),\
            client1.Broadcast().advancedBroadcast(sessionConfig, msg1),\
            client2.Broadcast().advancedBroadcast(sessionConfig, msg2),\
        ];

const results = await Promise.allSettled(promises);
        results.forEach(p => {
            expect(p.status).toBe("fulfilled")
            expect(p.value.get(0)).toEqual(msg0);
            expect(p.value.get(1)).toEqual(msg1);
            expect(p.value.get(2)).toEqual(msg2);
        });
    });
});

Caveat

The WASM SDK will not work with mTLS authentication, as TLS is not yet well supported in WASM.