Skip to main content

Signature Templates

When a contract function has a sig parameter, it needs a cryptographic signature from a private key for the spending transaction. In place of a signature, a SignatureTemplate can be passed, which will generate the correct signature when the transaction is built.

tip

SignatureTemplate can be used with a Contract as function argument to generate a signature automatically, or can be used in the TransactionBuilder to create an Unlocker for a P2PKH UTXO.

SignatureTemplate​

Constructor​

new SignatureTemplate(
signer: Keypair | Uint8Array | string,
sighashType?: SighashType,
signatureAlgorithm?: SignatureAlgorithm
)

In place of a signature, a SignatureTemplate can be passed, which will generate the correct signature using the signer parameter. This signer can be any representation of a private key, including WIF strings, hex strings (optionally 0x-prefixed), BCHJS' ECPair, bitcore-lib-cash' PrivateKey (any object with a toWIF() method), or binary private keys represented as Uint8Array. This ensures that SignatureTemplate can be used with any BCH library. A key that is not 32 bytes long throws.

The defaults are SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS and SignatureAlgorithm.SCHNORR.

note

checkMultiSig requires ECDSA signatures. For each signature argument of a checkMultiSig call, create the template with new SignatureTemplate(key, undefined, SignatureAlgorithm.ECDSA). The Schnorr default suits checkSig.

Example​

const aliceWif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1';
const aliceSignatureTemplate = new SignatureTemplate(aliceWif)

const transferDetails = await new TransactionBuilder({ provider })
.addInput(selectedContractUtxo, contract.unlock.transfer(aliceSignatureTemplate))
.addOutput({
to: 'bitcoincash:qrhea03074073ff3zv9whh0nggxc7k03ssh8jv9mkx',
amount: 10000n
})
.send();

The sighashType and signatureAlgorithm options are covered under 'Advanced Usage'.

SignatureTemplate Methods​

unlockP2PKH()​

Importantly the SignatureTemplate can also be used to generate the Unlocker for a P2PKH UTXO in the following way:

signatureTemplate.unlockP2PKH(): Unlocker

Example​

import { aliceTemplate, aliceAddress, transactionBuilder } from './somewhere.js';

const aliceUtxos = await provider.getUtxos(aliceAddress);
transactionBuilder.addInput(aliceUtxos[0], aliceTemplate.unlockP2PKH());

publicKey​

The SignatureTemplate exposes the matching compressed public key as a property:

signatureTemplate.publicKey: Uint8Array

Example​

import { aliceTemplate } from './somewhere.js';

const alicePublicKey = aliceTemplate.publicKey
note

getPublicKey(), getHashType() and getSignatureAlgorithm() remain available but are deprecated in favour of the publicKey, sighashType and signatureAlgorithm properties. HashType is a deprecated alias of SighashType.

signMessageHash()​

The SignatureTemplate also has a helper method to sign a message hash, which can be used to sign non-transaction messages. This is useful for generating datasig signatures for smart contract use cases.

signMessageHash() signs the 32-byte hash it is given with the template's algorithm (a 64-byte Schnorr signature by default) and appends no sighash byte. checkDataSig(s, msg, pk) verifies a signature over sha256(msg), so pass sha256(msg), not msg itself.

signatureTemplate.signMessageHash(message: Uint8Array): Uint8Array

Example​

import { aliceTemplate } from './somewhere.js';
import { sha256 } from '@solidcash/utils';
import { hexToBin } from '@bitauth/libauth';

const signature = aliceTemplate.signMessageHash(sha256(hexToBin('0000000000000000000000')));

Advanced Usage​

SighashType​

The default sighashType is SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS because this is the most secure option for smart contract use cases. Every signature also carries the fork id flag, which BCH consensus requires, so it is not part of the configured value.

The constructor throws on an unknown base type or flag, and on SIGHASH_UTXOS combined with SIGHASH_ANYONECANPAY. It prints a warning for SIGHASH_NONE, SIGHASH_SINGLE and SIGHASH_ANYONECANPAY, which do not commit to all inputs and outputs, so another party can change the transaction.

export enum SighashType {
SIGHASH_ALL = 0x01,
SIGHASH_NONE = 0x02,
SIGHASH_SINGLE = 0x03,
SIGHASH_UTXOS = 0x20,
SIGHASH_ANYONECANPAY = 0x80,
}

Example​

import { SighashType, SignatureTemplate } from 'solidcash';

const wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1';

const signatureTemplate = new SignatureTemplate(
wif, SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS
);

const configuredSighashType = signatureTemplate.sighashType

SignatureAlgorithm​

The signatureAlgorithm parameter determines the cryptographic algorithm used for signing. By default, the modern and compact Schnorr algorithm is used.

export enum SignatureAlgorithm {
ECDSA = 0x00,
SCHNORR = 0x01,
}

Example​

import { SighashType, SignatureAlgorithm, SignatureTemplate } from 'solidcash';

const wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1';

const sighashType = SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS
const signatureAlgorithm = SignatureAlgorithm.SCHNORR
const signatureTemplate = new SignatureTemplate(wif, sighashType, signatureAlgorithm);

const configuredSignatureAlgorithm = signatureTemplate.signatureAlgorithm