Core Concepts

Please note that the signing functions are not exported from the SDK and are not intended to be used directly by developers. They are used internally by the SDK to sign messages and transactions. They are described here for information purposes.

FROST (Flexible Round-Optimized Schnorr Threshold Signatures)

FROST is a threshold signature scheme that allows a group of signers to collectively generate a signature without revealing their individual private keys. In Spark, we modified FROST to have a required participant.

KeyPackage

The KeyPackage struct holds the secret key, public key and the verifying key.

SigningCommitment

The SigningCommitment struct is a crucial component of the FROST protocol. It contains two public keys:

  • hiding: A public key used for hiding the signer’s nonce.
  • binding: A public key used for binding the commitment to the message being signed.

SigningNonce

The SigningNonce struct are used to sign a message, and is made of two private keys:

  • binding: A random private key used to ensure the nonce is unique to the binding key.
  • hiding: A random private key used to hide the signer’s nonce.

Key Operations

1. frost_nonce(key_package: KeyPackage): NonceResult

Generates a signing nonce and the associated signing commitment.

Parameters

  • key_package: The KeyPackage containing the secret key, public key, and verifying key.

Returns

  • NonceResult: An object containing the generated SigningNonce and SigningCommitment.

Usage

import { KeyPackage } from "./wasm/spark_bindings.js";
import { frost_nonce } from "./utils/wasm.js";
const keyPackage = new KeyPackage(secretKey, publicKey, verifyingKey);
const { nonce, commitment } = frost_nonce(keyPackage);

2. signFrost(params: SignFrostParams): Uint8Array

Generates a signature share using the FROST signing protocol.

Parameters

  • SignFrostParams: An object containing:
    • msg: The message to be signed (as a Uint8Array).
    • keyPackage: The secret and public keys to derive a signing key and verifying key.
    • nonce: The signing nonce.
    • selfCommitment: The signing commitment.
    • statechainCommitments: An optional object mapping statechain IDs to their respective signing commitments.
    • adaptorPubKey: An optional adaptor public key (as a Uint8Array).

Returns

  • Uint8Array: The generated signature share.

Usage

import { KeyPackage } from "./wasm/spark_bindings.js";
import { SigningCommitment, SigningNonce } from "./signer/signer.js";
import { signFrost, createWasmSigningNonce, createWasmSigningCommitment } from "./utils/wasm.js";

// Example usage:
const msg: Uint8Array = new Uint8Array();
const keyPackage: KeyPackage = new KeyPackage();
const nonce: SigningNonce = { hiding: new Uint8Array(), binding: new Uint8Array() };
const selfCommitment: SigningCommitment = { hiding: new Uint8Array(), binding: new Uint8Array() };

const signatureShare = signFrost({
    msg,
    keyPackage,
    nonce: createWasmSigningNonce(nonce),
    selfCommitment: createWasmSigningCommitment(selfCommitment),
});

3. aggregateFrost(params: AggregateFrostParams): Uint8Array

Aggregates multiple signature shares into a single, complete signature.

Parameters

  • AggregateFrostParams: An object containing:
    • msg: The message that was signed (as a Uint8Array).
    • statechainCommitments: An object mapping statechain IDs to their respective signing commitments.
    • selfCommitment: The signing commitment.
    • statechainSignatures: An object mapping statechain IDs to their respective signature shares.
    • selfSignature: The user’s signature share.
    • statechainPublicKeys: An object mapping statechain IDs to their respective public keys.
    • selfPublicKey: The user’s public key.
    • verifyingKey: The verifying key.
    • adaptorPubKey: An optional adaptor public key (as a Uint8Array).

Returns

  • Uint8Array: The aggregated signature.

Usage

import { SigningCommitment } from "./signer/signer.js";
import { aggregateFrost, createWasmSigningCommitment } from "./utils/wasm.js";

// Example usage:
const msg = new Uint8Array();
const statechainCommitments: { [key: string]: SigningCommitment } = {};
const selfCommitment: SigningCommitment = {
  hiding: new Uint8Array(),
  binding: new Uint8Array(),
};

const statechainSignatures: { [key: string]: Uint8Array } = {};
const selfSignature: Uint8Array = new Uint8Array();
const statechainPublicKeys: { [key: string]: Uint8Array } = {};
const selfPublicKey: Uint8Array = new Uint8Array();
const verifyingKey: Uint8Array = new Uint8Array();

const aggregatedSignature = aggregateFrost({
  msg,
  statechainSignatures,
  statechainPublicKeys,
  verifyingKey,
  statechainCommitments,
  selfCommitment: createWasmSigningCommitment(selfCommitment),
  selfSignature,
  selfPublicKey,
});

Usage in Spark SDK

The signing functions are integrated into the SparkWallet class and are used internally by various services like TransferService, DepositService, and LightningService. These functions provide the low-level cryptographic operations required for secure and private transactions within Spark.