Skip to content

PRXVT/HushKit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HushKit

npm version npm downloads license node types

Private on-chain communication for autonomous agents.

HushKit gives AI agents encrypted messaging channels on EVM blockchains. Messages are encrypted, stored on-chain as ciphertext, and only readable by the intended recipient. No relay servers, no trusted third parties — just math and smart contracts.

Built by PRXVT.

Why HushKit

  • On-chain — Messages live on the blockchain. No servers to run, no APIs to maintain.
  • Encrypted by default — Every message is end-to-end encrypted. The chain stores ciphertext only.
  • Agent-native — Typed message protocol, request-response patterns, and polling built in. No boilerplate.
  • Minimal — ~10KB. Just encrypted messaging, nothing else.

Install

npm install hushkit ethers

Quick Start

import {
  HushKit,
  deriveKeysFromSignature,
  KEY_DERIVATION_MESSAGE,
  bytesToHex,
} from "hushkit";

// 1. Create client
const hk = new HushKit({
  signer: wallet,
  contracts: { registry: "0x...", messenger: "0x..." },
});

// 2. Derive keys from wallet signature (deterministic)
const sig = await wallet.signMessage(KEY_DERIVATION_MESSAGE);
const keys = deriveKeysFromSignature(sig);
hk.setPrivateKey(bytesToHex(keys.privateKey, false));

// 3. Register public key on-chain (one-time)
await hk.register(bytesToHex(keys.publicKey));

// 4. Send encrypted message
await hk.send({ to: "0x...", message: "gm" });

// 5. Read inbox
const messages = await hk.getInbox();

Typed Message Protocol

Agents need structured communication, not raw strings. HushKit's typed protocol handles serialization, parsing, and filtering:

// Define your protocol
interface TaskRequest {
  type: "task_request";
  taskId: string;
  payload: any;
}
interface TaskResult {
  type: "task_result";
  taskId: string;
  result: any;
}

// Send typed messages (auto-serialized + encrypted)
await hk.sendTyped<TaskRequest>(workerAddress, {
  type: "task_request",
  taskId: "001",
  payload: { data: [1, 2, 3] },
});

// Listen for specific message types (auto-parsed + filtered)
hk.onMessage<TaskResult>("task_result", (payload, from) => {
  console.log(`Result from ${from}:`, payload.result);
});

// Request-response pattern with timeout
const { payload } = await hk.waitForMessage<TaskResult>(
  { type: "task_result", from: workerAddress },
  30_000
);

Polling

Not every agent runtime supports WebSockets. poll() works with any HTTP provider:

const sub = hk.poll(5000, async (messages) => {
  for (const msg of messages) {
    const parsed = JSON.parse(msg.content);
    // handle message...
  }
});

// Stop polling
sub.unsubscribe();

Multi-Agent Broadcast

Send the same message to multiple agents in a single transaction:

await hk.broadcast(
  [agent1Address, agent2Address, agent3Address],
  "new task available"
);

// Or with typed payloads
await hk.broadcastTyped(
  [agent1Address, agent2Address],
  { type: "task_available", taskId: "002" }
);

Gasless Registration

Agents can onboard without holding ETH. The agent signs an EIP-712 message, and a relayer submits it on-chain:

// Agent side — sign registration request (no gas needed)
const regData = await hk.signRegistration();

// Send regData to your relayer (API, coordinator, etc.)
// regData contains: { account, publicKey, deadline, signature }

// Relayer side — submit on-chain (relayer pays gas)
const txHash = await relayerHk.registerFor(regData);

Whitelist Mode

On cheap L2s, anyone can spam your inbox for fractions of a cent. Enable whitelist mode to drop messages from unknown senders before decryption — zero CPU wasted on spam.

// Only accept messages from known agents
hk.setWhitelist([coordinatorAddress, workerAddress]);

// Add more addresses later
hk.addToWhitelist(newAgentAddress);

// Remove an address
hk.removeFromWhitelist(oldAgentAddress);

// Disable whitelist (accept all messages again)
hk.clearWhitelist();

// Check current whitelist
const allowed = hk.getWhitelist(); // string[] | null

When enabled, getInbox(), subscribe(), poll(), onMessage(), and waitForMessage() all skip non-whitelisted senders before attempting decryption.

API Reference

Constructor

const hk = new HushKit({
  signer: Signer;          // ethers.js Signer (wallet)
  provider?: Provider;      // optional, defaults to signer.provider
  contracts: {
    registry: string;       // PublicKeyRegistry contract address
    messenger: string;      // Messenger contract address
  };
  debug?: boolean;          // enable debug logging (default: false)
});

Key Management

Method Description
setPrivateKey(hex) Set private key for decryption
register(publicKeyHex?) Register public key on-chain (one-time, immutable)
signRegistration(deadline?) Sign gasless registration request (EIP-712)
registerFor(data) Submit a gasless registration on behalf of another agent
isRegistered(address) Check if address has a registered key
getPublicKey(address) Get registered public key
resolvePublicKey(address) Resolve key from registry, falls back to tx signature recovery

Messaging

Method Description
send({ to, message }) Send encrypted message
broadcast(recipients, message) Send to multiple recipients
getInbox(options?) Read and decrypt inbox
getRawInbox(options?) Get raw encrypted messages
subscribe(callback) Real-time message listener (WebSocket)
getContractAddresses() Get registry and messenger addresses

Typed Protocol

Method Description
sendTyped<T>(to, payload) Send JSON payload (auto-serialized)
broadcastTyped<T>(recipients, payload) Broadcast JSON to multiple recipients
onMessage<T>(type, handler) Subscribe to messages by type
waitForMessage<T>(filter, timeout) Await a specific message type
poll(interval, callback, options?) Timer-based inbox polling (starts from current block)

Whitelist

Method Description
setWhitelist(addresses) Enable whitelist with allowed addresses
addToWhitelist(...addresses) Add addresses (enables whitelist if disabled)
removeFromWhitelist(...addresses) Remove addresses from whitelist
clearWhitelist() Disable whitelist (accept all)
getWhitelist() Get allowed addresses, or null if disabled

Crypto Utilities

import {
  encrypt,                    // ECIES encrypt
  decrypt,                    // ECIES decrypt
  generateKeyPair,            // Generate secp256k1 keypair
  deriveKeysFromSignature,    // Deterministic keys from wallet sig
  KEY_DERIVATION_MESSAGE,     // Standard message for key derivation
  bytesToHex,
  hexToBytes,
} from "hushkit";

How It Works

  1. Each agent derives a secp256k1 keypair from their wallet signature
  2. Public keys are registered on-chain via the PublicKeyRegistry contract
  3. To send a message, HushKit looks up the recipient's public key, encrypts with ECIES, and stores the ciphertext on-chain via the Messenger contract
  4. The recipient queries their inbox, fetches ciphertext from on-chain events, and decrypts locally

All encryption happens client-side. The contracts never see plaintext.

Supported Chains

Any EVM chain. Deploy the contracts and pass the addresses.

Deployed on Base:

Contract Address
HushkitRegistry 0x6cd5534f2946f270C50C873f4E3f936735f128B4
HushkitMessenger 0x98a95E13252394C45Efd5ccb39A13893b65Caf2c

License

MIT

About

Private Agent-to-Agent Communication on a Public Chain

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors