UNPKG

ecash-lib

Version:

Library for eCash transaction building

102 lines 3.93 kB
"use strict"; // Copyright (c) 2025 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. Object.defineProperty(exports, "__esModule", { value: true }); exports.verifyMsg = exports.signMsg = exports.magicHash = void 0; const hash_1 = require("./hash"); const ecc_1 = require("./ecc"); const writerbytes_1 = require("./io/writerbytes"); const varsize_1 = require("./io/varsize"); const hex_1 = require("./io/hex"); const address_1 = require("./address/address"); /** * messages.ts * * Sign and verify messages */ const ECASH_MSG_SIGNING_PREFIX = '\x16eCash Signed Message:\n'; /** * Messages are prepared in a standard way before signing and verifying * * - The raw message (e.g., "Hello, world!") is encoded as a UTF-8 byte array * - The prefixed message is constructed as: * * [prefix][message_length][message] * * where message_length is a variable-length integer (varint) encoding the * byte length of the message * * We keep the "magicHash" name used in bitcoinjs-message as we do the same thing here * with eCash tools * * ref https://github.com/bitcoinjs/bitcoinjs-message/blob/master/index.js#L57 */ const magicHash = (message, messagePrefix = ECASH_MSG_SIGNING_PREFIX) => { const encoder = new TextEncoder(); // Convert prefix to Uint8Array const prefixBytes = encoder.encode(messagePrefix); // Convert message to Uint8Array const messageBytes = encoder.encode(message); // Calculate the maximum possible size of the varint for message length const maxVarintSize = messageBytes.length <= 0xfc ? 1 : messageBytes.length <= 0xffff ? 3 : messageBytes.length <= 0xffffffff ? 5 : 9; // Create a WriterBytes instance with enough capacity const writer = new writerbytes_1.WriterBytes(prefixBytes.length + maxVarintSize + messageBytes.length); // Write the prefix writer.putBytes(prefixBytes); // Write the message length as a varint (0, varsize_1.writeVarSize)(messageBytes.length, writer); // Write the message writer.putBytes(messageBytes); // Return double SHA-256 hash return (0, hash_1.sha256d)(writer.data); }; exports.magicHash = magicHash; /** * Sign a message * * While there is not an official BIP or spec here, there is * a de facto standard * * See implementation in bitcoinjs-lib and electrum */ const signMsg = (msg, sk, prefix = ECASH_MSG_SIGNING_PREFIX) => { const preparedMsg = (0, exports.magicHash)(msg, prefix); const sig = new ecc_1.Ecc().signRecoverable(sk, preparedMsg); // Convert Uint8Array to binary string and encode with btoa const binaryString = String.fromCharCode(...sig); return btoa(binaryString); }; exports.signMsg = signMsg; /** * Verify that a given message and signature * came from a given address */ const verifyMsg = (msg, signature, address, prefix = ECASH_MSG_SIGNING_PREFIX) => { try { const preparedMsg = (0, exports.magicHash)(msg, prefix); // Decode base64 signature to binary string and convert to Uint8Array const binaryString = atob(signature); const sig = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { sig[i] = binaryString.charCodeAt(i); } const recoveredPk = new ecc_1.Ecc().recoverSig(sig, preparedMsg); // Get recovered hash as a hex string and compare to tested hash const recoveredHash = (0, hex_1.toHex)((0, hash_1.shaRmd160)(recoveredPk)); const testedHash = address_1.Address.fromCashAddress(address).hash; return recoveredHash === testedHash; } catch (err) { console.error(`Error verifying signature`, err); return false; } }; exports.verifyMsg = verifyMsg; //# sourceMappingURL=messages.js.map