Getting Started
Generate a key and begin signing in under a minute with the Sodot Unity SDK.
Key Generation
First, we must generate a public key and 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 use the objects defined in the SDK:
BIP-340 (for Bitcoin Taproot), ECDSA and ED25519 are all supported through the Unity SDK.
- ECDSA
- ED25519
- BIP340
using SodotSDK;
using SodotSDK.Ecdsa;
// 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
ushort N = 3;
ushort T = 2;
var myApiKey = "MY_API_KEY";
var hostUrl = "demo.sodot.dev"; // Your Relay URL
// Create the Ecdsa instance with your relay server hostURL
var ecdsa = new Ecdsa(hostUrl);
// Create a room for key generation
var keygenRoomUuid = await ecdsa.CreateRoom(N, myApiKey);
// All parties call initKeygen to get initialization data that contains a public key and private key
var (keygenId, keygenSecret) = ecdsa.InitKeygen();
// All parties receive the keygenIds from all other parties
var keygenIds = new KeygenId[] { new KeygenId("keygenId1"), new KeygenId("keygenId3") };
// All parties join the keygen room
var (pubkey, secretShare) = await ecdsa.Keygen(keygenRoomUuid, N, T, keygenSecret, keygenIds);
// Pick the derivation path of the public key you want to sign for
var derivationPath = new uint[] { 44, 60, 0, 0, 0 };
// Get the public key for the derivation path
var derivedPubkey = await ecdsa.DerivePubkey(secretShare, derivationPath);
// Store secretShare securely for later use in signing
using SodotSDK;
using SodotSDK.Ed25519;
// 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
ushort N = 3;
ushort T = 2;
var myApiKey = "MY_API_KEY";
var hostUrl = "demo.sodot.dev"; // Your Relay URL
// Create the Ed25519 instance with your relay server hostURL
var ed25519 = new Ed25519(hostUrl);
// Create a room for key generation
var keygenRoomUuid = await ed25519.CreateRoom(N, myApiKey);
// All parties call initKeygen to get initialization data that contains a public key and private key
var (keygenId, keygenSecret) = ed25519.InitKeygen();
// All parties receive the keygenIds from all other parties
var keygenIds = new KeygenId[] { new KeygenId("keygenId1"), new KeygenId("keygenId3") };
// All parties join the keygen room
var (pubkey, secretShare) = await ed25519.Keygen(keygenRoomUuid, N, T, keygenSecret, keygenIds);
// Pick the derivation path of the public key you want to sign for
var derivationPath = new uint[] { 44, 60, 0, 0, 0 };
// Get the public key for the derivation path
var derivedPubkey = await ed25519.DerivePubkey(secretShare, derivationPath);
// Store secretShare securely for later use in signing
using SodotSDK;
using SodotSDK.Bip340;
// 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
ushort N = 3;
ushort T = 2;
var myApiKey = "MY_API_KEY";
var hostUrl = "demo.sodot.dev"; // Your Relay URL
// Create the Bip340 instance with your relay server hostURL
var bip340 = new Bip340(hostUrl);
// Create a room for key generation
var keygenRoomUuid = await bip340.CreateRoom(N, myApiKey);
// All parties call initKeygen to get initialization data that contains a public key and private key
var (keygenId, keygenSecret) = bip340.InitKeygen();
// All parties receive the keygenIds from all other parties
var keygenIds = new KeygenId[] { new KeygenId("keygenId1"), new KeygenId("keygenId3") };
// All parties join the keygen room
var (pubkey, secretShare) = await ed25519.Keygen(keygenRoomUuid, N, T, keygenSecret, keygenIds);
// Pick the derivation path of the public key you want to sign for
var derivationPath = new uint[] { 44, 60, 0, 0, 0 };
// For BIP340, you can optionally use a tweak
var tweak = null // `null` for no tweak
// Get the public key for the derivation path
var derivedPubkey = await bip340.DeriveTweakPubkey(secretShare, derivationPath, tweak);
// Store secretShare securely for later use in signing
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
- ED25519
- BIP340
using SodotSDK;
using static SodotSDK.SodotUtils;
using SodotSDK.Ecdsa;
// To sign a message, create a signing room on the server side, using your API_KEY
ushort T = 2; // We only need T signers (of our N total parties)
var myApiKey = "MY_API_KEY";
var hostUrl = "demo.sodot.dev"; // Your Relay URL
// Create the Ecdsa instance with your relay server hostURL
var ecdsa = new Ecdsa(hostUrl);
// Create a room for signing
var signingRoomUuid = await ecdsa.CreateRoom(T, myApiKey);
// Each participating party uses their secret share from key generation
var (_, secretShare) = await ecdsa.Keygen(/*...*/);
// The derivation path to use for signing (same as used to generate the pubkey)
var derivationPath = new uint[] { 44, 60, 0, 0, 0 };
// Hash the message and convert to MessageHash
var message = new byte[] { 0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe };
var msgHash = MessageHash.FromKeccak256(message);
// T parties join the signing room and perform the signing
var signature = await ecdsa.Sign(signingRoomUuid, secretShare, msgHash, derivationPath);
// The signature can be verified against the derived public key
using SodotSDK;
using SodotSDK.Ed25519;
// To sign a message, create a signing room on the server side, using your API_KEY
ushort T = 2; // We only need T signers (of our N total parties)
var myApiKey = "MY_API_KEY";
var hostUrl = "demo.sodot.dev"; // Your Relay URL
// Create the Ed25519 instance with your relay server hostURL
var ed25519 = new Ed25519(hostUrl);
// Create a room for signing
var signingRoomUuid = await ed25519.CreateRoom(T, myApiKey);
// Each participating party uses their secret share from key generation
var (_, secretShare) = await ed25519.Keygen(/*...*/);
// The derivation path to use for signing (same as used to generate the pubkey)
var derivationPath = new uint[] { 44, 60, 0, 0, 0 };
// The message to sign
var message = new byte[] { 0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe };
// T parties join the signing room and perform the signing
var signature = await ed25519.Sign(signingRoomUuid, secretShare, message, derivationPath);
// The signature can be verified against the derived public key
using SodotSDK;
using SodotSDK.Bip340;
// To sign a message, create a signing room on the server side, using your API_KEY
ushort T = 2; // We only need T signers (of our N total parties)
var myApiKey = "MY_API_KEY";
var hostUrl = "demo.sodot.dev"; // Your Relay URL
// Create the Bip340 instance with your relay server hostURL
var bip340 = new Bip340(hostUrl);
// Create a room for signing
var signingRoomUuid = await bip340.CreateRoom(T, myApiKey);
// Each participating party uses their secret share from key generation
var (_, secretShare) = await bip340.Keygen(/*...*/);
// The derivation path to use for signing (same as used to generate the pubkey)
var derivationPath = new uint[] { 44, 60, 0, 0, 0 };
// The message to sign
var message = new byte[] { 0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe };
// For BIP340, you can optionally use a tweak
var tweak = null // `null` for no tweak
// T parties join the signing room and perform the signing
var signature = await bip340.Sign(signingRoomUuid, secretShare, message, derivationPath, tweak);
// The signature can be verified against the derived public key
Additional Features
The Sodot Unity SDK provides additional advanced features, such as key refresh, key reshare, key import and export, etc. For more information on those features, please visit the Key Lifecycle page.
For full details on all available methods, refer to the SDK API Reference, also linked in the sidebar.