Elliptic Curve Integrated Encryption Scheme for secp256k1/curve25519 in TypeScript.
This is the JavaScript/TypeScript version of eciespy with a built-in class-like secp256k1/curve25519 API.
You can learn the details in DETAILS.md.
npm install eciesjsWe recommend using the latest JavaScript/TypeScript runtime although it's still possible to install on some old versions.
This library supports multiple platforms (browser, node, bun/deno, react native), see Multi-platform Support.
For security, see Security.
// example/runtime/quick-start.js
import { PrivateKey, decrypt, encrypt } from "eciesjs";
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const sk = new PrivateKey();
const data = encoder.encode("hello world🌍");
const decrypted = decrypt(sk.secret, encrypt(sk.publicKey.toBytes(), data));
console.log(decoder.decode(decrypted));Or run the example code:
$ pnpm install && pnpm build && cd example/runtime && pnpm install && node quick-start.js
hello world🌍See Configuration to control with more granularity.
Parameters:
receiverRawPK- Receiver's public key, hexstringorUint8Arraydata- Data to encrypt
Returns: Uint8Array
Parameters:
receiverRawSK- Receiver's private key, hexstringorUint8Arraydata- Data to decrypt
Returns: Uint8Array
- Methods
static fromHex(hex: string, curve?: EllipticCurve): PrivateKey;
constructor(secret?: Uint8Array, curve?: EllipticCurve);
toHex(): string;
encapsulate(pk: PublicKey, compressed?: boolean): Uint8Array;
multiply(pk: PublicKey, compressed?: boolean): Uint8Array;
equals(other: PrivateKey): boolean;- Properties
get secret(): Uint8Array;
readonly publicKey: PublicKey;- Methods
static fromHex(hex: string, curve?: EllipticCurve): PublicKey;
constructor(data: Uint8Array, curve?: EllipticCurve);
toBytes(compressed?: boolean): Uint8Array;
toHex(compressed?: boolean): string;
decapsulate(sk: PrivateKey, compressed?: boolean): Uint8Array;
equals(other: PublicKey): boolean;Following configurations are available.
- Elliptic curve: secp256k1 or curve25519 (x25519/ed25519)
- Ephemeral key format in the payload: compressed or uncompressed (only for secp256k1)
- Shared elliptic curve key format in the key derivation: compressed or uncompressed (only for secp256k1)
- Symmetric cipher algorithm: AES-256-GCM or XChaCha20-Poly1305
- Symmetric nonce length: 12 or 16 bytes (only for AES-256-GCM)
For compatibility, make sure different applications share the same configuration.
export type EllipticCurve = "secp256k1" | "x25519" | "ed25519";
export type SymmetricAlgorithm = "aes-256-gcm" | "xchacha20";
export type NonceLength = 12 | 16;
export class Config {
ellipticCurve: EllipticCurve = "secp256k1";
isEphemeralKeyCompressed: boolean = false;
isHkdfKeyCompressed: boolean = false;
symmetricAlgorithm: SymmetricAlgorithm = "aes-256-gcm";
symmetricNonceLength: NonceLength = 16;
}
export const ECIES_CONFIG = new Config();On ellipticCurve = "x25519" or ellipticCurve = "ed25519", x25519 (key exchange function on curve25519) or ed25519 (signature algorithm on curve25519) will be used for key exchange instead of secp256k1.
In this case, the payload would always be: 32 Bytes + Ciphered regardless of isEphemeralKeyCompressed.
If you don't know how to choose between x25519 and ed25519, just use the dedicated key exchange function x25519 for efficiency.
Because any 32-byte data is a valid curve25519 public key, the payload would seem random. This property is excellent for circumventing censorship by adversaries.
On isEphemeralKeyCompressed = true, the payload would be: 33 Bytes + Ciphered instead of 65 Bytes + Ciphered.
On isHkdfKeyCompressed = true, the hkdf key would be derived from ephemeral public key (compressed) + shared public key (compressed) instead of ephemeral public key (uncompressed) + shared public key (uncompressed).
On symmetricAlgorithm = "xchacha20", plaintext data would be encrypted with XChaCha20-Poly1305.
On symmetricNonceLength = 12, the nonce of AES-256-GCM would be 12 bytes. XChaCha20-Poly1305's nonce is always 24 bytes regardless of symmetricNonceLength.
For compatibility with other ecies libraries, start with the default (secp256k1 with AES-256-GCM).
For speed and security, pick x25519 with XChaCha20-Poly1305.
If you know exactly what you are doing, configure as you wish or build your own ecies logic with this library.
| Fully Supported | |
|---|---|
| Node | ✅ |
| Bun | ✅ |
| Deno | ✅ (see below) |
| Browser | ✅ |
| React Native | ✅ |
Via @ecies/ciphers, node:crypto's native implementation of AES-256-GCM and XChaCha20-Poly1305 is chosen if available.
This library is browser-friendly, check the example/browser directory for details. You can check the online demo as well.
If you want a WASM version to run directly in modern browsers or on some blockchains, you can also try ecies-wasm.
For bun/deno, see example/runtime. There are some limitations currently, mentioned in @ecies/ciphers:
chacha20-poly1305's pure JS implementation is used on bun (node:crypto'schacha20-poly1305is not available due to lack of implementation);chacha20-poly1305does not work on deno by default. You need to upgrade deno and run with--conditions deno(>=2.4.0) or--unstable-node-conditions deno(>=2.3.6,<2.4.0).
See the React Native demo.
To mitigate security risks, such as supply chain attacks and zero-day vulnerabilities, we only use node:crypto and these audited dependencies:
Every release is built on GitHub Actions with provenance.
This library is fully auditable as well. We're seeking funding for a professional third-party security audit to verify implementation and identify potential vulnerabilities.
If you rely on this library or value secure open-source cryptography, please consider donating to help fund this audit.
See CHANGELOG.md.
