diff --git a/.cspell.json b/.cspell.json index 3231913ce..a14829167 100644 --- a/.cspell.json +++ b/.cspell.json @@ -86,7 +86,6 @@ "hashprevouts", "hashsequence", "hashtype", - "hashtypes", "hodl", "hodling", "htlc", diff --git a/packages/cashscript/src/Contract.ts b/packages/cashscript/src/Contract.ts index bdf097d63..ff784aeee 100644 --- a/packages/cashscript/src/Contract.ts +++ b/packages/cashscript/src/Contract.ts @@ -195,7 +195,7 @@ class ContractInternal< if (!(arg instanceof SignatureTemplate)) return arg; // Generate transaction signature from SignatureTemplate - const preimage = createSighashPreimage(transaction, sourceOutputs, inputIndex, bytecode, arg.getHashType()); + const preimage = createSighashPreimage(transaction, sourceOutputs, inputIndex, bytecode, arg.sighashType); const sighash = hash256(preimage); return arg.generateSignature(sighash); }); diff --git a/packages/cashscript/src/SignatureTemplate.ts b/packages/cashscript/src/SignatureTemplate.ts index d8a3f9e7e..eae5d5fad 100644 --- a/packages/cashscript/src/SignatureTemplate.ts +++ b/packages/cashscript/src/SignatureTemplate.ts @@ -1,35 +1,40 @@ -import { decodePrivateKeyWif, hexToBin, isHex, secp256k1, SigningSerializationFlag } from '@bitauth/libauth'; +import { decodePrivateKeyWif, hexToBin, isHex, secp256k1 } from '@bitauth/libauth'; import { hash256, scriptToBytecode } from '@cashscript/utils'; import { GenerateUnlockingBytecodeOptions, - HashType, + SighashType, SignatureAlgorithm, P2PKHUnlocker, } from './interfaces.js'; -import { createSighashPreimage, publicKeyToP2PKHLockingBytecode } from './utils.js'; +import { createSighashPreimage, publicKeyToP2PKHLockingBytecode, toSigningSerializationType } from './utils.js'; /** * A signature template used to sign CashScript transactions. Wraps a private key together with - * the desired `HashType` and `SignatureAlgorithm`, and is consumed by the `TransactionBuilder` + * the desired `SighashType` and `SignatureAlgorithm`, and is consumed by the `TransactionBuilder` * whenever a `sig` argument is required or when unlocking a P2PKH input. */ export default class SignatureTemplate { /** The raw private key bytes used for signing. */ public privateKey: Uint8Array; + /** The 33-byte compressed public key that corresponds to the template's private key. */ + get publicKey(): Uint8Array { + return secp256k1.derivePublicKeyCompressed(this.privateKey) as Uint8Array; + } + /** * Create a new SignatureTemplate. * * @param signer - A 32-byte private key (Uint8Array), a WIF or hex-encoded private key string, * or any object exposing a `toWIF()` method (e.g. bitcore-lib or bitcoincashjs `ECPair`). - * @param hashtype - Sighash flags to use when signing. Defaults to `SIGHASH_ALL | SIGHASH_UTXOS`. + * @param sighashType - Sighash flags to use when signing. Defaults to `SIGHASH_ALL | SIGHASH_UTXOS`. * @param signatureAlgorithm - The signature algorithm to use. Defaults to * `SignatureAlgorithm.SCHNORR`. */ constructor( signer: Keypair | Uint8Array | string, - private hashtype: HashType = HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS, - private signatureAlgorithm: SignatureAlgorithm = SignatureAlgorithm.SCHNORR, + public readonly sighashType: SighashType = SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS, + public readonly signatureAlgorithm: SignatureAlgorithm = SignatureAlgorithm.SCHNORR, ) { if (isKeypair(signer)) { const wif = signer.toWIF(); @@ -47,24 +52,22 @@ export default class SignatureTemplate { } /** - * Sign the provided sighash payload and return the signature concatenated with the hashtype + * Sign the provided sighash payload and return the signature concatenated with the sighash type * byte, ready to be used as a transaction signature. * * @param payload - The 32-byte sighash to sign. - * @param bchForkId - Whether to include the BCH fork id flag in the appended hashtype byte. - * Defaults to `true`. - * @returns The signature bytes followed by the hashtype byte. + * @returns The signature bytes followed by the sighash type byte. */ - generateSignature(payload: Uint8Array, bchForkId?: boolean): Uint8Array { + generateSignature(payload: Uint8Array): Uint8Array { const signature = this.signMessageHash(payload); - return Uint8Array.from([...signature, this.getHashType(bchForkId)]); + return Uint8Array.from([...signature, toSigningSerializationType(this.sighashType)]); } /** * Sign a raw 32-byte message hash using the template's private key and signature algorithm. * * @param payload - The 32-byte hash to sign. - * @returns The raw signature bytes (without an appended hashtype byte). + * @returns The raw signature bytes (without an appended sighash type byte). */ signMessageHash(payload: Uint8Array): Uint8Array { const signature = this.signatureAlgorithm === SignatureAlgorithm.SCHNORR @@ -74,32 +77,6 @@ export default class SignatureTemplate { return signature; } - /** - * Get the sighash flags used by this template. - * - * @param bchForkId - Whether to OR in the BCH fork id flag. Defaults to `true`. - * @returns The combined hashtype byte. - */ - getHashType(bchForkId: boolean = true): number { - return bchForkId ? (this.hashtype | SigningSerializationFlag.forkId) : this.hashtype; - } - - /** - * @returns The signature algorithm (ECDSA or Schnorr) used by this template. - */ - getSignatureAlgorithm(): SignatureAlgorithm { - return this.signatureAlgorithm; - } - - /** - * Derive the compressed public key that corresponds to the template's private key. - * - * @returns The 33-byte compressed public key. - */ - getPublicKey(): Uint8Array { - return secp256k1.derivePublicKeyCompressed(this.privateKey) as Uint8Array; - } - /** * Build a P2PKH `Unlocker` for the address derived from this template's private key. The * returned unlocker can be passed directly to `TransactionBuilder.addInput`. @@ -107,17 +84,15 @@ export default class SignatureTemplate { * @returns An unlocker that signs the corresponding P2PKH UTXO. */ unlockP2PKH(): P2PKHUnlocker { - const publicKey = this.getPublicKey(); - const prevOutScript = publicKeyToP2PKHLockingBytecode(publicKey); - const hashtype = this.getHashType(); + const prevOutScript = publicKeyToP2PKHLockingBytecode(this.publicKey); return { generateLockingBytecode: () => prevOutScript, generateUnlockingBytecode: ({ transaction, sourceOutputs, inputIndex }: GenerateUnlockingBytecodeOptions) => { - const preimage = createSighashPreimage(transaction, sourceOutputs, inputIndex, prevOutScript, hashtype); + const preimage = createSighashPreimage(transaction, sourceOutputs, inputIndex, prevOutScript, this.sighashType); const sighash = hash256(preimage); const signature = this.generateSignature(sighash); - const unlockingBytecode = scriptToBytecode([signature, publicKey]); + const unlockingBytecode = scriptToBytecode([signature, this.publicKey]); return unlockingBytecode; }, template: this, diff --git a/packages/cashscript/src/interfaces.ts b/packages/cashscript/src/interfaces.ts index 5841ac9f2..009b672eb 100644 --- a/packages/cashscript/src/interfaces.ts +++ b/packages/cashscript/src/interfaces.ts @@ -133,7 +133,7 @@ export enum SignatureAlgorithm { SCHNORR = 0x01, } -export enum HashType { +export enum SighashType { SIGHASH_ALL = 0x01, SIGHASH_NONE = 0x02, SIGHASH_SINGLE = 0x03, diff --git a/packages/cashscript/src/libauth-template/utils.ts b/packages/cashscript/src/libauth-template/utils.ts index a987e61d8..8c4d0a5c7 100644 --- a/packages/cashscript/src/libauth-template/utils.ts +++ b/packages/cashscript/src/libauth-template/utils.ts @@ -1,5 +1,5 @@ import { AbiFunction, AbiInput, Artifact, formatBitAuthScript, sha256 } from '@cashscript/utils'; -import { HashType, LibauthTokenDetails, SignatureAlgorithm, TokenDetails, VmTarget } from '../interfaces.js'; +import { LibauthTokenDetails, SighashType, SignatureAlgorithm, TokenDetails, VmTarget } from '../interfaces.js'; import { hexToBin, binToHex, isHex, decodeCashAddress, Input, assertSuccess, decodeAuthenticationInstructions, AuthenticationInstructionPush } from '@bitauth/libauth'; import { EncodedFunctionArgument } from '../Argument.js'; import { zip } from '../utils.js'; @@ -32,23 +32,23 @@ export const getSignatureAlgorithmName = (signatureAlgorithm: SignatureAlgorithm return signatureAlgorithmNames[signatureAlgorithm]; }; -export const getHashTypeName = (hashType: HashType): string => { - const hashtypeNames = { - [HashType.SIGHASH_ALL]: 'all_outputs', - [HashType.SIGHASH_ALL | HashType.SIGHASH_ANYONECANPAY]: 'all_outputs_single_input', - [HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS]: 'all_outputs_all_utxos', - [HashType.SIGHASH_ALL | HashType.SIGHASH_ANYONECANPAY | HashType.SIGHASH_UTXOS]: 'all_outputs_single_input_INVALID_all_utxos', - [HashType.SIGHASH_SINGLE]: 'corresponding_output', - [HashType.SIGHASH_SINGLE | HashType.SIGHASH_ANYONECANPAY]: 'corresponding_output_single_input', - [HashType.SIGHASH_SINGLE | HashType.SIGHASH_UTXOS]: 'corresponding_output_all_utxos', - [HashType.SIGHASH_SINGLE | HashType.SIGHASH_ANYONECANPAY | HashType.SIGHASH_UTXOS]: 'corresponding_output_single_input_INVALID_all_utxos', - [HashType.SIGHASH_NONE]: 'no_outputs', - [HashType.SIGHASH_NONE | HashType.SIGHASH_ANYONECANPAY]: 'no_outputs_single_input', - [HashType.SIGHASH_NONE | HashType.SIGHASH_UTXOS]: 'no_outputs_all_utxos', - [HashType.SIGHASH_NONE | HashType.SIGHASH_ANYONECANPAY | HashType.SIGHASH_UTXOS]: 'no_outputs_single_input_INVALID_all_utxos', +export const getSighashTypeName = (sighashType: SighashType): string => { + const sighashTypeNames = { + [SighashType.SIGHASH_ALL]: 'all_outputs', + [SighashType.SIGHASH_ALL | SighashType.SIGHASH_ANYONECANPAY]: 'all_outputs_single_input', + [SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS]: 'all_outputs_all_utxos', + [SighashType.SIGHASH_ALL | SighashType.SIGHASH_ANYONECANPAY | SighashType.SIGHASH_UTXOS]: 'all_outputs_single_input_INVALID_all_utxos', + [SighashType.SIGHASH_SINGLE]: 'corresponding_output', + [SighashType.SIGHASH_SINGLE | SighashType.SIGHASH_ANYONECANPAY]: 'corresponding_output_single_input', + [SighashType.SIGHASH_SINGLE | SighashType.SIGHASH_UTXOS]: 'corresponding_output_all_utxos', + [SighashType.SIGHASH_SINGLE | SighashType.SIGHASH_ANYONECANPAY | SighashType.SIGHASH_UTXOS]: 'corresponding_output_single_input_INVALID_all_utxos', + [SighashType.SIGHASH_NONE]: 'no_outputs', + [SighashType.SIGHASH_NONE | SighashType.SIGHASH_ANYONECANPAY]: 'no_outputs_single_input', + [SighashType.SIGHASH_NONE | SighashType.SIGHASH_UTXOS]: 'no_outputs_all_utxos', + [SighashType.SIGHASH_NONE | SighashType.SIGHASH_ANYONECANPAY | SighashType.SIGHASH_UTXOS]: 'no_outputs_single_input_INVALID_all_utxos', }; - return hashtypeNames[hashType]; + return sighashTypeNames[sighashType]; }; export const addHexPrefixExceptEmpty = (value: string): string => { @@ -63,9 +63,9 @@ export const formatParametersForDebugging = (types: readonly AbiInput[], args: E return typesAndArguments.map(([input, arg]) => { if (arg instanceof SignatureTemplate) { - const signatureAlgorithmName = getSignatureAlgorithmName(arg.getSignatureAlgorithm()); - const hashtypeName = getHashTypeName(arg.getHashType(false)); - return `<${input.name}.${signatureAlgorithmName}.${hashtypeName}> // ${input.type}`; + const signatureAlgorithmName = getSignatureAlgorithmName(arg.signatureAlgorithm); + const sighashTypeName = getSighashTypeName(arg.sighashType); + return `<${input.name}.${signatureAlgorithmName}.${sighashTypeName}> // ${input.type}`; } const typeStr = input.type === 'bytes' ? `bytes${arg.length}` : input.type; diff --git a/packages/cashscript/src/utils.ts b/packages/cashscript/src/utils.ts index 743678938..d13b96cff 100644 --- a/packages/cashscript/src/utils.ts +++ b/packages/cashscript/src/utils.ts @@ -14,6 +14,7 @@ import { bigIntToCompactUint, NonFungibleTokenCapability, bigIntToVmNumber, + SigningSerializationFlag, } from '@bitauth/libauth'; import { encodeInt, @@ -35,6 +36,7 @@ import { UnlockableUtxo, LibauthTokenDetails, ContractType, + SighashType, } from './interfaces.js'; import { VERSION_SIZE, LOCKTIME_SIZE } from './constants.js'; import { @@ -265,15 +267,20 @@ function toBin(output: string): Uint8Array { return encode(data); } +// BCH consensus requires the fork id flag on every signing serialization +export function toSigningSerializationType(sighashType: SighashType): number { + return sighashType | SigningSerializationFlag.forkId; +} + export function createSighashPreimage( transaction: Transaction, sourceOutputs: LibauthOutput[], inputIndex: number, coveredBytecode: Uint8Array, - hashtype: number, + sighashType: SighashType, ): Uint8Array { const context = { inputIndex, sourceOutputs, transaction }; - const signingSerializationType = new Uint8Array([hashtype]); + const signingSerializationType = new Uint8Array([toSigningSerializationType(sighashType)]); const sighashPreimage = generateSigningSerializationBch(context, { coveredBytecode, signingSerializationType }); diff --git a/packages/cashscript/test/SignatureTemplate.test.ts b/packages/cashscript/test/SignatureTemplate.test.ts index 138d45118..c21f9588f 100644 --- a/packages/cashscript/test/SignatureTemplate.test.ts +++ b/packages/cashscript/test/SignatureTemplate.test.ts @@ -1,5 +1,5 @@ import { generateLibauthSourceOutputs } from 'cashscript/dist/utils.js'; -import { HashType, MockNetworkProvider, SignatureAlgorithm, SignatureTemplate, TransactionBuilder } from '../src/index.js'; +import { MockNetworkProvider, SighashType, SignatureAlgorithm, SignatureTemplate, TransactionBuilder } from '../src/index.js'; import { aliceAddress, alicePriv, alicePub, aliceWif } from './fixture/vars.js'; import { binToHex, decodeTransactionUnsafe, hexToBin } from '@bitauth/libauth'; @@ -33,17 +33,11 @@ describe('SignatureTemplate', () => { expect(signature).toEqual(hexToBin('3045022100fa1d6a159a124e99479f78152422d55ff3c16f7fac5ae47fa291907f8f47613f02200d6c906f667b3712860b6f5a1f296ecb7dcd44da83c6a1eb45869b61c6b8dadb61')); }); - it('should append the correct hash type when fork ID is true', () => { - const signatureTemplate = new SignatureTemplate(alicePriv, HashType.SIGHASH_SINGLE); - const signature = signatureTemplate.generateSignature(hexToBin('0000000000000000000000'), true); + it('should append the configured sighash type, always including the BCH fork ID', () => { + const signatureTemplate = new SignatureTemplate(alicePriv, SighashType.SIGHASH_SINGLE); + const signature = signatureTemplate.generateSignature(hexToBin('0000000000000000000000')); expect(signature).toEqual(hexToBin('bcac180e17de108003cce026708bd2af54b860dad2626cee157f4ed5abd993b9085d615015f905978adc51e8878226280ddd27d899f086519c0978e53332d79943')); }); - - it('should append the correct hash type when fork ID is false', () => { - const signatureTemplate = new SignatureTemplate(alicePriv, HashType.SIGHASH_SINGLE); - const signature = signatureTemplate.generateSignature(hexToBin('0000000000000000000000'), false); - expect(signature).toEqual(hexToBin('bcac180e17de108003cce026708bd2af54b860dad2626cee157f4ed5abd993b9085d615015f905978adc51e8878226280ddd27d899f086519c0978e53332d79903')); - }); }); describe('signMessageHash', () => { @@ -62,10 +56,10 @@ describe('SignatureTemplate', () => { }); }); - describe('getPublicKey', () => { + describe('publicKey', () => { it('should generate a correct public key', () => { const signatureTemplate = new SignatureTemplate(alicePriv); - expect(signatureTemplate.getPublicKey()).toEqual(alicePub); + expect(signatureTemplate.publicKey).toEqual(alicePub); }); }); diff --git a/packages/cashscript/test/e2e/HodlVault.test.ts b/packages/cashscript/test/e2e/HodlVault.test.ts index d3b0f81e6..7c42c5888 100644 --- a/packages/cashscript/test/e2e/HodlVault.test.ts +++ b/packages/cashscript/test/e2e/HodlVault.test.ts @@ -6,7 +6,7 @@ import { Network, TransactionBuilder, SignatureAlgorithm, - HashType, + SighashType, } from '../../src/index.js'; import { alicePriv, @@ -108,7 +108,7 @@ describe('HodlVault', () => { const amount = 10000n; const { utxos, changeAmount } = gatherUtxos(await hodlVault.getUtxos(), { amount, fee: 2000n }); - const signatureTemplate = new SignatureTemplate(alicePriv, HashType.SIGHASH_ALL, SignatureAlgorithm.ECDSA); + const signatureTemplate = new SignatureTemplate(alicePriv, SighashType.SIGHASH_ALL, SignatureAlgorithm.ECDSA); // when const tx = await new TransactionBuilder({ provider }) @@ -185,7 +185,7 @@ describe('HodlVault', () => { .send()).rejects.toThrow('HodlVault.cash:31 Require statement failed at input 0 in contract HodlVault.cash at line 31'); // datasig: unlocker should throw when given an improper length - const signatureTemplate = new SignatureTemplate(alicePriv, HashType.SIGHASH_ALL, SignatureAlgorithm.ECDSA); + const signatureTemplate = new SignatureTemplate(alicePriv, SighashType.SIGHASH_ALL, SignatureAlgorithm.ECDSA); expect(() => hodlVault.unlock.spend(signatureTemplate, placeholder(100), message)).toThrow("Found type 'bytes100' where type 'datasig' was expected"); // datasig: unlocker should not throw when given a proper length, but transaction should fail on invalid sig diff --git a/packages/cashscript/test/fixture/libauth-template/fixtures.ts b/packages/cashscript/test/fixture/libauth-template/fixtures.ts index 3facdf713..0a145f3b2 100644 --- a/packages/cashscript/test/fixture/libauth-template/fixtures.ts +++ b/packages/cashscript/test/fixture/libauth-template/fixtures.ts @@ -1,4 +1,4 @@ -import { Contract, HashType, MockNetworkProvider, SignatureAlgorithm, SignatureTemplate, TransactionBuilder, randomNFT, randomToken, randomUtxo } from '../../../src/index.js'; +import { Contract, MockNetworkProvider, SighashType, SignatureAlgorithm, SignatureTemplate, TransactionBuilder, randomNFT, randomToken, randomUtxo } from '../../../src/index.js'; import TransferWithTimeout from '../transfer_with_timeout.artifact.js'; import Mecenas from '../mecenas.artifact.js'; import P2PKH from '../p2pkh.artifact.js'; @@ -1262,7 +1262,7 @@ export const fixtures: Fixture[] = [ }, }, }, - // TODO: Make it work with different hashtypes and signature algorithms + // TODO: Make it work with different sighash types and signature algorithms // { // name: 'P2PKH (sending NFTs)', // transaction: (() => { @@ -1272,11 +1272,11 @@ export const fixtures: Fixture[] = [ // const to = contract.address; // const amount = 1000n; - // const hashtype = HashType.SIGHASH_SINGLE | HashType.SIGHASH_ANYONECANPAY; + // const sighashType = SighashType.SIGHASH_SINGLE | SighashType.SIGHASH_ANYONECANPAY; // const signatureAlgorithm = SignatureAlgorithm.ECDSA; // const tx = contract.functions - // .spend(alicePub, new SignatureTemplate(alicePriv, hashtype, signatureAlgorithm)) + // .spend(alicePub, new SignatureTemplate(alicePriv, sighashType, signatureAlgorithm)) // .to(to, amount); // return tx; @@ -1295,8 +1295,8 @@ export const fixtures: Fixture[] = [ const amount = 1000n; const aliceDefaultTemplate = new SignatureTemplate(alicePriv); - const aliceCustomTemplate = new SignatureTemplate(alicePriv, HashType.SIGHASH_NONE, SignatureAlgorithm.ECDSA); - const bobCustomTemplate = new SignatureTemplate(bobPriv, HashType.SIGHASH_ALL, SignatureAlgorithm.ECDSA); + const aliceCustomTemplate = new SignatureTemplate(alicePriv, SighashType.SIGHASH_NONE, SignatureAlgorithm.ECDSA); + const bobCustomTemplate = new SignatureTemplate(bobPriv, SighashType.SIGHASH_ALL, SignatureAlgorithm.ECDSA); const tx = new TransactionBuilder({ provider }) .addInput(p2pkhUtxo, aliceDefaultTemplate.unlockP2PKH()) diff --git a/website/docs/releases/migration-notes.md b/website/docs/releases/migration-notes.md index 8c2864e9b..d981afe46 100644 --- a/website/docs/releases/migration-notes.md +++ b/website/docs/releases/migration-notes.md @@ -2,6 +2,48 @@ title: Migration Notes --- +## v0.13 to v0.14 + +### CashScript SDK + +#### SignatureTemplate + +The `getHashType()`, `getPublicKey()` and `getSignatureAlgorithm()` are now simple `sighashType`, `publicKey` and `signatureAlgorithm` properties. + +```ts +// before +const hashType = signatureTemplate.getHashType(); +const publicKey = signatureTemplate.getPublicKey(); +const signatureAlgorithm = signatureTemplate.getSignatureAlgorithm(); + +// after +const sighashType = signatureTemplate.sighashType; +const publicKey = signatureTemplate.publicKey; +const signatureAlgorithm = signatureTemplate.signatureAlgorithm; +``` + +Note that `getHashType()` returned the sighash type with the BCH fork ID flag applied, while the `sighashType` property returns the configured sighash type as it was passed to the constructor. + +The `bchForkId` parameter has been removed from `generateSignature()`. A signature without the BCH fork ID flag is invalid under BCH consensus rules, so the flag is now always applied when signing. + +```ts +// before +const signature = signatureTemplate.generateSignature(sighash, bchForkId); + +// after +const signature = signatureTemplate.generateSignature(sighash); +``` + +The `HashType` enum has been renamed to `SighashType`. + +```ts +// before +const signatureTemplate = new SignatureTemplate(wif, HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS); + +// after +const signatureTemplate = new SignatureTemplate(wif, SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS); +``` + ## v0.12 to v0.13 ### cashc compiler diff --git a/website/docs/releases/release-notes.md b/website/docs/releases/release-notes.md index 92afce18e..faac8f294 100644 --- a/website/docs/releases/release-notes.md +++ b/website/docs/releases/release-notes.md @@ -22,6 +22,9 @@ title: Release Notes #### CashScript SDK - :sparkles: Add support for debugging user-defined functions. - :sparkles: Add stack trace when debugging failed requires inside nested functions. +- :hammer_and_wrench: **BREAKING**: Replace the `SignatureTemplate`'s `getHashType()`, `getPublicKey()` and `getSignatureAlgorithm()` methods with the `sighashType`, `publicKey` and `signatureAlgorithm` properties. +- :hammer_and_wrench: **BREAKING**: Remove the `bchForkId` parameter from `SignatureTemplate`'s `generateSignature()` method, since BCH consensus rules always require the fork ID flag. +- :hammer_and_wrench: **BREAKING**: Rename the `HashType` enum to `SighashType`. ## v0.13.2 diff --git a/website/docs/sdk/signature-templates.md b/website/docs/sdk/signature-templates.md index 9f9889663..b9e51b029 100644 --- a/website/docs/sdk/signature-templates.md +++ b/website/docs/sdk/signature-templates.md @@ -16,7 +16,7 @@ In place of a signature, a `SignatureTemplate` can be passed, which will generat ```ts new SignatureTemplate( signer: Keypair | Uint8Array | string, - hashtype?: HashType, + sighashType?: SighashType, signatureAlgorithm?: SignatureAlgorithm ) ``` @@ -37,39 +37,54 @@ const transferDetails = await new TransactionBuilder({ provider }) .send(); ``` -The `hashtype` and `signatureAlgorithm` options are covered under ['Advanced Usage'](/docs/sdk/signature-templates#advanced-usage). +The `sighashType` and `signatureAlgorithm` options are covered under ['Advanced Usage'](/docs/sdk/signature-templates#advanced-usage). -## SignatureTemplate Methods +## SignatureTemplate Properties -### unlockP2PKH() +### privateKey -Importantly the `SignatureTemplate` can also be used to generate the `Unlocker` for a P2PKH UTXO in the following way: +The `SignatureTemplate` exposes the private key it signs with as a property. Whichever format the `signer` was passed in (WIF, hex string, `Uint8Array` or a `Keypair` object), it is decoded to raw private key bytes. ```ts -signatureTemplate.unlockP2PKH(): Unlocker +signatureTemplate.privateKey: Uint8Array ``` -#### Example +### publicKey + +The `SignatureTemplate` exposes the matching public key as a property: + ```ts -import { aliceTemplate, aliceAddress, transactionBuilder } from './somewhere.js'; +signatureTemplate.publicKey: Uint8Array +``` -const aliceUtxos = await provider.getUtxos(aliceAddress); -transactionBuilder.addInput(aliceUtxos[0], aliceTemplate.unlockP2PKH()); +### sighashType + +The configured sighash type is exposed as a property. Note that the BCH fork ID flag is always applied on top of this value when signing, since it is required by BCH consensus. Its possible values are covered under ['Advanced Usage'](/docs/sdk/signature-templates#sighashtype). + +### signatureAlgorithm + +The configured signature algorithm is exposed as a property. Its possible values are covered under ['Advanced Usage'](/docs/sdk/signature-templates#signaturealgorithm). + +```ts +signatureTemplate.signatureAlgorithm: SignatureAlgorithm ``` -### getPublicKey() +## SignatureTemplate Methods + +### unlockP2PKH() -The `SignatureTemplate` also has a helper method to get the matching PublicKey in the following way: +Importantly the `SignatureTemplate` can also be used to generate the `Unlocker` for a P2PKH UTXO in the following way: ```ts -signatureTemplate.getPublicKey(): Uint8Array +signatureTemplate.unlockP2PKH(): Unlocker ``` #### Example ```ts -import { aliceTemplate } from './somewhere.js'; +import { aliceTemplate, aliceAddress, transactionBuilder } from './somewhere.js'; -const alicePublicKey = aliceTemplate.getPublicKey() +const aliceUtxos = await provider.getUtxos(aliceAddress); +transactionBuilder.addInput(aliceUtxos[0], aliceTemplate.unlockP2PKH()); ``` ### signMessageHash() @@ -91,12 +106,12 @@ const signature = aliceTemplate.signMessageHash(sha256(hexToBin('000000000000000 ## Advanced Usage -### HashType +### SighashType -The default `hashtype` is `HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS` because this is the most secure option for smart contract use cases. +The default `sighashType` is `SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS` because this is the most secure option for smart contract use cases. ```ts -export enum HashType { +export enum SighashType { SIGHASH_ALL = 0x01, SIGHASH_NONE = 0x02, SIGHASH_SINGLE = 0x03, @@ -110,10 +125,10 @@ export enum HashType { const wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1'; const signatureTemplate = new SignatureTemplate( - wif, HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS + wif, SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS ); -const configuredHashType = signatureTemplate.getHashType() +const configuredSighashType = signatureTemplate.sighashType ``` ### SignatureAlgorithm @@ -131,11 +146,11 @@ export enum SignatureAlgorithm { ```ts const wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1'; -const hashType = HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS +const sighashType = SighashType.SIGHASH_ALL | SighashType.SIGHASH_UTXOS const signatureAlgorithm = SignatureAlgorithm.SCHNORR -const signatureTemplate = new SignatureTemplate(wif, hashType,signatureAlgorithm); +const signatureTemplate = new SignatureTemplate(wif, sighashType,signatureAlgorithm); -const configuredSignatureAlgorithm = signatureTemplate.getSignatureAlgorithm() +const configuredSignatureAlgorithm = signatureTemplate.signatureAlgorithm ``` [wif]: https://en.bitcoin.it/wiki/Wallet_import_format