@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
JavaScript
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;
}
}