UNPKG

@covenance/dlc

Version:

Crypto and Bitcoin functions for Covenance DLC implementation

153 lines (138 loc) 4.69 kB
import { Point, utils } from './crypto/secp256k1'; import { Signature, SignatureHex, AdaptorSignature, AdaptorSignatureHex } from './crypto/types'; /** * Converts a hex string to a Uint8Array * @param hex - The hex string to convert * @returns The Uint8Array representation of the hex string */ export function hexToBytes(hex: string): Uint8Array { const bytes = new Uint8Array(hex.length / 2); for (let i = 0; i < hex.length; i += 2) { bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16); } return bytes; } /** * Converts a Uint8Array to a hex string * @param bytes - The Uint8Array to convert * @returns The hex string representation of the Uint8Array */ export function bytesToHex(bytes: Uint8Array): string { return Array.from(bytes) .map(b => b.toString(16).padStart(2, '0')) .join(''); } /** * Converts a Point to a hex string * @param point - The Point to convert * @returns The hex string representation of the Point */ export function pointToHex(point: Point): string { return bytesToHex(point.toRawBytes(true)); } /** * Converts a hex string to a Point * @param hex - The hex string to convert * @returns The Point representation of the hex string */ export function hexToPoint(hex: string): Point { return Point.fromHex(hex); } /** * Converts a Signature to a hex string representation * @param sig - The Signature to convert * @returns The hex string representation of the Signature */ export function signatureToHex(sig: Signature): SignatureHex { return { R: pointToHex(sig.R), s: sig.s.toString(16) }; } /** * Converts a hex string representation to a Signature * @param hex - The hex string representation to convert * @returns The Signature representation of the hex string */ export function hexToSignature(hex: SignatureHex): Signature { return { R: hexToPoint(hex.R), s: BigInt('0x' + hex.s) }; } /** * Converts an AdaptorSignature to a hex string representation * @param sig - The AdaptorSignature to convert * @returns The hex string representation of the AdaptorSignature */ export function adaptorSignatureToHex(sig: AdaptorSignature): AdaptorSignatureHex { return { R_prime: pointToHex(sig.R_prime), s_prime: sig.s_prime.toString(16) }; } /** * Converts a hex string representation to an AdaptorSignature * @param hex - The hex string representation to convert * @returns The AdaptorSignature representation of the hex string */ export function hexToAdaptorSignature(hex: AdaptorSignatureHex): AdaptorSignature { return { R_prime: hexToPoint(hex.R_prime), s_prime: BigInt('0x' + hex.s_prime) }; } /** * Computes the hash of a message using SHA256 * @param message - The message to hash * @returns The hash of the message */ export async function sha256(message: Uint8Array): Promise<Uint8Array> { return utils.sha256(message); } /** * Computes the hash of a message using SHA256 and returns it as a hex string * @param message - The message to hash * @returns The hex string representation of the hash */ export async function sha256Hex(message: string): Promise<string> { const hash = await sha256(hexToBytes(message)); return bytesToHex(hash); } /** * Copies a bigint to a Uint8Array as big-endian * @param dst - The Uint8Array to copy to * @param offset - The offset to copy to * @param n - The bigint to copy */ export function be32(dst: Uint8Array, offset: number, n: bigint): void { for (let i = 31; i >= 0; i--) { dst[offset + i] = Number(n & 0xffn); n >>= 8n; } if (n) throw new RangeError('integer > 256 bits'); } /** * Convert seconds → BIP68 buffer. * Uses 512-second granularity, sets the type flag (bit 22). * Throws if out of range (> 0xffff * 512 seconds). * @param seconds - The number of seconds to convert * @returns The BIP68 buffer */ export function csvTimeDelay(seconds: number): Buffer { if (!Number.isFinite(seconds) || seconds < 0) throw new RangeError("seconds ≥ 0"); const units = Math.ceil(seconds / 512); if (units > 0xffff) throw new RangeError("max 0xffff * 512s ≈ 388.5 days"); const TYPE_FLAG = 1 << 22; const value = TYPE_FLAG | units; const data = encodeScriptNum(value); // minimal ScriptNum return data; } export function encodeScriptNum(n: number): Buffer { if (n === 0) return Buffer.alloc(0); // minimal zero const bytes: number[] = []; let v = n >>> 0; // n ≤ 0x0040ffff fits 32-bit while (v) { bytes.push(v & 0xff); v >>>= 8; } // little-endian magnitude if (bytes[bytes.length - 1] & 0x80) bytes.push(0x00);// keep positive (no sign bit set) return Buffer.from(bytes); }