]> git.codecow.com Git - libnemo.git/commitdiff
BIP-32 specifies compressed public key serialization, so remove references to uncompr...
authorChris Duncan <chris@zoso.dev>
Fri, 5 Dec 2025 22:13:42 +0000 (14:13 -0800)
committerChris Duncan <chris@zoso.dev>
Fri, 5 Dec 2025 22:13:42 +0000 (14:13 -0800)
src/lib/crypto/secp256k1.ts

index 50c006884961f3e2ab8ad4f70b373ab2fce0b342..6b5cf9f05a2a74bf2c482e0b70fbe2b8cb678937 100644 (file)
  * noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com)
  */
 
+/** Alias to Uint8Array. */
+type Bytes = Uint8Array<ArrayBuffer>
+
+/** Point in 3d xyz coordinates. */
 type Point = {
        X: bigint
        Y: bigint
        Z: bigint
 }
 
-/** Alias to Uint8Array. */
-type Bytes = Uint8Array<ArrayBuffer>
-
 /** Point in 2d xy affine coordinates. */
 type AffinePoint = {
        x: bigint
        y: bigint
 }
 
-/** Type arithmetic to enable validation of literal integer types */
-type EnsureNumber<A extends number> = A extends number ? A : never
-type Length<T extends any[]> = EnsureNumber<T['length']>
-type Tuple<N extends number, T, Accumulator extends T[] = []> = Length<Accumulator> extends N ? Accumulator : Tuple<N, T, [...Accumulator, T]>
-type Add<A extends number, B extends number> = Length<[...Tuple<A, any>, ...Tuple<B, any>]>
-
-/** Public key length definitions */
-type Secp256k1Lengths = {
-       compressed: Add<typeof Secp256k1.L, 1>
-       uncompressed: Add<typeof Secp256k1.L2, 1>
-}
-
 export class Secp256k1 {
        /**
         * Curve params. secp256k1 is short weierstrass / koblitz curve. Equation is y² == x³ + ax + b.
@@ -58,10 +47,7 @@ export class Secp256k1 {
 
        static L: 32 = 32 // field / group byte length
        static L2: 64 = 64
-       static pkLength: Secp256k1Lengths = {
-               compressed: 33,
-               uncompressed: 65
-       }
+       static pkLength: 33 = 33
 
        // ## Helpers
        // ----------
@@ -259,7 +245,7 @@ export class Secp256k1 {
                const tail = bytes.subarray(1)
                const x = this.bytesToBigint(tail.subarray(0, this.L))
                // No actual validation is done here: use .assertValidity()
-               if (length === this.pkLength.compressed && (head === 0x02 || head === 0x03)) {
+               if (length === this.pkLength && (head === 0x02 || head === 0x03)) {
                        // Equation is y² == x³ + ax + b. We calculate y from x.
                        // y = √y²; there are two solutions: y, -y. Determine proper solution based on prefix
                        let y = this.lift_x(x)
@@ -268,18 +254,15 @@ export class Secp256k1 {
                        if (evenH !== evenY) y = this.M(-y)
                        p = this.Point(x, y, 1n)
                }
-               // Uncompressed 65-byte point, 0x04 prefix
-               if (length === this.pkLength.uncompressed && head === 0x04) p = this.Point(x, this.bytesToBigint(tail.subarray(this.L, this.L2)), 1n)
                // Validate point
                return this.isValidPoint(p)
        }
 
        /** Converts point to 33/65-byte Uint8Array. */
-       static pointToBytes (p: Point, isCompressed = true): Bytes {
+       static pointToBytes (p: Point): 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))
+               return this.concatBytes(this.getPrefix(y), x32b)
        }
 
        /** Generator / base point */
@@ -326,16 +309,15 @@ export class Secp256k1 {
        }
 
        /** Creates 33/65-byte public key from 32-byte private key. */
-       static getPublicKey (sk: Bytes, isCompressed = true): Bytes {
-               const pk = this.pointToBytes(this.wNAF(this.secretKeyToScalar(sk)).p, isCompressed)
+       static getPublicKey (sk: Bytes): Bytes {
+               const pk = this.pointToBytes(this.wNAF(this.secretKeyToScalar(sk)).p)
                return this.isValidPublicKey(pk) ? pk : this.err('derived invalid public key from secret key')
        }
 
-       static isValidPublicKey (pk: Bytes, isCompressed?: boolean): boolean {
+       static isValidPublicKey (pk: Bytes): boolean {
                try {
                        const l = pk.length
-                       if (isCompressed === true && l !== this.pkLength.compressed) return false
-                       if (isCompressed === false && l !== this.pkLength.uncompressed) return false
+                       if (l !== this.pkLength) return false
                        return !!this.pointFromBytes(pk)
                } catch (error) {
                        return false