{"id":45541891,"url":"https://github.com/CorvidLabs/ts-algochat","last_synced_at":"2026-03-08T07:01:37.490Z","repository":{"id":334149952,"uuid":"1140268421","full_name":"CorvidLabs/ts-algochat","owner":"CorvidLabs","description":"🔐 TypeScript implementation of AlgoChat - Encrypted messaging on Algorand","archived":false,"fork":false,"pushed_at":"2026-02-07T02:58:20.000Z","size":97,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-07T13:40:37.917Z","etag":null,"topics":["algorand","blockchain","chacha20-poly1305","cryptography","encryption","messaging","typescript","x25519"],"latest_commit_sha":null,"homepage":"https://corvidlabs.github.io/ts-algochat/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CorvidLabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-23T03:34:08.000Z","updated_at":"2026-02-07T06:35:15.000Z","dependencies_parsed_at":"2026-02-07T05:02:02.260Z","dependency_job_id":null,"html_url":"https://github.com/CorvidLabs/ts-algochat","commit_stats":null,"previous_names":["corvidlabs/ts-algochat"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/CorvidLabs/ts-algochat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CorvidLabs%2Fts-algochat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CorvidLabs%2Fts-algochat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CorvidLabs%2Fts-algochat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CorvidLabs%2Fts-algochat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CorvidLabs","download_url":"https://codeload.github.com/CorvidLabs/ts-algochat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CorvidLabs%2Fts-algochat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30248488,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T05:41:50.788Z","status":"ssl_error","status_checked_at":"2026-03-08T05:41:39.075Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorand","blockchain","chacha20-poly1305","cryptography","encryption","messaging","typescript","x25519"],"created_at":"2026-02-23T04:00:32.880Z","updated_at":"2026-03-08T07:01:37.480Z","avatar_url":"https://github.com/CorvidLabs.png","language":"TypeScript","funding_links":[],"categories":["AI and Machine Learning"],"sub_categories":["Metrics and Analytics Services"],"readme":"# ts-algochat\n\n[![CI](https://img.shields.io/github/actions/workflow/status/CorvidLabs/ts-algochat/ci.yml?label=CI\u0026branch=main)](https://github.com/CorvidLabs/ts-algochat/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/@corvidlabs/ts-algochat)](https://www.npmjs.com/package/@corvidlabs/ts-algochat)\n[![License](https://img.shields.io/github/license/CorvidLabs/ts-algochat)](https://github.com/CorvidLabs/ts-algochat/blob/main/LICENSE)\n[![Version](https://img.shields.io/github/v/release/CorvidLabs/ts-algochat?display_name=tag)](https://github.com/CorvidLabs/ts-algochat/releases)\n\n\u003e **Pre-1.0 Notice**: This library is under active development. The API may change between minor versions until 1.0.\n\nTypeScript implementation of the AlgoChat protocol for encrypted messaging on Algorand.\n\n## Features\n\n- **End-to-End Encryption** - X25519 + ChaCha20-Poly1305\n- **Forward Secrecy** - Per-message ephemeral keys\n- **PSK Mode (v1.1)** - Hybrid ECDH + pre-shared key ratcheting for quantum defense-in-depth\n- **Bidirectional Decryption** - Sender can decrypt own messages\n- **Reply Support** - Thread conversations with context\n- **Minimal Dependencies** - Uses @noble crypto libraries (audited) + algosdk\n- **TypeScript First** - Full type safety\n\n## Security Properties\n\n| Property | Status |\n|----------|--------|\n| Message content confidentiality | Protected (E2EE) |\n| Message integrity | Protected (authenticated encryption) |\n| Forward secrecy | Protected (ephemeral keys per message) |\n| Replay attacks | Protected (blockchain uniqueness + PSK counter) |\n| Quantum resistance (key exchange) | Optional (PSK mode provides defense-in-depth) |\n| PSK session forward secrecy | Optional (100-message session boundaries in PSK mode) |\n| Metadata privacy | **Not protected** (addresses, timing visible) |\n| Traffic analysis | **Not protected** |\n\n## Installation\n\n```bash\n# npm\nnpm install @corvidlabs/ts-algochat\n\n# bun\nbun add @corvidlabs/ts-algochat\n\n# pnpm\npnpm add @corvidlabs/ts-algochat\n```\n\n## Quick Start\n\n```typescript\nimport {\n    AlgorandService,\n    createChatAccountFromMnemonic,\n} from '@corvidlabs/ts-algochat';\n\n// Initialize service\nconst service = new AlgorandService({\n    algodToken: '',\n    algodServer: 'https://testnet-api.algonode.cloud',\n    indexerToken: '',\n    indexerServer: 'https://testnet-idx.algonode.cloud',\n});\n\n// Create account from mnemonic\nconst account = createChatAccountFromMnemonic('your 25 word mnemonic...');\n\n// Discover recipient's encryption key\nconst recipientKey = await service.discoverPublicKey('RECIPIENT_ADDRESS');\n\n// Send encrypted message\nconst result = await service.sendMessage(\n    account,\n    'RECIPIENT_ADDRESS',\n    recipientKey,\n    'Hello from AlgoChat!'\n);\n\nconsole.log('Transaction ID:', result.txid);\n\n// Fetch messages\nconst messages = await service.fetchMessages(account, 'RECIPIENT_ADDRESS');\n```\n\n## API Reference\n\n### Account Management\n\n```typescript\n// Create from mnemonic\nconst account = createChatAccountFromMnemonic('word1 word2 ...');\n\n// Generate new account\nconst newAccount = createRandomChatAccount();\nconsole.log('Address:', newAccount.address);\nconsole.log('Mnemonic:', newAccount.mnemonic);\n\n// Validate mnemonic\nif (validateMnemonic('word1 word2 ...')) {\n    // Valid 25-word mnemonic\n}\n\n// Validate address\nif (validateAddress('ALGO...')) {\n    // Valid Algorand address\n}\n```\n\n### Sending Messages\n\n```typescript\n// Simple message\nawait service.sendMessage(account, recipient, recipientKey, 'Hello!');\n\n// Reply to a message\nawait service.sendReply(account, recipient, recipientKey, 'Reply text', {\n    txid: 'original-tx-id',\n    preview: 'Original message preview...',\n});\n```\n\n### Fetching Messages\n\n```typescript\n// Get all messages with an address\nconst messages = await service.fetchMessages(account, 'ADDRESS');\n\n// Get all conversations\nconst conversations = await service.fetchConversations(account);\n\n// Discover public key\nconst pubKey = await service.discoverPublicKey('ADDRESS');\n```\n\n### Low-Level Crypto\n\n```typescript\nimport {\n    deriveEncryptionKeys,\n    encryptMessage,\n    decryptMessage,\n    encodeEnvelope,\n    decodeEnvelope,\n} from '@corvidlabs/ts-algochat';\n\n// Derive keys from seed\nconst keys = deriveEncryptionKeys(seed);\n\n// Encrypt message\nconst envelope = encryptMessage(\n    'Hello!',\n    senderPublicKey,\n    recipientPublicKey\n);\n\n// Encode for transmission\nconst bytes = encodeEnvelope(envelope);\n\n// Decode received envelope\nconst decoded = decodeEnvelope(bytes);\n\n// Decrypt message\nconst content = decryptMessage(decoded, myPrivateKey, myPublicKey);\n```\n\n## Types\n\n```typescript\ninterface ChatAccount {\n    address: string;\n    publicKey: Uint8Array;\n    privateKey: Uint8Array;\n    encryptionKeys: X25519KeyPair;\n    mnemonic?: string;\n}\n\ninterface Message {\n    id: string;\n    sender: string;\n    recipient: string;\n    content: string;\n    timestamp: Date;\n    confirmedRound: number;\n    direction: 'sent' | 'received';\n    replyContext?: ReplyContext;\n}\n\ninterface Conversation {\n    participant: string;\n    participantPublicKey?: Uint8Array;\n    messages: Message[];\n    lastMessage?: Message;\n}\n```\n\n## Protocol\n\nThis library implements the [AlgoChat Protocol v1](https://github.com/CorvidLabs/protocol-algochat) and the PSK v1.1 extension.\n\n### Wire Format (v1.0 Standard)\n\n```\n[version: 1][protocol: 1][sender_pubkey: 32][ephemeral_pubkey: 32][nonce: 12][encrypted_sender_key: 48][ciphertext: variable]\n```\n\n### Wire Format (v1.1 PSK)\n\n```\n[version: 1][protocol: 2][ratchet_counter: 4][sender_pubkey: 32][ephemeral_pubkey: 32][nonce: 12][encrypted_sender_key: 48][ciphertext: variable]\n```\n\n### Cryptographic Primitives\n\n| Function | Algorithm |\n|----------|-----------|\n| Key Agreement | X25519 ECDH |\n| Encryption | ChaCha20-Poly1305 |\n| Key Derivation | HKDF-SHA256 |\n\n## PSK v1.1 Protocol\n\nThe PSK (Pre-Shared Key) v1.1 protocol adds an additional layer of authentication and security on top of standard ECDH encryption by incorporating a pre-shared key into the key derivation process.\n\n### Features\n\n- **Two-level key ratchet** - Session keys derived per 100 messages, position keys per message\n- **Hybrid encryption** - Combines ECDH forward secrecy with PSK authentication\n- **Replay protection** - Counter-based sliding window prevents message replay\n- **Out-of-band key exchange** - URI scheme for sharing PSK keys (QR code compatible)\n\n### Quantum Defense-in-Depth\n\nPSK mode provides defense against future quantum attacks through **hybrid key derivation**:\n\n```\nsymmetricKey = HKDF(\n  ikm = ephemeralECDH || currentPSK,\n  salt = ephemeralPublicKey,\n  info = \"algochat-psk-v1\" || senderPubKey || recipientPubKey\n)\n```\n\nThe encryption key is derived from **both** the ephemeral ECDH shared secret and the ratcheted PSK, concatenated before HKDF. This means an attacker must break **both** layers:\n\n1. **ECDH only broken** (quantum computer): Attacker still needs the PSK\n2. **PSK only compromised**: Attacker still cannot break ECDH (per-message ephemeral keys)\n3. **Both compromised**: Only then can messages be decrypted\n\nThis hybrid approach ensures that even if quantum computers eventually break X25519 ECDH, messages encrypted with PSK mode remain secure as long as the pre-shared key was exchanged securely.\n\n### Two-Level Ratcheting\n\nPSK mode derives per-message keys using a two-level ratchet:\n\n1. **Session derivation**: `sessionPSK = HKDF(initialPSK, sessionIndex)` where `sessionIndex = counter / 100`\n2. **Position derivation**: `currentPSK = HKDF(sessionPSK, position)` where `position = counter % 100`\n\nThis creates 100-message session boundaries. Compromising a session PSK exposes at most 100 messages.\n\n### Exchange URI Format\n\nPSK exchange URIs are designed for QR code sharing:\n\n```\nalgochat-psk://v1?addr=\u003calgorand_address\u003e\u0026psk=\u003cbase64url\u003e\u0026label=\u003coptional\u003e\n```\n\nUse any QR library (e.g., `qrcode`) to encode the URI for easy scanning between devices.\n\n### Usage\n\n```typescript\nimport {\n    derivePSKAtCounter,\n    encryptPSKMessage,\n    decryptPSKMessage,\n    encodePSKEnvelope,\n    decodePSKEnvelope,\n    isPSKMessage,\n    createPSKState,\n    advanceSendCounter,\n    validateCounter,\n    recordReceive,\n    createPSKExchangeURI,\n    parsePSKExchangeURI,\n} from '@corvidlabs/ts-algochat';\n\n// Derive PSK for a specific counter\nconst psk = derivePSKAtCounter(sharedSecret, counter);\n\n// Encrypt a PSK message\nconst envelope = encryptPSKMessage(\n    'Hello with PSK!',\n    senderPublicKey,\n    recipientPublicKey,\n    psk,\n    counter,\n);\n\n// Encode for transmission\nconst bytes = encodePSKEnvelope(envelope);\n\n// Check if received data is a PSK message\nif (isPSKMessage(bytes)) {\n    const decoded = decodePSKEnvelope(bytes);\n    const content = decryptPSKMessage(decoded, myPrivateKey, myPublicKey, psk);\n}\n\n// Counter state management\nlet state = createPSKState();\nconst { counter: sendCounter, state: newState } = advanceSendCounter(state);\nstate = newState;\n\n// Exchange URI for out-of-band key sharing\nconst uri = createPSKExchangeURI('ALGO_ADDRESS', pskBytes, 'My Chat');\nconst parsed = parsePSKExchangeURI(uri);\n```\n\n## Testing\n\n```bash\nbun test\n```\n\n## Cross-Implementation Compatibility\n\nThis implementation is fully compatible with:\n- [swift-algochat](https://github.com/CorvidLabs/swift-algochat) (Swift)\n- [rs-algochat](https://github.com/CorvidLabs/rs-algochat) (Rust)\n- [py-algochat](https://github.com/CorvidLabs/py-algochat) (Python)\n- [kt-algochat](https://github.com/CorvidLabs/kt-algochat) (Kotlin)\n\n## License\n\nMIT License - See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCorvidLabs%2Fts-algochat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCorvidLabs%2Fts-algochat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCorvidLabs%2Fts-algochat/lists"}