# 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](/cryptography/signature-scheme#what-is-a-threshold-signature-scheme) setting)

To generate a key we use the objects defined in the SDK:

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

<Tabs>
  <Tab title="ECDSA">
    ```kotlin
    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 = "us1.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(N, API_KEY)
        
        // All parties call initKeygen to get a keygenId and its matching private key
        val (keygenId, keygenPrivateKey) = 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, 
            keygenPrivateKey, 
            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
    }
    ```
  </Tab>

  <Tab title="ED25519">
    ```kotlin
    import com.sodot.kotlin_sdk.Ed25519
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the Ed25519 scheme
        val ed25519 = Ed25519(HOST_URL)

        // Create a room for key generation
        val keygenRoomUuid = ed25519.createRoom(N, API_KEY)
        
        // All parties call initKeygen to get a keygenId and its matching private key
        val (keygenId, keygenPrivateKey) = ed25519.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) = ed25519.keygen(
            keygenRoomUuid, 
            N, 
            T, 
            keygenPrivateKey, 
            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 = ed25519.derivePubkey(secretShare, derivationPath)
        
        // Option 2: Derive public key using Spub for more flexibility
        val spub = ed25519.getSpub(secretShare)
        val pubkeyFromSpub = ed25519.derivePubkeyFromSpub(spub, derivationPath)
        
        // Store secretShare securely for later use in signing
    }
    ```
  </Tab>

  <Tab title="SR25519">
    ```kotlin
    import com.sodot.kotlin_sdk.Sr25519
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the Sr25519 scheme
        val sr25519 = Sr25519(HOST_URL)

        // Create a room for key generation
        val keygenRoomUuid = sr25519.createRoom(N, API_KEY)
        
        // All parties call initKeygen to get a keygenId and its matching private key
        val (keygenId, keygenPrivateKey) = sr25519.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) = sr25519.keygen(
            keygenRoomUuid, 
            N, 
            T, 
            keygenPrivateKey, 
            keygenIds
        )
        
        // Pick the derivation path of the public key you want to sign for
        // Note: SR25519 uses string arrays for derivation paths, unlike numeric paths in other schemes
        val derivationPath = arrayOf("this", "is", "a", "derivation", "path")
        
        // Get the public key for the derivation path
        val derivedPubkey = sr25519.derivePubkey(secretShare, derivationPath)
        
        // Option 2: Derive public key using the base pubkey for more flexibility
        val basePubkey = sr25519.getPubkey(secretShare)
        val pubkeyFromBase = sr25519.derivePubkeyFromPubkey(basePubkey, derivationPath)
        
        // Store secretShare securely for later use in signing
    }
    ```
  </Tab>

  <Tab title="BIP340">
    ```kotlin
    import com.sodot.kotlin_sdk.BIP340
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the BIP340 scheme
        val bip340 = BIP340(HOST_URL)

        // Create a room for key generation
        val keygenRoomUuid = bip340.createRoom(N, API_KEY)
        
        // All parties call initKeygen to get a keygenId and its matching private key
        val (keygenId, keygenPrivateKey) = bip340.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) = bip340.keygen(
            keygenRoomUuid, 
            N, 
            T, 
            keygenPrivateKey, 
            keygenIds
        )
        
        // Pick the derivation path of the public key you want to sign for
        val derivationPath = intArrayOf(44, 60, 0, 0, 0)
        
        // For BIP340, you can optionally use a tweak
        val tweak: ByteArray? = null // null for no tweak, or provide a 32-byte tweak
        
        // Get the tweaked public key for the derivation path
        val derivedPubkey = bip340.deriveTweakPubkey(secretShare, derivationPath, tweak)
        
        // Option 2: Derive tweaked public key using Xpub for more flexibility
        val xpub = bip340.getXpub(secretShare)
        val pubkeyFromXpub = bip340.deriveTweakPubkeyFromXpub(xpub, derivationPath, tweak)
        
        // Store secretShare securely for later use in signing
    }
    ```
  </Tab>

  <Tab title="EXPORTABLE ED25519">
    ```kotlin
    import com.sodot.kotlin_sdk.ExportableEd25519
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the ExportableEd25519 scheme
        val exportableEd25519 = ExportableEd25519(HOST_URL)

        // Create a room for key generation
        val keygenRoomUuid = exportableEd25519.createRoom(N, API_KEY)
        
        // All parties call initKeygen to get a keygenId and its matching private key
        val (keygenId, keygenPrivateKey) = exportableEd25519.initKeygen()
        
        // All parties receive the keygenIds from all other parties
        val keygenIds = arrayOf("keygenId1", "keygenId2", "keygenId3")
        
        // For ExportableEd25519, there are two distinct key generation methods:
        // 1. For the party initiating the key generation (Party 1):
        val (pubkey1, secretShare1) = exportableEd25519.sampleKey(
            keygenRoomUuid, 
            N, 
            T, 
            keygenPrivateKey, 
            keygenIds
        )
        
        // 2. For parties receiving the key (Parties 2 and 3):
        val (pubkey2, secretShare2) = exportableEd25519.receiveKey(
            keygenRoomUuid, 
            N, 
            T, 
            keygenPrivateKey, 
            keygenIds
        )
        
        // Get the public key from a secret share
        val pubkeyFromShare = exportableEd25519.getPubkey(secretShare1)
        
        // Store secretShare securely for later use in signing
    }
    ```
  </Tab>
</Tabs>

Behind the scenes this is the rough flow of communication that occurs:

```mermaid
sequenceDiagram
    actor Alice
    actor Bob
    actor Charlie
    participant App as App Server
    rect rgb(200,200,230,.3)
    Note left of Alice: Keygen Setup
    App->>Relay: Create room for 3 participants
    Relay->>App: room_id
    App->>Alice: room_id
    App->>Bob: room_id
    App->>Charlie: room_id
    par Alice handshakes w/ Bob
    Note over Alice,Bob: Propagated externally to the SDK 
    Alice-->>Bob: keygen_id
    Bob-->>Alice: keygen_id
    and Alice handshakes w/ Charlie
    Note over Alice,Charlie: Propagated externally to the SDK
    Alice-->>Charlie: keygen_id
    Charlie-->>Alice: keygen_id
    and Bob handshakes w/ Charlie
    Note over Bob,Charlie: Propagated externally to the SDK
    Bob-->>Charlie: keygen_id
    Charlie-->>Bob: keygen_id
    end
    Alice->>Relay: Connect to room_id
    Bob->>Relay: Connect to room_id
    Charlie->>Relay: Connect to room_id
    end
    rect rgb(200,230,200,.3)
    Note left of Alice: Key Generation
    Note over Alice,Charlie: Run Distributed Key Generation
    activate Alice
    activate Bob
    activate Charlie
    Alice->>Relay: Relayed Communication
    Relay->>Alice: 
    Bob->>Relay: 
    Relay->>Bob: 
    Charlie->>Relay: 
    Relay->>Charlie: 
    Note over Alice: Alice has a Key Share
    deactivate Alice
    Note over Bob: Bob has a Key Share
    deactivate Bob
    Note over Charlie: Charlie has a Key Share
    deactivate Charlie
    end
```

## Signing

Now that we have key shares on all the devices/servers of the potential signers, we can sign by running:

<Tabs>
  <Tab title="ECDSA">
    ```kotlin
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the ECDSA scheme
        val ecdsa = Ecdsa(HOST_URL)
        
        // Create a room for signing
        val signingRoomUuid = ecdsa.createRoom(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
        )
    }
    ```
  </Tab>

  <Tab title="ED25519">
    ```kotlin
    import com.sodot.kotlin_sdk.Ed25519
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the Ed25519 scheme
        val ed25519 = Ed25519(HOST_URL)

        // Create a room for signing
        val signingRoomUuid = ed25519.createRoom(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)
        
        // The message to sign
        val messageBytes = "Example message to sign".toByteArray()
        
        // T parties join the signing room and perform the signing
        val signature = ed25519.sign(
            signingRoomUuid, 
            secretShare, 
            messageBytes, 
            derivationPath
        )
        
        // The signature can be verified against the public key
        println("Signature: ${signature.joinToString("") { "%02x".format(it) }}")
    }
    ```
  </Tab>

  <Tab title="SR25519">
    ```kotlin
    import com.sodot.kotlin_sdk.Sr25519
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the Sr25519 scheme
        val sr25519 = Sr25519(HOST_URL)

        // Create a room for signing
        val signingRoomUuid = sr25519.createRoom(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)
        // Note: SR25519 uses string arrays for derivation paths, unlike numeric paths in other schemes
        val derivationPath = arrayOf("this", "is", "a", "derivation", "path")
        
        // The message to sign
        val messageBytes = "Example message to sign".toByteArray()
        
        // T parties join the signing room and perform the signing
        val signature = sr25519.sign(
            signingRoomUuid, 
            secretShare, 
            messageBytes, 
            derivationPath
        )
        
        // The signature can be verified against the public key
        println("Signature: ${signature.joinToString("") { "%02x".format(it) }}")
    }
    ```
  </Tab>

  <Tab title="BIP340">
    ```kotlin
    import com.sodot.kotlin_sdk.BIP340
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the BIP340 scheme
        val bip340 = BIP340(HOST_URL)

        // Create a room for signing
        val signingRoomUuid = bip340.createRoom(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)
        
        // For BIP340, you can optionally use a tweak (same as used for pubkey derivation)
        val tweak: ByteArray? = null // null for no tweak, or provide a 32-byte tweak
        
        // The message to sign
        val messageBytes = "Example message to sign".toByteArray()
        
        // T parties join the signing room and perform the signing
        val signature = bip340.sign(
            signingRoomUuid, 
            secretShare, 
            messageBytes, 
            derivationPath,
            tweak
        )
        
        // The signature can be verified against the public key
        println("Signature: ${signature.joinToString("") { "%02x".format(it) }}")
    }
    ```
  </Tab>

  <Tab title="EXPORTABLE ED25519">
    ```kotlin
    import com.sodot.kotlin_sdk.ExportableEd25519
    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 = "us1.sodot.dev" // Your Relay URL

    runBlocking {
        // Initialize the ExportableEd25519 scheme
        val exportableEd25519 = ExportableEd25519(HOST_URL)

        // Create a room for signing
        val signingRoomUuid = exportableEd25519.createRoom(T, API_KEY)
        
        // Each participating party uses their secret share from key generation
        val secretShare = "previously_stored_secret_share_from_keygen"
        
        // The message to sign
        val messageBytes = "Example message to sign".toByteArray()
        
        // T parties join the signing room and perform the signing
        // Note: ExportableEd25519 signing doesn't use derivation paths
        val signature = exportableEd25519.sign(
            signingRoomUuid, 
            secretShare, 
            messageBytes
        )
        
        // The signature can be verified against the public key
        println("Signature: ${signature.joinToString("") { "%02x".format(it) }}")
    }
    ```
  </Tab>
</Tabs>

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:

```mermaid
sequenceDiagram
    actor Alice
    actor Bob
    actor Charlie
    participant App as App Server
    rect rgb(200,200,230,.3)
    Note left of Alice: Room Setup
    App->>Relay: Create room for 2 participants
    Relay->>App: room_id
    App->>Bob: room_id
    App->>Charlie: room_id
    par Bob invites Charlie
    Note over Bob,Charlie: Propagated externally to the SDK
    Bob-->>Charlie: msg
    Note over Charlie: Charlie decides whether they wish to sign msg
    end
    Bob->>Relay: Connect to room_id
    Charlie->>Relay: Connect to room_id
    end
    rect rgb(230,200,200,.3)
    Note left of Alice: Signing
    Note over Bob,Charlie: Run Signing
    activate Bob
    activate Charlie
    Bob->>Relay: Relayed Communication
    Relay->>Bob: 
    Charlie->>Relay: 
    Relay->>Charlie: 
    Note over Bob: Bob has a signature on msg
    deactivate Bob
    Note over Charlie: Charlie has a signature on msg
    deactivate Charlie
    end
```

## Additional Features

The Sodot Kotlin SDK provides additional advanced features:

### Key Refresh

You can refresh key shares without changing the underlying key:

```kotlin
// HOST_URL and secretShare are defined as in the examples above;
// roomUuid is a refresh room created on your server via createRoom(N, API_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:

```kotlin
// Example for a new party joining BIP340 resharing
// roomUuid is a reshare room created via createRoom(N, API_KEY); keygenPrivateKey comes from
// this party's initKeygen() and keygenIds are collected from all parties, as in Key Generation
val bip340 = BIP340(HOST_URL)
val oldThreshold = 2
val newThreshold = 3
val (pubkey, secretShare) = bip340.reshareNewParty(
    roomUuid,
    oldThreshold,
    newThreshold,
    keygenPrivateKey,
    keygenIds
)
```

### Key Import

You can import existing private keys into the MPC framework:

```kotlin
// roomUuid, threshold, keygenPrivateKey and keygenIds are established as in the examples above

// 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,
    keygenPrivateKey,
    keygenIds,
    null // chaincode: optionally provide a 32-byte BIP-32 chaincode
)

// 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,
    keygenPrivateKey,
    keygenIds
)
```

:::tip[API Reference]
For full details on all available methods, refer to the SDK documentation for each cryptographic scheme object.
:::
