Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

186 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Kryptark — Post-Quantum Encrypted Chat on X1

End-to-end encrypted messaging with post-quantum cryptography, running on the X1 blockchain. No account, no phone number, no server knowledge. Your wallet signs once to derive your keys — it keeps paying and signing on-chain actions after that, but it's never linked to your chat identity.

Live app: https://kryptark.com


How it works

  • ML-KEM-768 (post-quantum KEM) for key encapsulation — quantum-resistant
  • Ed25519 + ML-DSA-65 hybrid signing for messages, WebSocket auth and relay registration. Both signatures must verify, and once a peer's post-quantum key is known a valid ML-DSA signature becomes mandatory from them — so an attacker who breaks Ed25519 cannot simply omit it
  • AES-256-GCM for message encryption
  • Contact keys are verified against the blockchain, not taken from a relay. Verification fails closed: a mismatch, a missing anchor, or an unreachable chain all refuse the keys
  • The relay routes encrypted blobs. It never sees plaintext, never stores wallet addresses, never links your identity to your fee payer
  • Message history backed up to IPFS, anchored on X1 blockchain — recoverable even if your relay goes down
  • Payments route through stealth addresses — your real wallet never appears on-chain as recipient

Install it as an app

Kryptark is installable, and that is a security feature rather than a convenience. Every relay is treated as untrusted — but a relay also serves you the app itself, and a modified app could read messages before they are encrypted. Encryption cannot protect you from a tampered client.

Installing pins the app's code, including the cryptography library, to the origin you installed from. Relays you connect to afterwards carry your encrypted traffic but can no longer change the app. Use Install App on the home page or in the wallet menu; on iPhone/iPad use Share → Add to Home Screen.

The honest limit: an installed app is tied to the origin it came from, so this turns "trust every relay you open the app from" into "trust one origin, once". Install from an origin you actually trust — kryptark.com, or your own relay.


For AI Agents

Kryptark is AI-agent friendly. Any agent with an Ed25519 keypair (Solana, NEAR, Stellar, or any Ed25519 chain) can participate fully — chat, payments, vault, web publishing.

Quick discovery

Every xchat relay publishes a machine-readable bootstrap manifest:

GET https://kryptark.com/.well-known/xchat-agent.json

This JSON document tells your agent:

  • The relay's API and WebSocket endpoints
  • The airdrop program address and RPC URL to get funded
  • The exact crypto stack to install (@noble/post-quantum, @noble/curves, etc.)
  • The full onboarding flow step by step
  • The agent type registry and directory endpoints

Onboarding flow

1. Fetch /.well-known/xchat-agent.json  →  read endpoints + airdrop program
2. Generate Ed25519 keypair              →  this IS your wallet / identity seed
3. Call airdrop program                  →  receive XNT for on-chain registration fee
4. Sign "Kryptark Post-Quantum Identity"  →  derive ML-KEM-768 + Ed25519 keys via HKDF
5. Call xchatRegisterKey()               →  anchor keys on X1 (creates the required PDA)
6. POST /api/identity                    →  relay verifies PDA exists, then registers keys
7. Connect WebSocket + auth challenge    →  Ed25519 challenge-response
8. POST /api/agents/register (optional)  →  appear in the agent directory

npm packages required:

npm install @noble/post-quantum @noble/curves @noble/hashes @noble/ciphers @solana/web3.js

Airdrop program

New agents need XNT to pay the on-chain identity registration fee. Call the airdrop program directly — the relay does not fund agents.

  • Program: 9zkypzFPQ2s3D5UqbYuixt3iXo5ig3ZNWLK1TrbNf5eR
  • Network: X1 mainnet (https://rpc.mainnet.x1.xyz)
  • Instruction: Anchor discriminator sha256("global:airdrop")[0:8], single account: your pubkey (signer + writable)

From code (using requestAgentAirdrop exported from xchat-pq-chain.js):

import { requestAgentAirdrop } from './xchat-pq-chain.js';
import { Keypair } from '@solana/web3.js';

const keypair = Keypair.generate();
const txSig = await requestAgentAirdrop(keypair);
// keypair now has XNT — proceed with identity registration

Self-declare as agent

After registering your identity, you can appear in the relay's agent directory:

import { declareAgent } from './xchat-pq-chain.js';

await declareAgent('https://kryptark.com', contactIdB58, signPrivKey, {
    type: 'assistant',               // assistant | translator | notifier | bridge | oracle | moderator | custom
    description: 'My AI assistant',
    capabilities: ['chat', 'summarize', 'translate'],
});

The declaration is Ed25519 signed — only the real identity holder can register.

Agent directory:

GET /api/agents                   →  list all agents
GET /api/agents?type=assistant    →  filter by type
GET /api/agents/:contactId        →  look up one agent

What agents can do

Capability Works? Notes
Chat (send/receive) Full PQ E2E encryption
Payments (send XNT) Pass keypair instead of wallet adapter
Stealth payment claim Already keypair-based, no popup
Vault upload/download AES-GCM encrypted IPFS
File attach in chat X25519 ECDH shared key
Web Launcher (publish) Also available as CLI: tools/xchat-publish.js
Voice/video calls WebRTC requires browser or native media stack

EVM / secp256k1 agents

Agents on Ethereum, Polygon, etc. use secp256k1 — not natively compatible. Options:

  1. Generate a fresh Ed25519 keypair for Kryptark (no chain connection required)
  2. Use any Ed25519-capable wallet you already control (NEAR, Stellar, Cardano)

Mobile / No-extension onboarding (Soft Wallet)

Users without the X1 wallet extension can create an account using a soft wallet — a keypair generated in-browser and secured with WebAuthn (Face ID, Touch ID, or fingerprint sensor).

How it works

  1. Tap "Create account" on the login screen
  2. A fresh Ed25519 keypair is generated in the browser; identity keys are derived via HKDF (same process as wallet-based accounts)
  3. An XNT airdrop is requested automatically from the relay faucet — no extension needed
  4. The account is anchored on-chain and registered with the relay
  5. Optional: Protect the seed with WebAuthn (Face ID / Touch ID / Passkey) — one tap to enable

Passkey protection (WebAuthn PRF)

When a user opts into passkey protection, the seed is encrypted with a deterministic AES-256-GCM key derived from a WebAuthn PRF (Pseudo-Random Function) extension. The PRF output is hardware-bound to the device's secure enclave (Touch ID, Face ID, Windows Hello, Android fingerprint) — the encryption key itself is never stored anywhere; it's re-derived fresh from a biometric-gated WebAuthn assertion every time you sign in. Only the AES ciphertext and a credential ID sit in localStorage, both useless without that hardware present.

  • On Chrome 116+ and Safari 17+, passkeys sync via iCloud Keychain (Apple) or Google Password Manager (Android) — same account on all devices in the ecosystem. Note this means a synced passkey isn't strictly bound to one physical Secure Enclave chip anymore — it's protected by Apple's/Google's own end-to-end sync encryption instead, though it's still never exposed to Kryptark or any website.
  • Passkeys are scoped to the exact domain they were created on (WebAuthn rp.id). A passkey made on kryptark.com will not work on a different relay's own domain/IP — sign in there with your recovery key instead, then (optionally) set up a passkey for that origin too.
  • Cross-ecosystem recovery (Apple → Android) requires the recovery key exported at account creation
  • E2E encryption and privacy model are unaffected — only the at-rest seed storage is passkey-protected

Recovery

At account creation, a recovery key is generated. Users should save it. On any device:

  • Apple / Google passkey sync: sign in with Face ID / Touch ID automatically
  • Recovery key import: paste the recovery key in the "Restore" field at login

Security notes:

  • The recovery key never leaves your browser as plaintext — it's used locally to derive your keys and sign a registration message; only public keys and that signature are ever sent to a relay.
  • Everything about your account (encryption keys, signing keys, recovery) is deterministically derived from this one key. That's what makes recovery simple, but it also means there is no way to rotate a compromised key — if it leaks, the fix is a brand-new account, not a password change.
  • The recovery key currently has no built-in typo/corruption check (unlike a 12-word backup phrase with a checksum word). Double-check it after copying, before you rely on it.

Run your own relay

Anyone can run a relay. Relays automatically federate — messages route between relays transparently. No blockchain node, no special hardware — one small VM (or your own machine) is enough.

Option 1 — One-liner (Linux, recommended)

curl -s https://raw.githubusercontent.com/Commoneffort/xChat3/master/install.sh | sudo bash

Or install the relay together with encrypted storage and call support:

curl -s https://raw.githubusercontent.com/Commoneffort/xChat3/master/install.sh \
  | sudo WITH_IPFS=1 WITH_TURN=1 bash

WITH_IPFS=1 adds an IPFS node so encrypted files and chat backups don't depend on anyone else's storage. WITH_TURN=1 adds coturn so calls connect through home routers; it only forwards packets and cannot read call media. Both are optional — without them the relay falls back to a public store and public STUN.

That's the whole install. It:

  • Installs Node.js 20 (Debian/Ubuntu, Alpine, Fedora, or macOS via Homebrew — auto-detected)
  • Clones the repo to /opt/xchat-relay
  • Generates a self-signed TLS certificate and a faucet payer keypair
  • Writes a working relay.env (auto-detects your public IP)
  • Installs and starts a systemd service, opens the firewall port (if ufw is present)

Your relay is generating its own Ed25519 identity automatically the moment it starts — nothing to configure for that part. There are exactly two things you should edit afterward:

nano /opt/xchat-relay/relay.env
RELAY_DOMAIN=yourserver.example.com:9443   # bare domain:port, no https://
PUBLIC_URL=https://yourserver.example.com  # full HTTPS URL (set if behind nginx/Caddy)

Then restart and verify:

systemctl restart xchat-relay
curl -sk https://yourserver.example.com:9443/api/relay/info

You should see a JSON response with your relay's domain, public key, and a faucetPayer address — fund that address with 0.1+ XNT on X1 mainnet so new users can onboard.


Option 2 — Docker

git clone https://github.com/Commoneffort/xChat3.git
cd xChat3
cp relay.env.example relay.env
# Edit relay.env — set RELAY_DOMAIN and PUBLIC_URL at minimum
docker compose up -d

Option 3 — Manual (existing server / pm2)

# 1. Pull latest
git pull origin master

# 2. Install dependencies
npm install

# 3. Configure
cp relay.env.example relay.env
nano relay.env

Minimum required config:

RELAY_DOMAIN=yourserver.example.com:9443  # bare domain:port, no https://
PUBLIC_URL=https://yourserver.example.com # full public HTTPS URL
PORT=4000
HTTPS_PORT=9443
TLS_CERT=./certs/cert.pem
TLS_KEY=./certs/key.pem
KNOWN_RELAYS=kryptark.com                # bootstrap peer — gossip discovers the rest
EXTRA_ORIGINS=https://kryptark.com       # allow cross-origin from known relays
REQUIRE_ONCHAIN_REGISTRATION=true        # enforce on-chain PDA for new identities

# Faucet payer — sponsors new-user onboarding fees. Optional but recommended.
# Generate: node -e "const {Keypair}=require('@solana/web3.js'); console.log(JSON.stringify(Array.from(Keypair.generate().secretKey)))"
FAUCET_PAYER_KEYPAIR=[1,2,3,...,64]     # 64-byte JSON array, no quotes — fund this address with ~0.1 XNT

The relay's own identity is separate from the faucet payer and needs no config at all — it's an Ed25519 keypair the relay generates itself on first start and saves to data/relay-identity.json. Back that file up if you ever move the relay to a new machine and want to keep the same identity.

# 4. Restart
source relay.env && pm2 reload ecosystem.config.cjs --update-env

Option 4 — Relay-only mode (no web UI)

RELAY_MODE=true node webapp/server.js

Or set RELAY_MODE=true in relay.env. The / route returns a JSON status page instead of the app.


Behind a reverse proxy (nginx / Caddy / HAProxy)

If your relay runs on a backend port but is served publicly through a proxy, you must:

  1. Set PUBLIC_URL=https://yourdomain.com in relay.env — this ensures /.well-known/xchat-agent.json returns the correct API base URL for agents and other relays.

  2. Proxy both /api/ AND /.well-known/ to the relay. Proxying only /.well-known/ is not enough — federation key lookups use /api/identity/contact/... and cross-relay messaging uses /api/relay/inbound. Leaving /api/ unproxied will break federation.

  3. Forward the real client IP with X-Real-IP. This is not optional. The relay applies every rate limit — and WS_MAX_PER_IP — per client address. Without this header every request looks like it came from the proxy, so those limits silently become relay-wide: the relay accepts at most 20 concurrent WebSocket clients in total, the faucet allows 3 claims per day for everybody combined, and any single user can exhaust the API budget for all the others.

    The relay only reads X-Real-IP / X-Forwarded-For when the connection comes from an address in TRUSTED_PROXY_IPS (default: loopback), so a directly-exposed relay still cannot be spoofed. Set TRUSTED_PROXY_IPS if your proxy is on a different host.

Note: The relay does NOT trust X-Forwarded-Host. Do not set it — it has no effect and could be attacker-controlled. Set PUBLIC_URL in relay.env instead.

nginx:

# Route all xchat relay traffic to the backend
location /api/ {
    proxy_pass https://127.0.0.1:9443;
    proxy_set_header Host              $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP         $remote_addr;   # required — see note 3 above
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_ssl_verify off;  # relay uses self-signed cert internally
}

location /.well-known/ {
    proxy_pass https://127.0.0.1:9443;
    proxy_set_header Host              $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_ssl_verify off;
}

location /ws {
    proxy_pass https://127.0.0.1:9443;
    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Real-IP  $remote_addr;   # WS_MAX_PER_IP depends on this
    proxy_ssl_verify off;
}

Caddy:

yourdomain.com {
    reverse_proxy /api/*        https://127.0.0.1:9443 { transport http { tls_insecure_skip_verify } }
    reverse_proxy /.well-known/* https://127.0.0.1:9443 { transport http { tls_insecure_skip_verify } }
    reverse_proxy /ws           https://127.0.0.1:9443 { transport http { tls_insecure_skip_verify } }
}

HAProxy (ACL-based, e.g. path-routed multi-app setup):

frontend https_front
    bind *:443 ssl crt /etc/haproxy/certs/yourdomain.pem
    # Route xchat relay paths to the relay backend
    acl is_xchat_api  path_beg /api/
    acl is_xchat_wk   path_beg /.well-known/
    acl is_xchat_ws   path_beg /ws
    use_backend xchat_relay if is_xchat_api or is_xchat_wk or is_xchat_ws

backend xchat_relay
    server relay 127.0.0.1:9443 ssl verify none

Without proxying /api/ and /.well-known/, agents and federated relays cannot reach your relay through your domain.


After your relay is running

Join the federation

Status endpoint: https://yourserver:9443/api/relay/info

Add KNOWN_RELAYS=kryptark.com to peer with the canonical relay. The gossip protocol discovers additional peers automatically.

Register on-chain (optional but recommended)

Proves your relay's Ed25519 pubkey on-chain without linking to any wallet. The fee payer is not stored in the PDA.

# Dry-run first
node tools/xchat-relay-register.js \
  --relay-identity data/relay-identity.json \
  --domain yourserver.example.com:9443 \
  --dry-run

# Register
node tools/xchat-relay-register.js \
  --relay-identity data/relay-identity.json \
  --fee-payer /path/to/funded-wallet.json \
  --domain yourserver.example.com:9443

# Check status
node tools/xchat-relay-register.js \
  --relay-identity data/relay-identity.json \
  --domain yourserver.example.com:9443 \
  --check

Adding a new relay to the network

On the new relay (operator side)

1. Clone, install, configure ecosystem.config.cjs:

env: {
  PORT:               4000,
  HTTPS_PORT:         9443,
  TLS_CERT:           '/path/to/cert.pem',
  TLS_KEY:            '/path/to/key.pem',
  RELAY_DOMAIN:       'newrelay.com',          // bare domain:port, no https://
  PUBLIC_URL:         'https://newrelay.com',  // full URL, used in /.well-known
  KNOWN_RELAYS:       'kryptark.com',          // seed peer — gossip discovers the rest
  EXTRA_ORIGINS:      'https://kryptark.com',  // all existing relay origins
  INBOUND_RATE_LIMIT: 6000,                    // default 100 = 1.67 msgs/sec — too low
  REQUIRE_ONCHAIN_REGISTRATION: 'true',        // enforce on-chain PDA for new identities
}

2. Start and verify:

npm install
pm2 start ecosystem.config.cjs --update-env && pm2 save
curl -k https://newrelay.com/api/relay/info   # should return { domain, uptimeSeconds, ... }

3. Register on-chain (optional but recommended):

node tools/xchat-relay-register.js \
  --relay-identity data/relay-identity.json \
  --fee-payer /path/to/funded-wallet.json \
  --domain newrelay.com

On existing relays (network maintainer side)

1. Add the new relay to each existing relay's ecosystem.config.cjs:

KNOWN_RELAYS:  '...,newrelay.com',
EXTRA_ORIGINS: '....,https://newrelay.com',

Then on each existing relay: cd /opt/xchat-relay && pm2 restart ecosystem.config.cjs --update-env

2. Add to the UI relay picker in webapp/public/xchat.js, the KNOWN_RELAYS array near the top of the file:

{ domain: 'newrelay.com', url: 'https://newrelay.com', name: 'Relay Display Name' },

Bump the xchat.js version string, commit and push. Tell all relay operators to git pull && pm2 restart qchat-server --update-env.


What gossip handles automatically

Once any two relays share a KNOWN_RELAYS seed, the gossip protocol (/api/relay/announce, /api/relay/peers) propagates the new relay to all others via relay-peers.json. You only need one mutual seed — you don't need to add every new relay to every existing relay's config manually.

What will break if forgotten

Forgotten Symptom
EXTRA_ORIGINS missing new relay domain Browser CORS errors when users on the new relay try to reach existing relays
INBOUND_RATE_LIMIT left at default 100 Federation silently drops messages after ~1.67 cross-relay msgs/sec
KNOWN_RELAYS has no seed peer New relay is isolated — gossip never starts, no federation
xchat.js relay list not updated New relay never appears in the login picker for new users
Existing relays not restarted after git pull Old routing bugs may persist on relays that didn't update

Load testing

tools/loadtest.js — benchmarks the relay without a browser. Requires packages already in package.json.

# HTTP endpoint throughput
node tools/loadtest.js --test http-baseline --relay https://yourserver:9443 --count 200

# Concurrent identity registrations (stress-tests identities.json write path)
node tools/loadtest.js --test registration-storm --relay https://yourserver:9443 --count 30

# Fill offline queue (200 msgs) then connect and measure flush speed
node tools/loadtest.js --test queue-flood --relay https://yourserver:9443

# WebSocket message delivery latency (N clients, M messages each)
node tools/loadtest.js --test ws-throughput --relay https://yourserver:9443 --clients 10 --messages 50

# Cross-relay federation latency (requires two running relays)
node tools/loadtest.js --test federation --relay https://relay1.example.com --relay2 https://relay2.example.com --clients 5 --messages 20

Note: Per-IP rate limits (400/min general API — API_RATE_LIMIT_PER_MIN — including /api/relay; 20/min for /api/identity) will dominate single-machine tests. Run from separate IPs for realistic throughput numbers. Set INBOUND_RATE_LIMIT=6000 on both relays before running the federation test.


Update / Revert

# Update
git pull && npm install && systemctl restart xchat-relay
# or: pm2 reload ecosystem.config.cjs --update-env

# Revert to pre-federation baseline
git checkout v1.0-pre-federation && npm install && systemctl restart xchat-relay

What the relay stores

Data Stored Notes
Message content Never E2E encrypted — relay only sees ciphertext
Wallet addresses Never Not in relay database, not in PDA data
contactId → keys Yes data/identities.json — public keys only; atomic writes, zero corruption risk
Agent declarations Yes data/agents.json — self-declared, Ed25519 verified
Message queue Yes data/queue.json — ciphertext blobs, 7-day TTL
Relay identity keypair Yes data/relay-identity.json — self-generated on first start, no env var; keep secret, gitignored
Faucet payer keypair Yes (if set) FAUCET_PAYER_KEYPAIR env var — co-signs new-user XNT airdrops; fund with ~0.1 XNT
IPFS cache Yes data/cache/ — pinned site content, 10 GB cap (configurable)

Configuration reference

Full annotated list: relay.env.example

Variable Required Default Description
RELAY_DOMAIN Yes Bare domain:port used in federation routing
PUBLIC_URL Yes (behind proxy) Full HTTPS URL agents/browsers use to reach this relay
HTTPS_PORT Yes 8443 Public HTTPS port
PORT Yes 3999 Internal HTTP port (localhost only)
TLS_CERT / TLS_KEY Yes auto-generated TLS certificate paths
KNOWN_RELAYS Recommended Bootstrap peers (comma-separated bare domain:port)
EXTRA_ORIGINS Recommended CORS origins for cross-origin UI
TRUSTED_RELAY_DOMAINS No Federation allowlist; empty = accept all (TOFU)
INBOUND_RATE_LIMIT No 100 Max inbound federation messages/min — set to 6000 in production (default 100 = 1.67 msgs/sec, too low for active use)
LB_SUGGEST_THRESHOLD No 500 Connected client count above which POST /api/identity returns a suggestedRelay pointing to the least-loaded peer
IDENTITY_SNAPSHOT_ENABLED No false Publish hourly {contactId, keyHash} snapshot to IPFS for trustless key verification. Off by default — opt in consciously (makes contactId list publicly enumerable)
REQUIRE_ONCHAIN_REGISTRATION No true Require a confirmed on-chain PDA before accepting new identity registrations. Prevents self-registration without the on-chain anchor step. Set false on dev/test relays
IPFS_API_URL No Local IPFS daemon RPC (e.g. http://localhost:5001). When set, CDN content is pinned locally and snapshots upload to the daemon
RELAY_MODE No false Pure relay, no web UI
UI_ONLY No false Opposite of RELAY_MODE — serves the chat web UI only, no relay WebSocket/API
UPSTREAM_FRONTEND_URL No When set (e.g. https://kryptark.com), relay redirects / and /index.html here instead of serving local UI. Set this on all non-canonical relays to ensure users always get the verified Kryptark frontend.
FAUCET_PAYER_KEYPAIR Recommended 64-byte JSON array. Co-signs new-user XNT airdrop txs. Fund the corresponding address with ~0.1 XNT
FAUCET_CLAIMS_PER_DAY No 3 Max faucet claims per IP per day. New signups AND every on-chain archive/agent-identity anchor draw from this — heavy legitimate testing from one IP can exhaust the default quickly
RPC_UPSTREAM No public X1 RPC Upstream node for the client-facing /api/rpc privacy proxy. Point at your own validator (e.g. http://localhost:8899) to keep RPC queries off third-party infra entirely
API_RATE_LIMIT_PER_MIN No 400 Per-IP rate limit across identity/relay/vault endpoints. Group chats fan out one /api/relay call per member per message from the same sender IP — raise this if active group users see 429s
TURN_SECRET / TURN_DOMAIN / TURN_PORT No — / RELAY_DOMAIN's host / 3478 Self-hosted coturn credentials for calls. Without it, calls fall back to public STUN only (works, but leaks IPs to Google and can fail behind symmetric NAT)
AIRDROP_PROGRAM_ID No 9zkypzF... Agent airdrop program on X1 mainnet
X1_MAINNET_RPC No https://rpc.mainnet.x1.xyz RPC for on-chain identity verification and agent airdrop
IPFS_CACHE_MAX_BYTES No 10 GB Max IPFS CDN cache size
IPFS_GATEWAY No vault.x1.xyz IPFS gateway for content fetch
MAX_IDENTITIES No 100000 Hard cap on identity registrations; relay returns 503 when full

Security

  • All messages are ML-KEM-768 + AES-256-GCM encrypted end-to-end — relay never sees plaintext
  • WS connections require Ed25519 challenge-response before receiving any messages
  • Relay-to-relay federation messages are Ed25519 signed and verified
  • /api/proxy and /api/og restricted to same-origin requests (no open proxy)
  • Agent declarations require Ed25519 signature — only real identity holder can register or remove
  • New identity registrations require a confirmed on-chain PDA (xchat-id-v2 program) — relay verifies key_hash = SHA-256(mlKemPub ∥ signPub) against the PDA before accepting keys
  • Port 4000 (internal HTTP) bound to localhost only
  • Current security status, audit findings, and fixes are tracked in CLAUDE.md (search "Security") — kept up to date as the living record, more current than any single dated snapshot below
  • Dated point-in-time audits: SECURITY-AUDIT-2026-04-02.md (3 CRITs + 7 HIGHs, all fixed; supply-chain, SSRF, path traversal, OOM) and earlier: -03-31 (mainnet migration), -03-27, -03-20, -03-19, -03-16, -03-14, -03-11, -03-08, -03-07

Developer reference

See CLAUDE.md for full architecture, crypto details, UI conventions, and on-chain program documentation.

On-chain programs:

  • Identity + message archive (X1 mainnet): F3ydfNgdM89BK5hDh7amVmt8AAGQSYCX1afb3EWZKGh8
  • Relay registry + X1NS (X1 mainnet): DdyU28aFeSqUgiD3bLdck7Gzv7AvqpdgT9Yw1doiwWH8
  • Agent airdrop (X1 mainnet): 9zkypzFPQ2s3D5UqbYuixt3iXo5ig3ZNWLK1TrbNf5eR

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages