Skip to content

Latest commit

Β 

History

106 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

@agntn/keys

npm version npm downloads license Ask DeepWiki

Typed key generation, address derivation, and message signing across eight blockchains and two curves.

Warning

@agntn/keys is experimental. The package name, public API, provider model, and tool surfaces may change before the first stable release. Pin exact versions if you build on it now.

Features

  • πŸ”‘ Key generation - cryptographically secure private keys via Web Crypto API
  • πŸ“« Address generation - all major formats per chain (legacy, segwit, taproot, base58, hex)
  • βœ… Address validation - verify validity and checksums for every supported format
  • πŸ’Ό Wallet construction - generate a new wallet, or derive one from a private key or from a BIP39 mnemonic and derivation path
  • ✍️ Message signing - sign and verify with secp256k1 or ed25519
  • πŸ›€οΈ BIP44 paths - derivation path utilities for all supported chains
  • 🧩 BIP39 puzzles - validate phrases, narrow one missing word, and map words or indices across all 10 official lists
  • πŸ”Œ Lazy loading - blockchain implementations load on demand for smaller bundles
  • πŸ€– MCP server - the same 13 key, mnemonic, address, and signing tools over stdio
  • πŸ“ Fully typed - TypeScript definitions for every interface

Install

pnpm add @agntn/keys

Usage

Concrete blockchain classes are lazy-loaded. The double-call pattern blockchains.chain(options)() first passes config, then imports and constructs the class.

Generate a wallet

import { useBlockchain, blockchains } from "@agntn/keys";

const ethereum = await blockchains.ethereum()();
const chain = useBlockchain(ethereum);

const wallet = chain.generateWallet();
console.log(wallet.keys.private); // hex private key
console.log(wallet.keys.public); // hex public key
console.log(wallet.address); // 0x... checksum address

Bitcoin address types

import { useBlockchain, blockchains } from "@agntn/keys";

const btc = useBlockchain(await blockchains.bitcoin()());

const privateKey = btc.generateKeyPrivate();
const publicKey = btc.getKeyPublic(privateKey);

btc.getAddress(publicKey); // legacy (1...)
btc.getAddress(publicKey, "segwit"); // native segwit (bc1q...)
btc.getAddress(publicKey, "taproot"); // taproot (bc1p...)
btc.getAddress(publicKey, "p2sh"); // pay-to-script-hash (3...)
btc.getAddress(publicKey, "p2wsh"); // witness script hash

// testnet
const testnet = useBlockchain(await blockchains.bitcoin({ network: "testnet" })());
testnet.getAddress(publicKey, "segwit"); // tb1q...

Sign and verify messages

import { useBlockchain, blockchains } from "@agntn/keys";

const chain = useBlockchain(await blockchains.solana()());

const { keys } = chain.generateKeys();
const signature = chain.signMessage("hello", keys.private);
const valid = chain.verifyMessage("hello", signature, keys.public); // true

EVM chains share addresses

import { useBlockchain, blockchains } from "@agntn/keys";

const eth = useBlockchain(await blockchains.ethereum()());
const base = useBlockchain(await blockchains.base()());

const privateKey = eth.generateKeyPrivate();
const pubKey = eth.getKeyPublic(privateKey);

eth.getAddress(pubKey) === base.getAddress(pubKey); // true

Derive HD keys

import { mnemonicToSeed } from "@agntn/keys/bip39";
import { getMasterKeyFromSeed, deriveHDKey } from "@agntn/keys/bip32";

const seed = mnemonicToSeed(
  "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
);
const master = getMasterKeyFromSeed(seed);
const account = deriveHDKey(master, "m/84'/0'/0'/0/0");

Use @agntn/keys/slip10 instead of @agntn/keys/bip32 for ed25519 derivation.

Derive a wallet from a mnemonic

import { useBlockchain, blockchains } from "@agntn/keys";

const mnemonic =
  "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";

const btc = useBlockchain(await blockchains.bitcoin()());
btc.deriveHDWallet(mnemonic, "m/84'/0'/0'/0/0").address; // bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu

const sol = useBlockchain(await blockchains.solana()());
sol.deriveHDWallet(mnemonic, "m/44'/501'/0'/0'", { passphrase: "TREZOR" }).address;

secp256k1 chains walk BIP32 and ed25519 chains walk SLIP-10, which accepts hardened segments only. Bitcoin reads the address type off the purpose level (44, 49, 84, 86) unless one is passed. Cardano throws, because CIP-1852 starts from the entropy rather than the BIP39 seed.

Recover one missing BIP39 word

import { getMnemonicWordCandidates } from "@agntn/keys/bip39";

const candidates = getMnemonicWordCandidates(
  "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon ?",
);

The result only satisfies the BIP39 checksum. It does not prove that a candidate belongs to the wallet or puzzle target.

Map localized BIP39 words and indices

import { lookupBIP39Indices, lookupBIP39Words } from "@agntn/keys/bip39";

const wordMatches = await lookupBIP39Words(["orologio", "civetta"], "italian");
const indexMatches = await lookupBIP39Indices([1, 1179, 2048], "italian", 1);

Language keys cover the 10 official BIP39 lists. Word lookup is case-insensitive and normalizes Unicode to NFKD. Index lookup uses base 0 by default and accepts base 1 explicitly.

MCP server

The package includes a stdio MCP server with the same 13 operations used by the Pi extension. After installing the package, configure an MCP client to run keys mcp. A checkout can run the built entry directly:

{
  "mcpServers": {
    "keys": {
      "command": "node",
      "args": ["/absolute/path/to/keys/dist/cli.mjs", "mcp"]
    }
  }
}

Hosts that own their transport can import createMcpServer from @agntn/keys/mcp.

The server handles private keys, mnemonics, entropy, messages, and signatures as plaintext MCP arguments or results. They enter client transcripts. Use only public puzzle material or disposable test keys, never a wallet that controls real funds.

Supported Blockchains

Chain Curve Address Formats Testnet
Bitcoin secp256k1 legacy, p2sh, segwit, p2wsh, taproot βœ…
Ethereum secp256k1 EIP-55 checksum -
Base secp256k1 EVM-compatible -
Solana ed25519 base58 -
Aptos ed25519 0x-prefixed hex -
Cardano ed25519 payment, stake, enterprise βœ…
SUI ed25519, secp256k1 0x-prefixed hex (blake2b) -
TRON secp256k1 base58check βœ…

All chains support key generation, address derivation, address validation, and message signing.

Security

Built on audited cryptographic packages from @paulmillr:

Caution

Never use this with real funds or with any wallet that has ever been used. Generated and signed material is handled as plaintext; treat every key it touches as burned the moment it is produced. Generate fresh throwaway keys for testing only and assume anything passing through @agntn/keys is compromised. Keys that control real funds belong on a hardware wallet, never in a process, log, or agent transcript.

License

MIT

About

A TypeScript library for interacting with various blockchains.

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages