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

@digitaldefiance/ecies-lib

v5.1.2

Published

Digital Defiance ECIES Library

Readme

@digitaldefiance/ecies-lib

npm version License: MIT Tests

Production-ready, browser-compatible ECIES (Elliptic Curve Integrated Encryption Scheme) library for TypeScript. Built on Web Crypto API and @noble/curves with comprehensive encryption, key management, and authentication services. Binary compatible with @digitaldefiance/node-ecies-lib for seamless cross-platform operations.

Part of Express Suite

This library implements a modern, enterprise-grade ECIES protocol (v4.0) featuring HKDF key derivation, AAD binding, and optimized multi-recipient encryption. It includes a pluggable ID provider system with PlatformID support, memory-efficient streaming encryption, comprehensive internationalization, and a complete cryptographic voting system with 15+ voting methods.

Features

🛡️ Core Cryptography (Protocol v4.0)

  • Advanced ECIES:
    • HKDF-SHA256: Cryptographically robust key derivation (RFC 5869).
    • AAD Binding: Strict binding of header metadata and recipient IDs to the encryption context to prevent tampering.
    • Shared Ephemeral Key: Optimized multi-recipient encryption using a single ephemeral key pair, reducing payload size.
    • Compressed Keys: Uses 33-byte compressed public keys for efficiency.
  • Algorithms:
    • Curve: secp256k1 for ECDH key exchange and ECDSA signatures.
    • Symmetric: AES-256-GCM for authenticated symmetric encryption.
    • Hashing: SHA-256 and SHA-512.
    • Key Derivation: PBKDF2 with configurable profiles (Fast, Standard, Secure, Maximum).
    • Checksums: CRC8, CRC16-CCITT, CRC32 for data integrity.
  • Modes:
    • Basic: Minimal overhead (no length prefix) - Use for fixed-size data or when size is known
    • WithLength: Includes data length prefix - Use for variable-size data or streaming
    • Multiple: Efficient encryption for up to 65,535 recipients - Use for group messaging

🗳️ Cryptographic Voting System

  • 15+ Voting Methods: Plurality, Approval, Weighted, Borda Count, Score, Ranked Choice (IRV), STAR, STV, Yes/No, Supermajority, and more
  • Threshold Decryption: Distributed trust with k-of-n Guardians, real-time interval tallies, and zero-knowledge proofs (details)
  • Government-Grade Security: Homomorphic encryption, verifiable receipts, immutable audit logs, public bulletin board
  • Role Separation: Poll aggregators cannot decrypt votes until closure (separate PollTallier)
  • Multi-Round Support: True IRV, STAR voting, STV with intermediate decryption
  • Hierarchical Aggregation: Precinct → County → State → National vote aggregation
  • Event Logging: Comprehensive audit trail with microsecond timestamps
  • Browser Compatible: Works in Node.js and modern browsers

🆔 Enhanced Identity & Management

  • Pluggable ID Providers:
    • Flexible IDs: Support for ObjectId (12 bytes), GUID/UUID (16 bytes), or custom formats (1-255 bytes)
    • PlatformID Type: Generic type system supporting Uint8Array | Guid | ObjectId | string
    • Auto-Sync: Configuration automatically adapts all cryptographic constants to the selected ID provider
    • Member System: User abstraction with cryptographic operations, fully integrated with the configured ID provider
    • Strong Typing: New typed configuration system provides compile-time type safety for ID operations
  • Key Management:
    • BIP39: Mnemonic phrase generation (12-24 words).
    • HD Wallets: BIP32/BIP44 hierarchical deterministic derivation.
    • Secure Storage: Memory-safe SecureString and SecureBuffer with XOR obfuscation and auto-zeroing.

🚀 Advanced Capabilities

  • Streaming Encryption: Memory-efficient processing for large files (<10MB RAM usage for any file size) with Web Streams API transforms
  • Fluent Builders: Type-safe configuration with ECIESBuilder and MemberBuilder for clean, chainable APIs
  • Internationalization (i18n): Automatic error translation in 8 languages (en-US, en-GB, fr, es, de, zh-CN, ja, uk)
  • Runtime Configuration: Injectable configuration profiles via ConstantsRegistry for dependency injection and testing
  • Cross-Platform: Fully compatible with Node.js 18+ and modern browsers (Chrome, Edge, Firefox, Safari)
  • Voting System: Complete cryptographic voting implementation with government-grade security requirements

Installation

npm install @digitaldefiance/ecies-lib
# or
yarn add @digitaldefiance/ecies-lib

Requirements

Node.js: 18+ (Web Crypto API built-in) Browsers: Modern browsers with Web Crypto API support.

Architecture & Protocol

Module Dependency Architecture

The library follows a strict hierarchical module dependency structure to prevent circular dependencies and ensure reliable initialization:

graph TD
    A[Level 1: Enumerations] --> B[Level 2: Translations]
    B --> C[Level 3: i18n Setup]
    C --> D[Level 4: Errors & Utils]
    D --> E[Level 5: Constants & Services]
    
    A1[ecies-string-key.ts] -.-> A
    A2[ecies-error-type.ts] -.-> A
    A3[ecies-encryption-type.ts] -.-> A
    
    B1[en-US.ts] -.-> B
    B2[fr.ts] -.-> B
    B3[es.ts] -.-> B
    
    C1[i18n-setup.ts] -.-> C
    
    D1[errors/ecies.ts] -.-> D
    D2[utils/encryption-type-utils.ts] -.-> D
    
    E1[constants.ts] -.-> E
    E2[services/ecies/service.ts] -.-> E
    
    style A fill:#e1f5e1
    style B fill:#e3f2fd
    style C fill:#fff3e0
    style D fill:#fce4ec
    style E fill:#f3e5f5

Dependency Levels:

  1. Level 1 - Enumerations (Pure, no dependencies)

    • Contains only TypeScript enums and type definitions
    • No imports from other project modules
    • Examples: EciesStringKey, EciesErrorType, EciesEncryptionType
  2. Level 2 - Translations (Depends only on Level 1)

    • Translation objects mapping enum keys to localized strings
    • Only imports enumerations
    • Examples: en-US.ts, fr.ts, es.ts
  3. Level 3 - i18n Setup (Depends on Levels 1-2)

    • Initializes the internationalization engine
    • Imports enumerations and translations
    • Example: i18n-setup.ts
  4. Level 4 - Errors & Utilities (Depends on Levels 1-3)

    • Error classes with lazy i18n initialization
    • Utility functions that may throw errors
    • Examples: errors/ecies.ts, utils/encryption-type-utils.ts
  5. Level 5 - Constants & Services (Depends on Levels 1-4)

    • Configuration constants and validation
    • Business logic and cryptographic services
    • Examples: constants.ts, services/ecies/service.ts

Key Principles:

  • Enumerations are pure: No imports except TypeScript types
  • Translations are data-only: Only import enumerations
  • Errors use lazy i18n: Translation lookup deferred until message access
  • Constants validate safely: Early errors use basic Error class with fallback messages

ECIES v4.0 Protocol Flow

The library implements a robust ECIES variant designed for security and efficiency.

  1. Key Derivation (HKDF): Shared secrets from ECDH are passed through HKDF-SHA256 to derive the actual symmetric encryption keys. This ensures that the resulting keys have uniform distribution and are resistant to weak shared secrets.

    SymmetricKey = HKDF(
      secret: ECDH(EphemeralPriv, RecipientPub),
      salt: empty,
      info: "ecies-v2-key-derivation"
    )
  2. Authenticated Encryption (AAD): All encryption operations use AES-256-GCM with Additional Authenticated Data (AAD).

    • Key Encryption: The Recipient's ID is bound to the encrypted key.
    • Message Encryption: The Message Header (containing version, algorithm, ephemeral key, etc.) is bound to the encrypted payload. This prevents "context manipulation" attacks where an attacker might try to swap recipient IDs or modify header metadata.
  3. Multi-Recipient Optimization: Instead of generating a new ephemeral key pair for every recipient, the sender generates one ephemeral key pair for the message.

    • The ephemeral public key is stored once in the header.
    • A random "Message Key" is generated.
    • This Message Key is encrypted individually for each recipient using the shared secret derived from the single ephemeral key and the recipient's public key.

ID Provider System

The library is agnostic to the format of unique identifiers. The IdProvider system drives the entire configuration and now supports the PlatformID type for enhanced cross-platform compatibility:

  • ObjectIdProvider (Default): 12-byte MongoDB-style IDs.
  • GuidV4Provider: 16-byte raw GUIDs.
  • UuidProvider: 16-byte UUIDs (string representation handles dashes).
  • CustomIdProvider: Define your own size (1-255 bytes).

The PlatformID type supports multiple ID formats:

export type PlatformID = Uint8Array | Guid | ObjectId | string;

When you configure an ID provider, the library automatically:

  • Updates MEMBER_ID_LENGTH.
  • Updates ECIES.MULTIPLE.RECIPIENT_ID_SIZE.
  • Validates that all internal constants are consistent.
  • Provides seamless integration with the voting system through generic type parameters.

Quick Start

1. Basic Configuration & Usage

import { 
  ECIESService, 
  getEciesI18nEngine, 
  createRuntimeConfiguration, 
  ObjectIdProvider,
  getEnhancedIdProvider,
  AESGCMService
} from '@digitaldefiance/ecies-lib';

try {
  // 1. Initialize i18n (required once)
  getEciesI18nEngine();

  // 2. Configure (Optional - defaults to ObjectIdProvider)
  const config = createRuntimeConfiguration({
    idProvider: new ObjectIdProvider()
  });

  // 3. Initialize Service
  const ecies = new ECIESService(config);

  // 4. Generate Keys
  const mnemonic = ecies.generateNewMnemonic();
  const { privateKey, publicKey } = ecies.mnemonicToSimpleKeyPair(mnemonic);

  // 5. Encrypt & Decrypt
  const message = new TextEncoder().encode('Hello, Secure World!');
  const encrypted = await ecies.encryptWithLength(publicKey, message);
  const decrypted = await ecies.decryptWithLengthAndHeader(privateKey, encrypted);

  console.log(new TextDecoder().decode(decrypted)); // "Hello, Secure World!"

  // 6. Strong Typing for ID Operations
  const idProvider = getEnhancedIdProvider<ObjectId>();
  const objectId = idProvider.generateTyped(); // Returns ObjectId - strongly typed!
  const serialized = idProvider.serializeTyped(objectId);
  const deserialized = idProvider.deserializeTyped(serialized);

  // 7. AES-GCM Service (Instance-based)
  const aesGcm = new AESGCMService();
  const key = crypto.getRandomValues(new Uint8Array(32));
  const data = new TextEncoder().encode('Sensitive Data');

  // Encrypt with authentication tag
  const { encrypted: aesEncrypted, iv, tag } = await aesGcm.encrypt(data, key, true);

  // Decrypt
  const combined = aesGcm.combineEncryptedDataAndTag(aesEncrypted, tag!);
  const aesDecrypted = await aesGcm.decrypt(iv, combined, key, true);

  // 8. JSON Encryption
  const userData = { name: 'Alice', email: '[email protected]', age: 30 };
  const encryptedJson = await aesGcm.encryptJson(userData, key);
  const decryptedJson = await aesGcm.decryptJson<typeof userData>(encryptedJson, key);
  console.log(decryptedJson); // { name: 'Alice', email: '[email protected]', age: 30 }
} catch (error) {
  console.error('Encryption error:', error.message);
  // Handle specific error types
  if (error.type === 'INVALID_KEY') {
    console.error('Invalid key provided');
  }
}

2. Internationalization (i18n)

The library provides automatic error translation in 8 languages with helper functions for direct translation:

import { 
  getEciesI18nEngine,
  getEciesTranslation,
  safeEciesTranslation,
  EciesStringKey 
} from '@digitaldefiance/ecies-lib';

// Initialize the i18n engine (required once at startup)
const engine = getEciesI18nEngine();

// Direct translation using branded string keys (v4.16.0+)
// Component ID is automatically resolved from the branded enum
const errorMessage = getEciesTranslation(EciesStringKey.Error_ECIESError_InvalidIV);

// With variables
const message = getEciesTranslation(
  EciesStringKey.Error_InvalidKeyLength,
  { expected: 32, actual: 16 }
);

// With specific language
const frenchMessage = getEciesTranslation(
  EciesStringKey.Error_ECIESError_InvalidIV,
  {},
  'fr'
);

// Safe translation (returns placeholder on failure instead of throwing)
const safeMessage = safeEciesTranslation(EciesStringKey.Error_ECIESError_InvalidIV);

// Or use the engine directly with translateStringKey
const directTranslation = engine.translateStringKey(EciesStringKey.Error_ECIESError_InvalidIV);

When to use each method:

  • getEciesTranslation(): Use for error messages and user-facing text (throws on failure)
  • safeEciesTranslation(): Use when translation failure should not break execution
  • engine.translateStringKey(): Use when you already have the engine instance

Supported Languages: en-US, en-GB, fr, es, de, zh-CN, ja, uk

Cryptographic Voting System

The library includes a complete cryptographic voting system with government-grade security features, supporting 15+ voting methods from simple plurality to complex ranked choice voting.

When to use the voting system:

  • Elections requiring verifiable, tamper-proof results
  • Anonymous voting with receipt verification
  • Multi-round elections (IRV, STAR, STV)
  • Government or organizational voting with audit requirements
  • Stakeholder voting with weighted votes

When NOT to use:

  • Simple polls without privacy requirements (use regular encryption)
  • Real-time voting displays (votes are encrypted until tally)
  • Systems requiring instant results (multi-round methods need intermediate decryption)

Quick Start - Voting

import { 
  ECIESService, 
  Member, 
  MemberType, 
  EmailString 
} from '@digitaldefiance/ecies-lib';
import { 
  PollFactory, 
  VoteEncoder, 
  PollTallier, 
  VotingMethod 
} from '@digitaldefiance/ecies-lib/voting';

try {
  // 1. Create authority with voting keys
  const ecies = new ECIESService();
  const { member: authority } = Member.newMember(
    ecies,
    MemberType.System,
    'Election Authority',
    new EmailString('[email protected]')
  );
  await authority.deriveVotingKeys();

  // 2. Create poll
  const poll = PollFactory.createPlurality(
    ['Alice', 'Bob', 'Charlie'],
    authority
  );

  // 3. Create voter and cast vote
  const { member: voter } = Member.newMember(
    ecies,
    MemberType.User,
    'Voter',
    new EmailString('[email protected]')
  );
  await voter.deriveVotingKeys();

  const encoder = new VoteEncoder(authority.votingPublicKey!);
  const vote = encoder.encodePlurality(0, 3); // Vote for Alice
  const receipt = poll.vote(voter, vote);

  // 4. Close and tally
  poll.close();
  const tallier = new PollTallier(
    authority,
    authority.votingPrivateKey!,
    authority.votingPublicKey!
  );
  const results = tallier.tally(poll);

  console.log('Winner:', results.choices[results.winner!]);
  console.log('Tallies:', results.tallies);
} catch (error) {
  console.error('Voting error:', error.message);
  if (error.message.includes('Already voted')) {
    console.error('This voter has already cast a vote');
  }
}

Supported Voting Methods

The system supports 15+ voting methods classified by security level:

✅ Fully Secure (Single-round, Privacy-preserving)

  • Plurality - First-past-the-post (most common) ✅ Fully Implemented
  • Approval - Vote for multiple candidates ✅ Fully Implemented
  • Weighted - Stakeholder voting with configurable limits ✅ Fully Implemented
  • Borda Count - Ranked voting with point allocation ✅ Fully Implemented
  • Score Voting - Rate candidates 0-10 ✅ Fully Implemented
  • Yes/No - Referendums and ballot measures ✅ Fully Implemented
  • Yes/No/Abstain - With abstention option ✅ Fully Implemented
  • Supermajority - Requires 2/3 or 3/4 threshold ✅ Fully Implemented

⚠️ Multi-Round (Requires intermediate decryption)

  • Ranked Choice (IRV) - Instant runoff with elimination ✅ Fully Implemented
  • Two-Round - Top 2 runoff election ✅ Fully Implemented
  • STAR - Score Then Automatic Runoff ✅ Fully Implemented
  • STV - Single Transferable Vote (proportional representation) ✅ Fully Implemented

❌ Insecure (No privacy - for special cases only)

  • Quadratic - Quadratic voting (requires non-homomorphic operations) ✅ Fully Implemented
  • Consensus - Requires 95%+ agreement ✅ Fully Implemented
  • Consent-Based - Sociocracy-style (no strong objections) ✅ Fully Implemented

Voting System Architecture

┌─────────────────────────────────────────────────────────────┐
│                    SECURE ARCHITECTURE                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Poll (Vote Aggregator)                                     │
│  ├─ Paillier PUBLIC key only  ← encrypts & aggregates      │
│  ├─ Authority's EC keys       ← signs receipts              │
│  └─ Cannot decrypt votes                                    │
│                                                              │
│  PollTallier (Separate Entity)                              │
│  ├─ Paillier PRIVATE key      ← decrypts ONLY after close  │
│  └─ Computes results                                        │
│                                                              │
│  Voter (Member)                                             │
│  ├─ EC keypair                ← verifies receipts           │
│  └─ Voting public key         ← encrypts votes              │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Government Requirements

The voting system meets government-grade requirements:

  • ✅ Immutable Audit Log - Cryptographic hash chain for all operations
  • ✅ Public Bulletin Board - Transparent, append-only vote publication with Merkle tree integrity
  • ✅ Event Logger - Comprehensive event tracking with microsecond timestamps
  • ✅ Verifiable Receipts - Cryptographically signed confirmations
  • ✅ Role Separation - Poll aggregator cannot decrypt votes
  • ✅ Homomorphic Encryption - Votes remain encrypted until tally

Example: Ranked Choice Voting

import { PollFactory, VoteEncoder, PollTallier } from '@digitaldefiance/ecies-lib/voting';

// Create ranked choice poll
const poll = PollFactory.createRankedChoice(
  ['Alice', 'Bob', 'Charlie', 'Diana'],
  authority
);

const encoder = new VoteEncoder(authority.votingPublicKey!);

// Voter ranks: Alice > Bob > Charlie (Diana not ranked)
const vote = encoder.encodeRankedChoice([0, 1, 2], 4);
const receipt = poll.vote(voter, vote);

// Verify receipt
const isValid = poll.verifyReceipt(voter, receipt);

// Close and tally with IRV elimination
poll.close();
const results = tallier.tally(poll);

console.log('Winner:', results.choices[results.winner!]);
console.log('Elimination rounds:', results.rounds);

Security Validation

import { VotingSecurityValidator, SecurityLevel } from '@digitaldefiance/ecies-lib/voting';

// Check security level
const level = VotingSecurityValidator.getSecurityLevel(VotingMethod.Plurality);
console.log(level); // SecurityLevel.FullyHomomorphic

// Validate before use (throws if insecure)
VotingSecurityValidator.validate(VotingMethod.Quadratic); // Throws error

// Allow insecure methods explicitly
VotingSecurityValidator.validate(VotingMethod.Quadratic, { allowInsecure: true });

2. Strong Typing for ID Providers (NEW!)

The library now provides strongly-typed alternatives to the weak typing pattern Constants.idProvider.generate():

import { 
  getRuntimeConfiguration,
  getEnhancedIdProvider,
  getTypedIdProvider,
  createObjectIdConfiguration
} from '@digitaldefiance/ecies-lib';
import { ObjectId } from 'bson';

// BEFORE: Weak typing (still works for compatibility)
const Constants = getRuntimeConfiguration();
const rawBytes = Constants.idProvider.generate(); // Returns Uint8Array, no strong typing
const nativeId = Constants.idProvider.fromBytes(rawBytes); // Returns unknown, requires casting

// AFTER: Strong typing - Option 1 (Enhanced Provider - Recommended)
const enhancedProvider = getEnhancedIdProvider<ObjectId>();

// Original methods still work exactly the same
const rawBytes2 = enhancedProvider.generate(); // Uint8Array (same as before)
const isValid = enhancedProvider.validate(rawBytes2); // boolean (same as before)

// Plus new strongly-typed methods
const objectId = enhancedProvider.generateTyped(); // ObjectId - strongly typed!
const validTyped = enhancedProvider.validateTyped(objectId); // boolean, accepts ObjectId
const serialized = enhancedProvider.serializeTyped(objectId); // string, accepts ObjectId
const deserialized = enhancedProvider.deserializeTyped(serialized); // ObjectId

// AFTER: Strong typing - Option 2 (Simple Typed Provider)
const typedProvider = getTypedIdProvider<ObjectId>();
const bytes = typedProvider.generate();
const typedId = typedProvider.fromBytes(bytes); // Returns ObjectId, not unknown!

// AFTER: Strong typing - Option 3 (Configuration Wrapper)
const config = createObjectIdConfiguration();
const configId = config.generateId(); // ObjectId directly!
const configValid = config.validateId(configId); // boolean, accepts ObjectId

Benefits:

  • Full IntelliSense - Autocomplete for native ID methods (objectId.toHexString())
  • Compile-time checking - Prevents type mismatches at build time
  • Zero breaking changes - All existing code continues to work
  • Multiple migration paths - Choose the approach that fits your use case

3. Using Custom ID Providers (e.g., GUID)

import { 
  createRuntimeConfiguration, 
  GuidV4Provider, 
  ECIESService 
} from '@digitaldefiance/ecies-lib';

// Configure to use 16-byte GUIDs
const config = createRuntimeConfiguration({
  idProvider: new GuidV4Provider()
});

// Pass IConstants directly to the constructor
const ecies = new ECIESService(config);
const id = config.idProvider.generate(); // Returns 16-byte Uint8Array

4. Streaming Encryption (Large Files)

Encrypt gigabytes of data with minimal memory footprint (<10MB).

import { ECIESService, EncryptionStream } from '@digitaldefiance/ecies-lib';

const ecies = new ECIESService();
const stream = new EncryptionStream(ecies);

// Assuming 'fileStream' is a ReadableStream from a File object
async function processFile(fileStream: ReadableStream, publicKey: Uint8Array) {
  const encryptedChunks: Uint8Array[] = [];
  
  // Encrypt
  for await (const chunk of stream.encryptStream(fileStream, publicKey)) {
    encryptedChunks.push(chunk.data);
    // In a real app, you'd write 'chunk.data' to disk or upload it immediately
  }
  
  return encryptedChunks;
}

5. Member System

The Member class provides a high-level user abstraction that integrates keys, IDs, and encryption.

import { Member, MemberType, EmailString } from '@digitaldefiance/ecies-lib';

// Create a new member (ID generated automatically based on configured provider)
const { member, mnemonic } = Member.newMember(
  ecies,
  MemberType.User,
  'Alice',
  new EmailString('[email protected]')
);

console.log(member.id); // Uint8Array (size depends on provider)

// Encrypt data for this member
const encrypted = await member.encryptData('My Secrets');

Constructor Signature Flexibility

The ECIESService constructor accepts two types of configuration:

  1. IConstants (from createRuntimeConfiguration): Complete runtime configuration including ID provider and all cryptographic constants
  2. Partial<IECIESConfig>: ECIES-specific configuration only (for backward compatibility)
// Option 1: Pass IConstants (recommended)
const config = createRuntimeConfiguration({ idProvider: new GuidV4Provider() });
const ecies = new ECIESService(config);

// Option 2: Pass Partial<IECIESConfig> (legacy)
const ecies = new ECIESService({
  curveName: 'secp256k1',
  symmetricAlgorithm: 'aes-256-gcm'
});

// Option 3: Use defaults
const ecies = new ECIESService();

This flexibility ensures backward compatibility while enabling the documented usage pattern with createRuntimeConfiguration.

ID Providers and Members: Deep Dive

Overview

The ID provider system is a core architectural feature that enables flexible identifier formats throughout the library. The Member class seamlessly integrates with the configured ID provider, making it easy to work with different ID formats (MongoDB ObjectIDs, GUIDs, UUIDs, or custom formats) without changing your application code.

How Member Uses ID Providers

The Member class relies on the ECIESService's configured idProvider (accessed via eciesService.constants.idProvider) for three critical operations:

  1. ID Generation - Creating unique identifiers for new members
  2. Serialization - Converting binary IDs to strings for storage/transmission
  3. Deserialization - Converting string IDs back to binary format

Internal Implementation

// 1. ID Generation (in Member.newMember())
// Uses the configured idProvider from the ECIESService
const idProvider = eciesService.constants.idProvider;

const newId = idProvider.generate();

// 2. Serialization (in Member.toJson())
public toJson(): string {
  const storage = {
    id: this._eciesService.constants.idProvider.serialize(this._id),  // Uint8Array → string
    // ... other fields
  };
  return JSON.stringify(storage);
}

// 3. Deserialization (in Member.fromJson())
public static fromJson(json: string, eciesService: ECIESService): Member {
  const storage = JSON.parse(json);
  const id = eciesService.constants.idProvider.deserialize(storage.id);  // string → Uint8Array
  
  // Validates ID length matches configured provider (warns if mismatch)
  const expectedLength = eciesService.constants.idProvider.byteLength;
  if (id.length !== expectedLength) {
    console.warn(`Member ID length mismatch...`);
  }
  
  return new Member(eciesService, /* ... */, id);
}

Available ID Providers

Choosing an ID Provider:

  • ObjectIdProvider: Use for MongoDB integration, backward compatibility (12 bytes)
  • GuidV4Provider: Use for Windows/.NET integration, compact serialization (16 bytes)
  • UuidProvider: Use for standard UUID format, maximum compatibility (16 bytes, dash format)
  • CustomIdProvider: Use for specialized requirements, legacy systems (1-255 bytes)

ObjectIdProvider (Default)

Format: 12-byte MongoDB-compatible ObjectID
Serialization: 24-character hex string
Use Case: MongoDB integration, backward compatibility

import { ObjectIdProvider, createRuntimeConfiguration } from '@digitaldefiance/ecies-lib';

const config = createRuntimeConfiguration({
  idProvider: new ObjectIdProvider()
});

const id = config.idProvider.generate();
console.log(id.length); // 12
console.log(config.idProvider.serialize(id)); // "507f1f77bcf86cd799439011"

GuidV4Provider

Format: 16-byte RFC 4122 v4 GUID
Serialization: 24-character base64 string (compact)
Use Case: Windows/.NET integration, compact serialization

import { GuidV4Provider } from '@digitaldefiance/ecies-lib';

const provider = new GuidV4Provider();
const id = provider.generate();
console.log(id.length); // 16
console.log(provider.serialize(id)); // "kT8xVzQ2RkKmN5pP3w=="

// Supports multiple deserialization formats
provider.deserialize('kT8xVzQ2RkKmN5pP3w==');  // base64 (24 chars)
provider.deserialize('913f315734364642a6379a4fdf');  // hex (32 chars)
provider.deserialize('913f3157-3436-4642-a637-9a4fdf000000');  // full hex with dashes (36 chars)

// Deterministic GUIDs (v5)
const deterministicId = provider.fromNamespace('my-namespace', 'user-alice');

UuidProvider

Format: 16-byte RFC 4122 v4 UUID
Serialization: 36-character string with dashes (standard format)
Use Case: Standard UUID format, maximum compatibility

import { UuidProvider } from '@digitaldefiance/ecies-lib';

const provider = new UuidProvider();
const id = provider.generate();
console.log(id.length); // 16
console.log(provider.serialize(id)); // "550e8400-e29b-41d4-a716-446655440000"

CustomIdProvider

Format: Any byte length (1-255 bytes)
Serialization: Hexadecimal string
Use Case: Custom requirements, legacy systems, specialized formats

import { CustomIdProvider } from '@digitaldefiance/ecies-lib';

// 32-byte SHA-256 hash as ID
const provider = new CustomIdProvider(32, 'SHA256Hash');
const id = provider.generate();
console.log(id.length); // 32
console.log(provider.serialize(id)); // 64-character hex string

Using ID Providers with Members

Creating Members with Different ID Providers

import { 
  Member, 
  MemberType, 
  EmailString, 
  ECIESService,
  createRuntimeConfiguration,
  ConstantsRegistry,
  GuidV4Provider,
  ObjectIdProvider
} from '@digitaldefiance/ecies-lib';

const ecies = new ECIESService();

// Option 1: Use default ObjectIdProvider
const alice = Member.newMember(
  ecies,
  MemberType.User,
  'Alice',
  new EmailString('[email protected]')
);
console.log(alice.member.id.length); // 12 bytes

// Option 2: Configure GUID provider globally
const guidConfig = createRuntimeConfiguration({
  idProvider: new GuidV4Provider()
});
ConstantsRegistry.register('guid-config', guidConfig);

// Now all new members use GUID IDs
const bob = Member.newMember(
  ecies,
  MemberType.User,
  'Bob',
  new EmailString('[email protected]')
);
console.log(bob.member.id.length); // 16 bytes

Serializing and Deserializing Members

import { Member, ECIESService, Constants } from '@digitaldefiance/ecies-lib';

const ecies = new ECIESService();
const { member } = Member.newMember(
  ecies,
  MemberType.User,
  'Charlie',
  new EmailString('[email protected]')
);

// Serialize to JSON (ID automatically converted to string)
const json = member.toJson();
console.log(json);
// {
//   "id": "507f1f77bcf86cd799439011",  // Serialized using idProvider
//   "type": 1,
//   "name": "Charlie",
//   "email": "[email protected]",
//   "publicKey": "...",
//   "creatorId": "507f1f77bcf86cd799439011",
//   "dateCreated": "2024-01-15T10:30:00.000Z",
//   "dateUpdated": "2024-01-15T10:30:00.000Z"
// }

// Deserialize from JSON (ID automatically converted back to Uint8Array)
const restored = Member.fromJson(json, ecies);
console.log(restored.id); // Uint8Array(12) [80, 127, 31, 119, ...]

Working with Member IDs

import { Member, ECIESService, createRuntimeConfiguration, GuidV4Provider } from '@digitaldefiance/ecies-lib';

// Create service with custom idProvider
const config = createRuntimeConfiguration({ idProvider: new GuidV4Provider() });
const ecies = new ECIESService(config);

const { member } = Member.newMember(ecies, /* ... */);

// Get binary ID
const binaryId: Uint8Array = member.id;

// Convert to string for display/storage (uses service's configured idProvider)
const stringId = ecies.constants.idProvider.serialize(member.id);
console.log(`Member ID: ${stringId}`);

// Convert string back to binary
const restoredId = ecies.constants.idProvider.deserialize(stringId);

// Compare IDs (constant-time comparison)
const isEqual = ecies.constants.idProvider.equals(member.id, restoredId);

// Validate ID format
const isValid = ecies.constants.idProvider.validate(member.id);

// Clone ID (defensive copy)
const idCopy = ecies.constants.idProvider.clone(member.id);

Multi-Recipient Encryption with Different ID Providers

The ID provider system is critical for multi-recipient encryption, where recipient IDs are embedded in the encrypted message:

import { ECIESService, Member, MemberType, EmailString, GuidV4Provider, createRuntimeConfiguration } from '@digitaldefiance/ecies-lib';

// Configure GUID provider (16 bytes)
const config = createRuntimeConfiguration({
  idProvider: new GuidV4Provider()
});

const ecies = new ECIESService(config);

// Create recipients with GUID IDs
const alice = Member.newMember(ecies, MemberType.User, 'Alice', new EmailString('[email protected]'));
const bob = Member.newMember(ecies, MemberType.User, 'Bob', new EmailString('[email protected]'));

const message = new TextEncoder().encode('Shared Secret');

// Encrypt for multiple recipients
// Each recipient's 16-byte GUID is embedded in the message
const encrypted = await ecies.encryptMultiple(
  [
    { id: alice.member.id, publicKey: alice.member.publicKey },
    { id: bob.member.id, publicKey: bob.member.publicKey }
  ],
  message
);

// Each recipient can decrypt using their ID
const aliceDecrypted = await ecies.decryptMultiple(
  alice.member.id,
  alice.member.privateKey!.value,
  encrypted
);

Configuration Auto-Sync

When you change the ID provider, the library automatically updates related constants:

import { createRuntimeConfiguration, CustomIdProvider } from '@digitaldefiance/ecies-lib';

// Create 20-byte custom ID provider
const customProvider = new CustomIdProvider(20, 'CustomHash');

const config = createRuntimeConfiguration({
  idProvider: customProvider
});

// These are automatically synced:
console.log(config.MEMBER_ID_LENGTH); // 20 (auto-synced)
console.log(config.ECIES.MULTIPLE.RECIPIENT_ID_SIZE); // 20 (auto-synced)
console.log(config.idProvider.byteLength); // 20

Best Practices

  1. Choose the Right Provider:

    • Use ObjectIdProvider for MongoDB integration
    • Use GuidV4Provider for compact serialization and Windows/.NET compatibility
    • Use UuidProvider for standard UUID format and maximum compatibility
    • Use CustomIdProvider for specialized requirements
  2. Configure Early: Set your ID provider before creating any members:

    const config = createRuntimeConfiguration({ idProvider: new GuidV4Provider() });
    ConstantsRegistry.register('app-config', config);
    const ecies = new ECIESService(config);
  3. Consistent Configuration: Use the same ID provider across your entire application to ensure compatibility

  4. Serialization for Storage: Always use ecies.constants.idProvider.serialize() when storing IDs in databases or transmitting over networks

  5. Validation: Validate IDs when receiving them from external sources:

    if (!ecies.constants.idProvider.validate(receivedId)) {
      throw new Error('Invalid ID format');
    }
  6. Cross-Platform Compatibility: The same ID provider configuration works in both browser (ecies-lib) and Node.js (node-ecies-lib)

Common Patterns

Pattern 1: Application-Wide ID Provider

// config.ts
import { createRuntimeConfiguration, GuidV4Provider, ConstantsRegistry } from '@digitaldefiance/ecies-lib';


export const APP_CONFIG_KEY = 'app-config';

const config = createRuntimeConfiguration({
  idProvider: new GuidV4Provider()
});

ConstantsRegistry.register(APP_CONFIG_KEY, config);

export { config };

// app.ts
import { ECIESService } from '@digitaldefiance/ecies-lib';
import { config } from './config';

const ecies = new ECIESService(config);
// All members created with this service will use GUID IDs

Pattern 2: Multiple ID Providers for Different Contexts

import { 
  createRuntimeConfiguration, 
  ConstantsRegistry,
  ObjectIdProvider,
  GuidV4Provider,
  ECIESService
} from '@digitaldefiance/ecies-lib';

// User context uses ObjectID (MongoDB)
const userConfig = createRuntimeConfiguration({
  idProvider: new ObjectIdProvider()
});
ConstantsRegistry.register('user-context', userConfig);

// Device context uses GUID
const deviceConfig = createRuntimeConfiguration({
  idProvider: new GuidV4Provider()
});
ConstantsRegistry.register('device-context', deviceConfig);

// Use different services for different contexts
const userEcies = new ECIESService(userConfig);
const deviceEcies = new ECIESService(deviceConfig);

Pattern 3: ID Provider Abstraction Layer

import { Member, ECIESService, MemberType, EmailString } from '@digitaldefiance/ecies-lib';

class MemberService {
  constructor(private ecies: ECIESService) {}

  createMember(name: string, email: string) {
    return Member.newMember(
      this.ecies,
      MemberType.User,
      name,
      new EmailString(email)
    );
  }

  serializeMemberId(id: Uint8Array): string {
    return this.ecies.constants.idProvider.serialize(id);
  }

  deserializeMemberId(id: string): Uint8Array {
    return this.ecies.constants.idProvider.deserialize(id);
  }

  validateMemberId(id: Uint8Array): boolean {
    return this.ecies.constants.idProvider.validate(id);
  }
}

API Reference

Core Services

  • ECIESService: The main entry point for encryption/decryption operations.
    • Constructor: constructor(config?: Partial<IECIESConfig> | IConstants, eciesParams?: IECIESConstants)
      • Accepts either IConstants (from createRuntimeConfiguration) or Partial<IECIESConfig> for backward compatibility
      • When IConstants is provided, ECIES configuration is automatically extracted
      • Optional eciesParams provides default values for any missing configuration
    • constants: Returns the full IConstants configuration including idProvider
    • config: Returns IECIESConfig for backward compatibility
  • EciesCryptoCore: Low-level cryptographic primitives (keys, signatures, ECDH).
  • EciesMultiRecipient: Specialized service for handling multi-recipient messages.
  • EciesFileService: Helper for chunked file encryption.
  • PasswordLoginService: Secure authentication using PBKDF2 and encrypted key bundles.
  • AESGCMService: Instance-based AES-256-GCM encryption with JSON support.
    • Methods: encrypt(), decrypt(), encryptJson(), decryptJson(), combineEncryptedDataAndTag()
    • Supports authenticated encryption with optional AAD
  • Pbkdf2Service: Password-based key derivation (PBKDF2).
    • Methods: deriveKeyFromPasswordAsync(), deriveKeyFromPasswordWithProfileAsync(), getProfileConfig()
    • Profiles: Fast, Standard, Secure, Maximum
  • CrcService: CRC checksum computation and verification.
    • Algorithms: CRC8, CRC16-CCITT, CRC32
    • Methods: crc8(), crc16(), crc32(), verifyCrc8(), verifyCrc16(), verifyCrc32()
    • Supports async stream processing with crc8Async(), crc16Async(), crc32Async()
  • XorService: Simple XOR cipher for memory obfuscation.
    • Static Methods: xor(), generateKey(), stringToBytes(), bytesToString()
    • Used internally by SecureString and SecureBuffer

Voting System Services

  • Poll: Core poll with vote aggregation and receipt generation
  • PollTallier: Decrypts and tallies votes (separate from Poll for security)
  • VoteEncoder: Encrypts votes using Paillier homomorphic encryption
  • PollFactory: Convenient poll creation with method-specific configurations
  • VotingSecurityValidator: Security level validation and enforcement
  • ImmutableAuditLog: Hash-chained audit trail for government compliance
  • PublicBulletinBoard: Append-only vote publication with Merkle tree integrity
  • PollEventLogger: Event tracking with microsecond timestamps
  • Hierarchical Aggregators: PrecinctAggregator, CountyAggregator, StateAggregator, NationalAggregator
  • BatchVoteProcessor: Batch processing and checkpoint management
  • Threshold Voting: ThresholdKeyGenerator, GuardianRegistry, CeremonyCoordinator, DecryptionCombiner, IntervalScheduler, PublicTallyFeed, TallyVerifier, ThresholdPoll, ThresholdPollFactory, ThresholdAuditLog — see Threshold Voting docs

ID Providers

  • IIdProvider: Interface that all ID providers implement

    • generate(): Create a new random ID
    • validate(id): Check if an ID is valid
    • serialize(id): Convert Uint8Array to string
    • deserialize(str): Convert string to Uint8Array
    • equals(a, b): Constant-time comparison
    • clone(id): Create defensive copy
    • idToString(id): Convert any ID type to string
    • idFromString(str): Convert string to ID buffer
  • ObjectIdProvider: 12-byte MongoDB ObjectID format

  • GuidV4Provider: 16-byte GUID with base64 serialization

  • UuidProvider: 16-byte UUID with standard dash formatting

  • CustomIdProvider: Custom byte length (1-255 bytes)

  • BaseIdProvider: Abstract base class for creating custom providers

Member System

  • Member: High-level user abstraction with cryptographic operations
    • id: Unique identifier (format determined by ID provider)
    • publicKey: Member's public key
    • privateKey: Member's private key (optional, can be loaded/unloaded)
    • votingPublicKey: Paillier public key for voting (optional)
    • votingPrivateKey: Paillier private key for voting (optional)
    • deriveVotingKeys(): Generate Paillier keypair for voting
    • encryptData(data, recipientPublicKey?): Encrypt data
    • decryptData(encryptedData): Decrypt data
    • sign(data): Sign data with private key
    • verify(signature, data): Verify signature
    • toJson(): Serialize to JSON (uses ID provider)
    • fromJson(json, eciesService): Deserialize from JSON (uses ID provider)
    • newMember(...): Static factory method
    • fromMnemonic(...): Create from BIP39 mnemonic
  • MemberBuilder: Fluent builder for creating Member instances
    • Methods: withId(), withName(), withEmail(), withPhone(), withType(), withKeys(), build()
    • Provides type-safe member construction with validation

Builders

  • ECIESBuilder: Fluent builder for ECIESService configuration
    • Methods: create(), withServiceConfig(), withConstants(), withI18n(), build()
    • Simplifies service initialization with method chaining

Stream Transforms

  • EciesEncryptTransform: Web Streams API transform for ECIES encryption
  • EciesDecryptTransform: Web Streams API transform for ECIES decryption
  • ChecksumTransform: Stream transform for CRC checksum computation
  • XorTransform: Stream transform for XOR cipher operations
  • XorMultipleTransform: Stream transform for multiple XOR operations

All transforms implement the standard Transformer<I, O> interface for use with TransformStream.

Voting System Types & Enumerations

  • VotingMethod: Enum with 15+ voting methods (Plurality, Approval, Weighted, Borda, Score, RankedChoice, STAR, STV, etc.)
  • SecurityLevel: Enum classifying voting methods (FullyHomomorphic, MultiRound, Insecure)
  • EventType: Enum for event logging (PollCreated, VoteCast, PollClosed, etc.)
  • AuditEventType: Enum for audit events
  • JurisdictionalLevel: Enum for hierarchical aggregation (Precinct, County, State, National)

Voting System Interfaces

  • EncryptedVote<TID extends PlatformID>: Encrypted vote structure with generic ID support
  • PollResults<TID extends PlatformID>: Tally results with winner(s) and generic ID support
  • VoteReceipt: Cryptographic vote receipt with signature verification
  • PollConfiguration: Poll setup parameters
  • SupermajorityConfig: Threshold configuration for supermajority voting
  • AuditEntry: Immutable audit log entry
  • BulletinBoardEntry: Public bulletin board entry
  • EventLogEntry: Event log entry with timestamps

Configuration & Registry

  • Constants: The default, immutable configuration object.
  • ConstantsRegistry: Manages runtime configurations.
    • register(key, config): Register a named configuration.
    • get(key): Retrieve a configuration.
  • createRuntimeConfiguration(overrides): Creates a validated configuration object with your overrides.

Strong Typing System (NEW!)

  • getEnhancedIdProvider<T>(key?): Get a strongly-typed ID provider with enhanced convenience methods
    • Drop-in replacement for Constants.idProvider with both original and typed methods
    • generateTyped(): Generate ID with native type (e.g., ObjectId)
    • validateTyped(id): Validate ID with native type
    • serializeTyped(id): Serialize ID with native type
    • deserializeTyped(str): Deserialize to native type
  • getTypedIdProvider<T>(key?): Get a simple strongly-typed ID provider
    • Minimal API surface with type-safe conversions
    • fromBytes(bytes): Returns native type instead of unknown
  • createObjectIdConfiguration(overrides?): Create ObjectId-typed configuration
  • createGuidV4Configuration(overrides?): Create GuidV4-typed configuration
  • createUint8ArrayConfiguration(overrides?): Create Uint8Array-typed configuration
  • createUuidConfiguration(overrides?): Create UUID string-typed configuration
  • TypedConfiguration<T>: Configuration wrapper with strongly-typed ID operations
    • generateId(): Generate ID with native type
    • validateId(id): Validate ID with native type
    • serializeId(id): Serialize ID with native type
    • deserializeId(str): Deserialize to native type

Secure Primitives

  • SecureString / SecureBuffer:
    • Stores sensitive data in memory using XOR obfuscation.
    • dispose() method to explicitly zero out memory.
    • Prevents accidental leakage via console.log or serialization.

Documentation

Architecture & Design

Developer Guides

Quick References

Development

Avoiding Circular Dependencies

This library maintains a strict module hierarchy to prevent circular dependencies. When contributing, follow these rules:

Import Rules by Module Type

Enumerations (src/enumerations/*.ts):

  • CAN import: TypeScript types only
  • CANNOT import: Translations, i18n, errors, constants, services, utilities

Translations (src/translations/*.ts):

  • CAN import: Enumerations, external libraries
  • CANNOT import: i18n setup, errors, constants, services

i18n Setup (src/i18n-setup.ts):

  • CAN import: Enumerations, translations, external libraries
  • CANNOT import: Errors, constants, services

Errors (src/errors/*.ts):

  • CAN import: Enumerations, i18n setup, external libraries
  • CANNOT import: Constants, services (except as lazy imports)
  • ⚠️ MUST use lazy i18n initialization (translation lookup on message access, not in constructor)

Utilities (src/utils/*.ts):

  • CAN import: Enumerations, i18n setup, errors, external libraries
  • CANNOT import: Constants, services (except as lazy imports)

Constants (src/constants.ts):

  • CAN import: Enumerations, errors, utilities, external libraries
  • CANNOT import: Services
  • ⚠️ MUST handle early initialization errors gracefully (use fallback messages)

Services (src/services/**/*.ts):

  • CAN import: All of the above
  • ⚠️ SHOULD avoid circular dependencies with other services

Detecting Circular Dependencies

The project uses madge to detect circular dependencies. Run these commands to check:

# Check for circular dependencies in the entire project
npx madge --circular --extensions ts src/index.ts

# Check a specific module
npx madge --circular --extensions ts src/enumerations/index.ts

# Generate a visual dependency graph
npx madge --image graph.svg --extensions ts src/index.ts

Common Patterns to Avoid

❌ Bad: Enumeration importing error class

// src/enumerations/ecies-encryption-type.ts
import { ECIESError } from '../errors/ecies'; // Creates circular dependency!

export function validateType(type: EciesEncryptionTypeEnum): void {
  if (!isValid(type)) {
    throw new ECIESError(ECIESErrorTypeEnum.InvalidEncryptionType);
  }
}

✅ Good: Move validation to utility module

// src/enumerations/ecies-encryption-type.ts
export enum EciesEncryptionTypeEnum {
  Simple = 33,
  Single = 66,
  Multiple = 99,
}

// src/utils/encryption-type-utils.ts
import { ECIESError } from '../errors/ecies';
import { EciesEncryptionTypeEnum } from '../enumerations/ecies-encryption-type';

export function validateType(type: EciesEncryptionTypeEnum): void {
  if (!isValid(type)) {
    throw new ECIESError(ECIESErrorTypeEnum.InvalidEncryptionType);
  }
}

❌ Bad: Error class with eager i18n initialization

// src/errors/ecies.ts
export class ECIESError extends Error {
  constructor(type: ECIESErrorTypeEnum) {
    const engine = getEciesI18nEngine(); // May not be initialized yet!
    super(engine.translate(EciesComponentId, getKeyForType(type)));
  }
}

✅ Good: Error class with lazy i18n initialization

// src/errors/ecies.ts
export class ECIESError extends TypedHandleableError {
  constructor(type: ECIESErrorTypeEnum) {
    super(type); // Don't access i18n in constructor
  }
  
  // Message is accessed lazily via getter when needed
  get message(): string {
    const engine = getEciesI18nEngine();
    return engine.translate(EciesComponentId, getKeyForType(this.type));
  }
}

❌ Bad: Constants validation with hard i18n dependency

// src/constants.ts
function validateConstants(config: IConstants): void {
  const engine = getEciesI18nEngine(); // May fail during module init!
  if (config.CHECKSUM.SHA3_BUFFER_LENGTH !== 32) {
    throw new Error(engine.translate(EciesComponentId, EciesStringKey.Error_InvalidChecksum));
  }
}

✅ Good: Constants validation with fallback

// src/constants.ts
function safeTranslate(key: EciesStringKey, fallback: string): string {
  try {
    const engine = getEciesI18nEngine();
    return engine.translate(EciesComponentId, key);
  } catch {
    return fallback; // Use fallback during early initialization
  }
}

function validateConstants(config: IConstants): void {
  if (config.CHECKSUM.SHA3_BUFFER_LENGTH !== 32) {
    throw new Error(safeTranslate(
      EciesStringKey.Error_InvalidChecksum,
      'Invalid checksum constants'
    ));
  }
}

Pre-commit Checks

Consider adding a pre-commit hook to catch circular dependencies early:

# .husky/pre-commit
#!/bin/sh
npx madge --circular --extensions ts src/index.ts
if [ $? -ne 0 ]; then
  echo "❌ Circular dependencies detected! Please fix before committing."
  exit 1
fi

Commands

yarn install         # Install dependencies
yarn build          # Compile TypeScript
yarn test           # Run all tests (2429 specs)
yarn lint           # ESLint check
yarn format         # Fix all (prettier + lint)

Testing

The library maintains 100% test coverage with over 1,200 tests, including:

  • Unit Tests: For all services and utilities.
  • Integration Tests: Verifying protocol flows and message structures.
  • Vectors: Validating against known test vectors.
  • Property-based Tests: Fuzzing inputs for robustness.

Troubleshooting

Encryption/Decryption Errors

Problem: ECIESError: Invalid IV length

Solutions:

  1. Ensure IV is exactly 12 bytes for AES-256-GCM
  2. Don't reuse IVs - generate new one for each encryption
  3. Check that encrypted data hasn't been corrupted

Problem: ECIESError: Decryption failed

Solutions:

  1. Verify you're using the correct private key
  2. Check that data wasn't modified in transit
  3. Ensure using same encryption mode (Basic/WithLength/Multiple)
  4. Verify recipient ID matches if using multi-recipient encryption

ID Provider Issues

Problem: Member ID length mismatch

Solutions:

  1. Ensure same ID provider used for serialization and deserialization
  2. Check configuration: ecies.constants.idProvider.byteLength
  3. Don't mix ID providers in same application

Voting System Issues

Problem: Already voted error

Solutions:

  1. Each voter can only vote once per poll
  2. Check if voter already has a receipt
  3. Use different Member instance for each voter

Problem: Poll is closed error

Solutions:

  1. Cannot vote after poll.close() is called
  2. Check poll status before voting
  3. Create new poll if needed

Key Management Issues

Problem: Invalid mnemonic phrase

Solutions:

  1. Ensure mnemonic is 12 or 24 words
  2. Use ecies.generateNewMnemonic() to create valid mnemonics
  3. Check for typos in mnemonic words

Cross-Platform Compatibility

Problem: Data encrypted in browser won't decrypt in Node.js

Solutions:

  1. Ensure both use same protocol version (v4.0)
  2. Use same ID provider configuration
  3. Verify binary compatibility with @digitaldefiance/node-ecies-lib

FAQ

General Questions

Q: What's the difference between ecies-lib and node-ecies-lib?

A: ecies-lib is for browsers (Web Crypto API), node-ecies-lib is for Node.js (crypto module). They are binary compatible - data encrypted in one can be decrypted in the other.

Q: Which encryption mode should I use?

A:

  • Basic: Fixed-size data, minimal overhead
  • WithLength: Variable-size data, includes length prefix
  • Multiple: Encrypting for multiple recipients

Q: Is this library production-ready?

A: Yes. It has 1,200+ tests, 100% coverage on critical paths, and implements industry-standard protocols (ECIES v4.0, HKDF, AES-256-GCM).

ID Providers

Q: Which ID provider should I use?

A:

  • MongoDB app: ObjectIdProvider (12 bytes)
  • Windows/.NET app: GuidV4Provider (16 bytes, compact)
  • Standard UUID: UuidProvider (16 bytes, dashed format)
  • Custom needs: CustomIdProvider (1-255 bytes)

Voting System

Q: Which voting method should I use?

A:

  • Simple elections: Plurality (most votes wins)
  • Multiple choices: Approval voting
  • Ranked preferences: Ranked Choice (IRV)
  • Score-based: Score voting or STAR
  • Proportional: STV (Single Transferable Vote)

Q: Are votes really private?

A: Yes. Votes are encrypted with Paillier homomorphic encryption. The poll aggregator cannot decrypt individual votes - only the separate PollTallier with the private key can decrypt after poll closure.

Q: How do I verify my vote was counted?

A: Each voter receives a cryptographically signed receipt. Use poll.verifyReceipt(voter, receipt) to verify it's valid.

Security

Q: How secure is the encryption?

A: Uses industry-standard algorithms:

  • Curve: secp256k1 (same as Bitcoin)
  • Key Derivation: HKDF-SHA256 (RFC 5869)
  • Symmetric: AES-256-GCM (NIST approved)
  • Hashing: SHA-256/SHA-512

Q: How do I securely store private keys?

A:

  1. Use SecureString for in-memory storage
  2. Encrypt keys at rest with user password
  3. Never log or transmit private keys
  4. Call dispose() when done

Performance

Q: How fast is encryption/decryption?

A: Typical performance:

  • Small messages (<1KB): <1ms
  • Medium messages (1MB): ~50ms
  • Large files (1GB): ~5 seconds (streaming)

Q: Can I encrypt large files?

A: Yes. Use EncryptionStream for memory-efficient processing of files of any size (<10MB RAM usage).

ChangeLog

Breaking Changes Summary

  • v4.19.0: Version syncs, id-provider improvements
  • v4.13.0: Encryption mode renaming (SIMPLEBASIC, SINGLEWITH_LENGTH), Guid class renamed to GuidUint8Array
  • v4.12.0: AESGCMService changed from abstract static class to instance-based
  • v4.0.0: ECIES protocol v4.0 — HKDF key derivation, AAD binding, compressed keys, new IV/key sizes
  • v3.0.0: Streaming encryption API, pluggable ID providers, i18n v2 architecture

Versions 4.19.x (v4.19.0 – v4.19.11)

Guid improvements, parseSafe, provider-to-GUID conversion

  • Added parseSafe(str) method to IIdProvider and all providers — returns undefined instead of throwing on invalid input, useful for parsing user input safely
  • New guid-provider-utils.ts module with fromProviderId() and fromProviderIdBytes() — deterministic conversion from any provider's native ID to GuidUint8Array using UUID v5 namespaces
  • All ID providers (GuidV4Provider, ObjectIdProvider, UuidProvider, CustomIdProvider, Uint8ArrayIdProvider) implement parseSafe
  • TypedConfiguration updated with new provider utility support
  • Threshold key generator PBT spec improvements

Version 4.18.0 (v4.18.8)

Threshold voting system

  • Threshold Decryption Module: Complete implementation of Damgård et al.'s threshold Paillier scheme for distributed vote tallying — no single party can decrypt votes alone
  • ThresholdKeyGenerator: Generate k-of-n threshold key pairs with configurable bit length (default 2048)
  • GuardianRegistry: Register, query, and manage Guardians with status tracking and backup designation
  • CeremonyCoordinator: Orchestrate decryption ceremonies where k Guardians submit partial decryptions with zero-knowledge proofs
  • IntervalScheduler: Configurable interval decryption (time-based, vote-count-based, or hybrid) for real-time running tallies
  • PublicTallyFeed: Real-time subscription API publishing verified interval tallies with cryptographic proofs
  • TallyVerifier: Verify interval tally integrity with ZK proof validation
  • ThresholdAuditLog: Cryptographic hash chain audit log for threshold operations
  • ThresholdPollFactory: Create threshold-enabled polls with the same voting API as standard polls
  • Hierarchical Aggregators: Precinct → County → State → National aggregation for threshold polls
  • Comprehensive PBT and unit test suites for all threshold components (10,700+ lines added)
  • Migration guide (THRESHOLD-MIGRATION.md) and security documentation (THRESHOLD-SECURITY.md)

Versions 4.17.x (v4.17.0 – v4.17.10)

i18n component package isolation, README expansion

  • Added i18n-setup.ts export for component-level i18n engine initialization
  • New i18n-component-package.spec.ts test suite for verifying i18n isolation
  • Major README expansion (~400 lines of documentation updates)
  • Version bumps and package dependency updates

Versions 4.16.x (v4.16.0 – v4.16.30)

Voting key derivation security, HKDF RFC 5869 compliance, i18n string key migration

  • v4.16.0: Use uncompressed voting keys in HKDF derivation for improved security
  • Migrated all engine.translate(EciesComponentId, key) calls to engine.translateStringKey(key) — removed EciesComponentId parameter throughout the codebase
  • Updated all error classes (CryptoError, GuidError, ECIESError, etc.) to use translateStringKey
  • Updated builders (MemberBuilder, ECIESBuilder), constants, and services
  • EciesStringKey enumeration expanded with new string keys
  • i18n string key migration test suite (i18n-string-key-migration.spec.ts, 400+ lines)
  • Guid spec improvements and timing attack resistance test updates
  • Showcase application updates across multiple patch versions

Versions 4.15.x (v4.15.0 – v4.15.6)

Error class refactoring, i18n translation updates, showcase improvements

  • Refactored all error classes (CryptoError, ECIESError, GuidError, IdProviderError, InvalidEmailError, LengthError, MemberError, Pbkdf2Error, SecureStorageError, SimpleEciesError, DisposedError) with improved i18n integration
  • EciesStringKey enumeration significantly expanded and reorganized
  • Updated de and fr translation files (~750 lines each reorganized)
  • Constants and invariant validator updates
  • crypto-core.ts and signature.ts improvements
  • password-login.ts refactored
  • Showcase application dependency updates (Vite config, yarn.lock, CSS)

Versions 4.14.x (v4.14.0 – v4.14.3)

Module independence testing, Guid spec hardening

  • Enhanced module independence tests (constants-independence, interface-type-imports, secure-storage-independence)
  • Property-based test (PBT) specs for module independence validation
  • Expanded Guid spec with 58+ lines of new test cases
  • secure-storage-id-provider.spec.ts and secure-storage-independence.spec.ts improvements
  • Jest config and package dependency updates

Version 4.13.0 (v4.13.0 – v4.13.8)

API naming improvements (SIMPLE→BASIC, SINGLE→WITH_LENGTH), Guid→GuidUint8Array

Breaking Changes:

  • Encryption Mode Renaming:
    • SIMPLEBASIC (constant)
    • SINGLEWITH_LENGTH (constant)
    • encryptSimpleOrSingle(isSimple, ...)encryptBasic(...) / encryptWithLength(...)
    • decryptSimpleOrSingleWithHeader(isSimple, ...)decryptBasicWithHeader(...) / decryptWithLengthAndHeader(...)
  • Removed Constants: OBJECT_ID_LENGTH removed — use idProvider.byteLength instead
  • Guid Class Renamed: GuidGuidUint8Array (browser implementation)
    • Added VersionedGuidUint8Array<V> type for compile-time version tracking

New Features:

  • ECIES_CONFIG: New configuration interface and constant for ECIES parameters
  • TranslatableEciesError: New error class with automatic i18n translation
  • Enhanced type system for GUIDs with VersionedGuidUint8Array<4> and __version property
  • Massive refactoring across 128 source files (2,250 insertions, 569 deletions)
  • JSDoc improvements, production build support, lint fixes

Migration Guide:

// BEFORE (v4.12.x)
const encrypted = await ecies.encryptSimpleOrSingle(false, publicKey, data);
const decrypted = await ecies.decryptSimpleOrSingleWithHeader(false, privateKey, encrypted);

// AFTER (v4.13.0+)
const encrypted = await ecies.encryptWithLength(publicKey, data);
const decrypted = await ecies.decryptWithLengthAndHeader(privateKey, encrypted);

Version 4.12.0 (v4.12.0 – v4.12.8)

AESGCMService refactoring, JSON encryption, CRC service, stream transforms

Breaking Changes:

  • AESGCMService is now instance-based: Changed from abstract static class to regular instance-based class
    • All methods are now instance methods instead of static methods
    • Constructor accepts optional IConstants parameter for configuration

New Features:

  • JSON Encryption Methods: encryptJson<T>() and decryptJson<T>() for convenient typed JSON encryption/decryption
  • CRC Service: New CRC service with 363-line test suite for checksum operations
  • Stream Transforms: New transform modules — checksumTransform, eciesEncryptTransform, eciesDecryptTransform, xorTransform, xorMultipleTransform
  • TypedConfiguration: New typed-configuration.ts with 105-line test suite
  • Uint8ArrayIdProvider fix, Member model updates
  • Multi-recipient processor improvements

Migration Guide:

// BEFORE (v4.10.x and earlier)
const { encrypted, iv, tag } = await AESGCMService.encrypt(data, key, true);

// AFTER (v4.12.0+)
const aesGcm = new AESGCMService();
const { encrypted, iv, tag } = await aesGcm.encrypt(data, key, true);

// NEW: JSON encryption
const encrypted = await aesGcm.encryptJson(userData, key);
const decrypted = await aesGcm.decryptJson<typeof userData>(encrypted, key);

Versions 4.11.x (v4.11.0 – v4.11.3)

Guid overhaul, versioned GUID types

  • Major GuidUint8Array rewrite (683 lines changed) — improved parsing, validation, and version tracking
  • New guid-versions.ts types module for compile-time GUID version tracking
  • GuidV4Provider refactored to align with new GUID architecture
  • ECIESService updates for new GUID integration
  • TypedConfiguration and PlatformID interface updates
  • Showcase and documentation updates across patch versions

Version 4.10.7

Strong typing for ID providers

  • getEnhancedIdProvider<T>(): Drop-in replacement for Constants.idProvider with typed methods
  • getTypedIdProvider<T>(): Simple typed provider for minimal API surface
  • createObjectIdConfiguration(), createGuidV4Configuration(), createUint8ArrayConfiguration(), createUuidConfiguration(): Typed configuration factories