DuoSession

A two-party threshold-signature session.

A DuoSession splits a private key between this party and one peer and signs without either side ever reconstructing the whole key — both must cooperate to produce a signature. It supports ECDSA (secp256k1) and EdDSA (Ed25519), with key generation, signing, refresh, import/export, backup verification, and deletion.

The keyId model

Session operations are addressed by an opaque keyId string, not by keyshare bytes. The SDK reads and writes the actual share through the StorageClient you supply at construction, so your code never holds raw keyshare material to sign, refresh, export, or delete. keygen and import return a keyId; the remaining operations take one.

The stateless helpers on the SilentShard facade — public-key, keyId, and child-key derivation — are the exception: they take keyshare bytes, which you read from your own StorageClient by keyId (see com.silencelaboratories.silentshard.duo.SilentShard.getKeysharePublicKey).

Usage

// Construct through the facade; see SilentShard.ECDSA.duoInitiator.
val session = SilentShard.ECDSA.duoInitiator(
messageSigner = myMessageSigner, // your hardware-backed identity key
cloudVerifyingKey = peerVerifyingKeyHex,
websocketConfig = WebsocketConfig(url = "wss://your-server.example.com"),
storageClient = myStorageClient, // the SDK persists keyshares here
)

// Generate a key. The share is written to your StorageClient; keep the keyId.
val keyId = session.keygen().getOrThrow()

// Sign a message hash (hex); derivationPath defaults to the root key.
val signature = session.sign(keyId, message = messageHashHex).getOrThrow()

All operations are suspend functions and perform network I/O; call them off the main thread. A session pairs with a peer session, and the two complete each operation together.

See also

for construction and stateless helpers.

for keyshare persistence.

for the staged/current keyshare lifecycle.

Properties

Link copied to clipboard

This party's identity verifying key, hex-encoded. Exchange it with the peer so each side can authenticate the other during a protocol run.

Functions

Link copied to clipboard
suspend fun delete(keyId: String): Result<Unit>

Deletes a stored key so its keyId no longer resolves to a keyshare.

Link copied to clipboard
suspend fun export(keyId: String, otherEncryptedKeyshare: ByteArray, hostEncryptionKey: ByteArray, otherDecryptionKey: ByteArray): Result<ByteArray>

Reconstructs the full private key by combining this party's share with the peer's — the way to move a key out of MPC, or to back it up.

Link copied to clipboard
suspend fun import(keysharePrivateKey: ByteArray, rootChainCode: String): Result<String>

Imports a private key into two-party MPC and returns the resulting keyId.

Link copied to clipboard
suspend fun keygen(): Result<String>

Generates a new distributed key through two-party MPC and returns its keyId.

Link copied to clipboard
suspend fun reconcile(keyId: String): Result<ByteArray>

Completes a staged keyshare, promoting it to the active share used for signing.

Link copied to clipboard
suspend fun refresh(keyId: String): Result<ByteArray>

Rotates the keyshares of an existing key without changing its public key.

Link copied to clipboard
suspend fun sign(keyId: String, message: String, derivationPath: String = "m"): Result<ByteArray>

Signs a message hash with two-party threshold signing.

Link copied to clipboard
suspend fun verifyBackup(keyId: String, backupData: ByteArray, rsaPublicKey: ByteArray, label: String = ""): Result<Boolean>

Verifies a signed backup against the signer's RSA public key.