Getting Started
Generate a key and begin signing in under a minute.
Key Generation
First we must generate a public key and some key shares so that we can later sign messages.
You will need your API_KEY
.
We show example code for a 2-of-3 threshold signing scenario.
(Note that Sodot MPC SDK allows any t-of-n threshold signing setting)
To generate a key we simply run:
- ECDSA Node
- Ed25519 Node
- ECDSA Web
- Ed25519 Web
- ECDSA RN
- Ed25519 RN
- ECDSA Go
- Ed25519 Go
import { Ecdsa } from '@sodot/sodot-node-sdk';
// 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, so that the API_KEY is never exposed to the client side
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);
Full details can be found here.
import { Ed25519 } from '@sodot/sodot-node-sdk';
// 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, so that the API_KEY is never exposed to the client side
const N = 3;
const T = 2;
const ed25519 = new Ed25519();
const API_KEY = 'MY_API_KEY';
const keygenRoomUuid = await ed25519.createRoom(N, API_KEY);
// All parties call initKeygen to get an Ed25519InitKeygenResult, that contains a keygenId
const keygenInitResult = await ed25519.initKeygen();
// All parties receive the keygenIds from all other parties
const keygenIds = [keygenId1, keygenId2];
// All parties join the keygen room
const keygenResult = await ed25519.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 ed25519.derivePubkey(keygenResult, derivationPath);
Full details can be found here.
import { Ecdsa } from '@sodot/sodot-web-sdk';
// 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, so that the API_KEY is never exposed to the client side
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);
Full details can be found here.
import { Ed25519 } from '@sodot/sodot-web-sdk';
// 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, so that the API_KEY is never exposed to the client side
const N = 3;
const T = 2;
const ed25519 = new Ed25519();
const API_KEY = 'MY_API_KEY';
const keygenRoomUuid = await ed25519.createRoom(N, API_KEY);
// All parties call initKeygen to get an Ed25519InitKeygenResult, that contains a keygenId
const keygenInitResult = await ed25519.initKeygen();
// All parties receive the keygenIds from all other parties
const keygenIds = [keygenId1, keygenId2];
// All parties join the keygen room
const keygenResult = await ed25519.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 ed25519.derivePubkey(keygenResult, derivationPath);
Full details can be found here.
import { StatefulEcdsa } from '@sodot/sodot-react-native-sdk';
// 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, so that the API_KEY is never exposed to the client side
const N = 3;
const T = 2;
const ecdsa = new StatefulEcdsa(); // Note that a stateless Ecdsa class is also available with the same API as the Node and Web SDKs
const API_KEY = 'MY_API_KEY';
const keygenRoomUuid = await ecdsa.createRoom(N, API_KEY);
// All parties call initKeygen to get a keygenId
const keygenId = await ecdsa.initKeygen('myKeyName');
// All parties receive the keygenIds from all other parties
const keygenIds = [keygenId1, keygenId2];
// All parties join the keygen room
const publicKey = await ecdsa.keygen(keygenRoomUuid, N, T, 'myKeyName', 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 derivedPubkey = await ecdsa.derivePubkey('myKeyName', derivationPath);
Full details can be found here.
import { StatefulEd25519 } from '@sodot/sodot-react-native-sdk';
// 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, so that the API_KEY is never exposed to the client side
const N = 3;
const T = 2;
const ed25519 = new StatefulEd25519(); // Note that a stateless Ed25519 class is also available with the same API as the Node and Web SDKs
const API_KEY = 'MY_API_KEY';
const keygenRoomUuid = await ed25519.createRoom(N, API_KEY);
// All parties call initKeygen to get a keygenId
const keygenId = await ed25519.initKeygen('myKeyName');
// All parties receive the keygenIds from all other parties
const keygenIds = [keygenId1, keygenId2];
// All parties join the keygen room
const publicKey = await ed25519.keygen(keygenRoomUuid, N, T, 'myKeyName', 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 derivedPubkey = await ed25519.derivePubkey('myKeyName', derivationPath);
Full details can be found here.
import "github.com/sodot-rs/sodot-go-sdk"
// 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 API_KEY = "MY_API_KEY"
ecdsa := sodot.NewEcdsa("")
keygenRoomUuid, err := ecdsa.CreateRoom(N, API_KEY)
if err != nil {
panic(err)
}
// All parties call InitKeygen to get a KeygenID and a KeygenPrivateKey
keygenID, keygenPrivKey, err := ecdsa.InitKeygen()
if err != nil {
panic(err)
}
// Send the keygenID to all other parties
_ = keygenID
// All parties receive the KeygenIDs from all other parties
keygenIds := []sodot.KeygenID{"keygenID1", "keygenID2"}
// All parties join the keygen room
secretShare, pk, err := ecdsa.Keygen(keygenRoomUuid, N, T, keygenPrivKey, keygenIds)
if err != nil {
panic(err)
}
// The public key can now be used to verify signatures
_, _ = secretShare, pk
// Pick the derivation path of the public key you want to sign for
derivationPath := []uint32{44, 60, 0, 0, 0}
// Get the public key for the derivation path
derivedPubKey, err := ecdsa.DerivePubkey(secretShare, derivationPath)
if err != nil {
panic(err)
}
// The derived public key can now be used to verify signatures with the same derivation path
_ = derivedPubKey
Full details can be found here.
import "github.com/sodot-rs/sodot-go-sdk"
// 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 API_KEY = "MY_API_KEY"
ed25519 := sodot.NewEd25519("")
keygenRoomUuid, err := ed25519.CreateRoom(N, API_KEY)
if err != nil {
panic(err)
}
// All parties call InitKeygen to get a KeygenID and a KeygenPrivateKey
keygenID, keygenPrivKey, err := ed25519.InitKeygen()
if err != nil {
panic(err)
}
// Send the keygenID to all other parties
_ = keygenID
// All parties receive the KeygenIDs from all other parties
keygenIds := []sodot.KeygenID{"keygenID1", "keygenID2"}
// All parties join the keygen room
secretShare, pk, err := ed25519.Keygen(keygenRoomUuid, N, T, keygenPrivKey, keygenIds)
if err != nil {
panic(err)
}
// The public key can now be used to verify signatures
_, _ = secretShare, pk
// Pick the derivation path of the public key you want to sign for
derivationPath := []uint32{44, 60, 0, 0, 0}
// Get the public key for the derivation path
derivedPubKey, err := ed25519.DerivePubkey(secretShare, derivationPath)
if err != nil {
panic(err)
}
// The derived public key can now be used to verify signatures with the same derivation path
_ = derivedPubKey
Full details can be found here.
Behind the scenes this is the rough flow of communication that occurs:
Signing
Now that we have key shares on all the devices/servers of the potential signers we can sign by running:
- ECDSA Node
- Ed25519 Node
- ECDSA Web
- Ed25519 Web
- ECDSA RN
- Ed25519 RN
- ECDSA Go
- Ed25519 Go
import { Ecdsa, MessageHash } from '@sodot/sodot-node-sdk';
// To sign a message, create a signing room on the server side, using your API_KEY
const N = 3;
const T = 2;
// An EcdsaKeygenResult was previously 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]);
// Get the public key for the derivation path
const pubkey = await ecdsa.derivePubkey(keygenResult, derivationPath);
// Hash the message
const messageHash = MessageHash.sha256('my message');
// 2 parties join the signing room
const signature = await ecdsa.sign(signingRoomUuid, keygenResult, messageHash, derivationPath);
// signature can be verified against pubkey
Full details can be found here.
import { Ed25519 } from '@sodot/sodot-node-sdk';
// To sign a message, create a signing room on the server side, using your API_KEY
const N = 3;
const T = 2;
// An Ed25519KeygenResult was previously generated using keygen
const keygenResult = await ed25519.keygen(...);
const ed25519 = new Ed25519();
const API_KEY = 'MY_API_KEY';
const signingRoomUuid = await ed25519.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]);
// Get the public key for the derivation path
const pubkey = await ed25519.derivePubkey(keygenResult, derivationPath);
// The message as a hex string
const message = 'cafecafe';
// 2 parties join the signing room
const signature = await ed25519.sign(signingRoomUuid, keygenResult, message, derivationPath);
// signature can be verified against pubkey
Full details can be found here.
import { Ecdsa, MessageHash } from '@sodot/sodot-web-sdk';
// To sign a message, create a signing room on the server side, using your API_KEY
const N = 3;
const T = 2;
// An EcdsaKeygenResult was previously 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]);
// Get the public key for the derivation path
const pubkey = await ecdsa.derivePubkey(keygenResult, derivationPath);
// Hash the message
const messageHash = MessageHash.sha256('my message');
// 2 parties join the signing room
const signature = await ecdsa.sign(signingRoomUuid, keygenResult, messageHash, derivationPath);
// signature can be verified against pubkey
Full details can be found here.
import { Ed25519 } from '@sodot/sodot-web-sdk';
// To sign a message, create a signing room on the server side, using your API_KEY
const N = 3;
const T = 2;
// An Ed25519KeygenResult was previously generated using keygen
const keygenResult = await ed25519.keygen(...);
const ed25519 = new Ed25519();
const API_KEY = 'MY_API_KEY';
const signingRoomUuid = await ed25519.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]);
// Get the public key for the derivation path
const pubkey = await ed25519.derivePubkey(keygenResult, derivationPath);
// The message as a hex string
const message = 'cafecafe';
// 2 parties join the signing room
const signature = await ed25519.sign(signingRoomUuid, keygenResult, message, derivationPath);
Full details can be found here.
import { StatefulEcdsa, MessageHash } from '@sodot/sodot-react-native-sdk';
// To sign a message, create a signing room on the server side, using your API_KEY
const N = 3;
const T = 2;
const ecdsa = new StatefulEcdsa(); // Note that a stateless Ecdsa class is also available with the same API as the Node and Web SDKs
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]);
// Get the public key for the derivation path
const derivedPubkey = await ecdsa.derivePubkey('myKeyName', derivationPath);
// Hash the message
const messageHash = MessageHash.sha256('my message');
// 2 parties join the signing room
const signature = await ecdsa.sign(signingRoomUuid, 'myKeyName', messageHash, derivationPath);
// This signature can now be verified against derivedPubkey
Full details can be found here.
import { StatefulEd25519 } from '@sodot/sodot-react-native-sdk';
// To sign a message, create a signing room on the server side, using your API_KEY
const N = 3;
const T = 2;
const ed25519 = new StatefulEd25519(); // Note that a stateless Ed25519 class is also available with the same API as the Node and Web SDKs
const API_KEY = 'MY_API_KEY';
const signingRoomUuid = await ed25519.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]);
// Get the public key for the derivation path
const derivedPubkey = await ed25519.derivePubkey('myKeyName', derivationPath);
// The message as a hex string
const message = 'cafecafe';
// 2 parties join the signing room
const signature = await ecdsa.sign(signingRoomUuid, 'myKeyName', message, derivationPath);
// This signature can now be verified against derivedPubkey
Full details can be found here.
import "github.com/sodot-rs/sodot-go-sdk"
// To sign a message, create a signing room on the server side, using your API_KEY
const N = 3
const T = 2
const API_KEY = "MY_API_KEY"
// An EcdsaSecretShare is generated using Keygen
// secretShare, pk, err := ecdsa.Keygen(...)
secretShare := sodot.EcdsaSecretShare{}
ecdsa := sodot.NewEcdsa("")
signingRoomUuid, err := ecdsa.CreateRoom(T, API_KEY)
if err != nil {
panic(err)
}
// Pick the derivation path of the public key you want to sign for
derivationPath := []uint32{44, 60, 0, 0, 0}
// Get the public key for the derivation path
derivedPubKey, err := ecdsa.DerivePubkey(secretShare, derivationPath)
if err != nil {
panic(err)
}
// The derived public key can now be used to verify signatures with the same derivation path
_ = derivedPubKey
// Hash the message
messageHash := sodot.MessageHashFromSha256([]byte("my message"))
// 2 parties join the signing room
signature, err := ecdsa.Sign(signingRoomUuid, secretShare, messageHash, derivationPath)
if err != nil {
panic(err)
}
// This signature can now be verified against derivedPubkey
_ = signature
Full details can be found here.
import "github.com/sodot-rs/sodot-go-sdk"
// To sign a message, create a signing room on the server side, using your API_KEY
const N = 3
const T = 2
const API_KEY = "MY_API_KEY"
// An Ed25519SecretShare is generated using Keygen
// secretShare, pk, err := ed25519.Keygen(...)
secretShare := sodot.Ed25519SecretShare{}
ed25519 := sodot.NewEd25519("")
signingRoomUuid, err := ed25519.CreateRoom(T, API_KEY)
if err != nil {
panic(err)
}
// Pick the derivation path of the public key you want to sign for
derivationPath := []uint32{44, 60, 0, 0, 0}
// Get the public key for the derivation path
derivedPubKey, err := ed25519.DerivePubkey(secretShare, derivationPath)
if err != nil {
panic(err)
}
// The derived public key can now be used to verify signatures with the same derivation path
_ = derivedPubKey
// Define the message
message := []byte("my message")
// 2 parties join the signing room
signature, err := ed25519.Sign(signingRoomUuid, secretShare, message, derivationPath)
if err != nil {
panic(err)
}
// This signature can now be verified against derivedPubkey
_ = signature
Full details can be found here.
Behind the scenes this is the rough flow of communication that occurs, note that since only 2 signers are needed, Alice (chosen as a non-signer in this example) doesn't participate at all in the protocol: