Session creation
High level flow of the SDK
- Set up the WebSocket client to connect and communicate with the cloud node.
- Optional: set up a storage provider for keyshare persistence and sync. The SDK provides a default store; see Custom Storage Client to plug in your own.
- Optional: create a message signer to authenticate messages between the mobile app and the cloud node. See Message Signer.
- Start a new MPC session.
- Perform MPC actions.
The example uses the minimal setup. A custom storage provider and message signer are optional; the SDK falls back to sensible defaults, and the linked guides show how to plug in your own.
Create a new React Native project
Skip this section if you already have a React Native project.
npx @react-native-community/cli@latest init SilentMPC
After the project is created, install @silencelaboratories/silent-shard-sdk using the instructions from the Installation Guide
Start a new session
- ECDSA
- EdDSA
- MLDSA
import { CloudWebSocketClient } from '@silencelaboratories/silent-shard-sdk';
import { createEcdsaDuoSession } from '@silencelaboratories/silent-shard-sdk/ecdsa';
const CLOUD_NODE_URI = 'localhost:8080';
const cloudVerifyingKey = 'SERVER_PUBLIC_KEY_HEX';
const cloudClient = new CloudWebSocketClient(CLOUD_NODE_URI, false);
export const initSession = async () => {
const session = await createEcdsaDuoSession({
client: cloudClient,
cloudVerifyingKey: cloudVerifyingKey,
});
console.log('Session created successfully');
return session;
};
import { CloudWebSocketClient } from '@silencelaboratories/silent-shard-sdk';
import { createEddsaDuoSession } from '@silencelaboratories/silent-shard-sdk/eddsa';
const CLOUD_NODE_URI = 'localhost:8080';
const cloudVerifyingKey = 'SERVER_PUBLIC_KEY_HEX';
const cloudClient = new CloudWebSocketClient(CLOUD_NODE_URI, false);
export const initSession = async () => {
const session = await createEddsaDuoSession({
client: cloudClient,
cloudVerifyingKey: cloudVerifyingKey,
});
console.log('Session created successfully');
return session;
};
import { CloudWebSocketClient } from '@silencelaboratories/silent-shard-sdk';
import { createMldsaDuoSession } from '@silencelaboratories/silent-shard-sdk/mldsa';
const CLOUD_NODE_URI = 'localhost:8080';
const cloudVerifyingKey = 'SERVER_PUBLIC_KEY_HEX';
const cloudClient = new CloudWebSocketClient(CLOUD_NODE_URI, false);
export const initSession = async () => {
const session = await createMldsaDuoSession({
client: cloudClient,
cloudVerifyingKey: cloudVerifyingKey,
});
console.log('Session created successfully');
return session;
};```
-
CloudWebSocketClient: is a class that handles the WebSocket communication with the cloud node.
-
IStorageProvider: is a class manager for storing and retrieving MPC keyshares through a standardized interface.
-
MessageSigner: is a class that handles the signing of messages for secure communication between mobile and cloud node.
-
EcdsaSession: is the class that facilitates all actions for ECDSA wallets.
-
SessionConfig: is a configuration object that contains the necessary information for the session.
-
CLOUD_NODE_URIis the URI of the cloud node. -
cloudVerifyingKeyis the Hex encoded cloud verifying key (Ed25519 public key).- This public key is used to verify the server's signature on each message
- See example here
The session is now ready to run MPC operations such as keygen and sign.
High level flow of the SDK
- Set up the WebSocket client to connect and communicate with the cloud node.
- Optional: set up a storage provider for keyshare persistence and sync. The SDK provides a default store; see Custom Storage Client to plug in your own.
- Optional: create a message signer to authenticate messages between the mobile app and the cloud node. See Message Signer.
- Start a new MPC session.
- Perform MPC actions.
The example uses the minimal setup. A custom storage provider and message signer are optional; the SDK falls back to sensible defaults, and the linked guides show how to plug in your own.
Start a new session
- ECDSA
- EdDSA
- Taproot
import 'dart:io';
import 'package:silent_shard_sdk/silent_shard_sdk.dart' as sdk;
Future<sdk.EcdsaSession> setup([String cloudVerifyingKeyHex = 'SERVER_PUBLIC_KEY_HEX']) async {
/// The port number is the port number of the cloud node.
const port = 8080;
/// The nodeUri is the URI of the cloud node. It is the IP address of the cloud node.
/// Localhost url used for Android and iOS is shown below.
/// 10.0.2.2 is the IP address of the Android emulator.
/// 0.0.0.0 is the IP address of the iOS simulator.
final nodeUri = Platform.isAndroid ? '10.0.2.2:$port' : '0.0.0.0:$port';
final cloudClient = sdk.CloudClient(
baseUri: nodeUri,
isSecure: false,
);
final session = await sdk.createDuoEcdsaSession(
cloudClient: cloudClient,
cloudVerifyingKeyHex: cloudVerifyingKeyHex,
storageClient: sdk.SimpleStorageClient(),
);
return session;
}
import 'package:silent_shard_sdk/silent_shard_sdk.dart' as sdk;
Future<sdk.EddsaSession> setup(
[String cloudVerifyingKeyHex =
'01cfa1ff5424d14eb60614d7ddf65a32243d26ddf7000d10007853d7336395efe4']) async {
// Our hosted demo server — for quick testing. Run your own for production.
final cloudClient = sdk.CloudClient(
baseUri: 'demo-server.silencelaboratories.com',
isSecure: true,
);
final session = await sdk.createDuoEddsaSession(
cloudClient: cloudClient,
cloudVerifyingKeyHex: cloudVerifyingKeyHex,
storageClient: sdk.SimpleStorageClient(),
);
return session;
}
import 'dart:io';
import 'package:silent_shard_sdk/silent_shard_sdk.dart' as sdk;
Future<sdk.TaprootSession> setup([String cloudVerifyingKeyHex = 'SERVER_PUBLIC_KEY_HEX']) async {
/// The port number is the port number of the cloud node.
const port = 8080;
/// The nodeUri is the URI of the cloud node. It is the IP address of the cloud node.
/// Localhost url used for Android and iOS is shown below.
/// 10.0.2.2 is the IP address of the Android emulator.
/// 0.0.0.0 is the IP address of the iOS simulator.
final nodeUri = Platform.isAndroid ? '10.0.2.2:$port' : '0.0.0.0:$port';
final cloudClient = sdk.CloudClient(
baseUri: nodeUri,
isSecure: false,
);
final session = await sdk.createDuoTaprootSession(
cloudClient: cloudClient,
cloudVerifyingKeyHex: cloudVerifyingKeyHex,
storageClient: sdk.SimpleStorageClient(),
);
return session;
}
-
Initialize an ECDSA session with the EcdsaSession class.
-
CloudClient: is a class that handles the WebSocket communication with the cloud node.
-
SessionConfig: is a configuration object that contains the necessary information for the session.
-
CLOUD_NODE_URIis the URI of the cloud node. -
cloudVerifyingKeyis the Hex encoded cloud verifying key (Ed25519 public key).- This public key is used to verify the server's signature on each message
- See example here
The session is now ready to run MPC operations such as keygen and sign.
High level flow of DuoSession
- Configure/Implement transport layer NetworkClient
- Configure/Implement storage layer StorageClient
- Configure/Implement MessageSigner
- Create DuoSession
- Perform MPC actions
DuoSession is the main object which will be used to perform all of the MPC operations supported. To create DuoSession please follow the steps below.
Step 1 : Add library to your Project
-
Create new android studio project if you haven't.
-
Add SilentShard-Duo SDK using the instructions from the Installation Guide
Step 2 : Create new session
- We can Create DuoSession by calling SilentShard.ECDSA.duoInitiator() or SilentShard.EdDSA.duoInitiator() (whichever applies) by providing the following four parameters
- Provide websocket client by using any of the below options :
- Providing WebsocketConfig object to let SDK use default Network Client i.e. DuoNetworkClient.
- Providing custom NetworkClient overriding(extending) DuoNetworkClient to override existing connect, read or write, etc. methods to add your own logic/configuration or additional process.
- Provide cloud/server public key.
- Provide storage client. (You need to implement the interface StorageClient).
- Provide Message Signer (You need to implement the interface MessageSigner).
Example
- ECDSA
- EdDSA
import com.silencelaboratories.silentshard.duo.DuoSession
import com.silencelaboratories.silentshard.duo.SilentShard
import com.silencelaboratories.silentshard.network.websocket.WebsocketConfig
import com.silencelaboratories.silentshard.storage.KeyType
import com.silencelaboratories.silentshard.storage.StorageClient
import com.silencelaboratories.silentshard.storage.StorageDao
import com.silencelaboratories.silentshard.storage.silentshard.ReconcileStoreDao
import com.silencelaboratories.silentshard.utils.MessageSigner
object Constants {
// Replace with your own
const val CLOUD_NODE_URI = "demo-server.silencelaboratories.com"
// Replace with your own
const val PORT = 443
}
// Other party verifying-key/public-key. Replace with your own Verifying Key.
val cloudPublicKey = "cfa1ff5424d14eb60614d7ddf65a32243d26ddf7000d10007853d7336395efe4"
// Create websocketConfig to let SilentShard use the default WebsocketClient.
val websocketConfig = WebsocketConfig(url = Constants.CLOUD_NODE_URI, port = Constants.PORT, isSecure = true)
// Create a storageClient to persist keyshares. The SDK owns keyshare storage and
// addresses every share by its keyId — your code never holds raw keyshare bytes.
val storageClient = object : StorageClient {
// The algorithm family this client stores keyshares for. Provide a separate
// client (with a matching keyType) per algorithm if you run more than one.
override val keyType = KeyType.ECDSA
/**
* An in-memory database. In the real world this should be a SQL-based DB,
* secure storage, or custom hardware — it is up to the implementing app.
*/
private val entries = mutableMapOf<String, ReconcileStoreDao>()
override suspend fun write(dao: StorageDao) {
require(dao is ReconcileStoreDao) { "Expected ReconcileStoreDao" }
// Persist the whole snapshot, including any null fields.
entries[dao.keyId] = dao
}
override suspend fun read(key: String): StorageDao? = entries[key]
}
// Create a messageSigner backed by your secure key storage (TEE / Keystore).
val messageSigner = object : MessageSigner {
override val verifyingKey: ByteArray
get() = TODO("Public key of secure key (Secure Environment - TEE)")
override val keyType: MessageSigner.KeyType
get() = TODO("Type of secure key (Secure Environment - TEE)")
override suspend fun sign(data: ByteArray): ByteArray {
TODO("Sign data using secure key (Secure Environment - TEE) and return the signature")
}
}
// For quick-start you can use the test message signer. Do not use it in production.
val testMessageSigner = SilentShard.ECDSA.TestMessageSigner
// Create a DuoSession for the ECDSA algorithm
val duoSession: DuoSession = SilentShard.ECDSA.duoInitiator(
// pass your messageSigner instance in production; do not use testMessageSigner
testMessageSigner, cloudPublicKey, websocketConfig, storageClient
)
// Or create a DuoSession with your own network client by extending DuoNetworkClient:
// val duoSession: DuoSession = SilentShard.ECDSA.duoInitiator(
// testMessageSigner, cloudPublicKey, CustomDuoNetworkClient(), storageClient
// )
import com.silencelaboratories.silentshard.duo.DuoSession
import com.silencelaboratories.silentshard.duo.SilentShard
import com.silencelaboratories.silentshard.network.websocket.WebsocketConfig
import com.silencelaboratories.silentshard.storage.KeyType
import com.silencelaboratories.silentshard.storage.StorageClient
import com.silencelaboratories.silentshard.storage.StorageDao
import com.silencelaboratories.silentshard.storage.silentshard.ReconcileStoreDao
import com.silencelaboratories.silentshard.utils.MessageSigner
object Constants {
// Replace with your own
const val CLOUD_NODE_URI = "demo-server.silencelaboratories.com"
// Replace with your own
const val PORT = 443
}
// Other party verifying-key/public-key. Replace with your own Verifying Key.
val cloudPublicKey = "cfa1ff5424d14eb60614d7ddf65a32243d26ddf7000d10007853d7336395efe4"
// Create websocketConfig to let SilentShard use the default WebsocketClient.
val websocketConfig = WebsocketConfig(url = Constants.CLOUD_NODE_URI, port = Constants.PORT, isSecure = true)
// Create a storageClient to persist keyshares. The SDK owns keyshare storage and
// addresses every share by its keyId — your code never holds raw keyshare bytes.
val storageClient = object : StorageClient {
// The algorithm family this client stores keyshares for. Provide a separate
// client (with a matching keyType) per algorithm if you run more than one.
override val keyType = KeyType.EdDSA
/**
* An in-memory database. In the real world this should be a SQL-based DB,
* secure storage, or custom hardware — it is up to the implementing app.
*/
private val entries = mutableMapOf<String, ReconcileStoreDao>()
override suspend fun write(dao: StorageDao) {
require(dao is ReconcileStoreDao) { "Expected ReconcileStoreDao" }
// Persist the whole snapshot, including any null fields.
entries[dao.keyId] = dao
}
override suspend fun read(key: String): StorageDao? = entries[key]
}
// Create a messageSigner backed by your secure key storage (TEE / Keystore).
val messageSigner = object : MessageSigner {
override val verifyingKey: ByteArray
get() = TODO("Public key of secure key (Secure Environment - TEE)")
override val keyType: MessageSigner.KeyType
get() = TODO("Type of secure key (Secure Environment - TEE)")
override suspend fun sign(data: ByteArray): ByteArray {
TODO("Sign data using secure key (Secure Environment - TEE) and return the signature")
}
}
// For quick-start you can use the test message signer. Do not use it in production.
val testMessageSigner = SilentShard.EdDSA.TestMessageSigner
// Create a DuoSession for the EdDSA algorithm
val duoSession: DuoSession = SilentShard.EdDSA.duoInitiator(
// pass your messageSigner instance in production; do not use testMessageSigner
testMessageSigner, cloudPublicKey, websocketConfig, storageClient
)
// Or create a DuoSession with your own network client by extending DuoNetworkClient:
// val duoSession: DuoSession = SilentShard.EdDSA.duoInitiator(
// testMessageSigner, cloudPublicKey, CustomDuoNetworkClient(), storageClient
// )
CLOUD_NODE_URIis the URI of the cloud node.cloudPublicKeyis the cloud verifying key (Ed25519 public key).- This public key is used to verify the server's signature on each message
- See example here
- SilentShard Provides API for creating MPC DuoSession (Two-Party) using ECDSA algorithm.
- ECDSA Provides factory methods for creating MPC session using ECDSA algorithm.
- DuoSession Represents a two-party computation session that lets you perform MPC operations using SilentShard protocol.
The session is now ready to run MPC operations such as keygen and sign.
High level flow of DuoSession
- Configure/Implement transport layer DuoNetworkClient
- Configure/Implement storage layer StorageClient
- Configure/Implement MessageSigner
- Create DuoSession
- Perform MPC actions
DuoSession is the main object which will be used to perform all of the MPC operations supported. To create DuoSession please follow the steps below.
Step 1 : Add library to your Project
-
Create new xcode project if you haven't.
-
Add SilentShard-Duo SDK using the instructions from the Installation Guide
Step 2 : Create new session
- Import module - duoinitiator.
- We can Create DuoSession by calling SilentShard.ECDSA.duoInitiator() or SilentShard.EdDSA.duoInitiator() (whichever applies) by providing the following parameters
- Provide websocket client by using any of the below options :
- Providing WebsocketConfig object to let SDK use default NetworkClient i.e. DuoNetworkClient.
- Providing custom NetworkClient overriding(extending) DuoNetworkClient to override existing connect, read or write, etc. methods to add your own logic/configuration or additional process.
- Provide cloud/server public key.
- Provide storage client. (You need to implement the protocol StorageClient).
- Provide message signer. (You need to implement the protocol MessageSigner).
Example
- ECDSA
- EdDSA
import SwiftUI
import duo
struct ContentView: View {
var body: some View {
VStack {
// The demo server, over TLS.
let CLOUD_NODE_URI = "demo-server.silencelaboratories.com"
// Other party verifying-key/public-key. Replace with your own Verifying Key.
let cloudVerifyingKey = "cfa1ff5424d14eb60614d7ddf65a32243d26ddf7000d10007853d7336395efe4"
// Create websocketConfig to let SilentShard use the default WebsocketClient.
let websocketConfig = WebsocketConfig(url: CLOUD_NODE_URI, port: 443, isSecure: true)
// Create a storageClient to persist keyshares. The SDK owns keyshare
// storage and addresses every share by its keyId.
let storageClient = CustomStorageClient()
// Create a messageSigner to authenticate protocol messages. For quick-start
// we use the test signer; do not use TestECDSAMessageSigner in production.
// Provide your own MessageSigner backed by the Secure Enclave instead:
// let messageSigner = CustomMessageSigner()
// Create a DuoSession
let duoSession = SilentShard.ECDSA.duoInitiator(
// Do not use TestECDSAMessageSigner in production
messageSigner: TestECDSAMessageSigner(),
cloudVerifyingKey: cloudVerifyingKey,
websocketConfig: websocketConfig,
storageClient: storageClient
)
// or using a custom network client
// let duoSession = SilentShard.ECDSA.duoInitiator(
// messageSigner: TestECDSAMessageSigner(),
// cloudVerifyingKey: cloudVerifyingKey,
// networkClient: CustomNetworkClient(),
// storageClient: storageClient
// )
}
.padding()
}
}
#Preview {
ContentView()
}
import SwiftUI
import duo
struct ContentView: View {
var body: some View {
VStack {
// The demo server, over TLS.
let CLOUD_NODE_URI = "demo-server.silencelaboratories.com"
// Other party verifying-key/public-key. Replace with your own Verifying Key.
let cloudVerifyingKey = "cfa1ff5424d14eb60614d7ddf65a32243d26ddf7000d10007853d7336395efe4"
// Create websocketConfig to let SilentShard use the default WebsocketClient.
let websocketConfig = WebsocketConfig(url: CLOUD_NODE_URI, port: 443, isSecure: true)
// Create a storageClient to persist keyshares. The SDK owns keyshare
// storage and addresses every share by its keyId.
let storageClient = CustomStorageClient()
// Create a messageSigner to authenticate protocol messages. For quick-start
// we use the test signer; do not use TestEdDSAMessageSigner in production.
// Provide your own MessageSigner backed by the Secure Enclave instead:
// let messageSigner = CustomMessageSigner()
// Create a DuoSession
let duoSession = SilentShard.EdDSA.duoInitiator(
// Do not use TestEdDSAMessageSigner in production
messageSigner: TestEdDSAMessageSigner(),
cloudVerifyingKey: cloudVerifyingKey,
websocketConfig: websocketConfig,
storageClient: storageClient
)
// or using a custom network client
// let duoSession = SilentShard.EdDSA.duoInitiator(
// messageSigner: TestEdDSAMessageSigner(),
// cloudVerifyingKey: cloudVerifyingKey,
// networkClient: CustomNetworkClient(),
// storageClient: storageClient
// )
}
.padding()
}
}
#Preview {
ContentView()
}
CLOUD_NODE_URIis the URI of the cloud node.cloudVerifyingKeyis the cloud verifying key (Ed25519 public key).- This public key is used to verify the server's signature on each message
- See example here
- SilentShard Provides API for creating MPC DuoSession (Two-Party) using ECDSA algorithm.
- ECDSA Provides factory methods for creating MPC session using ECDSA algorithm.
- DuoSession Represents a two-party computation session that lets you perform MPC operations using SilentShard protocol.
The session is now ready to run MPC operations such as keygen and sign.