UNPKG

lotus-sdk

Version:

Central repository for several classes of tools for integrating with, and building for, the Lotusia ecosystem

128 lines (127 loc) 4.29 kB
import elliptic from 'elliptic'; import { BN } from './bn.js'; const ecInstance = new elliptic.ec('secp256k1'); const ecPoint = ecInstance.curve.point.bind(ecInstance.curve); const ecPointFromX = ecInstance.curve.pointFromX.bind(ecInstance.curve); export class Point { _point; constructor(x, y, isRed) { try { const bnX = x instanceof BN ? x.bn : new BN(x); const bnY = y instanceof BN ? y.bn : new BN(y); this._point = ecPoint(bnX, bnY, isRed); } catch (e) { throw new Error('Invalid Point'); } this.validate(); } static fromX(odd, x) { try { const xStr = typeof x === 'string' ? x : x.toString(); let point; try { const bnX = x instanceof BN ? x.bn : new BN(xStr); point = ecInstance.curve.pointFromX(bnX, odd); } catch (e1) { try { const hexStr = typeof x === 'string' ? x : '0x' + x.toString(16); const bnX = new BN(hexStr); point = ecInstance.curve.pointFromX(bnX, odd); } catch (e2) { const xBigInt = typeof x === 'string' ? new BN(xStr) : x.bn; const y = ecInstance.curve.yFromX(xBigInt.toString(), odd); point = ecInstance.curve.point(xBigInt.toString(), y); } } const instance = new Point(new BN(0), new BN(0)); instance._point = point; instance.validate(); return instance; } catch (e) { throw new Error('Invalid X'); } } static getG() { const instance = new Point(new BN(0), new BN(0)); instance._point = ecInstance.curve.g; return instance; } static getN() { return new BN(ecInstance.curve.n.toArray()); } getX() { return new BN(this._point.getX().toString()); } getY() { return new BN(this._point.getY().toString()); } validate() { if (this.isInfinity()) { throw new Error('Point cannot be equal to Infinity'); } try { const x = this.getX(); const y = this.getY(); if (x === undefined || y === undefined) { throw new Error('Point coordinates are undefined'); } const n = ecInstance.curve.n; const infinityPoint = this._point.mul(n); if (!infinityPoint.isInfinity()) { throw new Error('Point is not in the correct subgroup'); } } catch (e) { throw new Error('Point does not lie on the curve'); } return this; } isInfinity() { return this._point.isInfinity(); } add(other) { const result = new Point(new BN(0), new BN(0)); result._point = this._point.add(other._point); return result; } mul(scalar) { const result = new Point(new BN(0), new BN(0)); result._point = this._point.mul(scalar.bn); return result; } mulAdd(scalar1, other, scalar2) { const result = new Point(new BN(0), new BN(0)); const point1 = this._point.mul(scalar1.bn); const point2 = other._point.mul(scalar2.bn); result._point = point1.add(point2); return result; } eq(other) { return this._point.eq(other._point); } static pointToCompressed(point) { const xbuf = point.getX().toArrayLike(Buffer, 'be', 32); const y = point.getY(); const odd = y.mod(new BN(2)).isOdd(); const prefix = odd ? Buffer.from([0x03]) : Buffer.from([0x02]); return Buffer.concat([prefix, xbuf]); } hasSquare() { if (this.isInfinity()) { return false; } const y = this.getY(); return !y.isOdd(); } isSquare(x) { const p = new BN('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16); const x0 = new BN(x.toString()); const exponent = p.sub(new BN(1)).div(new BN(2)); const result = x0.modPow(exponent, p); return result.eq(new BN(1)); } }