npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ec-compression

v2.0.0

Published

Readme

ec-compression

Elliptic curve public key point compression and decompression, with no runtime dependencies.

A public key on a short Weierstrass curve is a point (x, y). Because y is determined by x up to its parity, the point can be stored in compressed form (a parity prefix plus the x coordinate) instead of its full uncompressed form. This library converts between the two forms and validates that a given point lies on the curve.

Supported curves: secp256r1 (P-256), secp384r1 (P-384), secp521r1 (P-521), and secp256k1.

Installation

npm install ec-compression

Point encoding

Keys are represented as Uint8Array using the SEC1 encoding:

  • Compressed: 0x02 || x when y is even, 0x03 || x when y is odd.
  • Uncompressed: 0x04 || x || y.

Inputs whose coordinates lost leading zero bytes (as some JWK producers emit for P-521) are accepted; output is always canonical SEC1, with coordinates padded to the full curve width.

Usage

Compress and decompress

The curve may be a CurveParams instance or a curve name (see Curve names).

import { compressPublicKey, decompressPublicKey } from 'ec-compression'

const compressed = compressPublicKey(uncompressedKey, 'p256')
const uncompressed = decompressPublicKey(compressed, 'p256')

Both functions throw if the input is not a valid point for the given curve.

Best-effort variants

The *IfPossible variants return the input unchanged instead of throwing when it cannot be converted. This is useful when a key may already be in the desired form.

import {
  compressPublicKeyIfPossible,
  decompressPublicKeyIfPossible,
} from 'ec-compression'

const compressed = compressPublicKeyIfPossible(key, 'p256')

Validation

import {
  isValidCompressedPublicKeyFormat,
  isValidDecompressedPublicKeyFormat,
  isValidPublicKeyFormat,
} from 'ec-compression'

isValidCompressedPublicKeyFormat(key, 'p256')
isValidDecompressedPublicKeyFormat(key, 'p256')
isValidPublicKeyFormat(key, 'p256') // either form

Each check verifies the encoding prefix and length, and that the decoded point lies on the curve.

Working with points directly

AffinePoint exposes the underlying conversion.

import { AffinePoint, Secp256r1 } from 'ec-compression'

const point = AffinePoint.fromCompressedPoint(compressedKey, Secp256r1)

point.x // bigint
point.y // bigint
point.compressedForm // Uint8Array
point.decompressedForm // Uint8Array
point.isValidPoint(Secp256r1) // boolean

const other = new AffinePoint(xBigintOrBytes, yBigintOrBytes, Secp256r1)
AffinePoint.fromDecompressedPoint(uncompressedKey, Secp256r1)

API

Compression functions

  • compressPublicKey(uncompressed: Uint8Array, curve: CurveParams | string): Uint8Array
  • decompressPublicKey(compressed: Uint8Array, curve: CurveParams | string): Uint8Array
  • compressPublicKeyIfPossible(key: Uint8Array, curve: CurveParams | string): Uint8Array
  • decompressPublicKeyIfPossible(key: Uint8Array, curve: CurveParams | string): Uint8Array

Validation functions

  • isValidCompressedPublicKeyFormat(key: Uint8Array, curve: CurveParams | string): boolean
  • isValidDecompressedPublicKeyFormat(key: Uint8Array, curve: CurveParams | string): boolean
  • isValidPublicKeyFormat(key: Uint8Array, curve: CurveParams | string): boolean

AffinePoint

  • new AffinePoint(x: Uint8Array | bigint, y: Uint8Array | bigint, curve: CurveParams | string)
  • AffinePoint.fromCompressedPoint(form: Uint8Array | bigint, curve: CurveParams | string): AffinePoint
  • AffinePoint.fromDecompressedPoint(form: Uint8Array | bigint, curve: CurveParams | string): AffinePoint
  • point.x / point.y — coordinates as bigint
  • point.xBytes / point.yBytes — coordinates as full-width Uint8Array
  • point.compressedForm / point.decompressedForm — encoded key as Uint8Array
  • point.isValidPoint(curve: CurveParams | string): boolean

Curves

  • Secp256r1, Secp384r1, Secp521r1, Secp256k1 — CurveParams instances.
  • getCurveParamsByName(name: string): CurveParams | undefined
  • resolveCurveParams(curve: CurveParams | string): CurveParams — like getCurveParamsByName, but accepts an instance and throws on unknown names.
  • CurveParams — class holding the curve parameters p, a, b, pointBitLength, and names.

Curve names

Name lookups are case-insensitive. The following aliases are recognised:

| Curve | Aliases | | ----------- | ------------------------------ | | Secp256r1 | secp256r1, p256, p-256 | | Secp384r1 | secp384r1, p384, p-384 | | Secp521r1 | secp521r1, p521, p-521 | | Secp256k1 | secp256k1, k256, k-256 |

Conversion helpers

  • bigintToBytes(value: bigint, length?: number): Uint8Array — big-endian, zero-padded to length when given; throws on negative input.
  • bytesToBigint(bytes: Uint8Array): bigint — big-endian; throws on empty input.

Development

pnpm install
pnpm test
pnpm lint
pnpm build

The number of randomized round-trip cases per curve can be set with the TESTS_PER_CURVE environment variable (default 100).

License

MIT