Learn how to implement and use the Spark Signer interface for cryptographic operations. This guide covers the complete SparkSigner interface, key management, and advanced cryptographic features.
The Spark SDK provides the SparkSigner interface to enable flexible implementation of signing operations. This abstraction allows you to customize how cryptographic operations are performed and enables support for different signing strategies including multisig configurations, hardware wallets, and other specialized key management systems.
The SDK includes a default implementation (DefaultSparkSigner) that handles standard single-signature operations. This can serve as a reference for implementing custom signers that support multisig, hardware wallets, or other advanced signing schemes.
Core Concepts
Key Types
Identity Key Primary wallet identifier used for authentication and Spark Address generation
Signing Keys Derived keys for specific transaction outputs and operations
Deposit Keys Keys for receiving L1 Bitcoin deposits
Static Deposit Keys Reusable keys for deposit operations
Security Model
All private keys are derived from a master seed using BIP32 hierarchical deterministic key derivation. The signer maintains an internal mapping between public keys and their corresponding private keys, ensuring secure access control.
Wallet Initialization
Generate Mnemonic
generateMnemonic()
Generates a new BIP39 mnemonic phrase for wallet creation.
const mnemonic = await signer . generateMnemonic ();
console . log ( mnemonic ); // "abandon ability able about above absent..."
A 12-word BIP39 mnemonic phrase
Convert Mnemonic to Seed
mnemonicToSeed(mnemonic)
Converts a BIP39 mnemonic phrase to a cryptographic seed.
const seed = await signer . mnemonicToSeed ( mnemonic );
console . log ( "Seed length:" , seed . length ); // 64 bytes
Valid BIP39 mnemonic phrase
seed
Promise<Uint8Array>
required
64-byte seed derived from the mnemonic
Initialize from Seed
createSparkWalletFromSeed(seed, accountNumber?)
Initializes the signer with a master seed and derives all necessary keys.
const seed = await signer . mnemonicToSeed ( mnemonic );
const identityPubKey = await signer . createSparkWalletFromSeed ( seed , 0 );
console . log ( "Identity public key:" , identityPubKey );
seed
Uint8Array | string
required
Master seed as bytes or hex string
Account index for key derivation
Hex-encoded identity public key
Key Management
Get Identity Public Key
getIdentityPublicKey()
Retrieves the wallet’s identity public key.
const identityKey = await signer . getIdentityPublicKey ();
console . log ( "Identity key:" , identityKey );
identityKey
Promise<Uint8Array>
required
The identity public key
Get Master Public Key
getMasterPublicKey()
Retrieves the master public key.
const masterKey = await signer . getMasterPublicKey ();
console . log ( "Master public key:" , masterKey );
masterKey
Promise<Uint8Array>
required
The master public key
Generate Public Key
generatePublicKey(hash?)
Generates a new signing key pair and returns the public key.
const publicKey = await signer . generatePublicKey ();
console . log ( "Generated public key:" , publicKey );
// With deterministic hash
const hash = new Uint8Array ( 32 );
const deterministicKey = await signer . generatePublicKey ( hash );
Deterministic hash for key derivation
publicKey
Promise<Uint8Array>
required
The generated public key
Remove Public Key
removePublicKey(publicKey)
Removes a public key from the signer’s tracked keys.
await signer . removePublicKey ( publicKey );
console . log ( "Public key removed" );
Get Tracked Public Keys
getTrackedPublicKeys()
Returns all currently tracked public keys.
const trackedKeys = await signer . getTrackedPublicKeys ();
console . log ( "Tracked keys:" , trackedKeys . length );
trackedKeys
Promise<Uint8Array[]>
required
Array of tracked public keys
Deposit Address Management
Get Deposit Signing Key
getDepositSigningKey()
Retrieves the deposit signing public key.
const depositKey = await signer . getDepositSigningKey ();
console . log ( "Deposit signing key:" , depositKey );
depositKey
Promise<Uint8Array>
required
The deposit signing public key
Generate Static Deposit Key
generateStaticDepositKey(idx)
Generates or retrieves a static deposit key by index.
const staticDepositKey = await signer . generateStaticDepositKey ( 0 );
console . log ( "Static deposit key:" , staticDepositKey );
Index for the static deposit key
staticDepositKey
Promise<Uint8Array>
required
The static deposit public key
Get Static Deposit Signing Key
getStaticDepositSigningKey(idx)
Retrieves a static deposit signing key by index.
const signingKey = await signer . getStaticDepositSigningKey ( 0 );
console . log ( "Static deposit signing key:" , signingKey );
Index for the static deposit key
signingKey
Promise<Uint8Array>
required
The static deposit signing public key
Get Static Deposit Secret Key
getStaticDepositSecretKey(idx)
Retrieves a static deposit private key by index.
const secretKey = await signer . getStaticDepositSecretKey ( 0 );
console . log ( "Static deposit secret key:" , secretKey );
Index for the static deposit key
secretKey
Promise<Uint8Array>
required
The static deposit private key
Digital Signatures
Sign with Identity Key
signMessageWithIdentityKey(message, compact?)
Signs a message using the wallet’s identity key.
const message = new TextEncoder (). encode ( "Hello, Spark!" );
const signature = await signer . signMessageWithIdentityKey ( message );
console . log ( "Signature:" , signature );
// With compact format
const compactSignature = await signer . signMessageWithIdentityKey ( message , true );
Use compact signature format instead of DER
signature
Promise<Uint8Array>
required
ECDSA signature (DER or compact format)
Sign with Public Key
signMessageWithPublicKey(message, publicKey, compact?)
Signs a message using a specific public key.
const message = new TextEncoder (). encode ( "Hello, Spark!" );
const publicKey = await signer . generatePublicKey ();
const signature = await signer . signMessageWithPublicKey ( message , publicKey );
console . log ( "Signature:" , signature );
Public key to use for signing
Use compact signature format instead of DER
signature
Promise<Uint8Array>
required
ECDSA signature (DER or compact format)
Validate Signature
validateMessageWithIdentityKey(message, signature)
Validates a signature against the identity key.
const message = new TextEncoder (). encode ( "Hello, Spark!" );
const signature = await signer . signMessageWithIdentityKey ( message );
const isValid = await signer . validateMessageWithIdentityKey ( message , signature );
console . log ( "Signature valid:" , isValid );
True if signature is valid
Schnorr Signatures
Get Schnorr Public Key
getSchnorrPublicKey(publicKey)
Converts a secp256k1 public key to Schnorr format.
const publicKey = await signer . generatePublicKey ();
const schnorrKey = await signer . getSchnorrPublicKey ( publicKey );
console . log ( "Schnorr public key:" , schnorrKey );
schnorrKey
Promise<Uint8Array>
required
Schnorr public key
Sign with Schnorr
signSchnorr(message, publicKey)
Creates a Schnorr signature for a message.
const message = new TextEncoder (). encode ( "Hello, Spark!" );
const publicKey = await signer . generatePublicKey ();
const schnorrSignature = await signer . signSchnorr ( message , publicKey );
console . log ( "Schnorr signature:" , schnorrSignature );
Public key to use for signing
schnorrSignature
Promise<Uint8Array>
required
Schnorr signature
Sign with Identity Key (Schnorr)
signSchnorrWithIdentityKey(message)
Creates a Schnorr signature using the identity key.
const message = new TextEncoder (). encode ( "Hello, Spark!" );
const schnorrSignature = await signer . signSchnorrWithIdentityKey ( message );
console . log ( "Schnorr signature:" , schnorrSignature );
schnorrSignature
Promise<Uint8Array>
required
Schnorr signature
Advanced Cryptographic Operations
Restore Signing Keys
restoreSigningKeysFromLeafs(leafs)
Restores signing keys from a set of tree leaf nodes.
const leafs = [ /* TreeNode array */ ];
await signer . restoreSigningKeysFromLeafs ( leafs );
console . log ( "Signing keys restored" );
Private Key Subtraction
subtractPrivateKeysGivenPublicKeys(first, second)
Performs private key subtraction and returns the resulting public key.
const firstKey = await signer . generatePublicKey ();
const secondKey = await signer . generatePublicKey ();
const resultKey = await signer . subtractPrivateKeysGivenPublicKeys ( firstKey , secondKey );
console . log ( "Result key:" , resultKey );
resultKey
Promise<Uint8Array>
required
Resulting public key after subtraction
Secret Sharing
splitSecretWithProofs(params)
Implements Shamir’s Secret Sharing with verifiable proofs.
const params = {
secret: new Uint8Array ( 32 ),
curveOrder: BigInt ( "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" ),
threshold: 3 ,
numShares: 5 ,
isSecretPubkey: false
};
const shares = await signer . splitSecretWithProofs ( params );
console . log ( "Secret shares:" , shares . length );
params
SplitSecretWithProofsParams
required
Secret sharing parameters
shares
Promise<VerifiableSecretShare[]>
required
Array of verifiable secret shares
FROST Protocol (Threshold Signatures)
Get Random Signing Commitment
getRandomSigningCommitment()
Generates a random signing commitment for FROST protocol.
const commitment = await signer . getRandomSigningCommitment ();
console . log ( "Signing commitment:" , commitment );
commitment
Promise<SigningCommitment>
required
Random signing commitment
FROST Signing
signFrost(params)
Performs FROST signing operation.
const params = {
message: new TextEncoder (). encode ( "Hello, FROST!" ),
privateAsPubKey: await signer . generatePublicKey (),
publicKey: await signer . generatePublicKey (),
verifyingKey: await signer . generatePublicKey (),
selfCommitment: await signer . getRandomSigningCommitment (),
statechainCommitments: {},
adaptorPubKey: await signer . generatePublicKey ()
};
const frostSignature = await signer . signFrost ( params );
console . log ( "FROST signature:" , frostSignature );
frostSignature
Promise<Uint8Array>
required
FROST signature share
Aggregate FROST Signatures
aggregateFrost(params)
Aggregates FROST signature shares into a final signature.
const params = {
message: new TextEncoder (). encode ( "Hello, FROST!" ),
publicKey: await signer . generatePublicKey (),
verifyingKey: await signer . generatePublicKey (),
selfCommitment: await signer . getRandomSigningCommitment (),
selfSignature: new Uint8Array ( 64 ),
statechainSignatures: {},
statechainPublicKeys: {}
};
const finalSignature = await signer . aggregateFrost ( params );
console . log ( "Final signature:" , finalSignature );
params
AggregateFrostParams
required
FROST aggregation parameters
finalSignature
Promise<Uint8Array>
required
Final aggregated signature
Encryption
Encrypt Leaf Private Key
encryptLeafPrivateKeyEcies(receiverPublicKey, publicKey)
Encrypts a leaf private key using ECIES.
const receiverPublicKey = await signer . generatePublicKey ();
const publicKey = await signer . generatePublicKey ();
const encryptedKey = await signer . encryptLeafPrivateKeyEcies ( receiverPublicKey , publicKey );
console . log ( "Encrypted key:" , encryptedKey );
Public key whose private key to encrypt
encryptedKey
Promise<Uint8Array>
required
Encrypted private key
Decrypt ECIES
decryptEcies(ciphertext)
Decrypts ECIES-encrypted data using the identity key.
const ciphertext = new Uint8Array ( /* encrypted data */ );
const decryptedData = await signer . decryptEcies ( ciphertext );
console . log ( "Decrypted data:" , decryptedData );
decryptedData
Promise<Uint8Array>
required
Decrypted public key
Utility Functions
Hash Random Private Key
hashRandomPrivateKey()
Generates a hash of a random private key.
const hash = await signer . hashRandomPrivateKey ();
console . log ( "Random key hash:" , hash );
hash
Promise<Uint8Array>
required
SHA256 hash of a random private key
Generate Adaptor Signature
generateAdaptorFromSignature(signature)
Generates an adaptor signature from a regular signature.
const signature = new Uint8Array ( 64 );
const adaptor = await signer . generateAdaptorFromSignature ( signature );
console . log ( "Adaptor signature:" , adaptor . adaptorSignature );
console . log ( "Adaptor public key:" , adaptor . adaptorPublicKey );
adaptor
Promise<{adaptorSignature: Uint8Array, adaptorPublicKey: Uint8Array}>
required
Object containing adaptor signature and public key
Complete Example
import { SparkSigner } from "@buildonspark/spark-sdk" ;
async function demonstrateSparkSigner () {
// Initialize signer (this would be your custom implementation)
const signer = new SparkSigner ();
try {
// 1. Generate mnemonic and initialize
const mnemonic = await signer . generateMnemonic ();
console . log ( "Generated mnemonic:" , mnemonic );
const seed = await signer . mnemonicToSeed ( mnemonic );
const identityKey = await signer . createSparkWalletFromSeed ( seed , 0 );
console . log ( "Identity key:" , identityKey );
// 2. Generate and manage keys
const publicKey = await signer . generatePublicKey ();
console . log ( "Generated public key:" , publicKey );
const trackedKeys = await signer . getTrackedPublicKeys ();
console . log ( "Tracked keys:" , trackedKeys . length );
// 3. Sign messages
const message = new TextEncoder (). encode ( "Hello, Spark Signer!" );
// ECDSA signature
const ecdsaSignature = await signer . signMessageWithIdentityKey ( message );
console . log ( "ECDSA signature:" , ecdsaSignature );
// Schnorr signature
const schnorrSignature = await signer . signSchnorrWithIdentityKey ( message );
console . log ( "Schnorr signature:" , schnorrSignature );
// 4. Validate signature
const isValid = await signer . validateMessageWithIdentityKey ( message , ecdsaSignature );
console . log ( "Signature valid:" , isValid );
// 5. Deposit key management
const depositKey = await signer . getDepositSigningKey ();
console . log ( "Deposit key:" , depositKey );
const staticDepositKey = await signer . generateStaticDepositKey ( 0 );
console . log ( "Static deposit key:" , staticDepositKey );
} catch ( error ) {
console . error ( "Spark Signer operation failed:" , error );
}
}