X: bigint
Y: bigint
Z: bigint
- toAffine: () => AffinePoint
- toBytes: (isCompressed?: boolean) => Bytes
}
/** Alias to Uint8Array. */
return this.Point(X3, Y3, Z3)
}
+ /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
+ static Affine (p: Point): AffinePoint {
+ const { X: x, Y: y, Z: z } = p
+ // fast-paths for ZERO point OR Z=1
+ if (this.Equals(p, this.I)) return { x: 0n, y: 0n }
+ if (z === 1n) return { x, y }
+ const iz = this.invert(z)
+ // (Z * Z^-1) must be 1, otherwise bad math
+ if (this.M(z * iz) !== 1n) this.err('inverse invalid')
+ // x = X*Z^-1; y = Y*Z^-1
+ return { x: this.M(x * iz), y: this.M(y * iz) }
+ }
+
/** Point doubling: P+P */
static Double (p: Point) {
return this.Add(p, p)
X: this.bigintInRange(X, 0n, this.P),
Y: this.bigintInRange(Y, 1n, this.P), // Y can't be 0 in Projective
Z: this.bigintInRange(Z, 0n, this.P),
- /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
- toAffine (): AffinePoint {
- const { X: x, Y: y, Z: z } = this
- // fast-paths for ZERO point OR Z=1
- if (secp256k1.Equals(this, secp256k1.I)) return { x: 0n, y: 0n }
- if (z === 1n) return { x, y }
- const iz = secp256k1.invert(z)
- // (Z * Z^-1) must be 1, otherwise bad math
- if (secp256k1.M(z * iz) !== 1n) secp256k1.err('inverse invalid')
- // x = X*Z^-1; y = Y*Z^-1
- return { x: secp256k1.M(x * iz), y: secp256k1.M(y * iz) }
- },
- /** Converts point to 33/65-byte Uint8Array. */
- toBytes (isCompressed = true): Bytes {
- const { x, y } = secp256k1.isValidPoint(this).toAffine()
- const x32b = secp256k1.bigintTo32Bytes(x)
- if (isCompressed) return secp256k1.concatBytes(secp256k1.getPrefix(y), x32b)
- return secp256k1.concatBytes(Uint8Array.of(0x04), x32b, secp256k1.bigintTo32Bytes(y))
- }
})
}
return this.isValidPoint(p)
}
+ /** Converts point to 33/65-byte Uint8Array. */
+ static pointToBytes (p: Point, isCompressed = true): Bytes {
+ const { x, y } = this.Affine(this.isValidPoint(p))
+ const x32b = this.bigintTo32Bytes(x)
+ if (isCompressed) return this.concatBytes(this.getPrefix(y), x32b)
+ return this.concatBytes(Uint8Array.of(0x04), x32b, this.bigintTo32Bytes(y))
+ }
+
/** Generator / base point */
static G: Point = this.Point(this.Gx, this.Gy, 1n)
/** Identity / zero point */
/** Checks if the point is valid and on-curve. */
static isValidPoint (p?: Point): Point {
if (p) {
- const { x, y } = p.toAffine() // convert to 2d xy affine point.
+ const { x, y } = this.Affine(p) // convert to 2d xy affine point.
this.bigintInRange(x, 1n, this.P) // must be in range 1 <= x,y < P
this.bigintInRange(y, 1n, this.P)
// y² == x³ + ax + b, equation sides must be equal
/** Creates 33/65-byte public key from 32-byte private key. */
static getPublicKey (sk: Bytes, isCompressed = true): Bytes {
- return this.wNAF(this.secretKeyToScalar(sk)).p.toBytes(isCompressed)
+ const pk = this.pointToBytes(this.wNAF(this.secretKeyToScalar(sk)).p, isCompressed)
+ return this.isValidPublicKey(pk) ? pk : this.err('derived invalid public key from secret key')
}
static isValidPublicKey (pk: Bytes, isCompressed?: boolean): boolean {