Quick Start
If you don't have have access to the docker image or don't have access to the iOS sdk repository, please contact us at info@silencelaboratories.com.
Here is how you can setup the Mobile SDK and perform MPC operations in less than a minute.
You will create a working MPC two-party setup, where the first party, an iOS application interacts with Trio Server as a second party, and a third party.
Prerequisites
For quick testing, the demo server is already deployed at trio-server.demo.silencelaboratories.com. We are using this server for the quickstart guide.
The Cloud Verifying Key for the demo server is 019c4c79e942bbc3ff1d6ace7256404d701498056978cc4638c35832acdf821b1e.
The Cloud Node Endpoint for the demo server is https://trio-server.demo.silencelaboratories.com.
Setup the Mobile SDK (iOS)
Create a new XCode project by following the official guide or use existing one.
Dependency Installation
Session Creation
Instantiate TrioSession object, which could be used to perform all of the supported MPC operations such as keygen, sign etc.
import trioinitiator
class CustomStorageClient: StorageClient {
/*
* Representing in-memory database. In real world it should be some SQL based DB or
* secure storage or custom hardware. It's up to the implementation app's use-case.
*/
private var keyshareDaoSet: Set<ReconcileStoreDao> = []
func write(dao: ReconcileStoreDao) async {
if !keyshareDaoSet.insert(dao).inserted {
keyshareDaoSet.remove(dao)
keyshareDaoSet.insert(dao)
}
}
func read(key: String) async throws -> ReconcileStoreDao? {
return keyshareDaoSet.first { $0.keyId == key }
}
}
import SwiftUI
import trioinitiator
import Combine
struct ContentView: View {
var body: some View {
VStack {
let CLOUD_NODE_URI = "wss://trio-server.demo.silencelaboratories.com"
//Other party verifying-key/public-key
let cloudVerifyingKey = "9c4c79e942bbc3ff1d6ace7256404d701498056978cc4638c35832acdf821b1e"
//Create websocketConfig to let SilentShard use default WebsocketClient.
let websocketConfig = WebsocketConfig(
url: CLOUD_NODE_URI,
)
//Create storage client instance to manage keyshare state
let storageClient = CustomStorageClient()
//Create duoSession
/*
We only have to pass websocketConfig which contains the server config and
communication will be handled by internal websocketClient*/
let duoSession = SilentShard.ECDSA.createTrioSession(
messageSigner: TestECDSAMessageSigner(),
cloudVerifyingKey: String(
cloudVerifyingKey
),
websocketConfig: websocketConfig,
storageClient: storageClient
)
/*
//or for EdDSA algorithm
let duoSession = SilentShard.EdDSA.createDuoSession(
messageSigner: TestECDSAMessageSigner(),
cloudVerifyingKey: String(cloudVerifyingKey),
websocketConfig: websocketConfig,
storageClient: storageClient)
*/
Run the MPC operations
After creating the session, you can perform MPC operations.
Key Generation
Generate MPC keyshares and return the client keyshare with keygen method.
let result: Result<Data, any Error> = await trioSession.keygen()
switch result {
case .success(let dataBytes):
do {
// do something with keyshare dataBytes
Swift.print(dataBytes)
return dataBytes
}
case .failure(let error):
do {
// show error to user or abort process
Swift.print(error)
return nil
}
}
Signature Generation
Sign a message using the signature method.
let messageHash = "53c48e76b32d4fb862249a81f0fc95da2d3b16bf53771cc03fd512ef5d4e6ed9"
let result = await trioSession.signature(
keyshare: keyshare,
message: messageHash,
chainPath: "m" // This is the default, use your desired path here. For e.g 'm/1/2'
)
switch result {
case .success(let dataBytes):
do {
// do something with signature dataBytes
Swift.print(dataBytes)
return dataBytes
}
case .failure(let error):
do {
// show error to user or abort process
Swift.print(error)
return nil
}
}
Complete Code Example
import trioinitiator
class CustomStorageClient: StorageClient {
/*
* Representing in-memory database. In real world it should be some SQL based DB or
* secure storage or custom hardware. It's up to the implementation app's use-case.
*/
private var keyshareDaoSet: Set<ReconcileStoreDao> = []
func write(dao: ReconcileStoreDao) async {
if !keyshareDaoSet.insert(dao).inserted {
keyshareDaoSet.remove(dao)
keyshareDaoSet.insert(dao)
}
}
func read(key: String) async throws -> ReconcileStoreDao? {
return keyshareDaoSet.first { $0.keyId == key }
}
}
import trioinitiator
import Foundation
class CustomMessageSigner : MessageSigner {
//Public-key of Private-Key stored in Secure Enclave
var verifyingKey: Data
//KeyType of Private-Key
var keyType: duoinitiator.KeyType
//Message signer; silentshard calls it to sign
func sign(_ data: Data) -> Data {
<#code#>
}
}
import SwiftUI
import trioinitiator
import Combine
struct ContentView: View {
var body: some View {
VStack {
let CLOUD_NODE_URI = "wss://trio-server.demo.silencelaboratories.com"
//Other party verifying-key/public-key
let cloudVerifyingKey = "019c4c79e942bbc3ff1d6ace7256404d701498056978cc4638c35832acdf821b1e"
//Create websocketConfig to let SilentShard use default WebsocketClient.
let websocketConfig = WebsocketConfig(
url: CLOUD_NODE_URI,
)
//Create storage client instance to manage keyshare state
let storageClient = CustomStorageClient()
//Create duoSession
/*
We only have to pass websocketConfig which contains the server config and
communication will be handled by internal websocketClient*/
let duoSession = SilentShard.ECDSA.createTrioSession(
messageSigner: TestECDSAMessageSigner(),
cloudVerifyingKey: String(
cloudVerifyingKey
),
websocketConfig: websocketConfig,
storageClient: storageClient
)
/*
//or for EdDSA algorithm
let duoSession = SilentShard.EdDSA.createDuoSession(
messageSigner: TestECDSAMessageSigner(),
cloudVerifyingKey: String(cloudVerifyingKey),
websocketConfig: websocketConfig,
storageClient: storageClient)
*/
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
Button("Tap me") {
Task {
let result: Result<Data, any Error> = await duoSession.keygen()
switch result {
case .success(let keyshareDataBytes):
do {
// do something with keyshare dataBytes
let messageHash = "53c48e76b32d4fb862249a81f0fc95da2d3b16bf53771cc03fd512ef5d4e6ed9"
let signatureResult = await duoSession.signature(
keyshare: keyshareDataBytes,
message: messageHash,
chainPath: "m" // This is the default, use your desired path here. For e.g 'm/1/2'
)
switch signatureResult {
case .success(let signatureDataBytes):
do {
// do something with signature dataBytes
Swift.print(signatureDataBytes)
return signatureDataBytes
}
case .failure(let error):
do {
// show error to user or abort process
Swift.print(error)
return Data()
}
}
}
case .failure(let error):
do {
// show error to user or abort process
Swift.print(error)
return Data()
}
}
}
}
}
.padding()
}
}
#Preview {
ContentView()
}
Once the app launches, check your console logs to see the key generation and signing process updates in real-time.