UNPKG

@btc-vision/transaction

Version:

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

81 lines (80 loc) 2.5 kB
const P = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn; export class Secp256k1PointDeriver { constructor(maxTries = 10000) { this.maxTries = maxTries; } findOrDeriveValidPoint(xBytes, failOnInvalidX = true, maxTries = this.maxTries) { if (xBytes.length !== 32) { throw new Error('xBytes must be exactly 32 bytes.'); } let xCandidate = this.bytesToBigInt(xBytes) % P; let sqrtVal = this.isValidX(xCandidate); if (failOnInvalidX && sqrtVal === null) { throw new Error(`The given x is not a valid curve point.`); } let tries = 0; while (sqrtVal === null) { xCandidate = (xCandidate + 1n) % P; sqrtVal = this.isValidX(xCandidate); tries++; if (tries > maxTries) { throw new Error(`Could not find a valid X point within ${maxTries} increments.`); } } const y1 = sqrtVal; const y2 = (P - y1) % P; return { x: xCandidate, y1, y2 }; } getCanonicalY(y, y2) { return y < y2 ? y : y2; } getHybridPublicKey(x, y) { const prefix = y % 2n === 0n ? 0x06 : 0x07; const xBytes = this.bigIntTo32Bytes(x); const yBytes = this.bigIntTo32Bytes(y); const hybrid = new Uint8Array(65); hybrid[0] = prefix; hybrid.set(xBytes, 1); hybrid.set(yBytes, 33); return hybrid; } isValidX(x) { const alpha = (this.modPow(x, 3n, P) + 7n) % P; return this.sqrtModP(alpha, P); } modPow(base, exp, m) { let result = 1n; let cur = base % m; let e = exp; while (e > 0) { if ((e & 1n) === 1n) { result = (result * cur) % m; } cur = (cur * cur) % m; e >>= 1n; } return result; } sqrtModP(a, prime) { const root = this.modPow(a, (prime + 1n) >> 2n, prime); if ((root * root) % prime !== a % prime) { return null; } return root; } bytesToBigInt(bytes) { let b = 0n; for (const byte of bytes) { b = (b << 8n) | BigInt(byte); } return b; } bigIntTo32Bytes(value) { const bytes = new Uint8Array(32); for (let i = 31; i >= 0; i--) { bytes[i] = Number(value & 0xffn); value >>= 8n; } return bytes; } }