@btc-vision/transaction
Version:
OPNet transaction library allows you to create and sign transactions for the OPNet network.
107 lines (93 loc) • 3.86 kB
text/typescript
import { ECPairInterface } from 'ecpair';
import * as ecc from '@bitcoinerlab/secp256k1';
import { crypto, Network, toXOnly } from '@btc-vision/bitcoin';
import { TweakedSigner } from '../signer/TweakedSigner.js';
import { EcKeyPair } from './EcKeyPair.js';
export interface SignedMessage {
readonly signature: Uint8Array;
readonly message: Uint8Array;
}
class MessageSignerBase {
public sha256(message: Buffer | Uint8Array): Buffer {
return crypto.sha256(Buffer.from(message));
}
/**
* Tweak the keypair and sign a message.
* @param {ECPairInterface} keypair - The keypair to sign the message with. Must contain a private key.
* @param {Uint8Array | Buffer | string} message - The message to sign.
* @param {Network} network - The network to sign the message for.
* @returns The Schnorr signature.
*/
public tweakAndSignMessage(
keypair: ECPairInterface,
message: Uint8Array | Buffer | string,
network: Network,
): SignedMessage {
const tweaked = TweakedSigner.tweakSigner(keypair, {
network,
});
return this.signMessage(tweaked, message);
}
/**
* Signs a message using the provided keypair.
* @param {ECPairInterface} keypair - The keypair to sign the message with. Must contain a private key.
* @param {Uint8Array | Buffer | string} message - The message to sign.
* @returns The Schnorr signature.
* @throws Error if the private key is missing or invalid.
*/
public signMessage(
keypair: ECPairInterface,
message: Uint8Array | Buffer | string,
): SignedMessage {
if (typeof message === 'string') {
message = Buffer.from(message, 'utf-8');
}
if (!keypair.privateKey) {
throw new Error('Private key not found in keypair.');
}
const hashedMessage = this.sha256(message);
return {
signature: ecc.signSchnorr(hashedMessage, keypair.privateKey),
message: hashedMessage,
};
}
/**
* Verifies a Schnorr signature.
* @param {Uint8Array | Buffer} publicKey - The public key as a Uint8Array or Buffer.
* @param {Uint8Array | Buffer | string} message - The message to verify.
* @param {Uint8Array | Buffer} signature - The signature to verify.
* @returns True if the signature is valid, false otherwise.
* @throws Error if the signature length is invalid.
*/
public verifySignature(
publicKey: Uint8Array | Buffer,
message: Uint8Array | Buffer | string,
signature: Uint8Array | Buffer,
): boolean {
if (typeof message === 'string') {
message = Buffer.from(message, 'utf-8');
}
if (signature.length !== 64) {
throw new Error('Invalid signature length.');
}
const hashedMessage = this.sha256(message);
return ecc.verifySchnorr(hashedMessage, toXOnly(Buffer.from(publicKey)), signature);
}
/**
* Tweak the public key and verify a signature.
* @param {Uint8Array | Buffer} publicKey - The public key as a Uint8Array or Buffer.
* @param {Uint8Array | Buffer | string} message - The message to verify.
* @param {Uint8Array | Buffer} signature - The signature to verify.
* @returns True if the signature is valid, false otherwise.
* @throws Error if the signature length is invalid.
*/
public tweakAndVerifySignature(
publicKey: Uint8Array | Buffer,
message: Uint8Array | Buffer | string,
signature: Uint8Array | Buffer,
): boolean {
const tweakedPublicKey = EcKeyPair.tweakPublicKey(Buffer.from(publicKey));
return this.verifySignature(tweakedPublicKey, message, signature);
}
}
export const MessageSigner = new MessageSignerBase();