Precompute Sign
Precompute expensive signing material in advance, before a user needs to sign, so the final signature completes quickly.
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';
const messageHash = 'e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03';
export const preSign = 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,
};
const preSignature = await session.preSign(signConfig);
console.log('Pre computed signature:', preSignature);
// The signature is a Hex encoded string.
const preSignConfig = {
preSignHex: preSignature,
messageHash,
};
const signature = await session.finishPresign(preSignConfig);
console.log('Final Signature:', signature);
};
Pre sign flows two steps
- Precompute the signature of the message to be signed using the
preSignmethod.
- The
preSignmethod takes a EcdsaPreSignConfig object as an argument.keyshareis of type Keyshare and represents the client's share of the MPC wallet.
- The
preSignatureis the precomputed signature(Hex string) of the message to be signed.
- Finish the signature using the
finishPresignmethod.
- The
finishPresignmethod takes a EcdsaFinishPreSignConfig object as an argument.preSignHexis the precomputed signature from thepreSignmethod.messageHashis the hash of the message to be signed as a hex string.
- The
signatureis the ECDSA(EdDSA) 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
import 'package:silent_shard_sdk/silent_shard_sdk.dart' as sdk;
const messageHash =
'e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03';
Future<void> preSign(sdk.EcdsaSession session) async {
// Creating a new keyshare for demo purpose. In real application, you can use an existing keyshare.
final keyshare = await session.keygen();
print('Keyshare created, public key: ${keyshare.publicKeyHex}');
final preSign = await session.preSign(keyId: keyshare.keyId);
print('Pre computed signature: $preSign');
final signature = await session.finishPreSign(
messageHash: messageHash,
preSign: preSign,
);
print('Signature using pre-sign: $signature');
}
-
The
preSignmethod takes an argument.keyshareis of type DklsKeyshare and represents the client's share of the MPC wallet.
-
The
preSignatureis the precomputed signature (Uint8List) of the message to be signed. -
The
finishPresignmethod takes the following argument.preSignis the precomputed signature from thepreSignmethod.messageHashis the hash of the message to be signed as a hex string.
-
The
signatureis the ECDSA signature (hex string) ofmessageHash, corresponding to the public key (or address) of the wallet.
Presign allows the signing parties to offline precompute expensive signature material. Offline means before any active user needs to sign a specific message. By doing so the total running time for computing signatures is almost instant minimizing net work traffic load and computation demand.
We can finalise the precomputed signature with actual message later.
Step 1 : Create Session
- Create TrioSession if you haven't already.
Step 2 : Perform Precompute Signature
-
Call trioSession.preSign() which returns
ResultofSuccesswith Precompute SignatureByteArrayorFailurewith exception.trioSession.preSign(keyId = keyId).onSuccess { preComputedSignature ->
//todo: Do final signature later using preComputedSignature (lambda argument received here)
Log.i(
"PreComputeSignature","Success, Pre Computed Signature size : ${preComputedSignature.size}")
}.onFailure { failureReason ->
Log.e("PreComputeSignature", failureReason.message ?: "")
}keyIdis the identifier returned by keygen that addresses the client's keyshare.preComputedSignatureis the pre computed signature asByteArraywhich could later be used to perform final signature.
Step 3 : Finalise Precompute Signature (Later in the future)
-
Call trioSession.preSignFinal() which returns
ResultofSuccesswith the Final SignatureByteArrayorFailurewith exception.val messageHash = "e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03"
//preSign for context (Step 2)
trioSession.preSign(keyId = keyId).onSuccess { preComputedSignature ->
Log.i(
"PreComputeSignature","Success, Pre Computed Signature size : ${preComputedSignature.size}")
trioSession.preSignFinal(
preSignature = preComputedSignature, message = messageHash
).onSuccess { finalSignature ->
Log.i("PreSignatureFinal", "Success, Signature size : ${finalSignature.size}")
}.onFailure { reason ->
Log.e("PreSignatureFinal", reason.message ?: "")
}
}.onFailure { failureReason ->
Log.e("PreComputeSignature", failureReason.message ?: "")
}
}.onFailure { failureReason ->
Log.e("PreComputeSignature", failureReason.message ?: "")
}preComputedSignatureis the pre computed signature asByteArraygenerated in step 2.messageHashis the messageHash in Hex string without 0x suffix (absolute hex-string).
Example (Precompute Signature and Finalise Precomputed Signature)
val messageHash = "e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03"
suspend fun performPreComputeSignatureAndFinalisePreComputeSignature(
keyId: String,
trioSession: TrioSession,
): Result<ByteArray> {
//suspending operation
return withContext(Dispatchers.IO) {
//compute pre-signature
trioSession.preSign(keyId = keyId)
.onSuccess { preComputedSignature: ByteArray ->
//preSign success
Log.i(
"PreComputeSignature",
"Success, Pre Computed Signature size : ${preComputedSignature.size}"
)
//since preSign was success, we can now perform the signature (finalize pre-sign) with the message
trioSession.preSignFinal(
preSignature = preComputedSignature, message = messageHash,
derivationPath = "m" // This is the default, use your desired path here. For e.g 'm/1/2'
).onSuccess { finalSignature: ByteArray ->
//preSignFinal was a success
Log.i("PreSignatureFinal", "Success, Signature size : ${finalSignature.size}")
}.onFailure { reason: Throwable ->
//preSignFinal failed
Log.e("PreSignatureFinal", reason.message ?: "")
}
}
//preSign fail
.onFailure { failureReason: Throwable ->
Log.e("PreComputeSignature", failureReason.message ?: "")
}
}
}
keyIdis the identifier returned by keygen that addresses the client's keyshare.preComputedSignatureis the pre computed signature asByteArraywhich could later be used to perform final signature.messageHashis the messageHash in Hex string without 0x suffix (absolute hex-string).
- trioSession.preSign() performs message exchange between mobile and server to generate a pre computed ECDSA/EdDSA signature as ByteArray which is expected to be used to finalise the signature later with message.
- Result of trioSession.preSign() could be a
SuccesswithByteArray(ECDSA/EdDSA pre-computed signature), corresponding to the public key (or address) of the wallet orFailurewithException.
- trioSession.preSignFinal() performs message exchange between mobile and server to generate a ECDSA/EdDSA signature.
- Result of trioSession.preSignFinal() could be a
SuccesswithByteArray(ECDSA/EdDSA signature) ofmessageHash, corresponding to the public key (or address) of the wallet orFailurewithException.
Presign allows the signing parties to offline precompute expensive signature material. Offline means before any active user needs to sign a specific message. By doing so the total running time for computing signatures is almost instant minimizing net work traffic load and computation demand.
We can finalise the precomputed signature with actual message later.
Precompute signing (preSign / preSignFinal) is available for the ECDSA algorithm only.
Step 1 : Create Session
- Create TrioSession if you haven't already.
Step 2 : Perform Precompute Signature
-
Call trioSession.preSign() which returns
ResultofSuccesswith Precompute Signature bytes asDataorFailurewitherror.let result = await trioSession.preSign(keyId: keyId)
// returns nil if operation fails or other flow you might have
switch result {
case .success(let dataBytes):
do {
//todo: Do final signature later using preComputedSignature (lambda argument received here)
Swift.print("PreComputeSignature : Success, Pre Computed Signature size : \(dataBytes.count)")
return dataBytes
}
case .failure(let error):
do {
// show error to user or abort process
Swift.print(error)
return nil
}
}keyIdidentifies the client's key; the SDK loads the keyshare from your StorageClient using it.preComputedSignatureis the pre computed signature bytes asDatawhich could later be used to perform final signature.
Step 3 : Finalise Precompute Signature (Later in the future)
-
Call trioSession.preSignFinal() which returns
ResultofSuccesswith the Final Signature bytes asDataorFailurewitherror.
let messageHash = "e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03"
let result = await trioSession.preSign(keyId: keyId)
// returns nil if operation fails or other flow you might have
switch result {
case .success(let dataBytes):
do {
//todo: Do final signature later using preComputedSignature (lambda argument received here)
Swift.print("PreComputeSignature : Success, Pre Computed Signature size : \(dataBytes.count)")
let finalResult = await trioSession.preSignFinal(
preSignature: dataBytes,
message: messageHash
)
// returns nil if operation fails or other flow you might have
switch finalResult {
case .success(let finalSignatureBytes):
do {
Swift.print("PreSignatureFinal : Success, Signature size : \(finalSignatureBytes.count)")
return dataBytes
}
case .failure(let error):
do {
// show error to user or abort process
Swift.print(error)
return nil
}
}
}
case .failure(let error):
do {
// show error to user or abort process
Swift.print(error)
return nil
}
}preComputedSignatureis the pre computed signature bytes asDatagenerated in step 2.messageHashis the messageHash in Hex string without 0x suffix (absolute hex-string).
Example (Precompute Signature and Finalise Precomputed Signature)
let messageHash = "e2a159d17b7bb714aed7675d7c7d394dec8d2e4337842848104694bf89c71c03"
// preSign precomputes the message-independent part of a signature; preSignFinal
// turns it into a full signature once the message is known. ECDSA only.
func performPreSignAndFinalize(keyId: String, trioSession: TrioSession) async -> Data? {
// Compute the pre-signature.
let preSignResult = await trioSession.preSign(keyId: keyId)
switch preSignResult {
case .success(let preComputedSignature):
Swift.print("PreSign: success, size \(preComputedSignature.count)")
// Finalize the pre-signature with the actual message.
let finalResult = await trioSession.preSignFinal(
preSignature: preComputedSignature,
message: messageHash,
derivationPath: "m" // This is the default; use your desired path, e.g. "m/1/2"
)
switch finalResult {
case .success(let signature):
Swift.print("PreSignFinal: success, size \(signature.count)")
return signature
case .failure(let error):
// show the error to the user or abort the process
Swift.print(error)
return nil
}
case .failure(let error):
// show the error to the user or abort the process
Swift.print(error)
return nil
}
}
keyIdidentifies the client's key; the SDK loads the keyshare from your StorageClient using it.preComputedSignatureis the pre computed signature bytes asDatawhich could later be used to perform final signature.messageHashis the messageHash in Hex string without 0x suffix (absolute hex-string).
- trioSession.preSign() performs message exchange between mobile and server to generate a pre computed ECDSA signature byte as
Datawhich is expected to be used to finalise the signature later with message. - Result of trioSession.preSign() could be a
Successwith bytes asData(ECDSA pre-computed signature), corresponding to the public key (or address) of the wallet orFailurewitherror.
- trioSession.preSignFinal() performs message exchange between mobile and server to generate a ECDSA signature.
- Result of trioSession.preSignFinal() could be a
Successwith bytes asData(ECDSA signature) ofmessageHash, corresponding to the public key (or address) of the wallet orFailurewitherror.