Sign
Produce a signature over a message hash. The user's device and the first cloud node run a distributed signing protocol, each contributing a partial computation using only its own share, to jointly produce a single, standard signature. The full private key is never reassembled.
Please refer to the Session creation section to learn how to create a new session.
Full example
- ECDSA
- EdDSA
import { type EcdsaSession } from '@silencelaboratories/silent-shard-sdk/ecdsa';
// This could be a hash digest of any message you want to sign.
// For example, for the Ethereum transaction signing, you would use the keccak256 hash of the transaction data.
const messageHash = 'e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03';
export const signGen = async (session: EcdsaSession) => {
// Creating a new keyshare for demo purpose. In real application, you can use an existing keyshare.
const keyshare = await session.keygen();
const signConfig = {
keyshare,
messageHash,
};
const signature = await session.sign(signConfig);
console.log('Signature:', signature);
};
import { type EddsaSession } from '@silencelaboratories/silent-shard-sdk/eddsa';
const messageHash = 'e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03';
export const signGen = async (session: EddsaSession) => {
// Creating a new keyshare for demo purpose. In real application, you can use an existing keyshare.
const keyshare = await session.keygen();
const signConfig = {
keyshare,
messageHash,
};
const signature = await session.sign(signConfig);
console.log('Signature:', signature);
};
- The
signmethod takes a EcdsaSignConfig object as an argument. keyshare(Keyshare) is the client's "share" of the MPC wallet.messageHashis the hash of the message to be signed as a hex string.- When
session.sign()is called, the app and the server exchange messages to generate an ECDSA signature. signatureis the ECDSA signature (hex string) ofmessageHash, corresponding to the public key (or address) of the wallet.
Please refer to the Session creation section to learn how to create a new session.
Full example
- ECDSA
- EdDSA
- Taproot
import 'dart:typed_data';
import 'package:silent_shard_sdk/silent_shard_sdk.dart' as sdk;
// This could be a hash digest of any message you want to sign.
// For example, for the Ethereum transaction signing, you would use the keccak256 hash of the transaction data.
const messageHash =
'e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03';
Future<Uint8List> signGen(sdk.EcdsaSession session) async {
// Creating a new keyshare for demo purpose. In real application, you can use an existing keyshare.
final sdk.DklsKeyshare keyshare = await session.keygen();
print('Keyshare created, public key: ${keyshare.publicKeyHex}');
final signature = await session.sign(
keyId: keyshare.keyId,
messageHash: messageHash,
);
print('Signature: $signature');
return signature;
}
import 'package:silent_shard_sdk/silent_shard_sdk.dart' as sdk;
// This could be a hash digest of any message you want to sign.
// For example, for the Ethereum transaction signing, you would use the keccak256 hash of the transaction data.
const messageHash =
'e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03';
Future<void> signGen(sdk.EddsaSession session) async {
// Creating a new keyshare for demo purpose. In real application, you can use an existing keyshare.
final sdk.SchnorrKeyshare keyshare = await session.keygen();
print('Keyshare created, public key: ${keyshare.publicKeyHex}');
final signature = await session.sign(
keyId: keyshare.keyId,
messageHash: messageHash,
);
print('Signature: $signature');
}
import 'dart:typed_data';
import 'package:silent_shard_sdk/silent_shard_sdk.dart' as sdk;
// This could be a hash digest of any message you want to sign.
// For Bitcoin Taproot transactions, this is the sighash as defined in BIP 341.
const messageHash =
'5ae9337fe6b54559bf2c16aea4472f8f8cfab3cfa6844547801fb8c752151552';
Future<Uint8List> signGen(sdk.TaprootSession session) async {
// Creating a new keyshare for demo purpose. In real application, you can use an existing keyshare.
final sdk.TaprootKeyshare keyshare = await session.keygen();
print('Keyshare created, public key: ${keyshare.publicKeyHex}');
final signature = await session.sign(
keyId: keyshare.keyId,
messageHash: messageHash,
);
print('Signature: $signature');
return signature;
}
- DklsKeyshare is the client's "share" of the MPC wallet.
messageHashis the hash of the message to be signed as a hex string.- When
session.sign()is called, the app and the server exchange messages to generate an ECDSA signature. signatureis the signature (hex string) ofmessageHash, corresponding to the public key (or address) of the wallet.
This distributed signing process allows for secure transaction authorization while preserving the key's distributed nature, exemplifying the MPC wallet's enhanced security model.
Step 1 : Create Session
- Create TrioSession if you haven't already.
Step 2 : Perform Sign
- Call trioSession.sign() which returns Result of Success with Signature ByteArray or Failure with exception.
Example
val messageHash = "e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03"
// Sign the message hash with the key addressed by keyId (returned from keygen/import).
suspend fun performSignature(keyId: String, trioSession: TrioSession): ByteArray {
return withContext(Dispatchers.IO) {
trioSession.sign(
keyId = keyId,
message = messageHash,
derivationPath = "m" // This is the default; use your desired path, e.g. "m/1/2"
).getOrThrow()
}
}
keyIdis the identifier returned by keygen that addresses the client's keyshare in your storage.messageHashis the hash of the message to be signed asByteArray.- trioSession.sign() performs message exchange between mobile and server to generate a ECDSA/EdDSA signature.
- Result of trioSession.sign() could be a
SuccesswithByteArray(ECDSA/EdDSA signature) ofmessageHash, corresponding to the public key (or address) of the wallet orFailurewithException.
This distributed signing process allows for secure transaction authorization while preserving the key's distributed nature, exemplifying the MPC wallet's enhanced security model.
Step 1 : Create Session
- Create TrioSession if you haven't already.
Step 2 : Perform Sign
- Call trioSession.sign() which returns
ResultofSuccesswithSignaturebytes asDataor Failure witherror.
Example
let MESSAGE_HASH = "53c48e76b32d4fb862249a81f0fc95da2d3b16bf53771cc03fd512ef5d4e6ed9"
// Sign the message hash with the key addressed by keyId (from keygen/import).
func performSignature(keyId: String, trioSession: TrioSession) async -> Data? {
let result = await trioSession.sign(
keyId: keyId, message: MESSAGE_HASH,
derivationPath: "m" // This is the default; use your desired path, e.g. "m/1/2"
)
// returns nil if the operation fails, or handle it however your flow needs
switch result {
case .success(let signatureBytes):
// do something with the signature bytes
Swift.print(signatureBytes)
return signatureBytes
case .failure(let error):
// show the error to the user or abort the process
Swift.print(error)
return nil
}
}
keyIdidentifies the client's key (fromkeygen/import); the SDK loads the keyshare from your StorageClient using it.messageHashis the hash of the message to be signed as a hexString.- trioSession.sign() performs message exchange between mobile and server to generate a ECDSA/EdDSA signature.
- Result of trioSession.sign() could be a
SuccesswithData(ECDSA/EdDSA signature) ofmessageHash, corresponding to the public key (or address) of the wallet orFailurewitherror.
Handling the operation
This is an MPC operation, so it takes a few seconds (the app and the Trio nodes exchange several messages). Show a non-blocking loading state while it runs, confirm on success, and offer a retry on failure. When something goes wrong, the SDK surfaces the error for you to handle:
| Error | What it means | How to handle |
|---|---|---|
| Keyshares not in sync, run reconcile | A previous operation didn't finish cleanly (for example the app was force-closed mid-operation) | Run reconcile, then retry |
| Server error | A server ended the session unexpectedly | Show the error and offer a retry |
| Connection / transport error | A server was unreachable or the connection dropped | Show the error and offer a retry |
All of these operations are safe to retry from the start.