Skip to content

Latest commit

 

History

History
58 lines (42 loc) · 3.71 KB

File metadata and controls

58 lines (42 loc) · 3.71 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Nahualli is a TypeScript library for grinding vanity stealth key pairs for ERC-5564 stealth addresses. It brute-forces secp256k1 key generation until finding a compressed public key whose X coordinate matches a desired hex prefix. Parallelized via Web Workers with a main-thread fallback.

Commands

npm run build       # Build with tsdown (ESM, minified, DTS)
npm run dev         # Build in watch mode
npm test            # Run all tests (vitest run)
npx vitest run tests/grinder.test.ts   # Run a single test file
npm run typecheck   # tsc --noEmit
npm run lint        # Biome lint + format check
npm run format      # Biome lint + format with auto-fix
npm run clean       # Remove dist/

Architecture

Two entry points exported from package.json: ./ (main API) and ./worker (Web Worker code).

Core flow: session.ts orchestrates everything. It validates the pattern via matcher.ts, spawns a worker-pool.ts of N Web Workers (each running worker.ts -> grinder.ts), and exposes an observable state machine (subscribe()) that emits GrindingSessionState snapshots as workers report progress. First worker to find a match wins; all others are stopped.

Module roles:

  • grinder.ts -- the inner loop: generates random secp256k1 keys via keys.ts, checks X coordinate prefix via matcher.ts, returns on match or after batch exhaustion
  • worker.ts -- Web Worker entry point, runs grindBatch in an async loop with cooperative yielding (setTimeout(0))
  • worker-pool.ts -- spawns/manages N workers, aggregates progress, routes results
  • session.ts -- public GrindingSession interface with start()/stop()/getState()/subscribe(), observer pattern for state updates, falls back to main-thread grinding when Worker is unavailable
  • generate.ts -- convenience wrapper: generates a random spending + viewing key pair without pattern matching
  • matcher.ts -- hex pattern validation and prefix matching (skips parity byte of compressed pubkey)
  • keys.ts -- thin wrapper around @noble/curves/secp256k1 for key generation
  • hex.ts -- bytesToHex/hexToBytes utilities
  • types.ts -- shared type definitions (StealthKeyPair, StealthKeyResult, GrindingSessionState, worker protocol types)
  • constants.ts -- default batch size and other shared constants

Worker protocol: Main thread sends WorkerCommand ("start" | "stop"), workers respond with WorkerMessage ("progress" | "result" | "error"). Uint8Arrays are serialized as number[] across the message boundary.

State machine: idle -> running -> (found | stopped | error)

Key Design Details

  • Only the X coordinate of the compressed public key is matched (parity byte 02/03 is skipped)
  • DEFAULT_BATCH_SIZE = 1000 keys per worker iteration
  • Pattern difficulty is exponential: 16^N expected attempts for N hex chars
  • @noble/curves is a peer dependency, never bundled (see tsdown.config.ts)
  • The library targets both browser and Node.js; tests run in Node where Worker is unavailable, exercising the main-thread fallback path
  • State snapshots deep-clone Uint8Array key buffers so subscribers get isolated copies
  • Subscriber errors are caught per-listener to prevent one bad subscriber from breaking others
  • start() does not re-throw after setting error state; callers should use getState() or subscribe() to observe errors

Testing

Tests use Vitest with no mocks. Probabilistic tests use short patterns (1-2 hex chars) to guarantee success within bounded attempts. E2E tests verify cryptographic validity (private key recovers public key) and pattern matching on the final result.