Getting Started
Generate a key and begin signing in under a minute with the Sodot Swift 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 Swift SDK.
- ECDSA
- ED25519
- BIP340
import SodotSdk
// 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
let N = UInt16(3)
let T = UInt16(2)
let API_KEY = "MY_API_KEY"
let HOST_URL = "demo.sodot.dev" // Your Relay URL
// Create the Ecdsa class with your relay server hostURL
let ecdsa = Ecdsa(hostURL: HOST_URL)
// Create a room for key generation
let keygenRoomUuid = try await ecdsa.createRoom(numParties: N, apiKey: API_KEY)
// All parties call initKeygen to get initialization data that contains a public key and keypair
let (keygenId, keygenSecret) = try ecdsa.initKeygen()
// All parties receive the keygenIds from all other parties
let keygenIds = ["keygenId1", "keygenId2", "keygenId3"]
// All parties join the keygen room
let (publicKey, secretShare) = try await ecdsa.keygen(
roomUUID: keygenRoomUuid,
numParties: N,
threshold: T,
keygenInitKeypair: keygenSecret,
keygenIds: keygenIds
)
// Pick the derivation path of the public key you want to sign for
let derivationPath = [UInt32]([44, 60, 0, 0, 0])
// Get the public key for the derivation path
let pubkey = try ecdsa.derivePubkey(secretShare: secretShare, derivationPath: derivationPath)
// Store keygenResult.secretShare securely for later use in signing
import SodotSdk
// 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
let N = UInt16(3)
let T = UInt16(2)
let API_KEY = "MY_API_KEY"
let HOST_URL = "demo.sodot.dev" // Your Relay URL
// Create the Ed25519 class with your relay server hostURL
let ed25519 = Ed25519(hostURL: HOST_URL)
// Create a room for key generation
let keygenRoomUuid = try await ed25519.createRoom(numParties: N, apiKey: API_KEY)
// All parties call initKeygen to get initialization data that contains a public key and keypair
let (keygenId, keygenSecret) = try ed25519.initKeygen()
// All parties receive the keygenIds from all other parties
let keygenIds = ["keygenId1", "keygenId2", "keygenId3"]
// All parties join the keygen room
let (publicKey, secretShare) = try await ed25519.keygen(
roomUUID: keygenRoomUuid,
numParties: N,
threshold: T,
keygenInitKeypair: keygenSecret,
keygenIds: keygenIds
)
// Pick the derivation path of the public key you want to sign for
let derivationPath = [UInt32]([44, 60, 0, 0, 0])
// Get the public key for the derivation path
let pubkey = try ed25519.derivePubkey(secretShare: secretShare, derivationPath: derivationPath)
// Store keygenResult.secretShare securely for later use in signing
import SodotSdk
// 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
let N = UInt16(3)
let T = UInt16(2)
let API_KEY = "MY_API_KEY"
let HOST_URL = "demo.sodot.dev" // Your Relay URL
// Create the Bip340 class with your relay server hostURL
let bip340 = Bip340(hostURL: HOST_URL)
// Create a room for key generation
let keygenRoomUuid = try await bip340.createRoom(numParties: N, apiKey: API_KEY)
// All parties call initKeygen to get initialization data that contains a public key and keypair
let (keygenId, keygenSecret) = try bip340.initKeygen()
// All parties receive the keygenIds from all other parties
let keygenIds = ["keygenId1", "keygenId2", "keygenId3"]
// All parties join the keygen room
let (publicKey, secretShare) = try await bip340.keygen(
roomUUID: keygenRoomUuid,
numParties: N,
threshold: T,
keygenInitKeypair: keygenSecret,
keygenIds: keygenIds
)
// Pick the derivation path of the public key you want to sign for
let derivationPath = [UInt32]([44, 60, 0, 0, 0])
// For BIP340, you can optionally use a tweak
let tweak = nil // `nil` for no tweak
// Get the public key for the derivation path
let pubkey = try bip340.deriveTweakPubkey(secretShare: secretShare, derivationPath: derivationPath, tweak: tweak)
// Store keygenResult.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
import SodotSdk
// To sign a message, create a signing room on the server side, using your API_KEY
let T = UInt16(2) // We only need T signers (of our N total parties)
let API_KEY = "MY_API_KEY"
let HOST_URL = "demo.sodot.dev" // Your Relay URL
// Create the Ecdsa class with your relay server hostURL
let ecdsa = Ecdsa(hostURL: HOST_URL)
// Create a room for signing
let signingRoomUuid = try await ecdsa.createRoom(numParties: T, apiKey: API_KEY)
// Each participating party uses their secret share from key generation
let secretShare = "previously_stored_secret_share_from_keygen"
// The derivation path to use for signing (same as used to generate the pubkey)
let derivationPath = [UInt32]([44, 60, 0, 0, 0])
// Hash the message and convert to MessageHash
let message = Data([1,2,3,4])
let messageHash = MessageHash(sha256: message)
// T parties join the signing room and perform the signing
let signature = try await ecdsa.sign(
roomUUID: signingRoomUuid,
secretShare: secretShare,
message: messageHash,
derivationPath: derivationPath
)
// The signature can be verified against the public key
print("Signature: \(signature)")
import SodotSdk
// To sign a message, create a signing room on the server side, using your API_KEY
let T = UInt16(2) // We only need T signers (of our N total parties)
let API_KEY = "MY_API_KEY"
let HOST_URL = "demo.sodot.dev" // Your Relay URL
// Create the Ed25519 class with your relay server hostURL
let ed25519 = Ed25519(hostURL: HOST_URL)
// Create a room for signing
let signingRoomUuid = try await ed25519.createRoom(numParties: T, apiKey: API_KEY)
// Each participating party uses their secret share from key generation
let secretShare = "previously_stored_secret_share_from_keygen"
// The derivation path to use for signing (same as used to generate the pubkey)
let derivationPath = [UInt32]([44, 60, 0, 0, 0])
// The message to sign
let messageData = Data([1,2,3,4])
// T parties join the signing room and perform the signing
let signature = try await ed25519.sign(
roomUUID: signingRoomUuid,
secretShare: secretShare,
message: messageData,
derivationPath: derivationPath
)
// The signature can be verified against the public key
print("Signature: \(signature)")
import SodotSdk
// To sign a message, create a signing room on the server side, using your API_KEY
let T = UInt16(2) // We only need T signers (of our N total parties)
let API_KEY = "MY_API_KEY"
let HOST_URL = "demo.sodot.dev" // Your Relay URL
// Create the Bip340 class with your relay server hostURL
let bip340 = Bip340(hostURL: HOST_URL)
// Create a room for signing
let signingRoomUuid = try await bip340.createRoom(numParties: T, apiKey: API_KEY)
// Each participating party uses their secret share from key generation
let secretShare = "previously_stored_secret_share_from_keygen"
// The derivation path to use for signing (same as used to generate the pubkey)
let derivationPath = [UInt32]([44, 60, 0, 0, 0])
// For BIP340, you can optionally use a tweak (same as used for pubkey derivation)
let tweak = nil // `nil` for no tweak
// The message to sign
let messageData = Data([1,2,3,4])
// T parties join the signing room and perform the signing
let signature = try await bip340.sign(
roomUUID: signingRoomUuid,
secretShare: secretShare,
message: messageData,
derivationPath: derivationPath,
tweak: tweak
)
// The signature can be verified against the public key
print("Signature: \(signature)")
Additional Features
The Sodot Swift 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.