Skip to main content
Version: 1.2.1

Class: Ecdsa

Class providing the functionality for the ECDSA protocol via the DKLs19 MPC protocol.

Example

// Your server side creates a room for 3 parties using its API_KEY
// Creating a room uuid should always happen on the server side using your API_KEY
const N = 3;
const T = 2;
const ecdsa = new Ecdsa();
const API_KEY = 'MY_API_KEY';
const keygenRoomUuid = await ecdsa.createRoom(N, API_KEY);
// All parties call initKeygen to get an EcdsaInitKeygenResult, that contains a keygenId
const keygenInitResult = await ecdsa.initKeygen();
// All parties receive the keygenIds from all other parties
const keygenIds = [keygenId1, keygenId2];
// All parties join the keygen room
const keygenResult = await ecdsa.keygen(keygenRoomUuid, N, T, keygenInitResult, keygenIds);

// Pick the derivation path of the public key you want to sign for
const derivationPath = new Uint32Array([44,60,0,0,0]);
// Get the public key for the derivation path
const pubkey = await ecdsa.derivePubkey(keygenResult, derivationPath);
// To sign a message, create a signing room on the server side, using your API_KEY
const signingRoomUuid = await ecdsa.createRoom(T, API_KEY);
// Hash the message
const messageHash = MessageHash.sha256('my message');
// 2 parties join the signing room
const signature = await ecdsa.sign(signingRoomUuid, keygenResult, messageHash, derivationPath);
// This signature can now be verified against pubkey

// Refreshing the secret key material
// Your server creates a room for 3 parties
const refreshRoomUuid = await ecdsa.createRoom(N, API_KEY);
// All parties join the refresh room
const refreshResult = await ecdsa.refresh(refreshRoomUuid, keygenResult);
// Note: refreshResult.pubkey == keygenResult.pubkey

// Signing using the new secret key material
// The room is again created by the server
const signingRoomUuid2 = await ecdsa.createRoom(T, API_KEY);

const messageHash2 = MessageHash.sha256('my new message');
const signature2 = await ecdsa.sign(signingRoomUuid2, refreshResult, messageHash2, derivationPath);
// This signature can now be verified against pubkey

Hierarchy

  • Ecdsa

    Ecdsa

Constructors

constructor

new Ecdsa(hostUrl?): Ecdsa

Constructs a new Ecdsa instance.

Parameters

NameType
hostUrl?string

Returns

Ecdsa

Overrides

EcdsaInternal.constructor

Methods

createRoom

createRoom(numParties, apiKey): Promise<string>

Creates a room for the given number of parties. A room is a one time instance used to perform a single MPC operation(keygen/signing/refresh etc.) between parties

This function should be called in the backend so to not embed the API key in code that is distributed to the users. After the backend calls this function, the other parties can join the room by calling the relevant keygen/signing/refresh/etc. operation.

Parameters

NameTypeDescription
numPartiesnumberThe number of parties that will join the room. (an integer in range 1..65_535)
apiKeystringAn API key is required to create a room

Returns

Promise<string>

The UUID of the created room.

Inherited from

EcdsaInternal.createRoom


derivePrivateKeyFromXpriv

derivePrivateKeyFromXpriv(xpriv, derivationPath?): Promise<string>

Parses an xpriv string according to BIP-32 non-hardened, and returns the derived private key for a given BIP-32 non-hardened derivation path

Parameters

NameTypeDescription
xprivstringA valid secp256k1 xpriv string.
derivationPath?Uint32ArrayThe BIP-32 non-hardened derivation path to use for computing the private key.

Returns

Promise<string>

The derived private key of the xpriv.

Inherited from

EcdsaInternal.derivePrivateKeyFromXpriv


derivePubkey

derivePubkey(keygenResult, derivationPath?): Promise<EcdsaPublicKey>

Returns the derived public key for a keygenResult for a given BIP-32 non-hardened derivation path

Parameters

NameTypeDescription
keygenResultstring | EcdsaKeygenResultAn EcdsaKeygenResult that contains a secret share, or a secret share as a string
derivationPath?Uint32ArrayThe BIP-32 non-hardened derivation path to use for computing the public key.

Returns

Promise<EcdsaPublicKey>

The derived public key of the keypair.

Inherited from

EcdsaInternal.derivePubkey


derivePubkeyFromXpub

derivePubkeyFromXpub(Xpub, derivationPath?): Promise<EcdsaPublicKey>

Returns the derived public key for a given BIP-32 non-hardened derivation path and an extended public key (xpub).

Parameters

NameTypeDescription
XpubstringThe extended public key (xpub) of the keypair.
derivationPath?Uint32ArrayThe BIP-32 non-hardened derivation path to use for computing the public key.

Returns

Promise<EcdsaPublicKey>

The derived public key of the keypair.

Inherited from

EcdsaInternal.derivePubkeyFromXpub


exportFullPrivateKey

exportFullPrivateKey(roomUuid, keygenResult, toExportID): Promise<undefined | string>

Combine all secret shares and export the full private key to a single party. Requires a threshold amount of parties to participate.

Parameters

NameTypeDescription
roomUuidstringThe UUID of the export room.
keygenResultstring | EcdsaKeygenResultThe EcdsaKeygenResult that contains the secret share of the private key to be extracted, or the secret share as a string.
toExportIDstringThe exportID outputs from exportID() of the party that will receive the private key, this must match between all parties, and the receiving party must participate.

Returns

Promise<undefined | string>

The party being exported to will receive a string containing the full xpriv, while the rest will receive undefined.

Inherited from

EcdsaInternal.exportFullPrivateKey


exportID

exportID(keygenResult): Promise<string>

The party that expects to receive the private key needs to call this function before exportFullPrivatekey. It must then transmit the ID to threshold-1 parties, this can be done in an untrusted channel (as if the parties use different keys this will break) Once the parties have the exportID of the party they want to export the private key to, the party and the threshold-1 participants need to call exportFullPrivatekey with that ID.

Parameters

NameTypeDescription
keygenResultstring | EcdsaKeygenResultThe EcdsaKeygenResult that contains the secret share to be used for key extraction, or the secret share as a string.

Returns

Promise<string>

A string that contains a base58 string exportID.

Inherited from

EcdsaInternal.exportID


getHostUrl

getHostUrl(path?): string

Parameters

NameType
path?string

Returns

string

Inherited from

EcdsaInternal.getHostUrl


getXpub

getXpub(keygenResult): Promise<string>

Returns returns a base58 encoded extended public key (Xpub) derived from a EcdsaKeygenResult. See BIP-32: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format The Xpub can be used either via third party libraries or via Ecdsa.derivePubkeyFromXpub

Parameters

NameTypeDescription
keygenResultstring | EcdsaKeygenResultAn EcdsaKeygenResult that contains the secret share of the private key, or the secret share as a string.

Returns

Promise<string>

base58 encoded extended public key (Xpub).

Inherited from

EcdsaInternal.getXpub


importPrivateKeyImporter

importPrivateKeyImporter(roomUuid, threshold, privateKey, keygenInit, keygenIds): Promise<EcdsaKeygenResult>

WARNING: Private key import is an advanced feature of the SDK. We strongly advise consulting with the Sodot team before using it, due to a full private key being imported from a different system. Secret shares generated from imported private keys will always have the risk of the private key having been compromised in the past or in the future in case the private key is not deleted after the import operation.

Importing a full private key, and sharing into a T-of-N sharing, the resultant key shares will be of the exact same public key as the full private key.

This is the method that an importing party (meaning one the party in possesion of the private key) should use for receiving a key share in the new T-of-N quorum.

Parameters

NameTypeDescription
roomUuidstringThe UUID of the import room.
thresholdnumberThe threshold of the keypair of the new quorum. (an integer in range 1..65_535)
privateKeystringThe private key to be imported. (a hex string of length 64)
keygenInitEcdsaInitKeygenResultThis must be the same EcdsaInitKeygenResult the keygenId of was sent to the other parties.
keygenIdsstring[]The keygenId outputs from initKeygen(), of all other parties we wish to be part of the new quorum with, keygenIds from all parties must be received through an authenticated communication channel.

Returns

Promise<EcdsaKeygenResult>

An EcdsaKeygenResult that contains the public key as well as the secret data that can be used for signing.

Example

const N = 3;
const T = 2;
// A private key is created in some external system.
// const privateKey = "b3ac...0d71"; // hex string with 64 hex chars
// Some time passes...
// Now this party wishes to be part of a new quorum of `2-of-3` sharing of the private key.

// The app server creates a room for N(= 3) parties.
const importRoomUuid = await ecdsa.createRoom(N, API_KEY);
// The other parties must join the import room using the `importPrivateKeyRecipient` method.
const keygenInitResult = await ecdsa.initKeygen(); // This the importing party
// This importing party will send its `keygenInitResult.keygenId` to all other parties.
// This party will also receive the `keygenId`s of all other parties of the new quorum.
const keygenIds = [keygenId1, keygenId2, keygenId3]; // Note that here we must include our own `keygenId` as well, the order of the ids doesn't matter.
const importKeygenResult = await ecdsa.importPrivateKeyImporter(importRoomUuid, T, privateKey, keygenInitResult, keygenIds);
// importKeygenResult can now be used for signing under the T(= 2) threshold with the same public key

Inherited from

EcdsaInternal.importPrivateKeyImporter


importPrivateKeyRecipient

importPrivateKeyRecipient(roomUuid, threshold, keygenInit, keygenIds): Promise<EcdsaKeygenResult>

WARNING: Private key import is an advanced feature of the SDK. We strongly advise consulting with the Sodot team before using it, due to a full private key being imported from a different system. Secret shares generated from imported private keys will always have the risk of the private key having been compromised in the past or in the future in case the private key is not deleted after the import operation.

Importing a full private key, and sharing into a T-of-N sharing, the resultant key shares will be of the exact same public key as the full private key.

This is the method that a new party (meaning one that does not currently have the private key) should use for receiving a key share in the new T-of-N quorum. The method takes the same input parameters as keygen since for a new party joining the quorum the import operation is very similar to a keygen operation.

Parameters

NameTypeDescription
roomUuidstringThe UUID of the import room.
thresholdnumberThe threshold of the keypair of the new quorum. (an integer in range 1..65_535)
keygenInitEcdsaInitKeygenResultThis must be the same EcdsaInitKeygenResult the keygenId of was sent to the other parties.
keygenIdsstring[]The keygenId outputs from initKeygen(), of all other parties we wish to be part of the new quorum with, keygenIds from all parties must be received through an authenticated communication channel.

Returns

Promise<EcdsaKeygenResult>

An EcdsaKeygenResult that contains the public key as well as the secret data that can be used for signing.

Example

const N = 3;
const T = 2;
// A private key is created in some external system.
// Some time passes...
// Now this party wishes to be part of a new quorum of `2-of-3` sharing of the private key.

// The app server creates a room for N(= 3) parties.
const importRoomUuid = await ecdsa.createRoom(N, API_KEY);
// The party with the private key must join the import room using the `importPrivateKeyImporter` method.
const keygenInitResult = await ecdsa.initKeygen(); // This is a new party
// This new party will send its `keygenInitResult.keygenId` to all other parties.
// This party will also receive the `keygenId`s of all other parties of the new quorum.
const keygenIds = [keygenId1, keygenId2, keygenId3]; // Note that here we must include our own `keygenId` as well, the order of the ids doesn't matter.
const importKeygenResult = await ecdsa.importPrivateKeyRecipient(importRoomUuid, T, keygenInitResult, keygenIds);
// importKeygenResult can now be used for signing under the T(= 2) threshold with the same public key

Inherited from

EcdsaInternal.importPrivateKeyRecipient


initKeygen

initKeygen(): Promise<EcdsaInitKeygenResult>

All parties must call this function before calling keygen. All parties receive an EcdsaInitKeygenResult as an output from this function. The EcdsaInitKeygenResult.keygenId must be sent through an authenticated communication channel to all other devices we wish to perform keygen with. Once we have the keygenId-s of all parties, then keygen can be called with the same EcdsaInitKeygenResult.keygenSecret as was given here.

Returns

Promise<EcdsaInitKeygenResult>

An EcdsaInitKeygenResult that contains a base58 string keygenId and keygenSecret.

Inherited from

EcdsaInternal.initKeygen


keygen

keygen(roomUuid, numParties, threshold, keygenInit, keygenIds): Promise<EcdsaKeygenResult>

Generate a keypair for the given number of parties and threshold.

Parameters

NameTypeDescription
roomUuidstringThe UUID of the keygen room.
numPartiesnumberThe number of parties that will join the keygen room. (an integer in range 1..65_535)
thresholdnumberThe threshold of the keypair that will be generated. (an integer in range 1..65_535)
keygenInitEcdsaInitKeygenResultThis must be the same EcdsaInitKeygenResult the keygenId of was sent to the other parties.
keygenIdsstring[]The keygenId outputs from initKeygen of all other parties we wish to perform keygen with, these must have been received through an authenticated communication channel.

Returns

Promise<EcdsaKeygenResult>

An EcdsaKeygenResult that contains the public key as well as the secret data that can be used for signing.

Example

// Your server side creates a room for 5 parties using its API_KEY
// Creating a room uuid should always happen on the server side using your API_KEY
const N = 5;
const T = 3;
const ecdsa = new Ecdsa();
const API_KEY = 'MY_API_KEY';
const keygenRoomUuid = await ecdsa.createRoom(N, API_KEY);
// All parties call initKeygen to get an EcdsaInitKeygenResult, that contains a keygenId
const keygenInitResult = await ecdsa.initKeygen();
// All parties receive the keygenIds from all other parties
const keygenIds = [keygenId1, keygenId2, keygenId3, keygenId4];
// All parties join the keygen room
const keygenResult = await ecdsa.keygen(keygenRoomUuid, N, T, keygenInitResult, keygenIds);
// keygenResult.pubkey is now distributed between all 5 parties, such that any 3 parties can sign a message

Inherited from

EcdsaInternal.keygen


offlineExportFullPrivateKey

offlineExportFullPrivateKey(keygenResults): Promise<string>

Receives as input an array of threshold EcdsaKeygenResults and locally computes the full private key (xpriv). The main use case for this function is in an offline recovery setting where keygen results are collected manually and used to recover the full private key on an air-gapped server/device.

Parameters

NameTypeDescription
keygenResultsstring[] | EcdsaKeygenResult[]An array of threshold EcdsaKeygenResults that each contain a secret share of the private key to be locally extracted, or an array of secret shares as strings

Returns

Promise<string>

A string containing the full xpriv.

Inherited from

EcdsaInternal.offlineExportFullPrivateKey


refresh

refresh(roomUuid, keygenResult): Promise<EcdsaKeygenResult>

Used for refreshing the secret material of all parties without altering the public key at all. Takes an EcdsaKeygenResult as input and returns a new one with the same public key but with fresh key material. Be careful to delete the EcdsaKeygenResult given as input before it is certain that all devices have properly stored the fresh EcdsaKeygenResult that is output. Note that the new EcdsaKeygenResults may only be used with each other, attempting to use older EcdsaKeygenResults with newer ones for signing will result in failure. The motivation for using refresh is to enhance security by switching the secret key material frequently, this means that an adversary will need to compromise multiple devices at the same time in order to compromise the private key.

Parameters

NameTypeDescription
roomUuidstringThe UUID of the refresh room.
keygenResultstring | EcdsaKeygenResultThe EcdsaKeygenResult that contains the secret share that will be refreshed, or the secret share as a string.

Returns

Promise<EcdsaKeygenResult>

A new EcdsaKeygenResult with the same pubkey as the input but with fresh secret key material.

Example

const N = 5;
const T = 3;
const ecdsa = new Ecdsa();
const API_KEY = 'MY_API_KEY';
// An EcdsaKeygenResult is generated
const keygenResult = await ecdsa.keygen(...);
// Some time passes ...

// We now refresh the secret key material of our public key
// Your server creates a room for 5 parties
const refreshRoomUuid = await ecdsa.createRoom(N, API_KEY);
// All parties now join the refresh room using their current secret key material
// Option 1: Refresh the secret using the generated keygenResult
const refreshedKeygenResult = await ecdsa.refresh(refreshRoomUuid, keygenResult)

// Option 2: Refresh the secret using a secret share string
let secretShareString: string = keygenResult.secretShare;
const refreshedKeygenResult = await ecdsa.refresh(refreshRoomUuid, secretShareString)
// Note: refreshedKeygenResult.pubkey == keygenResult.pubkey
// refreshedKeygenResult can now be used for signing under the same T threshold, as well as be refreshed again

Inherited from

EcdsaInternal.refresh


reshareNewParty

reshareNewParty(roomUuid, oldThreshold, newThreshold, keygenInit, keygenIds): Promise<EcdsaKeygenResult>

WARNING: Key resharing is an advanced feature of the SDK. We strongly advise consulting with the Sodot team before using it, as incorrect usage might lead to the detriment of the private key security. To use the feature correctly, developers using this feature must make sure that at least n - t + 1 parties of the t-of-n signing quorum delete their current shares before using the resharing of the private key. Also, after resharing, the resharing operation must not be considered complete until such deletion has occurred. Since deleting a share cannot be guaranteed cryptographically, it must be guaranteed by the software architecture (hence, by the developers using the SDK).

Resharing the private key of the t-of-n quorum of signers, the resultant key shares will be of the exact same public key as the previous quorum. Resharing should be used in cases where we aim to modify the current t-of-n quorum with a new quorum with newT-of-newN signers for the same public key.

This is the method that a new party (meaning one that does not currently have a key share) should use for receiving a key share in the new newT-of-newN quorum. The method takes the same input parameters as keygen since for a new party joining the quorum the reshare operation is very similar to a keygen operation. In order to receive the keygenIds of parties that are already a part of the quorum, those parties will need to call exportID() and send the result to the parties in the new quorum.

Parameters

NameTypeDescription
roomUuidstringThe UUID of the reshare room.
oldThresholdnumberThe threshold of the existing quorum. (an integer in range 1..65_535)
newThresholdnumberThe threshold of the keypair of the new quorum. (an integer in range 1..65_535)
keygenInitEcdsaInitKeygenResultThis must be the same EcdsaInitKeygenResult the keygenId of was sent to the other parties.
keygenIdsstring[]The keygenId outputs from initKeygen() - for new parties / exportID() - for parties remaining in the quorum, of all other parties we wish to be part of the new quorum with, keygenIds from new parties must be received through an authenticated communication channel, keygenIds from remaining parties in the quorum can be sent through any communication channel.

Returns

Promise<EcdsaKeygenResult>

An EcdsaKeygenResult that contains the public key as well as the secret data that can be used for signing.

Example

const N = 5;
const T = 3;
const newN = 6;
const newT = 5;
// A signing quorum of `3-of-5` is set up without this party.
// Some time passes...
// Now this party wishes to be part of a new quorum of `5-of-6`.

// The app server creates a room for newN(= 6) parties.
const reshareRoomUuid = await ecdsa.createRoom(newN, API_KEY);
// At least T(= 3) parties now join the reshare room using the current secret key material (this will be done using `reshareRemainingParty`), all new parties will then join the reshare room using their `initKeygenResult` using `reshareNewParty`.
const keygenInitResult = await ecdsa.initKeygen(); // This is a new party
// This new party will send its `keygenInitResult.keygenId` to all other parties.
// This party will also receive the `keygenId`s of all other parties of the new quorum.
const keygenIds = [keygenId1, keygenId2, ..., keygenId6]; // Note that here we must include our own `keygenId` as well, the order of the ids doesn't matter.
const reshareKeygenResult = await ecdsa.reshareNewParty(reshareRoomUuid, T, newT, keygenInitResult, keygenIds);
// reshareKeygenResult can now be used for signing under the newT(= 5) threshold with the same public key, as well as be reshared again

Inherited from

EcdsaInternal.reshareNewParty


reshareRemainingParty

reshareRemainingParty(roomUuid, newThreshold, keygenResult, keygenIds): Promise<EcdsaKeygenResult>

WARNING: Key resharing is an advanced feature of the SDK. We strongly advise consulting with the Sodot team before using it, as incorrect usage might lead to the detriment of the private key security. To use the feature correctly, developers using this feature must make sure that at least n - t + 1 parties of the t-of-n signing quorum delete their current shares before using the resharing of the private key. Also, after resharing, the resharing operation must not be considered complete until such deletion has occurred. Since deleting a share cannot be guaranteed cryptographically, it must be guaranteed by the software architecture (hence, by the developers using the SDK).

Resharing the private key of the t-of-n quorum of signers, the resultant key shares will be of the exact same public key as the previous quorum. Resharing should be used in cases where we aim to modify the current t-of-n quorum with a new quorum with newT-of-newN signers for the same public key.

This is the method that a remaining party (meaning one that does currently have a key share) should use for receiving a new key share in the new newT-of-newN quorum. The method takes the same input parameters as reshareNewParty except that it will use its existing EcdsaKeygenResult instead of a new EcdsaInitKeygenResult. In order to receive the keygenIds of parties that are already a part of the quorum, those parties will need to call exportID() and send the result to the parties in the new quorum.

Parameters

NameTypeDescription
roomUuidstringThe UUID of the reshare room.
newThresholdnumberThe threshold of the keypair of the new quorum. (an integer in range 1..65_535)
keygenResultstring | EcdsaKeygenResultThe EcdsaKeygenResult that is used for signing with the existing t-of-n quorum, or the secret share as a string.
keygenIdsstring[]The keygenId outputs from initKeygen() - for new parties / exportID() - for parties remaining in the quorum, of all other parties we wish to be part of the new quorum with, keygenIds from all parties must be received through an authenticated communication channel.

Returns

Promise<EcdsaKeygenResult>

An EcdsaKeygenResult that contains the public key as well as the secret data that can be used for signing.

Example

const N = 5;
const T = 3;
const newN = 6;
const newT = 5;
// A signing quorum of `3-of-5` is set up with this party.
const keygenResult = ecdsa.keygen(...);
// Some time passes...
// Now this party wishes to be part of a new quorum of `5-of-6`.

// The app server creates a room for newN(= 6) parties.
const reshareRoomUuid = await ecdsa.createRoom(newN, API_KEY);
// At least T(= 3) parties now join the reshare room using the current secret key material (this will be done using `reshareRemainingParty`), all new parties will then join the reshare room using their `initKeygenResult` using `reshareNewParty`.
const keygenId = await ecdsa.exportID(keygenResult); // This is a remaining party
// This remaining party will send its `keygenId` to all other parties (new - via an authenticated channel and remaining - via any channel).
// This party will also receive the `keygenId`s of all other parties of the new quorum (new - via an authenticated channel and remaining - via any channel).
const keygenIds = [keygenId1, keygenId2, ..., keygenId6]; // Note that here we must include our own `keygenId` as well, the order of the ids doesn't matter.
// Option 1: Reshare the private key using the generated keygenResult
const reshareKeygenResult = await ecdsa.reshareRemainingParty(reshareRoomUuid, newT, keygenResult, keygenIds);

// Option 2: Reshare the private key using a secret share string
let secretShareString: string = keygenResult.secretShare;
const reshareKeygenResult = await ecdsa.reshareRemainingParty(reshareRoomUuid, newT, secretShareString, keygenIds);
// reshareKeygenResult can now be used for signing under the newT(= 5) threshold with the same public key, as well as be reshared again

Inherited from

EcdsaInternal.reshareRemainingParty


sign

sign(roomUuid, keygenResult, msgHash, derivationPath?): Promise<EcdsaSignature>

Sign a message with the secret share contained in an EcdsaKeygenResult. The message must be hashed before signing, this can be done using the MessageHash class.

Parameters

NameTypeDescription
roomUuidstringThe UUID of the signing room.
keygenResultstring | EcdsaKeygenResultThe EcdsaKeygenResult that contains the secret share to be used for signing, or the secret share as a string.
msgHashMessageHashThe MessageHash of the message that will be signed, using the relevant hash algorithm.
derivationPath?Uint32ArrayThe BIP-32 non-hardened derivation path to use for signing msgHash.

Returns

Promise<EcdsaSignature>

The signature of the message, this signature can be verified using keygenResult.pubkey

Example

To sign a message, create a signing room on the server side, using your API_KEY
const N = 5;
const T = 3;
// An EcdsaKeygenResult is generated using keygen
const keygenResult = await ecdsa.keygen(...);

const ecdsa = new Ecdsa();
const API_KEY = 'MY_API_KEY';
const signingRoomUuid = await ecdsa.createRoom(T, API_KEY);

// Pick the derivation path of the public key you want to sign for
const derivationPath = new Uint32Array([44,60,0,0,0]);

// Option 1: Derive public key using the secret share from keygenResult
const pubkey = await ecdsa.derivePubkey(keygenResult, derivationPath);

// Option 2: Derive public key using an extended public key (Xpub) for more flexibility
const Xpub = await ecdsa.getXpub(keygenResult);
const pubkeyFromXpub = await ecdsa.derivePubkeyFromXpub(Xpub, derivationPath);

// Hash the message
const messageHash = MessageHash.sha256('my message');

// 3 parties join the signing room

// Option 1: Sign using the generated keygenResult
const signature = await ecdsa.sign(signingRoomUuid, keygenResult, messageHash, derivationPath);

// Option 2: sign using a secret share string
let secretShareString: string = keygenResult.secretShare;
const signature = await ecdsa.sign(signingRoomUuid, secretShareString, message, derivationPath);

// signature can be verified against pubkey

Inherited from

EcdsaInternal.sign