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

@avalabs/crypto-nitro

v0.3.2

Published

React Native Nitro Modules wrapper around @avalabs/crypto-core. Exposes pubkey-only address derivation (xpub batch + per-chain encoders for EVM / BTC / SVM / Avalanche) plus the secp256k1/Schnorr/Ed25519 primitives to iOS and Android via a JS-thread-free

Readme

@avalabs/crypto-nitro

React Native Nitro Modules wrapper around @avalabs/crypto-core. Exposes the pubkey-only batched address derivation surface (xpub batch + per-chain encoders for EVM / BTC / SVM / Avalanche) and the secp256k1 / Schnorr / Ed25519 primitives to iOS and Android via a JS-thread-free C++ bridge.

Most consumers should depend on @avalabs/crypto-sdk instead — it routes Metro to this package via the "react-native" exports condition and to @avalabs/crypto-wasm for web / extension / Node via "browser" / "import". The SDK-mirrored exports here carry @deprecated JSDoc tags to nudge consumers toward the unified entry point.

Layout

src/
  specs/crypto.nitro.ts     Nitro spec — consumed by `nitrogen` codegen
  index.ts                  Public TypeScript API (init + xpub batch +
                            4 per-chain encoders + 7 primitives +
                            MAX_BATCH_SIZE)
cpp/
  CryptoHybrid.{hpp,cpp}    C++ bridge — extends generated HybridCryptoSpec
                            and delegates to crypto-core's api/ headers
nitrogen/generated/         CODEGEN OUTPUT — committed to git and shipped
                            in the npm tarball. Regenerated from
                            src/specs/crypto.nitro.ts on spec edits; the
                            diff is committed alongside the spec change.
                            Local regen: `pnpm --filter @avalabs/crypto-nitro
                            codegen`. Output includes:
                            - shared/c++/HybridCryptoSpec.{hpp,cpp}
                            - shared/c++/DerivedSecp256k1Addresses.hpp
                            - shared/c++/DerivedAvalancheAddresses.hpp
                            - shared/c++/ExtendedPublicKey.hpp
                            - ios/* (autolinking, Swift bridge)
                            - android/* (autolinking, Kotlin bridge)
android/
  build.gradle              RN autolinking entry point
  CMakeLists.txt            NDK build — adds crypto-core as subdirectory
  src/main/                 Android-side Kotlin (generated)
ios/                        iOS-side Swift / Obj-C++ (generated)
AvalabsCryptoNitro.podspec  iOS Pod spec — rsyncs crypto-core sources
nitro.json                  Nitro module configuration

Setup

One-time

# 1. Vendor libsecp256k1 into ../../packages-internal/crypto-core/deps/secp256k1
pnpm --filter @avalabs/crypto-nitro run setup:secp256k1

# 2. Install workspace deps (pulls in react, react-native, react-native-nitro-modules)
pnpm install

Regenerate codegen

The nitrogen/generated/ tree is committed to git and shipped in the published tarball, matching the convention used by upstream Nitro libraries (e.g. react-native-nitro-sqlite). Consumers do not run nitrogen — they install the package and CocoaPods / Gradle autolinking picks up the pre-generated files directly.

Regenerate after every edit to src/specs/crypto.nitro.ts and commit the diff alongside the spec change:

pnpm --filter @avalabs/crypto-nitro codegen
git add packages/crypto-nitro/nitrogen/generated

The codegen script is also wired into the turbo pipeline (typecheck, lint, test, build all dependsOn: ["codegen"]), so running any of those tasks transparently refreshes the tree if the spec is ahead.

Consumer setup

A downstream RN app (e.g. core-mobile) adds @avalabs/crypto-nitro and react-native-nitro-modules to its package.json and builds normally:

pnpm install
cd ios && pod install
pnpm ios                  # or react-native run-ios

No nitrogen devDependency, no postinstall hook — the published tarball already contains the generated C++ / Swift / Kotlin / Gradle / Ruby files under nitrogen/generated/, and the podspec + Android CMakeLists.txt reference them at that path.

How a downstream RN app consumes this

  1. App adds @avalabs/crypto-sdk (the canonical entry point) plus @avalabs/crypto-nitro and react-native-nitro-modules to its package.json. The latter two are needed so React Native's autolinker finds the native module — even though application code imports from @avalabs/crypto-sdk, the bundler still has to be able to resolve @avalabs/crypto-nitro for the codegen + podspec.
  2. React Native's autolinking discovers the package by scanning node_modules for react-native.config.js files. Our react-native.config.js declares the iOS + Android module locations.
  3. iOS: cd ios && pod install — CocoaPods picks up AvalabsCryptoNitro.podspec. Its prepare_command rsyncs packages-internal/crypto-core/ into vendor/crypto-core/ (real files, not a symlink — CocoaPods drops source_files whose realpath escapes the pod root). The Pod then compiles all of crypto-core + libsecp256k1
    • our bridge into a single static lib.
  4. Android: ./gradlew :app:assembleDebug — Gradle's RN autolinking adds this module to the build graph. android/build.gradle declares CMake as the native build system; android/CMakeLists.txt does add_subdirectory(${CRYPTO_CORE_DIR}) to pull in crypto-core's CMake tree, then links the resulting libavalabs-crypto-core.a into our libAvalabsCryptoNitro.so.
  5. At runtime, react-native-nitro-modules finds the auto-linked module and NitroModules.createHybridObject<Crypto>('Crypto') returns the C++-backed implementation. The hybrid handle is created lazily on first use; init() forces resolution so wiring problems surface early.

TypeScript API

ℹ️ Cross-platform consumers should import these from @avalabs/crypto-sdk — same signatures for the address-derivation surface, but the SDK picks the right backend at bundle time. The direct exports below carry @deprecated JSDoc tags for everything the SDK re-exports. The primitive surface (sign, verify, signSchnorr, verifySchnorr, getPublicKey, getExtendedPublicKey, pointAddScalar) is not re-exported by the SDK — direct import from this package is the supported path for those.

import {
  // Address derivation — SDK has equivalents (prefer those)
  init,
  deriveAddressesFromXpubs,
  deriveAddressesForEvm,
  deriveAddressesForSvm,
  deriveAddressesForBtc,
  deriveAddressesForAvalanche,
  MAX_BATCH_SIZE,
  // Primitives — nitro-only, no SDK equivalent
  sign,
  verify,
  signSchnorr,
  verifySchnorr,
  getPublicKey,
  getExtendedPublicKey,
  pointAddScalar,
  // Types
  type DerivedSecp256k1Addresses,
  type DerivedAvalancheAddresses,
  type ExtendedPublicKeyResult,
} from '@avalabs/crypto-nitro';

// 1. Force native-module resolution. Surfaces a clear error early if
//    autolinking isn't wired up. Idempotent after first call.
await init();

// 2. Xpub-driven batch derivation (Ledger / watch-only). BIP-32 walk +
//    address encoding runs on a native background thread so the JS
//    thread stays free. `avalancheXpubs[i]` and `accountIndices[i]`
//    pair up.
const rows: DerivedSecp256k1Addresses[] = await deriveAddressesFromXpubs(
  'xpub...', // EVM xpub at m/44'/60'/0'
  ['xpub...', 'xpub...'], // Avalanche xpubs (one per account)
  false, // isTestnet
  [0, 1], // account indices
);
// rows[i] === { accountIndex, evm, btc, avm, pvm, coreEth }

// 3. Per-chain encoders for batches of already-derived pubkeys. Each
//    hops to a native background thread; 1024-pubkey batches don't
//    block the UI. Inputs accept Uint8Array | ArrayBuffer per element.
const evmAddrs = await deriveAddressesForEvm(compressedSecp256k1Pubkeys33);
const btcAddrs = await deriveAddressesForBtc(compressedSecp256k1Pubkeys33, false);
const svmAddrs = await deriveAddressesForSvm(ed25519Pubkeys32);
const avaxBundles: DerivedAvalancheAddresses[] = await deriveAddressesForAvalanche(
  compressedAvaxPubkeys33, // drives X- / P-
  compressedEvmPubkeys33, // drives C-
  false,
);
// avaxBundles[i] === { x, p, coreEth }

// 4. Low-level primitives — nitro-only.
//    getPublicKey accepts hex / Uint8Array / ArrayBuffer / bigint.
const pubkey = getPublicKey(secretKey, /* isCompressed = */ true);
const ecdsaSig = sign(secretKey, msg32); // returns compact(64)
const okEcdsa = verify(pubkey, msg32, ecdsaSig); // accepts DER or compact

// BIP-340 Schnorr. auxRand defaults to 32 bytes from
// globalThis.crypto.getRandomValues; THROWS if no CSPRNG is available
// (silently falling back to zeros would weaken §3.3 side-channel
// protection). On RN, `import 'react-native-get-random-values'` first.
const schnorrSig = signSchnorr(msg32, secretKey);
const okSchnorr = verifySchnorr(pubkey, msg32, schnorrSig);

// Ed25519 extended public key (RFC 8032 §5.1.5). The scalar is
// reconstructed in JS from `head` as a bigint to keep secret-derived
// bytes out of the engine's interned string table.
const xpk: ExtendedPublicKeyResult = getExtendedPublicKey(secretKey);

// BIP-32 public-child tweak: P' = P + tweak·G
const child = pointAddScalar(pubkey, tweak32);

// Hard upper bound on items per batch (1024). Mirrors MAX_BATCH_SIZE
// in CryptoHybrid.cpp.
console.log(MAX_BATCH_SIZE);

What this package does NOT do

  • Mnemonic / private-key ingestion via the bridge. The bridge surface is deliberately pubkey-only. PBKDF2-based seed derivation and BIP-32 hardened walks run in caller code (@scure/bip39 + @scure/bip32) or on a Ledger device; only pubkeys and xpubs cross the JS↔C++ boundary. This matches CP-14228 § Security Architecture's handle-based contract.
  • OpenSSL backend on iOS/Android. Currently links the portable hash/HMAC backend. OpenSSL is already linked on mobile for TLS; switching to it would match the PR #3799 perf characteristics. Tracked as a follow-up — swap the add_subdirectory(crypto-core) line to set CRYPTO_BACKEND=openssl once that backend exists in crypto-core.

Verification

This package currently has no in-package automated runtime tests — it requires an iOS or Android build environment with the Nitro Modules runtime to load. Verification flows:

  1. TypeScript: pnpm --filter @avalabs/crypto-nitro typecheck (runs in CI on every push).
  2. C++ correctness: pnpm --filter @avalabs/crypto-core test runs crypto-core's host CTest suite (32 cases covering libsecp256k1 integration, the portable hash backend, BIP-32 derivation against the canonical BIP-39 abandon × 11 about vector, ECDSA / Schnorr / Ed25519 RFC test vectors, and parse_xpub against BIP-32 test vector 1). Any algorithmic regression in crypto-core surfaces here before the Nitro layer ever sees it.
  3. Mobile end-to-end (manual / local): Install this package into a fresh RN app (or use the playground.local/crypto-nitro-playground workspace), run a known xpub through deriveAddressesFromXpubs, and confirm the EVM address matches an external reference (MetaMask, ethers.js, the canonical 0x9858EfFD232B4033E47d90003D41EC34EcaEda94 for the abandon mnemonic at m/44'/60'/0'/0/0).