Skip to main content
Platform

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 from its own share alone, 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

App.tsx
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';

// The full message to sign. The SDK digests it with the given hashAlgo before signing.
// For an EIP-1559 transaction this would be the RLP-encoded transaction bytes (hex).
const message =
'02ef0182012c843b9aca00850165a0bc008252089470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0';

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);
};

// Sign with hash: pass the full message and the hash algorithm; the SDK digests it before signing.
export const signWithHash = async (session: EcdsaSession) => {
const keyshare = await session.keygen();

const signConfig = {
keyshare,
message,
hashAlgo: 'KECCAK256',
} as const;
const signature = await session.signWithHash(signConfig);

console.log('Signature (with hash):', signature);
};

// Sign with hash & custom tags: attach a TLV stream read by the policy engine.
// Tag slot 0 carries the transaction type.
export const signWithHashAndTag = async (session: EcdsaSession) => {
const keyshare = await session.keygen();

const signConfig = {
keyshare,
message,
hashAlgo: 'KECCAK256',
customTags: {
0: 'eip1559',
},
} as const;
const signature = await session.signWithHash(signConfig);

console.log('Signature (with hash & custom tag):', signature);
};
  • The sign method takes a EcdsaSignConfig object as an argument.
  • keyshare(Keyshare) is the client's "share" of the MPC wallet.
  • messageHash is 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.
  • signature is the ECDSA signature (hex string) of messageHash, corresponding to the public key (or address) of the wallet.

Signing a full message

sign() sends a 32-byte hash, so the server only ever sees that hash — it cannot tell what the message actually says.

signWithHashEcdsaSignWithHashConfig

Available on EcdsaSession only. Instead of messageHash, pass:

  • message — the full message to sign, as a hex string. For an EIP-1559 transaction, this is the RLP-encoded unsigned transaction.
  • hashAlgo — one of KECCAK256, SHA256, SHA256D or HASH32. The SDK hashes message with it before signing, so the signature matches what sign() would have produced over that hash.

Because the server receives the whole message, it can apply transaction policies to it. EdDSA sessions do not have signWithHash.

customTagsSignCustomTags

Optional on every algorithm, with either sign() or signWithHash().

  • Keys are tag slots — integers from 0 to 63.
  • Each value is a non-empty UTF-8 string (up to 65536 bytes), or an array of strings to put several values in one slot.
  • Tags are encoded as a TLV stream into the signing setup message and delivered to your backend, which can act on them in its DSG hook.

What each slot means is defined by your backend, not by the SDK.

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:

ErrorWhat it meansHow to handle
Keyshares not in sync, run reconcileA previous operation didn't finish cleanly (for example the app was force-closed mid-operation)Run reconcile, then retry
Server errorA server ended the session unexpectedlyShow the error and offer a retry
Connection / transport errorA server was unreachable or the connection droppedShow the error and offer a retry

All of these operations are safe to retry from the start.