Skip to main content
Version: 1.6

Getting Started

Generate a key and begin signing in under a minute with the Sodot Kotlin 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:

Feature

BIP-340 (for Bitcoin Taproot), ECDSA, ED25519, SR25519, and Exportable ED25519 are all supported through the Kotlin SDK.

import com.sodot.kotlin_sdk.Ecdsa
import kotlinx.coroutines.runBlocking

// 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
val N = 3
val T = 2
val API_KEY = "MY_API_KEY"
val HOST_URL = "demo.sodot.dev" // Your Relay URL

runBlocking {
// Initialize the ECDSA scheme
val ecdsa = Ecdsa(HOST_URL)

// Create a room for key generation
val keygenRoomUuid = ecdsa.createRoom(HOST_URL, N, API_KEY)

// All parties call initKeygen to get initialization data that contains a public key and keypair
val keygenInitResult = ecdsa.initKeygen()

// All parties receive the keygenIds from all other parties
val keygenIds = arrayOf("keygenId1", "keygenId2", "keygenId3")

// All parties join the keygen room
val (pubkey, secretShare) = ecdsa.keygen(
keygenRoomUuid,
N,
T,
keygenInitResult.keypair,
keygenIds
)

// Pick the derivation path of the public key you want to sign for
val derivationPath = intArrayOf(44, 60, 0, 0, 0)

// Get the public key for the derivation path
val derivedPubkey = ecdsa.derivePubkey(secretShare, derivationPath)

// 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:

import com.sodot.kotlin_sdk.Ecdsa
import com.sodot.kotlin_sdk.MessageHash
import kotlinx.coroutines.runBlocking

// To sign a message, create a signing room on the server side, using your API_KEY
val T = 2 // We only need T signers (of our N total parties)
val API_KEY = "MY_API_KEY"
val HOST_URL = "demo.sodot.dev" // Your Relay URL

runBlocking {
// Initialize the ECDSA scheme
val ecdsa = Ecdsa(HOST_URL)

// Create a room for signing
val signingRoomUuid = ecdsa.createRoom(HOST_URL, T, API_KEY)

// Each participating party uses their secret share from key generation
val secretShare = "previously_stored_secret_share_from_keygen"

// The derivation path to use for signing (same as used to generate the pubkey)
val derivationPath = intArrayOf(44, 60, 0, 0, 0)

// Create a simple example message instead of random bytes
val messageBytes = "Example message to sign".toByteArray()
val messageHash = MessageHash.sha256(messageBytes)

// T parties join the signing room and perform the signing
val signature = ecdsa.sign(
signingRoomUuid,
secretShare,
messageHash,
derivationPath
)
}

Additional Features

The Sodot Kotlin SDK provides additional advanced features:

Key Refresh

You can refresh key shares without changing the underlying key:

// Example for ECDSA
val ecdsa = Ecdsa(HOST_URL)
val (pubkey, refreshedSecretShare) = ecdsa.refresh(roomUuid, secretShare)
// Use refreshedSecretShare instead of the old secretShare

// Example for ExportableEd25519
val exportableEd25519 = ExportableEd25519(HOST_URL)
val (pubkey, refreshedSecretShare) = exportableEd25519.refresh(roomUuid, secretShare)
// Use refreshedSecretShare instead of the old secretShare

Resharing for New Thresholds

You can change the threshold parameters by resharing:

// Example for a new party joining BIP340 resharing
val bip340 = Bip340(HOST_URL)
val oldThreshold = 2
val newThreshold = 3
val (pubkey, secretShare) = bip340.reshareNewParty(
roomUuid,
oldThreshold,
newThreshold,
keygenInitResult.keypair,
keygenIds
)

Key Import

You can import existing private keys into the MPC framework:

// Example for importing an ECDSA key (as the importer)
val ecdsa = Ecdsa(HOST_URL)
val privateKey = byteArrayOf(/* your private key bytes */)
val (pubkey, secretShare) = ecdsa.importPrivateKeyImporter(
roomUuid,
threshold,
privateKey,
keygenInitResult.keypair,
keygenIds
)

// Example for importing an ExportableEd25519 key (as the importer)
val exportableEd25519 = ExportableEd25519(HOST_URL)
val ed25519PrivateKey = byteArrayOf(/* your private key bytes */)
val (pubkey, secretShare) = exportableEd25519.importPrivateKeyImporter(
roomUuid,
threshold,
ed25519PrivateKey,
keygenInitResult.keypair,
keygenIds
)
API Reference

For full details on all available methods, refer to the SDK documentation for each cryptographic scheme object.