UNPKG

@btc-vision/transaction

Version:

OPNet transaction library allows you to create and sign transactions for the OPNet network.

227 lines 9.05 kB
import {} from '@btc-vision/ecpair'; import { backend } from '../ecc/backend.js'; import { crypto, fromHex, toHex, toXOnly } from '@btc-vision/bitcoin'; import { TweakedSigner } from '../signer/TweakedSigner.js'; import { EcKeyPair } from './EcKeyPair.js'; import { MLDSASecurityLevel } from '@btc-vision/bip32'; import { isOPWallet } from '../transaction/browser/types/OPWallet.js'; import { SignatureType } from '../transaction/browser/types/Unisat.js'; class MessageSignerBase { sha256(message) { return crypto.sha256(message); } async trySignSchnorrWithOPWallet(message) { const wallet = this.getOPWallet(); if (!wallet) { return null; } const messageBuffer = typeof message === 'string' ? new TextEncoder().encode(message) : message; const hashedMessage = this.sha256(messageBuffer); const messageHex = toHex(hashedMessage); const signatureHex = await wallet.signData(messageHex, SignatureType.schnorr, typeof message === 'string' ? message : undefined); return { signature: fromHex(signatureHex), message: hashedMessage, }; } async trySignECDSAWithOPWallet(message) { const wallet = this.getOPWallet(); if (!wallet) { return null; } const messageBuffer = typeof message === 'string' ? new TextEncoder().encode(message) : message; const hashedMessage = this.sha256(messageBuffer); const messageHex = toHex(hashedMessage); const signatureHex = await wallet.signData(messageHex, SignatureType.ecdsa, typeof message === 'string' ? message : undefined); return { signature: fromHex(signatureHex), message: hashedMessage, }; } async trySignMLDSAWithOPWallet(message) { const wallet = this.getOPWallet(); if (!wallet) { return null; } const messageBuffer = typeof message === 'string' ? new TextEncoder().encode(message) : message; const hashedMessage = this.sha256(messageBuffer); const messageHex = toHex(hashedMessage); const result = await wallet.web3.signMLDSAMessage(messageHex, typeof message === 'string' ? message : undefined); return { signature: fromHex(result.signature), message: hashedMessage, publicKey: fromHex(result.publicKey), securityLevel: result.securityLevel, }; } async signMessageAuto(message, keypair) { if (!keypair) { const walletResult = await this.trySignSchnorrWithOPWallet(message); if (walletResult) { return walletResult; } throw new Error('No keypair provided and OP_WALLET is not available.'); } return this.signMessage(keypair, message); } async signMessageECDSAAuto(message, keypair) { if (!keypair) { const walletResult = await this.trySignECDSAWithOPWallet(message); if (walletResult) { return walletResult; } throw new Error('No keypair provided and OP_WALLET is not available.'); } return this.signECDSA(keypair, message); } async tweakAndSignMessageAuto(message, keypair, network) { if (!keypair) { const walletResult = await this.trySignSchnorrWithOPWallet(message); if (walletResult) { return walletResult; } throw new Error('No keypair provided and OP_WALLET is not available.'); } if (!network) { throw new Error('Network is required when signing with a local keypair.'); } return this.tweakAndSignMessage(keypair, message, network); } async signMLDSAMessageAuto(message, mldsaKeypair) { if (!mldsaKeypair) { const walletResult = await this.trySignMLDSAWithOPWallet(message); if (walletResult) { return walletResult; } throw new Error('No ML-DSA keypair provided and OP_WALLET is not available.'); } return this.signMLDSAMessage(mldsaKeypair, message); } async verifyMLDSAWithOPWallet(message, signature) { const wallet = this.getOPWallet(); if (!wallet) { return null; } const messageBuffer = typeof message === 'string' ? new TextEncoder().encode(message) : message; const hashedMessage = this.sha256(messageBuffer); const mldsaSignature = { signature: toHex(signature.signature), publicKey: toHex(signature.publicKey), securityLevel: signature.securityLevel, messageHash: toHex(hashedMessage), }; return wallet.web3.verifyMLDSASignature(toHex(hashedMessage), mldsaSignature); } async getMLDSAPublicKeyFromOPWallet() { const wallet = this.getOPWallet(); if (!wallet) { return null; } const publicKeyHex = await wallet.web3.getMLDSAPublicKey(); return fromHex(publicKeyHex); } tweakAndSignMessage(keypair, message, network) { const tweaked = TweakedSigner.tweakSigner(keypair, { network }); return this.signMessage(tweaked, message); } signMessage(keypair, message) { if (typeof message === 'string') { message = new TextEncoder().encode(message); } if (!keypair.privateKey) { throw new Error('Private key not found in keypair.'); } const hashedMessage = this.sha256(message); if (!backend.signSchnorr) { throw new Error('backend.signSchnorr is not available.'); } return { signature: backend.signSchnorr(hashedMessage, keypair.privateKey), message: hashedMessage, }; } signECDSA(keypair, message) { if (typeof message === 'string') { message = new TextEncoder().encode(message); } if (!keypair.privateKey) { throw new Error('Private key not found in keypair.'); } const hashedMessage = this.sha256(message); if (!backend.sign) { throw new Error('backend.signSchnorr is not available.'); } return { signature: backend.sign(hashedMessage, keypair.privateKey), message: hashedMessage, }; } verifyECDSASignature(publicKey, message, signature) { if (typeof message === 'string') { message = new TextEncoder().encode(message); } if (signature.length !== 64) { throw new Error('Invalid signature length.'); } const hashedMessage = this.sha256(message); if (!backend.verify) { throw new Error('backend.verifySchnorr is not available.'); } return backend.verify(hashedMessage, publicKey, signature); } verifySignature(publicKey, message, signature) { if (typeof message === 'string') { message = new TextEncoder().encode(message); } if (signature.length !== 64) { throw new Error('Invalid signature length.'); } const hashedMessage = this.sha256(message); if (!backend.verifySchnorr) { throw new Error('backend.verifySchnorr is not available.'); } return backend.verifySchnorr(hashedMessage, toXOnly(publicKey), signature); } tweakAndVerifySignature(publicKey, message, signature) { const tweakedPublicKey = EcKeyPair.tweakPublicKey(publicKey); return this.verifySignature(tweakedPublicKey, message, signature); } signMLDSAMessage(mldsaKeypair, message) { if (typeof message === 'string') { message = new TextEncoder().encode(message); } if (!mldsaKeypair.privateKey) { throw new Error('ML-DSA private key not found in keypair.'); } const hashedMessage = this.sha256(message); const signature = mldsaKeypair.sign(hashedMessage); return { signature: new Uint8Array(signature), message: hashedMessage, publicKey: new Uint8Array(mldsaKeypair.publicKey), securityLevel: mldsaKeypair.securityLevel, }; } verifyMLDSASignature(mldsaKeypair, message, signature) { if (typeof message === 'string') { message = new TextEncoder().encode(message); } const hashedMessage = this.sha256(message); return mldsaKeypair.verify(hashedMessage, signature); } isOPWalletAvailable() { return this.getOPWallet() !== null; } getOPWallet() { if (typeof window === 'undefined') { return null; } const _window = window; if (!_window.opnet || !isOPWallet(_window.opnet)) { return null; } return _window.opnet; } } export const MessageSigner = new MessageSignerBase(); //# sourceMappingURL=MessageSigner.js.map